xref: /plan9/sys/src/cmd/unix/drawterm/libc/fmt.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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