Blob


1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2 #include <stdarg.h>
3 #include <string.h>
4 #include <stdatomic.h>
5 #include "plan9.h"
6 #include "fmt.h"
7 #include "fmtdef.h"
9 enum
10 {
11 Maxfmt = 128
12 };
14 typedef struct Convfmt Convfmt;
15 struct Convfmt
16 {
17 int c;
18 Fmts fmt;
19 };
21 static struct
22 {
23 /*
24 * lock updates to fmt by calling __fmtlock, __fmtunlock.
25 * reads can start at nfmt and work backward without
26 * further locking. later fmtinstalls take priority over earlier
27 * ones because of the backwards loop.
28 * once installed, a format is never overwritten.
29 */
30 _Atomic int nfmt;
31 Convfmt fmt[Maxfmt];
32 } fmtalloc = {
33 #ifdef PLAN9PORT
34 ATOMIC_VAR_INIT(27),
35 #else
36 ATOMIC_VAR_INIT(30),
37 #endif
38 {
39 {' ', __flagfmt},
40 {'#', __flagfmt},
41 {'%', __percentfmt},
42 {'\'', __flagfmt},
43 {'+', __flagfmt},
44 {',', __flagfmt},
45 {'-', __flagfmt},
46 {'C', __runefmt}, /* Plan 9 addition */
47 {'E', __efgfmt},
48 #ifndef PLAN9PORT
49 {'F', __efgfmt}, /* ANSI only */
50 #endif
51 {'G', __efgfmt},
52 #ifndef PLAN9PORT
53 {'L', __flagfmt}, /* ANSI only */
54 #endif
55 {'S', __runesfmt}, /* Plan 9 addition */
56 {'X', __ifmt},
57 {'b', __ifmt}, /* Plan 9 addition */
58 {'c', __charfmt},
59 {'d', __ifmt},
60 {'e', __efgfmt},
61 {'f', __efgfmt},
62 {'g', __efgfmt},
63 {'h', __flagfmt},
64 #ifndef PLAN9PORT
65 {'i', __ifmt}, /* ANSI only */
66 #endif
67 {'l', __flagfmt},
68 {'n', __countfmt},
69 {'o', __ifmt},
70 {'p', __ifmt},
71 {'r', __errfmt},
72 {'s', __strfmt},
73 #ifdef PLAN9PORT
74 {'u', __flagfmt},
75 #else
76 {'u', __ifmt},
77 #endif
78 {'x', __ifmt},
79 }
80 };
82 int (*fmtdoquote)(int);
84 /*
85 * __fmtlock() must be set
86 */
87 static int
88 __fmtinstall(int c, Fmts f)
89 {
90 Convfmt *p;
91 int i;
93 if(c<=0 || c>=65536)
94 return -1;
95 if(!f)
96 f = __badfmt;
98 i = atomic_load(&fmtalloc.nfmt);
99 if(i == Maxfmt)
100 return -1;
101 p = &fmtalloc.fmt[i];
102 p->c = c;
103 p->fmt = f;
104 atomic_store(&fmtalloc.nfmt, i+1);
106 return 0;
109 int
110 fmtinstall(int c, int (*f)(Fmt*))
112 int ret;
114 __fmtlock();
115 ret = __fmtinstall(c, f);
116 __fmtunlock();
117 return ret;
120 static Fmts
121 fmtfmt(int c)
123 Convfmt *p, *ep;
125 ep = &fmtalloc.fmt[atomic_load(&fmtalloc.nfmt)];
126 for(p=ep; p-- > fmtalloc.fmt; )
127 if(p->c == c)
128 return p->fmt;
130 return __badfmt;
133 void*
134 __fmtdispatch(Fmt *f, void *fmt, int isrunes)
136 Rune rune, r;
137 int i, n;
139 f->flags = 0;
140 f->width = f->prec = 0;
142 for(;;){
143 if(isrunes){
144 r = *(Rune*)fmt;
145 fmt = (Rune*)fmt + 1;
146 }else{
147 fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
148 r = rune;
150 f->r = r;
151 switch(r){
152 case '\0':
153 return nil;
154 case '.':
155 f->flags |= FmtWidth|FmtPrec;
156 continue;
157 case '0':
158 if(!(f->flags & FmtWidth)){
159 f->flags |= FmtZero;
160 continue;
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;
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;
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;
201 i = -i;
202 f->flags |= FmtLeft;
204 goto numflag;
206 n = (*fmtfmt(r))(f);
207 if(n < 0)
208 return nil;
209 if(n == 0)
210 return fmt;