Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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