1 /*
2 * The authors of this software are Rob Pike and Ken Thompson.
3 * Copyright (c) 2002 by Lucent Technologies.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose without fee is hereby granted, provided that this entire notice
6 * is included in all copies of any software which is or includes a copy
7 * or modification of this software and in all copies of the supporting
8 * documentation for such software.
9 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13 */
14 #include "lib9.h"
15 #include "fmtdef.h"
16
17 /*
18 * How many bytes of output UTF will be produced by quoting (if necessary) this string?
19 * How many runes? How much of the input will be consumed?
20 * The parameter q is filled in by _quotesetup.
21 * The string may be UTF or Runes (s or r).
22 * Return count does not include NUL.
23 * Terminate the scan at the first of:
24 * NUL in input
25 * count exceeded in input
26 * count exceeded on output
27 * *ninp is set to number of input bytes accepted.
28 * nin may be <0 initially, to avoid checking input by count.
29 */
30 void
_quotesetup(char * s,Rune * r,int nin,int nout,Quoteinfo * q,int sharp,int runesout)31 _quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
32 {
33 int w;
34 Rune c;
35
36 q->quoted = 0;
37 q->nbytesout = 0;
38 q->nrunesout = 0;
39 q->nbytesin = 0;
40 q->nrunesin = 0;
41 if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
42 if(nout < 2)
43 return;
44 q->quoted = 1;
45 q->nbytesout = 2;
46 q->nrunesout = 2;
47 }
48 for(; nin!=0; nin-=w){
49 if(s)
50 w = chartorune(&c, s);
51 else{
52 c = *r;
53 w = runelen(c);
54 }
55
56 if(c == '\0')
57 break;
58 if(runesout){
59 if(q->nrunesout+1 > nout)
60 break;
61 }else{
62 if(q->nbytesout+w > nout)
63 break;
64 }
65
66 if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
67 if(!q->quoted){
68 if(runesout){
69 if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
70 break;
71 }else{
72 if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
73 break;
74 }
75 q->nrunesout += 2; /* include quotes */
76 q->nbytesout += 2; /* include quotes */
77 q->quoted = 1;
78 }
79 if(c == '\'') {
80 if(runesout){
81 if(1+q->nrunesout+1 > nout) /* no room for quotes */
82 break;
83 }else{
84 if(1+q->nbytesout+w > nout) /* no room for quotes */
85 break;
86 }
87 q->nbytesout++;
88 q->nrunesout++; /* quotes reproduce as two characters */
89 }
90 }
91
92 /* advance input */
93 if(s)
94 s += w;
95 else
96 r++;
97 q->nbytesin += w;
98 q->nrunesin++;
99
100 /* advance output */
101 q->nbytesout += w;
102 q->nrunesout++;
103 }
104 }
105
106 static int
qstrfmt(char * sin,Rune * rin,Quoteinfo * q,Fmt * f)107 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
108 {
109 Rune r, *rm, *rme;
110 char *t, *s, *m, *me;
111 Rune *rt, *rs;
112 ulong fl;
113 int nc, w;
114
115 m = sin;
116 me = m + q->nbytesin;
117 rm = rin;
118 rme = rm + q->nrunesin;
119
120 w = f->width;
121 fl = f->flags;
122 if(f->runes){
123 if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
124 return -1;
125 }else{
126 if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
127 return -1;
128 }
129 t = f->to;
130 s = f->stop;
131 rt = f->to;
132 rs = f->stop;
133 if(f->runes)
134 FMTRCHAR(f, rt, rs, '\'');
135 else
136 FMTRUNE(f, t, s, '\'');
137 for(nc = q->nrunesin; nc > 0; nc--){
138 if(sin){
139 r = *(uchar*)m;
140 if(r < Runeself)
141 m++;
142 else if((me - m) >= UTFmax || fullrune(m, me-m))
143 m += chartorune(&r, m);
144 else
145 break;
146 }else{
147 if(rm >= rme)
148 break;
149 r = *rm++;
150 }
151 if(f->runes){
152 FMTRCHAR(f, rt, rs, r);
153 if(r == '\'')
154 FMTRCHAR(f, rt, rs, r);
155 }else{
156 FMTRUNE(f, t, s, r);
157 if(r == '\'')
158 FMTRUNE(f, t, s, r);
159 }
160 }
161
162 if(f->runes){
163 FMTRCHAR(f, rt, rs, '\'');
164 USED(rs);
165 f->nfmt += rt - (Rune *)f->to;
166 f->to = rt;
167 if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
168 return -1;
169 }else{
170 FMTRUNE(f, t, s, '\'');
171 USED(s);
172 f->nfmt += t - (char *)f->to;
173 f->to = t;
174 if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
175 return -1;
176 }
177 return 0;
178 }
179
180 int
_quotestrfmt(int runesin,Fmt * f)181 _quotestrfmt(int runesin, Fmt *f)
182 {
183 int outlen;
184 Rune *r;
185 char *s;
186 Quoteinfo q;
187
188 f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
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, "<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, -1, 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