fmtquote.c (5183B) download
1/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2#include "fmt.h"
3#include "fmtdef.h"
4#include "plan9.h"
5
6#include <stdarg.h>
7#include <string.h>
8
9/*
10 * How many bytes of output UTF will be produced by quoting (if necessary) this string?
11 * How many runes? How much of the input will be consumed?
12 * The parameter q is filled in by __quotesetup.
13 * The string may be UTF or Runes (s or r).
14 * Return count does not include NUL.
15 * Terminate the scan at the first of:
16 * NUL in input
17 * count exceeded in input
18 * count exceeded on output
19 * *ninp is set to number of input bytes accepted.
20 * nin may be <0 initially, to avoid checking input by count.
21 */
22void __quotesetup(char* s, Rune* r, int nin, int nout, Quoteinfo* q, int sharp, int runesout) {
23 int w;
24 Rune c;
25
26 q->quoted = 0;
27 q->nbytesout = 0;
28 q->nrunesout = 0;
29 q->nbytesin = 0;
30 q->nrunesin = 0;
31 if (sharp || nin == 0 || (s && *s == '\0') || (r && *r == '\0')) {
32 if (nout < 2)
33 return;
34 q->quoted = 1;
35 q->nbytesout = 2;
36 q->nrunesout = 2;
37 }
38 for (; nin != 0; nin--) {
39 if (s)
40 w = chartorune(&c, s);
41 else {
42 c = *r;
43 w = runelen(c);
44 }
45
46 if (c == '\0')
47 break;
48 if (runesout) {
49 if (q->nrunesout + 1 > nout)
50 break;
51 } else {
52 if (q->nbytesout + w > nout)
53 break;
54 }
55
56 if ((c <= L' ') || (c == L'\'') || (fmtdoquote != nil && fmtdoquote(c))) {
57 if (!q->quoted) {
58 if (runesout) {
59 if (1 + q->nrunesout + 1 + 1 > nout) /* no room for quotes */
60 break;
61 } else {
62 if (1 + q->nbytesout + w + 1 > nout) /* no room for quotes */
63 break;
64 }
65 q->nrunesout += 2; /* include quotes */
66 q->nbytesout += 2; /* include quotes */
67 q->quoted = 1;
68 }
69 if (c == '\'') {
70 if (runesout) {
71 if (1 + q->nrunesout + 1 > nout) /* no room for quotes */
72 break;
73 } else {
74 if (1 + q->nbytesout + w > nout) /* no room for quotes */
75 break;
76 }
77 q->nbytesout++;
78 q->nrunesout++; /* quotes reproduce as two characters */
79 }
80 }
81
82 /* advance input */
83 if (s)
84 s += w;
85 else
86 r++;
87 q->nbytesin += w;
88 q->nrunesin++;
89
90 /* advance output */
91 q->nbytesout += w;
92 q->nrunesout++;
93
94#ifndef PLAN9PORT
95 /* ANSI requires precision in bytes, not Runes. */
96 nin -= w - 1; /* and then n-- in the loop */
97#endif
98 }
99}
100
101static int
102qstrfmt(char* sin, Rune* rin, Quoteinfo* q, Fmt* f) {
103 Rune r, *rm, *rme;
104 char *t, *s, *m, *me;
105 Rune *rt, *rs;
106 ulong fl;
107 int nc, w;
108
109 m = sin;
110 me = m + q->nbytesin;
111 rm = rin;
112 rme = rm + q->nrunesin;
113
114 fl = f->flags;
115 w = 0;
116 if (fl & FmtWidth)
117 w = f->width;
118 if (f->runes) {
119 if (!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
120 return -1;
121 } else {
122 if (!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
123 return -1;
124 }
125 t = (char*) f->to;
126 s = (char*) f->stop;
127 rt = (Rune*) f->to;
128 rs = (Rune*) f->stop;
129 if (f->runes)
130 FMTRCHAR(f, rt, rs, '\'');
131 else
132 FMTRUNE(f, t, s, '\'');
133 for (nc = q->nrunesin; nc > 0; nc--) {
134 if (sin) {
135 r = *(uchar*) m;
136 if (r < Runeself)
137 m++;
138 else if ((me - m) >= UTFmax || fullrune(m, me - m))
139 m += chartorune(&r, m);
140 else
141 break;
142 } else {
143 if (rm >= rme)
144 break;
145 r = *(uchar*) rm++;
146 }
147 if (f->runes) {
148 FMTRCHAR(f, rt, rs, r);
149 if (r == '\'')
150 FMTRCHAR(f, rt, rs, r);
151 } else {
152 FMTRUNE(f, t, s, r);
153 if (r == '\'')
154 FMTRUNE(f, t, s, r);
155 }
156 }
157
158 if (f->runes) {
159 FMTRCHAR(f, rt, rs, '\'');
160 USED(rs);
161 f->nfmt += rt - (Rune*) f->to;
162 f->to = rt;
163 if (fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
164 return -1;
165 } else {
166 FMTRUNE(f, t, s, '\'');
167 USED(s);
168 f->nfmt += t - (char*) f->to;
169 f->to = t;
170 if (fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
171 return -1;
172 }
173 return 0;
174}
175
176int __quotestrfmt(int runesin, Fmt* f) {
177 int nin, outlen;
178 Rune* r;
179 char* s;
180 Quoteinfo q;
181
182 nin = -1;
183 if (f->flags & FmtPrec)
184 nin = f->prec;
185 if (runesin) {
186 r = va_arg(f->args, Rune*);
187 s = nil;
188 } else {
189 s = va_arg(f->args, char*);
190 r = nil;
191 }
192 if (!s && !r)
193 return __fmtcpy(f, (void*) "<nil>", 5, 5);
194
195 if (f->flush)
196 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
197 else if (f->runes)
198 outlen = (Rune*) f->stop - (Rune*) f->to;
199 else
200 outlen = (char*) f->stop - (char*) f->to;
201
202 __quotesetup(s, r, nin, outlen, &q, f->flags & FmtSharp, f->runes);
203 /*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
204
205 if (runesin) {
206 if (!q.quoted)
207 return __fmtrcpy(f, r, q.nrunesin);
208 return qstrfmt(nil, r, &q, f);
209 }
210
211 if (!q.quoted)
212 return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
213 return qstrfmt(s, nil, &q, f);
214}
215
216int quotestrfmt(Fmt* f) {
217 return __quotestrfmt(0, f);
218}
219
220int quoterunestrfmt(Fmt* f) {
221 return __quotestrfmt(1, f);
222}
223
224void quotefmtinstall(void) {
225 fmtinstall('q', quotestrfmt);
226 fmtinstall('Q', quoterunestrfmt);
227}
228
229int __needsquotes(char* s, int* quotelenp) {
230 Quoteinfo q;
231
232 __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
233 *quotelenp = q.nbytesout;
234
235 return q.quoted;
236}
237
238int __runeneedsquotes(Rune* r, int* quotelenp) {
239 Quoteinfo q;
240
241 __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
242 *quotelenp = q.nrunesout;
243
244 return q.quoted;
245}