xref: /inferno-os/lib9/fmt.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth /*
2*37da2899SCharles.Forsyth  * The authors of this software are Rob Pike and Ken Thompson.
3*37da2899SCharles.Forsyth  *              Copyright (c) 2002 by Lucent Technologies.
4*37da2899SCharles.Forsyth  * Permission to use, copy, modify, and distribute this software for any
5*37da2899SCharles.Forsyth  * purpose without fee is hereby granted, provided that this entire notice
6*37da2899SCharles.Forsyth  * is included in all copies of any software which is or includes a copy
7*37da2899SCharles.Forsyth  * or modification of this software and in all copies of the supporting
8*37da2899SCharles.Forsyth  * documentation for such software.
9*37da2899SCharles.Forsyth  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10*37da2899SCharles.Forsyth  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
11*37da2899SCharles.Forsyth  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12*37da2899SCharles.Forsyth  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13*37da2899SCharles.Forsyth  */
14*37da2899SCharles.Forsyth #include "lib9.h"
15*37da2899SCharles.Forsyth #include "fmtdef.h"
16*37da2899SCharles.Forsyth 
17*37da2899SCharles.Forsyth enum
18*37da2899SCharles.Forsyth {
19*37da2899SCharles.Forsyth 	Maxfmt = 64
20*37da2899SCharles.Forsyth };
21*37da2899SCharles.Forsyth 
22*37da2899SCharles.Forsyth typedef struct Convfmt Convfmt;
23*37da2899SCharles.Forsyth struct Convfmt
24*37da2899SCharles.Forsyth {
25*37da2899SCharles.Forsyth 	int	c;
26*37da2899SCharles.Forsyth 	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
27*37da2899SCharles.Forsyth };
28*37da2899SCharles.Forsyth 
29*37da2899SCharles.Forsyth struct
30*37da2899SCharles.Forsyth {
31*37da2899SCharles.Forsyth 	/* lock by calling _fmtlock, _fmtunlock */
32*37da2899SCharles.Forsyth 	int	nfmt;
33*37da2899SCharles.Forsyth 	Convfmt	fmt[Maxfmt];
34*37da2899SCharles.Forsyth } fmtalloc;
35*37da2899SCharles.Forsyth 
36*37da2899SCharles.Forsyth static Convfmt knownfmt[] = {
37*37da2899SCharles.Forsyth 	' ',	_flagfmt,
38*37da2899SCharles.Forsyth 	'#',	_flagfmt,
39*37da2899SCharles.Forsyth 	'%',	_percentfmt,
40*37da2899SCharles.Forsyth 	'+',	_flagfmt,
41*37da2899SCharles.Forsyth 	',',	_flagfmt,
42*37da2899SCharles.Forsyth 	'-',	_flagfmt,
43*37da2899SCharles.Forsyth 	'C',	_runefmt,
44*37da2899SCharles.Forsyth 	'S',	_runesfmt,
45*37da2899SCharles.Forsyth 	'X',	_ifmt,
46*37da2899SCharles.Forsyth 	'b',	_ifmt,
47*37da2899SCharles.Forsyth 	'c',	_charfmt,
48*37da2899SCharles.Forsyth 	'd',	_ifmt,
49*37da2899SCharles.Forsyth 	'h',	_flagfmt,
50*37da2899SCharles.Forsyth 	'l',	_flagfmt,
51*37da2899SCharles.Forsyth 	'n',	_countfmt,
52*37da2899SCharles.Forsyth 	'o',	_ifmt,
53*37da2899SCharles.Forsyth 	'p',	_ifmt,
54*37da2899SCharles.Forsyth 	'r',	errfmt,
55*37da2899SCharles.Forsyth 	's',	_strfmt,
56*37da2899SCharles.Forsyth 	'u',	_flagfmt,
57*37da2899SCharles.Forsyth 	'x',	_ifmt,
58*37da2899SCharles.Forsyth 	0,	nil,
59*37da2899SCharles.Forsyth };
60*37da2899SCharles.Forsyth 
61*37da2899SCharles.Forsyth int	(*doquote)(int);
62*37da2899SCharles.Forsyth 
63*37da2899SCharles.Forsyth static Fmts
fmtfmt(int c)64*37da2899SCharles.Forsyth fmtfmt(int c)
65*37da2899SCharles.Forsyth {
66*37da2899SCharles.Forsyth 	Convfmt *p, *ep;
67*37da2899SCharles.Forsyth 
68*37da2899SCharles.Forsyth 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
69*37da2899SCharles.Forsyth 	for(p=fmtalloc.fmt; p<ep; p++)
70*37da2899SCharles.Forsyth 		if(p->c == c)
71*37da2899SCharles.Forsyth 			return p->fmt;
72*37da2899SCharles.Forsyth 
73*37da2899SCharles.Forsyth 	/* is this a predefined format char? */
74*37da2899SCharles.Forsyth 	for(p=knownfmt; p->c; p++)
75*37da2899SCharles.Forsyth 		if(p->c == c){
76*37da2899SCharles.Forsyth 			/* no need to lock; fmtinstall is idempotent */
77*37da2899SCharles.Forsyth 			fmtinstall(p->c, p->fmt);
78*37da2899SCharles.Forsyth 			while(p->fmt == nil)	/* loop until value is updated */
79*37da2899SCharles.Forsyth 				;
80*37da2899SCharles.Forsyth 			return p->fmt;
81*37da2899SCharles.Forsyth 		}
82*37da2899SCharles.Forsyth 
83*37da2899SCharles.Forsyth 	return _badfmt;
84*37da2899SCharles.Forsyth }
85*37da2899SCharles.Forsyth 
86*37da2899SCharles.Forsyth int
fmtinstall(int c,Fmts f)87*37da2899SCharles.Forsyth fmtinstall(int c, Fmts f)
88*37da2899SCharles.Forsyth {
89*37da2899SCharles.Forsyth 	Convfmt *p, *ep;
90*37da2899SCharles.Forsyth 
91*37da2899SCharles.Forsyth 	if(c<=0 || c>=65536)
92*37da2899SCharles.Forsyth 		return -1;
93*37da2899SCharles.Forsyth 	if(!f)
94*37da2899SCharles.Forsyth 		f = _badfmt;
95*37da2899SCharles.Forsyth 
96*37da2899SCharles.Forsyth 	_fmtlock();
97*37da2899SCharles.Forsyth 
98*37da2899SCharles.Forsyth 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
99*37da2899SCharles.Forsyth 	for(p=fmtalloc.fmt; p<ep; p++)
100*37da2899SCharles.Forsyth 		if(p->c == c)
101*37da2899SCharles.Forsyth 			break;
102*37da2899SCharles.Forsyth 
103*37da2899SCharles.Forsyth 	if(p == &fmtalloc.fmt[Maxfmt]){
104*37da2899SCharles.Forsyth 		_fmtunlock();
105*37da2899SCharles.Forsyth 		return -1;
106*37da2899SCharles.Forsyth 	}
107*37da2899SCharles.Forsyth 
108*37da2899SCharles.Forsyth 	p->fmt = f;
109*37da2899SCharles.Forsyth 	if(p == ep){	/* installing a new format character */
110*37da2899SCharles.Forsyth 		fmtalloc.nfmt++;
111*37da2899SCharles.Forsyth 		p->c = c;
112*37da2899SCharles.Forsyth 	}
113*37da2899SCharles.Forsyth 
114*37da2899SCharles.Forsyth 	_fmtunlock();
115*37da2899SCharles.Forsyth 	return 0;
116*37da2899SCharles.Forsyth }
117*37da2899SCharles.Forsyth 
118*37da2899SCharles.Forsyth void*
_fmtdispatch(Fmt * f,void * fmt,int isrunes)119*37da2899SCharles.Forsyth _fmtdispatch(Fmt *f, void *fmt, int isrunes)
120*37da2899SCharles.Forsyth {
121*37da2899SCharles.Forsyth 	Rune rune, r;
122*37da2899SCharles.Forsyth 	int i, n;
123*37da2899SCharles.Forsyth 
124*37da2899SCharles.Forsyth 	f->flags = 0;
125*37da2899SCharles.Forsyth 	f->width = f->prec = 0;
126*37da2899SCharles.Forsyth 
127*37da2899SCharles.Forsyth 	for(;;){
128*37da2899SCharles.Forsyth 		if(isrunes){
129*37da2899SCharles.Forsyth 			r = *(Rune*)fmt;
130*37da2899SCharles.Forsyth 			fmt = (Rune*)fmt + 1;
131*37da2899SCharles.Forsyth 		}else{
132*37da2899SCharles.Forsyth 			fmt = (char*)fmt + chartorune(&rune, fmt);
133*37da2899SCharles.Forsyth 			r = rune;
134*37da2899SCharles.Forsyth 		}
135*37da2899SCharles.Forsyth 		f->r = r;
136*37da2899SCharles.Forsyth 		switch(r){
137*37da2899SCharles.Forsyth 		case '\0':
138*37da2899SCharles.Forsyth 			return nil;
139*37da2899SCharles.Forsyth 		case '.':
140*37da2899SCharles.Forsyth 			f->flags |= FmtWidth|FmtPrec;
141*37da2899SCharles.Forsyth 			continue;
142*37da2899SCharles.Forsyth 		case '0':
143*37da2899SCharles.Forsyth 			if(!(f->flags & FmtWidth)){
144*37da2899SCharles.Forsyth 				f->flags |= FmtZero;
145*37da2899SCharles.Forsyth 				continue;
146*37da2899SCharles.Forsyth 			}
147*37da2899SCharles.Forsyth 			/* fall through */
148*37da2899SCharles.Forsyth 		case '1': case '2': case '3': case '4':
149*37da2899SCharles.Forsyth 		case '5': case '6': case '7': case '8': case '9':
150*37da2899SCharles.Forsyth 			i = 0;
151*37da2899SCharles.Forsyth 			while(r >= '0' && r <= '9'){
152*37da2899SCharles.Forsyth 				i = i * 10 + r - '0';
153*37da2899SCharles.Forsyth 				if(isrunes){
154*37da2899SCharles.Forsyth 					r = *(Rune*)fmt;
155*37da2899SCharles.Forsyth 					fmt = (Rune*)fmt + 1;
156*37da2899SCharles.Forsyth 				}else{
157*37da2899SCharles.Forsyth 					r = *(char*)fmt;
158*37da2899SCharles.Forsyth 					fmt = (char*)fmt + 1;
159*37da2899SCharles.Forsyth 				}
160*37da2899SCharles.Forsyth 			}
161*37da2899SCharles.Forsyth 			if(isrunes)
162*37da2899SCharles.Forsyth 				fmt = (Rune*)fmt - 1;
163*37da2899SCharles.Forsyth 			else
164*37da2899SCharles.Forsyth 				fmt = (char*)fmt - 1;
165*37da2899SCharles.Forsyth 		numflag:
166*37da2899SCharles.Forsyth 			if(f->flags & FmtWidth){
167*37da2899SCharles.Forsyth 				f->flags |= FmtPrec;
168*37da2899SCharles.Forsyth 				f->prec = i;
169*37da2899SCharles.Forsyth 			}else{
170*37da2899SCharles.Forsyth 				f->flags |= FmtWidth;
171*37da2899SCharles.Forsyth 				f->width = i;
172*37da2899SCharles.Forsyth 			}
173*37da2899SCharles.Forsyth 			continue;
174*37da2899SCharles.Forsyth 		case '*':
175*37da2899SCharles.Forsyth 			i = va_arg(f->args, int);
176*37da2899SCharles.Forsyth 			if(i < 0){
177*37da2899SCharles.Forsyth 				i = -i;
178*37da2899SCharles.Forsyth 				f->flags |= FmtLeft;
179*37da2899SCharles.Forsyth 			}
180*37da2899SCharles.Forsyth 			goto numflag;
181*37da2899SCharles.Forsyth 		}
182*37da2899SCharles.Forsyth 		n = (*fmtfmt(r))(f);
183*37da2899SCharles.Forsyth 		if(n < 0)
184*37da2899SCharles.Forsyth 			return nil;
185*37da2899SCharles.Forsyth 		if(n == 0)
186*37da2899SCharles.Forsyth 			return fmt;
187*37da2899SCharles.Forsyth 	}
188*37da2899SCharles.Forsyth }
189