Chameleon

Chameleon Svn Source Tree

Root/branches/Chimera/i386/modules/klibc/vsscanf.c

1/*
2 * vsscanf.c
3 *
4 * vsscanf(), from which the rest of the scanf()
5 * family is built
6 */
7
8#include "libsaio.h"
9#include "limits.h"
10extern uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n);
11
12#ifndef LONG_BIT
13#define LONG_BIT (CHAR_BIT*sizeof(long))
14#endif
15
16enum flags {
17FL_SPLAT = 0x01,/* Drop the value, do not assign */
18FL_INV = 0x02,/* Character-set with inverse */
19FL_WIDTH = 0x04,/* Field width specified */
20FL_MINUS = 0x08,/* Negative number */
21};
22
23enum ranks {
24rank_char = -2,
25rank_short = -1,
26rank_int = 0,
27rank_long = 1,
28rank_longlong = 2,
29rank_ptr = INT_MAX/* Special value used for pointers */
30};
31
32#define MIN_RANKrank_char
33#define MAX_RANKrank_longlong
34
35#define INTMAX_RANKrank_longlong
36#define SIZE_T_RANKrank_long
37#define PTRDIFF_T_RANKrank_long
38
39enum bail {
40bail_none = 0,/* No error condition */
41bail_eof,/* Hit EOF */
42bail_err/* Conversion mismatch */
43};
44
45static inline const char *skipspace(const char *p)
46{
47while (isspace((unsigned char)*p))
48p++;
49return p;
50}
51
52#undef set_bit
53static inline void set_bit(unsigned long *bitmap, unsigned int bit)
54{
55bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
56}
57
58#undef test_bit
59static inline int test_bit(unsigned long *bitmap, unsigned int bit)
60{
61return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;
62}
63
64int vsscanf(const char *buffer, const char *format, va_list ap)
65{
66const char *p = format;
67char ch;
68unsigned char uc;
69const char *q = buffer;
70const char *qq;
71uintmax_t val = 0;
72int rank = rank_int;/* Default rank */
73unsigned int width = UINT_MAX;
74int base;
75enum flags flags = 0;
76enum {
77st_normal,/* Ground state */
78st_flags,/* Special flags */
79st_width,/* Field width */
80st_modifiers,/* Length or conversion modifiers */
81st_match_init,/* Initial state of %[ sequence */
82st_match,/* Main state of %[ sequence */
83st_match_range,/* After - in a %[ sequence */
84} state = st_normal;
85char *sarg = NULL;/* %s %c or %[ string argument */
86enum bail bail = bail_none;
87int sign;
88int converted = 0;/* Successful conversions */
89unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
90int matchinv = 0;/* Is match map inverted? */
91unsigned char range_start = 0;
92
93while ((ch = *p++) && !bail) {
94switch (state) {
95case st_normal:
96if (ch == '%') {
97state = st_flags;
98flags = 0;
99rank = rank_int;
100width = UINT_MAX;
101} else if (isspace((unsigned char)ch)) {
102q = skipspace(q);
103} else {
104if (*q == ch)
105q++;
106else
107bail = bail_err; /* Match failure */
108}
109break;
110
111case st_flags:
112switch (ch) {
113case '*':
114flags |= FL_SPLAT;
115break;
116case '0'...'9':
117width = (ch - '0');
118state = st_width;
119flags |= FL_WIDTH;
120break;
121default:
122state = st_modifiers;
123p--;/* Process this character again */
124break;
125}
126break;
127
128case st_width:
129if (ch >= '0' && ch <= '9') {
130width = width * 10 + (ch - '0');
131} else {
132state = st_modifiers;
133p--;/* Process this character again */
134}
135break;
136
137case st_modifiers:
138switch (ch) {
139/* Length modifiers - nonterminal sequences */
140case 'h':
141rank--;/* Shorter rank */
142break;
143case 'l':
144rank++;/* Longer rank */
145break;
146case 'j':
147rank = INTMAX_RANK;
148break;
149case 'z':
150rank = SIZE_T_RANK;
151break;
152case 't':
153rank = PTRDIFF_T_RANK;
154break;
155case 'L':
156case 'q':
157rank = rank_longlong;/* long double/long long */
158break;
159
160default:
161/* Output modifiers - terminal sequences */
162/* Next state will be normal */
163state = st_normal;
164
165/* Canonicalize rank */
166if (rank < MIN_RANK)
167rank = MIN_RANK;
168else if (rank > MAX_RANK)
169rank = MAX_RANK;
170
171switch (ch) {
172case 'P':/* Upper case pointer */
173case 'p':/* Pointer */
174rank = rank_ptr;
175base = 0;
176sign = 0;
177goto scan_int;
178
179case 'i':/* Base-independent integer */
180base = 0;
181sign = 1;
182goto scan_int;
183
184case 'd':/* Decimal integer */
185base = 10;
186sign = 1;
187goto scan_int;
188
189case 'o':/* Octal integer */
190base = 8;
191sign = 0;
192goto scan_int;
193
194case 'u':/* Unsigned decimal integer */
195base = 10;
196sign = 0;
197goto scan_int;
198
199case 'x':/* Hexadecimal integer */
200case 'X':
201base = 16;
202sign = 0;
203goto scan_int;
204
205case 'n':/* # of characters consumed */
206val = (q - buffer);
207goto set_integer;
208
209 scan_int:
210q = skipspace(q);
211if (!*q) {
212bail = bail_eof;
213break;
214}
215val =
216 strntoumax(q, (char **)&qq, base,
217 width);
218if (qq == q) {
219bail = bail_err;
220break;
221}
222q = qq;
223if (!(flags & FL_SPLAT))
224converted++;
225/* fall through */
226
227 set_integer:
228if (!(flags & FL_SPLAT)) {
229switch (rank) {
230case rank_char:
231*va_arg(ap,
232unsigned char *)
233= val;
234break;
235case rank_short:
236*va_arg(ap,
237unsigned short
238*) = val;
239break;
240case rank_int:
241*va_arg(ap,
242unsigned int *)
243 = val;
244break;
245case rank_long:
246*va_arg(ap,
247unsigned long *)
248= val;
249break;
250case rank_longlong:
251*va_arg(ap,
252unsigned long
253long *) = val;
254break;
255case rank_ptr:
256*va_arg(ap, void **) =
257(void *)
258(uintptr_t)val;
259break;
260}
261}
262break;
263
264case 'c':/* Character */
265/* Default width == 1 */
266width = (flags & FL_WIDTH) ? width : 1;
267if (flags & FL_SPLAT) {
268while (width--) {
269if (!*q) {
270bail = bail_eof;
271break;
272}
273}
274} else {
275sarg = va_arg(ap, char *);
276while (width--) {
277if (!*q) {
278bail = bail_eof;
279break;
280}
281*sarg++ = *q++;
282}
283if (!bail)
284converted++;
285}
286break;
287
288case 's':/* String */
289uc = 1;/* Anything nonzero */
290if (flags & FL_SPLAT) {
291while (width-- && (uc = *q) &&
292 !isspace(uc)) {
293q++;
294}
295} else {
296char *sp;
297sp = sarg = va_arg(ap, char *);
298while (width-- && (uc = *q) &&
299 !isspace(uc)) {
300*sp++ = uc;
301q++;
302}
303if (sarg != sp) {
304/* Terminate output */
305*sp = '\0';
306converted++;
307}
308}
309if (!uc)
310bail = bail_eof;
311break;
312
313case '[':/* Character range */
314sarg = (flags & FL_SPLAT) ? NULL
315: va_arg(ap, char *);
316state = st_match_init;
317matchinv = 0;
318memset(matchmap, 0, sizeof matchmap);
319break;
320
321case '%':/* %% sequence */
322if (*q == '%')
323q++;
324else
325bail = bail_err;
326break;
327
328default:/* Anything else */
329/* Unknown sequence */
330bail = bail_err;
331break;
332}
333}
334break;
335
336case st_match_init:/* Initial state for %[ match */
337if (ch == '^' && !(flags & FL_INV)) {
338matchinv = 1;
339} else {
340set_bit(matchmap, (unsigned char)ch);
341state = st_match;
342}
343break;
344
345case st_match:/* Main state for %[ match */
346if (ch == ']') {
347goto match_run;
348} else if (ch == '-') {
349range_start = (unsigned char)ch;
350state = st_match_range;
351} else {
352set_bit(matchmap, (unsigned char)ch);
353}
354break;
355
356case st_match_range:/* %[ match after - */
357if (ch == ']') {
358/* - was last character */
359set_bit(matchmap, (unsigned char)'-');
360goto match_run;
361} else {
362int i;
363for (i = range_start; i < (unsigned char)ch;
364 i++)
365set_bit(matchmap, i);
366state = st_match;
367}
368break;
369
370 match_run:/* Match expression finished */
371qq = q;
372uc = 1;/* Anything nonzero */
373while (width && (uc = *q)
374 && test_bit(matchmap, uc)^matchinv) {
375if (sarg)
376*sarg++ = uc;
377q++;
378}
379if (q != qq && sarg) {
380*sarg = '\0';
381converted++;
382} else {
383bail = bail_err;
384}
385if (!uc)
386bail = bail_eof;
387break;
388}
389}
390
391if (bail == bail_eof && !converted)
392converted = -1;/* Return EOF (-1) */
393
394return converted;
395}
396

Archive Download this file

Revision: 850