xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libc/dofmt.c (revision 0d601874851962e88c6c60fdd2e637bba04e13c2)
1*0d601874SDavid du Colombier /*
2*0d601874SDavid du Colombier  * The authors of this software are Rob Pike and Ken Thompson.
3*0d601874SDavid du Colombier  *              Copyright (c) 2002 by Lucent Technologies.
4*0d601874SDavid du Colombier  * Permission to use, copy, modify, and distribute this software for any
5*0d601874SDavid du Colombier  * purpose without fee is hereby granted, provided that this entire notice
6*0d601874SDavid du Colombier  * is included in all copies of any software which is or includes a copy
7*0d601874SDavid du Colombier  * or modification of this software and in all copies of the supporting
8*0d601874SDavid du Colombier  * documentation for such software.
9*0d601874SDavid du Colombier  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10*0d601874SDavid du Colombier  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
11*0d601874SDavid du Colombier  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12*0d601874SDavid du Colombier  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13*0d601874SDavid du Colombier  */
148ccd4a63SDavid du Colombier #include <u.h>
158ccd4a63SDavid du Colombier #include <libc.h>
168ccd4a63SDavid du Colombier #include "fmtdef.h"
178ccd4a63SDavid du Colombier 
188ccd4a63SDavid du Colombier /* format the output into f->to and return the number of characters fmted  */
198ccd4a63SDavid du Colombier int
208ccd4a63SDavid du Colombier dofmt(Fmt *f, char *fmt)
218ccd4a63SDavid du Colombier {
228ccd4a63SDavid du Colombier 	Rune rune, *rt, *rs;
238ccd4a63SDavid du Colombier 	int r;
248ccd4a63SDavid du Colombier 	char *t, *s;
258ccd4a63SDavid du Colombier 	int n, nfmt;
268ccd4a63SDavid du Colombier 
278ccd4a63SDavid du Colombier 	nfmt = f->nfmt;
288ccd4a63SDavid du Colombier 	for(;;){
298ccd4a63SDavid du Colombier 		if(f->runes){
30*0d601874SDavid du Colombier 			rt = (Rune*)f->to;
31*0d601874SDavid du Colombier 			rs = (Rune*)f->stop;
328ccd4a63SDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
338ccd4a63SDavid du Colombier 				if(r < Runeself)
348ccd4a63SDavid du Colombier 					fmt++;
358ccd4a63SDavid du Colombier 				else{
368ccd4a63SDavid du Colombier 					fmt += chartorune(&rune, fmt);
378ccd4a63SDavid du Colombier 					r = rune;
388ccd4a63SDavid du Colombier 				}
398ccd4a63SDavid du Colombier 				FMTRCHAR(f, rt, rs, r);
408ccd4a63SDavid du Colombier 			}
418ccd4a63SDavid du Colombier 			fmt++;
428ccd4a63SDavid du Colombier 			f->nfmt += rt - (Rune *)f->to;
438ccd4a63SDavid du Colombier 			f->to = rt;
448ccd4a63SDavid du Colombier 			if(!r)
458ccd4a63SDavid du Colombier 				return f->nfmt - nfmt;
468ccd4a63SDavid du Colombier 			f->stop = rs;
478ccd4a63SDavid du Colombier 		}else{
48*0d601874SDavid du Colombier 			t = (char*)f->to;
49*0d601874SDavid du Colombier 			s = (char*)f->stop;
508ccd4a63SDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
518ccd4a63SDavid du Colombier 				if(r < Runeself){
528ccd4a63SDavid du Colombier 					FMTCHAR(f, t, s, r);
538ccd4a63SDavid du Colombier 					fmt++;
548ccd4a63SDavid du Colombier 				}else{
558ccd4a63SDavid du Colombier 					n = chartorune(&rune, fmt);
568ccd4a63SDavid du Colombier 					if(t + n > s){
57*0d601874SDavid du Colombier 						t = (char*)__fmtflush(f, t, n);
588ccd4a63SDavid du Colombier 						if(t != nil)
59*0d601874SDavid du Colombier 							s = (char*)f->stop;
608ccd4a63SDavid du Colombier 						else
618ccd4a63SDavid du Colombier 							return -1;
628ccd4a63SDavid du Colombier 					}
638ccd4a63SDavid du Colombier 					while(n--)
648ccd4a63SDavid du Colombier 						*t++ = *fmt++;
658ccd4a63SDavid du Colombier 				}
668ccd4a63SDavid du Colombier 			}
678ccd4a63SDavid du Colombier 			fmt++;
688ccd4a63SDavid du Colombier 			f->nfmt += t - (char *)f->to;
698ccd4a63SDavid du Colombier 			f->to = t;
708ccd4a63SDavid du Colombier 			if(!r)
718ccd4a63SDavid du Colombier 				return f->nfmt - nfmt;
728ccd4a63SDavid du Colombier 			f->stop = s;
738ccd4a63SDavid du Colombier 		}
748ccd4a63SDavid du Colombier 
75*0d601874SDavid du Colombier 		fmt = (char*)__fmtdispatch(f, fmt, 0);
768ccd4a63SDavid du Colombier 		if(fmt == nil)
778ccd4a63SDavid du Colombier 			return -1;
788ccd4a63SDavid du Colombier 	}
798ccd4a63SDavid du Colombier }
808ccd4a63SDavid du Colombier 
818ccd4a63SDavid du Colombier void *
82*0d601874SDavid du Colombier __fmtflush(Fmt *f, void *t, int len)
838ccd4a63SDavid du Colombier {
848ccd4a63SDavid du Colombier 	if(f->runes)
858ccd4a63SDavid du Colombier 		f->nfmt += (Rune*)t - (Rune*)f->to;
868ccd4a63SDavid du Colombier 	else
878ccd4a63SDavid du Colombier 		f->nfmt += (char*)t - (char *)f->to;
888ccd4a63SDavid du Colombier 	f->to = t;
898ccd4a63SDavid du Colombier 	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
908ccd4a63SDavid du Colombier 		f->stop = f->to;
918ccd4a63SDavid du Colombier 		return nil;
928ccd4a63SDavid du Colombier 	}
938ccd4a63SDavid du Colombier 	return f->to;
948ccd4a63SDavid du Colombier }
958ccd4a63SDavid du Colombier 
968ccd4a63SDavid du Colombier /*
978ccd4a63SDavid du Colombier  * put a formatted block of memory sz bytes long of n runes into the output buffer,
988ccd4a63SDavid du Colombier  * left/right justified in a field of at least f->width charactes
998ccd4a63SDavid du Colombier  */
1008ccd4a63SDavid du Colombier int
101*0d601874SDavid du Colombier __fmtpad(Fmt *f, int n)
1028ccd4a63SDavid du Colombier {
1038ccd4a63SDavid du Colombier 	char *t, *s;
1048ccd4a63SDavid du Colombier 	int i;
1058ccd4a63SDavid du Colombier 
106*0d601874SDavid du Colombier 	t = (char*)f->to;
107*0d601874SDavid du Colombier 	s = (char*)f->stop;
1088ccd4a63SDavid du Colombier 	for(i = 0; i < n; i++)
1098ccd4a63SDavid du Colombier 		FMTCHAR(f, t, s, ' ');
1108ccd4a63SDavid du Colombier 	f->nfmt += t - (char *)f->to;
1118ccd4a63SDavid du Colombier 	f->to = t;
1128ccd4a63SDavid du Colombier 	return 0;
1138ccd4a63SDavid du Colombier }
1148ccd4a63SDavid du Colombier 
1158ccd4a63SDavid du Colombier int
116*0d601874SDavid du Colombier __rfmtpad(Fmt *f, int n)
1178ccd4a63SDavid du Colombier {
1188ccd4a63SDavid du Colombier 	Rune *t, *s;
1198ccd4a63SDavid du Colombier 	int i;
1208ccd4a63SDavid du Colombier 
121*0d601874SDavid du Colombier 	t = (Rune*)f->to;
122*0d601874SDavid du Colombier 	s = (Rune*)f->stop;
1238ccd4a63SDavid du Colombier 	for(i = 0; i < n; i++)
1248ccd4a63SDavid du Colombier 		FMTRCHAR(f, t, s, ' ');
1258ccd4a63SDavid du Colombier 	f->nfmt += t - (Rune *)f->to;
1268ccd4a63SDavid du Colombier 	f->to = t;
1278ccd4a63SDavid du Colombier 	return 0;
1288ccd4a63SDavid du Colombier }
1298ccd4a63SDavid du Colombier 
1308ccd4a63SDavid du Colombier int
131*0d601874SDavid du Colombier __fmtcpy(Fmt *f, const void *vm, int n, int sz)
1328ccd4a63SDavid du Colombier {
1338ccd4a63SDavid du Colombier 	Rune *rt, *rs, r;
1348ccd4a63SDavid du Colombier 	char *t, *s, *m, *me;
1358ccd4a63SDavid du Colombier 	ulong fl;
1368ccd4a63SDavid du Colombier 	int nc, w;
1378ccd4a63SDavid du Colombier 
138*0d601874SDavid du Colombier 	m = (char*)vm;
1398ccd4a63SDavid du Colombier 	me = m + sz;
1408ccd4a63SDavid du Colombier 	w = f->width;
1418ccd4a63SDavid du Colombier 	fl = f->flags;
1428ccd4a63SDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
1438ccd4a63SDavid du Colombier 		n = f->prec;
1448ccd4a63SDavid du Colombier 	if(f->runes){
145*0d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
1468ccd4a63SDavid du Colombier 			return -1;
147*0d601874SDavid du Colombier 		rt = (Rune*)f->to;
148*0d601874SDavid du Colombier 		rs = (Rune*)f->stop;
1498ccd4a63SDavid du Colombier 		for(nc = n; nc > 0; nc--){
1508ccd4a63SDavid du Colombier 			r = *(uchar*)m;
1518ccd4a63SDavid du Colombier 			if(r < Runeself)
1528ccd4a63SDavid du Colombier 				m++;
1538ccd4a63SDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
1548ccd4a63SDavid du Colombier 				m += chartorune(&r, m);
1558ccd4a63SDavid du Colombier 			else
1568ccd4a63SDavid du Colombier 				break;
1578ccd4a63SDavid du Colombier 			FMTRCHAR(f, rt, rs, r);
1588ccd4a63SDavid du Colombier 		}
1598ccd4a63SDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
1608ccd4a63SDavid du Colombier 		f->to = rt;
161*0d601874SDavid du Colombier 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
1628ccd4a63SDavid du Colombier 			return -1;
1638ccd4a63SDavid du Colombier 	}else{
164*0d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
1658ccd4a63SDavid du Colombier 			return -1;
166*0d601874SDavid du Colombier 		t = (char*)f->to;
167*0d601874SDavid du Colombier 		s = (char*)f->stop;
1688ccd4a63SDavid du Colombier 		for(nc = n; nc > 0; nc--){
1698ccd4a63SDavid du Colombier 			r = *(uchar*)m;
1708ccd4a63SDavid du Colombier 			if(r < Runeself)
1718ccd4a63SDavid du Colombier 				m++;
1728ccd4a63SDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
1738ccd4a63SDavid du Colombier 				m += chartorune(&r, m);
1748ccd4a63SDavid du Colombier 			else
1758ccd4a63SDavid du Colombier 				break;
1768ccd4a63SDavid du Colombier 			FMTRUNE(f, t, s, r);
1778ccd4a63SDavid du Colombier 		}
1788ccd4a63SDavid du Colombier 		f->nfmt += t - (char *)f->to;
1798ccd4a63SDavid du Colombier 		f->to = t;
180*0d601874SDavid du Colombier 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
1818ccd4a63SDavid du Colombier 			return -1;
1828ccd4a63SDavid du Colombier 	}
1838ccd4a63SDavid du Colombier 	return 0;
1848ccd4a63SDavid du Colombier }
1858ccd4a63SDavid du Colombier 
1868ccd4a63SDavid du Colombier int
187*0d601874SDavid du Colombier __fmtrcpy(Fmt *f, const void *vm, int n)
1888ccd4a63SDavid du Colombier {
1898ccd4a63SDavid du Colombier 	Rune r, *m, *me, *rt, *rs;
1908ccd4a63SDavid du Colombier 	char *t, *s;
1918ccd4a63SDavid du Colombier 	ulong fl;
1928ccd4a63SDavid du Colombier 	int w;
1938ccd4a63SDavid du Colombier 
194*0d601874SDavid du Colombier 	m = (Rune*)vm;
1958ccd4a63SDavid du Colombier 	w = f->width;
1968ccd4a63SDavid du Colombier 	fl = f->flags;
1978ccd4a63SDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
1988ccd4a63SDavid du Colombier 		n = f->prec;
1998ccd4a63SDavid du Colombier 	if(f->runes){
200*0d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
2018ccd4a63SDavid du Colombier 			return -1;
202*0d601874SDavid du Colombier 		rt = (Rune*)f->to;
203*0d601874SDavid du Colombier 		rs = (Rune*)f->stop;
2048ccd4a63SDavid du Colombier 		for(me = m + n; m < me; m++)
2058ccd4a63SDavid du Colombier 			FMTRCHAR(f, rt, rs, *m);
2068ccd4a63SDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
2078ccd4a63SDavid du Colombier 		f->to = rt;
208*0d601874SDavid du Colombier 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
2098ccd4a63SDavid du Colombier 			return -1;
2108ccd4a63SDavid du Colombier 	}else{
211*0d601874SDavid du Colombier 		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
2128ccd4a63SDavid du Colombier 			return -1;
213*0d601874SDavid du Colombier 		t = (char*)f->to;
214*0d601874SDavid du Colombier 		s = (char*)f->stop;
2158ccd4a63SDavid du Colombier 		for(me = m + n; m < me; m++){
2168ccd4a63SDavid du Colombier 			r = *m;
2178ccd4a63SDavid du Colombier 			FMTRUNE(f, t, s, r);
2188ccd4a63SDavid du Colombier 		}
2198ccd4a63SDavid du Colombier 		f->nfmt += t - (char *)f->to;
2208ccd4a63SDavid du Colombier 		f->to = t;
221*0d601874SDavid du Colombier 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
2228ccd4a63SDavid du Colombier 			return -1;
2238ccd4a63SDavid du Colombier 	}
2248ccd4a63SDavid du Colombier 	return 0;
2258ccd4a63SDavid du Colombier }
2268ccd4a63SDavid du Colombier 
2278ccd4a63SDavid du Colombier /* fmt out one character */
2288ccd4a63SDavid du Colombier int
229*0d601874SDavid du Colombier __charfmt(Fmt *f)
2308ccd4a63SDavid du Colombier {
2318ccd4a63SDavid du Colombier 	char x[1];
2328ccd4a63SDavid du Colombier 
2338ccd4a63SDavid du Colombier 	x[0] = va_arg(f->args, int);
2348ccd4a63SDavid du Colombier 	f->prec = 1;
235*0d601874SDavid du Colombier 	return __fmtcpy(f, (const char*)x, 1, 1);
2368ccd4a63SDavid du Colombier }
2378ccd4a63SDavid du Colombier 
2388ccd4a63SDavid du Colombier /* fmt out one rune */
2398ccd4a63SDavid du Colombier int
240*0d601874SDavid du Colombier __runefmt(Fmt *f)
2418ccd4a63SDavid du Colombier {
2428ccd4a63SDavid du Colombier 	Rune x[1];
2438ccd4a63SDavid du Colombier 
2448ccd4a63SDavid du Colombier 	x[0] = va_arg(f->args, int);
245*0d601874SDavid du Colombier 	return __fmtrcpy(f, (const void*)x, 1);
2468ccd4a63SDavid du Colombier }
2478ccd4a63SDavid du Colombier 
2488ccd4a63SDavid du Colombier /* public helper routine: fmt out a null terminated string already in hand */
2498ccd4a63SDavid du Colombier int
2508ccd4a63SDavid du Colombier fmtstrcpy(Fmt *f, char *s)
2518ccd4a63SDavid du Colombier {
252*0d601874SDavid du Colombier 	int i, j;
253*0d601874SDavid du Colombier 	Rune r;
254*0d601874SDavid du Colombier 
2558ccd4a63SDavid du Colombier 	if(!s)
256*0d601874SDavid du Colombier 		return __fmtcpy(f, "<nil>", 5, 5);
2578ccd4a63SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
2588ccd4a63SDavid du Colombier 	if(f->flags & FmtPrec){
259*0d601874SDavid du Colombier 		i = 0;
260*0d601874SDavid du Colombier 		for(j=0; j<f->prec && s[i]; j++)
261*0d601874SDavid du Colombier 			i += chartorune(&r, s+i);
262*0d601874SDavid du Colombier 		return __fmtcpy(f, s, j, i);
2638ccd4a63SDavid du Colombier 	}
264*0d601874SDavid du Colombier 	return __fmtcpy(f, s, utflen(s), strlen(s));
2658ccd4a63SDavid du Colombier }
2668ccd4a63SDavid du Colombier 
2678ccd4a63SDavid du Colombier /* fmt out a null terminated utf string */
2688ccd4a63SDavid du Colombier int
269*0d601874SDavid du Colombier __strfmt(Fmt *f)
2708ccd4a63SDavid du Colombier {
2718ccd4a63SDavid du Colombier 	char *s;
2728ccd4a63SDavid du Colombier 
2738ccd4a63SDavid du Colombier 	s = va_arg(f->args, char *);
2748ccd4a63SDavid du Colombier 	return fmtstrcpy(f, s);
2758ccd4a63SDavid du Colombier }
2768ccd4a63SDavid du Colombier 
2778ccd4a63SDavid du Colombier /* public helper routine: fmt out a null terminated rune string already in hand */
2788ccd4a63SDavid du Colombier int
2798ccd4a63SDavid du Colombier fmtrunestrcpy(Fmt *f, Rune *s)
2808ccd4a63SDavid du Colombier {
2818ccd4a63SDavid du Colombier 	Rune *e;
2828ccd4a63SDavid du Colombier 	int n, p;
2838ccd4a63SDavid du Colombier 
2848ccd4a63SDavid du Colombier 	if(!s)
285*0d601874SDavid du Colombier 		return __fmtcpy(f, "<nil>", 5, 5);
2868ccd4a63SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
2878ccd4a63SDavid du Colombier 	if(f->flags & FmtPrec){
2888ccd4a63SDavid du Colombier 		p = f->prec;
2898ccd4a63SDavid du Colombier 		for(n = 0; n < p; n++)
2908ccd4a63SDavid du Colombier 			if(s[n] == 0)
2918ccd4a63SDavid du Colombier 				break;
2928ccd4a63SDavid du Colombier 	}else{
2938ccd4a63SDavid du Colombier 		for(e = s; *e; e++)
2948ccd4a63SDavid du Colombier 			;
2958ccd4a63SDavid du Colombier 		n = e - s;
2968ccd4a63SDavid du Colombier 	}
297*0d601874SDavid du Colombier 	return __fmtrcpy(f, s, n);
2988ccd4a63SDavid du Colombier }
2998ccd4a63SDavid du Colombier 
3008ccd4a63SDavid du Colombier /* fmt out a null terminated rune string */
3018ccd4a63SDavid du Colombier int
302*0d601874SDavid du Colombier __runesfmt(Fmt *f)
3038ccd4a63SDavid du Colombier {
3048ccd4a63SDavid du Colombier 	Rune *s;
3058ccd4a63SDavid du Colombier 
3068ccd4a63SDavid du Colombier 	s = va_arg(f->args, Rune *);
3078ccd4a63SDavid du Colombier 	return fmtrunestrcpy(f, s);
3088ccd4a63SDavid du Colombier }
3098ccd4a63SDavid du Colombier 
3108ccd4a63SDavid du Colombier /* fmt a % */
3118ccd4a63SDavid du Colombier int
312*0d601874SDavid du Colombier __percentfmt(Fmt *f)
3138ccd4a63SDavid du Colombier {
3148ccd4a63SDavid du Colombier 	Rune x[1];
3158ccd4a63SDavid du Colombier 
3168ccd4a63SDavid du Colombier 	x[0] = f->r;
3178ccd4a63SDavid du Colombier 	f->prec = 1;
318*0d601874SDavid du Colombier 	return __fmtrcpy(f, (const void*)x, 1);
3198ccd4a63SDavid du Colombier }
3208ccd4a63SDavid du Colombier 
3218ccd4a63SDavid du Colombier /* fmt an integer */
3228ccd4a63SDavid du Colombier int
323*0d601874SDavid du Colombier __ifmt(Fmt *f)
3248ccd4a63SDavid du Colombier {
3258ccd4a63SDavid du Colombier 	char buf[70], *p, *conv;
3268ccd4a63SDavid du Colombier 	uvlong vu;
3278ccd4a63SDavid du Colombier 	ulong u;
3288ccd4a63SDavid du Colombier 	int neg, base, i, n, fl, w, isv;
3298ccd4a63SDavid du Colombier 
3308ccd4a63SDavid du Colombier 	neg = 0;
3318ccd4a63SDavid du Colombier 	fl = f->flags;
3328ccd4a63SDavid du Colombier 	isv = 0;
3338ccd4a63SDavid du Colombier 	vu = 0;
3348ccd4a63SDavid du Colombier 	u = 0;
335*0d601874SDavid du Colombier 	/*
336*0d601874SDavid du Colombier 	 * Unsigned verbs for ANSI C
337*0d601874SDavid du Colombier 	 */
338*0d601874SDavid du Colombier 	switch(f->r){
339*0d601874SDavid du Colombier 	case 'x':
340*0d601874SDavid du Colombier 	case 'X':
341*0d601874SDavid du Colombier 	case 'o':
342*0d601874SDavid du Colombier 	case 'u':
343*0d601874SDavid du Colombier 	case 'p':
344*0d601874SDavid du Colombier 		fl |= FmtUnsigned;
345*0d601874SDavid du Colombier 		fl &= ~(FmtSign|FmtSpace);
346*0d601874SDavid du Colombier 		break;
347*0d601874SDavid du Colombier 	}
3488ccd4a63SDavid du Colombier 	if(f->r == 'p'){
3498ccd4a63SDavid du Colombier 		u = (ulong)va_arg(f->args, void*);
3508ccd4a63SDavid du Colombier 		f->r = 'x';
3518ccd4a63SDavid du Colombier 		fl |= FmtUnsigned;
3528ccd4a63SDavid du Colombier 	}else if(fl & FmtVLong){
3538ccd4a63SDavid du Colombier 		isv = 1;
3548ccd4a63SDavid du Colombier 		if(fl & FmtUnsigned)
3558ccd4a63SDavid du Colombier 			vu = va_arg(f->args, uvlong);
3568ccd4a63SDavid du Colombier 		else
3578ccd4a63SDavid du Colombier 			vu = va_arg(f->args, vlong);
3588ccd4a63SDavid du Colombier 	}else if(fl & FmtLong){
3598ccd4a63SDavid du Colombier 		if(fl & FmtUnsigned)
3608ccd4a63SDavid du Colombier 			u = va_arg(f->args, ulong);
3618ccd4a63SDavid du Colombier 		else
3628ccd4a63SDavid du Colombier 			u = va_arg(f->args, long);
3638ccd4a63SDavid du Colombier 	}else if(fl & FmtByte){
3648ccd4a63SDavid du Colombier 		if(fl & FmtUnsigned)
3658ccd4a63SDavid du Colombier 			u = (uchar)va_arg(f->args, int);
3668ccd4a63SDavid du Colombier 		else
3678ccd4a63SDavid du Colombier 			u = (char)va_arg(f->args, int);
3688ccd4a63SDavid du Colombier 	}else if(fl & FmtShort){
3698ccd4a63SDavid du Colombier 		if(fl & FmtUnsigned)
3708ccd4a63SDavid du Colombier 			u = (ushort)va_arg(f->args, int);
3718ccd4a63SDavid du Colombier 		else
3728ccd4a63SDavid du Colombier 			u = (short)va_arg(f->args, int);
3738ccd4a63SDavid du Colombier 	}else{
3748ccd4a63SDavid du Colombier 		if(fl & FmtUnsigned)
3758ccd4a63SDavid du Colombier 			u = va_arg(f->args, uint);
3768ccd4a63SDavid du Colombier 		else
3778ccd4a63SDavid du Colombier 			u = va_arg(f->args, int);
3788ccd4a63SDavid du Colombier 	}
3798ccd4a63SDavid du Colombier 	conv = "0123456789abcdef";
3808ccd4a63SDavid du Colombier 	switch(f->r){
3818ccd4a63SDavid du Colombier 	case 'd':
382*0d601874SDavid du Colombier 	case 'i':
383*0d601874SDavid du Colombier 	case 'u':
3848ccd4a63SDavid du Colombier 		base = 10;
3858ccd4a63SDavid du Colombier 		break;
3868ccd4a63SDavid du Colombier 	case 'x':
3878ccd4a63SDavid du Colombier 		base = 16;
3888ccd4a63SDavid du Colombier 		break;
3898ccd4a63SDavid du Colombier 	case 'X':
3908ccd4a63SDavid du Colombier 		base = 16;
3918ccd4a63SDavid du Colombier 		conv = "0123456789ABCDEF";
3928ccd4a63SDavid du Colombier 		break;
3938ccd4a63SDavid du Colombier 	case 'b':
3948ccd4a63SDavid du Colombier 		base = 2;
3958ccd4a63SDavid du Colombier 		break;
3968ccd4a63SDavid du Colombier 	case 'o':
3978ccd4a63SDavid du Colombier 		base = 8;
3988ccd4a63SDavid du Colombier 		break;
3998ccd4a63SDavid du Colombier 	default:
4008ccd4a63SDavid du Colombier 		return -1;
4018ccd4a63SDavid du Colombier 	}
4028ccd4a63SDavid du Colombier 	if(!(fl & FmtUnsigned)){
4038ccd4a63SDavid du Colombier 		if(isv && (vlong)vu < 0){
4048ccd4a63SDavid du Colombier 			vu = -(vlong)vu;
4058ccd4a63SDavid du Colombier 			neg = 1;
4068ccd4a63SDavid du Colombier 		}else if(!isv && (long)u < 0){
4078ccd4a63SDavid du Colombier 			u = -(long)u;
4088ccd4a63SDavid du Colombier 			neg = 1;
4098ccd4a63SDavid du Colombier 		}
4108ccd4a63SDavid du Colombier 	}
4118ccd4a63SDavid du Colombier 	p = buf + sizeof buf - 1;
4128ccd4a63SDavid du Colombier 	n = 0;
4138ccd4a63SDavid du Colombier 	if(isv){
4148ccd4a63SDavid du Colombier 		while(vu){
4158ccd4a63SDavid du Colombier 			i = vu % base;
4168ccd4a63SDavid du Colombier 			vu /= base;
4178ccd4a63SDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
4188ccd4a63SDavid du Colombier 				*p-- = ',';
4198ccd4a63SDavid du Colombier 				n++;
4208ccd4a63SDavid du Colombier 			}
4218ccd4a63SDavid du Colombier 			*p-- = conv[i];
4228ccd4a63SDavid du Colombier 			n++;
4238ccd4a63SDavid du Colombier 		}
4248ccd4a63SDavid du Colombier 	}else{
4258ccd4a63SDavid du Colombier 		while(u){
4268ccd4a63SDavid du Colombier 			i = u % base;
4278ccd4a63SDavid du Colombier 			u /= base;
4288ccd4a63SDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
4298ccd4a63SDavid du Colombier 				*p-- = ',';
4308ccd4a63SDavid du Colombier 				n++;
4318ccd4a63SDavid du Colombier 			}
4328ccd4a63SDavid du Colombier 			*p-- = conv[i];
4338ccd4a63SDavid du Colombier 			n++;
4348ccd4a63SDavid du Colombier 		}
4358ccd4a63SDavid du Colombier 	}
4368ccd4a63SDavid du Colombier 	if(n == 0){
4378ccd4a63SDavid du Colombier 		*p-- = '0';
4388ccd4a63SDavid du Colombier 		n = 1;
4398ccd4a63SDavid du Colombier 	}
4408ccd4a63SDavid du Colombier 	for(w = f->prec; n < w && p > buf+3; n++)
4418ccd4a63SDavid du Colombier 		*p-- = '0';
4428ccd4a63SDavid du Colombier 	if(neg || (fl & (FmtSign|FmtSpace)))
4438ccd4a63SDavid du Colombier 		n++;
4448ccd4a63SDavid du Colombier 	if(fl & FmtSharp){
4458ccd4a63SDavid du Colombier 		if(base == 16)
4468ccd4a63SDavid du Colombier 			n += 2;
4478ccd4a63SDavid du Colombier 		else if(base == 8){
4488ccd4a63SDavid du Colombier 			if(p[1] == '0')
4498ccd4a63SDavid du Colombier 				fl &= ~FmtSharp;
4508ccd4a63SDavid du Colombier 			else
4518ccd4a63SDavid du Colombier 				n++;
4528ccd4a63SDavid du Colombier 		}
4538ccd4a63SDavid du Colombier 	}
454*0d601874SDavid du Colombier 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
4558ccd4a63SDavid du Colombier 		for(w = f->width; n < w && p > buf+3; n++)
4568ccd4a63SDavid du Colombier 			*p-- = '0';
4578ccd4a63SDavid du Colombier 		f->width = 0;
4588ccd4a63SDavid du Colombier 	}
4598ccd4a63SDavid du Colombier 	if(fl & FmtSharp){
4608ccd4a63SDavid du Colombier 		if(base == 16)
4618ccd4a63SDavid du Colombier 			*p-- = f->r;
4628ccd4a63SDavid du Colombier 		if(base == 16 || base == 8)
4638ccd4a63SDavid du Colombier 			*p-- = '0';
4648ccd4a63SDavid du Colombier 	}
4658ccd4a63SDavid du Colombier 	if(neg)
4668ccd4a63SDavid du Colombier 		*p-- = '-';
4678ccd4a63SDavid du Colombier 	else if(fl & FmtSign)
4688ccd4a63SDavid du Colombier 		*p-- = '+';
4698ccd4a63SDavid du Colombier 	else if(fl & FmtSpace)
4708ccd4a63SDavid du Colombier 		*p-- = ' ';
4718ccd4a63SDavid du Colombier 	f->flags &= ~FmtPrec;
472*0d601874SDavid du Colombier 	return __fmtcpy(f, p + 1, n, n);
4738ccd4a63SDavid du Colombier }
4748ccd4a63SDavid du Colombier 
4758ccd4a63SDavid du Colombier int
476*0d601874SDavid du Colombier __countfmt(Fmt *f)
4778ccd4a63SDavid du Colombier {
4788ccd4a63SDavid du Colombier 	void *p;
4798ccd4a63SDavid du Colombier 	ulong fl;
4808ccd4a63SDavid du Colombier 
4818ccd4a63SDavid du Colombier 	fl = f->flags;
4828ccd4a63SDavid du Colombier 	p = va_arg(f->args, void*);
4838ccd4a63SDavid du Colombier 	if(fl & FmtVLong){
4848ccd4a63SDavid du Colombier 		*(vlong*)p = f->nfmt;
4858ccd4a63SDavid du Colombier 	}else if(fl & FmtLong){
4868ccd4a63SDavid du Colombier 		*(long*)p = f->nfmt;
4878ccd4a63SDavid du Colombier 	}else if(fl & FmtByte){
4888ccd4a63SDavid du Colombier 		*(char*)p = f->nfmt;
4898ccd4a63SDavid du Colombier 	}else if(fl & FmtShort){
4908ccd4a63SDavid du Colombier 		*(short*)p = f->nfmt;
4918ccd4a63SDavid du Colombier 	}else{
4928ccd4a63SDavid du Colombier 		*(int*)p = f->nfmt;
4938ccd4a63SDavid du Colombier 	}
4948ccd4a63SDavid du Colombier 	return 0;
4958ccd4a63SDavid du Colombier }
4968ccd4a63SDavid du Colombier 
4978ccd4a63SDavid du Colombier int
498*0d601874SDavid du Colombier __flagfmt(Fmt *f)
4998ccd4a63SDavid du Colombier {
5008ccd4a63SDavid du Colombier 	switch(f->r){
5018ccd4a63SDavid du Colombier 	case ',':
5028ccd4a63SDavid du Colombier 		f->flags |= FmtComma;
5038ccd4a63SDavid du Colombier 		break;
5048ccd4a63SDavid du Colombier 	case '-':
5058ccd4a63SDavid du Colombier 		f->flags |= FmtLeft;
5068ccd4a63SDavid du Colombier 		break;
5078ccd4a63SDavid du Colombier 	case '+':
5088ccd4a63SDavid du Colombier 		f->flags |= FmtSign;
5098ccd4a63SDavid du Colombier 		break;
5108ccd4a63SDavid du Colombier 	case '#':
5118ccd4a63SDavid du Colombier 		f->flags |= FmtSharp;
5128ccd4a63SDavid du Colombier 		break;
5138ccd4a63SDavid du Colombier 	case ' ':
5148ccd4a63SDavid du Colombier 		f->flags |= FmtSpace;
5158ccd4a63SDavid du Colombier 		break;
5168ccd4a63SDavid du Colombier 	case 'u':
5178ccd4a63SDavid du Colombier 		f->flags |= FmtUnsigned;
5188ccd4a63SDavid du Colombier 		break;
5198ccd4a63SDavid du Colombier 	case 'h':
5208ccd4a63SDavid du Colombier 		if(f->flags & FmtShort)
5218ccd4a63SDavid du Colombier 			f->flags |= FmtByte;
5228ccd4a63SDavid du Colombier 		f->flags |= FmtShort;
5238ccd4a63SDavid du Colombier 		break;
524*0d601874SDavid du Colombier 	case 'L':
525*0d601874SDavid du Colombier 		f->flags |= FmtLDouble;
526*0d601874SDavid du Colombier 		break;
5278ccd4a63SDavid du Colombier 	case 'l':
5288ccd4a63SDavid du Colombier 		if(f->flags & FmtLong)
5298ccd4a63SDavid du Colombier 			f->flags |= FmtVLong;
5308ccd4a63SDavid du Colombier 		f->flags |= FmtLong;
5318ccd4a63SDavid du Colombier 		break;
5328ccd4a63SDavid du Colombier 	}
5338ccd4a63SDavid du Colombier 	return 1;
5348ccd4a63SDavid du Colombier }
5358ccd4a63SDavid du Colombier 
5368ccd4a63SDavid du Colombier /* default error format */
5378ccd4a63SDavid du Colombier int
538*0d601874SDavid du Colombier __badfmt(Fmt *f)
5398ccd4a63SDavid du Colombier {
5408ccd4a63SDavid du Colombier 	char x[3];
5418ccd4a63SDavid du Colombier 
5428ccd4a63SDavid du Colombier 	x[0] = '%';
5438ccd4a63SDavid du Colombier 	x[1] = f->r;
5448ccd4a63SDavid du Colombier 	x[2] = '%';
5458ccd4a63SDavid du Colombier 	f->prec = 3;
546*0d601874SDavid du Colombier 	__fmtcpy(f, (const void*)x, 3, 3);
5478ccd4a63SDavid du Colombier 	return 0;
5488ccd4a63SDavid du Colombier }
549