wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

fmt.c (4054B)


      1 /*
      2  * The authors of this software are Rob Pike and Ken Thompson.
      3  *              Copyright (c) 2002 by Lucent Technologies.
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose without fee is hereby granted, provided that this entire notice
      6  * is included in all copies of any software which is or includes a copy
      7  * or modification of this software and in all copies of the supporting
      8  * documentation for such software.
      9  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
     10  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
     11  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
     12  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
     13  */
     14 #include <stdarg.h>
     15 #include <string.h>
     16 #include "plan9.h"
     17 #include "fmt.h"
     18 #include "fmtdef.h"
     19 
     20 enum
     21 {
     22 	Maxfmt = 64
     23 };
     24 
     25 typedef struct Convfmt Convfmt;
     26 struct Convfmt
     27 {
     28 	int	c;
     29 	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
     30 };
     31 
     32 struct
     33 {
     34 	/* lock by calling __fmtlock, __fmtunlock */
     35 	int	nfmt;
     36 	Convfmt	fmt[Maxfmt];
     37 } fmtalloc;
     38 
     39 static Convfmt knownfmt[] = {
     40 	' ',	__flagfmt,
     41 	'#',	__flagfmt,
     42 	'%',	__percentfmt,
     43 	'\'',	__flagfmt,
     44 	'+',	__flagfmt,
     45 	',',	__flagfmt,
     46 	'-',	__flagfmt,
     47 	'C',	__runefmt,	/* Plan 9 addition */
     48 	'E',	__efgfmt,
     49 	'G',	__efgfmt,
     50 	'S',	__runesfmt,	/* Plan 9 addition */
     51 	'X',	__ifmt,
     52 	'b',	__ifmt,		/* Plan 9 addition */
     53 	'c',	__charfmt,
     54 	'd',	__ifmt,
     55 	'e',	__efgfmt,
     56 	'f',	__efgfmt,
     57 	'g',	__efgfmt,
     58 	'h',	__flagfmt,
     59 	'l',	__flagfmt,
     60 	'n',	__countfmt,
     61 	'o',	__ifmt,
     62 	'p',	__ifmt,
     63 	'r',	__errfmt,
     64 	's',	__strfmt,
     65 	'u',	__flagfmt,
     66 	'x',	__ifmt,
     67 	0,	nil,
     68 };
     69 
     70 
     71 int	(*fmtdoquote)(int);
     72 
     73 /*
     74  * __fmtlock() must be set
     75  */
     76 static int
     77 __fmtinstall(int c, Fmts f)
     78 {
     79 	Convfmt *p, *ep;
     80 
     81 	if(c<=0 || c>=65536)
     82 		return -1;
     83 	if(!f)
     84 		f = __badfmt;
     85 
     86 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
     87 	for(p=fmtalloc.fmt; p<ep; p++)
     88 		if(p->c == c)
     89 			break;
     90 
     91 	if(p == &fmtalloc.fmt[Maxfmt])
     92 		return -1;
     93 
     94 	p->fmt = f;
     95 	if(p == ep){	/* installing a new format character */
     96 		fmtalloc.nfmt++;
     97 		p->c = c;
     98 	}
     99 
    100 	return 0;
    101 }
    102 
    103 int
    104 fmtinstall(int c, int (*f)(Fmt*))
    105 {
    106 	int ret;
    107 
    108 	__fmtlock();
    109 	ret = __fmtinstall(c, f);
    110 	__fmtunlock();
    111 	return ret;
    112 }
    113 
    114 static Fmts
    115 fmtfmt(int c)
    116 {
    117 	Convfmt *p, *ep;
    118 
    119 	ep = &fmtalloc.fmt[fmtalloc.nfmt];
    120 	for(p=fmtalloc.fmt; p<ep; p++)
    121 		if(p->c == c){
    122 			while(p->fmt == nil)	/* loop until value is updated */
    123 				;
    124 			return p->fmt;
    125 		}
    126 
    127 	/* is this a predefined format char? */
    128 	__fmtlock();
    129 	for(p=knownfmt; p->c; p++)
    130 		if(p->c == c){
    131 			__fmtinstall(p->c, p->fmt);
    132 			__fmtunlock();
    133 			return p->fmt;
    134 		}
    135 	__fmtunlock();
    136 
    137 	return __badfmt;
    138 }
    139 
    140 void*
    141 __fmtdispatch(Fmt *f, const void *fmt, int isrunes)
    142 {
    143 	Rune rune, r;
    144 	int i, n;
    145 
    146 	f->flags = 0;
    147 	f->width = f->prec = 0;
    148 
    149 	for(;;){
    150 		if(isrunes){
    151 			r = *(Rune*)fmt;
    152 			fmt = (Rune*)fmt + 1;
    153 		}else{
    154 			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
    155 			r = rune;
    156 		}
    157 		f->r = r;
    158 		switch(r){
    159 		case '\0':
    160 			return nil;
    161 		case '.':
    162 			f->flags |= FmtWidth|FmtPrec;
    163 			continue;
    164 		case '0':
    165 			if(!(f->flags & FmtWidth)){
    166 				f->flags |= FmtZero;
    167 				continue;
    168 			}
    169 			/* fall through */
    170 		case '1': case '2': case '3': case '4':
    171 		case '5': case '6': case '7': case '8': case '9':
    172 			i = 0;
    173 			while(r >= '0' && r <= '9'){
    174 				i = i * 10 + r - '0';
    175 				if(isrunes){
    176 					r = *(Rune*)fmt;
    177 					fmt = (Rune*)fmt + 1;
    178 				}else{
    179 					r = *(char*)fmt;
    180 					fmt = (char*)fmt + 1;
    181 				}
    182 			}
    183 			if(isrunes)
    184 				fmt = (Rune*)fmt - 1;
    185 			else
    186 				fmt = (char*)fmt - 1;
    187 		numflag:
    188 			if(f->flags & FmtWidth){
    189 				f->flags |= FmtPrec;
    190 				f->prec = i;
    191 			}else{
    192 				f->flags |= FmtWidth;
    193 				f->width = i;
    194 			}
    195 			continue;
    196 		case '*':
    197 			i = va_arg(f->args, int);
    198 			if(i < 0){
    199 				/*
    200 				 * negative precision =>
    201 				 * ignore the precision.
    202 				 */
    203 				if(f->flags & FmtPrec){
    204 					f->flags &= ~FmtPrec;
    205 					f->prec = 0;
    206 					continue;
    207 				}
    208 				i = -i;
    209 				f->flags |= FmtLeft;
    210 			}
    211 			goto numflag;
    212 		}
    213 		n = (*fmtfmt(r))(f);
    214 		if(n < 0)
    215 			return nil;
    216 		if(n == 0)
    217 			return (void*)fmt;
    218 	}
    219 }