Blob
1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */2 #include <stdarg.h>3 #include <string.h>4 #include "plan9.h"5 #include "fmt.h"6 #include "fmtdef.h"8 enum9 {10 Maxfmt = 6411 };13 typedef struct Convfmt Convfmt;14 struct Convfmt15 {16 int c;17 volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */18 };20 static struct21 {22 /* lock by calling __fmtlock, __fmtunlock */23 int nfmt;24 Convfmt fmt[Maxfmt];25 } fmtalloc;27 static Convfmt knownfmt[] = {28 ' ', __flagfmt,29 '#', __flagfmt,30 '%', __percentfmt,31 '\'', __flagfmt,32 '+', __flagfmt,33 ',', __flagfmt,34 '-', __flagfmt,35 'C', __runefmt, /* Plan 9 addition */36 'E', __efgfmt,37 #ifndef PLAN9PORT38 'F', __efgfmt, /* ANSI only */39 #endif40 'G', __efgfmt,41 #ifndef PLAN9PORT42 'L', __flagfmt, /* ANSI only */43 #endif44 'S', __runesfmt, /* Plan 9 addition */45 'X', __ifmt,46 'b', __ifmt, /* Plan 9 addition */47 'c', __charfmt,48 'd', __ifmt,49 'e', __efgfmt,50 'f', __efgfmt,51 'g', __efgfmt,52 'h', __flagfmt,53 #ifndef PLAN9PORT54 'i', __ifmt, /* ANSI only */55 #endif56 'l', __flagfmt,57 'n', __countfmt,58 'o', __ifmt,59 'p', __ifmt,60 'r', __errfmt,61 's', __strfmt,62 #ifdef PLAN9PORT63 'u', __flagfmt,64 #else65 'u', __ifmt,66 #endif67 'x', __ifmt,68 0, nil,69 };72 int (*fmtdoquote)(int);74 /*75 * __fmtlock() must be set76 */77 static int78 __fmtinstall(int c, Fmts f)79 {80 Convfmt *p, *ep;82 if(c<=0 || c>=65536)83 return -1;84 if(!f)85 f = __badfmt;87 ep = &fmtalloc.fmt[fmtalloc.nfmt];88 for(p=fmtalloc.fmt; p<ep; p++)89 if(p->c == c)90 break;92 if(p == &fmtalloc.fmt[Maxfmt])93 return -1;95 p->fmt = f;96 if(p == ep){ /* installing a new format character */97 fmtalloc.nfmt++;98 p->c = c;99 }101 return 0;102 }104 int105 fmtinstall(int c, int (*f)(Fmt*))106 {107 int ret;109 __fmtlock();110 ret = __fmtinstall(c, f);111 __fmtunlock();112 return ret;113 }115 static Fmts116 fmtfmt(int c)117 {118 Convfmt *p, *ep;120 ep = &fmtalloc.fmt[fmtalloc.nfmt];121 for(p=fmtalloc.fmt; p<ep; p++)122 if(p->c == c){123 while(p->fmt == nil) /* loop until value is updated */124 ;125 return p->fmt;126 }128 /* is this a predefined format char? */129 __fmtlock();130 for(p=knownfmt; p->c; p++)131 if(p->c == c){132 __fmtinstall(p->c, p->fmt);133 __fmtunlock();134 return p->fmt;135 }136 __fmtunlock();138 return __badfmt;139 }141 void*142 __fmtdispatch(Fmt *f, void *fmt, int isrunes)143 {144 Rune rune, r;145 int i, n;147 f->flags = 0;148 f->width = f->prec = 0;150 for(;;){151 if(isrunes){152 r = *(Rune*)fmt;153 fmt = (Rune*)fmt + 1;154 }else{155 fmt = (char*)fmt + chartorune(&rune, (char*)fmt);156 r = rune;157 }158 f->r = r;159 switch(r){160 case '\0':161 return nil;162 case '.':163 f->flags |= FmtWidth|FmtPrec;164 continue;165 case '0':166 if(!(f->flags & FmtWidth)){167 f->flags |= FmtZero;168 continue;169 }170 /* fall through */171 case '1': case '2': case '3': case '4':172 case '5': case '6': case '7': case '8': case '9':173 i = 0;174 while(r >= '0' && r <= '9'){175 i = i * 10 + r - '0';176 if(isrunes){177 r = *(Rune*)fmt;178 fmt = (Rune*)fmt + 1;179 }else{180 r = *(char*)fmt;181 fmt = (char*)fmt + 1;182 }183 }184 if(isrunes)185 fmt = (Rune*)fmt - 1;186 else187 fmt = (char*)fmt - 1;188 numflag:189 if(f->flags & FmtWidth){190 f->flags |= FmtPrec;191 f->prec = i;192 }else{193 f->flags |= FmtWidth;194 f->width = i;195 }196 continue;197 case '*':198 i = va_arg(f->args, int);199 if(i < 0){200 /*201 * negative precision =>202 * ignore the precision.203 */204 if(f->flags & FmtPrec){205 f->flags &= ~FmtPrec;206 f->prec = 0;207 continue;208 }209 i = -i;210 f->flags |= FmtLeft;211 }212 goto numflag;213 }214 n = (*fmtfmt(r))(f);215 if(n < 0)216 return nil;217 if(n == 0)218 return fmt;219 }220 }