#include #include enum{ Flag = 1, PTR = sizeof(char*), SHORT = sizeof(int), INT = sizeof(int), LONG = sizeof(long), VLONG = sizeof(vlong), IDIGIT = 64+64/3+2, MAXCON = 30, }; static int convcount = 15; static int noconv(Fmt*); static int bconv(Fmt*); static int cconv(Fmt*); static int dconv(Fmt*); static int hconv(Fmt*); static int lconv(Fmt*); static int oconv(Fmt*); static int rconv(Fmt*); static int sconv(Fmt*); static int uconv(Fmt*); static int xconv(Fmt*); static int percent(Fmt*); static int enet(Fmt*); static int pconv(Fmt*); static int sharpconv(Fmt*); static int (*fmtconv[MAXCON])(Fmt*) = { noconv, bconv, cconv, dconv, hconv, lconv, oconv, rconv, sconv, uconv, xconv, percent, enet, pconv, sharpconv }; static uchar fmtindex[128] = { ['b'] 1, ['c'] 2, ['d'] 3, ['h'] 4, ['l'] 5, ['o'] 6, ['r'] 7, ['s'] 8, ['u'] 9, ['x'] 10, ['%'] 11, ['E'] 12, ['p'] 13, ['#'] 14, }; int fmtinstall(int c, int (*f)(Fmt*)) { c &= 0177; if(fmtindex[c] == 0) { if(convcount >= MAXCON) return 1; fmtindex[c] = convcount++; } fmtconv[fmtindex[c]] = f; return 0; } int strflush(Fmt *f) { USED(f); return -1; } int vsnprint(char *s, int len, char *fmt, va_list args) { Fmt f; int n; f.buf = s; f.p = s; f.ep = s+len-1; f.flush = strflush; n = vfmtprint(&f, fmt, args); *f.p = 0; return n; } int snprint(char *s, int len, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vsnprint(s, len, fmt, args); va_end(args); return n; } char* seprint(char *s, char *e, char *fmt, ...) { int n; va_list args; if(e <= s) return 0; va_start(args, fmt); n = vsnprint(s, e-s, fmt, args); va_end(args); return s+n; } int fdflush(Fmt *f) { int n; n = f->p-f->buf; if(n && write(*(int*)f->farg, f->buf, n) != n) return -1; f->p = f->buf; return n; } int vfprint(int fd, char *fmt, va_list args) { char buf[256]; int n; Fmt f; f.buf = buf; f.p = buf; f.ep = buf+sizeof buf; f.flush = fdflush; f.farg = &fd; n = vfmtprint(&f, fmt, args); if(fdflush(&f) == -1) return -1; return n; } int fprint(int fd, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vfprint(fd, fmt, args); va_end(args); return n; } int print(char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vfprint(1, fmt, args); va_end(args); return n; } static int put(Fmt *f, int c) { if(f->p == f->ep) if(f->flush(f) == -1) return -1; if(f->p == f->ep) return -1; *f->p++ = c; f->n++; return 0; } int vfmtprint(Fmt *f, char *fmt, va_list args) { int sf1, c; va_copy(f->args, args); // f->args = args; f->n = 0; loop: c = *fmt++; if(c != '%') { if(c == 0 || put(f, c) == -1) return f->n; goto loop; } f->f1 = 0; f->f2 = -1; f->f3 = 0; c = *fmt++; if (c == ',') { f->f3 |= FmtComma; c = *fmt++; } if (c == '0') { f->f3 |= FmtZero; c = *fmt++; } if (c == '*') { f->f1 = *(int*)va_arg(f->args, int*); c = *fmt++; } else { sf1 = 0; if(c == '-') { sf1 = 1; c = *fmt++; } while(c >= '0' && c <= '9') { f->f1 = f->f1*10 + c-'0'; c = *fmt++; } if(sf1) f->f1 = -f->f1; } if (f->f3 & FmtZero) f->f2 = f->f1; if(c != '.') goto l1; c = *fmt++; if (c == '*') { f->f1 = *(int*)va_arg(f->args, int*); c = *fmt++; } else { while(c >= '0' && c <= '9') { if(f->f2 < 0) f->f2 = 0; f->f2 = f->f2*10 + c-'0'; c = *fmt++; } } l1: if(c == 0) fmt--; f->verb = c; c = fmtconv[fmtindex[c&0177]](f); if(c < 0) { f->f3 |= -c; c = *fmt++; goto l1; } goto loop; } int fmtprint(Fmt *f, char *fmt, ...) { int n; va_list args; va_start(args, fmt); n = vfmtprint(f, fmt, args); va_end(args); return n; } void strconv(char *o, Fmt *f, int f1, int f2) { int n, c; char *p; if(o == 0) o = ""; n = strlen(o); if(f1 >= 0) while(n < f1) { if(put(f, ' ') == -1) return; n++; } for(p = o; c = *p++;) if(f2 != 0) { if(put(f, c) == -1) return; f2--; } if(f1 < 0) { f1 = -f1; while(n < f1) { if(put(f, ' ') == -1) return; n++; } } } int numbconv(Fmt *op, int base) { char b[IDIGIT], d[IDIGIT]; int i, f, n, c, j, k; vlong vl; f = 0; switch(op->f3 & (FmtLong|FmtShort|FmtUnsigned|FmtVLong)) { case FmtLong: vl = va_arg(op->args, long); break; case FmtUnsigned|FmtLong: vl = (ulong)va_arg(op->args, ulong); break; case FmtShort: vl = (short)va_arg(op->args, int); break; case FmtUnsigned|FmtShort: vl = (ushort)va_arg(op->args, uint); break; case FmtVLong: vl = (vlong)va_arg(op->args, vlong); break; case FmtUnsigned|FmtVLong: vl = (uvlong)va_arg(op->args, uvlong); break; default: vl = (int)va_arg(op->args, int); break; case FmtUnsigned: vl = (uint)va_arg(op->args, uint); break; } if(!(op->f3 & FmtUnsigned) && vl < 0) { vl = -vl; f = 1; } b[IDIGIT-1] = 0; for (i = IDIGIT-2;; i--) { n = (uvlong)vl % base; n += '0'; if(n > '9') n += 'a' - '9'+1; b[i] = n; if(i < 22) // room for commas break; vl = (uvlong)vl / base; if(op->f2 >= 0 && i >= IDIGIT-op->f2) continue; if(vl <= 0) break; } if (op->f3 & FmtComma) { c = 0; for (j = k = IDIGIT-2; k >= i; k--) { if (c == 3) { d[j--] = ','; c = 0; } c++; d[j--] = b[k]; } for (i = IDIGIT-2; i > j; i--) b[i] = d[i]; i++; } if (f) b[--i] = '-'; else if(op->f3&FmtSign) b[--i] = '+'; strconv(b+i, op, op->f1, -1); return 0; } static int noconv(Fmt *f) { fmtprint(f, "%%%c", f->verb); return 0; } static int bconv(Fmt *f) { return numbconv(f, 2); } static int cconv(Fmt *f) { char b[2]; b[0] = (int)va_arg(f->args, int); b[1] = 0; strconv(b, f, f->f1, -1); return 0; } static int dconv(Fmt *f) { return numbconv(f, 10); } static int hconv(Fmt *f) { USED(f); return -FmtShort; } static int lconv(Fmt *f) { if (f->f3 & FmtLong) { f->f3 &= ~FmtLong; return -FmtVLong; } return -FmtLong; } static int oconv(Fmt *f) { return numbconv(f, 8); } static int pconv(Fmt *f) { f->f1 = 8; f->f2 = 8; return numbconv(f, 16); } static int rconv(Fmt *f) { char buf[ERRMAX]; errstr(buf, sizeof buf); strconv(buf, f, f->f1, f->f2); return 0; } static int sconv(Fmt *f) { strconv((char*)va_arg(f->args, char*), f, f->f1, f->f2); return 0; } static int uconv(Fmt *f) { USED(f); return -FmtUnsigned; } static int xconv(Fmt *f) { return numbconv(f, 16); } static int percent(Fmt *f) { put(f, '%'); return 0; } static int enet(Fmt *f) { char *p, buf[32]; uchar *up; int i, n; up = (uchar*)va_arg(f->args, uchar*); p = buf; n = sizeof buf; for (i = 0; i < 6; i++, n -= 2) p += snprint(p, n, "%2.2x", *up++); strconv(buf, f, f->f1, f->f2); return 0; } static int sharpconv(Fmt *f) { USED(f); return -FmtSharp; }