Subversion Repositories planix.SVN

Rev

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

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