Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/modules/klibc/vsscanf.c

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

Archive Download this file

Revision: 1308