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