Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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