aboutsummaryrefslogtreecommitdiff
path: root/src/libfmt/do.c
diff options
context:
space:
mode:
authorNicholas <nbnoll@eml.cc>2021-11-20 10:53:19 -0800
committerNicholas <nbnoll@eml.cc>2021-11-20 10:53:19 -0800
commita9bfe650038afea8b751175cac16f6027345e45f (patch)
tree9a7f9feb76a64bb3efe573036d80b7bdbf8a59a5 /src/libfmt/do.c
parent1c8d4e69205fd875f6bec3fa3bd929c2e7f52f62 (diff)
Chore: reorganize libutf and libfmt into base
I found the split to be arbitrary. Better to include the functionality in the standard library. I also split the headers to allow for more granular inclusion (but the library is still monolithic). The only ugliness is the circular dependency introduced with libutf's generated functions. We put explicit prereqs with the necessary object files instead.
Diffstat (limited to 'src/libfmt/do.c')
-rw-r--r--src/libfmt/do.c728
1 files changed, 0 insertions, 728 deletions
diff --git a/src/libfmt/do.c b/src/libfmt/do.c
deleted file mode 100644
index bd2e65c..0000000
--- a/src/libfmt/do.c
+++ /dev/null
@@ -1,728 +0,0 @@
-#include "internal.h"
-#include <arch/atomic.h>
-
-#define MaxFmt 128
-#define atomic·load(p) (*(p))
-
-// -----------------------------------------------------------------------
-// globals
-
-/* built in verbs */
-static int fmtflag(fmt·State *);
-static int fmtpercent(fmt·State *);
-static int fmtrune(fmt·State *);
-static int fmtfloat(fmt·State *);
-static int fmtutf8(fmt·State *);
-static int fmtint(fmt·State *);
-static int fmtchar(fmt·State *);
-static int fmtcount(fmt·State *);
-static int fmtstring(fmt·State *);
-static int fmterror(fmt·State *);
-
-static int badfmt(fmt·State *);
-
-static struct
-{
- volatile int len;
- Verb verb[MaxFmt];
-} formatter =
-{
- 30,
- {
- {' ', fmtflag},
- {'#', fmtflag},
- {'%', fmtpercent},
- {'\'',fmtflag},
- {'+', fmtflag},
- {',', fmtflag},
- {'-', fmtflag},
- {'C', fmtrune},
- {'E', fmtfloat},
- {'F', fmtfloat},
- {'G', fmtfloat},
- {'L', fmtflag},
- {'S', fmtutf8},
- {'X', fmtint},
- {'b', fmtint},
- {'c', fmtchar},
- {'d', fmtint},
- {'e', fmtfloat},
- {'f', fmtfloat},
- {'g', fmtfloat},
- {'h', fmtflag},
- {'i', fmtint},
- {'l', fmtflag},
- {'n', fmtcount},
- {'o', fmtint},
- {'p', fmtint},
- {'r', fmterror},
- {'s', fmtstring},
- {'U', fmtflag},
- {'u', fmtint},
- {'x', fmtint},
- }
-};
-
-// -----------------------------------------------------------------------
-// internal functions
-
-static Formatter
-format(int c)
-{
- Verb *v, *e;
- e = &formatter.verb[atomic·load(&formatter.len)];
- for(v=e; v > formatter.verb; --v){
- if(v->c == c)
- return v->fmt;
- }
-
- return badfmt;
-}
-
-static char *
-dispatch(fmt·State *io, char *fmt)
-{
- rune r;
- int i, n;
-
- io->flag = 0;
- io->width = io->prec = 0;
-
- /*
- * the form of each print verb:
- * % [flags] verb
- * + the verb is a single character
- * + each flag is either
- * - a single character
- * - a decimal numeric string
- * - up to 2 decimal strings can be used
- * - [width|*].[prec|*]
- * - if missing, set to 0
- * - if *, grab from varargs
- */
- for(;;){
- fmt += utf8·decode(fmt, &r);
- io->verb = r;
- switch(r){
- case 0:
- return nil;
- case '.':
- io->flag |= fmt·Width|fmt·Prec;
- continue;
- case '0':
- if(!(io->flag & fmt·Width)){
- io->flag |= fmt·Zero;
- continue;
- }
- /* fallthrough */
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- i = 0;
- while('0' <= r && r <= '9'){
- i = 10*i + (r-'0');
- r = *fmt++;
- }
- fmt--;
- number:
- if(io->flag & fmt·Width){
- io->flag |= fmt·Prec;
- io->prec = i;
- }else{
- io->flag |= fmt·Width;
- io->width = i;
- }
- continue;
- case '*':
- i = va_arg(io->args, int);
- if(i < 0){
- if(io->flag&fmt·Prec){
- io->flag &= ~fmt·Prec;
- io->prec = 0;
- continue;
- }
- i = -i;
- io->flag |= fmt·Left;
- }
- goto number;
- }
- n = format(r)(io);
- if(n < 0)
- return nil;
- if(!n)
- return fmt;
- }
-}
-
-static char *
-flush(fmt·State *io, char *b, int len)
-{
- io->n += b - io->buffer.cur;
- io->buffer.cur = b;
- if(!io->flush || !(*io->flush)(io) || io->buffer.cur + len >= io->buffer.end) {
- io->buffer.end = io->buffer.cur;
- return nil;
- }
- return io->buffer.cur;
-}
-
-static int
-pad(fmt·State *io, int n)
-{
- int i;
- char *b=io->buffer.cur, *e=io->buffer.end;
-
- for(i=0; i<n; i++){
- if(b>=e){
- if(!(b=flush(io, b, 1)))
- return -1;
- e = io->buffer.end;
- }
- *b++ = ' ';
- }
-
- io->n += b - io->buffer.cur;
- io->buffer.cur = b;
- return 0;
-}
-
-static int
-copy(fmt·State *io, char *m, int sz, int n)
-{
- ulong f;
- rune r;
- int nc, w, nb;
- char *b, *e, *me;
-
- w = 0;
- f = io->flag;
- me = m + sz;
-
- if(f&fmt·Width)
- w = io->width;
- if(f&fmt·Prec && n > io->prec)
- n = io->prec;
- if(!(f&fmt·Left) && pad(io, w-n)<0)
- return -1;
-
- b = io->buffer.cur;
- e = io->buffer.end;
-
- for(nc=n; nc>0; nc--){
- r = *(uchar *)m;
- if(utf8·onebyte(r)){
- nb=1;
- m++;
- }else if((me-m) >= UTFmax || utf8·canfit(m, me-m)){
- nb=utf8·decode(m, &r);
- m+=n;
- }else
- break;
-
- if(b+n>e){
- if(!(b=flush(io, b, nb)))
- return -1;
- e = io->buffer.end;
- }
- b += utf8·encode(&r, b);
- }
-
- io->n += b - io->buffer.cur;
- io->buffer.cur = b;
- if(f&fmt·Left && pad(io, w-n)<0)
- return -1;
-
- return 0;
-}
-
-static int
-copyrune(fmt·State *io, rune *m, int n)
-{
- ulong f;
- rune r, *me;
- int w, nb;
- char *b, *e;
-
- w = 0;
- f = io->flag;
-
- if(f&fmt·Width)
- w = io->width;
- if(f&fmt·Prec && n > io->prec)
- n = io->prec;
-
- if(!(f&fmt·Left) && pad(io, w-n)<0)
- return -1;
-
- b = io->buffer.cur;
- e = io->buffer.end;
-
- for(me=m+n; m < me; m++){
- r = *m;
- nb = utf8·runelen(r);
- if(b + nb > e){
- if(!(b=flush(io, b, nb)))
- return -1;
- e = io->buffer.end;
- }
- b += utf8·encode(&r, b);
- }
-
- io->n += b - io->buffer.cur;
- io->buffer.cur = b;
- if(f&fmt·Left && pad(io, w-n)<0)
- return -1;
-
- return 0;
-}
-
-static int
-copystring(fmt·State *io, char *s)
-{
- rune r;
- int i,j;
-
- if(!s)
- return copy(io, "<nil>", 5, 5);
-
- if(io->flag&fmt·Prec){
- i = 0;
- for(j=0; j < io->prec && s[i]; j++)
- i += utf8·decode(s+i, &r);
-
- return copy(io, s, i, j);
- }
- return copy(io, s, strlen(s), utf8·len(s));
-}
-
-static int
-copyutf8(fmt·State *io, rune *s)
-{
- rune *e;
- int n,p;
-
- if(!s)
- return copy(io, "<nil>", 5, 5);
-
- if(io->flag & fmt·Prec){
- p = io->prec;
- for(n=0; n<p; n++)
- if(!s[n])
- break;
- }else{
- for(e=s; *e; e++)
- ;
- n = e - s;
- }
-
- return copyrune(io, s, n);
-}
-
-// -----------------------------------------------------------------------
-// format helpers
-
-static int
-needseperate(int *digits, char **groups)
-{
- int group;
-
- (*digits)++;
- group = *(uchar *)*groups;
-
- if(group == 0xFF || group == 0x7f || group == 0x00)
- return 0;
- if(*digits > group){
- if((*groups)[1] != 0)
- (*groups)++;
- *digits = 1;
- return 1;
- }
- return 0;
-}
-
-// -----------------------------------------------------------------------
-// formatters
-
-static int
-fmtchar(fmt·State *io)
-{
- char x[1];
- x[0] = va_arg(io->args, int);
- io->prec = 1;
-
- return copy(io, x, 1, 1);
-}
-
-static int
-fmtstring(fmt·State *io)
-{
- char *s;
- s = va_arg(io->args, char *);
- return copystring(io, s);
-}
-
-static int
-fmterror(fmt·State *io)
-{
- char *s;
- s = strerror(errno);
- return copystring(io, s);
-}
-
-static int
-fmtrune(fmt·State *io)
-{
- rune x[1];
-
- x[0] = va_arg(io->args, int);
- return copyrune(io, x, 1);
-}
-
-static int
-fmtutf8(fmt·State *io)
-{
- rune *s;
-
- s = va_arg(io->args, rune *);
- return copyutf8(io, s);
-}
-
-static int
-fmtpercent(fmt·State *io)
-{
- rune x[1];
-
- x[0] = io->verb;
- io->prec = 1;
- return copyrune(io, x, 1);
-}
-
-static int
-fmtint(fmt·State *io)
-{
- union{
- ulong u;
- uvlong v;
- } val;
- int neg, base, i, n, f, w, isv;
- int digits, bytes, runes, excess;
- char *groups, *thousands;
- char *p, *conv, buf[140];
-
- f = io->flag;
- neg = 0;
- isv = 0;
- val.u = 0;
-
- switch(io->verb){
- case 'o': case 'p': case 'u': case 'x': case 'X':
- f |= fmt·Unsigned;
- f &= ~(fmt·Sign|fmt·Space);
- }
-
- /* set flags */
- if(io->verb=='p'){
- val.u = (ulong)va_arg(io->args, void*);
- io->verb = 'x';
- f |= fmt·Unsigned;
- }else if(f&fmt·Vlong){
- isv=1;
- if(f&fmt·Unsigned)
- val.v = va_arg(io->args, uvlong);
- else
- val.v = va_arg(io->args, vlong);
- }else if(f&fmt·Long){
- if(f&fmt·Unsigned)
- val.u = va_arg(io->args, ulong);
- else
- val.u = va_arg(io->args, long);
- }else if(f&fmt·Byte){
- if(f&fmt·Unsigned)
- val.u = (uchar)va_arg(io->args, int);
- else
- val.u = (char)va_arg(io->args, int);
- }else if(f&fmt·Short){
- if(f&fmt·Unsigned)
- val.u = (ushort)va_arg(io->args, int);
- else
- val.u = (short)va_arg(io->args, int);
- }else{
- if(f&fmt·Unsigned)
- val.u = va_arg(io->args, uint);
- else
- val.u = va_arg(io->args, int);
- }
-
- conv = "0123456789abcdef";
- groups = "\4";
- thousands = io->thousands;
- /* get base */
- switch(io->verb){
- case 'd': case 'i': case 'u':
- base = 10;
- groups = io->groups;
- break;
- case 'X':
- conv = "0123456789ABCDEF";
- /*fallthrough*/
- case 'x':
- base = 16;
- thousands = ":";
- break;
- case 'b':
- base = 2;
- thousands = ":";
- break;
- case 'o':
- base = 8;
- break;
- default:
- return -1;
- }
-
- /* check for negativity */
- if(!(f&fmt·Unsigned)){
- if(isv && (vlong)val.v < 0){
- val.v = -(vlong)val.v;
- neg = 1;
- }else if(!isv && (long)val.u < 0){
- val.u = -(long)val.u;
- neg = 1;
- }
- }
-
- p = buf + sizeof(buf) - 1;
- n = 0;
- digits = 0;
- excess = 0;
- runes = utf8·len(thousands);
- bytes = strlen(thousands);
-
-#define PARSE(VALUE) \
- while((VALUE)){ \
- i = (VALUE) % base; \
- (VALUE) /= base; \
- if((f&fmt·Comma) && n%4 == 3){ \
- *p-- = ','; \
- n++; \
- } \
- if((f&fmt·Apost) && needseperate(&digits, &groups)){ \
- n += runes; \
- excess += bytes - runes; \
- p -= bytes; \
- memmove(p+1, thousands, bytes); \
- } \
- *p-- = conv[i]; \
- n++; \
- }
- if(isv)
- PARSE(val.v)
- else
- PARSE(val.u)
-#undef PARSE
-
- if(!n){
- if(!(f&fmt·Prec) || io->prec != 0 || (io->verb == 'o' && (f&fmt·Sharp))){
- *p-- = '0';
- n = 1;
- if(f&fmt·Apost)
- needseperate(&digits,&groups);
- }
-
- if(io->verb == 'x' || io->verb == 'X')
- f &= ~fmt·Sharp;
- }
-
- for(w = io->prec; n < w && p > buf+3; n++){
- if((f&fmt·Apost) && needseperate(&digits, &groups)){
- n += runes;
- excess += bytes - runes;
- p -= bytes;
- memmove(p+1, thousands, bytes);
- }
- *p-- = '0';
- }
-
- if(neg || (f&(fmt·Sign|fmt·Space)))
- n++;
-
- if(f&fmt·Sharp){
- if(base==16)
- n += 2;
- else if(base == 8){
- if(p[1] == '0')
- f &= ~fmt·Sharp;
- else
- n++;
- }
- }
-
- if(f&fmt·Zero && !(f & (fmt·Left|fmt·Prec))){
- w = 0;
- if(f & fmt·Width)
- w = io->width;
- for(; n < w && p > buf+3; n++){
- if((f & fmt·Apost) && needseperate(&digits, &groups)){
- n += runes;
- excess += bytes - runes;
- p -= bytes;
- memmove(p+1, thousands, bytes);
- }
- *p-- = '0';
- }
- io->flag &= ~fmt·Width;
- }
-
- if(f&fmt·Sharp){
- if(base==16)
- *p-- = io->verb;
- if(base==16 || base == 8)
- *p-- = '0';
- }
-
- if(neg)
- *p-- = '-';
- else if(f & fmt·Sign)
- *p-- = '+';
- else if (f & fmt·Space)
- *p-- = ' ';
-
- io->flag &= ~fmt·Prec;
- return copy(io, p+1, n+excess, n);
-}
-
-static int
-fmtcount(fmt·State *io)
-{
- void *p;
- ulong f;
-
- f = io->flag;
- p = va_arg(io->args, void*);
-
- if(f&fmt·Vlong)
- *(vlong*)p = io->n;
- else if(f&fmt·Long)
- *(long*)p = io->n;
- else if(f&fmt·Byte)
- *(char*)p = io->n;
- else if(f&fmt·Short)
- *(short*)p = io->n;
- else
- *(int*)p = io->n;
-
- return 0;
-}
-
-static int
-fmtflag(fmt·State *io)
-{
- switch(io->verb){
- case ',': io->flag |= fmt·Comma; break;
- case '-': io->flag |= fmt·Left; break;
- case '+': io->flag |= fmt·Sign; break;
- case '#': io->flag |= fmt·Sharp; break;
- case '\'': io->flag |= fmt·Apost; break;
- case ' ': io->flag |= fmt·Space; break;
- case 'u': io->flag |= fmt·Unsigned; break;
- case 'L': io->flag |= fmt·Ldouble; break;
- case 'h':
- if(io->flag&fmt·Short)
- io->flag |= fmt·Byte;
- io->flag |= fmt·Short;
- break;
- case 'l':
- if(io->flag&fmt·Long)
- io->flag |= fmt·Vlong;
- io->flag |= fmt·Long;
- break;
- }
- return 1;
-}
-
-static int
-badfmt(fmt·State *io)
-{
- int n;
- char x[UTFmax+2];
-
- x[0] = '%';
- n = 1 + utf8·encode(&io->verb, x+1);
- x[n++] = '%';
- io->prec = n;
- copy(io, x, n, n);
-
- return 0;
-}
-
-#include "float.c"
-
-// -----------------------------------------------------------------------
-// exports
-
-int
-fmt·do(fmt·State *io, char *fmt)
-{
- rune r;
- int c, n;
- char *b, *e;
-
- for(;;){
- b = io->buffer.cur;
- e = io->buffer.end;
- while((c = *(uchar *)fmt) && c != '%'){
- if(utf8·onebyte(c)){
- if(b >= e){
- if(!(b=flush(io, b, 1)))
- return -1;
- e = io->buffer.end;
- }
- *b++ = *fmt++;
- }else{
- n = utf8·decode(fmt, &r);
- if(b + n > e){
- if(!(b=flush(io, b, n)))
- return -1;
- e = io->buffer.end;
- }
- while(n--)
- *b++ = *fmt++;
- }
- }
- fmt++;
- io->n += b - io->buffer.cur;
- io->buffer.cur = b;
- if(!c) /* we hit our nul terminator */
- return io->n - n;
- io->buffer.end = e;
-
- if(!(fmt=dispatch(io, fmt)))
- return -1;
- }
-}
-
-int
-fmt·install(int verb, Formatter func)
-{
- Verb *v;
- int i, ret;
-
-lock:
- if(verb <= 0 || verb >= 65536){
- ret = -1;
- goto unlock;
- }
- if(!func)
- func = badfmt;
-
- if((i = atomic·load(&formatter.len))==MaxFmt)
- return -1;
-
- v = &formatter.verb[i];
- v->c = verb;
- v->fmt = func;
-
- atomic·store(&formatter.len, i+1);
- ret = 0;
-unlock:
- return ret;
-}