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 *skipspace(const char *p
)
51 while (isspace((unsigned char)*p
))
57 static inline void set_bit(unsigned long *bitmap
, unsigned int bit
)
59 bitmap
[bit
/ LONG_BIT
] |= 1UL << (bit
% LONG_BIT
);
63 static inline int test_bit(unsigned long *bitmap
, unsigned int bit
)
65 return (int)(bitmap
[bit
/ LONG_BIT
] >> (bit
% LONG_BIT
)) & 1;
68 int vsscanf(const char *buffer
, const char *format
, va_list ap
)
70 const char *p
= format
;
72 const char *q
= buffer
;
75 int rank
= rank_int
; /* Default rank */
76 unsigned int width
= UINT_MAX
;
80 st_normal
, /* Ground state */
81 st_flags
, /* Special flags */
82 st_width
, /* Field width */
83 st_modifiers
, /* Length or conversion modifiers */
84 st_match_init
, /* Initial state of %[ sequence */
85 st_match
, /* Main state of %[ sequence */
86 st_match_range
, /* After - in a %[ sequence */
88 char *sarg
= NULL
; /* %s %c or %[ string argument */
89 enum bail bail
= bail_none
;
91 int converted
= 0; /* Successful conversions */
92 unsigned long matchmap
[((1 << CHAR_BIT
) + (LONG_BIT
- 1)) / LONG_BIT
];
93 int matchinv
= 0; /* Is match map inverted? */
94 unsigned char range_start
= 0;
96 while ((ch
= *p
++) && !bail
) {
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)",
180 const char *const *np
;
182 /* Check to see if it's a null pointer by name */
183 for (np
= nullnames
; *np
; np
++) {
184 if (!strncasecmp(q
, *np
, strlen(*np
))) {
185 val
= (uintmax_t) ((void *)NULL
);
200 case 'i': /* Base-independent integer */
205 case 'd': /* Decimal integer */
210 case 'o': /* Octal integer */
215 case 'u': /* Unsigned decimal integer */
220 case 'x': /* Hexadecimal integer */
226 case 'n': /* Number of characters consumed */
236 val
= strntoumax(q
, (char **)&qq
, base
, width
);
246 if (!(flags
& FL_SPLAT
)) {
249 *va_arg(ap
, unsigned char *) = (unsigned char)val
;
252 *va_arg(ap
, unsigned short *) = (unsigned short)val
;
255 *va_arg(ap
, unsigned int *) = (unsigned int)val
;
258 *va_arg(ap
, unsigned long *) = (unsigned long)val
;
261 *va_arg(ap
, unsigned long long *) =
262 (unsigned long long)val
;
265 *va_arg(ap
, void **) = (void *)(uintptr_t) val
;
271 case 'c': /* Character */
272 width
= (flags
& FL_WIDTH
) ? width
: 1; /* Default width == 1 */
273 sarg
= va_arg(ap
, char *);
285 case 's': /* String */
288 sp
= sarg
= va_arg(ap
, char *);
289 while (width
-- && *q
&& !isspace((unsigned char)*q
)) {
293 *sp
= '\0'; /* Terminate output */
301 case '[': /* Character range */
302 sarg
= va_arg(ap
, char *);
303 state
= st_match_init
;
305 memset(matchmap
, 0, sizeof matchmap
);
308 case '%': /* %% sequence */
315 default: /* Anything else */
316 bail
= bail_err
; /* Unknown sequence */
322 case st_match_init
: /* Initial state for %[ match */
323 if (ch
== '^' && !(flags
& FL_INV
)) {
326 set_bit(matchmap
, (unsigned char)ch
);
331 case st_match
: /* Main state for %[ match */
334 } else if (ch
== '-') {
335 range_start
= (unsigned char)ch
;
336 state
= st_match_range
;
338 set_bit(matchmap
, (unsigned char)ch
);
342 case st_match_range
: /* %[ match after - */
344 set_bit(matchmap
, (unsigned char)'-'); /* - was last character */
348 for (i
= range_start
; i
< (unsigned char)ch
; i
++)
349 set_bit(matchmap
, i
);
354 match_run
: /* Match expression finished */
357 && test_bit(matchmap
, (unsigned char)*q
) ^ matchinv
) {
364 bail
= *q
? bail_err
: bail_eof
;
370 if (bail
== bail_eof
&& !converted
)
371 converted
= -1; /* Return EOF (-1) */