Chameleon

Chameleon Svn Source Tree

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

Source at commit 1406 created 12 years 10 months ago.
By meklort, Revert drivers.c so that kexts are only loaded when OSBundleRequired is set and that value is not safe mode. Added some comments about it too.
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: 1406