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>
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.)
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).
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)
23 9505cd15 2020-01-14 rsc #include <stdatomic.h>
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"
35 91c13e54 2004-02-29 devnull typedef struct Convfmt Convfmt;
36 91c13e54 2004-02-29 devnull struct Convfmt
42 85231fd8 2006-05-21 devnull static struct
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.
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),
57 9505cd15 2020-01-14 rsc ATOMIC_VAR_INIT(30),
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 */
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 */
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 */
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},
97 9505cd15 2020-01-14 rsc {'u', __ifmt},
99 9505cd15 2020-01-14 rsc {'x', __ifmt},
103 91c13e54 2004-02-29 devnull int (*fmtdoquote)(int);
106 9505cd15 2020-01-14 rsc * __fmtlock() must be set
108 91c13e54 2004-02-29 devnull static int
109 91c13e54 2004-02-29 devnull __fmtinstall(int c, Fmts f)
114 91c13e54 2004-02-29 devnull if(c<=0 || c>=65536)
115 91c13e54 2004-02-29 devnull return -1;
117 91c13e54 2004-02-29 devnull f = __badfmt;
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];
124 91c13e54 2004-02-29 devnull p->fmt = f;
125 9505cd15 2020-01-14 rsc atomic_store(&fmtalloc.nfmt, i+1);
127 91c13e54 2004-02-29 devnull return 0;
131 e5aa96ac 2004-12-26 devnull fmtinstall(int c, int (*f)(Fmt*))
133 91c13e54 2004-02-29 devnull int ret;
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;
141 91c13e54 2004-02-29 devnull static Fmts
142 91c13e54 2004-02-29 devnull fmtfmt(int c)
144 9505cd15 2020-01-14 rsc Convfmt *p, *ep;
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;
151 91c13e54 2004-02-29 devnull return __badfmt;
155 91c13e54 2004-02-29 devnull __fmtdispatch(Fmt *f, void *fmt, int isrunes)
157 91c13e54 2004-02-29 devnull Rune rune, r;
158 91c13e54 2004-02-29 devnull int i, n;
160 91c13e54 2004-02-29 devnull f->flags = 0;
161 91c13e54 2004-02-29 devnull f->width = f->prec = 0;
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;
168 91c13e54 2004-02-29 devnull fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
169 91c13e54 2004-02-29 devnull r = rune;
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;
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':
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;
193 91c13e54 2004-02-29 devnull r = *(char*)fmt;
194 91c13e54 2004-02-29 devnull fmt = (char*)fmt + 1;
197 91c13e54 2004-02-29 devnull if(isrunes)
198 91c13e54 2004-02-29 devnull fmt = (Rune*)fmt - 1;
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;
206 91c13e54 2004-02-29 devnull f->flags |= FmtWidth;
207 91c13e54 2004-02-29 devnull f->width = i;
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){
214 91c13e54 2004-02-29 devnull * negative precision =>
215 91c13e54 2004-02-29 devnull * ignore the precision.
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;
223 91c13e54 2004-02-29 devnull f->flags |= FmtLeft;
225 91c13e54 2004-02-29 devnull goto numflag;
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;