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