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