Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1062