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, /* Plan 9 addition */
32 'E', __efgfmt,
33 #ifndef PLAN9PORT
34 'F', __efgfmt, /* ANSI only */
35 #endif
36 'G', __efgfmt,
37 #ifndef PLAN9PORT
38 'L', __flagfmt, /* ANSI only */
39 #endif
40 'S', __runesfmt, /* Plan 9 addition */
41 'X', __ifmt,
42 'b', __ifmt, /* Plan 9 addition */
43 'c', __charfmt,
44 'd', __ifmt,
45 'e', __efgfmt,
46 'f', __efgfmt,
47 'g', __efgfmt,
48 'h', __flagfmt,
49 #ifndef PLAN9PORT
50 'i', __ifmt, /* ANSI only */
51 #endif
52 'l', __flagfmt,
53 'n', __countfmt,
54 'o', __ifmt,
55 'p', __ifmt,
56 'r', __errfmt,
57 's', __strfmt,
58 #ifdef PLAN9PORT
59 'u', __flagfmt,
60 #else
61 'u', __ifmt,
62 #endif
63 'x', __ifmt,
64 0, 0,
65 };
66
67
68 int (*fmtdoquote)(int);
69
70 /*
71 * __fmtlock() must be set
72 */
73 static int
__fmtinstall(int c,Fmts f)74 __fmtinstall(int c, Fmts f)
75 {
76 Convfmt *p, *ep;
77
78 if(c<=0 || c>=65536)
79 return -1;
80 if(!f)
81 f = __badfmt;
82
83 ep = &fmtalloc.fmt[fmtalloc.nfmt];
84 for(p=fmtalloc.fmt; p<ep; p++)
85 if(p->c == c)
86 break;
87
88 if(p == &fmtalloc.fmt[Maxfmt])
89 return -1;
90
91 p->fmt = f;
92 if(p == ep){ /* installing a new format character */
93 fmtalloc.nfmt++;
94 p->c = c;
95 }
96
97 return 0;
98 }
99
100 int
fmtinstall(int c,int (* f)(Fmt *))101 fmtinstall(int c, int (*f)(Fmt*))
102 {
103 int ret;
104
105 __fmtlock();
106 ret = __fmtinstall(c, f);
107 __fmtunlock();
108 return ret;
109 }
110
111 static Fmts
fmtfmt(int c)112 fmtfmt(int c)
113 {
114 Convfmt *p, *ep;
115
116 ep = &fmtalloc.fmt[fmtalloc.nfmt];
117 for(p=fmtalloc.fmt; p<ep; p++)
118 if(p->c == c){
119 while(p->fmt == 0) /* loop until value is updated */
120 ;
121 return p->fmt;
122 }
123
124 /* is this a predefined format char? */
125 __fmtlock();
126 for(p=knownfmt; p->c; p++)
127 if(p->c == c){
128 __fmtinstall(p->c, p->fmt);
129 __fmtunlock();
130 return p->fmt;
131 }
132 __fmtunlock();
133
134 return __badfmt;
135 }
136
137 void*
__fmtdispatch(Fmt * f,void * fmt,int isrunes)138 __fmtdispatch(Fmt *f, void *fmt, int isrunes)
139 {
140 Rune rune, r;
141 int i, n;
142
143 f->flags = 0;
144 f->width = f->prec = 0;
145
146 for(;;){
147 if(isrunes){
148 r = *(Rune*)fmt;
149 fmt = (Rune*)fmt + 1;
150 }else{
151 fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
152 r = rune;
153 }
154 f->r = r;
155 switch(r){
156 case '\0':
157 return nil;
158 case '.':
159 f->flags |= FmtWidth|FmtPrec;
160 continue;
161 case '0':
162 if(!(f->flags & FmtWidth)){
163 f->flags |= FmtZero;
164 continue;
165 }
166 /* fall through */
167 case '1': case '2': case '3': case '4':
168 case '5': case '6': case '7': case '8': case '9':
169 i = 0;
170 while(r >= '0' && r <= '9'){
171 i = i * 10 + r - '0';
172 if(isrunes){
173 r = *(Rune*)fmt;
174 fmt = (Rune*)fmt + 1;
175 }else{
176 r = *(char*)fmt;
177 fmt = (char*)fmt + 1;
178 }
179 }
180 if(isrunes)
181 fmt = (Rune*)fmt - 1;
182 else
183 fmt = (char*)fmt - 1;
184 numflag:
185 if(f->flags & FmtWidth){
186 f->flags |= FmtPrec;
187 f->prec = i;
188 }else{
189 f->flags |= FmtWidth;
190 f->width = i;
191 }
192 continue;
193 case '*':
194 i = va_arg(f->args, int);
195 if(i < 0){
196 /*
197 * negative precision =>
198 * ignore the precision.
199 */
200 if(f->flags & FmtPrec){
201 f->flags &= ~FmtPrec;
202 f->prec = 0;
203 continue;
204 }
205 i = -i;
206 f->flags |= FmtLeft;
207 }
208 goto numflag;
209 }
210 n = (*fmtfmt(r))(f);
211 if(n < 0)
212 return nil;
213 if(n == 0)
214 return fmt;
215 }
216 }
217