#include "internal.h" #include #define atomic _Atomic #define MaxFmt 128 #define atomic·load atomic_load #define atomic·store atomic_store static struct { atomic int len; Verb verb[MaxFmt]; } formatter = { ATOMIC_VAR_INIT(27), { {' ', ·fmtflag}, {'#', ·fmtflag}, {'%', ·fmtpercent}, {'\'',·fmtflag}, {'+', ·fmtflag}, {',', ·fmtflag}, {'-', ·fmtflag}, {'C', ·fmtrune}, {'E', ·fmtfloat}, {'G', ·fmtfloat}, {'S', ·fmtutf8}, {'X', ·fmtint}, {'b', ·fmtint}, {'c', ·fmtchar}, {'d', ·fmtint}, {'e', ·fmtfloat}, {'f', ·fmtfloat}, {'g', ·fmtfloat}, {'h', ·fmtflag}, {'l', ·fmtflag}, {'n', ·fmtcount}, {'o', ·fmtint}, {'p', ·fmtint}, {'r', ·fmterr}, {'s', ·fmtstr}, {'u', ·fmtflag}, {'u', ·fmtint}, {'x', ·fmtint}, } }; 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 ·fmterr; } 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; } 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; } 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 + 1 > e){ if(!(b=flush(io, b, sizeof(*b)))) return -1; e = io->buffer.end; } *b++ = *fmt++; }else{ n = utf8·decode(fmt, &r); if(b + n > e){ if(!(b=flush(io, b, sizeof(*b)))) return -1; e = io->buffer.end; } while(n--) *b++ = *fmt++; } fmt++; io->n += b - io->buffer.cur; io->buffer.cur = b; if(c=='\0') /* we hit our nul terminator */ return io->n = n; io->buffer.end = e; } if(!(fmt=dispatch(io, fmt))) return -1; } }