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