Removed fork()
[meinos.git] / apps / lib / stdlibc / vsscanf.c
blob7af8d9cbbd4336f7a1bda6f44ca88200cb9884ab
1 /*
2 * vsscanf.c
4 * vsscanf(), from which the rest of the scanf()
5 * family is built
7 * Copyright (c)
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include <ctype.h>
40 #include <stdarg.h>
41 #include <stddef.h>
42 #include <inttypes.h>
43 #include <string.h>
44 #include <limits.h>
45 #include <stdio.h>
47 #ifndef LONG_BIT
48 #define LONG_BIT (CHAR_BIT*sizeof(long))
49 #endif
51 enum flags {
52 FL_SPLAT = 0x01, /* Drop the value, do not assign */
53 FL_INV = 0x02, /* Character-set with inverse */
54 FL_WIDTH = 0x04, /* Field width specified */
55 FL_MINUS = 0x08, /* Negative number */
58 enum ranks {
59 rank_char = -2,
60 rank_short = -1,
61 rank_int = 0,
62 rank_long = 1,
63 rank_longlong = 2,
64 rank_ptr = INT_MAX /* Special value used for pointers */
67 #define MIN_RANK rank_char
68 #define MAX_RANK rank_longlong
70 #define INTMAX_RANK rank_longlong
71 #define SIZE_T_RANK rank_long
72 #define PTRDIFF_T_RANK rank_long
74 enum bail {
75 bail_none = 0, /* No error condition */
76 bail_eof, /* Hit EOF */
77 bail_err /* Conversion mismatch */
80 static inline const char *skipspace(const char *p)
82 while (isspace((unsigned char)*p))
83 p++;
84 return p;
87 #undef set_bit
88 static inline void set_bit(unsigned long *bitmap, unsigned int bit)
90 bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
93 #undef test_bit
94 static inline int test_bit(unsigned long *bitmap, unsigned int bit)
96 return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;
99 int vsscanf(const char *buffer, const char *format, va_list ap)
101 const char *p = format;
102 char ch;
103 unsigned char uc;
104 const char *q = buffer;
105 const char *qq;
106 uintmax_t val = 0;
107 int rank = rank_int; /* Default rank */
108 unsigned int width = UINT_MAX;
109 int base;
110 enum flags flags = 0;
111 enum {
112 st_normal, /* Ground state */
113 st_flags, /* Special flags */
114 st_width, /* Field width */
115 st_modifiers, /* Length or conversion modifiers */
116 st_match_init, /* Initial state of %[ sequence */
117 st_match, /* Main state of %[ sequence */
118 st_match_range, /* After - in a %[ sequence */
119 } state = st_normal;
120 char *sarg = NULL; /* %s %c or %[ string argument */
121 enum bail bail = bail_none;
122 int sign;
123 int converted = 0; /* Successful conversions */
124 unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
125 int matchinv = 0; /* Is match map inverted? */
126 unsigned char range_start = 0;
128 while ((ch = *p++) && !bail) {
129 switch (state) {
130 case st_normal:
131 if (ch == '%') {
132 state = st_flags;
133 flags = 0;
134 rank = rank_int;
135 width = UINT_MAX;
136 } else if (isspace((unsigned char)ch)) {
137 q = skipspace(q);
138 } else {
139 if (*q == ch)
140 q++;
141 else
142 bail = bail_err; /* Match failure */
144 break;
146 case st_flags:
147 switch (ch) {
148 case '*':
149 flags |= FL_SPLAT;
150 break;
151 case '0'...'9':
152 width = (ch - '0');
153 state = st_width;
154 flags |= FL_WIDTH;
155 break;
156 default:
157 state = st_modifiers;
158 p--; /* Process this character again */
159 break;
161 break;
163 case st_width:
164 if (ch >= '0' && ch <= '9') {
165 width = width * 10 + (ch - '0');
166 } else {
167 state = st_modifiers;
168 p--; /* Process this character again */
170 break;
172 case st_modifiers:
173 switch (ch) {
174 /* Length modifiers - nonterminal sequences */
175 case 'h':
176 rank--; /* Shorter rank */
177 break;
178 case 'l':
179 rank++; /* Longer rank */
180 break;
181 case 'j':
182 rank = INTMAX_RANK;
183 break;
184 case 'z':
185 rank = SIZE_T_RANK;
186 break;
187 case 't':
188 rank = PTRDIFF_T_RANK;
189 break;
190 case 'L':
191 case 'q':
192 rank = rank_longlong; /* long double/long long */
193 break;
195 default:
196 /* Output modifiers - terminal sequences */
197 /* Next state will be normal */
198 state = st_normal;
200 /* Canonicalize rank */
201 if (rank < MIN_RANK)
202 rank = MIN_RANK;
203 else if (rank > MAX_RANK)
204 rank = MAX_RANK;
206 switch (ch) {
207 case 'P': /* Upper case pointer */
208 case 'p': /* Pointer */
209 rank = rank_ptr;
210 base = 0;
211 sign = 0;
212 goto scan_int;
214 case 'i': /* Base-independent integer */
215 base = 0;
216 sign = 1;
217 goto scan_int;
219 case 'd': /* Decimal integer */
220 base = 10;
221 sign = 1;
222 goto scan_int;
224 case 'o': /* Octal integer */
225 base = 8;
226 sign = 0;
227 goto scan_int;
229 case 'u': /* Unsigned decimal integer */
230 base = 10;
231 sign = 0;
232 goto scan_int;
234 case 'x': /* Hexadecimal integer */
235 case 'X':
236 base = 16;
237 sign = 0;
238 goto scan_int;
240 case 'n': /* # of characters consumed */
241 val = (q - buffer);
242 goto set_integer;
244 scan_int:
245 q = skipspace(q);
246 if (!*q) {
247 bail = bail_eof;
248 break;
250 val =
251 strntoumax(q, (char **)&qq, base,
252 width);
253 if (qq == q) {
254 bail = bail_err;
255 break;
257 q = qq;
258 if (!(flags & FL_SPLAT))
259 converted++;
260 /* fall through */
262 set_integer:
263 if (!(flags & FL_SPLAT)) {
264 switch (rank) {
265 case rank_char:
266 *va_arg(ap,
267 unsigned char *)
268 = val;
269 break;
270 case rank_short:
271 *va_arg(ap,
272 unsigned short
273 *) = val;
274 break;
275 case rank_int:
276 *va_arg(ap,
277 unsigned int *)
278 = val;
279 break;
280 case rank_long:
281 *va_arg(ap,
282 unsigned long *)
283 = val;
284 break;
285 case rank_longlong:
286 *va_arg(ap,
287 unsigned long
288 long *) = val;
289 break;
290 case rank_ptr:
291 *va_arg(ap, void **) =
292 (void *)
293 (uintptr_t)val;
294 break;
297 break;
299 case 'c': /* Character */
300 /* Default width == 1 */
301 width = (flags & FL_WIDTH) ? width : 1;
302 if (flags & FL_SPLAT) {
303 while (width--) {
304 if (!*q) {
305 bail = bail_eof;
306 break;
309 } else {
310 sarg = va_arg(ap, char *);
311 while (width--) {
312 if (!*q) {
313 bail = bail_eof;
314 break;
316 *sarg++ = *q++;
318 if (!bail)
319 converted++;
321 break;
323 case 's': /* String */
324 uc = 1; /* Anything nonzero */
325 if (flags & FL_SPLAT) {
326 while (width-- && (uc = *q) &&
327 !isspace(uc)) {
328 q++;
330 } else {
331 char *sp;
332 sp = sarg = va_arg(ap, char *);
333 while (width-- && (uc = *q) &&
334 !isspace(uc)) {
335 *sp++ = uc;
336 q++;
338 if (sarg != sp) {
339 /* Terminate output */
340 *sp = '\0';
341 converted++;
344 if (!uc)
345 bail = bail_eof;
346 break;
348 case '[': /* Character range */
349 sarg = (flags & FL_SPLAT) ? NULL
350 : va_arg(ap, char *);
351 state = st_match_init;
352 matchinv = 0;
353 memset(matchmap, 0, sizeof matchmap);
354 break;
356 case '%': /* %% sequence */
357 if (*q == '%')
358 q++;
359 else
360 bail = bail_err;
361 break;
363 default: /* Anything else */
364 /* Unknown sequence */
365 bail = bail_err;
366 break;
369 break;
371 case st_match_init: /* Initial state for %[ match */
372 if (ch == '^' && !(flags & FL_INV)) {
373 matchinv = 1;
374 } else {
375 set_bit(matchmap, (unsigned char)ch);
376 state = st_match;
378 break;
380 case st_match: /* Main state for %[ match */
381 if (ch == ']') {
382 goto match_run;
383 } else if (ch == '-') {
384 range_start = (unsigned char)ch;
385 state = st_match_range;
386 } else {
387 set_bit(matchmap, (unsigned char)ch);
389 break;
391 case st_match_range: /* %[ match after - */
392 if (ch == ']') {
393 /* - was last character */
394 set_bit(matchmap, (unsigned char)'-');
395 goto match_run;
396 } else {
397 int i;
398 for (i = range_start; i < (unsigned char)ch;
399 i++)
400 set_bit(matchmap, i);
401 state = st_match;
403 break;
405 match_run: /* Match expression finished */
406 qq = q;
407 uc = 1; /* Anything nonzero */
408 while (width && (uc = *q)
409 && test_bit(matchmap, uc)^matchinv) {
410 if (sarg)
411 *sarg++ = uc;
412 q++;
414 if (q != qq && sarg) {
415 *sarg = '\0';
416 converted++;
417 } else {
418 bail = bail_err;
420 if (!uc)
421 bail = bail_eof;
422 break;
426 if (bail == bail_eof && !converted)
427 converted = -1; /* Return EOF (-1) */
429 return converted;