]> git.lizzy.rs Git - plan9front.git/blob - sys/src/ape/lib/fmt/fmt.c
sdiahci, sdodin: avoid calling kproc() while holding ilock()
[plan9front.git] / sys / src / ape / lib / fmt / fmt.c
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 ANY
11  * 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 "utf.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         'C',    __runefmt,      /* Plan 9 addition */
47         'E',    __efgfmt,
48         'F',    __efgfmt,       /* ANSI only */
49         'G',    __efgfmt,
50         'L',    __flagfmt,      /* ANSI only */
51         'S',    __runesfmt,     /* Plan 9 addition */
52         'X',    __ifmt,
53         'b',    __ifmt,         /* Plan 9 addition */
54         'c',    __charfmt,
55         'd',    __ifmt,
56         'e',    __efgfmt,
57         'f',    __efgfmt,
58         'g',    __efgfmt,
59         'h',    __flagfmt,
60         'i',    __ifmt,         /* ANSI only */
61         'l',    __flagfmt,
62         'n',    __countfmt,
63         'o',    __ifmt,
64         'p',    __ifmt,
65         'r',    __errfmt,
66         's',    __strfmt,
67         'u',    __flagfmt,      /* in Unix, __ifmt */
68         'x',    __ifmt,
69         'z',    __flagfmt,
70         0,      nil,
71 };
72
73
74 int     (*fmtdoquote)(int);
75
76 /*
77  * __fmtlock() must be set
78  */
79 static int
80 __fmtinstall(int c, Fmts f)
81 {
82         Convfmt *p, *ep;
83
84         if(c<=0 || c>Runemax)
85                 return -1;
86         if(!f)
87                 f = __badfmt;
88
89         ep = &fmtalloc.fmt[fmtalloc.nfmt];
90         for(p=fmtalloc.fmt; p<ep; p++)
91                 if(p->c == c)
92                         break;
93
94         if(p == &fmtalloc.fmt[Maxfmt])
95                 return -1;
96
97         p->fmt = f;
98         if(p == ep){    /* installing a new format character */
99                 fmtalloc.nfmt++;
100                 p->c = c;
101         }
102
103         return 0;
104 }
105
106 int
107 fmtinstall(int c, Fmts f)
108 {
109         int ret;
110
111         __fmtlock();
112         ret = __fmtinstall(c, f);
113         __fmtunlock();
114         return ret;
115 }
116
117 static Fmts
118 fmtfmt(int c)
119 {
120         Convfmt *p, *ep;
121
122         ep = &fmtalloc.fmt[fmtalloc.nfmt];
123         for(p=fmtalloc.fmt; p<ep; p++)
124                 if(p->c == c){
125                         while(p->fmt == nil)    /* loop until value is updated */
126                                 ;
127                         return p->fmt;
128                 }
129
130         /* is this a predefined format char? */
131         __fmtlock();
132         for(p=knownfmt; p->c; p++)
133                 if(p->c == c){
134                         __fmtinstall(p->c, p->fmt);
135                         __fmtunlock();
136                         return p->fmt;
137                 }
138         __fmtunlock();
139
140         return __badfmt;
141 }
142
143 void*
144 __fmtdispatch(Fmt *f, void *fmt, int isrunes)
145 {
146         Rune rune, r;
147         int i, n;
148
149         f->flags = 0;
150         f->width = f->prec = 0;
151
152         for(;;){
153                 if(isrunes){
154                         r = *(Rune*)fmt;
155                         fmt = (Rune*)fmt + 1;
156                 }else{
157                         fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
158                         r = rune;
159                 }
160                 f->r = r;
161                 switch(r){
162                 case '\0':
163                         return nil;
164                 case '.':
165                         f->flags |= FmtWidth|FmtPrec;
166                         continue;
167                 case '0':
168                         if(!(f->flags & FmtWidth)){
169                                 f->flags |= FmtZero;
170                                 continue;
171                         }
172                         /* fall through */
173                 case '1': case '2': case '3': case '4':
174                 case '5': case '6': case '7': case '8': case '9':
175                         i = 0;
176                         while(r >= '0' && r <= '9'){
177                                 i = i * 10 + r - '0';
178                                 if(isrunes){
179                                         r = *(Rune*)fmt;
180                                         fmt = (Rune*)fmt + 1;
181                                 }else{
182                                         r = *(char*)fmt;
183                                         fmt = (char*)fmt + 1;
184                                 }
185                         }
186                         if(isrunes)
187                                 fmt = (Rune*)fmt - 1;
188                         else
189                                 fmt = (char*)fmt - 1;
190                 numflag:
191                         if(f->flags & FmtWidth){
192                                 f->flags |= FmtPrec;
193                                 f->prec = i;
194                         }else{
195                                 f->flags |= FmtWidth;
196                                 f->width = i;
197                         }
198                         continue;
199                 case '*':
200                         i = va_arg(f->args, int);
201                         if(i < 0){
202                                 /*
203                                  * negative precision =>
204                                  * ignore the precision.
205                                  */
206                                 if(f->flags & FmtPrec){
207                                         f->flags &= ~FmtPrec;
208                                         f->prec = 0;
209                                         continue;
210                                 }
211                                 i = -i;
212                                 f->flags |= FmtLeft;
213                         }
214                         goto numflag;
215                 }
216                 n = (*fmtfmt(r))(f);
217                 if(n < 0)
218                         return nil;
219                 if(n == 0)
220                         return fmt;
221         }
222 }