#include "u.h" #include "lib.h" #define PTR sizeof(char*) #define SHORT sizeof(int) #define INT sizeof(int) #define LONG sizeof(long) #define IDIGIT 30 #define MAXCON 30 #define FLONG (1<<0) #define FSHORT (1<<1) #define FUNSIGN (1<<2) typedef struct Op Op; struct Op { char *p; char *ep; void *argp; int f1; int f2; int f3; }; static int noconv(Op*); static int cconv(Op*); static int dconv(Op*); static int hconv(Op*); static int lconv(Op*); static int oconv(Op*); static int sconv(Op*); static int uconv(Op*); static int xconv(Op*); static int Xconv(Op*); static int percent(Op*); static int pconv(Op*); static int (*fmtconv[MAXCON])(Op*) = { noconv, cconv, dconv, hconv, lconv, oconv, sconv, uconv, xconv, Xconv, percent, pconv, }; static char fmtindex[128] = { ['c'] 1, ['d'] 2, ['h'] 3, ['l'] 4, ['o'] 5, ['s'] 6, ['u'] 7, ['x'] 8, ['X'] 9, ['%'] 10, ['p'] 11, }; static int convcount = { 12 }; static int ucase; static void PUT(Op *o, int c) { static int pos; int opos; if(c == '\t'){ opos = pos; pos = (opos+8) & ~7; while(opos++ < pos && o->p < o->ep) *o->p++ = ' '; return; } if(o->p < o->ep){ *o->p++ = c; pos++; } if(c == '\n') pos = 0; } int fmtinstall(char c, int (*f)(Op*)) { c &= 0177; if(fmtindex[c] == 0) { if(convcount >= MAXCON) return 1; fmtindex[c] = convcount++; } fmtconv[fmtindex[c]] = f; return 0; } char* donprint(char *p, char *ep, char *fmt, void *argp) { int sf1, c; Op o; o.p = p; o.ep = ep; o.argp = argp; loop: c = *fmt++; if(c != '%') { if(c == 0) { if(o.p < o.ep) *o.p = 0; return o.p; } PUT(&o, c); goto loop; } o.f1 = 0; o.f2 = -1; o.f3 = 0; c = *fmt++; sf1 = 0; if(c == '-') { sf1 = 1; c = *fmt++; } while(c >= '0' && c <= '9') { o.f1 = o.f1*10 + c-'0'; c = *fmt++; } if(sf1) o.f1 = -o.f1; if(c != '.') goto l1; c = *fmt++; while(c >= '0' && c <= '9') { if(o.f2 < 0) o.f2 = 0; o.f2 = o.f2*10 + c-'0'; c = *fmt++; } l1: if(c == 0) fmt--; c = (*fmtconv[fmtindex[c&0177]])(&o); if(c < 0) { o.f3 |= -c; c = *fmt++; goto l1; } o.argp = (char*)o.argp + c; goto loop; } void strconv(char *o, Op *op, int f1, int f2) { int n, c; char *p; n = strlen(o); if(f1 >= 0) while(n < f1) { PUT(op, ' '); n++; } for(p=o; c = *p++;) if(f2 != 0) { PUT(op, c); f2--; } if(f1 < 0) { f1 = -f1; while(n < f1) { PUT(op, ' '); n++; } } } int numbconv(Op *op, int base) { char b[IDIGIT]; int i, f, n, r; long v; short h; f = 0; switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { case FLONG: v = *(long*)op->argp; r = LONG; break; case FUNSIGN|FLONG: v = *(ulong*)op->argp; r = LONG; break; case FSHORT: h = *(int*)op->argp; v = h; r = SHORT; break; case FUNSIGN|FSHORT: h = *(int*)op->argp; v = (ushort)h; r = SHORT; break; default: v = *(int*)op->argp; r = INT; break; case FUNSIGN: v = *(unsigned*)op->argp; r = INT; break; } if(!(op->f3 & FUNSIGN) && v < 0) { v = -v; f = 1; } b[IDIGIT-1] = 0; for(i = IDIGIT-2;; i--) { n = (ulong)v % base; n += '0'; if(n > '9'){ n += 'a' - ('9'+1); if(ucase) n += 'A'-'a'; } b[i] = n; if(i < 2) break; v = (ulong)v / base; if(op->f2 >= 0 && i >= IDIGIT-op->f2) continue; if(v <= 0) break; } if(f) b[--i] = '-'; strconv(b+i, op, op->f1, -1); return r; } static int noconv(Op *op) { strconv("***", op, 0, -1); return 0; } static int cconv(Op *op) { char b[2]; b[0] = *(int*)op->argp; b[1] = 0; strconv(b, op, op->f1, -1); return INT; } static int dconv(Op *op) { return numbconv(op, 10); } static int hconv(Op*) { return -FSHORT; } static int lconv(Op*) { return -FLONG; } static int oconv(Op *op) { return numbconv(op, 8); } static int sconv(Op *op) { strconv(*(char**)op->argp, op, op->f1, op->f2); return PTR; } static int uconv(Op*) { return -FUNSIGN; } static int xconv(Op *op) { return numbconv(op, 16); } static int pconv(Op *op) { op->f3 |= FLONG|FUNSIGN; return numbconv(op, 16); } static int Xconv(Op *op) { int r; ucase = 1; r = numbconv(op, 16); ucase = 0; return r; } static int percent(Op *op) { PUT(op, '%'); return 0; }