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