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