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