summaryrefslogtreecommitdiff
path: root/sys/src/libc/arm/doprint.xc
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/libc/arm/doprint.xc617
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;
+}