18ccd4a63SDavid du Colombier #include <u.h>
28ccd4a63SDavid du Colombier #include <libc.h>
38ccd4a63SDavid du Colombier #include "fmtdef.h"
48ccd4a63SDavid du Colombier
58ccd4a63SDavid du Colombier enum
68ccd4a63SDavid du Colombier {
78ccd4a63SDavid du Colombier Maxfmt = 64
88ccd4a63SDavid du Colombier };
98ccd4a63SDavid du Colombier
108ccd4a63SDavid du Colombier typedef struct Convfmt Convfmt;
118ccd4a63SDavid du Colombier struct Convfmt
128ccd4a63SDavid du Colombier {
138ccd4a63SDavid du Colombier int c;
148ccd4a63SDavid du Colombier volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
158ccd4a63SDavid du Colombier };
168ccd4a63SDavid du Colombier
178ccd4a63SDavid du Colombier struct
188ccd4a63SDavid du Colombier {
190d601874SDavid du Colombier /* lock by calling __fmtlock, __fmtunlock */
208ccd4a63SDavid du Colombier int nfmt;
218ccd4a63SDavid du Colombier Convfmt fmt[Maxfmt];
228ccd4a63SDavid du Colombier } fmtalloc;
238ccd4a63SDavid du Colombier
248ccd4a63SDavid du Colombier static Convfmt knownfmt[] = {
250d601874SDavid du Colombier ' ', __flagfmt,
260d601874SDavid du Colombier '#', __flagfmt,
270d601874SDavid du Colombier '%', __percentfmt,
280d601874SDavid du Colombier '+', __flagfmt,
290d601874SDavid du Colombier ',', __flagfmt,
300d601874SDavid du Colombier '-', __flagfmt,
310d601874SDavid du Colombier 'C', __runefmt, /* Plan 9 addition */
320d601874SDavid du Colombier 'E', __efgfmt,
330d601874SDavid du Colombier #ifndef PLAN9PORT
340d601874SDavid du Colombier 'F', __efgfmt, /* ANSI only */
350d601874SDavid du Colombier #endif
360d601874SDavid du Colombier 'G', __efgfmt,
370d601874SDavid du Colombier #ifndef PLAN9PORT
380d601874SDavid du Colombier 'L', __flagfmt, /* ANSI only */
390d601874SDavid du Colombier #endif
400d601874SDavid du Colombier 'S', __runesfmt, /* Plan 9 addition */
410d601874SDavid du Colombier 'X', __ifmt,
420d601874SDavid du Colombier 'b', __ifmt, /* Plan 9 addition */
430d601874SDavid du Colombier 'c', __charfmt,
440d601874SDavid du Colombier 'd', __ifmt,
450d601874SDavid du Colombier 'e', __efgfmt,
460d601874SDavid du Colombier 'f', __efgfmt,
470d601874SDavid du Colombier 'g', __efgfmt,
480d601874SDavid du Colombier 'h', __flagfmt,
490d601874SDavid du Colombier #ifndef PLAN9PORT
500d601874SDavid du Colombier 'i', __ifmt, /* ANSI only */
510d601874SDavid du Colombier #endif
520d601874SDavid du Colombier 'l', __flagfmt,
530d601874SDavid du Colombier 'n', __countfmt,
540d601874SDavid du Colombier 'o', __ifmt,
550d601874SDavid du Colombier 'p', __ifmt,
560d601874SDavid du Colombier 'r', __errfmt,
570d601874SDavid du Colombier 's', __strfmt,
580d601874SDavid du Colombier #ifdef PLAN9PORT
590d601874SDavid du Colombier 'u', __flagfmt,
600d601874SDavid du Colombier #else
610d601874SDavid du Colombier 'u', __ifmt,
620d601874SDavid du Colombier #endif
630d601874SDavid du Colombier 'x', __ifmt,
64*ec59a3ddSDavid du Colombier 0, 0,
658ccd4a63SDavid du Colombier };
668ccd4a63SDavid du Colombier
670d601874SDavid du Colombier
680d601874SDavid du Colombier int (*fmtdoquote)(int);
698ccd4a63SDavid du Colombier
708ccd4a63SDavid du Colombier /*
710d601874SDavid du Colombier * __fmtlock() must be set
728ccd4a63SDavid du Colombier */
738ccd4a63SDavid du Colombier static int
__fmtinstall(int c,Fmts f)740d601874SDavid du Colombier __fmtinstall(int c, Fmts f)
758ccd4a63SDavid du Colombier {
768ccd4a63SDavid du Colombier Convfmt *p, *ep;
778ccd4a63SDavid du Colombier
788ccd4a63SDavid du Colombier if(c<=0 || c>=65536)
798ccd4a63SDavid du Colombier return -1;
808ccd4a63SDavid du Colombier if(!f)
810d601874SDavid du Colombier f = __badfmt;
828ccd4a63SDavid du Colombier
838ccd4a63SDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt];
848ccd4a63SDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++)
858ccd4a63SDavid du Colombier if(p->c == c)
868ccd4a63SDavid du Colombier break;
878ccd4a63SDavid du Colombier
888ccd4a63SDavid du Colombier if(p == &fmtalloc.fmt[Maxfmt])
898ccd4a63SDavid du Colombier return -1;
908ccd4a63SDavid du Colombier
918ccd4a63SDavid du Colombier p->fmt = f;
928ccd4a63SDavid du Colombier if(p == ep){ /* installing a new format character */
938ccd4a63SDavid du Colombier fmtalloc.nfmt++;
948ccd4a63SDavid du Colombier p->c = c;
958ccd4a63SDavid du Colombier }
968ccd4a63SDavid du Colombier
978ccd4a63SDavid du Colombier return 0;
988ccd4a63SDavid du Colombier }
998ccd4a63SDavid du Colombier
1008ccd4a63SDavid du Colombier int
fmtinstall(int c,int (* f)(Fmt *))1010d601874SDavid du Colombier fmtinstall(int c, int (*f)(Fmt*))
1028ccd4a63SDavid du Colombier {
1038ccd4a63SDavid du Colombier int ret;
1048ccd4a63SDavid du Colombier
1050d601874SDavid du Colombier __fmtlock();
1060d601874SDavid du Colombier ret = __fmtinstall(c, f);
1070d601874SDavid du Colombier __fmtunlock();
1088ccd4a63SDavid du Colombier return ret;
1098ccd4a63SDavid du Colombier }
1108ccd4a63SDavid du Colombier
1118ccd4a63SDavid du Colombier static Fmts
fmtfmt(int c)1128ccd4a63SDavid du Colombier fmtfmt(int c)
1138ccd4a63SDavid du Colombier {
1148ccd4a63SDavid du Colombier Convfmt *p, *ep;
1158ccd4a63SDavid du Colombier
1168ccd4a63SDavid du Colombier ep = &fmtalloc.fmt[fmtalloc.nfmt];
1178ccd4a63SDavid du Colombier for(p=fmtalloc.fmt; p<ep; p++)
1188ccd4a63SDavid du Colombier if(p->c == c){
119*ec59a3ddSDavid du Colombier while(p->fmt == 0) /* loop until value is updated */
1208ccd4a63SDavid du Colombier ;
1218ccd4a63SDavid du Colombier return p->fmt;
1228ccd4a63SDavid du Colombier }
1238ccd4a63SDavid du Colombier
1248ccd4a63SDavid du Colombier /* is this a predefined format char? */
1250d601874SDavid du Colombier __fmtlock();
1268ccd4a63SDavid du Colombier for(p=knownfmt; p->c; p++)
1278ccd4a63SDavid du Colombier if(p->c == c){
1280d601874SDavid du Colombier __fmtinstall(p->c, p->fmt);
1290d601874SDavid du Colombier __fmtunlock();
1308ccd4a63SDavid du Colombier return p->fmt;
1318ccd4a63SDavid du Colombier }
1320d601874SDavid du Colombier __fmtunlock();
1338ccd4a63SDavid du Colombier
1340d601874SDavid du Colombier return __badfmt;
1358ccd4a63SDavid du Colombier }
1368ccd4a63SDavid du Colombier
1378ccd4a63SDavid du Colombier void*
__fmtdispatch(Fmt * f,void * fmt,int isrunes)1380d601874SDavid du Colombier __fmtdispatch(Fmt *f, void *fmt, int isrunes)
1398ccd4a63SDavid du Colombier {
1408ccd4a63SDavid du Colombier Rune rune, r;
1418ccd4a63SDavid du Colombier int i, n;
1428ccd4a63SDavid du Colombier
1438ccd4a63SDavid du Colombier f->flags = 0;
1448ccd4a63SDavid du Colombier f->width = f->prec = 0;
1458ccd4a63SDavid du Colombier
1468ccd4a63SDavid du Colombier for(;;){
1478ccd4a63SDavid du Colombier if(isrunes){
1488ccd4a63SDavid du Colombier r = *(Rune*)fmt;
1498ccd4a63SDavid du Colombier fmt = (Rune*)fmt + 1;
1508ccd4a63SDavid du Colombier }else{
1510d601874SDavid du Colombier fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
1528ccd4a63SDavid du Colombier r = rune;
1538ccd4a63SDavid du Colombier }
1548ccd4a63SDavid du Colombier f->r = r;
1558ccd4a63SDavid du Colombier switch(r){
1568ccd4a63SDavid du Colombier case '\0':
1578ccd4a63SDavid du Colombier return nil;
1588ccd4a63SDavid du Colombier case '.':
1598ccd4a63SDavid du Colombier f->flags |= FmtWidth|FmtPrec;
1608ccd4a63SDavid du Colombier continue;
1618ccd4a63SDavid du Colombier case '0':
1628ccd4a63SDavid du Colombier if(!(f->flags & FmtWidth)){
1638ccd4a63SDavid du Colombier f->flags |= FmtZero;
1648ccd4a63SDavid du Colombier continue;
1658ccd4a63SDavid du Colombier }
1668ccd4a63SDavid du Colombier /* fall through */
1678ccd4a63SDavid du Colombier case '1': case '2': case '3': case '4':
1688ccd4a63SDavid du Colombier case '5': case '6': case '7': case '8': case '9':
1698ccd4a63SDavid du Colombier i = 0;
1708ccd4a63SDavid du Colombier while(r >= '0' && r <= '9'){
1718ccd4a63SDavid du Colombier i = i * 10 + r - '0';
1728ccd4a63SDavid du Colombier if(isrunes){
1738ccd4a63SDavid du Colombier r = *(Rune*)fmt;
1748ccd4a63SDavid du Colombier fmt = (Rune*)fmt + 1;
1758ccd4a63SDavid du Colombier }else{
1768ccd4a63SDavid du Colombier r = *(char*)fmt;
1778ccd4a63SDavid du Colombier fmt = (char*)fmt + 1;
1788ccd4a63SDavid du Colombier }
1798ccd4a63SDavid du Colombier }
1808ccd4a63SDavid du Colombier if(isrunes)
1818ccd4a63SDavid du Colombier fmt = (Rune*)fmt - 1;
1828ccd4a63SDavid du Colombier else
1838ccd4a63SDavid du Colombier fmt = (char*)fmt - 1;
1848ccd4a63SDavid du Colombier numflag:
1858ccd4a63SDavid du Colombier if(f->flags & FmtWidth){
1868ccd4a63SDavid du Colombier f->flags |= FmtPrec;
1878ccd4a63SDavid du Colombier f->prec = i;
1888ccd4a63SDavid du Colombier }else{
1898ccd4a63SDavid du Colombier f->flags |= FmtWidth;
1908ccd4a63SDavid du Colombier f->width = i;
1918ccd4a63SDavid du Colombier }
1928ccd4a63SDavid du Colombier continue;
1938ccd4a63SDavid du Colombier case '*':
1948ccd4a63SDavid du Colombier i = va_arg(f->args, int);
1958ccd4a63SDavid du Colombier if(i < 0){
1960d601874SDavid du Colombier /*
1970d601874SDavid du Colombier * negative precision =>
1980d601874SDavid du Colombier * ignore the precision.
1990d601874SDavid du Colombier */
2000d601874SDavid du Colombier if(f->flags & FmtPrec){
2010d601874SDavid du Colombier f->flags &= ~FmtPrec;
2020d601874SDavid du Colombier f->prec = 0;
2030d601874SDavid du Colombier continue;
2040d601874SDavid du Colombier }
2058ccd4a63SDavid du Colombier i = -i;
2068ccd4a63SDavid du Colombier f->flags |= FmtLeft;
2078ccd4a63SDavid du Colombier }
2088ccd4a63SDavid du Colombier goto numflag;
2098ccd4a63SDavid du Colombier }
2108ccd4a63SDavid du Colombier n = (*fmtfmt(r))(f);
2118ccd4a63SDavid du Colombier if(n < 0)
2128ccd4a63SDavid du Colombier return nil;
2138ccd4a63SDavid du Colombier if(n == 0)
2148ccd4a63SDavid du Colombier return fmt;
2158ccd4a63SDavid du Colombier }
2168ccd4a63SDavid du Colombier }
217