|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3:
4: enum
5: {
6: SIZE = 1024,
7: IDIGIT = 30,
8: MAXCONV = 40,
9: FDIGIT = 30,
10: FDEFLT = 6,
11: NONE = -1000,
12: MAXFMT = 512,
13:
14: FPLUS = (1<<0),
15: FMINUS = (1<<1),
16: FSHARP = (1<<2),
17: FLONG = (1<<3),
18: FSHORT = (1<<4),
19: FUNSIGN = (1<<5),
20: FVLONG = (1<<6),
21: };
22:
23: #define PTR sizeof(char*)
24: #define SHORT sizeof(int)
25: #define INT sizeof(int)
26: #define LONG sizeof(long)
27: #define VLONG sizeof(vlong)
28:
29: int printcol;
30:
31: static int convcount;
32: static char fmtindex[MAXFMT];
33:
34: static int noconv(void*, Fconv*);
35: static int flags(void*, Fconv*);
36:
37: static int cconv(void*, Fconv*);
38: static int sconv(void*, Fconv*);
39: static int percent(void*, Fconv*);
40:
41: int numbconv(void*, Fconv*);
42:
43: static
44: int (*fmtconv[MAXCONV])(void*, Fconv*) =
45: {
46: noconv
47: };
48:
49: static
50: void
51: initfmt(void)
52: {
53: int cc;
54:
55: cc = 0;
56: fmtconv[cc] = noconv;
57: cc++;
58:
59: fmtconv[cc] = flags;
60: fmtindex['+'] = cc;
61: fmtindex['-'] = cc;
62: fmtindex['#'] = cc;
63: fmtindex['h'] = cc;
64: fmtindex['l'] = cc;
65: fmtindex['u'] = cc;
66: cc++;
67:
68: fmtconv[cc] = numbconv;
69: fmtindex['d'] = cc;
70: fmtindex['o'] = cc;
71: fmtindex['x'] = cc;
72: fmtindex['X'] = cc;
73: cc++;
74:
75: fmtconv[cc] = cconv;
76: fmtindex['c'] = cc;
77: fmtindex['C'] = cc;
78: cc++;
79:
80: fmtconv[cc] = sconv;
81: fmtindex['s'] = cc;
82: fmtindex['S'] = cc;
83: cc++;
84:
85: fmtconv[cc] = percent;
86: fmtindex['%'] = cc;
87: cc++;
88:
89: convcount = cc;
90: }
91:
92: int
93: fmtinstall(int c, int (*f)(void*, Fconv*))
94: {
95:
96: if(convcount == 0)
97: initfmt();
98: if(c < 0 || c >= MAXFMT)
99: return 1;
100: if(convcount >= MAXCONV)
101: return 1;
102: fmtconv[convcount] = f;
103: fmtindex[c] = convcount;
104: convcount++;
105: return 0;
106: }
107:
108: char*
109: doprint(char *s, char *es, char *fmt, void *argp)
110: {
111: int n, c;
112: Rune rune;
113: Fconv local;
114:
115: local.out = s;
116: local.eout = es-4; /* room for multi-byte character and 0 */
117:
118: loop:
119: c = *fmt & 0xff;
120: if(c >= Runeself) {
121: n = chartorune(&rune, fmt);
122: fmt += n;
123: c = rune;
124: } else
125: fmt++;
126: switch(c) {
127: case 0:
128: *local.out = 0;
129: return local.out;
130:
131: default:
132: printcol++;
133: goto common;
134:
135: case '\n':
136: printcol = 0;
137: goto common;
138:
139: case '\t':
140: printcol = (printcol+8) & ~7;
141: goto common;
142:
143: common:
144: if(local.out < local.eout)
145: if(c >= Runeself) {
146: rune = c;
147: n = runetochar(local.out, &rune); /* BUG */
148: local.out += n;
149: } else
150: *local.out++ = c;
151: goto loop;
152:
153: case '%':
154: break;
155: }
156: local.f1 = NONE;
157: local.f2 = NONE;
158: local.f3 = 0;
159:
160: /*
161: * read one of the following
162: * 1. number, => f1, f2 in order.
163: * 2. '*' same as number (from args)
164: * 3. '.' ignored (separates numbers)
165: * 4. flag => f3
166: * 5. verb and terminate
167: */
168: l0:
169: c = *fmt & 0xff;
170: if(c >= Runeself) {
171: n = chartorune(&rune, fmt);
172: fmt += n;
173: c = rune;
174: } else
175: fmt++;
176:
177: l1:
178: if(c == 0) {
179: fmt--;
180: goto loop;
181: }
182: if(c == '.') {
183: if(local.f1 == NONE)
184: local.f1 = 0;
185: local.f2 = 0;
186: goto l0;
187: }
188: if((c >= '1' && c <= '9') ||
189: (c == '0' && local.f1 != NONE)) { /* '0' is a digit for f2 */
190: n = 0;
191: while(c >= '0' && c <= '9') {
192: n = n*10 + c-'0';
193: c = *fmt++;
194: }
195: if(local.f1 == NONE)
196: local.f1 = n;
197: else
198: local.f2 = n;
199: goto l1;
200: }
201: if(c == '*') {
202: n = *(int*)argp;
203: argp = (char*)argp + INT;
204: if(local.f1 == NONE)
205: local.f1 = n;
206: else
207: local.f2 = n;
208: goto l0;
209: }
210: n = 0;
211: if(c >= 0 && c < MAXFMT)
212: n = fmtindex[c];
213: local.chr = c;
214: n = (*fmtconv[n])(argp, &local);
215: if(n < 0) {
216: local.f3 |= -n;
217: goto l0;
218: }
219: argp = (char*)argp + n;
220: goto loop;
221: }
222:
223: int
224: numbconv(void *o, Fconv *fp)
225: {
226: char s[IDIGIT];
227: int i, f, n, r, b, ucase;
228: short h;
229: long v;
230: vlong vl;
231:
232: SET(v);
233: SET(vl);
234:
235: ucase = 0;
236: b = fp->chr;
237: switch(fp->chr) {
238: case 'u':
239: fp->f3 |= FUNSIGN;
240: case 'd':
241: b = 10;
242: break;
243:
244: case 'o':
245: b = 8;
246: break;
247:
248: case 'X':
249: ucase = 1;
250: case 'x':
251: b = 16;
252: break;
253: }
254:
255: f = 0;
256: switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
257: case FVLONG|FLONG:
258: vl = *(vlong*)o;
259: r = VLONG;
260: break;
261:
262: case FLONG:
263: v = *(long*)o;
264: r = LONG;
265: break;
266:
267: case FUNSIGN|FLONG:
268: v = *(ulong*)o;
269: r = LONG;
270: break;
271:
272: case FSHORT:
273: h = *(int*)o;
274: v = h;
275: r = SHORT;
276: break;
277:
278: case FUNSIGN|FSHORT:
279: h = *(int*)o;
280: v = (ushort)h;
281: r = SHORT;
282: break;
283:
284: default:
285: v = *(int*)o;
286: r = INT;
287: break;
288:
289: case FUNSIGN:
290: v = *(unsigned*)o;
291: r = INT;
292: break;
293: }
294: if(!(fp->f3 & FUNSIGN) && v < 0) {
295: v = -v;
296: f = 1;
297: }
298: s[IDIGIT-1] = 0;
299: for(i = IDIGIT-2;; i--) {
300: if(fp->f3 & FVLONG)
301: n = vl % b;
302: else
303: n = (ulong)v % b;
304: n += '0';
305: if(n > '9') {
306: n += 'a' - ('9'+1);
307: if(ucase)
308: n += 'A'-'a';
309: }
310: s[i] = n;
311: if(i < 2)
312: break;
313: if(fp->f3 & FVLONG)
314: vl = vl / b;
315: else
316: v = (ulong)v / b;
317: if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
318: continue;
319: if(fp->f3 & FVLONG)
320: if(vl <= 0)
321: break;
322: if(v <= 0)
323: break;
324: }
325: if(fp->f3 & FSHARP)
326: if(s[i] != '0') {
327: if(b == 8)
328: s[--i] = '0';
329: else
330: if(b == 16) {
331: if(ucase)
332: s[--i] = 'X';
333: else
334: s[--i] = 'x';
335: s[--i] = '0';
336: }
337: }
338: if(f)
339: s[--i] = '-';
340: fp->f2 = NONE;
341: strconv(s+i, fp);
342: return r;
343: }
344:
345: void
346: Strconv(Rune *s, Fconv *fp)
347: {
348: int n, c, i;
349: Rune rune;
350:
351: if(fp->f3 & FMINUS)
352: fp->f1 = -fp->f1;
353: n = 0;
354: if(fp->f1 != NONE && fp->f1 >= 0) {
355: for(; s[n]; n++)
356: ;
357: while(n < fp->f1) {
358: if(fp->out < fp->eout)
359: *fp->out++ = ' ';
360: printcol++;
361: n++;
362: }
363: }
364: for(;;) {
365: c = *s++;
366: if(c == 0)
367: break;
368: n++;
369: if(fp->f2 == NONE || fp->f2 > 0) {
370: if(fp->out < fp->eout)
371: if(c >= Runeself) {
372: rune = c;
373: i = runetochar(fp->out, &rune);
374: fp->out += i;
375: } else
376: *fp->out++ = c;
377: if(fp->f2 != NONE)
378: fp->f2--;
379: switch(c) {
380: default:
381: printcol++;
382: break;
383: case '\n':
384: printcol = 0;
385: break;
386: case '\t':
387: printcol = (printcol+8) & ~7;
388: break;
389: }
390: }
391: }
392: if(fp->f1 != NONE && fp->f1 < 0) {
393: fp->f1 = -fp->f1;
394: while(n < fp->f1) {
395: if(fp->out < fp->eout)
396: *fp->out++ = ' ';
397: printcol++;
398: n++;
399: }
400: }
401: }
402:
403: void
404: strconv(char *s, Fconv *fp)
405: {
406: int n, c, i;
407: Rune rune;
408:
409: if(fp->f3 & FMINUS)
410: fp->f1 = -fp->f1;
411: n = 0;
412: if(fp->f1 != NONE && fp->f1 >= 0) {
413: n = utflen(s);
414: while(n < fp->f1) {
415: if(fp->out < fp->eout)
416: *fp->out++ = ' ';
417: printcol++;
418: n++;
419: }
420: }
421: for(;;) {
422: c = *s & 0xff;
423: if(c >= Runeself) {
424: i = chartorune(&rune, s);
425: s += i;
426: c = rune;
427: } else
428: s++;
429: if(c == 0)
430: break;
431: n++;
432: if(fp->f2 == NONE || fp->f2 > 0) {
433: if(fp->out < fp->eout)
434: if(c >= Runeself) {
435: rune = c;
436: i = runetochar(fp->out, &rune);
437: fp->out += i;
438: } else
439: *fp->out++ = c;
440: if(fp->f2 != NONE)
441: fp->f2--;
442: switch(c) {
443: default:
444: printcol++;
445: break;
446: case '\n':
447: printcol = 0;
448: break;
449: case '\t':
450: printcol = (printcol+8) & ~7;
451: break;
452: }
453: }
454: }
455: if(fp->f1 != NONE && fp->f1 < 0) {
456: fp->f1 = -fp->f1;
457: while(n < fp->f1) {
458: if(fp->out < fp->eout)
459: *fp->out++ = ' ';
460: printcol++;
461: n++;
462: }
463: }
464: }
465:
466: static
467: int
468: noconv(void *o, Fconv *fp)
469: {
470: int n;
471: char s[10];
472:
473: if(convcount == 0) {
474: initfmt();
475: n = 0;
476: if(fp->chr >= 0 && fp->chr < MAXFMT)
477: n = fmtindex[fp->chr];
478: return (*fmtconv[n])(o, fp);
479: }
480: sprint(s, "*%c*", fp->chr);
481: fp->f1 = 0;
482: fp->f2 = NONE;
483: fp->f3 = 0;
484: strconv(s, fp);
485: return 0;
486: }
487:
488: static
489: int
490: cconv(void *o, Fconv *fp)
491: {
492: char s[10];
493: Rune rune;
494:
495: rune = *(int*)o;
496: if(fp->chr == 'c')
497: rune &= 0xff;
498: s[runetochar(s, &rune)] = 0;
499:
500: fp->f2 = NONE;
501: strconv(s, fp);
502: return INT;
503: }
504:
505: static
506: int
507: sconv(void *o, Fconv *fp)
508: {
509: char *s;
510: Rune *r;
511:
512: if(fp->chr == 's') {
513: s = *(char**)o;
514: if(s == 0)
515: s = "<null>";
516: strconv(s, fp);
517: } else {
518: r = *(Rune**)o;
519: if(r == 0)
520: r = L"<null>";
521: Strconv(r, fp);
522: }
523: return PTR;
524: }
525:
526: static
527: int
528: percent(void *o, Fconv *fp)
529: {
530:
531: USED(o);
532: if(fp->out < fp->eout)
533: *fp->out++ = '%';
534: return 0;
535: }
536:
537: static
538: int
539: flags(void *o, Fconv *fp)
540: {
541: int f;
542:
543: USED(o);
544:
545: f = 0;
546: switch(fp->chr) {
547: case '+':
548: f = FPLUS;
549: break;
550:
551: case '-':
552: f = FMINUS;
553: break;
554:
555: case '#':
556: f = FSHARP;
557: break;
558:
559: case 'h':
560: f = FSHORT;
561: break;
562:
563: case 'l':
564: f = FLONG;
565: if(fp->f3 & FLONG)
566: f = FVLONG;
567: break;
568:
569: case 'u':
570: f = FUNSIGN;
571: break;
572: }
573: return -f;
574: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.