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) */