From 42f34f5aa9f9b01101cde6f4f48865d0e832b15f Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 24 Oct 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-10-24 --- port/devcons.c | 4 +- port/lib.h | 33 +-- port/print.c | 624 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 472 insertions(+), 189 deletions(-) diff --git a/port/devcons.c b/port/devcons.c index a455ab6570f7bc8af1b47a35999b21b231c8f188..69bc7b041432534195490bc57c34fee66c02e9a0 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -383,9 +383,9 @@ int readnum(ulong off, char *buf, ulong n, ulong val, int size) { char tmp[64]; - Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG }; + Fconv fconv = (Fconv){ tmp, tmp+sizeof(tmp), size-1, 0, 0, 'd' }; - numbconv(&op, 10); + numbconv(&val, &fconv); tmp[size-1] = ' '; if(off >= size) return 0; diff --git a/port/lib.h b/port/lib.h index 1272564c294c3599d457fd45843150e857b1d13c..7fb60d78ee73741c8d4a43825a84d82147c532ca 100644 --- a/port/lib.h +++ b/port/lib.h @@ -24,12 +24,19 @@ extern int strncmp(char*, char*, long); extern long strlen(char*); extern int atoi(char*); +enum +{ + UTFmax = 3, /* maximum bytes per rune */ + Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ + Runeerror = 0x80, /* decoding error in UTF */ +}; + /* * rune routines */ extern int runetochar(char*, Rune*); extern int chartorune(Rune*, char*); -extern int countrune(char*); extern char* utfrune(char*, long); extern int utflen(char*); @@ -38,26 +45,20 @@ extern int abs(int); /* * print routines */ - -#define FUNSIGN 4 -#define FSHORT 2 -#define FLONG 1 - -typedef struct Op Op; -struct Op +typedef +struct { - char *p; - char *ep; - void *argp; + char* out; /* pointer to next output */ + char* eout; /* pointer to end */ int f1; int f2; int f3; -}; -typedef void* Fconv; /* to allow fcall.h to compile */ -extern void strconv(char*, Op*, int, int); -extern int numbconv(Op*, int); + int chr; +} Fconv; +extern void strconv(char*, Fconv*); +extern int numbconv(void*, Fconv*); extern char *doprint(char*, char*, char*, void*); -extern int fmtinstall(char, int (*)(Op*)); +extern int fmtinstall(int, int (*)(void*, Fconv*)); extern int sprint(char*, char*, ...); extern int print(char*, ...); diff --git a/port/print.c b/port/print.c index 4112dc20493af546a1376f584c6e2f4462100d03..f5dc7a757e6f73bc28c560e68320fd955109e668 100644 --- a/port/print.c +++ b/port/print.c @@ -1,292 +1,574 @@ #include "u.h" #include "../port/lib.h" +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), +}; + #define PTR sizeof(char*) #define SHORT sizeof(int) #define INT sizeof(int) #define LONG sizeof(long) -#define IDIGIT 30 -#define MAXCON 30 +#define VLONG sizeof(vlong) -static int convcount = { 10 }; +int printcol; -#define PUT(o, c) if((o)->p < (o)->ep) *(o)->p++ = c +static int convcount; +static char fmtindex[MAXFMT]; -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 percent(Op*); +static int noconv(void*, Fconv*); +static int flags(void*, Fconv*); + +static int cconv(void*, Fconv*); +static int sconv(void*, Fconv*); +static int percent(void*, Fconv*); + +int numbconv(void*, Fconv*); static -int (*fmtconv[MAXCON])(Op*) = +int (*fmtconv[MAXCONV])(void*, Fconv*) = { - noconv, - cconv, dconv, hconv, lconv, - oconv, sconv, uconv, xconv, - percent, + noconv }; + static -char fmtindex[128] = +void +initfmt(void) { - ['c'] 1, - ['d'] 2, - ['h'] 3, - ['l'] 4, - ['o'] 5, - ['s'] 6, - ['u'] 7, - ['x'] 8, - ['%'] 9, -}; + 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] = sconv; + fmtindex['s'] = cc; + fmtindex['S'] = cc; + cc++; + + fmtconv[cc] = percent; + fmtindex['%'] = cc; + cc++; + + convcount = cc; +} int -fmtinstall(char c, int (*f)(Op*)) +fmtinstall(int c, int (*f)(void*, Fconv*)) { - c &= 0177; - if(fmtindex[c] == 0) { - if(convcount >= MAXCON) - return 1; - fmtindex[c] = convcount++; - } - fmtconv[fmtindex[c]] = f; + 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 *p, char *ep, char *fmt, void *argp) +doprint(char *s, char *es, char *fmt, void *argp) { - int sf1, c; - Op o; + int n, c; + Rune rune; + Fconv local; - o.p = p; - o.ep = ep; - o.argp = argp; + local.out = s; + local.eout = es-4; /* room for multi-byte character and 0 */ loop: - c = *fmt++; - if(c != '%') { - if(c == 0) { - if(o.p < o.ep) - *o.p = 0; - return o.p; - } - PUT(&o, c); + 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; goto loop; + + case '%': + break; } - o.f1 = 0; - o.f2 = -1; - o.f3 = 0; - c = *fmt++; - sf1 = 0; - if(c == '-') { - sf1 = 1; - c = *fmt++; + 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; } - while(c >= '0' && c <= '9') { - o.f1 = o.f1*10 + c-'0'; - c = *fmt++; + if(c == '.') { + if(local.f1 == NONE) + local.f1 = 0; + local.f2 = 0; + goto l0; } - if(sf1) - o.f1 = -o.f1; - if(c != '.') + 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; - 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; + if(c == '*') { + n = *(int*)argp; + argp = (char*)argp + INT; + if(local.f1 == NONE) + local.f1 = n; + else + local.f2 = n; + goto l0; } - o.argp = (char*)o.argp + c; + 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; goto loop; } int -numbconv(Op *op, int base) +numbconv(void *o, Fconv *fp) { - char b[IDIGIT]; - int i, f, n, r; - long v; + char s[IDIGIT]; + int i, f, n, r, 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(op->f3 & (FLONG|FSHORT|FUNSIGN)) { + switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) { + case FVLONG|FLONG: + vl = *(vlong*)o; + r = VLONG; + break; + case FLONG: - v = *(long*)op->argp; + v = *(long*)o; r = LONG; break; case FUNSIGN|FLONG: - v = *(unsigned long*)op->argp; + v = *(ulong*)o; r = LONG; break; case FSHORT: - h = *(int*)op->argp; + h = *(int*)o; v = h; r = SHORT; break; case FUNSIGN|FSHORT: - h = *(int*)op->argp; - v = (unsigned short)h; + h = *(int*)o; + v = (ushort)h; r = SHORT; break; default: - v = *(int*)op->argp; + v = *(int*)o; r = INT; break; case FUNSIGN: - v = *(unsigned*)op->argp; + v = *(unsigned*)o; r = INT; break; } - if(!(op->f3 & FUNSIGN) && v < 0) { + if(!(fp->f3 & FUNSIGN) && v < 0) { v = -v; f = 1; } - b[IDIGIT-1] = 0; + s[IDIGIT-1] = 0; for(i = IDIGIT-2;; i--) { - n = (unsigned long)v % base; + if(fp->f3 & FVLONG) + n = vl % b; + else + n = (ulong)v % b; n += '0'; - if(n > '9') + if(n > '9') { n += 'a' - ('9'+1); - b[i] = n; + if(ucase) + n += 'A'-'a'; + } + s[i] = n; if(i < 2) break; - v = (unsigned long)v / base; - if(op->f2 >= 0 && i >= IDIGIT-op->f2) + if(fp->f3 & FVLONG) + vl = vl / b; + else + v = (ulong)v / b; + if(fp->f2 != NONE && i >= IDIGIT-fp->f2) continue; + if(fp->f3 & FVLONG) + if(vl <= 0) + break; if(v <= 0) break; } -sout: + 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'; + } + } if(f) - b[--i] = '-'; - strconv(b+i, op, op->f1, -1); + s[--i] = '-'; + fp->f2 = NONE; + strconv(s+i, fp); return r; } void -strconv(char *o, Op *op, int f1, int f2) +Strconv(Rune *s, Fconv *fp) { - int n, c; - char *p; - - n = strlen(o); - if(f1 >= 0) - while(n < f1) { - PUT(op, ' '); + 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(p=o; c = *p++;) - if(f2 != 0) { - PUT(op, c); - f2--; + } + 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(f1 < 0) { - f1 = -f1; - while(n < f1) { - PUT(op, ' '); + } + 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(Op *op) +void +strconv(char *s, Fconv *fp) { - - strconv("***", op, 0, -1); - return 0; + 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 -cconv(Op *op) +static +int +noconv(void *o, Fconv *fp) { - char b[2]; - - b[0] = *(int*)op->argp; - b[1] = 0; - strconv(b, op, op->f1, -1); - return INT; + 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])(o, fp); + } + sprint(s, "*%c*", fp->chr); + fp->f1 = 0; + fp->f2 = NONE; + fp->f3 = 0; + strconv(s, fp); + return 0; } -static int -dconv(Op *op) +static +int +cconv(void *o, Fconv *fp) { + char s[10]; + Rune rune; - return numbconv(op, 10); -} + rune = *(int*)o; + if(fp->chr == 'c') + rune &= 0xff; + s[runetochar(s, &rune)] = 0; -static int -hconv(Op *op) -{ - - USED(op); - return -FSHORT; + fp->f2 = NONE; + strconv(s, fp); + return INT; } -static int -lconv(Op *op) +static +int +sconv(void *o, Fconv *fp) { - - USED(op); - return -FLONG; + char *s; + Rune *r; + + if(fp->chr == 's') { + s = *(char**)o; + if(s == 0) + s = ""; + strconv(s, fp); + } else { + r = *(Rune**)o; + if(r == 0) + r = L""; + Strconv(r, fp); + } + return PTR; } -static int -oconv(Op *op) +static +int +percent(void *o, Fconv *fp) { - return numbconv(op, 8); + USED(o); + if(fp->out < fp->eout) + *fp->out++ = '%'; + return 0; } -static int -sconv(Op *op) +static +int +flags(void *o, Fconv *fp) { + int f; - strconv(*(char**)op->argp, op, op->f1, op->f2); - return PTR; -} + USED(o); -static int -uconv(Op *op) -{ + f = 0; + switch(fp->chr) { + case '+': + f = FPLUS; + break; - USED(op); - return -FUNSIGN; -} + case '-': + f = FMINUS; + break; -static int -xconv(Op *op) -{ + case '#': + f = FSHARP; + break; - return numbconv(op, 16); -} + case 'h': + f = FSHORT; + break; -static int -percent(Op *op) -{ + case 'l': + f = FLONG; + if(fp->f3 & FLONG) + f = FVLONG; + break; - PUT(op, '%'); - return 0; + case 'u': + f = FUNSIGN; + break; + } + return -f; }