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 Rune 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
_fmtinstall(Rune c,Fmts f)60 _fmtinstall(Rune 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
fmtinstall(int c,Fmts f)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
fmtfmt(Rune c)98 fmtfmt(Rune c)
99 {
100 Convfmt *p, *ep;
101
102 if (c == '\0')
103 return _badfmt;
104
105 ep = &fmtalloc.fmt[fmtalloc.nfmt];
106 for(p=fmtalloc.fmt; p<ep; p++)
107 if(p->c == c){
108 while(p->fmt == nil) /* loop until value is updated */
109 ;
110 return p->fmt;
111 }
112
113 /* is this a predefined format char? */
114 _fmtlock();
115 for(p=knownfmt; p->c; p++)
116 if(p->c == c){
117 _fmtinstall(p->c, p->fmt);
118 _fmtunlock();
119 return p->fmt;
120 }
121 _fmtunlock();
122
123 return _badfmt;
124 }
125
126 void*
_fmtdispatch(Fmt * f,void * fmt,int isrunes)127 _fmtdispatch(Fmt *f, void *fmt, int isrunes)
128 {
129 Rune rune, r;
130 int i, n, w, p;
131 ulong fl;
132 void *ret;
133
134 w = f->width;
135 p = f->prec;
136 fl = f->flags;
137
138 f->flags = 0;
139 f->width = f->prec = 0;
140
141 for(;;){
142 if(isrunes){
143 r = *(Rune*)fmt;
144 fmt = (Rune*)fmt + 1;
145 }else{
146 fmt = (char*)fmt + chartorune(&rune, fmt);
147 r = rune;
148 }
149 f->r = r;
150 switch(r){
151 case '\0':
152 ret = nil;
153 goto end;
154 case '.':
155 f->flags |= FmtWidth|FmtPrec;
156 continue;
157 case '0':
158 if(!(f->flags & FmtWidth)){
159 f->flags |= FmtZero;
160 continue;
161 }
162 /* fall through */
163 case '1': case '2': case '3': case '4':
164 case '5': case '6': case '7': case '8': case '9':
165 i = 0;
166 while(r >= '0' && r <= '9'){
167 i = i * 10 + r - '0';
168 if(isrunes){
169 r = *(Rune*)fmt;
170 fmt = (Rune*)fmt + 1;
171 }else{
172 r = *(char*)fmt;
173 fmt = (char*)fmt + 1;
174 }
175 }
176 if(isrunes)
177 fmt = (Rune*)fmt - 1;
178 else
179 fmt = (char*)fmt - 1;
180 numflag:
181 if(f->flags & FmtWidth){
182 f->flags |= FmtPrec;
183 f->prec = i;
184 }else{
185 f->flags |= FmtWidth;
186 f->width = i;
187 }
188 continue;
189 case '*':
190 i = va_arg(f->args, int);
191 if(i < 0){
192 /*
193 * negative precision =>
194 * ignore the precision.
195 */
196 if(f->flags & FmtPrec){
197 f->flags &= ~FmtPrec;
198 f->prec = 0;
199 continue;
200 }
201 i = -i;
202 f->flags |= FmtLeft;
203 }
204 goto numflag;
205 }
206 n = (*fmtfmt(r))(f);
207 if(n < 0){
208 ret = nil;
209 break;
210 }
211 if(n == 0){
212 ret = fmt;
213 break;
214 }
215 }
216 end:
217 f->width = w;
218 f->prec = p;
219 f->flags = fl;
220 return ret;
221 }
222