1 /*
2 * The authors of this software are Rob Pike and Ken Thompson,
3 * with contributions from Mike Burrows and Sean Dorward.
4 *
5 * Copyright (c) 2002-2006 by Lucent Technologies.
6 * Portions Copyright (c) 2004 Google Inc.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose without fee is hereby granted, provided that this entire notice
10 * is included in all copies of any software which is or includes a copy
11 * or modification of this software and in all copies of the supporting
12 * documentation for such software.
13 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
14 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
15 * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
16 * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
17 */
18
19 #include <u.h>
20 #include <libc.h>
21 #include "fmtdef.h"
22
23 /*
24 * How many bytes of output UTF will be produced by quoting (if necessary) this string?
25 * How many runes? How much of the input will be consumed?
26 * The parameter q is filled in by __quotesetup.
27 * The string may be UTF or Runes (s or r).
28 * Return count does not include NUL.
29 * Terminate the scan at the first of:
30 * NUL in input
31 * count exceeded in input
32 * count exceeded on output
33 * *ninp is set to number of input bytes accepted.
34 * nin may be <0 initially, to avoid checking input by count.
35 */
36 void
37 __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
38 {
39 int w;
40 Rune c;
41
42 q->quoted = 0;
43 q->nbytesout = 0;
44 q->nrunesout = 0;
45 q->nbytesin = 0;
46 q->nrunesin = 0;
47 if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
48 if(nout < 2)
49 return;
50 q->quoted = 1;
51 q->nbytesout = 2;
52 q->nrunesout = 2;
53 }
54 for(; nin!=0; nin--){
55 if(s)
56 w = chartorune(&c, s);
57 else{
58 c = *r;
59 w = runelen(c);
60 }
61
62 if(c == '\0')
63 break;
64 if(runesout){
65 if(q->nrunesout+1 > nout)
66 break;
67 }else{
68 if(q->nbytesout+w > nout)
69 break;
70 }
71
72 if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
73 if(!q->quoted){
74 if(runesout){
75 if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
76 break;
77 }else{
78 if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
79 break;
80 }
81 q->nrunesout += 2; /* include quotes */
82 q->nbytesout += 2; /* include quotes */
83 q->quoted = 1;
84 }
85 if(c == '\'') {
86 if(runesout){
87 if(1+q->nrunesout+1 > nout) /* no room for quotes */
88 break;
89 }else{
90 if(1+q->nbytesout+w > nout) /* no room for quotes */
91 break;
92 }
93 q->nbytesout++;
94 q->nrunesout++; /* quotes reproduce as two characters */
95 }
96 }
97
98 /* advance input */
99 if(s)
100 s += w;
101 else
102 r++;
103 q->nbytesin += w;
104 q->nrunesin++;
105
106 /* advance output */
107 q->nbytesout += w;
108 q->nrunesout++;
109
110 #ifndef PLAN9PORT
111 /* ANSI requires precision in bytes, not Runes. */
112 nin-= w-1; /* and then n-- in the loop */
113 #endif
114 }
115 }
116
117 static int
118 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
119 {
120 Rune r, *rm, *rme;
121 char *t, *s, *m, *me;
122 Rune *rt, *rs;
123 ulong fl;
124 int nc, w;
125
126 m = sin;
127 me = m + q->nbytesin;
128 rm = rin;
129 rme = rm + q->nrunesin;
130
131 fl = f->flags;
132 w = 0;
133 if(fl & FmtWidth)
134 w = f->width;
135 if(f->runes){
136 if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
137 return -1;
138 }else{
139 if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
140 return -1;
141 }
142 t = (char*)f->to;
143 s = (char*)f->stop;
144 rt = (Rune*)f->to;
145 rs = (Rune*)f->stop;
146 if(f->runes)
147 FMTRCHAR(f, rt, rs, '\'');
148 else
149 FMTRUNE(f, t, s, '\'');
150 for(nc = q->nrunesin; nc > 0; nc--){
151 if(sin){
152 r = *(uchar*)m;
153 if(r < Runeself)
154 m++;
155 else if((me - m) >= UTFmax || fullrune(m, me-m))
156 m += chartorune(&r, m);
157 else
158 break;
159 }else{
160 if(rm >= rme)
161 break;
162 r = *(uchar*)rm++;
163 }
164 if(f->runes){
165 FMTRCHAR(f, rt, rs, r);
166 if(r == '\'')
167 FMTRCHAR(f, rt, rs, r);
168 }else{
169 FMTRUNE(f, t, s, r);
170 if(r == '\'')
171 FMTRUNE(f, t, s, r);
172 }
173 }
174
175 if(f->runes){
176 FMTRCHAR(f, rt, rs, '\'');
177 USED(rs);
178 f->nfmt += rt - (Rune *)f->to;
179 f->to = rt;
180 if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
181 return -1;
182 }else{
183 FMTRUNE(f, t, s, '\'');
184 USED(s);
185 f->nfmt += t - (char *)f->to;
186 f->to = t;
187 if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
188 return -1;
189 }
190 return 0;
191 }
192
193 int
194 __quotestrfmt(int runesin, Fmt *f)
195 {
196 int nin, outlen;
197 Rune *r;
198 char *s;
199 Quoteinfo q;
200
201 nin = -1;
202 if(f->flags&FmtPrec)
203 nin = f->prec;
204 if(runesin){
205 r = va_arg(f->args, Rune *);
206 s = nil;
207 }else{
208 s = va_arg(f->args, char *);
209 r = nil;
210 }
211 if(!s && !r)
212 return __fmtcpy(f, (void*)"<nil>", 5, 5);
213
214 if(f->flush)
215 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
216 else if(f->runes)
217 outlen = (Rune*)f->stop - (Rune*)f->to;
218 else
219 outlen = (char*)f->stop - (char*)f->to;
220
221 __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
222 /*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
223
224 if(runesin){
225 if(!q.quoted)
226 return __fmtrcpy(f, r, q.nrunesin);
227 return qstrfmt(nil, r, &q, f);
228 }
229
230 if(!q.quoted)
231 return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
232 return qstrfmt(s, nil, &q, f);
233 }
234
235 int
236 quotestrfmt(Fmt *f)
237 {
238 return __quotestrfmt(0, f);
239 }
240
241 int
242 quoterunestrfmt(Fmt *f)
243 {
244 return __quotestrfmt(1, f);
245 }
246
247 void
248 quotefmtinstall(void)
249 {
250 fmtinstall('q', quotestrfmt);
251 fmtinstall('Q', quoterunestrfmt);
252 }
253
254 int
255 __needsquotes(char *s, int *quotelenp)
256 {
257 Quoteinfo q;
258
259 __quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
260 *quotelenp = q.nbytesout;
261
262 return q.quoted;
263 }
264
265 int
266 __runeneedsquotes(Rune *r, int *quotelenp)
267 {
268 Quoteinfo q;
269
270 __quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
271 *quotelenp = q.nrunesout;
272
273 return q.quoted;
274 }