Blob


1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2 #include <stdarg.h>
3 #include <string.h>
4 #include "plan9.h"
5 #include "fmt.h"
6 #include "fmtdef.h"
8 enum
9 {
10 Maxfmt = 64
11 };
13 typedef struct Convfmt Convfmt;
14 struct Convfmt
15 {
16 int c;
17 volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
18 };
20 static struct
21 {
22 /* lock by calling __fmtlock, __fmtunlock */
23 int nfmt;
24 Convfmt fmt[Maxfmt];
25 } fmtalloc;
27 static Convfmt knownfmt[] = {
28 ' ', __flagfmt,
29 '#', __flagfmt,
30 '%', __percentfmt,
31 '\'', __flagfmt,
32 '+', __flagfmt,
33 ',', __flagfmt,
34 '-', __flagfmt,
35 'C', __runefmt, /* Plan 9 addition */
36 'E', __efgfmt,
37 #ifndef PLAN9PORT
38 'F', __efgfmt, /* ANSI only */
39 #endif
40 'G', __efgfmt,
41 #ifndef PLAN9PORT
42 'L', __flagfmt, /* ANSI only */
43 #endif
44 'S', __runesfmt, /* Plan 9 addition */
45 'X', __ifmt,
46 'b', __ifmt, /* Plan 9 addition */
47 'c', __charfmt,
48 'd', __ifmt,
49 'e', __efgfmt,
50 'f', __efgfmt,
51 'g', __efgfmt,
52 'h', __flagfmt,
53 #ifndef PLAN9PORT
54 'i', __ifmt, /* ANSI only */
55 #endif
56 'l', __flagfmt,
57 'n', __countfmt,
58 'o', __ifmt,
59 'p', __ifmt,
60 'r', __errfmt,
61 's', __strfmt,
62 #ifdef PLAN9PORT
63 'u', __flagfmt,
64 #else
65 'u', __ifmt,
66 #endif
67 'x', __ifmt,
68 0, nil,
69 };
72 int (*fmtdoquote)(int);
74 /*
75 * __fmtlock() must be set
76 */
77 static int
78 __fmtinstall(int c, Fmts f)
79 {
80 Convfmt *p, *ep;
82 if(c<=0 || c>=65536)
83 return -1;
84 if(!f)
85 f = __badfmt;
87 ep = &fmtalloc.fmt[fmtalloc.nfmt];
88 for(p=fmtalloc.fmt; p<ep; p++)
89 if(p->c == c)
90 break;
92 if(p == &fmtalloc.fmt[Maxfmt])
93 return -1;
95 p->fmt = f;
96 if(p == ep){ /* installing a new format character */
97 fmtalloc.nfmt++;
98 p->c = c;
99 }
101 return 0;
104 int
105 fmtinstall(int c, int (*f)(Fmt*))
107 int ret;
109 __fmtlock();
110 ret = __fmtinstall(c, f);
111 __fmtunlock();
112 return ret;
115 static Fmts
116 fmtfmt(int c)
118 Convfmt *p, *ep;
120 ep = &fmtalloc.fmt[fmtalloc.nfmt];
121 for(p=fmtalloc.fmt; p<ep; p++)
122 if(p->c == c){
123 while(p->fmt == nil) /* loop until value is updated */
125 return p->fmt;
128 /* is this a predefined format char? */
129 __fmtlock();
130 for(p=knownfmt; p->c; p++)
131 if(p->c == c){
132 __fmtinstall(p->c, p->fmt);
133 __fmtunlock();
134 return p->fmt;
136 __fmtunlock();
138 return __badfmt;
141 void*
142 __fmtdispatch(Fmt *f, void *fmt, int isrunes)
144 Rune rune, r;
145 int i, n;
147 f->flags = 0;
148 f->width = f->prec = 0;
150 for(;;){
151 if(isrunes){
152 r = *(Rune*)fmt;
153 fmt = (Rune*)fmt + 1;
154 }else{
155 fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
156 r = rune;
158 f->r = r;
159 switch(r){
160 case '\0':
161 return nil;
162 case '.':
163 f->flags |= FmtWidth|FmtPrec;
164 continue;
165 case '0':
166 if(!(f->flags & FmtWidth)){
167 f->flags |= FmtZero;
168 continue;
170 /* fall through */
171 case '1': case '2': case '3': case '4':
172 case '5': case '6': case '7': case '8': case '9':
173 i = 0;
174 while(r >= '0' && r <= '9'){
175 i = i * 10 + r - '0';
176 if(isrunes){
177 r = *(Rune*)fmt;
178 fmt = (Rune*)fmt + 1;
179 }else{
180 r = *(char*)fmt;
181 fmt = (char*)fmt + 1;
184 if(isrunes)
185 fmt = (Rune*)fmt - 1;
186 else
187 fmt = (char*)fmt - 1;
188 numflag:
189 if(f->flags & FmtWidth){
190 f->flags |= FmtPrec;
191 f->prec = i;
192 }else{
193 f->flags |= FmtWidth;
194 f->width = i;
196 continue;
197 case '*':
198 i = va_arg(f->args, int);
199 if(i < 0){
200 /*
201 * negative precision =>
202 * ignore the precision.
203 */
204 if(f->flags & FmtPrec){
205 f->flags &= ~FmtPrec;
206 f->prec = 0;
207 continue;
209 i = -i;
210 f->flags |= FmtLeft;
212 goto numflag;
214 n = (*fmtfmt(r))(f);
215 if(n < 0)
216 return nil;
217 if(n == 0)
218 return fmt;