Blob
1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */2 #include <stdarg.h>3 #include <string.h>4 #include <stdatomic.h>5 #include "plan9.h"6 #include "fmt.h"7 #include "fmtdef.h"9 enum10 {11 Maxfmt = 12812 };14 typedef struct Convfmt Convfmt;15 struct Convfmt16 {17 int c;18 Fmts fmt;19 };21 static struct22 {23 /*24 * lock updates to fmt by calling __fmtlock, __fmtunlock.25 * reads can start at nfmt and work backward without26 * further locking. later fmtinstalls take priority over earlier27 * ones because of the backwards loop.28 * once installed, a format is never overwritten.29 */30 _Atomic int nfmt;31 Convfmt fmt[Maxfmt];32 } fmtalloc = {33 #ifdef PLAN9PORT34 ATOMIC_VAR_INIT(27),35 #else36 ATOMIC_VAR_INIT(30),37 #endif38 {39 {' ', __flagfmt},40 {'#', __flagfmt},41 {'%', __percentfmt},42 {'\'', __flagfmt},43 {'+', __flagfmt},44 {',', __flagfmt},45 {'-', __flagfmt},46 {'C', __runefmt}, /* Plan 9 addition */47 {'E', __efgfmt},48 #ifndef PLAN9PORT49 {'F', __efgfmt}, /* ANSI only */50 #endif51 {'G', __efgfmt},52 #ifndef PLAN9PORT53 {'L', __flagfmt}, /* ANSI only */54 #endif55 {'S', __runesfmt}, /* Plan 9 addition */56 {'X', __ifmt},57 {'b', __ifmt}, /* Plan 9 addition */58 {'c', __charfmt},59 {'d', __ifmt},60 {'e', __efgfmt},61 {'f', __efgfmt},62 {'g', __efgfmt},63 {'h', __flagfmt},64 #ifndef PLAN9PORT65 {'i', __ifmt}, /* ANSI only */66 #endif67 {'l', __flagfmt},68 {'n', __countfmt},69 {'o', __ifmt},70 {'p', __ifmt},71 {'r', __errfmt},72 {'s', __strfmt},73 #ifdef PLAN9PORT74 {'u', __flagfmt},75 #else76 {'u', __ifmt},77 #endif78 {'x', __ifmt},79 }80 };82 int (*fmtdoquote)(int);84 /*85 * __fmtlock() must be set86 */87 static int88 __fmtinstall(int c, Fmts f)89 {90 Convfmt *p;91 int i;93 if(c<=0 || c>=65536)94 return -1;95 if(!f)96 f = __badfmt;98 i = atomic_load(&fmtalloc.nfmt);99 if(i == Maxfmt)100 return -1;101 p = &fmtalloc.fmt[i];102 p->c = c;103 p->fmt = f;104 atomic_store(&fmtalloc.nfmt, i+1);106 return 0;107 }109 int110 fmtinstall(int c, int (*f)(Fmt*))111 {112 int ret;114 __fmtlock();115 ret = __fmtinstall(c, f);116 __fmtunlock();117 return ret;118 }120 static Fmts121 fmtfmt(int c)122 {123 Convfmt *p, *ep;125 ep = &fmtalloc.fmt[atomic_load(&fmtalloc.nfmt)];126 for(p=ep; p-- > fmtalloc.fmt; )127 if(p->c == c)128 return p->fmt;130 return __badfmt;131 }133 void*134 __fmtdispatch(Fmt *f, void *fmt, int isrunes)135 {136 Rune rune, r;137 int i, n;139 f->flags = 0;140 f->width = f->prec = 0;142 for(;;){143 if(isrunes){144 r = *(Rune*)fmt;145 fmt = (Rune*)fmt + 1;146 }else{147 fmt = (char*)fmt + chartorune(&rune, (char*)fmt);148 r = rune;149 }150 f->r = r;151 switch(r){152 case '\0':153 return nil;154 case '.':155 f->flags |= FmtWidth|FmtPrec;156 continue;157 case '0':158 if(!(f->flags & FmtWidth)){159 f->flags |= FmtZero;160 continue;161 }162 /* fall through */163 case '1': case '2': case '3': case '4':164 case '5': case '6': case '7': case '8': case '9':165 i = 0;166 while(r >= '0' && r <= '9'){167 i = i * 10 + r - '0';168 if(isrunes){169 r = *(Rune*)fmt;170 fmt = (Rune*)fmt + 1;171 }else{172 r = *(char*)fmt;173 fmt = (char*)fmt + 1;174 }175 }176 if(isrunes)177 fmt = (Rune*)fmt - 1;178 else179 fmt = (char*)fmt - 1;180 numflag:181 if(f->flags & FmtWidth){182 f->flags |= FmtPrec;183 f->prec = i;184 }else{185 f->flags |= FmtWidth;186 f->width = i;187 }188 continue;189 case '*':190 i = va_arg(f->args, int);191 if(i < 0){192 /*193 * negative precision =>194 * ignore the precision.195 */196 if(f->flags & FmtPrec){197 f->flags &= ~FmtPrec;198 f->prec = 0;199 continue;200 }201 i = -i;202 f->flags |= FmtLeft;203 }204 goto numflag;205 }206 n = (*fmtfmt(r))(f);207 if(n < 0)208 return nil;209 if(n == 0)210 return fmt;211 }212 }