xref: /plan9/sys/src/libc/arm/doprint.xc (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier#include	<u.h>
2*7dd7cddfSDavid du Colombier#include	<libc.h>
3*7dd7cddfSDavid du Colombier
4*7dd7cddfSDavid du Colombierenum
5*7dd7cddfSDavid du Colombier{
6*7dd7cddfSDavid du Colombier	SIZE	= 1024,
7*7dd7cddfSDavid du Colombier	IDIGIT	= 40,
8*7dd7cddfSDavid du Colombier	MAXCONV	= 40,
9*7dd7cddfSDavid du Colombier	FDIGIT	= 30,
10*7dd7cddfSDavid du Colombier	FDEFLT	= 6,
11*7dd7cddfSDavid du Colombier	NONE	= -1000,
12*7dd7cddfSDavid du Colombier	MAXFMT	= 512,
13*7dd7cddfSDavid du Colombier
14*7dd7cddfSDavid du Colombier	FPLUS	= 1<<0,
15*7dd7cddfSDavid du Colombier	FMINUS	= 1<<1,
16*7dd7cddfSDavid du Colombier	FSHARP	= 1<<2,
17*7dd7cddfSDavid du Colombier	FLONG	= 1<<3,
18*7dd7cddfSDavid du Colombier	FSHORT	= 1<<4,
19*7dd7cddfSDavid du Colombier	FUNSIGN	= 1<<5,
20*7dd7cddfSDavid du Colombier	FVLONG	= 1<<6,
21*7dd7cddfSDavid du Colombier};
22*7dd7cddfSDavid du Colombier
23*7dd7cddfSDavid du Colombierint	printcol;
24*7dd7cddfSDavid du Colombier
25*7dd7cddfSDavid du Colombierstatic	int	convcount;
26*7dd7cddfSDavid du Colombierstatic	char	fmtindex[MAXFMT];
27*7dd7cddfSDavid du Colombier
28*7dd7cddfSDavid du Colombierstatic	int	noconv(va_list*, Fconv*);
29*7dd7cddfSDavid du Colombierstatic	int	flags(va_list*, Fconv*);
30*7dd7cddfSDavid du Colombier
31*7dd7cddfSDavid du Colombierstatic	int	cconv(va_list*, Fconv*);
32*7dd7cddfSDavid du Colombierstatic	int	rconv(va_list*, Fconv*);
33*7dd7cddfSDavid du Colombierstatic	int	sconv(va_list*, Fconv*);
34*7dd7cddfSDavid du Colombierstatic	int	percent(va_list*, Fconv*);
35*7dd7cddfSDavid du Colombierstatic	int	column(va_list*, Fconv*);
36*7dd7cddfSDavid du Colombier
37*7dd7cddfSDavid du Colombierint	numbconv(va_list*, Fconv*);
38*7dd7cddfSDavid du Colombier
39*7dd7cddfSDavid du Colombierstatic
40*7dd7cddfSDavid du Colombierint	(*fmtconv[MAXCONV])(va_list*, Fconv*) =
41*7dd7cddfSDavid du Colombier{
42*7dd7cddfSDavid du Colombier	noconv
43*7dd7cddfSDavid du Colombier};
44*7dd7cddfSDavid du Colombier
45*7dd7cddfSDavid du Colombierstatic
46*7dd7cddfSDavid du Colombiervoid
47*7dd7cddfSDavid du Colombierinitfmt(void)
48*7dd7cddfSDavid du Colombier{
49*7dd7cddfSDavid du Colombier	int cc;
50*7dd7cddfSDavid du Colombier
51*7dd7cddfSDavid du Colombier	cc = 0;
52*7dd7cddfSDavid du Colombier	fmtconv[cc] = noconv;
53*7dd7cddfSDavid du Colombier	cc++;
54*7dd7cddfSDavid du Colombier
55*7dd7cddfSDavid du Colombier	fmtconv[cc] = flags;
56*7dd7cddfSDavid du Colombier	fmtindex['+'] = cc;
57*7dd7cddfSDavid du Colombier	fmtindex['-'] = cc;
58*7dd7cddfSDavid du Colombier	fmtindex['#'] = cc;
59*7dd7cddfSDavid du Colombier	fmtindex['h'] = cc;
60*7dd7cddfSDavid du Colombier	fmtindex['l'] = cc;
61*7dd7cddfSDavid du Colombier	fmtindex['u'] = cc;
62*7dd7cddfSDavid du Colombier	cc++;
63*7dd7cddfSDavid du Colombier
64*7dd7cddfSDavid du Colombier	fmtconv[cc] = numbconv;
65*7dd7cddfSDavid du Colombier	fmtindex['d'] = cc;
66*7dd7cddfSDavid du Colombier	fmtindex['o'] = cc;
67*7dd7cddfSDavid du Colombier	fmtindex['x'] = cc;
68*7dd7cddfSDavid du Colombier	fmtindex['X'] = cc;
69*7dd7cddfSDavid du Colombier	cc++;
70*7dd7cddfSDavid du Colombier
71*7dd7cddfSDavid du Colombier	fmtconv[cc] = cconv;
72*7dd7cddfSDavid du Colombier	fmtindex['c'] = cc;
73*7dd7cddfSDavid du Colombier	fmtindex['C'] = cc;
74*7dd7cddfSDavid du Colombier	cc++;
75*7dd7cddfSDavid du Colombier
76*7dd7cddfSDavid du Colombier	fmtconv[cc] = rconv;
77*7dd7cddfSDavid du Colombier	fmtindex['r'] = cc;
78*7dd7cddfSDavid du Colombier	cc++;
79*7dd7cddfSDavid du Colombier
80*7dd7cddfSDavid du Colombier	fmtconv[cc] = sconv;
81*7dd7cddfSDavid du Colombier	fmtindex['s'] = cc;
82*7dd7cddfSDavid du Colombier	fmtindex['S'] = cc;
83*7dd7cddfSDavid du Colombier	cc++;
84*7dd7cddfSDavid du Colombier
85*7dd7cddfSDavid du Colombier	fmtconv[cc] = percent;
86*7dd7cddfSDavid du Colombier	fmtindex['%'] = cc;
87*7dd7cddfSDavid du Colombier	cc++;
88*7dd7cddfSDavid du Colombier
89*7dd7cddfSDavid du Colombier	fmtconv[cc] = column;
90*7dd7cddfSDavid du Colombier	fmtindex['|'] = cc;
91*7dd7cddfSDavid du Colombier	cc++;
92*7dd7cddfSDavid du Colombier
93*7dd7cddfSDavid du Colombier	convcount = cc;
94*7dd7cddfSDavid du Colombier}
95*7dd7cddfSDavid du Colombier
96*7dd7cddfSDavid du Colombierint
97*7dd7cddfSDavid du Colombierfmtinstall(int c, int (*f)(va_list*, Fconv*))
98*7dd7cddfSDavid du Colombier{
99*7dd7cddfSDavid du Colombier
100*7dd7cddfSDavid du Colombier	if(convcount == 0)
101*7dd7cddfSDavid du Colombier		initfmt();
102*7dd7cddfSDavid du Colombier	if(c < 0 || c >= MAXFMT)
103*7dd7cddfSDavid du Colombier		return -1;
104*7dd7cddfSDavid du Colombier	if(convcount >= MAXCONV)
105*7dd7cddfSDavid du Colombier		return -1;
106*7dd7cddfSDavid du Colombier	fmtconv[convcount] = f;
107*7dd7cddfSDavid du Colombier	fmtindex[c] = convcount;
108*7dd7cddfSDavid du Colombier	convcount++;
109*7dd7cddfSDavid du Colombier	return 0;
110*7dd7cddfSDavid du Colombier}
111*7dd7cddfSDavid du Colombier
112*7dd7cddfSDavid du Colombierchar*
113*7dd7cddfSDavid du Colombierdoprint(char *s, char *es, char *fmt, va_list argp)
114*7dd7cddfSDavid du Colombier{
115*7dd7cddfSDavid du Colombier	int n, c;
116*7dd7cddfSDavid du Colombier	Rune rune;
117*7dd7cddfSDavid du Colombier	Fconv local;
118*7dd7cddfSDavid du Colombier
119*7dd7cddfSDavid du Colombier	if(s >= es)
120*7dd7cddfSDavid du Colombier		return s;
121*7dd7cddfSDavid du Colombier	local.out = s;
122*7dd7cddfSDavid du Colombier	local.eout = es-UTFmax-1;
123*7dd7cddfSDavid du Colombier
124*7dd7cddfSDavid du Colombierloop:
125*7dd7cddfSDavid du Colombier	c = *fmt & 0xff;
126*7dd7cddfSDavid du Colombier	if(c >= Runeself) {
127*7dd7cddfSDavid du Colombier		n = chartorune(&rune, fmt);
128*7dd7cddfSDavid du Colombier		fmt += n;
129*7dd7cddfSDavid du Colombier		c = rune;
130*7dd7cddfSDavid du Colombier	} else
131*7dd7cddfSDavid du Colombier		fmt++;
132*7dd7cddfSDavid du Colombier	switch(c) {
133*7dd7cddfSDavid du Colombier	case 0:
134*7dd7cddfSDavid du Colombier		*local.out = 0;
135*7dd7cddfSDavid du Colombier		return local.out;
136*7dd7cddfSDavid du Colombier
137*7dd7cddfSDavid du Colombier	default:
138*7dd7cddfSDavid du Colombier		printcol++;
139*7dd7cddfSDavid du Colombier		goto common;
140*7dd7cddfSDavid du Colombier
141*7dd7cddfSDavid du Colombier	case '\n':
142*7dd7cddfSDavid du Colombier		printcol = 0;
143*7dd7cddfSDavid du Colombier		goto common;
144*7dd7cddfSDavid du Colombier
145*7dd7cddfSDavid du Colombier	case '\t':
146*7dd7cddfSDavid du Colombier		printcol = (printcol+8) & ~7;
147*7dd7cddfSDavid du Colombier		goto common;
148*7dd7cddfSDavid du Colombier
149*7dd7cddfSDavid du Colombier	common:
150*7dd7cddfSDavid du Colombier		if(local.out < local.eout)
151*7dd7cddfSDavid du Colombier			if(c >= Runeself) {
152*7dd7cddfSDavid du Colombier				rune = c;
153*7dd7cddfSDavid du Colombier				n = runetochar(local.out, &rune);
154*7dd7cddfSDavid du Colombier				local.out += n;
155*7dd7cddfSDavid du Colombier			} else
156*7dd7cddfSDavid du Colombier				*local.out++ = c;
157*7dd7cddfSDavid du Colombier		goto loop;
158*7dd7cddfSDavid du Colombier
159*7dd7cddfSDavid du Colombier	case '%':
160*7dd7cddfSDavid du Colombier		break;
161*7dd7cddfSDavid du Colombier	}
162*7dd7cddfSDavid du Colombier	local.f1 = NONE;
163*7dd7cddfSDavid du Colombier	local.f2 = NONE;
164*7dd7cddfSDavid du Colombier	local.f3 = 0;
165*7dd7cddfSDavid du Colombier
166*7dd7cddfSDavid du Colombier	/*
167*7dd7cddfSDavid du Colombier	 * read one of the following
168*7dd7cddfSDavid du Colombier	 *	1. number, => f1, f2 in order.
169*7dd7cddfSDavid du Colombier	 *	2. '*' same as number (from args)
170*7dd7cddfSDavid du Colombier	 *	3. '.' ignored (separates numbers)
171*7dd7cddfSDavid du Colombier	 *	4. flag => f3
172*7dd7cddfSDavid du Colombier	 *	5. verb and terminate
173*7dd7cddfSDavid du Colombier	 */
174*7dd7cddfSDavid du Colombierl0:
175*7dd7cddfSDavid du Colombier	c = *fmt & 0xff;
176*7dd7cddfSDavid du Colombier	if(c >= Runeself) {
177*7dd7cddfSDavid du Colombier		n = chartorune(&rune, fmt);
178*7dd7cddfSDavid du Colombier		fmt += n;
179*7dd7cddfSDavid du Colombier		c = rune;
180*7dd7cddfSDavid du Colombier	} else
181*7dd7cddfSDavid du Colombier		fmt++;
182*7dd7cddfSDavid du Colombier
183*7dd7cddfSDavid du Colombierl1:
184*7dd7cddfSDavid du Colombier	if(c == 0) {
185*7dd7cddfSDavid du Colombier		fmt--;
186*7dd7cddfSDavid du Colombier		goto loop;
187*7dd7cddfSDavid du Colombier	}
188*7dd7cddfSDavid du Colombier	if(c == '.') {
189*7dd7cddfSDavid du Colombier		if(local.f1 == NONE)
190*7dd7cddfSDavid du Colombier			local.f1 = 0;
191*7dd7cddfSDavid du Colombier		local.f2 = 0;
192*7dd7cddfSDavid du Colombier		goto l0;
193*7dd7cddfSDavid du Colombier	}
194*7dd7cddfSDavid du Colombier	if((c >= '1' && c <= '9') ||
195*7dd7cddfSDavid du Colombier	   (c == '0' && local.f1 != NONE)) {	/* '0' is a digit for f2 */
196*7dd7cddfSDavid du Colombier		n = 0;
197*7dd7cddfSDavid du Colombier		while(c >= '0' && c <= '9') {
198*7dd7cddfSDavid du Colombier			n = n*10 + c-'0';
199*7dd7cddfSDavid du Colombier			c = *fmt++;
200*7dd7cddfSDavid du Colombier		}
201*7dd7cddfSDavid du Colombier		if(local.f1 == NONE)
202*7dd7cddfSDavid du Colombier			local.f1 = n;
203*7dd7cddfSDavid du Colombier		else
204*7dd7cddfSDavid du Colombier			local.f2 = n;
205*7dd7cddfSDavid du Colombier		goto l1;
206*7dd7cddfSDavid du Colombier	}
207*7dd7cddfSDavid du Colombier	if(c == '*') {
208*7dd7cddfSDavid du Colombier		n = va_arg(argp, int);
209*7dd7cddfSDavid du Colombier		if(local.f1 == NONE)
210*7dd7cddfSDavid du Colombier			local.f1 = n;
211*7dd7cddfSDavid du Colombier		else
212*7dd7cddfSDavid du Colombier			local.f2 = n;
213*7dd7cddfSDavid du Colombier		goto l0;
214*7dd7cddfSDavid du Colombier	}
215*7dd7cddfSDavid du Colombier	n = 0;
216*7dd7cddfSDavid du Colombier	if(c >= 0 && c < MAXFMT)
217*7dd7cddfSDavid du Colombier		n = fmtindex[c];
218*7dd7cddfSDavid du Colombier	local.chr = c;
219*7dd7cddfSDavid du Colombier	n = (*fmtconv[n])(&argp, &local);
220*7dd7cddfSDavid du Colombier	if(n < 0) {
221*7dd7cddfSDavid du Colombier		local.f3 |= -n;
222*7dd7cddfSDavid du Colombier		goto l0;
223*7dd7cddfSDavid du Colombier	}
224*7dd7cddfSDavid du Colombier	goto loop;
225*7dd7cddfSDavid du Colombier}
226*7dd7cddfSDavid du Colombier
227*7dd7cddfSDavid du Colombierint
228*7dd7cddfSDavid du Colombiernumbconv(va_list *arg, Fconv *fp)
229*7dd7cddfSDavid du Colombier{
230*7dd7cddfSDavid du Colombier	char s[IDIGIT];
231*7dd7cddfSDavid du Colombier	int i, f, n, b, ucase;
232*7dd7cddfSDavid du Colombier	short h;
233*7dd7cddfSDavid du Colombier	long v;
234*7dd7cddfSDavid du Colombier	vlong vl;
235*7dd7cddfSDavid du Colombier
236*7dd7cddfSDavid du Colombier	SET(v);
237*7dd7cddfSDavid du Colombier	SET(vl);
238*7dd7cddfSDavid du Colombier
239*7dd7cddfSDavid du Colombier	ucase = 0;
240*7dd7cddfSDavid du Colombier	b = fp->chr;
241*7dd7cddfSDavid du Colombier	switch(fp->chr) {
242*7dd7cddfSDavid du Colombier	case 'u':
243*7dd7cddfSDavid du Colombier		fp->f3 |= FUNSIGN;
244*7dd7cddfSDavid du Colombier	case 'd':
245*7dd7cddfSDavid du Colombier		b = 10;
246*7dd7cddfSDavid du Colombier		break;
247*7dd7cddfSDavid du Colombier
248*7dd7cddfSDavid du Colombier	case 'o':
249*7dd7cddfSDavid du Colombier		b = 8;
250*7dd7cddfSDavid du Colombier		break;
251*7dd7cddfSDavid du Colombier
252*7dd7cddfSDavid du Colombier	case 'X':
253*7dd7cddfSDavid du Colombier		ucase = 1;
254*7dd7cddfSDavid du Colombier	case 'x':
255*7dd7cddfSDavid du Colombier		b = 16;
256*7dd7cddfSDavid du Colombier		break;
257*7dd7cddfSDavid du Colombier	}
258*7dd7cddfSDavid du Colombier
259*7dd7cddfSDavid du Colombier	f = 0;
260*7dd7cddfSDavid du Colombier	switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
261*7dd7cddfSDavid du Colombier	case FVLONG|FLONG:
262*7dd7cddfSDavid du Colombier		vl = va_arg(*arg, vlong);
263*7dd7cddfSDavid du Colombier		break;
264*7dd7cddfSDavid du Colombier
265*7dd7cddfSDavid du Colombier	case FUNSIGN|FVLONG|FLONG:
266*7dd7cddfSDavid du Colombier		vl = va_arg(*arg, uvlong);
267*7dd7cddfSDavid du Colombier		break;
268*7dd7cddfSDavid du Colombier
269*7dd7cddfSDavid du Colombier	case FLONG:
270*7dd7cddfSDavid du Colombier		v = va_arg(*arg, long);
271*7dd7cddfSDavid du Colombier		break;
272*7dd7cddfSDavid du Colombier
273*7dd7cddfSDavid du Colombier	case FUNSIGN|FLONG:
274*7dd7cddfSDavid du Colombier		v = va_arg(*arg, ulong);
275*7dd7cddfSDavid du Colombier		break;
276*7dd7cddfSDavid du Colombier
277*7dd7cddfSDavid du Colombier	case FSHORT:
278*7dd7cddfSDavid du Colombier		h = va_arg(*arg, int);
279*7dd7cddfSDavid du Colombier		v = h;
280*7dd7cddfSDavid du Colombier		break;
281*7dd7cddfSDavid du Colombier
282*7dd7cddfSDavid du Colombier	case FUNSIGN|FSHORT:
283*7dd7cddfSDavid du Colombier		h = va_arg(*arg, int);
284*7dd7cddfSDavid du Colombier		v = (ushort)h;
285*7dd7cddfSDavid du Colombier		break;
286*7dd7cddfSDavid du Colombier
287*7dd7cddfSDavid du Colombier	default:
288*7dd7cddfSDavid du Colombier		v = va_arg(*arg, int);
289*7dd7cddfSDavid du Colombier		break;
290*7dd7cddfSDavid du Colombier
291*7dd7cddfSDavid du Colombier	case FUNSIGN:
292*7dd7cddfSDavid du Colombier		v = va_arg(*arg, unsigned);
293*7dd7cddfSDavid du Colombier		break;
294*7dd7cddfSDavid du Colombier	}
295*7dd7cddfSDavid du Colombier	if(fp->f3 & FVLONG) {
296*7dd7cddfSDavid du Colombier		if(!(fp->f3 & FUNSIGN) && vl < 0) {
297*7dd7cddfSDavid du Colombier			vl = -vl;
298*7dd7cddfSDavid du Colombier			f = 1;
299*7dd7cddfSDavid du Colombier		}
300*7dd7cddfSDavid du Colombier	} else {
301*7dd7cddfSDavid du Colombier		if(!(fp->f3 & FUNSIGN) && v < 0) {
302*7dd7cddfSDavid du Colombier			v = -v;
303*7dd7cddfSDavid du Colombier			f = 1;
304*7dd7cddfSDavid du Colombier		}
305*7dd7cddfSDavid du Colombier	}
306*7dd7cddfSDavid du Colombier	s[IDIGIT-1] = 0;
307*7dd7cddfSDavid du Colombier	for(i = IDIGIT-2;; i--) {
308*7dd7cddfSDavid du Colombier		if(fp->f3 & FVLONG)
309*7dd7cddfSDavid du Colombier			n = (uvlong)vl % b;
310*7dd7cddfSDavid du Colombier		else
311*7dd7cddfSDavid du Colombier			n = (ulong)v % b;
312*7dd7cddfSDavid du Colombier		n += '0';
313*7dd7cddfSDavid du Colombier		if(n > '9') {
314*7dd7cddfSDavid du Colombier			n += 'a' - ('9'+1);
315*7dd7cddfSDavid du Colombier			if(ucase)
316*7dd7cddfSDavid du Colombier				n += 'A'-'a';
317*7dd7cddfSDavid du Colombier		}
318*7dd7cddfSDavid du Colombier		s[i] = n;
319*7dd7cddfSDavid du Colombier		if(i < 2)
320*7dd7cddfSDavid du Colombier			break;
321*7dd7cddfSDavid du Colombier		if(fp->f3 & FVLONG)
322*7dd7cddfSDavid du Colombier			vl = (uvlong)vl / b;
323*7dd7cddfSDavid du Colombier		else
324*7dd7cddfSDavid du Colombier			v = (ulong)v / b;
325*7dd7cddfSDavid du Colombier		if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
326*7dd7cddfSDavid du Colombier			continue;
327*7dd7cddfSDavid du Colombier		if(fp->f3 & FVLONG) {
328*7dd7cddfSDavid du Colombier			if(vl <= 0)
329*7dd7cddfSDavid du Colombier				break;
330*7dd7cddfSDavid du Colombier			continue;
331*7dd7cddfSDavid du Colombier		}
332*7dd7cddfSDavid du Colombier		if(v <= 0)
333*7dd7cddfSDavid du Colombier			break;
334*7dd7cddfSDavid du Colombier	}
335*7dd7cddfSDavid du Colombier
336*7dd7cddfSDavid du Colombier	if(fp->f3 & FSHARP) {
337*7dd7cddfSDavid du Colombier		if(b == 8 && s[i] != '0')
338*7dd7cddfSDavid du Colombier			s[--i] = '0';
339*7dd7cddfSDavid du Colombier		if(b == 16) {
340*7dd7cddfSDavid du Colombier			if(ucase)
341*7dd7cddfSDavid du Colombier				s[--i] = 'X';
342*7dd7cddfSDavid du Colombier			else
343*7dd7cddfSDavid du Colombier				s[--i] = 'x';
344*7dd7cddfSDavid du Colombier			s[--i] = '0';
345*7dd7cddfSDavid du Colombier		}
346*7dd7cddfSDavid du Colombier	}
347*7dd7cddfSDavid du Colombier	if(f)
348*7dd7cddfSDavid du Colombier		s[--i] = '-';
349*7dd7cddfSDavid du Colombier	fp->f2 = NONE;
350*7dd7cddfSDavid du Colombier	strconv(s+i, fp);
351*7dd7cddfSDavid du Colombier	return 0;
352*7dd7cddfSDavid du Colombier}
353*7dd7cddfSDavid du Colombier
354*7dd7cddfSDavid du Colombiervoid
355*7dd7cddfSDavid du ColombierStrconv(Rune *s, Fconv *fp)
356*7dd7cddfSDavid du Colombier{
357*7dd7cddfSDavid du Colombier	int n, c, i;
358*7dd7cddfSDavid du Colombier	Rune rune;
359*7dd7cddfSDavid du Colombier
360*7dd7cddfSDavid du Colombier	if(fp->f3 & FMINUS)
361*7dd7cddfSDavid du Colombier		fp->f1 = -fp->f1;
362*7dd7cddfSDavid du Colombier	n = 0;
363*7dd7cddfSDavid du Colombier	if(fp->f1 != NONE && fp->f1 >= 0) {
364*7dd7cddfSDavid du Colombier		for(; s[n]; n++)
365*7dd7cddfSDavid du Colombier			;
366*7dd7cddfSDavid du Colombier		while(n < fp->f1) {
367*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
368*7dd7cddfSDavid du Colombier				*fp->out++ = ' ';
369*7dd7cddfSDavid du Colombier			printcol++;
370*7dd7cddfSDavid du Colombier			n++;
371*7dd7cddfSDavid du Colombier		}
372*7dd7cddfSDavid du Colombier	}
373*7dd7cddfSDavid du Colombier	for(;;) {
374*7dd7cddfSDavid du Colombier		c = *s++;
375*7dd7cddfSDavid du Colombier		if(c == 0)
376*7dd7cddfSDavid du Colombier			break;
377*7dd7cddfSDavid du Colombier		n++;
378*7dd7cddfSDavid du Colombier		if(fp->f2 == NONE || fp->f2 > 0) {
379*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
380*7dd7cddfSDavid du Colombier				if(c >= Runeself) {
381*7dd7cddfSDavid du Colombier					rune = c;
382*7dd7cddfSDavid du Colombier					i = runetochar(fp->out, &rune);
383*7dd7cddfSDavid du Colombier					fp->out += i;
384*7dd7cddfSDavid du Colombier				} else
385*7dd7cddfSDavid du Colombier					*fp->out++ = c;
386*7dd7cddfSDavid du Colombier			if(fp->f2 != NONE)
387*7dd7cddfSDavid du Colombier				fp->f2--;
388*7dd7cddfSDavid du Colombier			switch(c) {
389*7dd7cddfSDavid du Colombier			default:
390*7dd7cddfSDavid du Colombier				printcol++;
391*7dd7cddfSDavid du Colombier				break;
392*7dd7cddfSDavid du Colombier			case '\n':
393*7dd7cddfSDavid du Colombier				printcol = 0;
394*7dd7cddfSDavid du Colombier				break;
395*7dd7cddfSDavid du Colombier			case '\t':
396*7dd7cddfSDavid du Colombier				printcol = (printcol+8) & ~7;
397*7dd7cddfSDavid du Colombier				break;
398*7dd7cddfSDavid du Colombier			}
399*7dd7cddfSDavid du Colombier		}
400*7dd7cddfSDavid du Colombier	}
401*7dd7cddfSDavid du Colombier	if(fp->f1 != NONE && fp->f1 < 0) {
402*7dd7cddfSDavid du Colombier		fp->f1 = -fp->f1;
403*7dd7cddfSDavid du Colombier		while(n < fp->f1) {
404*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
405*7dd7cddfSDavid du Colombier				*fp->out++ = ' ';
406*7dd7cddfSDavid du Colombier			printcol++;
407*7dd7cddfSDavid du Colombier			n++;
408*7dd7cddfSDavid du Colombier		}
409*7dd7cddfSDavid du Colombier	}
410*7dd7cddfSDavid du Colombier}
411*7dd7cddfSDavid du Colombier
412*7dd7cddfSDavid du Colombiervoid
413*7dd7cddfSDavid du Colombierstrconv(char *s, Fconv *fp)
414*7dd7cddfSDavid du Colombier{
415*7dd7cddfSDavid du Colombier	int n, c, i;
416*7dd7cddfSDavid du Colombier	Rune rune;
417*7dd7cddfSDavid du Colombier
418*7dd7cddfSDavid du Colombier	if(fp->f3 & FMINUS)
419*7dd7cddfSDavid du Colombier		fp->f1 = -fp->f1;
420*7dd7cddfSDavid du Colombier	n = 0;
421*7dd7cddfSDavid du Colombier	if(fp->f1 != NONE && fp->f1 >= 0) {
422*7dd7cddfSDavid du Colombier		n = utflen(s);
423*7dd7cddfSDavid du Colombier		while(n < fp->f1) {
424*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
425*7dd7cddfSDavid du Colombier				*fp->out++ = ' ';
426*7dd7cddfSDavid du Colombier			printcol++;
427*7dd7cddfSDavid du Colombier			n++;
428*7dd7cddfSDavid du Colombier		}
429*7dd7cddfSDavid du Colombier	}
430*7dd7cddfSDavid du Colombier	for(;;) {
431*7dd7cddfSDavid du Colombier		c = *s & 0xff;
432*7dd7cddfSDavid du Colombier		if(c >= Runeself) {
433*7dd7cddfSDavid du Colombier			i = chartorune(&rune, s);
434*7dd7cddfSDavid du Colombier			s += i;
435*7dd7cddfSDavid du Colombier			c = rune;
436*7dd7cddfSDavid du Colombier		} else
437*7dd7cddfSDavid du Colombier			s++;
438*7dd7cddfSDavid du Colombier		if(c == 0)
439*7dd7cddfSDavid du Colombier			break;
440*7dd7cddfSDavid du Colombier		n++;
441*7dd7cddfSDavid du Colombier		if(fp->f2 == NONE || fp->f2 > 0) {
442*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
443*7dd7cddfSDavid du Colombier				if(c >= Runeself) {
444*7dd7cddfSDavid du Colombier					rune = c;
445*7dd7cddfSDavid du Colombier					i = runetochar(fp->out, &rune);
446*7dd7cddfSDavid du Colombier					fp->out += i;
447*7dd7cddfSDavid du Colombier				} else
448*7dd7cddfSDavid du Colombier					*fp->out++ = c;
449*7dd7cddfSDavid du Colombier			if(fp->f2 != NONE)
450*7dd7cddfSDavid du Colombier				fp->f2--;
451*7dd7cddfSDavid du Colombier			switch(c) {
452*7dd7cddfSDavid du Colombier			default:
453*7dd7cddfSDavid du Colombier				printcol++;
454*7dd7cddfSDavid du Colombier				break;
455*7dd7cddfSDavid du Colombier			case '\n':
456*7dd7cddfSDavid du Colombier				printcol = 0;
457*7dd7cddfSDavid du Colombier				break;
458*7dd7cddfSDavid du Colombier			case '\t':
459*7dd7cddfSDavid du Colombier				printcol = (printcol+8) & ~7;
460*7dd7cddfSDavid du Colombier				break;
461*7dd7cddfSDavid du Colombier			}
462*7dd7cddfSDavid du Colombier		}
463*7dd7cddfSDavid du Colombier	}
464*7dd7cddfSDavid du Colombier	if(fp->f1 != NONE && fp->f1 < 0) {
465*7dd7cddfSDavid du Colombier		fp->f1 = -fp->f1;
466*7dd7cddfSDavid du Colombier		while(n < fp->f1) {
467*7dd7cddfSDavid du Colombier			if(fp->out < fp->eout)
468*7dd7cddfSDavid du Colombier				*fp->out++ = ' ';
469*7dd7cddfSDavid du Colombier			printcol++;
470*7dd7cddfSDavid du Colombier			n++;
471*7dd7cddfSDavid du Colombier		}
472*7dd7cddfSDavid du Colombier	}
473*7dd7cddfSDavid du Colombier}
474*7dd7cddfSDavid du Colombier
475*7dd7cddfSDavid du Colombierstatic
476*7dd7cddfSDavid du Colombierint
477*7dd7cddfSDavid du Colombiernoconv(va_list *arg, Fconv *fp)
478*7dd7cddfSDavid du Colombier{
479*7dd7cddfSDavid du Colombier	int n;
480*7dd7cddfSDavid du Colombier	char s[10];
481*7dd7cddfSDavid du Colombier
482*7dd7cddfSDavid du Colombier	if(convcount == 0) {
483*7dd7cddfSDavid du Colombier		initfmt();
484*7dd7cddfSDavid du Colombier		n = 0;
485*7dd7cddfSDavid du Colombier		if(fp->chr >= 0 && fp->chr < MAXFMT)
486*7dd7cddfSDavid du Colombier			n = fmtindex[fp->chr];
487*7dd7cddfSDavid du Colombier		return (*fmtconv[n])(arg, fp);
488*7dd7cddfSDavid du Colombier	}
489*7dd7cddfSDavid du Colombier	s[0] = '*';
490*7dd7cddfSDavid du Colombier	s[1] = fp->chr;
491*7dd7cddfSDavid du Colombier	s[2] = '*';
492*7dd7cddfSDavid du Colombier	s[3] = 0;
493*7dd7cddfSDavid du Colombier	fp->f1 = 0;
494*7dd7cddfSDavid du Colombier	fp->f2 = NONE;
495*7dd7cddfSDavid du Colombier	fp->f3 = 0;
496*7dd7cddfSDavid du Colombier	strconv(s, fp);
497*7dd7cddfSDavid du Colombier	return 0;
498*7dd7cddfSDavid du Colombier}
499*7dd7cddfSDavid du Colombier
500*7dd7cddfSDavid du Colombierstatic
501*7dd7cddfSDavid du Colombierint
502*7dd7cddfSDavid du Colombierrconv(va_list*, Fconv *fp)
503*7dd7cddfSDavid du Colombier{
504*7dd7cddfSDavid du Colombier	char s[ERRLEN];
505*7dd7cddfSDavid du Colombier
506*7dd7cddfSDavid du Colombier	s[0] = 0;
507*7dd7cddfSDavid du Colombier	errstr(s);
508*7dd7cddfSDavid du Colombier	fp->f2 = NONE;
509*7dd7cddfSDavid du Colombier	strconv(s, fp);
510*7dd7cddfSDavid du Colombier	return 0;
511*7dd7cddfSDavid du Colombier}
512*7dd7cddfSDavid du Colombier
513*7dd7cddfSDavid du Colombierstatic
514*7dd7cddfSDavid du Colombierint
515*7dd7cddfSDavid du Colombiercconv(va_list *arg, Fconv *fp)
516*7dd7cddfSDavid du Colombier{
517*7dd7cddfSDavid du Colombier	char s[10];
518*7dd7cddfSDavid du Colombier	Rune rune;
519*7dd7cddfSDavid du Colombier
520*7dd7cddfSDavid du Colombier	rune = va_arg(*arg, int);
521*7dd7cddfSDavid du Colombier	if(fp->chr == 'c')
522*7dd7cddfSDavid du Colombier		rune &= 0xff;
523*7dd7cddfSDavid du Colombier	s[runetochar(s, &rune)] = 0;
524*7dd7cddfSDavid du Colombier
525*7dd7cddfSDavid du Colombier	fp->f2 = NONE;
526*7dd7cddfSDavid du Colombier	strconv(s, fp);
527*7dd7cddfSDavid du Colombier	return 0;
528*7dd7cddfSDavid du Colombier}
529*7dd7cddfSDavid du Colombier
530*7dd7cddfSDavid du Colombierstatic
531*7dd7cddfSDavid du Colombierint
532*7dd7cddfSDavid du Colombiersconv(va_list *arg, Fconv *fp)
533*7dd7cddfSDavid du Colombier{
534*7dd7cddfSDavid du Colombier	char *s;
535*7dd7cddfSDavid du Colombier	Rune *r;
536*7dd7cddfSDavid du Colombier
537*7dd7cddfSDavid du Colombier	if(fp->chr == 's') {
538*7dd7cddfSDavid du Colombier		s = va_arg(*arg, char*);
539*7dd7cddfSDavid du Colombier		if(s == 0)
540*7dd7cddfSDavid du Colombier			s = "<null>";
541*7dd7cddfSDavid du Colombier		strconv(s, fp);
542*7dd7cddfSDavid du Colombier	} else {
543*7dd7cddfSDavid du Colombier		r = va_arg(*arg, Rune*);
544*7dd7cddfSDavid du Colombier		if(r == 0)
545*7dd7cddfSDavid du Colombier			r = L"<null>";
546*7dd7cddfSDavid du Colombier		Strconv(r, fp);
547*7dd7cddfSDavid du Colombier	}
548*7dd7cddfSDavid du Colombier	return 0;
549*7dd7cddfSDavid du Colombier}
550*7dd7cddfSDavid du Colombier
551*7dd7cddfSDavid du Colombierstatic
552*7dd7cddfSDavid du Colombierint
553*7dd7cddfSDavid du Colombierpercent(va_list*, Fconv *fp)
554*7dd7cddfSDavid du Colombier{
555*7dd7cddfSDavid du Colombier
556*7dd7cddfSDavid du Colombier	if(fp->out < fp->eout)
557*7dd7cddfSDavid du Colombier		*fp->out++ = '%';
558*7dd7cddfSDavid du Colombier	printcol++;
559*7dd7cddfSDavid du Colombier	return 0;
560*7dd7cddfSDavid du Colombier}
561*7dd7cddfSDavid du Colombier
562*7dd7cddfSDavid du Colombierstatic
563*7dd7cddfSDavid du Colombierint
564*7dd7cddfSDavid du Colombiercolumn(va_list *arg, Fconv *fp)
565*7dd7cddfSDavid du Colombier{
566*7dd7cddfSDavid du Colombier	int col, pc;
567*7dd7cddfSDavid du Colombier
568*7dd7cddfSDavid du Colombier	col = va_arg(*arg, int);
569*7dd7cddfSDavid du Colombier	while(fp->out < fp->eout && printcol < col) {
570*7dd7cddfSDavid du Colombier		pc = (printcol+8) & ~7;
571*7dd7cddfSDavid du Colombier		if(pc <= col) {
572*7dd7cddfSDavid du Colombier			*fp->out++ = '\t';
573*7dd7cddfSDavid du Colombier			printcol = pc;
574*7dd7cddfSDavid du Colombier		} else {
575*7dd7cddfSDavid du Colombier			*fp->out++ = ' ';
576*7dd7cddfSDavid du Colombier			printcol++;
577*7dd7cddfSDavid du Colombier		}
578*7dd7cddfSDavid du Colombier	}
579*7dd7cddfSDavid du Colombier	return 0;
580*7dd7cddfSDavid du Colombier}
581*7dd7cddfSDavid du Colombier
582*7dd7cddfSDavid du Colombierstatic
583*7dd7cddfSDavid du Colombierint
584*7dd7cddfSDavid du Colombierflags(va_list*, Fconv *fp)
585*7dd7cddfSDavid du Colombier{
586*7dd7cddfSDavid du Colombier	int f;
587*7dd7cddfSDavid du Colombier
588*7dd7cddfSDavid du Colombier	f = 0;
589*7dd7cddfSDavid du Colombier	switch(fp->chr) {
590*7dd7cddfSDavid du Colombier	case '+':
591*7dd7cddfSDavid du Colombier		f = FPLUS;
592*7dd7cddfSDavid du Colombier		break;
593*7dd7cddfSDavid du Colombier
594*7dd7cddfSDavid du Colombier	case '-':
595*7dd7cddfSDavid du Colombier		f = FMINUS;
596*7dd7cddfSDavid du Colombier		break;
597*7dd7cddfSDavid du Colombier
598*7dd7cddfSDavid du Colombier	case '#':
599*7dd7cddfSDavid du Colombier		f = FSHARP;
600*7dd7cddfSDavid du Colombier		break;
601*7dd7cddfSDavid du Colombier
602*7dd7cddfSDavid du Colombier	case 'h':
603*7dd7cddfSDavid du Colombier		f = FSHORT;
604*7dd7cddfSDavid du Colombier		break;
605*7dd7cddfSDavid du Colombier
606*7dd7cddfSDavid du Colombier	case 'l':
607*7dd7cddfSDavid du Colombier		f = FLONG;
608*7dd7cddfSDavid du Colombier		if(fp->f3 & FLONG)
609*7dd7cddfSDavid du Colombier			f = FVLONG;
610*7dd7cddfSDavid du Colombier		break;
611*7dd7cddfSDavid du Colombier
612*7dd7cddfSDavid du Colombier	case 'u':
613*7dd7cddfSDavid du Colombier		f = FUNSIGN;
614*7dd7cddfSDavid du Colombier		break;
615*7dd7cddfSDavid du Colombier	}
616*7dd7cddfSDavid du Colombier	return -f;
617*7dd7cddfSDavid du Colombier}
618