Blob


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