fmt.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
fmt.c (3575B) | |
--- | |
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" | |
7 | |
8 enum | |
9 { | |
10 Maxfmt = 64 | |
11 }; | |
12 | |
13 typedef struct Convfmt Convfmt; | |
14 struct Convfmt | |
15 { | |
16 int c; | |
17 volatile Fmts fmt; /* for spin lock in fmtf… | |
18 }; | |
19 | |
20 static struct | |
21 { | |
22 /* lock by calling __fmtlock, __fmtunlock */ | |
23 int nfmt; | |
24 Convfmt fmt[Maxfmt]; | |
25 } fmtalloc; | |
26 | |
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 }; | |
70 | |
71 | |
72 int (*fmtdoquote)(int); | |
73 | |
74 /* | |
75 * __fmtlock() must be set | |
76 */ | |
77 static int | |
78 __fmtinstall(int c, Fmts f) | |
79 { | |
80 Convfmt *p, *ep; | |
81 | |
82 if(c<=0 || c>=65536) | |
83 return -1; | |
84 if(!f) | |
85 f = __badfmt; | |
86 | |
87 ep = &fmtalloc.fmt[fmtalloc.nfmt]; | |
88 for(p=fmtalloc.fmt; p<ep; p++) | |
89 if(p->c == c) | |
90 break; | |
91 | |
92 if(p == &fmtalloc.fmt[Maxfmt]) | |
93 return -1; | |
94 | |
95 p->fmt = f; | |
96 if(p == ep){ /* installing a new format character */ | |
97 fmtalloc.nfmt++; | |
98 p->c = c; | |
99 } | |
100 | |
101 return 0; | |
102 } | |
103 | |
104 int | |
105 fmtinstall(int c, int (*f)(Fmt*)) | |
106 { | |
107 int ret; | |
108 | |
109 __fmtlock(); | |
110 ret = __fmtinstall(c, f); | |
111 __fmtunlock(); | |
112 return ret; | |
113 } | |
114 | |
115 static Fmts | |
116 fmtfmt(int c) | |
117 { | |
118 Convfmt *p, *ep; | |
119 | |
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 … | |
124 ; | |
125 return p->fmt; | |
126 } | |
127 | |
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; | |
135 } | |
136 __fmtunlock(); | |
137 | |
138 return __badfmt; | |
139 } | |
140 | |
141 void* | |
142 __fmtdispatch(Fmt *f, void *fmt, int isrunes) | |
143 { | |
144 Rune rune, r; | |
145 int i, n; | |
146 | |
147 f->flags = 0; | |
148 f->width = f->prec = 0; | |
149 | |
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; | |
157 } | |
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; | |
169 } | |
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; | |
182 } | |
183 } | |
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; | |
195 } | |
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; | |
208 } | |
209 i = -i; | |
210 f->flags |= FmtLeft; | |
211 } | |
212 goto numflag; | |
213 } | |
214 n = (*fmtfmt(r))(f); | |
215 if(n < 0) | |
216 return nil; | |
217 if(n == 0) | |
218 return fmt; | |
219 } | |
220 } |