xref: /plan9/sys/src/libc/fmt/dofmt.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include "fmtdef.h"
49a747e4fSDavid du Colombier 
59a747e4fSDavid du Colombier /* format the output into f->to and return the number of characters fmted  */
69a747e4fSDavid du Colombier int
dofmt(Fmt * f,char * fmt)79a747e4fSDavid du Colombier dofmt(Fmt *f, char *fmt)
89a747e4fSDavid du Colombier {
99a747e4fSDavid du Colombier 	Rune rune, *rt, *rs;
109a747e4fSDavid du Colombier 	int r;
119a747e4fSDavid du Colombier 	char *t, *s;
129a747e4fSDavid du Colombier 	int n, nfmt;
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier 	nfmt = f->nfmt;
159a747e4fSDavid du Colombier 	for(;;){
169a747e4fSDavid du Colombier 		if(f->runes){
179a747e4fSDavid du Colombier 			rt = f->to;
189a747e4fSDavid du Colombier 			rs = f->stop;
199a747e4fSDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
209a747e4fSDavid du Colombier 				if(r < Runeself)
219a747e4fSDavid du Colombier 					fmt++;
229a747e4fSDavid du Colombier 				else{
239a747e4fSDavid du Colombier 					fmt += chartorune(&rune, fmt);
249a747e4fSDavid du Colombier 					r = rune;
259a747e4fSDavid du Colombier 				}
269a747e4fSDavid du Colombier 				FMTRCHAR(f, rt, rs, r);
279a747e4fSDavid du Colombier 			}
289a747e4fSDavid du Colombier 			fmt++;
299a747e4fSDavid du Colombier 			f->nfmt += rt - (Rune *)f->to;
309a747e4fSDavid du Colombier 			f->to = rt;
319a747e4fSDavid du Colombier 			if(!r)
329a747e4fSDavid du Colombier 				return f->nfmt - nfmt;
339a747e4fSDavid du Colombier 			f->stop = rs;
349a747e4fSDavid du Colombier 		}else{
359a747e4fSDavid du Colombier 			t = f->to;
369a747e4fSDavid du Colombier 			s = f->stop;
379a747e4fSDavid du Colombier 			while((r = *(uchar*)fmt) && r != '%'){
389a747e4fSDavid du Colombier 				if(r < Runeself){
399a747e4fSDavid du Colombier 					FMTCHAR(f, t, s, r);
409a747e4fSDavid du Colombier 					fmt++;
419a747e4fSDavid du Colombier 				}else{
429a747e4fSDavid du Colombier 					n = chartorune(&rune, fmt);
439a747e4fSDavid du Colombier 					if(t + n > s){
449a747e4fSDavid du Colombier 						t = _fmtflush(f, t, n);
459a747e4fSDavid du Colombier 						if(t != nil)
469a747e4fSDavid du Colombier 							s = f->stop;
479a747e4fSDavid du Colombier 						else
489a747e4fSDavid du Colombier 							return -1;
499a747e4fSDavid du Colombier 					}
509a747e4fSDavid du Colombier 					while(n--)
519a747e4fSDavid du Colombier 						*t++ = *fmt++;
529a747e4fSDavid du Colombier 				}
539a747e4fSDavid du Colombier 			}
549a747e4fSDavid du Colombier 			fmt++;
559a747e4fSDavid du Colombier 			f->nfmt += t - (char *)f->to;
569a747e4fSDavid du Colombier 			f->to = t;
579a747e4fSDavid du Colombier 			if(!r)
589a747e4fSDavid du Colombier 				return f->nfmt - nfmt;
599a747e4fSDavid du Colombier 			f->stop = s;
609a747e4fSDavid du Colombier 		}
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier 		fmt = _fmtdispatch(f, fmt, 0);
639a747e4fSDavid du Colombier 		if(fmt == nil)
649a747e4fSDavid du Colombier 			return -1;
659a747e4fSDavid du Colombier 	}
669a747e4fSDavid du Colombier }
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier void *
_fmtflush(Fmt * f,void * t,int len)699a747e4fSDavid du Colombier _fmtflush(Fmt *f, void *t, int len)
709a747e4fSDavid du Colombier {
719a747e4fSDavid du Colombier 	if(f->runes)
729a747e4fSDavid du Colombier 		f->nfmt += (Rune*)t - (Rune*)f->to;
739a747e4fSDavid du Colombier 	else
749a747e4fSDavid du Colombier 		f->nfmt += (char*)t - (char *)f->to;
759a747e4fSDavid du Colombier 	f->to = t;
769a747e4fSDavid du Colombier 	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
779a747e4fSDavid du Colombier 		f->stop = f->to;
789a747e4fSDavid du Colombier 		return nil;
799a747e4fSDavid du Colombier 	}
809a747e4fSDavid du Colombier 	return f->to;
819a747e4fSDavid du Colombier }
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier /*
849a747e4fSDavid du Colombier  * put a formatted block of memory sz bytes long of n runes into the output buffer,
859a747e4fSDavid du Colombier  * left/right justified in a field of at least f->width charactes
869a747e4fSDavid du Colombier  */
879a747e4fSDavid du Colombier int
_fmtpad(Fmt * f,int n)889a747e4fSDavid du Colombier _fmtpad(Fmt *f, int n)
899a747e4fSDavid du Colombier {
909a747e4fSDavid du Colombier 	char *t, *s;
919a747e4fSDavid du Colombier 	int i;
929a747e4fSDavid du Colombier 
939a747e4fSDavid du Colombier 	t = f->to;
949a747e4fSDavid du Colombier 	s = f->stop;
959a747e4fSDavid du Colombier 	for(i = 0; i < n; i++)
969a747e4fSDavid du Colombier 		FMTCHAR(f, t, s, ' ');
979a747e4fSDavid du Colombier 	f->nfmt += t - (char *)f->to;
989a747e4fSDavid du Colombier 	f->to = t;
999a747e4fSDavid du Colombier 	return 0;
1009a747e4fSDavid du Colombier }
1019a747e4fSDavid du Colombier 
1029a747e4fSDavid du Colombier int
_rfmtpad(Fmt * f,int n)1039a747e4fSDavid du Colombier _rfmtpad(Fmt *f, int n)
1049a747e4fSDavid du Colombier {
1059a747e4fSDavid du Colombier 	Rune *t, *s;
1069a747e4fSDavid du Colombier 	int i;
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier 	t = f->to;
1099a747e4fSDavid du Colombier 	s = f->stop;
1109a747e4fSDavid du Colombier 	for(i = 0; i < n; i++)
1119a747e4fSDavid du Colombier 		FMTRCHAR(f, t, s, ' ');
1129a747e4fSDavid du Colombier 	f->nfmt += t - (Rune *)f->to;
1139a747e4fSDavid du Colombier 	f->to = t;
1149a747e4fSDavid du Colombier 	return 0;
1159a747e4fSDavid du Colombier }
1169a747e4fSDavid du Colombier 
1179a747e4fSDavid du Colombier int
_fmtcpy(Fmt * f,void * vm,int n,int sz)1189a747e4fSDavid du Colombier _fmtcpy(Fmt *f, void *vm, int n, int sz)
1199a747e4fSDavid du Colombier {
1209a747e4fSDavid du Colombier 	Rune *rt, *rs, r;
1219a747e4fSDavid du Colombier 	char *t, *s, *m, *me;
1229a747e4fSDavid du Colombier 	ulong fl;
1239a747e4fSDavid du Colombier 	int nc, w;
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	m = vm;
1269a747e4fSDavid du Colombier 	me = m + sz;
1279a747e4fSDavid du Colombier 	w = f->width;
1289a747e4fSDavid du Colombier 	fl = f->flags;
1299a747e4fSDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
1309a747e4fSDavid du Colombier 		n = f->prec;
1319a747e4fSDavid du Colombier 	if(f->runes){
1329a747e4fSDavid du Colombier 		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
1339a747e4fSDavid du Colombier 			return -1;
1349a747e4fSDavid du Colombier 		rt = f->to;
1359a747e4fSDavid du Colombier 		rs = f->stop;
1369a747e4fSDavid du Colombier 		for(nc = n; nc > 0; nc--){
1379a747e4fSDavid du Colombier 			r = *(uchar*)m;
1389a747e4fSDavid du Colombier 			if(r < Runeself)
1399a747e4fSDavid du Colombier 				m++;
1409a747e4fSDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
1419a747e4fSDavid du Colombier 				m += chartorune(&r, m);
1429a747e4fSDavid du Colombier 			else
1439a747e4fSDavid du Colombier 				break;
1449a747e4fSDavid du Colombier 			FMTRCHAR(f, rt, rs, r);
1459a747e4fSDavid du Colombier 		}
1469a747e4fSDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
1479a747e4fSDavid du Colombier 		f->to = rt;
1489a747e4fSDavid du Colombier 		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
1499a747e4fSDavid du Colombier 			return -1;
1509a747e4fSDavid du Colombier 	}else{
1519a747e4fSDavid du Colombier 		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
1529a747e4fSDavid du Colombier 			return -1;
1539a747e4fSDavid du Colombier 		t = f->to;
1549a747e4fSDavid du Colombier 		s = f->stop;
1559a747e4fSDavid du Colombier 		for(nc = n; nc > 0; nc--){
1569a747e4fSDavid du Colombier 			r = *(uchar*)m;
1579a747e4fSDavid du Colombier 			if(r < Runeself)
1589a747e4fSDavid du Colombier 				m++;
1599a747e4fSDavid du Colombier 			else if((me - m) >= UTFmax || fullrune(m, me-m))
1609a747e4fSDavid du Colombier 				m += chartorune(&r, m);
1619a747e4fSDavid du Colombier 			else
1629a747e4fSDavid du Colombier 				break;
1639a747e4fSDavid du Colombier 			FMTRUNE(f, t, s, r);
1649a747e4fSDavid du Colombier 		}
1659a747e4fSDavid du Colombier 		f->nfmt += t - (char *)f->to;
1669a747e4fSDavid du Colombier 		f->to = t;
1679a747e4fSDavid du Colombier 		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
1689a747e4fSDavid du Colombier 			return -1;
1699a747e4fSDavid du Colombier 	}
1709a747e4fSDavid du Colombier 	return 0;
1719a747e4fSDavid du Colombier }
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier int
_fmtrcpy(Fmt * f,void * vm,int n)1749a747e4fSDavid du Colombier _fmtrcpy(Fmt *f, void *vm, int n)
1759a747e4fSDavid du Colombier {
1769a747e4fSDavid du Colombier 	Rune r, *m, *me, *rt, *rs;
1779a747e4fSDavid du Colombier 	char *t, *s;
1789a747e4fSDavid du Colombier 	ulong fl;
1799a747e4fSDavid du Colombier 	int w;
1809a747e4fSDavid du Colombier 
1819a747e4fSDavid du Colombier 	m = vm;
1829a747e4fSDavid du Colombier 	w = f->width;
1839a747e4fSDavid du Colombier 	fl = f->flags;
1849a747e4fSDavid du Colombier 	if((fl & FmtPrec) && n > f->prec)
1859a747e4fSDavid du Colombier 		n = f->prec;
1869a747e4fSDavid du Colombier 	if(f->runes){
1879a747e4fSDavid du Colombier 		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
1889a747e4fSDavid du Colombier 			return -1;
1899a747e4fSDavid du Colombier 		rt = f->to;
1909a747e4fSDavid du Colombier 		rs = f->stop;
1919a747e4fSDavid du Colombier 		for(me = m + n; m < me; m++)
1929a747e4fSDavid du Colombier 			FMTRCHAR(f, rt, rs, *m);
1939a747e4fSDavid du Colombier 		f->nfmt += rt - (Rune *)f->to;
1949a747e4fSDavid du Colombier 		f->to = rt;
1959a747e4fSDavid du Colombier 		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
1969a747e4fSDavid du Colombier 			return -1;
1979a747e4fSDavid du Colombier 	}else{
1989a747e4fSDavid du Colombier 		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
1999a747e4fSDavid du Colombier 			return -1;
2009a747e4fSDavid du Colombier 		t = f->to;
2019a747e4fSDavid du Colombier 		s = f->stop;
2029a747e4fSDavid du Colombier 		for(me = m + n; m < me; m++){
2039a747e4fSDavid du Colombier 			r = *m;
2049a747e4fSDavid du Colombier 			FMTRUNE(f, t, s, r);
2059a747e4fSDavid du Colombier 		}
2069a747e4fSDavid du Colombier 		f->nfmt += t - (char *)f->to;
2079a747e4fSDavid du Colombier 		f->to = t;
2089a747e4fSDavid du Colombier 		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
2099a747e4fSDavid du Colombier 			return -1;
2109a747e4fSDavid du Colombier 	}
2119a747e4fSDavid du Colombier 	return 0;
2129a747e4fSDavid du Colombier }
2139a747e4fSDavid du Colombier 
2149a747e4fSDavid du Colombier /* fmt out one character */
2159a747e4fSDavid du Colombier int
_charfmt(Fmt * f)2169a747e4fSDavid du Colombier _charfmt(Fmt *f)
2179a747e4fSDavid du Colombier {
2189a747e4fSDavid du Colombier 	char x[1];
2199a747e4fSDavid du Colombier 
2209a747e4fSDavid du Colombier 	x[0] = va_arg(f->args, int);
221d9306527SDavid du Colombier 	f->prec = 1;
2229a747e4fSDavid du Colombier 	return _fmtcpy(f, x, 1, 1);
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier 
2259a747e4fSDavid du Colombier /* fmt out one rune */
2269a747e4fSDavid du Colombier int
_runefmt(Fmt * f)2279a747e4fSDavid du Colombier _runefmt(Fmt *f)
2289a747e4fSDavid du Colombier {
2299a747e4fSDavid du Colombier 	Rune x[1];
2309a747e4fSDavid du Colombier 
2319a747e4fSDavid du Colombier 	x[0] = va_arg(f->args, int);
2329a747e4fSDavid du Colombier 	return _fmtrcpy(f, x, 1);
2339a747e4fSDavid du Colombier }
2349a747e4fSDavid du Colombier 
2359a747e4fSDavid du Colombier /* public helper routine: fmt out a null terminated string already in hand */
2369a747e4fSDavid du Colombier int
fmtstrcpy(Fmt * f,char * s)2379a747e4fSDavid du Colombier fmtstrcpy(Fmt *f, char *s)
2389a747e4fSDavid du Colombier {
23967031067SDavid du Colombier 	int i, j;
24067031067SDavid du Colombier 	Rune r;
24167031067SDavid du Colombier 
2429a747e4fSDavid du Colombier 	if(!s)
2439a747e4fSDavid du Colombier 		return _fmtcpy(f, "<nil>", 5, 5);
2446a9fc400SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
2456a9fc400SDavid du Colombier 	if(f->flags & FmtPrec){
24667031067SDavid du Colombier 		i = 0;
24767031067SDavid du Colombier 		for(j=0; j<f->prec && s[i]; j++)
24867031067SDavid du Colombier 			i += chartorune(&r, s+i);
24967031067SDavid du Colombier 		return _fmtcpy(f, s, j, i);
2506a9fc400SDavid du Colombier 	}
2519a747e4fSDavid du Colombier 	return _fmtcpy(f, s, utflen(s), strlen(s));
2529a747e4fSDavid du Colombier }
2539a747e4fSDavid du Colombier 
2549a747e4fSDavid du Colombier /* fmt out a null terminated utf string */
2559a747e4fSDavid du Colombier int
_strfmt(Fmt * f)2569a747e4fSDavid du Colombier _strfmt(Fmt *f)
2579a747e4fSDavid du Colombier {
2589a747e4fSDavid du Colombier 	char *s;
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier 	s = va_arg(f->args, char *);
2619a747e4fSDavid du Colombier 	return fmtstrcpy(f, s);
2629a747e4fSDavid du Colombier }
2639a747e4fSDavid du Colombier 
2649a747e4fSDavid du Colombier /* public helper routine: fmt out a null terminated rune string already in hand */
2659a747e4fSDavid du Colombier int
fmtrunestrcpy(Fmt * f,Rune * s)2669a747e4fSDavid du Colombier fmtrunestrcpy(Fmt *f, Rune *s)
2679a747e4fSDavid du Colombier {
2689a747e4fSDavid du Colombier 	Rune *e;
2696a9fc400SDavid du Colombier 	int n, p;
2709a747e4fSDavid du Colombier 
2719a747e4fSDavid du Colombier 	if(!s)
2729a747e4fSDavid du Colombier 		return _fmtcpy(f, "<nil>", 5, 5);
2736a9fc400SDavid du Colombier 	/* if precision is specified, make sure we don't wander off the end */
2746a9fc400SDavid du Colombier 	if(f->flags & FmtPrec){
2756a9fc400SDavid du Colombier 		p = f->prec;
2766a9fc400SDavid du Colombier 		for(n = 0; n < p; n++)
2776a9fc400SDavid du Colombier 			if(s[n] == 0)
2786a9fc400SDavid du Colombier 				break;
2796a9fc400SDavid du Colombier 	}else{
2809a747e4fSDavid du Colombier 		for(e = s; *e; e++)
2819a747e4fSDavid du Colombier 			;
2829a747e4fSDavid du Colombier 		n = e - s;
2836a9fc400SDavid du Colombier 	}
2849a747e4fSDavid du Colombier 	return _fmtrcpy(f, s, n);
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier 
2879a747e4fSDavid du Colombier /* fmt out a null terminated rune string */
2889a747e4fSDavid du Colombier int
_runesfmt(Fmt * f)2899a747e4fSDavid du Colombier _runesfmt(Fmt *f)
2909a747e4fSDavid du Colombier {
2919a747e4fSDavid du Colombier 	Rune *s;
2929a747e4fSDavid du Colombier 
2939a747e4fSDavid du Colombier 	s = va_arg(f->args, Rune *);
2949a747e4fSDavid du Colombier 	return fmtrunestrcpy(f, s);
2959a747e4fSDavid du Colombier }
2969a747e4fSDavid du Colombier 
2979a747e4fSDavid du Colombier /* fmt a % */
2989a747e4fSDavid du Colombier int
_percentfmt(Fmt * f)2999a747e4fSDavid du Colombier _percentfmt(Fmt *f)
3009a747e4fSDavid du Colombier {
3019a747e4fSDavid du Colombier 	Rune x[1];
3029a747e4fSDavid du Colombier 
3039a747e4fSDavid du Colombier 	x[0] = f->r;
304d9306527SDavid du Colombier 	f->prec = 1;
3059a747e4fSDavid du Colombier 	return _fmtrcpy(f, x, 1);
3069a747e4fSDavid du Colombier }
3079a747e4fSDavid du Colombier 
308*ad6ca847SDavid du Colombier enum {
309*ad6ca847SDavid du Colombier 	/* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */
310*ad6ca847SDavid du Colombier 	Maxintwidth = 1 + 2 + 64 + 64/3,
311*ad6ca847SDavid du Colombier };
312*ad6ca847SDavid du Colombier 
3139a747e4fSDavid du Colombier /* fmt an integer */
3149a747e4fSDavid du Colombier int
_ifmt(Fmt * f)3159a747e4fSDavid du Colombier _ifmt(Fmt *f)
3169a747e4fSDavid du Colombier {
317*ad6ca847SDavid du Colombier 	char buf[Maxintwidth + 1], *p, *conv;
3189a747e4fSDavid du Colombier 	uvlong vu;
3199a747e4fSDavid du Colombier 	ulong u;
3201517f4bcSDavid du Colombier 	uintptr pu;
3219a747e4fSDavid du Colombier 	int neg, base, i, n, fl, w, isv;
3229a747e4fSDavid du Colombier 
3239a747e4fSDavid du Colombier 	neg = 0;
3249a747e4fSDavid du Colombier 	fl = f->flags;
3259a747e4fSDavid du Colombier 	isv = 0;
3269a747e4fSDavid du Colombier 	vu = 0;
3279a747e4fSDavid du Colombier 	u = 0;
3289a747e4fSDavid du Colombier 	if(f->r == 'p'){
3291517f4bcSDavid du Colombier 		pu = va_arg(f->args, uintptr);
3301517f4bcSDavid du Colombier 		if(sizeof(uintptr) == sizeof(uvlong)){
3311517f4bcSDavid du Colombier 			vu = pu;
3321517f4bcSDavid du Colombier 			isv = 1;
3331517f4bcSDavid du Colombier 		}else
3341517f4bcSDavid du Colombier 			u = pu;
3359a747e4fSDavid du Colombier 		f->r = 'x';
3369a747e4fSDavid du Colombier 		fl |= FmtUnsigned;
3379a747e4fSDavid du Colombier 	}else if(fl & FmtVLong){
3389a747e4fSDavid du Colombier 		isv = 1;
3399a747e4fSDavid du Colombier 		if(fl & FmtUnsigned)
3409a747e4fSDavid du Colombier 			vu = va_arg(f->args, uvlong);
3419a747e4fSDavid du Colombier 		else
3429a747e4fSDavid du Colombier 			vu = va_arg(f->args, vlong);
3439a747e4fSDavid du Colombier 	}else if(fl & FmtLong){
3449a747e4fSDavid du Colombier 		if(fl & FmtUnsigned)
3459a747e4fSDavid du Colombier 			u = va_arg(f->args, ulong);
3469a747e4fSDavid du Colombier 		else
3479a747e4fSDavid du Colombier 			u = va_arg(f->args, long);
348b7b24591SDavid du Colombier 	}else if(fl & FmtByte){
349b7b24591SDavid du Colombier 		if(fl & FmtUnsigned)
350b7b24591SDavid du Colombier 			u = (uchar)va_arg(f->args, int);
351b7b24591SDavid du Colombier 		else
352b7b24591SDavid du Colombier 			u = (char)va_arg(f->args, int);
3539a747e4fSDavid du Colombier 	}else if(fl & FmtShort){
3549a747e4fSDavid du Colombier 		if(fl & FmtUnsigned)
355b7b24591SDavid du Colombier 			u = (ushort)va_arg(f->args, int);
3569a747e4fSDavid du Colombier 		else
357b7b24591SDavid du Colombier 			u = (short)va_arg(f->args, int);
3589a747e4fSDavid du Colombier 	}else{
3599a747e4fSDavid du Colombier 		if(fl & FmtUnsigned)
3609a747e4fSDavid du Colombier 			u = va_arg(f->args, uint);
3619a747e4fSDavid du Colombier 		else
3629a747e4fSDavid du Colombier 			u = va_arg(f->args, int);
3639a747e4fSDavid du Colombier 	}
3649a747e4fSDavid du Colombier 	conv = "0123456789abcdef";
3659a747e4fSDavid du Colombier 	switch(f->r){
3669a747e4fSDavid du Colombier 	case 'd':
3679a747e4fSDavid du Colombier 		base = 10;
3689a747e4fSDavid du Colombier 		break;
3699a747e4fSDavid du Colombier 	case 'x':
3709a747e4fSDavid du Colombier 		base = 16;
3719a747e4fSDavid du Colombier 		break;
3729a747e4fSDavid du Colombier 	case 'X':
3739a747e4fSDavid du Colombier 		base = 16;
3749a747e4fSDavid du Colombier 		conv = "0123456789ABCDEF";
3759a747e4fSDavid du Colombier 		break;
3769a747e4fSDavid du Colombier 	case 'b':
3779a747e4fSDavid du Colombier 		base = 2;
3789a747e4fSDavid du Colombier 		break;
3799a747e4fSDavid du Colombier 	case 'o':
3809a747e4fSDavid du Colombier 		base = 8;
3819a747e4fSDavid du Colombier 		break;
3829a747e4fSDavid du Colombier 	default:
3839a747e4fSDavid du Colombier 		return -1;
3849a747e4fSDavid du Colombier 	}
3859a747e4fSDavid du Colombier 	if(!(fl & FmtUnsigned)){
3869a747e4fSDavid du Colombier 		if(isv && (vlong)vu < 0){
3879a747e4fSDavid du Colombier 			vu = -(vlong)vu;
3889a747e4fSDavid du Colombier 			neg = 1;
3899a747e4fSDavid du Colombier 		}else if(!isv && (long)u < 0){
3909a747e4fSDavid du Colombier 			u = -(long)u;
3919a747e4fSDavid du Colombier 			neg = 1;
3929a747e4fSDavid du Colombier 		}
3939a747e4fSDavid du Colombier 	}
3949a747e4fSDavid du Colombier 	p = buf + sizeof buf - 1;
3959a747e4fSDavid du Colombier 	n = 0;
3969a747e4fSDavid du Colombier 	if(isv){
3979a747e4fSDavid du Colombier 		while(vu){
3989a747e4fSDavid du Colombier 			i = vu % base;
3999a747e4fSDavid du Colombier 			vu /= base;
4009a747e4fSDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
4019a747e4fSDavid du Colombier 				*p-- = ',';
4029a747e4fSDavid du Colombier 				n++;
4039a747e4fSDavid du Colombier 			}
4049a747e4fSDavid du Colombier 			*p-- = conv[i];
4059a747e4fSDavid du Colombier 			n++;
4069a747e4fSDavid du Colombier 		}
4079a747e4fSDavid du Colombier 	}else{
4089a747e4fSDavid du Colombier 		while(u){
4099a747e4fSDavid du Colombier 			i = u % base;
4109a747e4fSDavid du Colombier 			u /= base;
4119a747e4fSDavid du Colombier 			if((fl & FmtComma) && n % 4 == 3){
4129a747e4fSDavid du Colombier 				*p-- = ',';
4139a747e4fSDavid du Colombier 				n++;
4149a747e4fSDavid du Colombier 			}
4159a747e4fSDavid du Colombier 			*p-- = conv[i];
4169a747e4fSDavid du Colombier 			n++;
4179a747e4fSDavid du Colombier 		}
4189a747e4fSDavid du Colombier 	}
4199a747e4fSDavid du Colombier 	if(n == 0){
4209a747e4fSDavid du Colombier 		*p-- = '0';
4219a747e4fSDavid du Colombier 		n = 1;
4229a747e4fSDavid du Colombier 	}
4239a747e4fSDavid du Colombier 	for(w = f->prec; n < w && p > buf+3; n++)
4249a747e4fSDavid du Colombier 		*p-- = '0';
4259a747e4fSDavid du Colombier 	if(neg || (fl & (FmtSign|FmtSpace)))
4269a747e4fSDavid du Colombier 		n++;
4279a747e4fSDavid du Colombier 	if(fl & FmtSharp){
4289a747e4fSDavid du Colombier 		if(base == 16)
4299a747e4fSDavid du Colombier 			n += 2;
4309a747e4fSDavid du Colombier 		else if(base == 8){
4319a747e4fSDavid du Colombier 			if(p[1] == '0')
4329a747e4fSDavid du Colombier 				fl &= ~FmtSharp;
4339a747e4fSDavid du Colombier 			else
4349a747e4fSDavid du Colombier 				n++;
4359a747e4fSDavid du Colombier 		}
4369a747e4fSDavid du Colombier 	}
437a0ef1dc2SDavid du Colombier 	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
4389a747e4fSDavid du Colombier 		for(w = f->width; n < w && p > buf+3; n++)
4399a747e4fSDavid du Colombier 			*p-- = '0';
4409a747e4fSDavid du Colombier 		f->width = 0;
4419a747e4fSDavid du Colombier 	}
4429a747e4fSDavid du Colombier 	if(fl & FmtSharp){
4439a747e4fSDavid du Colombier 		if(base == 16)
4449a747e4fSDavid du Colombier 			*p-- = f->r;
4459a747e4fSDavid du Colombier 		if(base == 16 || base == 8)
4469a747e4fSDavid du Colombier 			*p-- = '0';
4479a747e4fSDavid du Colombier 	}
4489a747e4fSDavid du Colombier 	if(neg)
4499a747e4fSDavid du Colombier 		*p-- = '-';
4509a747e4fSDavid du Colombier 	else if(fl & FmtSign)
4519a747e4fSDavid du Colombier 		*p-- = '+';
4529a747e4fSDavid du Colombier 	else if(fl & FmtSpace)
4539a747e4fSDavid du Colombier 		*p-- = ' ';
4549a747e4fSDavid du Colombier 	f->flags &= ~FmtPrec;
4559a747e4fSDavid du Colombier 	return _fmtcpy(f, p + 1, n, n);
4569a747e4fSDavid du Colombier }
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier int
_countfmt(Fmt * f)4599a747e4fSDavid du Colombier _countfmt(Fmt *f)
4609a747e4fSDavid du Colombier {
4619a747e4fSDavid du Colombier 	void *p;
4629a747e4fSDavid du Colombier 	ulong fl;
4639a747e4fSDavid du Colombier 
4649a747e4fSDavid du Colombier 	fl = f->flags;
4659a747e4fSDavid du Colombier 	p = va_arg(f->args, void*);
4669a747e4fSDavid du Colombier 	if(fl & FmtVLong){
4679a747e4fSDavid du Colombier 		*(vlong*)p = f->nfmt;
4689a747e4fSDavid du Colombier 	}else if(fl & FmtLong){
4699a747e4fSDavid du Colombier 		*(long*)p = f->nfmt;
4709a747e4fSDavid du Colombier 	}else if(fl & FmtByte){
4719a747e4fSDavid du Colombier 		*(char*)p = f->nfmt;
4729a747e4fSDavid du Colombier 	}else if(fl & FmtShort){
4739a747e4fSDavid du Colombier 		*(short*)p = f->nfmt;
4749a747e4fSDavid du Colombier 	}else{
4759a747e4fSDavid du Colombier 		*(int*)p = f->nfmt;
4769a747e4fSDavid du Colombier 	}
4779a747e4fSDavid du Colombier 	return 0;
4789a747e4fSDavid du Colombier }
4799a747e4fSDavid du Colombier 
4809a747e4fSDavid du Colombier int
_flagfmt(Fmt * f)4819a747e4fSDavid du Colombier _flagfmt(Fmt *f)
4829a747e4fSDavid du Colombier {
4839a747e4fSDavid du Colombier 	switch(f->r){
4849a747e4fSDavid du Colombier 	case ',':
4859a747e4fSDavid du Colombier 		f->flags |= FmtComma;
4869a747e4fSDavid du Colombier 		break;
4879a747e4fSDavid du Colombier 	case '-':
4889a747e4fSDavid du Colombier 		f->flags |= FmtLeft;
4899a747e4fSDavid du Colombier 		break;
4909a747e4fSDavid du Colombier 	case '+':
4919a747e4fSDavid du Colombier 		f->flags |= FmtSign;
4929a747e4fSDavid du Colombier 		break;
4939a747e4fSDavid du Colombier 	case '#':
4949a747e4fSDavid du Colombier 		f->flags |= FmtSharp;
4959a747e4fSDavid du Colombier 		break;
4969a747e4fSDavid du Colombier 	case ' ':
4979a747e4fSDavid du Colombier 		f->flags |= FmtSpace;
4989a747e4fSDavid du Colombier 		break;
4999a747e4fSDavid du Colombier 	case 'u':
5009a747e4fSDavid du Colombier 		f->flags |= FmtUnsigned;
5019a747e4fSDavid du Colombier 		break;
5029a747e4fSDavid du Colombier 	case 'h':
5039a747e4fSDavid du Colombier 		if(f->flags & FmtShort)
5049a747e4fSDavid du Colombier 			f->flags |= FmtByte;
5059a747e4fSDavid du Colombier 		f->flags |= FmtShort;
5069a747e4fSDavid du Colombier 		break;
5079a747e4fSDavid du Colombier 	case 'l':
5089a747e4fSDavid du Colombier 		if(f->flags & FmtLong)
5099a747e4fSDavid du Colombier 			f->flags |= FmtVLong;
5109a747e4fSDavid du Colombier 		f->flags |= FmtLong;
5119a747e4fSDavid du Colombier 		break;
5129a747e4fSDavid du Colombier 	}
5139a747e4fSDavid du Colombier 	return 1;
5149a747e4fSDavid du Colombier }
5159a747e4fSDavid du Colombier 
5169a747e4fSDavid du Colombier /* default error format */
5179a747e4fSDavid du Colombier int
_badfmt(Fmt * f)5189a747e4fSDavid du Colombier _badfmt(Fmt *f)
5199a747e4fSDavid du Colombier {
520*ad6ca847SDavid du Colombier 	Rune x[3];
5219a747e4fSDavid du Colombier 
5229a747e4fSDavid du Colombier 	x[0] = '%';
5239a747e4fSDavid du Colombier 	x[1] = f->r;
5249a747e4fSDavid du Colombier 	x[2] = '%';
525d9306527SDavid du Colombier 	f->prec = 3;
526*ad6ca847SDavid du Colombier 	_fmtrcpy(f, x, 3);
5279a747e4fSDavid du Colombier 	return 0;
5289a747e4fSDavid du Colombier }
529