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