1*0d601874SDavid du Colombier /* 2*0d601874SDavid du Colombier * The authors of this software are Rob Pike and Ken Thompson. 3*0d601874SDavid du Colombier * Copyright (c) 2002 by Lucent Technologies. 4*0d601874SDavid du Colombier * Permission to use, copy, modify, and distribute this software for any 5*0d601874SDavid du Colombier * purpose without fee is hereby granted, provided that this entire notice 6*0d601874SDavid du Colombier * is included in all copies of any software which is or includes a copy 7*0d601874SDavid du Colombier * or modification of this software and in all copies of the supporting 8*0d601874SDavid du Colombier * documentation for such software. 9*0d601874SDavid du Colombier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 10*0d601874SDavid du Colombier * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE 11*0d601874SDavid du Colombier * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12*0d601874SDavid du Colombier * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13*0d601874SDavid du Colombier */ 148ccd4a63SDavid du Colombier #include <u.h> 158ccd4a63SDavid du Colombier #include <libc.h> 168ccd4a63SDavid du Colombier #include "fmtdef.h" 178ccd4a63SDavid du Colombier 188ccd4a63SDavid du Colombier enum 198ccd4a63SDavid du Colombier { 208ccd4a63SDavid du Colombier Maxfmt = 64 218ccd4a63SDavid du Colombier }; 228ccd4a63SDavid du Colombier 238ccd4a63SDavid du Colombier typedef struct Convfmt Convfmt; 248ccd4a63SDavid du Colombier struct Convfmt 258ccd4a63SDavid du Colombier { 268ccd4a63SDavid du Colombier int c; 278ccd4a63SDavid du Colombier volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ 288ccd4a63SDavid du Colombier }; 298ccd4a63SDavid du Colombier 308ccd4a63SDavid du Colombier struct 318ccd4a63SDavid du Colombier { 32*0d601874SDavid du Colombier /* lock by calling __fmtlock, __fmtunlock */ 338ccd4a63SDavid du Colombier int nfmt; 348ccd4a63SDavid du Colombier Convfmt fmt[Maxfmt]; 358ccd4a63SDavid du Colombier } fmtalloc; 368ccd4a63SDavid du Colombier 378ccd4a63SDavid du Colombier static Convfmt knownfmt[] = { 38*0d601874SDavid du Colombier ' ', __flagfmt, 39*0d601874SDavid du Colombier '#', __flagfmt, 40*0d601874SDavid du Colombier '%', __percentfmt, 41*0d601874SDavid du Colombier '+', __flagfmt, 42*0d601874SDavid du Colombier ',', __flagfmt, 43*0d601874SDavid du Colombier '-', __flagfmt, 44*0d601874SDavid du Colombier 'C', __runefmt, /* Plan 9 addition */ 45*0d601874SDavid du Colombier 'E', __efgfmt, 46*0d601874SDavid du Colombier #ifndef PLAN9PORT 47*0d601874SDavid du Colombier 'F', __efgfmt, /* ANSI only */ 48*0d601874SDavid du Colombier #endif 49*0d601874SDavid du Colombier 'G', __efgfmt, 50*0d601874SDavid du Colombier #ifndef PLAN9PORT 51*0d601874SDavid du Colombier 'L', __flagfmt, /* ANSI only */ 52*0d601874SDavid du Colombier #endif 53*0d601874SDavid du Colombier 'S', __runesfmt, /* Plan 9 addition */ 54*0d601874SDavid du Colombier 'X', __ifmt, 55*0d601874SDavid du Colombier 'b', __ifmt, /* Plan 9 addition */ 56*0d601874SDavid du Colombier 'c', __charfmt, 57*0d601874SDavid du Colombier 'd', __ifmt, 58*0d601874SDavid du Colombier 'e', __efgfmt, 59*0d601874SDavid du Colombier 'f', __efgfmt, 60*0d601874SDavid du Colombier 'g', __efgfmt, 61*0d601874SDavid du Colombier 'h', __flagfmt, 62*0d601874SDavid du Colombier #ifndef PLAN9PORT 63*0d601874SDavid du Colombier 'i', __ifmt, /* ANSI only */ 64*0d601874SDavid du Colombier #endif 65*0d601874SDavid du Colombier 'l', __flagfmt, 66*0d601874SDavid du Colombier 'n', __countfmt, 67*0d601874SDavid du Colombier 'o', __ifmt, 68*0d601874SDavid du Colombier 'p', __ifmt, 69*0d601874SDavid du Colombier 'r', __errfmt, 70*0d601874SDavid du Colombier 's', __strfmt, 71*0d601874SDavid du Colombier #ifdef PLAN9PORT 72*0d601874SDavid du Colombier 'u', __flagfmt, 73*0d601874SDavid du Colombier #else 74*0d601874SDavid du Colombier 'u', __ifmt, 75*0d601874SDavid du Colombier #endif 76*0d601874SDavid du Colombier 'x', __ifmt, 778ccd4a63SDavid du Colombier 0, nil, 788ccd4a63SDavid du Colombier }; 798ccd4a63SDavid du Colombier 80*0d601874SDavid du Colombier 81*0d601874SDavid du Colombier int (*fmtdoquote)(int); 828ccd4a63SDavid du Colombier 838ccd4a63SDavid du Colombier /* 84*0d601874SDavid du Colombier * __fmtlock() must be set 858ccd4a63SDavid du Colombier */ 868ccd4a63SDavid du Colombier static int 87*0d601874SDavid du Colombier __fmtinstall(int c, Fmts f) 888ccd4a63SDavid du Colombier { 898ccd4a63SDavid du Colombier Convfmt *p, *ep; 908ccd4a63SDavid du Colombier 918ccd4a63SDavid du Colombier if(c<=0 || c>=65536) 928ccd4a63SDavid du Colombier return -1; 938ccd4a63SDavid du Colombier if(!f) 94*0d601874SDavid du Colombier f = __badfmt; 958ccd4a63SDavid du Colombier 968ccd4a63SDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt]; 978ccd4a63SDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++) 988ccd4a63SDavid du Colombier if(p->c == c) 998ccd4a63SDavid du Colombier break; 1008ccd4a63SDavid du Colombier 1018ccd4a63SDavid du Colombier if(p == &fmtalloc.fmt[Maxfmt]) 1028ccd4a63SDavid du Colombier return -1; 1038ccd4a63SDavid du Colombier 1048ccd4a63SDavid du Colombier p->fmt = f; 1058ccd4a63SDavid du Colombier if(p == ep){ /* installing a new format character */ 1068ccd4a63SDavid du Colombier fmtalloc.nfmt++; 1078ccd4a63SDavid du Colombier p->c = c; 1088ccd4a63SDavid du Colombier } 1098ccd4a63SDavid du Colombier 1108ccd4a63SDavid du Colombier return 0; 1118ccd4a63SDavid du Colombier } 1128ccd4a63SDavid du Colombier 1138ccd4a63SDavid du Colombier int 114*0d601874SDavid du Colombier fmtinstall(int c, int (*f)(Fmt*)) 1158ccd4a63SDavid du Colombier { 1168ccd4a63SDavid du Colombier int ret; 1178ccd4a63SDavid du Colombier 118*0d601874SDavid du Colombier __fmtlock(); 119*0d601874SDavid du Colombier ret = __fmtinstall(c, f); 120*0d601874SDavid du Colombier __fmtunlock(); 1218ccd4a63SDavid du Colombier return ret; 1228ccd4a63SDavid du Colombier } 1238ccd4a63SDavid du Colombier 1248ccd4a63SDavid du Colombier static Fmts 1258ccd4a63SDavid du Colombier fmtfmt(int c) 1268ccd4a63SDavid du Colombier { 1278ccd4a63SDavid du Colombier Convfmt *p, *ep; 1288ccd4a63SDavid du Colombier 1298ccd4a63SDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt]; 1308ccd4a63SDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++) 1318ccd4a63SDavid du Colombier if(p->c == c){ 1328ccd4a63SDavid du Colombier while(p->fmt == nil) /* loop until value is updated */ 1338ccd4a63SDavid du Colombier ; 1348ccd4a63SDavid du Colombier return p->fmt; 1358ccd4a63SDavid du Colombier } 1368ccd4a63SDavid du Colombier 1378ccd4a63SDavid du Colombier /* is this a predefined format char? */ 138*0d601874SDavid du Colombier __fmtlock(); 1398ccd4a63SDavid du Colombier for(p=knownfmt; p->c; p++) 1408ccd4a63SDavid du Colombier if(p->c == c){ 141*0d601874SDavid du Colombier __fmtinstall(p->c, p->fmt); 142*0d601874SDavid du Colombier __fmtunlock(); 1438ccd4a63SDavid du Colombier return p->fmt; 1448ccd4a63SDavid du Colombier } 145*0d601874SDavid du Colombier __fmtunlock(); 1468ccd4a63SDavid du Colombier 147*0d601874SDavid du Colombier return __badfmt; 1488ccd4a63SDavid du Colombier } 1498ccd4a63SDavid du Colombier 1508ccd4a63SDavid du Colombier void* 151*0d601874SDavid du Colombier __fmtdispatch(Fmt *f, void *fmt, int isrunes) 1528ccd4a63SDavid du Colombier { 1538ccd4a63SDavid du Colombier Rune rune, r; 1548ccd4a63SDavid du Colombier int i, n; 1558ccd4a63SDavid du Colombier 1568ccd4a63SDavid du Colombier f->flags = 0; 1578ccd4a63SDavid du Colombier f->width = f->prec = 0; 1588ccd4a63SDavid du Colombier 1598ccd4a63SDavid du Colombier for(;;){ 1608ccd4a63SDavid du Colombier if(isrunes){ 1618ccd4a63SDavid du Colombier r = *(Rune*)fmt; 1628ccd4a63SDavid du Colombier fmt = (Rune*)fmt + 1; 1638ccd4a63SDavid du Colombier }else{ 164*0d601874SDavid du Colombier fmt = (char*)fmt + chartorune(&rune, (char*)fmt); 1658ccd4a63SDavid du Colombier r = rune; 1668ccd4a63SDavid du Colombier } 1678ccd4a63SDavid du Colombier f->r = r; 1688ccd4a63SDavid du Colombier switch(r){ 1698ccd4a63SDavid du Colombier case '\0': 1708ccd4a63SDavid du Colombier return nil; 1718ccd4a63SDavid du Colombier case '.': 1728ccd4a63SDavid du Colombier f->flags |= FmtWidth|FmtPrec; 1738ccd4a63SDavid du Colombier continue; 1748ccd4a63SDavid du Colombier case '0': 1758ccd4a63SDavid du Colombier if(!(f->flags & FmtWidth)){ 1768ccd4a63SDavid du Colombier f->flags |= FmtZero; 1778ccd4a63SDavid du Colombier continue; 1788ccd4a63SDavid du Colombier } 1798ccd4a63SDavid du Colombier /* fall through */ 1808ccd4a63SDavid du Colombier case '1': case '2': case '3': case '4': 1818ccd4a63SDavid du Colombier case '5': case '6': case '7': case '8': case '9': 1828ccd4a63SDavid du Colombier i = 0; 1838ccd4a63SDavid du Colombier while(r >= '0' && r <= '9'){ 1848ccd4a63SDavid du Colombier i = i * 10 + r - '0'; 1858ccd4a63SDavid du Colombier if(isrunes){ 1868ccd4a63SDavid du Colombier r = *(Rune*)fmt; 1878ccd4a63SDavid du Colombier fmt = (Rune*)fmt + 1; 1888ccd4a63SDavid du Colombier }else{ 1898ccd4a63SDavid du Colombier r = *(char*)fmt; 1908ccd4a63SDavid du Colombier fmt = (char*)fmt + 1; 1918ccd4a63SDavid du Colombier } 1928ccd4a63SDavid du Colombier } 1938ccd4a63SDavid du Colombier if(isrunes) 1948ccd4a63SDavid du Colombier fmt = (Rune*)fmt - 1; 1958ccd4a63SDavid du Colombier else 1968ccd4a63SDavid du Colombier fmt = (char*)fmt - 1; 1978ccd4a63SDavid du Colombier numflag: 1988ccd4a63SDavid du Colombier if(f->flags & FmtWidth){ 1998ccd4a63SDavid du Colombier f->flags |= FmtPrec; 2008ccd4a63SDavid du Colombier f->prec = i; 2018ccd4a63SDavid du Colombier }else{ 2028ccd4a63SDavid du Colombier f->flags |= FmtWidth; 2038ccd4a63SDavid du Colombier f->width = i; 2048ccd4a63SDavid du Colombier } 2058ccd4a63SDavid du Colombier continue; 2068ccd4a63SDavid du Colombier case '*': 2078ccd4a63SDavid du Colombier i = va_arg(f->args, int); 2088ccd4a63SDavid du Colombier if(i < 0){ 209*0d601874SDavid du Colombier /* 210*0d601874SDavid du Colombier * negative precision => 211*0d601874SDavid du Colombier * ignore the precision. 212*0d601874SDavid du Colombier */ 213*0d601874SDavid du Colombier if(f->flags & FmtPrec){ 214*0d601874SDavid du Colombier f->flags &= ~FmtPrec; 215*0d601874SDavid du Colombier f->prec = 0; 216*0d601874SDavid du Colombier continue; 217*0d601874SDavid du Colombier } 2188ccd4a63SDavid du Colombier i = -i; 2198ccd4a63SDavid du Colombier f->flags |= FmtLeft; 2208ccd4a63SDavid du Colombier } 2218ccd4a63SDavid du Colombier goto numflag; 2228ccd4a63SDavid du Colombier } 2238ccd4a63SDavid du Colombier n = (*fmtfmt(r))(f); 2248ccd4a63SDavid du Colombier if(n < 0) 2258ccd4a63SDavid du Colombier return nil; 2268ccd4a63SDavid du Colombier if(n == 0) 2278ccd4a63SDavid du Colombier return fmt; 2288ccd4a63SDavid du Colombier } 2298ccd4a63SDavid du Colombier } 230