4 * vsscanf(), from which the rest of the scanf()
17 #define LONG_BIT (CHAR_BIT*sizeof(long))
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 */
33 rank_ptr = INT_MAX /* Special value used for pointers */
36 #define MIN_RANK rank_char
37 #define MAX_RANK rank_longlong
39 #define INTMAX_RANK rank_longlong
40 #define SIZE_T_RANK rank_long
41 #define PTRDIFF_T_RANK rank_long
44 bail_none = 0, /* No error condition */
45 bail_eof, /* Hit EOF */
46 bail_err /* Conversion mismatch */
49 static inline const char *
50 skipspace(const char *p)
52 while ( isspace((unsigned char)*p) ) p++;
58 set_bit(unsigned long *bitmap, unsigned int bit)
60 bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);
65 test_bit(unsigned long *bitmap, unsigned int bit)
67 return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;
70 int vsscanf(const char *buffer, const char *format, va_list ap)
72 const char *p = format;
74 const char *q = buffer;
77 int rank = rank_int; /* Default rank */
78 unsigned int width = UINT_MAX;
82 st_normal, /* Ground state */
83 st_flags, /* Special flags */
84 st_width, /* Field width */
85 st_modifiers, /* Length or conversion modifiers */
86 st_match_init, /* Initial state of %[ sequence */
87 st_match, /* Main state of %[ sequence */
88 st_match_range, /* After - in a %[ sequence */
90 char *sarg = NULL; /* %s %c or %[ string argument */
91 enum bail bail = bail_none;
93 int converted = 0; /* Successful conversions */
94 unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT];
95 int matchinv = 0; /* Is match map inverted? */
96 unsigned char range_start = 0;
98 while ( (ch = *p++) && !bail ) {
103 flags = 0; rank = rank_int; width = UINT_MAX;
104 } else if ( isspace((unsigned char)ch) ) {
110 bail = bail_err; /* Match failure */
125 state = st_modifiers;
126 p--; /* Process this character again */
132 if ( ch >= '0' && ch <= '9' ) {
133 width = width*10+(ch-'0');
135 state = st_modifiers;
136 p--; /* Process this character again */
142 /* Length modifiers - nonterminal sequences */
144 rank--; /* Shorter rank */
147 rank++; /* Longer rank */
156 rank = PTRDIFF_T_RANK;
160 rank = rank_longlong; /* long double/long long */
164 /* Output modifiers - terminal sequences */
165 state = st_normal; /* Next state will be normal */
166 if ( rank < MIN_RANK ) /* Canonicalize rank */
168 else if ( rank > MAX_RANK )
172 case 'P': /* Upper case pointer */
173 case 'p': /* Pointer */
174 #if 0 /* Enable this to allow null pointers by name */
176 if ( !isdigit((unsigned char)*q) ) {
177 static const char * const nullnames[] =
178 { "null", "nul", "nil", "(null)", "(nul)", "(nil)", 0 };
179 const char * const *np;
181 /* Check to see if it's a null pointer by name */
182 for ( np = nullnames ; *np ; np++ ) {
183 if ( !strncasecmp(q, *np, strlen(*np)) ) {
184 val = (uintmax_t)((void *)NULL);
198 case 'i': /* Base-independent integer */
202 case 'd': /* Decimal integer */
206 case 'o': /* Octal integer */
210 case 'u': /* Unsigned decimal integer */
214 case 'x': /* Hexadecimal integer */
219 case 'n': /* Number of characters consumed */
229 val = strntoumax(q, (char **)&qq, base, width);
239 if ( !(flags & FL_SPLAT) ) {
242 *va_arg(ap, unsigned char *) = (unsigned char)val;
245 *va_arg(ap, unsigned short *) = (unsigned short)val;
248 *va_arg(ap, unsigned int *) = (unsigned int)val;
251 *va_arg(ap, unsigned long *) = (unsigned long)val;
254 *va_arg(ap, unsigned long long *) = (unsigned long long)val;
257 *va_arg(ap, void **) = (void *)(uintptr_t)val;
263 case 'c': /* Character */
264 width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */
265 sarg = va_arg(ap, char *);
277 case 's': /* String */
280 sp = sarg = va_arg(ap, char *);
281 while ( width-- && *q && !isspace((unsigned char)*q) ) {
285 *sp = '\0'; /* Terminate output */
293 case '[': /* Character range */
294 sarg = va_arg(ap, char *);
295 state = st_match_init;
297 memset(matchmap, 0, sizeof matchmap);
300 case '%': /* %% sequence */
307 default: /* Anything else */
308 bail = bail_err; /* Unknown sequence */
314 case st_match_init: /* Initial state for %[ match */
315 if ( ch == '^' && !(flags & FL_INV) ) {
318 set_bit(matchmap, (unsigned char)ch);
323 case st_match: /* Main state for %[ match */
326 } else if ( ch == '-' ) {
327 range_start = (unsigned char)ch;
328 state = st_match_range;
330 set_bit(matchmap, (unsigned char)ch);
334 case st_match_range: /* %[ match after - */
336 set_bit(matchmap, (unsigned char)'-'); /* - was last character */
340 for ( i = range_start ; i < (unsigned char)ch ; i++ )
341 set_bit(matchmap, i);
346 match_run: /* Match expression finished */
348 while ( width && *q && test_bit(matchmap, (unsigned char)*q)^matchinv ) {
355 bail = *q ? bail_err : bail_eof;
361 if ( bail == bail_eof && !converted )
362 converted = -1; /* Return EOF (-1) */