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