| plan 9 kernel history: overview | file list | diff list |
1995/0804/port/print.c (diff list | history)
| port/print.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | ||
| 1992/1024 | enum { SIZE = 1024, IDIGIT = 30, 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), }; | |
| 1990/0227 | #define PTR sizeof(char*) #define SHORT sizeof(int) #define INT sizeof(int) #define LONG sizeof(long) | |
| 1992/1024 | #define VLONG sizeof(vlong) | |
| 1990/0227 | ||
| 1992/1024 | int printcol; | |
| 1990/0227 | ||
| 1992/1024 | static int convcount; static char fmtindex[MAXFMT]; | |
| 1990/0227 | ||
| 1992/1024 | static int noconv(void*, Fconv*); static int flags(void*, Fconv*); | |
| 1990/0227 | ||
| 1992/1024 | static int cconv(void*, Fconv*); static int sconv(void*, Fconv*); static int percent(void*, Fconv*); int numbconv(void*, Fconv*); | |
| 1990/0227 | static | |
| 1992/1024 | int (*fmtconv[MAXCONV])(void*, Fconv*) = | |
| 1990/0227 | { | |
| 1992/1024 | noconv | |
| 1990/0227 | }; | |
| 1992/1024 | ||
| 1990/0227 | static | |
| 1992/1024 | void initfmt(void) | |
| 1990/0227 | { | |
| 1992/1024 | int cc; | |
| 1990/0227 | ||
| 1992/1024 | 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] = sconv; fmtindex['s'] = cc; fmtindex['S'] = cc; cc++; fmtconv[cc] = percent; fmtindex['%'] = cc; cc++; convcount = cc; } | |
| 1990/0227 | int | |
| 1992/1024 | fmtinstall(int c, int (*f)(void*, Fconv*)) | |
| 1990/0227 | { | |
| 1992/1024 | if(convcount == 0) initfmt(); if(c < 0 || c >= MAXFMT) return 1; if(convcount >= MAXCONV) return 1; fmtconv[convcount] = f; fmtindex[c] = convcount; convcount++; | |
| 1990/0227 | return 0; } char* | |
| 1992/1024 | doprint(char *s, char *es, char *fmt, void *argp) | |
| 1990/0227 | { | |
| 1992/1024 | int n, c; Rune rune; Fconv local; | |
| 1990/0227 | ||
| 1992/1024 | local.out = s; local.eout = es-4; /* room for multi-byte character and 0 */ | |
| 1990/0227 | loop: | |
| 1992/1024 | 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); /* BUG */ local.out += n; } else *local.out++ = c; | |
| 1990/0227 | goto loop; | |
| 1992/1024 | case '%': break; | |
| 1990/0227 | } | |
| 1992/1024 | 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; | |
| 1990/0227 | } | |
| 1992/1024 | if(c == '.') { if(local.f1 == NONE) local.f1 = 0; local.f2 = 0; goto l0; | |
| 1990/0227 | } | |
| 1992/1024 | 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; | |
| 1990/0227 | goto l1; } | |
| 1992/1024 | if(c == '*') { n = *(int*)argp; argp = (char*)argp + INT; if(local.f1 == NONE) local.f1 = n; else local.f2 = n; goto l0; | |
| 1990/0227 | } | |
| 1992/1024 | 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; } argp = (char*)argp + n; | |
| 1990/0227 | goto loop; } int | |
| 1992/1024 | numbconv(void *o, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | char s[IDIGIT]; int i, f, n, r, b, ucase; | |
| 1990/0227 | short h; | |
| 1992/1024 | long v; vlong vl; | |
| 1990/0227 | ||
| 1992/1024 | 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; } | |
| 1990/0227 | f = 0; | |
| 1992/1024 | switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) { case FVLONG|FLONG: vl = *(vlong*)o; r = VLONG; break; | |
| 1990/0227 | case FLONG: | |
| 1992/1024 | v = *(long*)o; | |
| 1990/0227 | r = LONG; break; case FUNSIGN|FLONG: | |
| 1992/1024 | v = *(ulong*)o; | |
| 1990/0227 | r = LONG; break; case FSHORT: | |
| 1992/1024 | h = *(int*)o; | |
| 1990/0227 | v = h; r = SHORT; break; case FUNSIGN|FSHORT: | |
| 1992/1024 | h = *(int*)o; v = (ushort)h; | |
| 1990/0227 | r = SHORT; break; default: | |
| 1992/1024 | v = *(int*)o; | |
| 1990/0227 | r = INT; break; case FUNSIGN: | |
| 1992/1024 | v = *(unsigned*)o; | |
| 1990/0227 | r = INT; break; } | |
| 1992/1024 | if(!(fp->f3 & FUNSIGN) && v < 0) { | |
| 1990/0227 | v = -v; f = 1; } | |
| 1992/1024 | s[IDIGIT-1] = 0; | |
| 1990/0227 | for(i = IDIGIT-2;; i--) { | |
| 1992/1024 | if(fp->f3 & FVLONG) n = vl % b; else n = (ulong)v % b; | |
| 1990/0227 | n += '0'; | |
| 1992/1024 | if(n > '9') { | |
| 1990/0227 | n += 'a' - ('9'+1); | |
| 1992/1024 | if(ucase) n += 'A'-'a'; } s[i] = n; | |
| 1990/0227 | if(i < 2) break; | |
| 1992/1024 | if(fp->f3 & FVLONG) vl = vl / b; else v = (ulong)v / b; if(fp->f2 != NONE && i >= IDIGIT-fp->f2) | |
| 1990/0227 | continue; | |
| 1992/1024 | if(fp->f3 & FVLONG) if(vl <= 0) break; | |
| 1990/0227 | if(v <= 0) break; } | |
| 1992/1024 | if(fp->f3 & FSHARP) if(s[i] != '0') { if(b == 8) s[--i] = '0'; else if(b == 16) { if(ucase) s[--i] = 'X'; else s[--i] = 'x'; s[--i] = '0'; } } | |
| 1990/0227 | if(f) | |
| 1992/1024 | s[--i] = '-'; fp->f2 = NONE; strconv(s+i, fp); | |
| 1990/0227 | return r; } void | |
| 1992/1024 | Strconv(Rune *s, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | int n, c, i; Rune rune; | |
| 1990/0227 | ||
| 1992/1024 | 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++; | |
| 1990/0227 | n++; } | |
| 1992/1024 | } 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; } | |
| 1990/0227 | } | |
| 1992/1024 | } if(fp->f1 != NONE && fp->f1 < 0) { fp->f1 = -fp->f1; while(n < fp->f1) { if(fp->out < fp->eout) *fp->out++ = ' '; printcol++; | |
| 1990/0227 | n++; } } } | |
| 1992/1024 | void strconv(char *s, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | int n, c, i; Rune rune; | |
| 1990/0227 | ||
| 1992/1024 | 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++; } } | |
| 1990/0227 | } | |
| 1992/1024 | static int noconv(void *o, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | int n; char s[10]; | |
| 1990/0227 | ||
| 1992/1024 | if(convcount == 0) { initfmt(); n = 0; if(fp->chr >= 0 && fp->chr < MAXFMT) n = fmtindex[fp->chr]; return (*fmtconv[n])(o, fp); } sprint(s, "*%c*", fp->chr); fp->f1 = 0; fp->f2 = NONE; fp->f3 = 0; strconv(s, fp); return 0; | |
| 1990/0227 | } | |
| 1992/1024 | static int cconv(void *o, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | char s[10]; Rune rune; | |
| 1990/0227 | ||
| 1992/1024 | rune = *(int*)o; if(fp->chr == 'c') rune &= 0xff; s[runetochar(s, &rune)] = 0; | |
| 1990/0227 | ||
| 1992/1024 | fp->f2 = NONE; strconv(s, fp); return INT; | |
| 1990/0227 | } | |
| 1992/1024 | static int sconv(void *o, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | char *s; Rune *r; | |
| 1990/0227 | ||
| 1992/1024 | if(fp->chr == 's') { s = *(char**)o; if(s == 0) s = "<null>"; strconv(s, fp); } else { r = *(Rune**)o; if(r == 0) r = L"<null>"; Strconv(r, fp); } return PTR; | |
| 1990/0227 | } | |
| 1992/1024 | static int | |
| 1995/0804 | percent(void*, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | if(fp->out < fp->eout) *fp->out++ = '%'; return 0; | |
| 1990/0227 | } | |
| 1992/1024 | static int | |
| 1995/0804 | flags(void*, Fconv *fp) | |
| 1990/0227 | { | |
| 1992/1024 | int f; | |
| 1990/0227 | ||
| 1992/1024 | f = 0; switch(fp->chr) { case '+': f = FPLUS; break; | |
| 1991/1115 | ||
| 1992/1024 | case '-': f = FMINUS; break; | |
| 1990/0227 | ||
| 1992/1024 | case '#': f = FSHARP; break; | |
| 1990/0227 | ||
| 1992/1024 | case 'h': f = FSHORT; break; | |
| 1990/0227 | ||
| 1992/1024 | case 'l': f = FLONG; if(fp->f3 & FLONG) f = FVLONG; break; | |
| 1990/0227 | ||
| 1992/1024 | case 'u': f = FUNSIGN; break; } return -f; | |
| 1990/0227 | } | |