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"
7
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
__quotesetup(char * s,Rune * r,int nin,int nout,Quoteinfo * q,int sharp,int runesout)22 __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
23 {
24 int w;
25 Rune c;
26
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 }
46
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 }
56
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 }
82
83 /* advance input */
84 if(s)
85 s += w;
86 else
87 r++;
88 q->nbytesin += w;
89 q->nrunesin++;
90
91 /* advance output */
92 q->nbytesout += w;
93 q->nrunesout++;
94
95 #ifndef PLAN9PORT
96 /* ANSI requires precision in bytes, not Runes. */
97 nin-= w-1; /* and then n-- in the loop */
98 #endif
99 }
100 }
101
102 static int
qstrfmt(char * sin,Rune * rin,Quoteinfo * q,Fmt * f)103 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
104 {
105 Rune r, *rm, *rme;
106 char *t, *s, *m, *me;
107 Rune *rt, *rs;
108 ulong fl;
109 int nc, w;
110
111 m = sin;
112 me = m + q->nbytesin;
113 rm = rin;
114 rme = rm + q->nrunesin;
115
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;
126 }
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++;
148 }
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);
157 }
158 }
159
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;
174 }
175 return 0;
176 }
177
178 int
__quotestrfmt(int runesin,Fmt * f)179 __quotestrfmt(int runesin, Fmt *f)
180 {
181 int nin, outlen;
182 Rune *r;
183 char *s;
184 Quoteinfo q;
185
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;
195 }
196 if(!s && !r)
197 return __fmtcpy(f, (void*)"<nil>", 5, 5);
198
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;
205
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); */
208
209 if(runesin){
210 if(!q.quoted)
211 return __fmtrcpy(f, r, q.nrunesin);
212 return qstrfmt(nil, r, &q, f);
213 }
214
215 if(!q.quoted)
216 return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
217 return qstrfmt(s, nil, &q, f);
218 }
219
220 int
quotestrfmt(Fmt * f)221 quotestrfmt(Fmt *f)
222 {
223 return __quotestrfmt(0, f);
224 }
225
226 int
quoterunestrfmt(Fmt * f)227 quoterunestrfmt(Fmt *f)
228 {
229 return __quotestrfmt(1, f);
230 }
231
232 void
quotefmtinstall(void)233 quotefmtinstall(void)
234 {
235 fmtinstall('q', quotestrfmt);
236 fmtinstall('Q', quoterunestrfmt);
237 }
238
239 int
__needsquotes(char * s,int * quotelenp)240 __needsquotes(char *s, int *quotelenp)
241 {
242 Quoteinfo q;
243
244 __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
245 *quotelenp = q.nbytesout;
246
247 return q.quoted;
248 }
249
250 int
__runeneedsquotes(Rune * r,int * quotelenp)251 __runeneedsquotes(Rune *r, int *quotelenp)
252 {
253 Quoteinfo q;
254
255 __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
256 *quotelenp = q.nrunesout;
257
258 return q.quoted;
259 }
260