xref: /inferno-os/libkern/fmtquote.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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