19a747e4fSDavid du Colombier #include <u.h> 29a747e4fSDavid du Colombier #include <libc.h> 39a747e4fSDavid du Colombier #include "fmtdef.h" 49a747e4fSDavid du Colombier 59a747e4fSDavid du Colombier enum 69a747e4fSDavid du Colombier { 79a747e4fSDavid du Colombier Maxfmt = 64 89a747e4fSDavid du Colombier }; 99a747e4fSDavid du Colombier 109a747e4fSDavid du Colombier typedef struct Convfmt Convfmt; 119a747e4fSDavid du Colombier struct Convfmt 129a747e4fSDavid du Colombier { 139a747e4fSDavid du Colombier int c; 149a747e4fSDavid du Colombier volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ 159a747e4fSDavid du Colombier }; 169a747e4fSDavid du Colombier 179a747e4fSDavid du Colombier struct 189a747e4fSDavid du Colombier { 199a747e4fSDavid du Colombier /* lock by calling _fmtlock, _fmtunlock */ 209a747e4fSDavid du Colombier int nfmt; 219a747e4fSDavid du Colombier Convfmt fmt[Maxfmt]; 229a747e4fSDavid du Colombier } fmtalloc; 239a747e4fSDavid du Colombier 249a747e4fSDavid du Colombier static Convfmt knownfmt[] = { 259a747e4fSDavid du Colombier ' ', _flagfmt, 269a747e4fSDavid du Colombier '#', _flagfmt, 279a747e4fSDavid du Colombier '%', _percentfmt, 289a747e4fSDavid du Colombier '+', _flagfmt, 299a747e4fSDavid du Colombier ',', _flagfmt, 309a747e4fSDavid du Colombier '-', _flagfmt, 319a747e4fSDavid du Colombier 'C', _runefmt, 329a747e4fSDavid du Colombier 'E', _efgfmt, 339a747e4fSDavid du Colombier 'G', _efgfmt, 349a747e4fSDavid du Colombier 'S', _runesfmt, 359a747e4fSDavid du Colombier 'X', _ifmt, 369a747e4fSDavid du Colombier 'b', _ifmt, 379a747e4fSDavid du Colombier 'c', _charfmt, 389a747e4fSDavid du Colombier 'd', _ifmt, 399a747e4fSDavid du Colombier 'e', _efgfmt, 409a747e4fSDavid du Colombier 'f', _efgfmt, 419a747e4fSDavid du Colombier 'g', _efgfmt, 429a747e4fSDavid du Colombier 'h', _flagfmt, 439a747e4fSDavid du Colombier 'l', _flagfmt, 449a747e4fSDavid du Colombier 'n', _countfmt, 459a747e4fSDavid du Colombier 'o', _ifmt, 469a747e4fSDavid du Colombier 'p', _ifmt, 479a747e4fSDavid du Colombier 'r', errfmt, 489a747e4fSDavid du Colombier 's', _strfmt, 499a747e4fSDavid du Colombier 'u', _flagfmt, 509a747e4fSDavid du Colombier 'x', _ifmt, 519a747e4fSDavid du Colombier 0, nil, 529a747e4fSDavid du Colombier }; 539a747e4fSDavid du Colombier 549a747e4fSDavid du Colombier int (*doquote)(int); 559a747e4fSDavid du Colombier 563ff48bf5SDavid du Colombier /* 573ff48bf5SDavid du Colombier * _fmtlock() must be set 583ff48bf5SDavid du Colombier */ 593ff48bf5SDavid du Colombier static int 603ff48bf5SDavid du Colombier _fmtinstall(int c, Fmts f) 619a747e4fSDavid du Colombier { 629a747e4fSDavid du Colombier Convfmt *p, *ep; 639a747e4fSDavid du Colombier 649a747e4fSDavid du Colombier if(c<=0 || c>=65536) 659a747e4fSDavid du Colombier return -1; 669a747e4fSDavid du Colombier if(!f) 679a747e4fSDavid du Colombier f = _badfmt; 689a747e4fSDavid du Colombier 699a747e4fSDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt]; 709a747e4fSDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++) 719a747e4fSDavid du Colombier if(p->c == c) 729a747e4fSDavid du Colombier break; 739a747e4fSDavid du Colombier 743ff48bf5SDavid du Colombier if(p == &fmtalloc.fmt[Maxfmt]) 759a747e4fSDavid du Colombier return -1; 769a747e4fSDavid du Colombier 779a747e4fSDavid du Colombier p->fmt = f; 789a747e4fSDavid du Colombier if(p == ep){ /* installing a new format character */ 799a747e4fSDavid du Colombier fmtalloc.nfmt++; 809a747e4fSDavid du Colombier p->c = c; 819a747e4fSDavid du Colombier } 829a747e4fSDavid du Colombier 839a747e4fSDavid du Colombier return 0; 849a747e4fSDavid du Colombier } 859a747e4fSDavid du Colombier 863ff48bf5SDavid du Colombier int 873ff48bf5SDavid du Colombier fmtinstall(int c, Fmts f) 883ff48bf5SDavid du Colombier { 893ff48bf5SDavid du Colombier int ret; 903ff48bf5SDavid du Colombier 913ff48bf5SDavid du Colombier _fmtlock(); 923ff48bf5SDavid du Colombier ret = _fmtinstall(c, f); 933ff48bf5SDavid du Colombier _fmtunlock(); 943ff48bf5SDavid du Colombier return ret; 953ff48bf5SDavid du Colombier } 963ff48bf5SDavid du Colombier 973ff48bf5SDavid du Colombier static Fmts 983ff48bf5SDavid du Colombier fmtfmt(int c) 993ff48bf5SDavid du Colombier { 1003ff48bf5SDavid du Colombier Convfmt *p, *ep; 1013ff48bf5SDavid du Colombier 1023ff48bf5SDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt]; 1033ff48bf5SDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++) 1043ff48bf5SDavid du Colombier if(p->c == c){ 1053ff48bf5SDavid du Colombier while(p->fmt == nil) /* loop until value is updated */ 1063ff48bf5SDavid du Colombier ; 1073ff48bf5SDavid du Colombier return p->fmt; 1083ff48bf5SDavid du Colombier } 1093ff48bf5SDavid du Colombier 1103ff48bf5SDavid du Colombier /* is this a predefined format char? */ 1113ff48bf5SDavid du Colombier _fmtlock(); 1123ff48bf5SDavid du Colombier for(p=knownfmt; p->c; p++) 1133ff48bf5SDavid du Colombier if(p->c == c){ 1143ff48bf5SDavid du Colombier _fmtinstall(p->c, p->fmt); 1153ff48bf5SDavid du Colombier _fmtunlock(); 1163ff48bf5SDavid du Colombier return p->fmt; 1173ff48bf5SDavid du Colombier } 1183ff48bf5SDavid du Colombier _fmtunlock(); 1193ff48bf5SDavid du Colombier 1203ff48bf5SDavid du Colombier return _badfmt; 1213ff48bf5SDavid du Colombier } 1223ff48bf5SDavid du Colombier 1239a747e4fSDavid du Colombier void* 1249a747e4fSDavid du Colombier _fmtdispatch(Fmt *f, void *fmt, int isrunes) 1259a747e4fSDavid du Colombier { 1269a747e4fSDavid du Colombier Rune rune, r; 1279a747e4fSDavid du Colombier int i, n; 1289a747e4fSDavid du Colombier 1299a747e4fSDavid du Colombier f->flags = 0; 1309a747e4fSDavid du Colombier f->width = f->prec = 0; 1319a747e4fSDavid du Colombier 1329a747e4fSDavid du Colombier for(;;){ 1339a747e4fSDavid du Colombier if(isrunes){ 1349a747e4fSDavid du Colombier r = *(Rune*)fmt; 1359a747e4fSDavid du Colombier fmt = (Rune*)fmt + 1; 1369a747e4fSDavid du Colombier }else{ 1379a747e4fSDavid du Colombier fmt = (char*)fmt + chartorune(&rune, fmt); 1389a747e4fSDavid du Colombier r = rune; 1399a747e4fSDavid du Colombier } 1409a747e4fSDavid du Colombier f->r = r; 1419a747e4fSDavid du Colombier switch(r){ 1429a747e4fSDavid du Colombier case '\0': 1439a747e4fSDavid du Colombier return nil; 1449a747e4fSDavid du Colombier case '.': 1459a747e4fSDavid du Colombier f->flags |= FmtWidth|FmtPrec; 1469a747e4fSDavid du Colombier continue; 1479a747e4fSDavid du Colombier case '0': 1489a747e4fSDavid du Colombier if(!(f->flags & FmtWidth)){ 1499a747e4fSDavid du Colombier f->flags |= FmtZero; 1509a747e4fSDavid du Colombier continue; 1519a747e4fSDavid du Colombier } 1529a747e4fSDavid du Colombier /* fall through */ 1539a747e4fSDavid du Colombier case '1': case '2': case '3': case '4': 1549a747e4fSDavid du Colombier case '5': case '6': case '7': case '8': case '9': 1559a747e4fSDavid du Colombier i = 0; 1569a747e4fSDavid du Colombier while(r >= '0' && r <= '9'){ 1579a747e4fSDavid du Colombier i = i * 10 + r - '0'; 1589a747e4fSDavid du Colombier if(isrunes){ 1599a747e4fSDavid du Colombier r = *(Rune*)fmt; 1609a747e4fSDavid du Colombier fmt = (Rune*)fmt + 1; 1619a747e4fSDavid du Colombier }else{ 1629a747e4fSDavid du Colombier r = *(char*)fmt; 1639a747e4fSDavid du Colombier fmt = (char*)fmt + 1; 1649a747e4fSDavid du Colombier } 1659a747e4fSDavid du Colombier } 1669a747e4fSDavid du Colombier if(isrunes) 1679a747e4fSDavid du Colombier fmt = (Rune*)fmt - 1; 1689a747e4fSDavid du Colombier else 1699a747e4fSDavid du Colombier fmt = (char*)fmt - 1; 1709a747e4fSDavid du Colombier numflag: 1719a747e4fSDavid du Colombier if(f->flags & FmtWidth){ 1729a747e4fSDavid du Colombier f->flags |= FmtPrec; 1739a747e4fSDavid du Colombier f->prec = i; 1749a747e4fSDavid du Colombier }else{ 1759a747e4fSDavid du Colombier f->flags |= FmtWidth; 1769a747e4fSDavid du Colombier f->width = i; 1779a747e4fSDavid du Colombier } 1789a747e4fSDavid du Colombier continue; 1799a747e4fSDavid du Colombier case '*': 1809a747e4fSDavid du Colombier i = va_arg(f->args, int); 1819a747e4fSDavid du Colombier if(i < 0){ 182*a0ef1dc2SDavid du Colombier /* 183*a0ef1dc2SDavid du Colombier * negative precision => 184*a0ef1dc2SDavid du Colombier * ignore the precision. 185*a0ef1dc2SDavid du Colombier */ 186*a0ef1dc2SDavid du Colombier if(f->flags & FmtPrec){ 187*a0ef1dc2SDavid du Colombier f->flags &= ~FmtPrec; 188*a0ef1dc2SDavid du Colombier f->prec = 0; 189*a0ef1dc2SDavid du Colombier continue; 190*a0ef1dc2SDavid du Colombier } 1919a747e4fSDavid du Colombier i = -i; 1929a747e4fSDavid du Colombier f->flags |= FmtLeft; 1939a747e4fSDavid du Colombier } 1949a747e4fSDavid du Colombier goto numflag; 1959a747e4fSDavid du Colombier } 1969a747e4fSDavid du Colombier n = (*fmtfmt(r))(f); 1979a747e4fSDavid du Colombier if(n < 0) 1989a747e4fSDavid du Colombier return nil; 1999a747e4fSDavid du Colombier if(n == 0) 2009a747e4fSDavid du Colombier return fmt; 2019a747e4fSDavid du Colombier } 2029a747e4fSDavid du Colombier } 203