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
_fmtinstall(int c,Fmts f)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
fmtinstall(int c,Fmts f)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
fmtfmt(int c)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*
_fmtdispatch(Fmt * f,void * fmt,int isrunes)1249a747e4fSDavid du Colombier _fmtdispatch(Fmt *f, void *fmt, int isrunes)
1259a747e4fSDavid du Colombier {
1269a747e4fSDavid du Colombier Rune rune, r;
127*53ff6c4dSDavid du Colombier int i, n, w, p;
128*53ff6c4dSDavid du Colombier ulong fl;
129*53ff6c4dSDavid du Colombier void *ret;
130*53ff6c4dSDavid du Colombier
131*53ff6c4dSDavid du Colombier w = f->width;
132*53ff6c4dSDavid du Colombier p = f->prec;
133*53ff6c4dSDavid du Colombier fl = f->flags;
1349a747e4fSDavid du Colombier
1359a747e4fSDavid du Colombier f->flags = 0;
1369a747e4fSDavid du Colombier f->width = f->prec = 0;
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier for(;;){
1399a747e4fSDavid du Colombier if(isrunes){
1409a747e4fSDavid du Colombier r = *(Rune*)fmt;
1419a747e4fSDavid du Colombier fmt = (Rune*)fmt + 1;
1429a747e4fSDavid du Colombier }else{
1439a747e4fSDavid du Colombier fmt = (char*)fmt + chartorune(&rune, fmt);
1449a747e4fSDavid du Colombier r = rune;
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier f->r = r;
1479a747e4fSDavid du Colombier switch(r){
1489a747e4fSDavid du Colombier case '\0':
149*53ff6c4dSDavid du Colombier ret = nil;
150*53ff6c4dSDavid du Colombier goto end;
1519a747e4fSDavid du Colombier case '.':
1529a747e4fSDavid du Colombier f->flags |= FmtWidth|FmtPrec;
1539a747e4fSDavid du Colombier continue;
1549a747e4fSDavid du Colombier case '0':
1559a747e4fSDavid du Colombier if(!(f->flags & FmtWidth)){
1569a747e4fSDavid du Colombier f->flags |= FmtZero;
1579a747e4fSDavid du Colombier continue;
1589a747e4fSDavid du Colombier }
1599a747e4fSDavid du Colombier /* fall through */
1609a747e4fSDavid du Colombier case '1': case '2': case '3': case '4':
1619a747e4fSDavid du Colombier case '5': case '6': case '7': case '8': case '9':
1629a747e4fSDavid du Colombier i = 0;
1639a747e4fSDavid du Colombier while(r >= '0' && r <= '9'){
1649a747e4fSDavid du Colombier i = i * 10 + r - '0';
1659a747e4fSDavid du Colombier if(isrunes){
1669a747e4fSDavid du Colombier r = *(Rune*)fmt;
1679a747e4fSDavid du Colombier fmt = (Rune*)fmt + 1;
1689a747e4fSDavid du Colombier }else{
1699a747e4fSDavid du Colombier r = *(char*)fmt;
1709a747e4fSDavid du Colombier fmt = (char*)fmt + 1;
1719a747e4fSDavid du Colombier }
1729a747e4fSDavid du Colombier }
1739a747e4fSDavid du Colombier if(isrunes)
1749a747e4fSDavid du Colombier fmt = (Rune*)fmt - 1;
1759a747e4fSDavid du Colombier else
1769a747e4fSDavid du Colombier fmt = (char*)fmt - 1;
1779a747e4fSDavid du Colombier numflag:
1789a747e4fSDavid du Colombier if(f->flags & FmtWidth){
1799a747e4fSDavid du Colombier f->flags |= FmtPrec;
1809a747e4fSDavid du Colombier f->prec = i;
1819a747e4fSDavid du Colombier }else{
1829a747e4fSDavid du Colombier f->flags |= FmtWidth;
1839a747e4fSDavid du Colombier f->width = i;
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier continue;
1869a747e4fSDavid du Colombier case '*':
1879a747e4fSDavid du Colombier i = va_arg(f->args, int);
1889a747e4fSDavid du Colombier if(i < 0){
189a0ef1dc2SDavid du Colombier /*
190a0ef1dc2SDavid du Colombier * negative precision =>
191a0ef1dc2SDavid du Colombier * ignore the precision.
192a0ef1dc2SDavid du Colombier */
193a0ef1dc2SDavid du Colombier if(f->flags & FmtPrec){
194a0ef1dc2SDavid du Colombier f->flags &= ~FmtPrec;
195a0ef1dc2SDavid du Colombier f->prec = 0;
196a0ef1dc2SDavid du Colombier continue;
197a0ef1dc2SDavid du Colombier }
1989a747e4fSDavid du Colombier i = -i;
1999a747e4fSDavid du Colombier f->flags |= FmtLeft;
2009a747e4fSDavid du Colombier }
2019a747e4fSDavid du Colombier goto numflag;
2029a747e4fSDavid du Colombier }
2039a747e4fSDavid du Colombier n = (*fmtfmt(r))(f);
204*53ff6c4dSDavid du Colombier if(n < 0){
205*53ff6c4dSDavid du Colombier ret = nil;
206*53ff6c4dSDavid du Colombier break;
2079a747e4fSDavid du Colombier }
208*53ff6c4dSDavid du Colombier if(n == 0){
209*53ff6c4dSDavid du Colombier ret = fmt;
210*53ff6c4dSDavid du Colombier break;
211*53ff6c4dSDavid du Colombier }
212*53ff6c4dSDavid du Colombier }
213*53ff6c4dSDavid du Colombier end:
214*53ff6c4dSDavid du Colombier f->width = w;
215*53ff6c4dSDavid du Colombier f->prec = p;
216*53ff6c4dSDavid du Colombier f->flags = fl;
217*53ff6c4dSDavid du Colombier return ret;
2189a747e4fSDavid du Colombier }
219