Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/klibc/vsscanf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 8160 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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