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_WIDTH
= 0x02, /* Field width specified */
24 FL_MINUS
= 0x04, /* 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 int vsscanf(const char *buffer
, const char *format
, va_list ap
)
51 const char *p
= format
;
53 const char *q
= buffer
;
56 int rank
= rank_int
; /* Default rank */
57 unsigned int width
= UINT_MAX
;
61 st_normal
, /* Ground state */
62 st_flags
, /* Special flags */
63 st_width
, /* Field width */
64 st_modifiers
, /* Length or conversion modifiers */
65 st_match_init
, /* Initial state of %[ sequence */
66 st_match
, /* Main state of %[ sequence */
67 st_match_range
, /* After - in a %[ sequence */
69 char *sarg
= NULL
; /* %s %c or %[ string argument */
70 enum bail bail
= bail_none
;
71 int converted
= 0; /* Successful conversions */
72 unsigned long matchmap
[((1 << CHAR_BIT
) + (LONG_BIT
- 1)) / LONG_BIT
];
73 int matchinv
= 0; /* Is match map inverted? */
74 unsigned char range_start
= 0;
76 while ((ch
= *p
++) && !bail
) {
84 } else if (isspace((unsigned char)ch
)) {
90 bail
= bail_err
; /* Match failure */
105 state
= st_modifiers
;
106 p
--; /* Process this character again */
112 if (ch
>= '0' && ch
<= '9') {
113 width
= width
* 10 + (ch
- '0');
115 state
= st_modifiers
;
116 p
--; /* Process this character again */
122 /* Length modifiers - nonterminal sequences */
124 rank
--; /* Shorter rank */
127 rank
++; /* Longer rank */
136 rank
= PTRDIFF_T_RANK
;
140 rank
= rank_longlong
; /* long double/long long */
144 /* Output modifiers - terminal sequences */
145 state
= st_normal
; /* Next state will be normal */
146 if (rank
< MIN_RANK
) /* Canonicalize rank */
148 else if (rank
> MAX_RANK
)
152 case 'P': /* Upper case pointer */
153 case 'p': /* Pointer */
154 #if 0 /* Enable this to allow null pointers by name */
156 if (!isdigit((unsigned char)*q
)) {
157 static const char *const nullnames
[] =
158 { "null", "nul", "nil", "(null)", "(nul)", "(nil)",
160 const char *const *np
;
162 /* Check to see if it's a null pointer by name */
163 for (np
= nullnames
; *np
; np
++) {
164 if (!strncasecmp(q
, *np
, strlen(*np
))) {
165 val
= (uintmax_t) ((void *)NULL
);
179 case 'i': /* Base-independent integer */
183 case 'd': /* Decimal integer */
187 case 'o': /* Octal integer */
191 case 'u': /* Unsigned decimal integer */
195 case 'x': /* Hexadecimal integer */
200 case 'n': /* Number of characters consumed */
210 val
= strntoumax(q
, (char **)&qq
, base
, width
);
220 if (!(flags
& FL_SPLAT
)) {
223 *va_arg(ap
, unsigned char *) = (unsigned char)val
;
226 *va_arg(ap
, unsigned short *) = (unsigned short)val
;
229 *va_arg(ap
, unsigned int *) = (unsigned int)val
;
232 *va_arg(ap
, unsigned long *) = (unsigned long)val
;
235 *va_arg(ap
, unsigned long long *) =
236 (unsigned long long)val
;
239 *va_arg(ap
, void **) = (void *)(uintptr_t) val
;
245 case 'c': /* Character */
246 width
= (flags
& FL_WIDTH
) ? width
: 1; /* Default width == 1 */
247 sarg
= va_arg(ap
, char *);
259 case 's': /* String */
262 sp
= sarg
= va_arg(ap
, char *);
263 while (width
-- && *q
&& !isspace((unsigned char)*q
)) {
267 *sp
= '\0'; /* Terminate output */
275 case '[': /* Character range */
276 sarg
= va_arg(ap
, char *);
277 state
= st_match_init
;
279 memset(matchmap
, 0, sizeof matchmap
);
282 case '%': /* %% sequence */
289 default: /* Anything else */
290 bail
= bail_err
; /* Unknown sequence */
296 case st_match_init
: /* Initial state for %[ match */
297 if (ch
== '^' && !matchinv
) {
300 range_start
= (unsigned char)ch
;
301 set_bit((unsigned char)ch
, matchmap
);
306 case st_match
: /* Main state for %[ match */
309 } else if (ch
== '-') {
310 state
= st_match_range
;
312 range_start
= (unsigned char)ch
;
313 set_bit((unsigned char)ch
, matchmap
);
317 case st_match_range
: /* %[ match after - */
319 set_bit((unsigned char)'-', matchmap
); /* - was last character */
323 for (i
= range_start
; i
<= (unsigned char)ch
; i
++)
324 set_bit(i
, matchmap
);
329 match_run
: /* Match expression finished */
332 && test_bit((unsigned char)*q
, matchmap
) ^ matchinv
) {
339 bail
= *q
? bail_err
: bail_eof
;
345 if (bail
== bail_eof
&& !converted
)
346 converted
= -1; /* Return EOF (-1) */