1 #include "all.h"
2
3 #define PTR sizeof(char*)
4 #define SHORT sizeof(int)
5 #define INT sizeof(int)
6 #define LONG sizeof(long)
7 #define IDIGIT 30
8 #define MAXCON 30
9
10 static int convcount = { 10 };
11
12 #define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c
13
14 static int noconv(Op*);
15 static int cconv(Op*);
16 static int dconv(Op*);
17 static int hconv(Op*);
18 static int lconv(Op*);
19 static int oconv(Op*);
20 static int sconv(Op*);
21 static int uconv(Op*);
22 static int xconv(Op*);
23 static int percent(Op*);
24
25 static
26 int (*fmtconv[MAXCON])(Op*) =
27 {
28 noconv,
29 cconv, dconv, hconv, lconv,
30 oconv, sconv, uconv, xconv,
31 percent,
32 };
33 static
34 char fmtindex[128] =
35 {
36 ['c'] 1,
37 ['d'] 2,
38 ['h'] 3,
39 ['l'] 4,
40 ['o'] 5,
41 ['s'] 6,
42 ['u'] 7,
43 ['x'] 8,
44 ['%'] 9,
45 };
46
47 int
fmtinstall(char c,int (* f)(Op *))48 fmtinstall(char c, int (*f)(Op*))
49 {
50
51 c &= 0177;
52 if(fmtindex[c] == 0) {
53 if(convcount >= MAXCON)
54 return 1;
55 fmtindex[c] = convcount++;
56 }
57 fmtconv[fmtindex[c]] = f;
58 return 0;
59 }
60
61 char*
doprint(char * p,char * ep,char * fmt,void * argp)62 doprint(char *p, char *ep, char *fmt, void *argp)
63 {
64 int sf1, c;
65 Op o;
66
67 o.p = p;
68 o.ep = ep;
69 o.argp = argp;
70
71 loop:
72 c = *fmt++;
73 if(c != '%') {
74 if(c == 0) {
75 if(o.p < o.ep)
76 *o.p = 0;
77 return o.p;
78 }
79 PUT(&o, c);
80 goto loop;
81 }
82 o.f1 = 0;
83 o.f2 = -1;
84 o.f3 = 0;
85 c = *fmt++;
86 sf1 = 0;
87 if(c == '-') {
88 sf1 = 1;
89 c = *fmt++;
90 }
91 while(c >= '0' && c <= '9') {
92 o.f1 = o.f1*10 + c-'0';
93 c = *fmt++;
94 }
95 if(sf1)
96 o.f1 = -o.f1;
97 if(c != '.')
98 goto l1;
99 c = *fmt++;
100 while(c >= '0' && c <= '9') {
101 if(o.f2 < 0)
102 o.f2 = 0;
103 o.f2 = o.f2*10 + c-'0';
104 c = *fmt++;
105 }
106 l1:
107 if(c == 0)
108 fmt--;
109 c = (*fmtconv[fmtindex[c&0177]])(&o);
110 if(c < 0) {
111 o.f3 |= -c;
112 c = *fmt++;
113 goto l1;
114 }
115 o.argp = (char*)o.argp + c;
116 goto loop;
117 }
118
119 int
numbconv(Op * op,int base)120 numbconv(Op *op, int base)
121 {
122 char b[IDIGIT];
123 int i, f, n, r;
124 long v;
125 short h;
126
127 f = 0;
128 switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) {
129 case FLONG:
130 v = *(long*)op->argp;
131 r = LONG;
132 break;
133
134 case FUNSIGN|FLONG:
135 v = *(ulong*)op->argp;
136 r = LONG;
137 break;
138
139 case FSHORT:
140 h = *(int*)op->argp;
141 v = h;
142 r = SHORT;
143 break;
144
145 case FUNSIGN|FSHORT:
146 h = *(int*)op->argp;
147 v = (ushort)h;
148 r = SHORT;
149 break;
150
151 default:
152 v = *(int*)op->argp;
153 r = INT;
154 break;
155
156 case FUNSIGN:
157 v = *(unsigned*)op->argp;
158 r = INT;
159 break;
160 }
161 if(!(op->f3 & FUNSIGN) && v < 0) {
162 v = -v;
163 f = 1;
164 }
165 b[IDIGIT-1] = 0;
166 for(i = IDIGIT-2;; i--) {
167 n = (ulong)v % base;
168 n += '0';
169 if(n > '9')
170 n += 'a' - ('9'+1);
171 b[i] = n;
172 if(i < 2)
173 break;
174 v = (ulong)v / base;
175 if(op->f2 >= 0 && i >= IDIGIT-op->f2)
176 continue;
177 if(v <= 0)
178 break;
179 }
180 sout:
181 if(f)
182 b[--i] = '-';
183 strconv(b+i, op, op->f1, -1);
184 return r;
185 }
186
187 void
strconv(char * o,Op * op,int f1,int f2)188 strconv(char *o, Op *op, int f1, int f2)
189 {
190 int n, c;
191 char *p;
192
193 n = strlen(o);
194 if(f1 >= 0)
195 while(n < f1) {
196 PUT(op, ' ');
197 n++;
198 }
199 for(p=o; c = *p++;)
200 if(f2 != 0) {
201 PUT(op, c);
202 f2--;
203 }
204 if(f1 < 0) {
205 f1 = -f1;
206 while(n < f1) {
207 PUT(op, ' ');
208 n++;
209 }
210 }
211 }
212
213 static int
noconv(Op * op)214 noconv(Op *op)
215 {
216
217 strconv("***", op, 0, -1);
218 return 0;
219 }
220
221 static int
cconv(Op * op)222 cconv(Op *op)
223 {
224 char b[2];
225
226 b[0] = *(int*)op->argp;
227 b[1] = 0;
228 strconv(b, op, op->f1, -1);
229 return INT;
230 }
231
232 static int
dconv(Op * op)233 dconv(Op *op)
234 {
235
236 return numbconv(op, 10);
237 }
238
239 static int
hconv(Op * op)240 hconv(Op *op)
241 {
242 USED(op);
243 return -FSHORT;
244 }
245
246 static int
lconv(Op * op)247 lconv(Op *op)
248 {
249 USED(op);
250 return -FLONG;
251 }
252
253 static int
oconv(Op * op)254 oconv(Op *op)
255 {
256 USED(op);
257 return numbconv(op, 8);
258 }
259
260 static int
sconv(Op * op)261 sconv(Op *op)
262 {
263
264 strconv(*(char**)op->argp, op, op->f1, op->f2);
265 return PTR;
266 }
267
268 static int
uconv(Op * op)269 uconv(Op *op)
270 {
271 USED(op);
272 return -FUNSIGN;
273 }
274
275 static int
xconv(Op * op)276 xconv(Op *op)
277 {
278
279 return numbconv(op, 16);
280 }
281
282 static int
percent(Op * op)283 percent(Op *op)
284 {
285
286 PUT(op, '%');
287 return 0;
288 }
289