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