123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- #include <u.h>
- #include <libc.h>
- enum
- {
- SIZE = 1024,
- IDIGIT = 40,
- MAXCONV = 40,
- FDIGIT = 30,
- FDEFLT = 6,
- NONE = -1000,
- MAXFMT = 512,
- FPLUS = 1<<0,
- FMINUS = 1<<1,
- FSHARP = 1<<2,
- FLONG = 1<<3,
- FSHORT = 1<<4,
- FUNSIGN = 1<<5,
- FVLONG = 1<<6,
- };
- int printcol;
- static int convcount;
- static char fmtindex[MAXFMT];
- static int noconv(va_list*, Fconv*);
- static int flags(va_list*, Fconv*);
- static int cconv(va_list*, Fconv*);
- static int rconv(va_list*, Fconv*);
- static int sconv(va_list*, Fconv*);
- static int percent(va_list*, Fconv*);
- static int column(va_list*, Fconv*);
- int numbconv(va_list*, Fconv*);
- static
- int (*fmtconv[MAXCONV])(va_list*, Fconv*) =
- {
- noconv
- };
- static
- void
- initfmt(void)
- {
- int cc;
- cc = 0;
- fmtconv[cc] = noconv;
- cc++;
- fmtconv[cc] = flags;
- fmtindex['+'] = cc;
- fmtindex['-'] = cc;
- fmtindex['#'] = cc;
- fmtindex['h'] = cc;
- fmtindex['l'] = cc;
- fmtindex['u'] = cc;
- cc++;
- fmtconv[cc] = numbconv;
- fmtindex['d'] = cc;
- fmtindex['o'] = cc;
- fmtindex['x'] = cc;
- fmtindex['X'] = cc;
- cc++;
- fmtconv[cc] = cconv;
- fmtindex['c'] = cc;
- fmtindex['C'] = cc;
- cc++;
- fmtconv[cc] = rconv;
- fmtindex['r'] = cc;
- cc++;
- fmtconv[cc] = sconv;
- fmtindex['s'] = cc;
- fmtindex['S'] = cc;
- cc++;
- fmtconv[cc] = percent;
- fmtindex['%'] = cc;
- cc++;
- fmtconv[cc] = column;
- fmtindex['|'] = cc;
- cc++;
- convcount = cc;
- }
- int
- fmtinstall(int c, int (*f)(va_list*, Fconv*))
- {
- if(convcount == 0)
- initfmt();
- if(c < 0 || c >= MAXFMT)
- return -1;
- if(convcount >= MAXCONV)
- return -1;
- fmtconv[convcount] = f;
- fmtindex[c] = convcount;
- convcount++;
- return 0;
- }
- char*
- doprint(char *s, char *es, char *fmt, va_list argp)
- {
- int n, c;
- Rune rune;
- Fconv local;
- if(s >= es)
- return s;
- local.out = s;
- local.eout = es-UTFmax-1;
- loop:
- c = *fmt & 0xff;
- if(c >= Runeself) {
- n = chartorune(&rune, fmt);
- fmt += n;
- c = rune;
- } else
- fmt++;
- switch(c) {
- case 0:
- *local.out = 0;
- return local.out;
-
- default:
- printcol++;
- goto common;
- case '\n':
- printcol = 0;
- goto common;
- case '\t':
- printcol = (printcol+8) & ~7;
- goto common;
- common:
- if(local.out < local.eout)
- if(c >= Runeself) {
- rune = c;
- n = runetochar(local.out, &rune);
- local.out += n;
- } else
- *local.out++ = c;
- goto loop;
- case '%':
- break;
- }
- local.f1 = NONE;
- local.f2 = NONE;
- local.f3 = 0;
- /*
- * read one of the following
- * 1. number, => f1, f2 in order.
- * 2. '*' same as number (from args)
- * 3. '.' ignored (separates numbers)
- * 4. flag => f3
- * 5. verb and terminate
- */
- l0:
- c = *fmt & 0xff;
- if(c >= Runeself) {
- n = chartorune(&rune, fmt);
- fmt += n;
- c = rune;
- } else
- fmt++;
- l1:
- if(c == 0) {
- fmt--;
- goto loop;
- }
- if(c == '.') {
- if(local.f1 == NONE)
- local.f1 = 0;
- local.f2 = 0;
- goto l0;
- }
- if((c >= '1' && c <= '9') ||
- (c == '0' && local.f1 != NONE)) { /* '0' is a digit for f2 */
- n = 0;
- while(c >= '0' && c <= '9') {
- n = n*10 + c-'0';
- c = *fmt++;
- }
- if(local.f1 == NONE)
- local.f1 = n;
- else
- local.f2 = n;
- goto l1;
- }
- if(c == '*') {
- n = va_arg(argp, int);
- if(local.f1 == NONE)
- local.f1 = n;
- else
- local.f2 = n;
- goto l0;
- }
- n = 0;
- if(c >= 0 && c < MAXFMT)
- n = fmtindex[c];
- local.chr = c;
- n = (*fmtconv[n])(&argp, &local);
- if(n < 0) {
- local.f3 |= -n;
- goto l0;
- }
- goto loop;
- }
- int
- numbconv(va_list *arg, Fconv *fp)
- {
- char s[IDIGIT];
- int i, f, n, b, ucase;
- short h;
- long v;
- vlong vl;
- SET(v);
- SET(vl);
- ucase = 0;
- b = fp->chr;
- switch(fp->chr) {
- case 'u':
- fp->f3 |= FUNSIGN;
- case 'd':
- b = 10;
- break;
- case 'o':
- b = 8;
- break;
- case 'X':
- ucase = 1;
- case 'x':
- b = 16;
- break;
- }
- f = 0;
- switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
- case FVLONG|FLONG:
- vl = va_arg(*arg, vlong);
- break;
- case FUNSIGN|FVLONG|FLONG:
- vl = va_arg(*arg, uvlong);
- break;
- case FLONG:
- v = va_arg(*arg, long);
- break;
- case FUNSIGN|FLONG:
- v = va_arg(*arg, ulong);
- break;
- case FSHORT:
- h = va_arg(*arg, int);
- v = h;
- break;
- case FUNSIGN|FSHORT:
- h = va_arg(*arg, int);
- v = (ushort)h;
- break;
- default:
- v = va_arg(*arg, int);
- break;
- case FUNSIGN:
- v = va_arg(*arg, unsigned);
- break;
- }
- if(fp->f3 & FVLONG) {
- if(!(fp->f3 & FUNSIGN) && vl < 0) {
- vl = -vl;
- f = 1;
- }
- } else {
- if(!(fp->f3 & FUNSIGN) && v < 0) {
- v = -v;
- f = 1;
- }
- }
- s[IDIGIT-1] = 0;
- for(i = IDIGIT-2;; i--) {
- if(fp->f3 & FVLONG)
- n = (uvlong)vl % b;
- else
- n = (ulong)v % b;
- n += '0';
- if(n > '9') {
- n += 'a' - ('9'+1);
- if(ucase)
- n += 'A'-'a';
- }
- s[i] = n;
- if(i < 2)
- break;
- if(fp->f3 & FVLONG)
- vl = (uvlong)vl / b;
- else
- v = (ulong)v / b;
- if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
- continue;
- if(fp->f3 & FVLONG) {
- if(vl <= 0)
- break;
- continue;
- }
- if(v <= 0)
- break;
- }
- if(fp->f3 & FSHARP) {
- if(b == 8 && s[i] != '0')
- s[--i] = '0';
- if(b == 16) {
- if(ucase)
- s[--i] = 'X';
- else
- s[--i] = 'x';
- s[--i] = '0';
- }
- }
- if(f)
- s[--i] = '-';
- fp->f2 = NONE;
- strconv(s+i, fp);
- return 0;
- }
- void
- Strconv(Rune *s, Fconv *fp)
- {
- int n, c, i;
- Rune rune;
- if(fp->f3 & FMINUS)
- fp->f1 = -fp->f1;
- n = 0;
- if(fp->f1 != NONE && fp->f1 >= 0) {
- for(; s[n]; n++)
- ;
- while(n < fp->f1) {
- if(fp->out < fp->eout)
- *fp->out++ = ' ';
- printcol++;
- n++;
- }
- }
- for(;;) {
- c = *s++;
- if(c == 0)
- break;
- n++;
- if(fp->f2 == NONE || fp->f2 > 0) {
- if(fp->out < fp->eout)
- if(c >= Runeself) {
- rune = c;
- i = runetochar(fp->out, &rune);
- fp->out += i;
- } else
- *fp->out++ = c;
- if(fp->f2 != NONE)
- fp->f2--;
- switch(c) {
- default:
- printcol++;
- break;
- case '\n':
- printcol = 0;
- break;
- case '\t':
- printcol = (printcol+8) & ~7;
- break;
- }
- }
- }
- if(fp->f1 != NONE && fp->f1 < 0) {
- fp->f1 = -fp->f1;
- while(n < fp->f1) {
- if(fp->out < fp->eout)
- *fp->out++ = ' ';
- printcol++;
- n++;
- }
- }
- }
- void
- strconv(char *s, Fconv *fp)
- {
- int n, c, i;
- Rune rune;
- if(fp->f3 & FMINUS)
- fp->f1 = -fp->f1;
- n = 0;
- if(fp->f1 != NONE && fp->f1 >= 0) {
- n = utflen(s);
- while(n < fp->f1) {
- if(fp->out < fp->eout)
- *fp->out++ = ' ';
- printcol++;
- n++;
- }
- }
- for(;;) {
- c = *s & 0xff;
- if(c >= Runeself) {
- i = chartorune(&rune, s);
- s += i;
- c = rune;
- } else
- s++;
- if(c == 0)
- break;
- n++;
- if(fp->f2 == NONE || fp->f2 > 0) {
- if(fp->out < fp->eout)
- if(c >= Runeself) {
- rune = c;
- i = runetochar(fp->out, &rune);
- fp->out += i;
- } else
- *fp->out++ = c;
- if(fp->f2 != NONE)
- fp->f2--;
- switch(c) {
- default:
- printcol++;
- break;
- case '\n':
- printcol = 0;
- break;
- case '\t':
- printcol = (printcol+8) & ~7;
- break;
- }
- }
- }
- if(fp->f1 != NONE && fp->f1 < 0) {
- fp->f1 = -fp->f1;
- while(n < fp->f1) {
- if(fp->out < fp->eout)
- *fp->out++ = ' ';
- printcol++;
- n++;
- }
- }
- }
- static
- int
- noconv(va_list *arg, Fconv *fp)
- {
- int n;
- char s[10];
- if(convcount == 0) {
- initfmt();
- n = 0;
- if(fp->chr >= 0 && fp->chr < MAXFMT)
- n = fmtindex[fp->chr];
- return (*fmtconv[n])(arg, fp);
- }
- s[0] = '*';
- s[1] = fp->chr;
- s[2] = '*';
- s[3] = 0;
- fp->f1 = 0;
- fp->f2 = NONE;
- fp->f3 = 0;
- strconv(s, fp);
- return 0;
- }
- static
- int
- rconv(va_list*, Fconv *fp)
- {
- char s[ERRLEN];
- s[0] = 0;
- errstr(s);
- fp->f2 = NONE;
- strconv(s, fp);
- return 0;
- }
- static
- int
- cconv(va_list *arg, Fconv *fp)
- {
- char s[10];
- Rune rune;
- rune = va_arg(*arg, int);
- if(fp->chr == 'c')
- rune &= 0xff;
- s[runetochar(s, &rune)] = 0;
- fp->f2 = NONE;
- strconv(s, fp);
- return 0;
- }
- static
- int
- sconv(va_list *arg, Fconv *fp)
- {
- char *s;
- Rune *r;
- if(fp->chr == 's') {
- s = va_arg(*arg, char*);
- if(s == 0)
- s = "<null>";
- strconv(s, fp);
- } else {
- r = va_arg(*arg, Rune*);
- if(r == 0)
- r = L"<null>";
- Strconv(r, fp);
- }
- return 0;
- }
- static
- int
- percent(va_list*, Fconv *fp)
- {
- if(fp->out < fp->eout)
- *fp->out++ = '%';
- printcol++;
- return 0;
- }
- static
- int
- column(va_list *arg, Fconv *fp)
- {
- int col, pc;
- col = va_arg(*arg, int);
- while(fp->out < fp->eout && printcol < col) {
- pc = (printcol+8) & ~7;
- if(pc <= col) {
- *fp->out++ = '\t';
- printcol = pc;
- } else {
- *fp->out++ = ' ';
- printcol++;
- }
- }
- return 0;
- }
- static
- int
- flags(va_list*, Fconv *fp)
- {
- int f;
- f = 0;
- switch(fp->chr) {
- case '+':
- f = FPLUS;
- break;
- case '-':
- f = FMINUS;
- break;
- case '#':
- f = FSHARP;
- break;
- case 'h':
- f = FSHORT;
- break;
- case 'l':
- f = FLONG;
- if(fp->f3 & FLONG)
- f = FVLONG;
- break;
- case 'u':
- f = FUNSIGN;
- break;
- }
- return -f;
- }
|