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