]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libc/fmt/fmt.c
etheriwl: don't break controller on command flush timeout
[plan9front.git] / sys / src / libc / fmt / fmt.c
1 #include <u.h>
2 #include <libc.h>
3 #include "fmtdef.h"
4
5 enum
6 {
7         Maxfmt = 64
8 };
9
10 typedef struct Convfmt Convfmt;
11 struct Convfmt
12 {
13         int     c;
14         volatile        Fmts    fmt;    /* for spin lock in fmtfmt; avoids race due to write order */
15 };
16
17 struct
18 {
19         /* lock by calling _fmtlock, _fmtunlock */
20         int     nfmt;
21         Convfmt fmt[Maxfmt];
22 } fmtalloc;
23
24 static Convfmt knownfmt[] = {
25         ' ',    _flagfmt,
26         '#',    _flagfmt,
27         '%',    _percentfmt,
28         '+',    _flagfmt,
29         ',',    _flagfmt,
30         '-',    _flagfmt,
31         'C',    _runefmt,
32         'E',    _efgfmt,
33         'G',    _efgfmt,
34         'S',    _runesfmt,
35         'X',    _ifmt,
36         'b',    _ifmt,
37         'c',    _charfmt,
38         'd',    _ifmt,
39         'e',    _efgfmt,
40         'f',    _efgfmt,
41         'g',    _efgfmt,
42         'h',    _flagfmt,
43         'l',    _flagfmt,
44         'n',    _countfmt,
45         'o',    _ifmt,
46         'p',    _ifmt,
47         'r',    errfmt,
48         's',    _strfmt,
49         'u',    _flagfmt,
50         'x',    _ifmt,
51         'z',    _flagfmt,
52         0,      nil,
53 };
54
55 int     (*doquote)(int);
56
57 /*
58  * _fmtlock() must be set
59  */
60 static int
61 _fmtinstall(int c, Fmts f)
62 {
63         Convfmt *p, *ep;
64
65         if(c<=0 || c>Runemax)
66                 return -1;
67         if(!f)
68                 f = _badfmt;
69
70         ep = &fmtalloc.fmt[fmtalloc.nfmt];
71         for(p=fmtalloc.fmt; p<ep; p++)
72                 if(p->c == c)
73                         break;
74
75         if(p == &fmtalloc.fmt[Maxfmt])
76                 return -1;
77
78         p->fmt = f;
79         if(p == ep){    /* installing a new format character */
80                 fmtalloc.nfmt++;
81                 p->c = c;
82         }
83
84         return 0;
85 }
86
87 int
88 fmtinstall(int c, Fmts f)
89 {
90         int ret;
91
92         _fmtlock();
93         ret = _fmtinstall(c, f);
94         _fmtunlock();
95         return ret;
96 }
97
98 static Fmts
99 fmtfmt(int c)
100 {
101         Convfmt *p, *ep;
102
103         ep = &fmtalloc.fmt[fmtalloc.nfmt];
104         for(p=fmtalloc.fmt; p<ep; p++)
105                 if(p->c == c){
106                         while(p->fmt == nil)    /* loop until value is updated */
107                                 ;
108                         return p->fmt;
109                 }
110
111         /* is this a predefined format char? */
112         _fmtlock();
113         for(p=knownfmt; p->c; p++)
114                 if(p->c == c){
115                         _fmtinstall(p->c, p->fmt);
116                         _fmtunlock();
117                         return p->fmt;
118                 }
119         _fmtunlock();
120
121         return _badfmt;
122 }
123
124 void*
125 _fmtdispatch(Fmt *f, void *fmt, int isrunes)
126 {
127         Rune rune, r;
128         int i, n;
129
130         f->flags = 0;
131         f->width = f->prec = 0;
132
133         for(;;){
134                 if(isrunes){
135                         r = *(Rune*)fmt;
136                         fmt = (Rune*)fmt + 1;
137                 }else{
138                         fmt = (char*)fmt + chartorune(&rune, fmt);
139                         r = rune;
140                 }
141                 f->r = r;
142                 switch(r){
143                 case '\0':
144                         return nil;
145                 case '.':
146                         f->flags |= FmtWidth|FmtPrec;
147                         continue;
148                 case '0':
149                         if(!(f->flags & FmtWidth)){
150                                 f->flags |= FmtZero;
151                                 continue;
152                         }
153                         /* fall through */
154                 case '1': case '2': case '3': case '4':
155                 case '5': case '6': case '7': case '8': case '9':
156                         i = 0;
157                         while(r >= '0' && r <= '9'){
158                                 i = i * 10 + r - '0';
159                                 if(isrunes){
160                                         r = *(Rune*)fmt;
161                                         fmt = (Rune*)fmt + 1;
162                                 }else{
163                                         r = *(char*)fmt;
164                                         fmt = (char*)fmt + 1;
165                                 }
166                         }
167                         if(isrunes)
168                                 fmt = (Rune*)fmt - 1;
169                         else
170                                 fmt = (char*)fmt - 1;
171                 numflag:
172                         if(f->flags & FmtWidth){
173                                 f->flags |= FmtPrec;
174                                 f->prec = i;
175                         }else{
176                                 f->flags |= FmtWidth;
177                                 f->width = i;
178                         }
179                         continue;
180                 case '*':
181                         i = va_arg(f->args, int);
182                         if(i < 0){
183                                 /*
184                                  * negative precision =>
185                                  * ignore the precision.
186                                  */
187                                 if(f->flags & FmtPrec){
188                                         f->flags &= ~FmtPrec;
189                                         f->prec = 0;
190                                         continue;
191                                 }
192                                 i = -i;
193                                 f->flags |= FmtLeft;
194                         }
195                         goto numflag;
196                 }
197                 n = (*fmtfmt(r))(f);
198                 if(n < 0)
199                         return nil;
200                 if(n == 0)
201                         return fmt;
202         }
203 }