xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libc/fmt.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include "fmtdef.h"
4*8ccd4a63SDavid du Colombier 
5*8ccd4a63SDavid du Colombier enum
6*8ccd4a63SDavid du Colombier {
7*8ccd4a63SDavid du Colombier 	Maxfmt = 64
8*8ccd4a63SDavid du Colombier };
9*8ccd4a63SDavid du Colombier 
10*8ccd4a63SDavid du Colombier typedef struct Convfmt Convfmt;
11*8ccd4a63SDavid du Colombier struct Convfmt
12*8ccd4a63SDavid du Colombier {
13*8ccd4a63SDavid du Colombier 	int	c;
14*8ccd4a63SDavid du Colombier 	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
15*8ccd4a63SDavid du Colombier };
16*8ccd4a63SDavid du Colombier 
17*8ccd4a63SDavid du Colombier struct
18*8ccd4a63SDavid du Colombier {
19*8ccd4a63SDavid du Colombier 	/* lock by calling _fmtlock, _fmtunlock */
20*8ccd4a63SDavid du Colombier 	int	nfmt;
21*8ccd4a63SDavid du Colombier 	Convfmt	fmt[Maxfmt];
22*8ccd4a63SDavid du Colombier } fmtalloc;
23*8ccd4a63SDavid du Colombier 
24*8ccd4a63SDavid du Colombier static Convfmt knownfmt[] = {
25*8ccd4a63SDavid du Colombier 	' ',	_flagfmt,
26*8ccd4a63SDavid du Colombier 	'#',	_flagfmt,
27*8ccd4a63SDavid du Colombier 	'%',	_percentfmt,
28*8ccd4a63SDavid du Colombier 	'+',	_flagfmt,
29*8ccd4a63SDavid du Colombier 	',',	_flagfmt,
30*8ccd4a63SDavid du Colombier 	'-',	_flagfmt,
31*8ccd4a63SDavid du Colombier 	'C',	_runefmt,
32*8ccd4a63SDavid du Colombier 	'E',	_efgfmt,
33*8ccd4a63SDavid du Colombier 	'G',	_efgfmt,
34*8ccd4a63SDavid du Colombier 	'S',	_runesfmt,
35*8ccd4a63SDavid du Colombier 	'X',	_ifmt,
36*8ccd4a63SDavid du Colombier 	'b',	_ifmt,
37*8ccd4a63SDavid du Colombier 	'c',	_charfmt,
38*8ccd4a63SDavid du Colombier 	'd',	_ifmt,
39*8ccd4a63SDavid du Colombier 	'e',	_efgfmt,
40*8ccd4a63SDavid du Colombier 	'f',	_efgfmt,
41*8ccd4a63SDavid du Colombier 	'g',	_efgfmt,
42*8ccd4a63SDavid du Colombier 	'h',	_flagfmt,
43*8ccd4a63SDavid du Colombier 	'l',	_flagfmt,
44*8ccd4a63SDavid du Colombier 	'n',	_countfmt,
45*8ccd4a63SDavid du Colombier 	'o',	_ifmt,
46*8ccd4a63SDavid du Colombier 	'p',	_ifmt,
47*8ccd4a63SDavid du Colombier /*	'r',	errfmt, */
48*8ccd4a63SDavid du Colombier 	's',	_strfmt,
49*8ccd4a63SDavid du Colombier 	'u',	_flagfmt,
50*8ccd4a63SDavid du Colombier 	'x',	_ifmt,
51*8ccd4a63SDavid du Colombier 	0,	nil,
52*8ccd4a63SDavid du Colombier };
53*8ccd4a63SDavid du Colombier 
54*8ccd4a63SDavid du Colombier int	(*doquote)(int);
55*8ccd4a63SDavid du Colombier 
56*8ccd4a63SDavid du Colombier /*
57*8ccd4a63SDavid du Colombier  * _fmtlock() must be set
58*8ccd4a63SDavid du Colombier  */
59*8ccd4a63SDavid du Colombier static int
60*8ccd4a63SDavid du Colombier _fmtinstall(int c, Fmts f)
61*8ccd4a63SDavid du Colombier {
62*8ccd4a63SDavid du Colombier 	Convfmt *p, *ep;
63*8ccd4a63SDavid du Colombier 
64*8ccd4a63SDavid du Colombier 	if(c<=0 || c>=65536)
65*8ccd4a63SDavid du Colombier 		return -1;
66*8ccd4a63SDavid du Colombier 	if(!f)
67*8ccd4a63SDavid du Colombier 		f = _badfmt;
68*8ccd4a63SDavid du Colombier 
69*8ccd4a63SDavid du Colombier 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
70*8ccd4a63SDavid du Colombier 	for(p=fmtalloc.fmt; p<ep; p++)
71*8ccd4a63SDavid du Colombier 		if(p->c == c)
72*8ccd4a63SDavid du Colombier 			break;
73*8ccd4a63SDavid du Colombier 
74*8ccd4a63SDavid du Colombier 	if(p == &fmtalloc.fmt[Maxfmt])
75*8ccd4a63SDavid du Colombier 		return -1;
76*8ccd4a63SDavid du Colombier 
77*8ccd4a63SDavid du Colombier 	p->fmt = f;
78*8ccd4a63SDavid du Colombier 	if(p == ep){	/* installing a new format character */
79*8ccd4a63SDavid du Colombier 		fmtalloc.nfmt++;
80*8ccd4a63SDavid du Colombier 		p->c = c;
81*8ccd4a63SDavid du Colombier 	}
82*8ccd4a63SDavid du Colombier 
83*8ccd4a63SDavid du Colombier 	return 0;
84*8ccd4a63SDavid du Colombier }
85*8ccd4a63SDavid du Colombier 
86*8ccd4a63SDavid du Colombier int
87*8ccd4a63SDavid du Colombier fmtinstall(int c, Fmts f)
88*8ccd4a63SDavid du Colombier {
89*8ccd4a63SDavid du Colombier 	int ret;
90*8ccd4a63SDavid du Colombier 
91*8ccd4a63SDavid du Colombier 	_fmtlock();
92*8ccd4a63SDavid du Colombier 	ret = _fmtinstall(c, f);
93*8ccd4a63SDavid du Colombier 	_fmtunlock();
94*8ccd4a63SDavid du Colombier 	return ret;
95*8ccd4a63SDavid du Colombier }
96*8ccd4a63SDavid du Colombier 
97*8ccd4a63SDavid du Colombier static Fmts
98*8ccd4a63SDavid du Colombier fmtfmt(int c)
99*8ccd4a63SDavid du Colombier {
100*8ccd4a63SDavid du Colombier 	Convfmt *p, *ep;
101*8ccd4a63SDavid du Colombier 
102*8ccd4a63SDavid du Colombier 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
103*8ccd4a63SDavid du Colombier 	for(p=fmtalloc.fmt; p<ep; p++)
104*8ccd4a63SDavid du Colombier 		if(p->c == c){
105*8ccd4a63SDavid du Colombier 			while(p->fmt == nil)	/* loop until value is updated */
106*8ccd4a63SDavid du Colombier 				;
107*8ccd4a63SDavid du Colombier 			return p->fmt;
108*8ccd4a63SDavid du Colombier 		}
109*8ccd4a63SDavid du Colombier 
110*8ccd4a63SDavid du Colombier 	/* is this a predefined format char? */
111*8ccd4a63SDavid du Colombier 	_fmtlock();
112*8ccd4a63SDavid du Colombier 	for(p=knownfmt; p->c; p++)
113*8ccd4a63SDavid du Colombier 		if(p->c == c){
114*8ccd4a63SDavid du Colombier 			_fmtinstall(p->c, p->fmt);
115*8ccd4a63SDavid du Colombier 			_fmtunlock();
116*8ccd4a63SDavid du Colombier 			return p->fmt;
117*8ccd4a63SDavid du Colombier 		}
118*8ccd4a63SDavid du Colombier 	_fmtunlock();
119*8ccd4a63SDavid du Colombier 
120*8ccd4a63SDavid du Colombier 	return _badfmt;
121*8ccd4a63SDavid du Colombier }
122*8ccd4a63SDavid du Colombier 
123*8ccd4a63SDavid du Colombier void*
124*8ccd4a63SDavid du Colombier _fmtdispatch(Fmt *f, void *fmt, int isrunes)
125*8ccd4a63SDavid du Colombier {
126*8ccd4a63SDavid du Colombier 	Rune rune, r;
127*8ccd4a63SDavid du Colombier 	int i, n;
128*8ccd4a63SDavid du Colombier 
129*8ccd4a63SDavid du Colombier 	f->flags = 0;
130*8ccd4a63SDavid du Colombier 	f->width = f->prec = 0;
131*8ccd4a63SDavid du Colombier 
132*8ccd4a63SDavid du Colombier 	for(;;){
133*8ccd4a63SDavid du Colombier 		if(isrunes){
134*8ccd4a63SDavid du Colombier 			r = *(Rune*)fmt;
135*8ccd4a63SDavid du Colombier 			fmt = (Rune*)fmt + 1;
136*8ccd4a63SDavid du Colombier 		}else{
137*8ccd4a63SDavid du Colombier 			fmt = (char*)fmt + chartorune(&rune, fmt);
138*8ccd4a63SDavid du Colombier 			r = rune;
139*8ccd4a63SDavid du Colombier 		}
140*8ccd4a63SDavid du Colombier 		f->r = r;
141*8ccd4a63SDavid du Colombier 		switch(r){
142*8ccd4a63SDavid du Colombier 		case '\0':
143*8ccd4a63SDavid du Colombier 			return nil;
144*8ccd4a63SDavid du Colombier 		case '.':
145*8ccd4a63SDavid du Colombier 			f->flags |= FmtWidth|FmtPrec;
146*8ccd4a63SDavid du Colombier 			continue;
147*8ccd4a63SDavid du Colombier 		case '0':
148*8ccd4a63SDavid du Colombier 			if(!(f->flags & FmtWidth)){
149*8ccd4a63SDavid du Colombier 				f->flags |= FmtZero;
150*8ccd4a63SDavid du Colombier 				continue;
151*8ccd4a63SDavid du Colombier 			}
152*8ccd4a63SDavid du Colombier 			/* fall through */
153*8ccd4a63SDavid du Colombier 		case '1': case '2': case '3': case '4':
154*8ccd4a63SDavid du Colombier 		case '5': case '6': case '7': case '8': case '9':
155*8ccd4a63SDavid du Colombier 			i = 0;
156*8ccd4a63SDavid du Colombier 			while(r >= '0' && r <= '9'){
157*8ccd4a63SDavid du Colombier 				i = i * 10 + r - '0';
158*8ccd4a63SDavid du Colombier 				if(isrunes){
159*8ccd4a63SDavid du Colombier 					r = *(Rune*)fmt;
160*8ccd4a63SDavid du Colombier 					fmt = (Rune*)fmt + 1;
161*8ccd4a63SDavid du Colombier 				}else{
162*8ccd4a63SDavid du Colombier 					r = *(char*)fmt;
163*8ccd4a63SDavid du Colombier 					fmt = (char*)fmt + 1;
164*8ccd4a63SDavid du Colombier 				}
165*8ccd4a63SDavid du Colombier 			}
166*8ccd4a63SDavid du Colombier 			if(isrunes)
167*8ccd4a63SDavid du Colombier 				fmt = (Rune*)fmt - 1;
168*8ccd4a63SDavid du Colombier 			else
169*8ccd4a63SDavid du Colombier 				fmt = (char*)fmt - 1;
170*8ccd4a63SDavid du Colombier 		numflag:
171*8ccd4a63SDavid du Colombier 			if(f->flags & FmtWidth){
172*8ccd4a63SDavid du Colombier 				f->flags |= FmtPrec;
173*8ccd4a63SDavid du Colombier 				f->prec = i;
174*8ccd4a63SDavid du Colombier 			}else{
175*8ccd4a63SDavid du Colombier 				f->flags |= FmtWidth;
176*8ccd4a63SDavid du Colombier 				f->width = i;
177*8ccd4a63SDavid du Colombier 			}
178*8ccd4a63SDavid du Colombier 			continue;
179*8ccd4a63SDavid du Colombier 		case '*':
180*8ccd4a63SDavid du Colombier 			i = va_arg(f->args, int);
181*8ccd4a63SDavid du Colombier 			if(i < 0){
182*8ccd4a63SDavid du Colombier 				i = -i;
183*8ccd4a63SDavid du Colombier 				f->flags |= FmtLeft;
184*8ccd4a63SDavid du Colombier 			}
185*8ccd4a63SDavid du Colombier 			goto numflag;
186*8ccd4a63SDavid du Colombier 		}
187*8ccd4a63SDavid du Colombier 		n = (*fmtfmt(r))(f);
188*8ccd4a63SDavid du Colombier 		if(n < 0)
189*8ccd4a63SDavid du Colombier 			return nil;
190*8ccd4a63SDavid du Colombier 		if(n == 0)
191*8ccd4a63SDavid du Colombier 			return fmt;
192*8ccd4a63SDavid du Colombier 	}
193*8ccd4a63SDavid du Colombier }
194