fmt.c (3575B)
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" 7 8 enum 9 { 10 Maxfmt = 64 11 }; 12 13 typedef struct Convfmt Convfmt; 14 struct Convfmt 15 { 16 int c; 17 volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ 18 }; 19 20 static struct 21 { 22 /* lock by calling __fmtlock, __fmtunlock */ 23 int nfmt; 24 Convfmt fmt[Maxfmt]; 25 } fmtalloc; 26 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 PLAN9PORT 38 'F', __efgfmt, /* ANSI only */ 39 #endif 40 'G', __efgfmt, 41 #ifndef PLAN9PORT 42 'L', __flagfmt, /* ANSI only */ 43 #endif 44 '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 PLAN9PORT 54 'i', __ifmt, /* ANSI only */ 55 #endif 56 'l', __flagfmt, 57 'n', __countfmt, 58 'o', __ifmt, 59 'p', __ifmt, 60 'r', __errfmt, 61 's', __strfmt, 62 #ifdef PLAN9PORT 63 'u', __flagfmt, 64 #else 65 'u', __ifmt, 66 #endif 67 'x', __ifmt, 68 0, nil, 69 }; 70 71 72 int (*fmtdoquote)(int); 73 74 /* 75 * __fmtlock() must be set 76 */ 77 static int 78 __fmtinstall(int c, Fmts f) 79 { 80 Convfmt *p, *ep; 81 82 if(c<=0 || c>=65536) 83 return -1; 84 if(!f) 85 f = __badfmt; 86 87 ep = &fmtalloc.fmt[fmtalloc.nfmt]; 88 for(p=fmtalloc.fmt; p<ep; p++) 89 if(p->c == c) 90 break; 91 92 if(p == &fmtalloc.fmt[Maxfmt]) 93 return -1; 94 95 p->fmt = f; 96 if(p == ep){ /* installing a new format character */ 97 fmtalloc.nfmt++; 98 p->c = c; 99 } 100 101 return 0; 102 } 103 104 int 105 fmtinstall(int c, int (*f)(Fmt*)) 106 { 107 int ret; 108 109 __fmtlock(); 110 ret = __fmtinstall(c, f); 111 __fmtunlock(); 112 return ret; 113 } 114 115 static Fmts 116 fmtfmt(int c) 117 { 118 Convfmt *p, *ep; 119 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 } 127 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(); 137 138 return __badfmt; 139 } 140 141 void* 142 __fmtdispatch(Fmt *f, void *fmt, int isrunes) 143 { 144 Rune rune, r; 145 int i, n; 146 147 f->flags = 0; 148 f->width = f->prec = 0; 149 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 else 187 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 }