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, 32 'E', _efgfmt, 33 'G', _efgfmt, 34 'S', _runesfmt, 35 'X', _ifmt, 36 'b', _ifmt, 37 'c', _charfmt, 38 'd', _ifmt, 39 'e', _efgfmt, 40 'f', _efgfmt, 41 'g', _efgfmt, 42 'h', _flagfmt, 43 'l', _flagfmt, 44 'n', _countfmt, 45 'o', _ifmt, 46 'p', _ifmt, 47 /* 'r', errfmt, */ 48 's', _strfmt, 49 'u', _flagfmt, 50 'x', _ifmt, 51 0, nil, 52 }; 53 54 int (*doquote)(int); 55 56 /* 57 * _fmtlock() must be set 58 */ 59 static int 60 _fmtinstall(int c, Fmts f) 61 { 62 Convfmt *p, *ep; 63 64 if(c<=0 || c>=65536) 65 return -1; 66 if(!f) 67 f = _badfmt; 68 69 ep = &fmtalloc.fmt[fmtalloc.nfmt]; 70 for(p=fmtalloc.fmt; p<ep; p++) 71 if(p->c == c) 72 break; 73 74 if(p == &fmtalloc.fmt[Maxfmt]) 75 return -1; 76 77 p->fmt = f; 78 if(p == ep){ /* installing a new format character */ 79 fmtalloc.nfmt++; 80 p->c = c; 81 } 82 83 return 0; 84 } 85 86 int 87 fmtinstall(int c, Fmts f) 88 { 89 int ret; 90 91 _fmtlock(); 92 ret = _fmtinstall(c, f); 93 _fmtunlock(); 94 return ret; 95 } 96 97 static Fmts 98 fmtfmt(int c) 99 { 100 Convfmt *p, *ep; 101 102 ep = &fmtalloc.fmt[fmtalloc.nfmt]; 103 for(p=fmtalloc.fmt; p<ep; p++) 104 if(p->c == c){ 105 while(p->fmt == nil) /* loop until value is updated */ 106 ; 107 return p->fmt; 108 } 109 110 /* is this a predefined format char? */ 111 _fmtlock(); 112 for(p=knownfmt; p->c; p++) 113 if(p->c == c){ 114 _fmtinstall(p->c, p->fmt); 115 _fmtunlock(); 116 return p->fmt; 117 } 118 _fmtunlock(); 119 120 return _badfmt; 121 } 122 123 void* 124 _fmtdispatch(Fmt *f, void *fmt, int isrunes) 125 { 126 Rune rune, r; 127 int i, n; 128 129 f->flags = 0; 130 f->width = f->prec = 0; 131 132 for(;;){ 133 if(isrunes){ 134 r = *(Rune*)fmt; 135 fmt = (Rune*)fmt + 1; 136 }else{ 137 fmt = (char*)fmt + chartorune(&rune, fmt); 138 r = rune; 139 } 140 f->r = r; 141 switch(r){ 142 case '\0': 143 return nil; 144 case '.': 145 f->flags |= FmtWidth|FmtPrec; 146 continue; 147 case '0': 148 if(!(f->flags & FmtWidth)){ 149 f->flags |= FmtZero; 150 continue; 151 } 152 /* fall through */ 153 case '1': case '2': case '3': case '4': 154 case '5': case '6': case '7': case '8': case '9': 155 i = 0; 156 while(r >= '0' && r <= '9'){ 157 i = i * 10 + r - '0'; 158 if(isrunes){ 159 r = *(Rune*)fmt; 160 fmt = (Rune*)fmt + 1; 161 }else{ 162 r = *(char*)fmt; 163 fmt = (char*)fmt + 1; 164 } 165 } 166 if(isrunes) 167 fmt = (Rune*)fmt - 1; 168 else 169 fmt = (char*)fmt - 1; 170 numflag: 171 if(f->flags & FmtWidth){ 172 f->flags |= FmtPrec; 173 f->prec = i; 174 }else{ 175 f->flags |= FmtWidth; 176 f->width = i; 177 } 178 continue; 179 case '*': 180 i = va_arg(f->args, int); 181 if(i < 0){ 182 i = -i; 183 f->flags |= FmtLeft; 184 } 185 goto numflag; 186 } 187 n = (*fmtfmt(r))(f); 188 if(n < 0) 189 return nil; 190 if(n == 0) 191 return fmt; 192 } 193 } 194