Blob


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