@@ 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;
@@ 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*, ...);
@@ 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 = "<null>";
+ strconv(s, fp);
+ } else {
+ r = *(Rune**)o;
+ if(r == 0)
+ r = L"<null>";
+ 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;
}