xref: /plan9/sys/src/ape/lib/fmt/dofmt.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
1*40ef9009SDavid du Colombier /*
2*40ef9009SDavid du Colombier  * The authors of this software are Rob Pike and Ken Thompson.
3*40ef9009SDavid du Colombier  *              Copyright (c) 2002 by Lucent Technologies.
4*40ef9009SDavid du Colombier  * Permission to use, copy, modify, and distribute this software for any
5*40ef9009SDavid du Colombier  * purpose without fee is hereby granted, provided that this entire notice
6*40ef9009SDavid du Colombier  * is included in all copies of any software which is or includes a copy
7*40ef9009SDavid du Colombier  * or modification of this software and in all copies of the supporting
8*40ef9009SDavid du Colombier  * documentation for such software.
9*40ef9009SDavid du Colombier  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10*40ef9009SDavid du Colombier  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
11*40ef9009SDavid du Colombier  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12*40ef9009SDavid du Colombier  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13*40ef9009SDavid du Colombier  */
14*40ef9009SDavid du Colombier #include <stdarg.h>
15*40ef9009SDavid du Colombier #include <string.h>
16*40ef9009SDavid du Colombier #include "utf.h"
17*40ef9009SDavid du Colombier #include "fmt.h"
18*40ef9009SDavid du Colombier #include "fmtdef.h"
19*40ef9009SDavid du Colombier 
20*40ef9009SDavid du Colombier /* format the output into f->to and return the number of characters fmted  */
21*40ef9009SDavid du Colombier int
dofmt(Fmt * f,char * fmt)22*40ef9009SDavid du Colombier dofmt(Fmt *f, char *fmt)
23*40ef9009SDavid du Colombier {
24*40ef9009SDavid du Colombier 	Rune rune, *rt, *rs;
25*40ef9009SDavid du Colombier 	int r;
26*40ef9009SDavid du Colombier 	char *t, *s;
27*40ef9009SDavid du Colombier 	int n, nfmt;
28*40ef9009SDavid du Colombier 
29*40ef9009SDavid du Colombier 	nfmt = f->nfmt;
30*40ef9009SDavid du Colombier 	for(;;){
31*40ef9009SDavid du Colombier 		if(f->runes){
32*40ef9009SDavid du Colombier 			rt = (Rune*)f->to;
33*40ef9009SDavid du Colombier 			rs = (Rune*)f->stop;
34*40ef9009SDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
35*40ef9009SDavid du Colombier 				if(r < Runeself)
36*40ef9009SDavid du Colombier 					fmt++;
37*40ef9009SDavid du Colombier 				else{
38*40ef9009SDavid du Colombier 					fmt += chartorune(&rune, fmt);
39*40ef9009SDavid du Colombier 					r = rune;
40*40ef9009SDavid du Colombier 				}
41*40ef9009SDavid du Colombier 				FMTRCHAR(f, rt, rs, r);
42*40ef9009SDavid du Colombier 			}
43*40ef9009SDavid du Colombier 			fmt++;
44*40ef9009SDavid du Colombier 			f->nfmt += rt - (Rune *)f->to;
45*40ef9009SDavid du Colombier 			f->to = rt;
46*40ef9009SDavid du Colombier 			if(!r)
47*40ef9009SDavid du Colombier 				return f->nfmt - nfmt;
48*40ef9009SDavid du Colombier 			f->stop = rs;
49*40ef9009SDavid du Colombier 		}else{
50*40ef9009SDavid du Colombier 			t = (char*)f->to;
51*40ef9009SDavid du Colombier 			s = (char*)f->stop;
52*40ef9009SDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
53*40ef9009SDavid du Colombier 				if(r < Runeself){
54*40ef9009SDavid du Colombier 					FMTCHAR(f, t, s, r);
55*40ef9009SDavid du Colombier 					fmt++;
56*40ef9009SDavid du Colombier 				}else{
57*40ef9009SDavid du Colombier 					n = chartorune(&rune, fmt);
58*40ef9009SDavid du Colombier 					if(t + n > s){
59*40ef9009SDavid du Colombier 						t = (char*)__fmtflush(f, t, n);
60*40ef9009SDavid du Colombier 						if(t != nil)
61*40ef9009SDavid du Colombier 							s = (char*)f->stop;
62*40ef9009SDavid du Colombier 						else
63*40ef9009SDavid du Colombier 							return -1;
64*40ef9009SDavid du Colombier 					}
65*40ef9009SDavid du Colombier 					while(n--)
66*40ef9009SDavid du Colombier 						*t++ = *fmt++;
67*40ef9009SDavid du Colombier 				}
68*40ef9009SDavid du Colombier 			}
69*40ef9009SDavid du Colombier 			fmt++;
70*40ef9009SDavid du Colombier 			f->nfmt += t - (char *)f->to;
71*40ef9009SDavid du Colombier 			f->to = t;
72*40ef9009SDavid du Colombier 			if(!r)
73*40ef9009SDavid du Colombier 				return f->nfmt - nfmt;
74*40ef9009SDavid du Colombier 			f->stop = s;
75*40ef9009SDavid du Colombier 		}
76*40ef9009SDavid du Colombier 
77*40ef9009SDavid du Colombier 		fmt = (char*)__fmtdispatch(f, fmt, 0);
78*40ef9009SDavid du Colombier 		if(fmt == nil)
79*40ef9009SDavid du Colombier 			return -1;
80*40ef9009SDavid du Colombier 	}
81*40ef9009SDavid du Colombier }
82*40ef9009SDavid du Colombier 
83*40ef9009SDavid du Colombier void *
__fmtflush(Fmt * f,void * t,int len)84*40ef9009SDavid du Colombier __fmtflush(Fmt *f, void *t, int len)
85*40ef9009SDavid du Colombier {
86*40ef9009SDavid du Colombier 	if(f->runes)
87*40ef9009SDavid du Colombier 		f->nfmt += (Rune*)t - (Rune*)f->to;
88*40ef9009SDavid du Colombier 	else
89*40ef9009SDavid du Colombier 		f->nfmt += (char*)t - (char *)f->to;
90*40ef9009SDavid du Colombier 	f->to = t;
91*40ef9009SDavid du Colombier 	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
92*40ef9009SDavid du Colombier 		f->stop = f->to;
93*40ef9009SDavid du Colombier 		return nil;
94*40ef9009SDavid du Colombier 	}
95*40ef9009SDavid du Colombier 	return f->to;
96*40ef9009SDavid du Colombier }
97*40ef9009SDavid du Colombier 
98*40ef9009SDavid du Colombier /*
99*40ef9009SDavid du Colombier  * put a formatted block of memory sz bytes long of n runes into the output buffer,
100*40ef9009SDavid du Colombier  * left/right justified in a field of at least f->width charactes
101*40ef9009SDavid du Colombier  */
102*40ef9009SDavid du Colombier int
__fmtpad(Fmt * f,int n)103*40ef9009SDavid du Colombier __fmtpad(Fmt *f, int n)
104*40ef9009SDavid du Colombier {
105*40ef9009SDavid du Colombier 	char *t, *s;
106*40ef9009SDavid du Colombier 	int i;
107*40ef9009SDavid du Colombier 
108*40ef9009SDavid du Colombier 	t = (char*)f->to;
109*40ef9009SDavid du Colombier 	s = (char*)f->stop;
110*40ef9009SDavid du Colombier 	for(i = 0; i < n; i++)
111*40ef9009SDavid du Colombier 		FMTCHAR(f, t, s, ' ');
112*40ef9009SDavid du Colombier 	f->nfmt += t - (char *)f->to;
113*40ef9009SDavid du Colombier 	f->to = t;
114*40ef9009SDavid du Colombier 	return 0;
115*40ef9009SDavid du Colombier }
116*40ef9009SDavid du Colombier 
117*40ef9009SDavid du Colombier int
__rfmtpad(Fmt * f,int n)118*40ef9009SDavid du Colombier __rfmtpad(Fmt *f, int n)
119*40ef9009SDavid du Colombier {
120*40ef9009SDavid du Colombier 	Rune *t, *s;
121*40ef9009SDavid du Colombier 	int i;
122*40ef9009SDavid du Colombier 
123*40ef9009SDavid du Colombier 	t = (Rune*)f->to;
124*40ef9009SDavid du Colombier 	s = (Rune*)f->stop;
125*40ef9009SDavid du Colombier 	for(i = 0; i < n; i++)
126*40ef9009SDavid du Colombier 		FMTRCHAR(f, t, s, ' ');
127*40ef9009SDavid du Colombier 	f->nfmt += t - (Rune *)f->to;
128*40ef9009SDavid du Colombier 	f->to = t;
129*40ef9009SDavid du Colombier 	return 0;
130*40ef9009SDavid du Colombier }
131*40ef9009SDavid du Colombier 
132*40ef9009SDavid du Colombier int
__fmtcpy(Fmt * f,const void * vm,int n,int sz)133*40ef9009SDavid du Colombier __fmtcpy(Fmt *f, const void *vm, int n, int sz)
134*40ef9009SDavid du Colombier {
135*40ef9009SDavid du Colombier 	Rune *rt, *rs, r;
136*40ef9009SDavid du Colombier 	char *t, *s, *m, *me;
137*40ef9009SDavid du Colombier 	ulong fl;
138*40ef9009SDavid du Colombier 	int nc, w;
139*40ef9009SDavid du Colombier 
140*40ef9009SDavid du Colombier 	m = (char*)vm;
141*40ef9009SDavid du Colombier 	me = m + sz;
142*40ef9009SDavid du Colombier 	w = f->width;
143*40ef9009SDavid du Colombier 	fl = f->flags;
144*40ef9009SDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
145*40ef9009SDavid du Colombier 		n = f->prec;
146*40ef9009SDavid du Colombier 	if(f->runes){
147*40ef9009SDavid du Colombier 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
148*40ef9009SDavid du Colombier 			return -1;
149*40ef9009SDavid du Colombier 		rt = (Rune*)f->to;
150*40ef9009SDavid du Colombier 		rs = (Rune*)f->stop;
151*40ef9009SDavid du Colombier 		for(nc = n; nc > 0; nc--){
152*40ef9009SDavid du Colombier 			r = *(uchar*)m;
153*40ef9009SDavid du Colombier 			if(r < Runeself)
154*40ef9009SDavid du Colombier 				m++;
155*40ef9009SDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
156*40ef9009SDavid du Colombier 				m += chartorune(&r, m);
157*40ef9009SDavid du Colombier 			else
158*40ef9009SDavid du Colombier 				break;
159*40ef9009SDavid du Colombier 			FMTRCHAR(f, rt, rs, r);
160*40ef9009SDavid du Colombier 		}
161*40ef9009SDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
162*40ef9009SDavid du Colombier 		f->to = rt;
163*40ef9009SDavid du Colombier 		if(m < me)
164*40ef9009SDavid du Colombier 			return -1;
165*40ef9009SDavid du Colombier 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
166*40ef9009SDavid du Colombier 			return -1;
167*40ef9009SDavid du Colombier 	}else{
168*40ef9009SDavid du Colombier 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
169*40ef9009SDavid du Colombier 			return -1;
170*40ef9009SDavid du Colombier 		t = (char*)f->to;
171*40ef9009SDavid du Colombier 		s = (char*)f->stop;
172*40ef9009SDavid du Colombier 		for(nc = n; nc > 0; nc--){
173*40ef9009SDavid du Colombier 			r = *(uchar*)m;
174*40ef9009SDavid du Colombier 			if(r < Runeself)
175*40ef9009SDavid du Colombier 				m++;
176*40ef9009SDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
177*40ef9009SDavid du Colombier 				m += chartorune(&r, m);
178*40ef9009SDavid du Colombier 			else
179*40ef9009SDavid du Colombier 				break;
180*40ef9009SDavid du Colombier 			FMTRUNE(f, t, s, r);
181*40ef9009SDavid du Colombier 		}
182*40ef9009SDavid du Colombier 		f->nfmt += t - (char *)f->to;
183*40ef9009SDavid du Colombier 		f->to = t;
184*40ef9009SDavid du Colombier 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
185*40ef9009SDavid du Colombier 			return -1;
186*40ef9009SDavid du Colombier 	}
187*40ef9009SDavid du Colombier 	return 0;
188*40ef9009SDavid du Colombier }
189*40ef9009SDavid du Colombier 
190*40ef9009SDavid du Colombier int
__fmtrcpy(Fmt * f,const void * vm,int n)191*40ef9009SDavid du Colombier __fmtrcpy(Fmt *f, const void *vm, int n)
192*40ef9009SDavid du Colombier {
193*40ef9009SDavid du Colombier 	Rune r, *m, *me, *rt, *rs;
194*40ef9009SDavid du Colombier 	char *t, *s;
195*40ef9009SDavid du Colombier 	ulong fl;
196*40ef9009SDavid du Colombier 	int w;
197*40ef9009SDavid du Colombier 
198*40ef9009SDavid du Colombier 	m = (Rune*)vm;
199*40ef9009SDavid du Colombier 	w = f->width;
200*40ef9009SDavid du Colombier 	fl = f->flags;
201*40ef9009SDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
202*40ef9009SDavid du Colombier 		n = f->prec;
203*40ef9009SDavid du Colombier 	if(f->runes){
204*40ef9009SDavid du Colombier 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
205*40ef9009SDavid du Colombier 			return -1;
206*40ef9009SDavid du Colombier 		rt = (Rune*)f->to;
207*40ef9009SDavid du Colombier 		rs = (Rune*)f->stop;
208*40ef9009SDavid du Colombier 		for(me = m + n; m < me; m++)
209*40ef9009SDavid du Colombier 			FMTRCHAR(f, rt, rs, *m);
210*40ef9009SDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
211*40ef9009SDavid du Colombier 		f->to = rt;
212*40ef9009SDavid du Colombier 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
213*40ef9009SDavid du Colombier 			return -1;
214*40ef9009SDavid du Colombier 	}else{
215*40ef9009SDavid du Colombier 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
216*40ef9009SDavid du Colombier 			return -1;
217*40ef9009SDavid du Colombier 		t = (char*)f->to;
218*40ef9009SDavid du Colombier 		s = (char*)f->stop;
219*40ef9009SDavid du Colombier 		for(me = m + n; m < me; m++){
220*40ef9009SDavid du Colombier 			r = *m;
221*40ef9009SDavid du Colombier 			FMTRUNE(f, t, s, r);
222*40ef9009SDavid du Colombier 		}
223*40ef9009SDavid du Colombier 		f->nfmt += t - (char *)f->to;
224*40ef9009SDavid du Colombier 		f->to = t;
225*40ef9009SDavid du Colombier 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
226*40ef9009SDavid du Colombier 			return -1;
227*40ef9009SDavid du Colombier 	}
228*40ef9009SDavid du Colombier 	return 0;
229*40ef9009SDavid du Colombier }
230*40ef9009SDavid du Colombier 
231*40ef9009SDavid du Colombier /* fmt out one character */
232*40ef9009SDavid du Colombier int
__charfmt(Fmt * f)233*40ef9009SDavid du Colombier __charfmt(Fmt *f)
234*40ef9009SDavid du Colombier {
235*40ef9009SDavid du Colombier 	char x[1];
236*40ef9009SDavid du Colombier 
237*40ef9009SDavid du Colombier 	x[0] = va_arg(f->args, int);
238*40ef9009SDavid du Colombier 	f->prec = 1;
239*40ef9009SDavid du Colombier 	return __fmtcpy(f, (const char*)x, 1, 1);
240*40ef9009SDavid du Colombier }
241*40ef9009SDavid du Colombier 
242*40ef9009SDavid du Colombier /* fmt out one rune */
243*40ef9009SDavid du Colombier int
__runefmt(Fmt * f)244*40ef9009SDavid du Colombier __runefmt(Fmt *f)
245*40ef9009SDavid du Colombier {
246*40ef9009SDavid du Colombier 	Rune x[1];
247*40ef9009SDavid du Colombier 
248*40ef9009SDavid du Colombier 	x[0] = va_arg(f->args, int);
249*40ef9009SDavid du Colombier 	return __fmtrcpy(f, (const void*)x, 1);
250*40ef9009SDavid du Colombier }
251*40ef9009SDavid du Colombier 
252*40ef9009SDavid du Colombier /* public helper routine: fmt out a null terminated string already in hand */
253*40ef9009SDavid du Colombier int
fmtstrcpy(Fmt * f,char * s)254*40ef9009SDavid du Colombier fmtstrcpy(Fmt *f, char *s)
255*40ef9009SDavid du Colombier {
256*40ef9009SDavid du Colombier 	int p, i;
257*40ef9009SDavid du Colombier 	if(!s)
258*40ef9009SDavid du Colombier 		return __fmtcpy(f, "<nil>", 5, 5);
259*40ef9009SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
260*40ef9009SDavid du Colombier 	if(f->flags & FmtPrec){
261*40ef9009SDavid du Colombier 		p = f->prec;
262*40ef9009SDavid du Colombier 		for(i = 0; i < p; i++)
263*40ef9009SDavid du Colombier 			if(s[i] == 0)
264*40ef9009SDavid du Colombier 				break;
265*40ef9009SDavid du Colombier 		return __fmtcpy(f, s, utfnlen(s, i), i);	/* BUG?: won't print a partial rune at end */
266*40ef9009SDavid du Colombier 	}
267*40ef9009SDavid du Colombier 
268*40ef9009SDavid du Colombier 	return __fmtcpy(f, s, utflen(s), strlen(s));
269*40ef9009SDavid du Colombier }
270*40ef9009SDavid du Colombier 
271*40ef9009SDavid du Colombier /* fmt out a null terminated utf string */
272*40ef9009SDavid du Colombier int
__strfmt(Fmt * f)273*40ef9009SDavid du Colombier __strfmt(Fmt *f)
274*40ef9009SDavid du Colombier {
275*40ef9009SDavid du Colombier 	char *s;
276*40ef9009SDavid du Colombier 
277*40ef9009SDavid du Colombier 	s = va_arg(f->args, char *);
278*40ef9009SDavid du Colombier 	return fmtstrcpy(f, s);
279*40ef9009SDavid du Colombier }
280*40ef9009SDavid du Colombier 
281*40ef9009SDavid du Colombier /* public helper routine: fmt out a null terminated rune string already in hand */
282*40ef9009SDavid du Colombier int
fmtrunestrcpy(Fmt * f,Rune * s)283*40ef9009SDavid du Colombier fmtrunestrcpy(Fmt *f, Rune *s)
284*40ef9009SDavid du Colombier {
285*40ef9009SDavid du Colombier 	Rune *e;
286*40ef9009SDavid du Colombier 	int n, p;
287*40ef9009SDavid du Colombier 
288*40ef9009SDavid du Colombier 	if(!s)
289*40ef9009SDavid du Colombier 		return __fmtcpy(f, "<nil>", 5, 5);
290*40ef9009SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
291*40ef9009SDavid du Colombier 	if(f->flags & FmtPrec){
292*40ef9009SDavid du Colombier 		p = f->prec;
293*40ef9009SDavid du Colombier 		for(n = 0; n < p; n++)
294*40ef9009SDavid du Colombier 			if(s[n] == 0)
295*40ef9009SDavid du Colombier 				break;
296*40ef9009SDavid du Colombier 	}else{
297*40ef9009SDavid du Colombier 		for(e = s; *e; e++)
298*40ef9009SDavid du Colombier 			;
299*40ef9009SDavid du Colombier 		n = e - s;
300*40ef9009SDavid du Colombier 	}
301*40ef9009SDavid du Colombier 	return __fmtrcpy(f, s, n);
302*40ef9009SDavid du Colombier }
303*40ef9009SDavid du Colombier 
304*40ef9009SDavid du Colombier /* fmt out a null terminated rune string */
305*40ef9009SDavid du Colombier int
__runesfmt(Fmt * f)306*40ef9009SDavid du Colombier __runesfmt(Fmt *f)
307*40ef9009SDavid du Colombier {
308*40ef9009SDavid du Colombier 	Rune *s;
309*40ef9009SDavid du Colombier 
310*40ef9009SDavid du Colombier 	s = va_arg(f->args, Rune *);
311*40ef9009SDavid du Colombier 	return fmtrunestrcpy(f, s);
312*40ef9009SDavid du Colombier }
313*40ef9009SDavid du Colombier 
314*40ef9009SDavid du Colombier /* fmt a % */
315*40ef9009SDavid du Colombier int
__percentfmt(Fmt * f)316*40ef9009SDavid du Colombier __percentfmt(Fmt *f)
317*40ef9009SDavid du Colombier {
318*40ef9009SDavid du Colombier 	Rune x[1];
319*40ef9009SDavid du Colombier 
320*40ef9009SDavid du Colombier 	x[0] = f->r;
321*40ef9009SDavid du Colombier 	f->prec = 1;
322*40ef9009SDavid du Colombier 	return __fmtrcpy(f, (const void*)x, 1);
323*40ef9009SDavid du Colombier }
324*40ef9009SDavid du Colombier 
325*40ef9009SDavid du Colombier /* fmt an integer */
326*40ef9009SDavid du Colombier int
__ifmt(Fmt * f)327*40ef9009SDavid du Colombier __ifmt(Fmt *f)
328*40ef9009SDavid du Colombier {
329*40ef9009SDavid du Colombier 	char buf[70], *p, *conv;
330*40ef9009SDavid du Colombier 	uvlong vu;
331*40ef9009SDavid du Colombier 	ulong u;
332*40ef9009SDavid du Colombier 	int neg, base, i, n, fl, w, isv;
333*40ef9009SDavid du Colombier 
334*40ef9009SDavid du Colombier 	neg = 0;
335*40ef9009SDavid du Colombier 	fl = f->flags;
336*40ef9009SDavid du Colombier 	isv = 0;
337*40ef9009SDavid du Colombier 	vu = 0;
338*40ef9009SDavid du Colombier 	u = 0;
339*40ef9009SDavid du Colombier 	/*
340*40ef9009SDavid du Colombier 	 * Unsigned verbs
341*40ef9009SDavid du Colombier 	 */
342*40ef9009SDavid du Colombier 	switch(f->r){
343*40ef9009SDavid du Colombier 	case 'o':
344*40ef9009SDavid du Colombier 	case 'u':
345*40ef9009SDavid du Colombier 	case 'x':
346*40ef9009SDavid du Colombier 	case 'X':
347*40ef9009SDavid du Colombier 		fl |= FmtUnsigned;
348*40ef9009SDavid du Colombier 		break;
349*40ef9009SDavid du Colombier 	}
350*40ef9009SDavid du Colombier 	if(f->r == 'p'){
351*40ef9009SDavid du Colombier 		u = (ulong)va_arg(f->args, void*);
352*40ef9009SDavid du Colombier 		f->r = 'x';
353*40ef9009SDavid du Colombier 		fl |= FmtUnsigned;
354*40ef9009SDavid du Colombier 	}else if(fl & FmtVLong){
355*40ef9009SDavid du Colombier 		isv = 1;
356*40ef9009SDavid du Colombier 		if(fl & FmtUnsigned)
357*40ef9009SDavid du Colombier 			vu = va_arg(f->args, uvlong);
358*40ef9009SDavid du Colombier 		else
359*40ef9009SDavid du Colombier 			vu = va_arg(f->args, vlong);
360*40ef9009SDavid du Colombier 	}else if(fl & FmtLong){
361*40ef9009SDavid du Colombier 		if(fl & FmtUnsigned)
362*40ef9009SDavid du Colombier 			u = va_arg(f->args, ulong);
363*40ef9009SDavid du Colombier 		else
364*40ef9009SDavid du Colombier 			u = va_arg(f->args, long);
365*40ef9009SDavid du Colombier 	}else if(fl & FmtByte){
366*40ef9009SDavid du Colombier 		if(fl & FmtUnsigned)
367*40ef9009SDavid du Colombier 			u = (uchar)va_arg(f->args, int);
368*40ef9009SDavid du Colombier 		else
369*40ef9009SDavid du Colombier 			u = (char)va_arg(f->args, int);
370*40ef9009SDavid du Colombier 	}else if(fl & FmtShort){
371*40ef9009SDavid du Colombier 		if(fl & FmtUnsigned)
372*40ef9009SDavid du Colombier 			u = (ushort)va_arg(f->args, int);
373*40ef9009SDavid du Colombier 		else
374*40ef9009SDavid du Colombier 			u = (short)va_arg(f->args, int);
375*40ef9009SDavid du Colombier 	}else{
376*40ef9009SDavid du Colombier 		if(fl & FmtUnsigned)
377*40ef9009SDavid du Colombier 			u = va_arg(f->args, uint);
378*40ef9009SDavid du Colombier 		else
379*40ef9009SDavid du Colombier 			u = va_arg(f->args, int);
380*40ef9009SDavid du Colombier 	}
381*40ef9009SDavid du Colombier 	conv = "0123456789abcdef";
382*40ef9009SDavid du Colombier 	switch(f->r){
383*40ef9009SDavid du Colombier 	case 'd':
384*40ef9009SDavid du Colombier 	case 'i':
385*40ef9009SDavid du Colombier 		base = 10;
386*40ef9009SDavid du Colombier 		break;
387*40ef9009SDavid du Colombier 	case 'u':
388*40ef9009SDavid du Colombier 		base = 10;
389*40ef9009SDavid du Colombier 		break;
390*40ef9009SDavid du Colombier 	case 'x':
391*40ef9009SDavid du Colombier 		base = 16;
392*40ef9009SDavid du Colombier 		break;
393*40ef9009SDavid du Colombier 	case 'X':
394*40ef9009SDavid du Colombier 		base = 16;
395*40ef9009SDavid du Colombier 		conv = "0123456789ABCDEF";
396*40ef9009SDavid du Colombier 		break;
397*40ef9009SDavid du Colombier 	case 'b':
398*40ef9009SDavid du Colombier 		base = 2;
399*40ef9009SDavid du Colombier 		break;
400*40ef9009SDavid du Colombier 	case 'o':
401*40ef9009SDavid du Colombier 		base = 8;
402*40ef9009SDavid du Colombier 		break;
403*40ef9009SDavid du Colombier 	default:
404*40ef9009SDavid du Colombier 		return -1;
405*40ef9009SDavid du Colombier 	}
406*40ef9009SDavid du Colombier 	if(!(fl & FmtUnsigned)){
407*40ef9009SDavid du Colombier 		if(isv && (vlong)vu < 0){
408*40ef9009SDavid du Colombier 			vu = -(vlong)vu;
409*40ef9009SDavid du Colombier 			neg = 1;
410*40ef9009SDavid du Colombier 		}else if(!isv && (long)u < 0){
411*40ef9009SDavid du Colombier 			u = -(long)u;
412*40ef9009SDavid du Colombier 			neg = 1;
413*40ef9009SDavid du Colombier 		}
414*40ef9009SDavid du Colombier 	}else{
415*40ef9009SDavid du Colombier 		fl &= ~(FmtSign|FmtSpace);	/* no + for unsigned conversions */
416*40ef9009SDavid du Colombier 	}
417*40ef9009SDavid du Colombier 	p = buf + sizeof buf - 1;
418*40ef9009SDavid du Colombier 	n = 0;
419*40ef9009SDavid du Colombier 	if(isv){
420*40ef9009SDavid du Colombier 		while(vu){
421*40ef9009SDavid du Colombier 			i = vu % base;
422*40ef9009SDavid du Colombier 			vu /= base;
423*40ef9009SDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
424*40ef9009SDavid du Colombier 				*p-- = ',';
425*40ef9009SDavid du Colombier 				n++;
426*40ef9009SDavid du Colombier 			}
427*40ef9009SDavid du Colombier 			*p-- = conv[i];
428*40ef9009SDavid du Colombier 			n++;
429*40ef9009SDavid du Colombier 		}
430*40ef9009SDavid du Colombier 	}else{
431*40ef9009SDavid du Colombier 		while(u){
432*40ef9009SDavid du Colombier 			i = u % base;
433*40ef9009SDavid du Colombier 			u /= base;
434*40ef9009SDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
435*40ef9009SDavid du Colombier 				*p-- = ',';
436*40ef9009SDavid du Colombier 				n++;
437*40ef9009SDavid du Colombier 			}
438*40ef9009SDavid du Colombier 			*p-- = conv[i];
439*40ef9009SDavid du Colombier 			n++;
440*40ef9009SDavid du Colombier 		}
441*40ef9009SDavid du Colombier 	}
442*40ef9009SDavid du Colombier 	if(n == 0){
443*40ef9009SDavid du Colombier 		if(!(fl & FmtPrec) || f->prec != 0){
444*40ef9009SDavid du Colombier 			*p-- = '0';
445*40ef9009SDavid du Colombier 			n = 1;
446*40ef9009SDavid du Colombier 		}
447*40ef9009SDavid du Colombier 		fl &= ~FmtSharp;
448*40ef9009SDavid du Colombier 	}
449*40ef9009SDavid du Colombier 	for(w = f->prec; n < w && p > buf+3; n++)
450*40ef9009SDavid du Colombier 		*p-- = '0';
451*40ef9009SDavid du Colombier 	if(neg || (fl & (FmtSign|FmtSpace)))
452*40ef9009SDavid du Colombier 		n++;
453*40ef9009SDavid du Colombier 	if(fl & FmtSharp){
454*40ef9009SDavid du Colombier 		if(base == 16)
455*40ef9009SDavid du Colombier 			n += 2;
456*40ef9009SDavid du Colombier 		else if(base == 8){
457*40ef9009SDavid du Colombier 			if(p[1] == '0')
458*40ef9009SDavid du Colombier 				fl &= ~FmtSharp;
459*40ef9009SDavid du Colombier 			else
460*40ef9009SDavid du Colombier 				n++;
461*40ef9009SDavid du Colombier 		}
462*40ef9009SDavid du Colombier 	}
463*40ef9009SDavid du Colombier 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
464*40ef9009SDavid du Colombier 		for(w = f->width; n < w && p > buf+3; n++)
465*40ef9009SDavid du Colombier 			*p-- = '0';
466*40ef9009SDavid du Colombier 		f->width = 0;
467*40ef9009SDavid du Colombier 	}
468*40ef9009SDavid du Colombier 	if(fl & FmtSharp){
469*40ef9009SDavid du Colombier 		if(base == 16)
470*40ef9009SDavid du Colombier 			*p-- = f->r;
471*40ef9009SDavid du Colombier 		if(base == 16 || base == 8)
472*40ef9009SDavid du Colombier 			*p-- = '0';
473*40ef9009SDavid du Colombier 	}
474*40ef9009SDavid du Colombier 	if(neg)
475*40ef9009SDavid du Colombier 		*p-- = '-';
476*40ef9009SDavid du Colombier 	else if(fl & FmtSign)
477*40ef9009SDavid du Colombier 		*p-- = '+';
478*40ef9009SDavid du Colombier 	else if(fl & FmtSpace)
479*40ef9009SDavid du Colombier 		*p-- = ' ';
480*40ef9009SDavid du Colombier 	f->flags &= ~FmtPrec;
481*40ef9009SDavid du Colombier 	return __fmtcpy(f, p + 1, n, n);
482*40ef9009SDavid du Colombier }
483*40ef9009SDavid du Colombier 
484*40ef9009SDavid du Colombier int
__countfmt(Fmt * f)485*40ef9009SDavid du Colombier __countfmt(Fmt *f)
486*40ef9009SDavid du Colombier {
487*40ef9009SDavid du Colombier 	void *p;
488*40ef9009SDavid du Colombier 	ulong fl;
489*40ef9009SDavid du Colombier 
490*40ef9009SDavid du Colombier 	fl = f->flags;
491*40ef9009SDavid du Colombier 	p = va_arg(f->args, void*);
492*40ef9009SDavid du Colombier 	if(fl & FmtVLong){
493*40ef9009SDavid du Colombier 		*(vlong*)p = f->nfmt;
494*40ef9009SDavid du Colombier 	}else if(fl & FmtLong){
495*40ef9009SDavid du Colombier 		*(long*)p = f->nfmt;
496*40ef9009SDavid du Colombier 	}else if(fl & FmtByte){
497*40ef9009SDavid du Colombier 		*(char*)p = f->nfmt;
498*40ef9009SDavid du Colombier 	}else if(fl & FmtShort){
499*40ef9009SDavid du Colombier 		*(short*)p = f->nfmt;
500*40ef9009SDavid du Colombier 	}else{
501*40ef9009SDavid du Colombier 		*(int*)p = f->nfmt;
502*40ef9009SDavid du Colombier 	}
503*40ef9009SDavid du Colombier 	return 0;
504*40ef9009SDavid du Colombier }
505*40ef9009SDavid du Colombier 
506*40ef9009SDavid du Colombier int
__flagfmt(Fmt * f)507*40ef9009SDavid du Colombier __flagfmt(Fmt *f)
508*40ef9009SDavid du Colombier {
509*40ef9009SDavid du Colombier 	switch(f->r){
510*40ef9009SDavid du Colombier 	case ',':
511*40ef9009SDavid du Colombier 		f->flags |= FmtComma;
512*40ef9009SDavid du Colombier 		break;
513*40ef9009SDavid du Colombier 	case '-':
514*40ef9009SDavid du Colombier 		f->flags |= FmtLeft;
515*40ef9009SDavid du Colombier 		break;
516*40ef9009SDavid du Colombier 	case '+':
517*40ef9009SDavid du Colombier 		f->flags |= FmtSign;
518*40ef9009SDavid du Colombier 		break;
519*40ef9009SDavid du Colombier 	case '#':
520*40ef9009SDavid du Colombier 		f->flags |= FmtSharp;
521*40ef9009SDavid du Colombier 		break;
522*40ef9009SDavid du Colombier 	case ' ':
523*40ef9009SDavid du Colombier 		f->flags |= FmtSpace;
524*40ef9009SDavid du Colombier 		break;
525*40ef9009SDavid du Colombier 	case 'u':
526*40ef9009SDavid du Colombier 		f->flags |= FmtUnsigned;
527*40ef9009SDavid du Colombier 		break;
528*40ef9009SDavid du Colombier 	case 'h':
529*40ef9009SDavid du Colombier 		if(f->flags & FmtShort)
530*40ef9009SDavid du Colombier 			f->flags |= FmtByte;
531*40ef9009SDavid du Colombier 		f->flags |= FmtShort;
532*40ef9009SDavid du Colombier 		break;
533*40ef9009SDavid du Colombier 	case 'L':
534*40ef9009SDavid du Colombier 		f->flags |= FmtLDouble;
535*40ef9009SDavid du Colombier 		break;
536*40ef9009SDavid du Colombier 	case 'l':
537*40ef9009SDavid du Colombier 		if(f->flags & FmtLong)
538*40ef9009SDavid du Colombier 			f->flags |= FmtVLong;
539*40ef9009SDavid du Colombier 		f->flags |= FmtLong;
540*40ef9009SDavid du Colombier 		break;
541*40ef9009SDavid du Colombier 	}
542*40ef9009SDavid du Colombier 	return 1;
543*40ef9009SDavid du Colombier }
544*40ef9009SDavid du Colombier 
545*40ef9009SDavid du Colombier /* default error format */
546*40ef9009SDavid du Colombier int
__badfmt(Fmt * f)547*40ef9009SDavid du Colombier __badfmt(Fmt *f)
548*40ef9009SDavid du Colombier {
549*40ef9009SDavid du Colombier 	char x[3];
550*40ef9009SDavid du Colombier 
551*40ef9009SDavid du Colombier 	x[0] = '%';
552*40ef9009SDavid du Colombier 	x[1] = f->r;
553*40ef9009SDavid du Colombier 	x[2] = '%';
554*40ef9009SDavid du Colombier 	f->prec = 3;
555*40ef9009SDavid du Colombier 	__fmtcpy(f, (const void*)x, 3, 3);
556*40ef9009SDavid du Colombier 	return 0;
557*40ef9009SDavid du Colombier }
558