diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libc/arm/doprint.xc |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/arm/doprint.xc')
-rwxr-xr-x | sys/src/libc/arm/doprint.xc | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/sys/src/libc/arm/doprint.xc b/sys/src/libc/arm/doprint.xc new file mode 100755 index 000000000..e3846a8d8 --- /dev/null +++ b/sys/src/libc/arm/doprint.xc @@ -0,0 +1,617 @@ +#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; +} |