xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libc/fmtquote.c (revision 0d601874851962e88c6c60fdd2e637bba04e13c2)
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
11  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13  */
14 #include <u.h>
15 #include <libc.h>
16 #include "fmtdef.h"
17 
18 /*
19  * How many bytes of output UTF will be produced by quoting (if necessary) this string?
20  * How many runes? How much of the input will be consumed?
21  * The parameter q is filled in by __quotesetup.
22  * The string may be UTF or Runes (s or r).
23  * Return count does not include NUL.
24  * Terminate the scan at the first of:
25  *	NUL in input
26  *	count exceeded in input
27  *	count exceeded on output
28  * *ninp is set to number of input bytes accepted.
29  * nin may be <0 initially, to avoid checking input by count.
30  */
31 void
32 __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
33 {
34 	int w;
35 	Rune c;
36 
37 	q->quoted = 0;
38 	q->nbytesout = 0;
39 	q->nrunesout = 0;
40 	q->nbytesin = 0;
41 	q->nrunesin = 0;
42 	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
43 		if(nout < 2)
44 			return;
45 		q->quoted = 1;
46 		q->nbytesout = 2;
47 		q->nrunesout = 2;
48 	}
49 	for(; nin!=0; nin--){
50 		if(s)
51 			w = chartorune(&c, s);
52 		else{
53 			c = *r;
54 			w = runelen(c);
55 		}
56 
57 		if(c == '\0')
58 			break;
59 		if(runesout){
60 			if(q->nrunesout+1 > nout)
61 				break;
62 		}else{
63 			if(q->nbytesout+w > nout)
64 				break;
65 		}
66 
67 		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
68 			if(!q->quoted){
69 				if(runesout){
70 					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
71 						break;
72 				}else{
73 					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
74 						break;
75 				}
76 				q->nrunesout += 2;	/* include quotes */
77 				q->nbytesout += 2;	/* include quotes */
78 				q->quoted = 1;
79 			}
80 			if(c == '\'')	{
81 				if(runesout){
82 					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
83 						break;
84 				}else{
85 					if(1+q->nbytesout+w > nout)	/* no room for quotes */
86 						break;
87 				}
88 				q->nbytesout++;
89 				q->nrunesout++;	/* quotes reproduce as two characters */
90 			}
91 		}
92 
93 		/* advance input */
94 		if(s)
95 			s += w;
96 		else
97 			r++;
98 		q->nbytesin += w;
99 		q->nrunesin++;
100 
101 		/* advance output */
102 		q->nbytesout += w;
103 		q->nrunesout++;
104 	}
105 }
106 
107 static int
108 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
109 {
110 	Rune r, *rm, *rme;
111 	char *t, *s, *m, *me;
112 	Rune *rt, *rs;
113 	ulong fl;
114 	int nc, w;
115 
116 	m = sin;
117 	me = m + q->nbytesin;
118 	rm = rin;
119 	rme = rm + q->nrunesin;
120 
121 	w = f->width;
122 	fl = f->flags;
123 	if(f->runes){
124 		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
125 			return -1;
126 	}else{
127 		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
128 			return -1;
129 	}
130 	t = (char*)f->to;
131 	s = (char*)f->stop;
132 	rt = (Rune*)f->to;
133 	rs = (Rune*)f->stop;
134 	if(f->runes)
135 		FMTRCHAR(f, rt, rs, '\'');
136 	else
137 		FMTRUNE(f, t, s, '\'');
138 	for(nc = q->nrunesin; nc > 0; nc--){
139 		if(sin){
140 			r = *(uchar*)m;
141 			if(r < Runeself)
142 				m++;
143 			else if((me - m) >= UTFmax || fullrune(m, me-m))
144 				m += chartorune(&r, m);
145 			else
146 				break;
147 		}else{
148 			if(rm >= rme)
149 				break;
150 			r = *(uchar*)rm++;
151 		}
152 		if(f->runes){
153 			FMTRCHAR(f, rt, rs, r);
154 			if(r == '\'')
155 				FMTRCHAR(f, rt, rs, r);
156 		}else{
157 			FMTRUNE(f, t, s, r);
158 			if(r == '\'')
159 				FMTRUNE(f, t, s, r);
160 		}
161 	}
162 
163 	if(f->runes){
164 		FMTRCHAR(f, rt, rs, '\'');
165 		USED(rs);
166 		f->nfmt += rt - (Rune *)f->to;
167 		f->to = rt;
168 		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
169 			return -1;
170 	}else{
171 		FMTRUNE(f, t, s, '\'');
172 		USED(s);
173 		f->nfmt += t - (char *)f->to;
174 		f->to = t;
175 		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
176 			return -1;
177 	}
178 	return 0;
179 }
180 
181 int
182 __quotestrfmt(int runesin, Fmt *f)
183 {
184 	int nin, outlen;
185 	Rune *r;
186 	char *s;
187 	Quoteinfo q;
188 
189 	nin = -1;
190 	if(f->flags&FmtPrec)
191 		nin = f->prec;
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;
198 	}
199 	if(!s && !r)
200 		return __fmtcpy(f, (void*)"<nil>", 5, 5);
201 
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;
208 
209 	__quotesetup(s, r, nin, 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);
211 
212 	if(runesin){
213 		if(!q.quoted)
214 			return __fmtrcpy(f, r, q.nrunesin);
215 		return qstrfmt(nil, r, &q, f);
216 	}
217 
218 	if(!q.quoted)
219 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
220 	return qstrfmt(s, nil, &q, f);
221 }
222 
223 int
224 quotestrfmt(Fmt *f)
225 {
226 	return __quotestrfmt(0, f);
227 }
228 
229 int
230 quoterunestrfmt(Fmt *f)
231 {
232 	return __quotestrfmt(1, f);
233 }
234 
235 void
236 quotefmtinstall(void)
237 {
238 	fmtinstall('q', quotestrfmt);
239 	fmtinstall('Q', quoterunestrfmt);
240 }
241 
242 int
243 __needsquotes(char *s, int *quotelenp)
244 {
245 	Quoteinfo q;
246 
247 	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
248 	*quotelenp = q.nbytesout;
249 
250 	return q.quoted;
251 }
252 
253 int
254 __runeneedsquotes(Rune *r, int *quotelenp)
255 {
256 	Quoteinfo q;
257 
258 	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
259 	*quotelenp = q.nrunesout;
260 
261 	return q.quoted;
262 }
263