4 * vsscanf(), from which the rest of the scanf()
15 #include <sys/bitops.h>
18 #define LONG_BIT (CHAR_BIT*sizeof(long))
22 FL_SPLAT
= 0x01, /* Drop the value, do not assign */
23 FL_INV
= 0x02, /* Character-set with inverse */
24 FL_WIDTH
= 0x04, /* Field width specified */
25 FL_MINUS
= 0x08, /* Negative number */
34 rank_ptr
= INT_MAX
/* Special value used for pointers */
37 #define MIN_RANK rank_char
38 #define MAX_RANK rank_longlong
40 #define INTMAX_RANK rank_longlong
41 #define SIZE_T_RANK rank_long
42 #define PTRDIFF_T_RANK rank_long
45 bail_none
= 0, /* No error condition */
46 bail_eof
, /* Hit EOF */
47 bail_err
/* Conversion mismatch */
50 int vsscanf(const char *buffer
, const char *format
, va_list ap
)
52 const char *p
= format
;
54 const char *q
= buffer
;
57 int rank
= rank_int
; /* Default rank */
58 unsigned int width
= UINT_MAX
;
62 st_normal
, /* Ground state */
63 st_flags
, /* Special flags */
64 st_width
, /* Field width */
65 st_modifiers
, /* Length or conversion modifiers */
66 st_match_init
, /* Initial state of %[ sequence */
67 st_match
, /* Main state of %[ sequence */
68 st_match_range
, /* After - in a %[ sequence */
70 char *sarg
= NULL
; /* %s %c or %[ string argument */
71 enum bail bail
= bail_none
;
73 int converted
= 0; /* Successful conversions */
74 unsigned long matchmap
[((1 << CHAR_BIT
) + (LONG_BIT
- 1)) / LONG_BIT
];
75 int matchinv
= 0; /* Is match map inverted? */
76 unsigned char range_start
= 0;
78 while ((ch
= *p
++) && !bail
) {
86 } else if (isspace((unsigned char)ch
)) {
92 bail
= bail_err
; /* Match failure */
107 state
= st_modifiers
;
108 p
--; /* Process this character again */
114 if (ch
>= '0' && ch
<= '9') {
115 width
= width
* 10 + (ch
- '0');
117 state
= st_modifiers
;
118 p
--; /* Process this character again */
124 /* Length modifiers - nonterminal sequences */
126 rank
--; /* Shorter rank */
129 rank
++; /* Longer rank */
138 rank
= PTRDIFF_T_RANK
;
142 rank
= rank_longlong
; /* long double/long long */
146 /* Output modifiers - terminal sequences */
147 state
= st_normal
; /* Next state will be normal */
148 if (rank
< MIN_RANK
) /* Canonicalize rank */
150 else if (rank
> MAX_RANK
)
154 case 'P': /* Upper case pointer */
155 case 'p': /* Pointer */
156 #if 0 /* Enable this to allow null pointers by name */
158 if (!isdigit((unsigned char)*q
)) {
159 static const char *const nullnames
[] =
160 { "null", "nul", "nil", "(null)", "(nul)", "(nil)",
162 const char *const *np
;
164 /* Check to see if it's a null pointer by name */
165 for (np
= nullnames
; *np
; np
++) {
166 if (!strncasecmp(q
, *np
, strlen(*np
))) {
167 val
= (uintmax_t) ((void *)NULL
);
182 case 'i': /* Base-independent integer */
187 case 'd': /* Decimal integer */
192 case 'o': /* Octal integer */
197 case 'u': /* Unsigned decimal integer */
202 case 'x': /* Hexadecimal integer */
208 case 'n': /* Number of characters consumed */
218 val
= strntoumax(q
, (char **)&qq
, base
, width
);
228 if (!(flags
& FL_SPLAT
)) {
231 *va_arg(ap
, unsigned char *) = (unsigned char)val
;
234 *va_arg(ap
, unsigned short *) = (unsigned short)val
;
237 *va_arg(ap
, unsigned int *) = (unsigned int)val
;
240 *va_arg(ap
, unsigned long *) = (unsigned long)val
;
243 *va_arg(ap
, unsigned long long *) =
244 (unsigned long long)val
;
247 *va_arg(ap
, void **) = (void *)(uintptr_t) val
;
253 case 'c': /* Character */
254 width
= (flags
& FL_WIDTH
) ? width
: 1; /* Default width == 1 */
255 sarg
= va_arg(ap
, char *);
267 case 's': /* String */
270 sp
= sarg
= va_arg(ap
, char *);
271 while (width
-- && *q
&& !isspace((unsigned char)*q
)) {
275 *sp
= '\0'; /* Terminate output */
283 case '[': /* Character range */
284 sarg
= va_arg(ap
, char *);
285 state
= st_match_init
;
287 memset(matchmap
, 0, sizeof matchmap
);
290 case '%': /* %% sequence */
297 default: /* Anything else */
298 bail
= bail_err
; /* Unknown sequence */
304 case st_match_init
: /* Initial state for %[ match */
305 if (ch
== '^' && !(flags
& FL_INV
)) {
308 set_bit((unsigned char)ch
, matchmap
);
313 case st_match
: /* Main state for %[ match */
316 } else if (ch
== '-') {
317 range_start
= (unsigned char)ch
;
318 state
= st_match_range
;
320 set_bit((unsigned char)ch
, matchmap
);
324 case st_match_range
: /* %[ match after - */
326 set_bit((unsigned char)'-', matchmap
); /* - was last character */
330 for (i
= range_start
; i
< (unsigned char)ch
; i
++)
331 set_bit(i
, matchmap
);
336 match_run
: /* Match expression finished */
339 && test_bit((unsigned char)*q
, matchmap
) ^ matchinv
) {
346 bail
= *q
? bail_err
: bail_eof
;
352 if (bail
== bail_eof
&& !converted
)
353 converted
= -1; /* Return EOF (-1) */