Blame


1 85231fd8 2006-05-21 devnull /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2 91c13e54 2004-02-29 devnull #include <stdarg.h>
3 91c13e54 2004-02-29 devnull #include <string.h>
4 c3c9c7b6 2020-05-08 rsc
5 c3c9c7b6 2020-05-08 rsc /*
6 c3c9c7b6 2020-05-08 rsc * As of 2020, older systems like RHEL 6 and AIX still do not have C11 atomics.
7 c3c9c7b6 2020-05-08 rsc * On those systems, make the code use volatile int accesses and hope for the best.
8 c3c9c7b6 2020-05-08 rsc * (Most uses of fmtinstall are not actually racing with calls to print that lookup
9 c3c9c7b6 2020-05-08 rsc * formats. The code used volatile here for years without too many problems,
10 c3c9c7b6 2020-05-08 rsc * even though that's technically racy. A mutex is not OK, because we want to
11 c3c9c7b6 2020-05-08 rsc * be able to call print from signal handlers.)
12 c3c9c7b6 2020-05-08 rsc *
13 bd6f1206 2020-05-08 crossd * RHEL is using an old GCC (atomics were added in GCC 4.9).
14 c3c9c7b6 2020-05-08 rsc * AIX is using its own IBM compiler (XL C).
15 c3c9c7b6 2020-05-08 rsc */
16 bd6f1206 2020-05-08 crossd #if __IBMC__ || !__clang__ && __GNUC__ && (__GNUC__ < 4 || (__GNUC__==4 && __GNUC_MINOR__<9))
17 c3c9c7b6 2020-05-08 rsc #warning not using C11 stdatomic on legacy system
18 c3c9c7b6 2020-05-08 rsc #define _Atomic volatile
19 c3c9c7b6 2020-05-08 rsc #define atomic_load(x) (*(x))
20 c3c9c7b6 2020-05-08 rsc #define atomic_store(x, y) (*(x)=(y))
21 c3c9c7b6 2020-05-08 rsc #define ATOMIC_VAR_INIT(x) (x)
22 c3c9c7b6 2020-05-08 rsc #else
23 9505cd15 2020-01-14 rsc #include <stdatomic.h>
24 c3c9c7b6 2020-05-08 rsc #endif
25 c3c9c7b6 2020-05-08 rsc
26 e5aa96ac 2004-12-26 devnull #include "plan9.h"
27 91c13e54 2004-02-29 devnull #include "fmt.h"
28 91c13e54 2004-02-29 devnull #include "fmtdef.h"
29 91c13e54 2004-02-29 devnull
30 91c13e54 2004-02-29 devnull enum
31 91c13e54 2004-02-29 devnull {
32 9505cd15 2020-01-14 rsc Maxfmt = 128
33 91c13e54 2004-02-29 devnull };
34 91c13e54 2004-02-29 devnull
35 91c13e54 2004-02-29 devnull typedef struct Convfmt Convfmt;
36 91c13e54 2004-02-29 devnull struct Convfmt
37 91c13e54 2004-02-29 devnull {
38 91c13e54 2004-02-29 devnull int c;
39 9505cd15 2020-01-14 rsc Fmts fmt;
40 91c13e54 2004-02-29 devnull };
41 91c13e54 2004-02-29 devnull
42 85231fd8 2006-05-21 devnull static struct
43 91c13e54 2004-02-29 devnull {
44 9505cd15 2020-01-14 rsc /*
45 9505cd15 2020-01-14 rsc * lock updates to fmt by calling __fmtlock, __fmtunlock.
46 9505cd15 2020-01-14 rsc * reads can start at nfmt and work backward without
47 9505cd15 2020-01-14 rsc * further locking. later fmtinstalls take priority over earlier
48 9505cd15 2020-01-14 rsc * ones because of the backwards loop.
49 9505cd15 2020-01-14 rsc * once installed, a format is never overwritten.
50 9505cd15 2020-01-14 rsc */
51 9505cd15 2020-01-14 rsc _Atomic int nfmt;
52 91c13e54 2004-02-29 devnull Convfmt fmt[Maxfmt];
53 9505cd15 2020-01-14 rsc } fmtalloc = {
54 9505cd15 2020-01-14 rsc #ifdef PLAN9PORT
55 9505cd15 2020-01-14 rsc ATOMIC_VAR_INIT(27),
56 9505cd15 2020-01-14 rsc #else
57 9505cd15 2020-01-14 rsc ATOMIC_VAR_INIT(30),
58 9505cd15 2020-01-14 rsc #endif
59 9505cd15 2020-01-14 rsc {
60 9505cd15 2020-01-14 rsc {' ', __flagfmt},
61 9505cd15 2020-01-14 rsc {'#', __flagfmt},
62 9505cd15 2020-01-14 rsc {'%', __percentfmt},
63 9505cd15 2020-01-14 rsc {'\'', __flagfmt},
64 9505cd15 2020-01-14 rsc {'+', __flagfmt},
65 9505cd15 2020-01-14 rsc {',', __flagfmt},
66 9505cd15 2020-01-14 rsc {'-', __flagfmt},
67 9505cd15 2020-01-14 rsc {'C', __runefmt}, /* Plan 9 addition */
68 9505cd15 2020-01-14 rsc {'E', __efgfmt},
69 9505cd15 2020-01-14 rsc #ifndef PLAN9PORT
70 9505cd15 2020-01-14 rsc {'F', __efgfmt}, /* ANSI only */
71 9505cd15 2020-01-14 rsc #endif
72 9505cd15 2020-01-14 rsc {'G', __efgfmt},
73 9505cd15 2020-01-14 rsc #ifndef PLAN9PORT
74 9505cd15 2020-01-14 rsc {'L', __flagfmt}, /* ANSI only */
75 9505cd15 2020-01-14 rsc #endif
76 9505cd15 2020-01-14 rsc {'S', __runesfmt}, /* Plan 9 addition */
77 9505cd15 2020-01-14 rsc {'X', __ifmt},
78 9505cd15 2020-01-14 rsc {'b', __ifmt}, /* Plan 9 addition */
79 9505cd15 2020-01-14 rsc {'c', __charfmt},
80 9505cd15 2020-01-14 rsc {'d', __ifmt},
81 9505cd15 2020-01-14 rsc {'e', __efgfmt},
82 9505cd15 2020-01-14 rsc {'f', __efgfmt},
83 9505cd15 2020-01-14 rsc {'g', __efgfmt},
84 9505cd15 2020-01-14 rsc {'h', __flagfmt},
85 9505cd15 2020-01-14 rsc #ifndef PLAN9PORT
86 9505cd15 2020-01-14 rsc {'i', __ifmt}, /* ANSI only */
87 9505cd15 2020-01-14 rsc #endif
88 9505cd15 2020-01-14 rsc {'l', __flagfmt},
89 9505cd15 2020-01-14 rsc {'n', __countfmt},
90 9505cd15 2020-01-14 rsc {'o', __ifmt},
91 9505cd15 2020-01-14 rsc {'p', __ifmt},
92 9505cd15 2020-01-14 rsc {'r', __errfmt},
93 9505cd15 2020-01-14 rsc {'s', __strfmt},
94 9505cd15 2020-01-14 rsc #ifdef PLAN9PORT
95 9505cd15 2020-01-14 rsc {'u', __flagfmt},
96 9505cd15 2020-01-14 rsc #else
97 9505cd15 2020-01-14 rsc {'u', __ifmt},
98 9505cd15 2020-01-14 rsc #endif
99 9505cd15 2020-01-14 rsc {'x', __ifmt},
100 9505cd15 2020-01-14 rsc }
101 91c13e54 2004-02-29 devnull };
102 91c13e54 2004-02-29 devnull
103 91c13e54 2004-02-29 devnull int (*fmtdoquote)(int);
104 91c13e54 2004-02-29 devnull
105 91c13e54 2004-02-29 devnull /*
106 9505cd15 2020-01-14 rsc * __fmtlock() must be set
107 91c13e54 2004-02-29 devnull */
108 91c13e54 2004-02-29 devnull static int
109 91c13e54 2004-02-29 devnull __fmtinstall(int c, Fmts f)
110 91c13e54 2004-02-29 devnull {
111 9505cd15 2020-01-14 rsc Convfmt *p;
112 9505cd15 2020-01-14 rsc int i;
113 91c13e54 2004-02-29 devnull
114 91c13e54 2004-02-29 devnull if(c<=0 || c>=65536)
115 91c13e54 2004-02-29 devnull return -1;
116 91c13e54 2004-02-29 devnull if(!f)
117 91c13e54 2004-02-29 devnull f = __badfmt;
118 91c13e54 2004-02-29 devnull
119 9505cd15 2020-01-14 rsc i = atomic_load(&fmtalloc.nfmt);
120 9505cd15 2020-01-14 rsc if(i == Maxfmt)
121 91c13e54 2004-02-29 devnull return -1;
122 9505cd15 2020-01-14 rsc p = &fmtalloc.fmt[i];
123 9505cd15 2020-01-14 rsc p->c = c;
124 91c13e54 2004-02-29 devnull p->fmt = f;
125 9505cd15 2020-01-14 rsc atomic_store(&fmtalloc.nfmt, i+1);
126 91c13e54 2004-02-29 devnull
127 91c13e54 2004-02-29 devnull return 0;
128 91c13e54 2004-02-29 devnull }
129 91c13e54 2004-02-29 devnull
130 91c13e54 2004-02-29 devnull int
131 e5aa96ac 2004-12-26 devnull fmtinstall(int c, int (*f)(Fmt*))
132 91c13e54 2004-02-29 devnull {
133 91c13e54 2004-02-29 devnull int ret;
134 91c13e54 2004-02-29 devnull
135 9505cd15 2020-01-14 rsc __fmtlock();
136 91c13e54 2004-02-29 devnull ret = __fmtinstall(c, f);
137 9505cd15 2020-01-14 rsc __fmtunlock();
138 91c13e54 2004-02-29 devnull return ret;
139 91c13e54 2004-02-29 devnull }
140 91c13e54 2004-02-29 devnull
141 91c13e54 2004-02-29 devnull static Fmts
142 91c13e54 2004-02-29 devnull fmtfmt(int c)
143 91c13e54 2004-02-29 devnull {
144 9505cd15 2020-01-14 rsc Convfmt *p, *ep;
145 91c13e54 2004-02-29 devnull
146 9505cd15 2020-01-14 rsc ep = &fmtalloc.fmt[atomic_load(&fmtalloc.nfmt)];
147 9505cd15 2020-01-14 rsc for(p=ep; p-- > fmtalloc.fmt; )
148 9505cd15 2020-01-14 rsc if(p->c == c)
149 91c13e54 2004-02-29 devnull return p->fmt;
150 91c13e54 2004-02-29 devnull
151 91c13e54 2004-02-29 devnull return __badfmt;
152 91c13e54 2004-02-29 devnull }
153 91c13e54 2004-02-29 devnull
154 91c13e54 2004-02-29 devnull void*
155 91c13e54 2004-02-29 devnull __fmtdispatch(Fmt *f, void *fmt, int isrunes)
156 91c13e54 2004-02-29 devnull {
157 91c13e54 2004-02-29 devnull Rune rune, r;
158 91c13e54 2004-02-29 devnull int i, n;
159 91c13e54 2004-02-29 devnull
160 91c13e54 2004-02-29 devnull f->flags = 0;
161 91c13e54 2004-02-29 devnull f->width = f->prec = 0;
162 91c13e54 2004-02-29 devnull
163 91c13e54 2004-02-29 devnull for(;;){
164 91c13e54 2004-02-29 devnull if(isrunes){
165 91c13e54 2004-02-29 devnull r = *(Rune*)fmt;
166 91c13e54 2004-02-29 devnull fmt = (Rune*)fmt + 1;
167 91c13e54 2004-02-29 devnull }else{
168 91c13e54 2004-02-29 devnull fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
169 91c13e54 2004-02-29 devnull r = rune;
170 91c13e54 2004-02-29 devnull }
171 91c13e54 2004-02-29 devnull f->r = r;
172 91c13e54 2004-02-29 devnull switch(r){
173 91c13e54 2004-02-29 devnull case '\0':
174 91c13e54 2004-02-29 devnull return nil;
175 91c13e54 2004-02-29 devnull case '.':
176 91c13e54 2004-02-29 devnull f->flags |= FmtWidth|FmtPrec;
177 91c13e54 2004-02-29 devnull continue;
178 91c13e54 2004-02-29 devnull case '0':
179 91c13e54 2004-02-29 devnull if(!(f->flags & FmtWidth)){
180 91c13e54 2004-02-29 devnull f->flags |= FmtZero;
181 91c13e54 2004-02-29 devnull continue;
182 91c13e54 2004-02-29 devnull }
183 91c13e54 2004-02-29 devnull /* fall through */
184 91c13e54 2004-02-29 devnull case '1': case '2': case '3': case '4':
185 91c13e54 2004-02-29 devnull case '5': case '6': case '7': case '8': case '9':
186 91c13e54 2004-02-29 devnull i = 0;
187 91c13e54 2004-02-29 devnull while(r >= '0' && r <= '9'){
188 91c13e54 2004-02-29 devnull i = i * 10 + r - '0';
189 91c13e54 2004-02-29 devnull if(isrunes){
190 91c13e54 2004-02-29 devnull r = *(Rune*)fmt;
191 91c13e54 2004-02-29 devnull fmt = (Rune*)fmt + 1;
192 91c13e54 2004-02-29 devnull }else{
193 91c13e54 2004-02-29 devnull r = *(char*)fmt;
194 91c13e54 2004-02-29 devnull fmt = (char*)fmt + 1;
195 91c13e54 2004-02-29 devnull }
196 91c13e54 2004-02-29 devnull }
197 91c13e54 2004-02-29 devnull if(isrunes)
198 91c13e54 2004-02-29 devnull fmt = (Rune*)fmt - 1;
199 91c13e54 2004-02-29 devnull else
200 91c13e54 2004-02-29 devnull fmt = (char*)fmt - 1;
201 91c13e54 2004-02-29 devnull numflag:
202 91c13e54 2004-02-29 devnull if(f->flags & FmtWidth){
203 91c13e54 2004-02-29 devnull f->flags |= FmtPrec;
204 91c13e54 2004-02-29 devnull f->prec = i;
205 91c13e54 2004-02-29 devnull }else{
206 91c13e54 2004-02-29 devnull f->flags |= FmtWidth;
207 91c13e54 2004-02-29 devnull f->width = i;
208 91c13e54 2004-02-29 devnull }
209 91c13e54 2004-02-29 devnull continue;
210 91c13e54 2004-02-29 devnull case '*':
211 91c13e54 2004-02-29 devnull i = va_arg(f->args, int);
212 91c13e54 2004-02-29 devnull if(i < 0){
213 91c13e54 2004-02-29 devnull /*
214 91c13e54 2004-02-29 devnull * negative precision =>
215 91c13e54 2004-02-29 devnull * ignore the precision.
216 91c13e54 2004-02-29 devnull */
217 91c13e54 2004-02-29 devnull if(f->flags & FmtPrec){
218 91c13e54 2004-02-29 devnull f->flags &= ~FmtPrec;
219 91c13e54 2004-02-29 devnull f->prec = 0;
220 91c13e54 2004-02-29 devnull continue;
221 91c13e54 2004-02-29 devnull }
222 91c13e54 2004-02-29 devnull i = -i;
223 91c13e54 2004-02-29 devnull f->flags |= FmtLeft;
224 91c13e54 2004-02-29 devnull }
225 91c13e54 2004-02-29 devnull goto numflag;
226 91c13e54 2004-02-29 devnull }
227 91c13e54 2004-02-29 devnull n = (*fmtfmt(r))(f);
228 91c13e54 2004-02-29 devnull if(n < 0)
229 91c13e54 2004-02-29 devnull return nil;
230 91c13e54 2004-02-29 devnull if(n == 0)
231 91c13e54 2004-02-29 devnull return fmt;
232 91c13e54 2004-02-29 devnull }
233 91c13e54 2004-02-29 devnull }