xref: /plan9/sys/src/cmd/unix/u9fs/doprint.c (revision 9df354649c4cda9c2f83c9ee41152de551c09141)
19a747e4fSDavid du Colombier #include	<plan9.h>
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier #define lock(x)
49a747e4fSDavid du Colombier #define unlock(x)
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier enum
79a747e4fSDavid du Colombier {
89a747e4fSDavid du Colombier 	IDIGIT	= 40,
99a747e4fSDavid du Colombier 	MAXCONV	= 40,
109a747e4fSDavid du Colombier 	FDIGIT	= 30,
119a747e4fSDavid du Colombier 	FDEFLT	= 6,
129a747e4fSDavid du Colombier 	NONE	= -1000,
139a747e4fSDavid du Colombier 	MAXFMT	= 512,
149a747e4fSDavid du Colombier 
159a747e4fSDavid du Colombier 	FPLUS	= 1<<0,
169a747e4fSDavid du Colombier 	FMINUS	= 1<<1,
179a747e4fSDavid du Colombier 	FSHARP	= 1<<2,
189a747e4fSDavid du Colombier 	FLONG	= 1<<3,
199a747e4fSDavid du Colombier 	FUNSIGN	= 1<<5,
209a747e4fSDavid du Colombier 	FVLONG	= 1<<6,
219a747e4fSDavid du Colombier 	FPOINTER= 1<<7
229a747e4fSDavid du Colombier };
239a747e4fSDavid du Colombier 
249a747e4fSDavid du Colombier int	printcol;
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier static struct
279a747e4fSDavid du Colombier {
289a747e4fSDavid du Colombier /*	Lock;	*/
299a747e4fSDavid du Colombier 	int	convcount;
309a747e4fSDavid du Colombier 	char	index[MAXFMT];
319a747e4fSDavid du Colombier 	int	(*conv[MAXCONV])(va_list*, Fconv*);
329a747e4fSDavid du Colombier } fmtalloc;
339a747e4fSDavid du Colombier 
349a747e4fSDavid du Colombier static	int	noconv(va_list*, Fconv*);
359a747e4fSDavid du Colombier static	int	flags(va_list*, Fconv*);
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier static	int	cconv(va_list*, Fconv*);
389a747e4fSDavid du Colombier static	int	sconv(va_list*, Fconv*);
399a747e4fSDavid du Colombier static	int	percent(va_list*, Fconv*);
409a747e4fSDavid du Colombier static	int	column(va_list*, Fconv*);
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier extern	int	numbconv(va_list*, Fconv*);
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier static	void
initfmt(void)469a747e4fSDavid du Colombier initfmt(void)
479a747e4fSDavid du Colombier {
489a747e4fSDavid du Colombier 	int cc;
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier 	lock(&fmtalloc);
519a747e4fSDavid du Colombier 	if(fmtalloc.convcount <= 0) {
529a747e4fSDavid du Colombier 		cc = 0;
539a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = noconv;
549a747e4fSDavid du Colombier 		cc++;
559a747e4fSDavid du Colombier 
569a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = flags;
579a747e4fSDavid du Colombier 		fmtalloc.index['+'] = cc;
589a747e4fSDavid du Colombier 		fmtalloc.index['-'] = cc;
599a747e4fSDavid du Colombier 		fmtalloc.index['#'] = cc;
609a747e4fSDavid du Colombier 		fmtalloc.index['l'] = cc;
619a747e4fSDavid du Colombier 		fmtalloc.index['u'] = cc;
629a747e4fSDavid du Colombier 		cc++;
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = numbconv;
659a747e4fSDavid du Colombier 		fmtalloc.index['d'] = cc;
669a747e4fSDavid du Colombier 		fmtalloc.index['o'] = cc;
679a747e4fSDavid du Colombier 		fmtalloc.index['x'] = cc;
689a747e4fSDavid du Colombier 		fmtalloc.index['X'] = cc;
699a747e4fSDavid du Colombier 		fmtalloc.index['p'] = cc;
709a747e4fSDavid du Colombier 		cc++;
719a747e4fSDavid du Colombier 
729a747e4fSDavid du Colombier 
739a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = cconv;
749a747e4fSDavid du Colombier 		fmtalloc.index['c'] = cc;
759a747e4fSDavid du Colombier 		fmtalloc.index['C'] = cc;
769a747e4fSDavid du Colombier 		cc++;
779a747e4fSDavid du Colombier 
789a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = sconv;
799a747e4fSDavid du Colombier 		fmtalloc.index['s'] = cc;
809a747e4fSDavid du Colombier 		fmtalloc.index['S'] = cc;
819a747e4fSDavid du Colombier 		cc++;
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = percent;
849a747e4fSDavid du Colombier 		fmtalloc.index['%'] = cc;
859a747e4fSDavid du Colombier 		cc++;
869a747e4fSDavid du Colombier 
879a747e4fSDavid du Colombier 		fmtalloc.conv[cc] = column;
889a747e4fSDavid du Colombier 		fmtalloc.index['|'] = cc;
899a747e4fSDavid du Colombier 		cc++;
909a747e4fSDavid du Colombier 
919a747e4fSDavid du Colombier 		fmtalloc.convcount = cc;
929a747e4fSDavid du Colombier 	}
939a747e4fSDavid du Colombier 	unlock(&fmtalloc);
949a747e4fSDavid du Colombier }
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier int
fmtinstall(int c,int (* f)(va_list *,Fconv *))979a747e4fSDavid du Colombier fmtinstall(int c, int (*f)(va_list*, Fconv*))
989a747e4fSDavid du Colombier {
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier 	if(fmtalloc.convcount <= 0)
1019a747e4fSDavid du Colombier 		initfmt();
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier 	lock(&fmtalloc);
1049a747e4fSDavid du Colombier 	if(c < 0 || c >= MAXFMT) {
1059a747e4fSDavid du Colombier 		unlock(&fmtalloc);
1069a747e4fSDavid du Colombier 		return -1;
1079a747e4fSDavid du Colombier 	}
1089a747e4fSDavid du Colombier 	if(fmtalloc.convcount >= MAXCONV) {
1099a747e4fSDavid du Colombier 		unlock(&fmtalloc);
1109a747e4fSDavid du Colombier 		return -1;
1119a747e4fSDavid du Colombier 	}
1129a747e4fSDavid du Colombier 	fmtalloc.conv[fmtalloc.convcount] = f;
1139a747e4fSDavid du Colombier 	fmtalloc.index[c] = fmtalloc.convcount;
1149a747e4fSDavid du Colombier 	fmtalloc.convcount++;
1159a747e4fSDavid du Colombier 
1169a747e4fSDavid du Colombier 	unlock(&fmtalloc);
1179a747e4fSDavid du Colombier 	return 0;
1189a747e4fSDavid du Colombier }
1199a747e4fSDavid du Colombier 
1209a747e4fSDavid du Colombier static	void
pchar(Rune c,Fconv * fp)1219a747e4fSDavid du Colombier pchar(Rune c, Fconv *fp)
1229a747e4fSDavid du Colombier {
1239a747e4fSDavid du Colombier 	int n;
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	n = fp->eout - fp->out;
1269a747e4fSDavid du Colombier 	if(n > 0) {
1279a747e4fSDavid du Colombier 		if(c < Runeself) {
1289a747e4fSDavid du Colombier 			*fp->out++ = c;
1299a747e4fSDavid du Colombier 			return;
1309a747e4fSDavid du Colombier 		}
1319a747e4fSDavid du Colombier 		if(n >= UTFmax || n >= runelen(c)) {
1329a747e4fSDavid du Colombier 			n = runetochar(fp->out, &c);
1339a747e4fSDavid du Colombier 			fp->out += n;
1349a747e4fSDavid du Colombier 			return;
1359a747e4fSDavid du Colombier 		}
1369a747e4fSDavid du Colombier 		fp->eout = fp->out;
1379a747e4fSDavid du Colombier 	}
1389a747e4fSDavid du Colombier }
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier char*
doprint(char * s,char * es,char * fmt,va_list * argp)141*9df35464SDavid du Colombier doprint(char *s, char *es, char *fmt, va_list *argp)
1429a747e4fSDavid du Colombier {
1439a747e4fSDavid du Colombier 	int n, c;
1449a747e4fSDavid du Colombier 	Rune rune;
1459a747e4fSDavid du Colombier 	Fconv local;
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	if(fmtalloc.convcount <= 0)
1489a747e4fSDavid du Colombier 		initfmt();
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier 	if(s >= es)
1519a747e4fSDavid du Colombier 		return s;
1529a747e4fSDavid du Colombier 	local.out = s;
1539a747e4fSDavid du Colombier 	local.eout = es-1;
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier loop:
1569a747e4fSDavid du Colombier 	c = *fmt & 0xff;
1579a747e4fSDavid du Colombier 	if(c >= Runeself) {
1589a747e4fSDavid du Colombier 		n = chartorune(&rune, fmt);
1599a747e4fSDavid du Colombier 		fmt += n;
1609a747e4fSDavid du Colombier 		c = rune;
1619a747e4fSDavid du Colombier 	} else
1629a747e4fSDavid du Colombier 		fmt++;
1639a747e4fSDavid du Colombier 	switch(c) {
1649a747e4fSDavid du Colombier 	case 0:
1659a747e4fSDavid du Colombier 		*local.out = 0;
1669a747e4fSDavid du Colombier 		return local.out;
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier 	default:
1699a747e4fSDavid du Colombier 		printcol++;
1709a747e4fSDavid du Colombier 		goto common;
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	case '\n':
1739a747e4fSDavid du Colombier 		printcol = 0;
1749a747e4fSDavid du Colombier 		goto common;
1759a747e4fSDavid du Colombier 
1769a747e4fSDavid du Colombier 	case '\t':
1779a747e4fSDavid du Colombier 		printcol = (printcol+8) & ~7;
1789a747e4fSDavid du Colombier 		goto common;
1799a747e4fSDavid du Colombier 
1809a747e4fSDavid du Colombier 	common:
1819a747e4fSDavid du Colombier 		pchar(c, &local);
1829a747e4fSDavid du Colombier 		goto loop;
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier 	case '%':
1859a747e4fSDavid du Colombier 		break;
1869a747e4fSDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	local.f1 = NONE;
1889a747e4fSDavid du Colombier 	local.f2 = NONE;
1899a747e4fSDavid du Colombier 	local.f3 = 0;
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier 	/*
1929a747e4fSDavid du Colombier 	 * read one of the following
1939a747e4fSDavid du Colombier 	 *	1. number, => f1, f2 in order.
1949a747e4fSDavid du Colombier 	 *	2. '*' same as number (from args)
1959a747e4fSDavid du Colombier 	 *	3. '.' ignored (separates numbers)
1969a747e4fSDavid du Colombier 	 *	4. flag => f3
1979a747e4fSDavid du Colombier 	 *	5. verb and terminate
1989a747e4fSDavid du Colombier 	 */
1999a747e4fSDavid du Colombier l0:
2009a747e4fSDavid du Colombier 	c = *fmt & 0xff;
2019a747e4fSDavid du Colombier 	if(c >= Runeself) {
2029a747e4fSDavid du Colombier 		n = chartorune(&rune, fmt);
2039a747e4fSDavid du Colombier 		fmt += n;
2049a747e4fSDavid du Colombier 		c = rune;
2059a747e4fSDavid du Colombier 	} else
2069a747e4fSDavid du Colombier 		fmt++;
2079a747e4fSDavid du Colombier 
2089a747e4fSDavid du Colombier l1:
2099a747e4fSDavid du Colombier 	if(c == 0) {
2109a747e4fSDavid du Colombier 		fmt--;
2119a747e4fSDavid du Colombier 		goto loop;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	if(c == '.') {
2149a747e4fSDavid du Colombier 		if(local.f1 == NONE)
2159a747e4fSDavid du Colombier 			local.f1 = 0;
2169a747e4fSDavid du Colombier 		local.f2 = 0;
2179a747e4fSDavid du Colombier 		goto l0;
2189a747e4fSDavid du Colombier 	}
2199a747e4fSDavid du Colombier 	if((c >= '1' && c <= '9') ||
2209a747e4fSDavid du Colombier 	   (c == '0' && local.f1 != NONE)) {	/* '0' is a digit for f2 */
2219a747e4fSDavid du Colombier 		n = 0;
2229a747e4fSDavid du Colombier 		while(c >= '0' && c <= '9') {
2239a747e4fSDavid du Colombier 			n = n*10 + c-'0';
2249a747e4fSDavid du Colombier 			c = *fmt++;
2259a747e4fSDavid du Colombier 		}
2269a747e4fSDavid du Colombier 		if(local.f1 == NONE)
2279a747e4fSDavid du Colombier 			local.f1 = n;
2289a747e4fSDavid du Colombier 		else
2299a747e4fSDavid du Colombier 			local.f2 = n;
2309a747e4fSDavid du Colombier 		goto l1;
2319a747e4fSDavid du Colombier 	}
2329a747e4fSDavid du Colombier 	if(c == '*') {
233*9df35464SDavid du Colombier 		n = va_arg(*argp, int);
2349a747e4fSDavid du Colombier 		if(local.f1 == NONE)
2359a747e4fSDavid du Colombier 			local.f1 = n;
2369a747e4fSDavid du Colombier 		else
2379a747e4fSDavid du Colombier 			local.f2 = n;
2389a747e4fSDavid du Colombier 		goto l0;
2399a747e4fSDavid du Colombier 	}
2409a747e4fSDavid du Colombier 	n = 0;
2419a747e4fSDavid du Colombier 	if(c >= 0 && c < MAXFMT)
2429a747e4fSDavid du Colombier 		n = fmtalloc.index[c];
2439a747e4fSDavid du Colombier 	local.chr = c;
244*9df35464SDavid du Colombier 	n = (*fmtalloc.conv[n])(argp, &local);
2459a747e4fSDavid du Colombier 	if(n < 0) {
2469a747e4fSDavid du Colombier 		local.f3 |= -n;
2479a747e4fSDavid du Colombier 		goto l0;
2489a747e4fSDavid du Colombier 	}
2499a747e4fSDavid du Colombier 	goto loop;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier 
2529a747e4fSDavid du Colombier int
numbconv(va_list * arg,Fconv * fp)2539a747e4fSDavid du Colombier numbconv(va_list *arg, Fconv *fp)
2549a747e4fSDavid du Colombier {
2559a747e4fSDavid du Colombier 	char s[IDIGIT];
2569a747e4fSDavid du Colombier 	int i, f, n, b, ucase;
2579a747e4fSDavid du Colombier 	long v;
2589a747e4fSDavid du Colombier 	vlong vl;
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier 	SET(v);
2619a747e4fSDavid du Colombier 	SET(vl);
2629a747e4fSDavid du Colombier 
2639a747e4fSDavid du Colombier 	ucase = 0;
2649a747e4fSDavid du Colombier 	b = fp->chr;
2659a747e4fSDavid du Colombier 	switch(fp->chr) {
2669a747e4fSDavid du Colombier 	case 'u':
2679a747e4fSDavid du Colombier 		fp->f3 |= FUNSIGN;
2689a747e4fSDavid du Colombier 	case 'd':
2699a747e4fSDavid du Colombier 		b = 10;
2709a747e4fSDavid du Colombier 		break;
2719a747e4fSDavid du Colombier 
2729a747e4fSDavid du Colombier 	case 'b':
2739a747e4fSDavid du Colombier 		b = 2;
2749a747e4fSDavid du Colombier 		break;
2759a747e4fSDavid du Colombier 
2769a747e4fSDavid du Colombier 	case 'o':
2779a747e4fSDavid du Colombier 		b = 8;
2789a747e4fSDavid du Colombier 		break;
2799a747e4fSDavid du Colombier 
2809a747e4fSDavid du Colombier 	case 'X':
2819a747e4fSDavid du Colombier 		ucase = 1;
2829a747e4fSDavid du Colombier 	case 'x':
2839a747e4fSDavid du Colombier 		b = 16;
2849a747e4fSDavid du Colombier 		break;
2859a747e4fSDavid du Colombier 	case 'p':
2869a747e4fSDavid du Colombier 		fp->f3 |= FPOINTER|FUNSIGN;
2879a747e4fSDavid du Colombier 		b = 16;
2889a747e4fSDavid du Colombier 		break;
2899a747e4fSDavid du Colombier 	}
2909a747e4fSDavid du Colombier 
2919a747e4fSDavid du Colombier 	f = 0;
2929a747e4fSDavid du Colombier 	switch(fp->f3 & (FVLONG|FLONG|FUNSIGN|FPOINTER)) {
2939a747e4fSDavid du Colombier 	case FVLONG|FLONG:
2949a747e4fSDavid du Colombier 		vl = va_arg(*arg, vlong);
2959a747e4fSDavid du Colombier 		break;
2969a747e4fSDavid du Colombier 
2979a747e4fSDavid du Colombier 	case FUNSIGN|FVLONG|FLONG:
2989a747e4fSDavid du Colombier 		vl = va_arg(*arg, uvlong);
2999a747e4fSDavid du Colombier 		break;
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier 	case FUNSIGN|FPOINTER:
3029a747e4fSDavid du Colombier 		v = (ulong)va_arg(*arg, void*);
3039a747e4fSDavid du Colombier 		break;
3049a747e4fSDavid du Colombier 
3059a747e4fSDavid du Colombier 	case FLONG:
3069a747e4fSDavid du Colombier 		v = va_arg(*arg, long);
3079a747e4fSDavid du Colombier 		break;
3089a747e4fSDavid du Colombier 
3099a747e4fSDavid du Colombier 	case FUNSIGN|FLONG:
3109a747e4fSDavid du Colombier 		v = va_arg(*arg, ulong);
3119a747e4fSDavid du Colombier 		break;
3129a747e4fSDavid du Colombier 
3139a747e4fSDavid du Colombier 	default:
3149a747e4fSDavid du Colombier 		v = va_arg(*arg, int);
3159a747e4fSDavid du Colombier 		break;
3169a747e4fSDavid du Colombier 
3179a747e4fSDavid du Colombier 	case FUNSIGN:
3189a747e4fSDavid du Colombier 		v = va_arg(*arg, unsigned);
3199a747e4fSDavid du Colombier 		break;
3209a747e4fSDavid du Colombier 	}
3219a747e4fSDavid du Colombier 	if(fp->f3 & FVLONG) {
3229a747e4fSDavid du Colombier 		if(!(fp->f3 & FUNSIGN) && vl < 0) {
3239a747e4fSDavid du Colombier 			vl = -vl;
3249a747e4fSDavid du Colombier 			f = 1;
3259a747e4fSDavid du Colombier 		}
3269a747e4fSDavid du Colombier 	} else {
3279a747e4fSDavid du Colombier 		if(!(fp->f3 & FUNSIGN) && v < 0) {
3289a747e4fSDavid du Colombier 			v = -v;
3299a747e4fSDavid du Colombier 			f = 1;
3309a747e4fSDavid du Colombier 		}
3319a747e4fSDavid du Colombier 	}
3329a747e4fSDavid du Colombier 	s[IDIGIT-1] = 0;
3339a747e4fSDavid du Colombier 	for(i = IDIGIT-2;; i--) {
3349a747e4fSDavid du Colombier 		if(fp->f3 & FVLONG)
3359a747e4fSDavid du Colombier 			n = (uvlong)vl % b;
3369a747e4fSDavid du Colombier 		else
3379a747e4fSDavid du Colombier 			n = (ulong)v % b;
3389a747e4fSDavid du Colombier 		n += '0';
3399a747e4fSDavid du Colombier 		if(n > '9') {
3409a747e4fSDavid du Colombier 			n += 'a' - ('9'+1);
3419a747e4fSDavid du Colombier 			if(ucase)
3429a747e4fSDavid du Colombier 				n += 'A'-'a';
3439a747e4fSDavid du Colombier 		}
3449a747e4fSDavid du Colombier 		s[i] = n;
3459a747e4fSDavid du Colombier 		if(i < 2)
3469a747e4fSDavid du Colombier 			break;
3479a747e4fSDavid du Colombier 		if(fp->f3 & FVLONG)
3489a747e4fSDavid du Colombier 			vl = (uvlong)vl / b;
3499a747e4fSDavid du Colombier 		else
3509a747e4fSDavid du Colombier 			v = (ulong)v / b;
3519a747e4fSDavid du Colombier 		if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
3529a747e4fSDavid du Colombier 			continue;
3539a747e4fSDavid du Colombier 		if(fp->f3 & FVLONG) {
3549a747e4fSDavid du Colombier 			if(vl <= 0)
3559a747e4fSDavid du Colombier 				break;
3569a747e4fSDavid du Colombier 			continue;
3579a747e4fSDavid du Colombier 		}
3589a747e4fSDavid du Colombier 		if(v <= 0)
3599a747e4fSDavid du Colombier 			break;
3609a747e4fSDavid du Colombier 	}
3619a747e4fSDavid du Colombier 
3629a747e4fSDavid du Colombier 	if(fp->f3 & FSHARP) {
3639a747e4fSDavid du Colombier 		if(b == 8 && s[i] != '0')
3649a747e4fSDavid du Colombier 			s[--i] = '0';
3659a747e4fSDavid du Colombier 		if(b == 16) {
3669a747e4fSDavid du Colombier 			if(ucase)
3679a747e4fSDavid du Colombier 				s[--i] = 'X';
3689a747e4fSDavid du Colombier 			else
3699a747e4fSDavid du Colombier 				s[--i] = 'x';
3709a747e4fSDavid du Colombier 			s[--i] = '0';
3719a747e4fSDavid du Colombier 		}
3729a747e4fSDavid du Colombier 	}
3739a747e4fSDavid du Colombier 	if(f)
3749a747e4fSDavid du Colombier 		s[--i] = '-';
3759a747e4fSDavid du Colombier 	else if(fp->f3 & FPLUS)
3769a747e4fSDavid du Colombier 		s[--i] = '+';
3779a747e4fSDavid du Colombier 
3789a747e4fSDavid du Colombier 	fp->f2 = NONE;
3799a747e4fSDavid du Colombier 	strconv(s+i, fp);
3809a747e4fSDavid du Colombier 	return 0;
3819a747e4fSDavid du Colombier }
3829a747e4fSDavid du Colombier 
3839a747e4fSDavid du Colombier void
Strconv(Rune * s,Fconv * fp)3849a747e4fSDavid du Colombier Strconv(Rune *s, Fconv *fp)
3859a747e4fSDavid du Colombier {
3869a747e4fSDavid du Colombier 	int n, c;
3879a747e4fSDavid du Colombier 
3889a747e4fSDavid du Colombier 	if(fp->f3 & FMINUS)
3899a747e4fSDavid du Colombier 		fp->f1 = -fp->f1;
3909a747e4fSDavid du Colombier 	n = 0;
3919a747e4fSDavid du Colombier 	if(fp->f1 != NONE && fp->f1 >= 0) {
3929a747e4fSDavid du Colombier 		for(; s[n]; n++)
3939a747e4fSDavid du Colombier 			;
3949a747e4fSDavid du Colombier 		while(n < fp->f1) {
3959a747e4fSDavid du Colombier 			pchar(' ', fp);
3969a747e4fSDavid du Colombier 			printcol++;
3979a747e4fSDavid du Colombier 			n++;
3989a747e4fSDavid du Colombier 		}
3999a747e4fSDavid du Colombier 	}
4009a747e4fSDavid du Colombier 	for(;;) {
4019a747e4fSDavid du Colombier 		c = *s++;
4029a747e4fSDavid du Colombier 		if(c == 0)
4039a747e4fSDavid du Colombier 			break;
4049a747e4fSDavid du Colombier 		n++;
4059a747e4fSDavid du Colombier 		if(fp->f2 == NONE || fp->f2 > 0) {
4069a747e4fSDavid du Colombier 			pchar(c, fp);
4079a747e4fSDavid du Colombier 			if(fp->f2 != NONE)
4089a747e4fSDavid du Colombier 				fp->f2--;
4099a747e4fSDavid du Colombier 			switch(c) {
4109a747e4fSDavid du Colombier 			default:
4119a747e4fSDavid du Colombier 				printcol++;
4129a747e4fSDavid du Colombier 				break;
4139a747e4fSDavid du Colombier 			case '\n':
4149a747e4fSDavid du Colombier 				printcol = 0;
4159a747e4fSDavid du Colombier 				break;
4169a747e4fSDavid du Colombier 			case '\t':
4179a747e4fSDavid du Colombier 				printcol = (printcol+8) & ~7;
4189a747e4fSDavid du Colombier 				break;
4199a747e4fSDavid du Colombier 			}
4209a747e4fSDavid du Colombier 		}
4219a747e4fSDavid du Colombier 	}
4229a747e4fSDavid du Colombier 	if(fp->f1 != NONE && fp->f1 < 0) {
4239a747e4fSDavid du Colombier 		fp->f1 = -fp->f1;
4249a747e4fSDavid du Colombier 		while(n < fp->f1) {
4259a747e4fSDavid du Colombier 			pchar(' ', fp);
4269a747e4fSDavid du Colombier 			printcol++;
4279a747e4fSDavid du Colombier 			n++;
4289a747e4fSDavid du Colombier 		}
4299a747e4fSDavid du Colombier 	}
4309a747e4fSDavid du Colombier }
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier void
strconv(char * s,Fconv * fp)4339a747e4fSDavid du Colombier strconv(char *s, Fconv *fp)
4349a747e4fSDavid du Colombier {
4359a747e4fSDavid du Colombier 	int n, c, i;
4369a747e4fSDavid du Colombier 	Rune rune;
4379a747e4fSDavid du Colombier 
4389a747e4fSDavid du Colombier 	if(fp->f3 & FMINUS)
4399a747e4fSDavid du Colombier 		fp->f1 = -fp->f1;
4409a747e4fSDavid du Colombier 	n = 0;
4419a747e4fSDavid du Colombier 	if(fp->f1 != NONE && fp->f1 >= 0) {
4429a747e4fSDavid du Colombier 		n = utflen(s);
4439a747e4fSDavid du Colombier 		while(n < fp->f1) {
4449a747e4fSDavid du Colombier 			pchar(' ', fp);
4459a747e4fSDavid du Colombier 			printcol++;
4469a747e4fSDavid du Colombier 			n++;
4479a747e4fSDavid du Colombier 		}
4489a747e4fSDavid du Colombier 	}
4499a747e4fSDavid du Colombier 	for(;;) {
4509a747e4fSDavid du Colombier 		c = *s & 0xff;
4519a747e4fSDavid du Colombier 		if(c >= Runeself) {
4529a747e4fSDavid du Colombier 			i = chartorune(&rune, s);
4539a747e4fSDavid du Colombier 			s += i;
4549a747e4fSDavid du Colombier 			c = rune;
4559a747e4fSDavid du Colombier 		} else
4569a747e4fSDavid du Colombier 			s++;
4579a747e4fSDavid du Colombier 		if(c == 0)
4589a747e4fSDavid du Colombier 			break;
4599a747e4fSDavid du Colombier 		n++;
4609a747e4fSDavid du Colombier 		if(fp->f2 == NONE || fp->f2 > 0) {
4619a747e4fSDavid du Colombier 			pchar(c, fp);
4629a747e4fSDavid du Colombier 			if(fp->f2 != NONE)
4639a747e4fSDavid du Colombier 				fp->f2--;
4649a747e4fSDavid du Colombier 			switch(c) {
4659a747e4fSDavid du Colombier 			default:
4669a747e4fSDavid du Colombier 				printcol++;
4679a747e4fSDavid du Colombier 				break;
4689a747e4fSDavid du Colombier 			case '\n':
4699a747e4fSDavid du Colombier 				printcol = 0;
4709a747e4fSDavid du Colombier 				break;
4719a747e4fSDavid du Colombier 			case '\t':
4729a747e4fSDavid du Colombier 				printcol = (printcol+8) & ~7;
4739a747e4fSDavid du Colombier 				break;
4749a747e4fSDavid du Colombier 			}
4759a747e4fSDavid du Colombier 		}
4769a747e4fSDavid du Colombier 	}
4779a747e4fSDavid du Colombier 	if(fp->f1 != NONE && fp->f1 < 0) {
4789a747e4fSDavid du Colombier 		fp->f1 = -fp->f1;
4799a747e4fSDavid du Colombier 		while(n < fp->f1) {
4809a747e4fSDavid du Colombier 			pchar(' ', fp);
4819a747e4fSDavid du Colombier 			printcol++;
4829a747e4fSDavid du Colombier 			n++;
4839a747e4fSDavid du Colombier 		}
4849a747e4fSDavid du Colombier 	}
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier 
4879a747e4fSDavid du Colombier static int
noconv(va_list * va,Fconv * fp)4889a747e4fSDavid du Colombier noconv(va_list *va, Fconv *fp)
4899a747e4fSDavid du Colombier {
4909a747e4fSDavid du Colombier 	char s[10];
4919a747e4fSDavid du Colombier 
4929a747e4fSDavid du Colombier 	USED(va);
4939a747e4fSDavid du Colombier 	s[0] = '*';
4949a747e4fSDavid du Colombier 	s[1] = fp->chr;
4959a747e4fSDavid du Colombier 	s[2] = '*';
4969a747e4fSDavid du Colombier 	s[3] = 0;
4979a747e4fSDavid du Colombier 	fp->f1 = 0;
4989a747e4fSDavid du Colombier 	fp->f2 = NONE;
4999a747e4fSDavid du Colombier 	fp->f3 = 0;
5009a747e4fSDavid du Colombier 	strconv(s, fp);
5019a747e4fSDavid du Colombier 	return 0;
5029a747e4fSDavid du Colombier }
5039a747e4fSDavid du Colombier 
5049a747e4fSDavid du Colombier static int
cconv(va_list * arg,Fconv * fp)5059a747e4fSDavid du Colombier cconv(va_list *arg, Fconv *fp)
5069a747e4fSDavid du Colombier {
5079a747e4fSDavid du Colombier 	char s[10];
5089a747e4fSDavid du Colombier 	Rune rune;
5099a747e4fSDavid du Colombier 
5109a747e4fSDavid du Colombier 	rune = va_arg(*arg, int);
5119a747e4fSDavid du Colombier 	if(fp->chr == 'c')
5129a747e4fSDavid du Colombier 		rune &= 0xff;
5139a747e4fSDavid du Colombier 	s[runetochar(s, &rune)] = 0;
5149a747e4fSDavid du Colombier 
5159a747e4fSDavid du Colombier 	fp->f2 = NONE;
5169a747e4fSDavid du Colombier 	strconv(s, fp);
5179a747e4fSDavid du Colombier 	return 0;
5189a747e4fSDavid du Colombier }
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier static Rune null[] = { L'<', L'n', L'u', L'l', L'l', L'>', L'\0' };
5219a747e4fSDavid du Colombier 
5229a747e4fSDavid du Colombier static	int
sconv(va_list * arg,Fconv * fp)5239a747e4fSDavid du Colombier sconv(va_list *arg, Fconv *fp)
5249a747e4fSDavid du Colombier {
5259a747e4fSDavid du Colombier 	char *s;
5269a747e4fSDavid du Colombier 	Rune *r;
5279a747e4fSDavid du Colombier 
5289a747e4fSDavid du Colombier 	if(fp->chr == 's') {
5299a747e4fSDavid du Colombier 		s = va_arg(*arg, char*);
5309a747e4fSDavid du Colombier 		if(s == 0)
5319a747e4fSDavid du Colombier 			s = "<null>";
5329a747e4fSDavid du Colombier 		strconv(s, fp);
5339a747e4fSDavid du Colombier 	} else {
5349a747e4fSDavid du Colombier 		r = va_arg(*arg, Rune*);
5359a747e4fSDavid du Colombier 		if(r == 0)
5369a747e4fSDavid du Colombier 			r = null;
5379a747e4fSDavid du Colombier 		Strconv(r, fp);
5389a747e4fSDavid du Colombier 	}
5399a747e4fSDavid du Colombier 	return 0;
5409a747e4fSDavid du Colombier }
5419a747e4fSDavid du Colombier 
5429a747e4fSDavid du Colombier static	int
percent(va_list * va,Fconv * fp)5439a747e4fSDavid du Colombier percent(va_list *va, Fconv *fp)
5449a747e4fSDavid du Colombier {
5459a747e4fSDavid du Colombier 	USED(va);
5469a747e4fSDavid du Colombier 
5479a747e4fSDavid du Colombier 	pchar('%', fp);
5489a747e4fSDavid du Colombier 	printcol++;
5499a747e4fSDavid du Colombier 	return 0;
5509a747e4fSDavid du Colombier }
5519a747e4fSDavid du Colombier 
5529a747e4fSDavid du Colombier static	int
column(va_list * arg,Fconv * fp)5539a747e4fSDavid du Colombier column(va_list *arg, Fconv *fp)
5549a747e4fSDavid du Colombier {
5559a747e4fSDavid du Colombier 	int col, pc;
5569a747e4fSDavid du Colombier 
5579a747e4fSDavid du Colombier 	col = va_arg(*arg, int);
5589a747e4fSDavid du Colombier 	while(printcol < col) {
5599a747e4fSDavid du Colombier 		pc = (printcol+8) & ~7;
5609a747e4fSDavid du Colombier 		if(pc <= col) {
5619a747e4fSDavid du Colombier 			pchar('\t', fp);
5629a747e4fSDavid du Colombier 			printcol = pc;
5639a747e4fSDavid du Colombier 		} else {
5649a747e4fSDavid du Colombier 			pchar(' ', fp);
5659a747e4fSDavid du Colombier 			printcol++;
5669a747e4fSDavid du Colombier 		}
5679a747e4fSDavid du Colombier 	}
5689a747e4fSDavid du Colombier 	return 0;
5699a747e4fSDavid du Colombier }
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier static int
flags(va_list * va,Fconv * fp)5729a747e4fSDavid du Colombier flags(va_list *va, Fconv *fp)
5739a747e4fSDavid du Colombier {
5749a747e4fSDavid du Colombier 	int f;
5759a747e4fSDavid du Colombier 
5769a747e4fSDavid du Colombier 	USED(va);
5779a747e4fSDavid du Colombier 	f = 0;
5789a747e4fSDavid du Colombier 	switch(fp->chr) {
5799a747e4fSDavid du Colombier 	case '+':
5809a747e4fSDavid du Colombier 		f = FPLUS;
5819a747e4fSDavid du Colombier 		break;
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier 	case '-':
5849a747e4fSDavid du Colombier 		f = FMINUS;
5859a747e4fSDavid du Colombier 		break;
5869a747e4fSDavid du Colombier 
5879a747e4fSDavid du Colombier 	case '#':
5889a747e4fSDavid du Colombier 		f = FSHARP;
5899a747e4fSDavid du Colombier 		break;
5909a747e4fSDavid du Colombier 
5919a747e4fSDavid du Colombier 	case 'l':
5929a747e4fSDavid du Colombier 		f = FLONG;
5939a747e4fSDavid du Colombier 		if(fp->f3 & FLONG)
5949a747e4fSDavid du Colombier 			f = FVLONG;
5959a747e4fSDavid du Colombier 		break;
5969a747e4fSDavid du Colombier 
5979a747e4fSDavid du Colombier 	case 'u':
5989a747e4fSDavid du Colombier 		f = FUNSIGN;
5999a747e4fSDavid du Colombier 		break;
6009a747e4fSDavid du Colombier 	}
6019a747e4fSDavid du Colombier 	return -f;
6029a747e4fSDavid du Colombier }
6039a747e4fSDavid du Colombier 
6049a747e4fSDavid du Colombier /*
6059a747e4fSDavid du Colombier  * This code is superseded by the more accurate (but more complex)
6069a747e4fSDavid du Colombier  * algorithm in fltconv.c and dtoa.c.  Uncomment this routine to avoid
6079a747e4fSDavid du Colombier  * using the more complex code.
6089a747e4fSDavid du Colombier  *
6099a747e4fSDavid du Colombier  */
6109a747e4fSDavid du Colombier 
611