Root/
Source at commit 1078 created 13 years 1 month ago. By azimutz, Put back message removed by mistake on r1061. | |
---|---|
1 | /*␊ |
2 | * vsscanf.c␊ |
3 | *␊ |
4 | * vsscanf(), from which the rest of the scanf()␊ |
5 | * family is built␊ |
6 | */␊ |
7 | ␊ |
8 | #include "libsaio.h"␊ |
9 | #include "limits.h"␊ |
10 | extern uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n);␊ |
11 | ␊ |
12 | #ifndef LONG_BIT␊ |
13 | #define LONG_BIT (CHAR_BIT*sizeof(long))␊ |
14 | #endif␊ |
15 | ␊ |
16 | enum flags {␊ |
17 | ␉FL_SPLAT = 0x01,␉/* Drop the value, do not assign */␊ |
18 | ␉FL_INV = 0x02,␉/* Character-set with inverse */␊ |
19 | ␉FL_WIDTH = 0x04,␉/* Field width specified */␊ |
20 | ␉FL_MINUS = 0x08,␉/* Negative number */␊ |
21 | };␊ |
22 | ␊ |
23 | enum ranks {␊ |
24 | ␉rank_char = -2,␊ |
25 | ␉rank_short = -1,␊ |
26 | ␉rank_int = 0,␊ |
27 | ␉rank_long = 1,␊ |
28 | ␉rank_longlong = 2,␊ |
29 | ␉rank_ptr = INT_MAX␉/* Special value used for pointers */␊ |
30 | };␊ |
31 | ␊ |
32 | #define MIN_RANK␉rank_char␊ |
33 | #define MAX_RANK␉rank_longlong␊ |
34 | ␊ |
35 | #define INTMAX_RANK␉rank_longlong␊ |
36 | #define SIZE_T_RANK␉rank_long␊ |
37 | #define PTRDIFF_T_RANK␉rank_long␊ |
38 | ␊ |
39 | enum bail {␊ |
40 | ␉bail_none = 0,␉␉/* No error condition */␊ |
41 | ␉bail_eof,␉␉/* Hit EOF */␊ |
42 | ␉bail_err␉␉/* Conversion mismatch */␊ |
43 | };␊ |
44 | ␊ |
45 | static inline const char *skipspace(const char *p)␊ |
46 | {␊ |
47 | ␉while (isspace((unsigned char)*p))␊ |
48 | ␉␉p++;␊ |
49 | ␉return p;␊ |
50 | }␊ |
51 | ␊ |
52 | #undef set_bit␊ |
53 | static inline void set_bit(unsigned long *bitmap, unsigned int bit)␊ |
54 | {␊ |
55 | ␉bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);␊ |
56 | }␊ |
57 | ␊ |
58 | #undef test_bit␊ |
59 | static inline int test_bit(unsigned long *bitmap, unsigned int bit)␊ |
60 | {␊ |
61 | ␉return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;␊ |
62 | }␊ |
63 | ␊ |
64 | int vsscanf(const char *buffer, const char *format, va_list ap)␊ |
65 | {␊ |
66 | ␉const char *p = format;␊ |
67 | ␉char ch;␊ |
68 | ␉unsigned char uc;␊ |
69 | ␉const char *q = buffer;␊ |
70 | ␉const char *qq;␊ |
71 | ␉uintmax_t val = 0;␊ |
72 | ␉int rank = rank_int;␉/* Default rank */␊ |
73 | ␉unsigned int width = UINT_MAX;␊ |
74 | ␉int base;␊ |
75 | ␉enum flags flags = 0;␊ |
76 | ␉enum {␊ |
77 | ␉␉st_normal,␉/* Ground state */␊ |
78 | ␉␉st_flags,␉/* Special flags */␊ |
79 | ␉␉st_width,␉/* Field width */␊ |
80 | ␉␉st_modifiers,␉/* Length or conversion modifiers */␊ |
81 | ␉␉st_match_init,␉/* Initial state of %[ sequence */␊ |
82 | ␉␉st_match,␉/* Main state of %[ sequence */␊ |
83 | ␉␉st_match_range,␉/* After - in a %[ sequence */␊ |
84 | ␉} state = st_normal;␊ |
85 | ␉char *sarg = NULL;␉/* %s %c or %[ string argument */␊ |
86 | ␉enum bail bail = bail_none;␊ |
87 | ␉int sign;␊ |
88 | ␉int converted = 0;␉/* Successful conversions */␊ |
89 | ␉unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];␊ |
90 | ␉int matchinv = 0;␉/* Is match map inverted? */␊ |
91 | ␉unsigned char range_start = 0;␊ |
92 | ␊ |
93 | ␉while ((ch = *p++) && !bail) {␊ |
94 | ␉␉switch (state) {␊ |
95 | ␉␉case st_normal:␊ |
96 | ␉␉␉if (ch == '%') {␊ |
97 | ␉␉␉␉state = st_flags;␊ |
98 | ␉␉␉␉flags = 0;␊ |
99 | ␉␉␉␉rank = rank_int;␊ |
100 | ␉␉␉␉width = UINT_MAX;␊ |
101 | ␉␉␉} else if (isspace((unsigned char)ch)) {␊ |
102 | ␉␉␉␉q = skipspace(q);␊ |
103 | ␉␉␉} else {␊ |
104 | ␉␉␉␉if (*q == ch)␊ |
105 | ␉␉␉␉␉q++;␊ |
106 | ␉␉␉␉else␊ |
107 | ␉␉␉␉␉bail = bail_err; /* Match failure */␊ |
108 | ␉␉␉}␊ |
109 | ␉␉␉break;␊ |
110 | ␊ |
111 | ␉␉case st_flags:␊ |
112 | ␉␉␉switch (ch) {␊ |
113 | ␉␉␉case '*':␊ |
114 | ␉␉␉␉flags |= FL_SPLAT;␊ |
115 | ␉␉␉␉break;␊ |
116 | ␉␉␉case '0'...'9':␊ |
117 | ␉␉␉␉width = (ch - '0');␊ |
118 | ␉␉␉␉state = st_width;␊ |
119 | ␉␉␉␉flags |= FL_WIDTH;␊ |
120 | ␉␉␉␉break;␊ |
121 | ␉␉␉default:␊ |
122 | ␉␉␉␉state = st_modifiers;␊ |
123 | ␉␉␉␉p--;␉/* Process this character again */␊ |
124 | ␉␉␉␉break;␊ |
125 | ␉␉␉}␊ |
126 | ␉␉␉break;␊ |
127 | ␊ |
128 | ␉␉case st_width:␊ |
129 | ␉␉␉if (ch >= '0' && ch <= '9') {␊ |
130 | ␉␉␉␉width = width * 10 + (ch - '0');␊ |
131 | ␉␉␉} else {␊ |
132 | ␉␉␉␉state = st_modifiers;␊ |
133 | ␉␉␉␉p--;␉/* Process this character again */␊ |
134 | ␉␉␉}␊ |
135 | ␉␉␉break;␊ |
136 | ␊ |
137 | ␉␉case st_modifiers:␊ |
138 | ␉␉␉switch (ch) {␊ |
139 | ␉␉␉␉/* Length modifiers - nonterminal sequences */␊ |
140 | ␉␉␉case 'h':␊ |
141 | ␉␉␉␉rank--;␉/* Shorter rank */␊ |
142 | ␉␉␉␉break;␊ |
143 | ␉␉␉case 'l':␊ |
144 | ␉␉␉␉rank++;␉/* Longer rank */␊ |
145 | ␉␉␉␉break;␊ |
146 | ␉␉␉case 'j':␊ |
147 | ␉␉␉␉rank = INTMAX_RANK;␊ |
148 | ␉␉␉␉break;␊ |
149 | ␉␉␉case 'z':␊ |
150 | ␉␉␉␉rank = SIZE_T_RANK;␊ |
151 | ␉␉␉␉break;␊ |
152 | ␉␉␉case 't':␊ |
153 | ␉␉␉␉rank = PTRDIFF_T_RANK;␊ |
154 | ␉␉␉␉break;␊ |
155 | ␉␉␉case 'L':␊ |
156 | ␉␉␉case 'q':␊ |
157 | ␉␉␉␉rank = rank_longlong;␉/* long double/long long */␊ |
158 | ␉␉␉␉break;␊ |
159 | ␊ |
160 | ␉␉␉default:␊ |
161 | ␉␉␉␉/* Output modifiers - terminal sequences */␊ |
162 | ␉␉␉␉/* Next state will be normal */␊ |
163 | ␉␉␉␉state = st_normal;␊ |
164 | ␊ |
165 | ␉␉␉␉/* Canonicalize rank */␊ |
166 | ␉␉␉␉if (rank < MIN_RANK)␊ |
167 | ␉␉␉␉␉rank = MIN_RANK;␊ |
168 | ␉␉␉␉else if (rank > MAX_RANK)␊ |
169 | ␉␉␉␉␉rank = MAX_RANK;␊ |
170 | ␊ |
171 | ␉␉␉␉switch (ch) {␊ |
172 | ␉␉␉␉case 'P':␉/* Upper case pointer */␊ |
173 | ␉␉␉␉case 'p':␉/* Pointer */␊ |
174 | ␉␉␉␉␉rank = rank_ptr;␊ |
175 | ␉␉␉␉␉base = 0;␊ |
176 | ␉␉␉␉␉sign = 0;␊ |
177 | ␉␉␉␉␉goto scan_int;␊ |
178 | ␊ |
179 | ␉␉␉␉case 'i':␉/* Base-independent integer */␊ |
180 | ␉␉␉␉␉base = 0;␊ |
181 | ␉␉␉␉␉sign = 1;␊ |
182 | ␉␉␉␉␉goto scan_int;␊ |
183 | ␊ |
184 | ␉␉␉␉case 'd':␉/* Decimal integer */␊ |
185 | ␉␉␉␉␉base = 10;␊ |
186 | ␉␉␉␉␉sign = 1;␊ |
187 | ␉␉␉␉␉goto scan_int;␊ |
188 | ␊ |
189 | ␉␉␉␉case 'o':␉/* Octal integer */␊ |
190 | ␉␉␉␉␉base = 8;␊ |
191 | ␉␉␉␉␉sign = 0;␊ |
192 | ␉␉␉␉␉goto scan_int;␊ |
193 | ␊ |
194 | ␉␉␉␉case 'u':␉/* Unsigned decimal integer */␊ |
195 | ␉␉␉␉␉base = 10;␊ |
196 | ␉␉␉␉␉sign = 0;␊ |
197 | ␉␉␉␉␉goto scan_int;␊ |
198 | ␊ |
199 | ␉␉␉␉case 'x':␉/* Hexadecimal integer */␊ |
200 | ␉␉␉␉case 'X':␊ |
201 | ␉␉␉␉␉base = 16;␊ |
202 | ␉␉␉␉␉sign = 0;␊ |
203 | ␉␉␉␉␉goto scan_int;␊ |
204 | ␊ |
205 | ␉␉␉␉case 'n':␉/* # of characters consumed */␊ |
206 | ␉␉␉␉␉val = (q - buffer);␊ |
207 | ␉␉␉␉␉goto set_integer;␊ |
208 | ␊ |
209 | ␉␉␉␉ scan_int:␊ |
210 | ␉␉␉␉␉q = skipspace(q);␊ |
211 | ␉␉␉␉␉if (!*q) {␊ |
212 | ␉␉␉␉␉␉bail = bail_eof;␊ |
213 | ␉␉␉␉␉␉break;␊ |
214 | ␉␉␉␉␉}␊ |
215 | ␉␉␉␉␉val =␊ |
216 | ␉␉␉␉␉ strntoumax(q, (char **)&qq, base,␊ |
217 | ␉␉␉␉␉␉ width);␊ |
218 | ␉␉␉␉␉if (qq == q) {␊ |
219 | ␉␉␉␉␉␉bail = bail_err;␊ |
220 | ␉␉␉␉␉␉break;␊ |
221 | ␉␉␉␉␉}␊ |
222 | ␉␉␉␉␉q = qq;␊ |
223 | ␉␉␉␉␉if (!(flags & FL_SPLAT))␊ |
224 | ␉␉␉␉␉␉converted++;␊ |
225 | ␉␉␉␉␉/* fall through */␊ |
226 | ␊ |
227 | ␉␉␉␉ set_integer:␊ |
228 | ␉␉␉␉␉if (!(flags & FL_SPLAT)) {␊ |
229 | ␉␉␉␉␉␉switch (rank) {␊ |
230 | ␉␉␉␉␉␉case rank_char:␊ |
231 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
232 | ␉␉␉␉␉␉␉␉unsigned char *)␊ |
233 | ␉␉␉␉␉␉␉␉= val;␊ |
234 | ␉␉␉␉␉␉␉break;␊ |
235 | ␉␉␉␉␉␉case rank_short:␊ |
236 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
237 | ␉␉␉␉␉␉␉␉unsigned short␊ |
238 | ␉␉␉␉␉␉␉␉*) = val;␊ |
239 | ␉␉␉␉␉␉␉break;␊ |
240 | ␉␉␉␉␉␉case rank_int:␊ |
241 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
242 | ␉␉␉␉␉␉␉␉unsigned int *)␊ |
243 | ␉␉␉␉␉␉␉ = val;␊ |
244 | ␉␉␉␉␉␉␉break;␊ |
245 | ␉␉␉␉␉␉case rank_long:␊ |
246 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
247 | ␉␉␉␉␉␉␉␉unsigned long *)␊ |
248 | ␉␉␉␉␉␉␉␉= val;␊ |
249 | ␉␉␉␉␉␉␉break;␊ |
250 | ␉␉␉␉␉␉case rank_longlong:␊ |
251 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
252 | ␉␉␉␉␉␉␉␉unsigned long␊ |
253 | ␉␉␉␉␉␉␉␉long *) = val;␊ |
254 | ␉␉␉␉␉␉␉break;␊ |
255 | ␉␉␉␉␉␉case rank_ptr:␊ |
256 | ␉␉␉␉␉␉␉*va_arg(ap, void **) =␊ |
257 | ␉␉␉␉␉␉␉␉(void *)␊ |
258 | ␉␉␉␉␉␉␉␉(uintptr_t)val;␊ |
259 | ␉␉␉␉␉␉␉break;␊ |
260 | ␉␉␉␉␉␉}␊ |
261 | ␉␉␉␉␉}␊ |
262 | ␉␉␉␉␉break;␊ |
263 | ␊ |
264 | ␉␉␉␉case 'c':␉/* Character */␊ |
265 | ␉␉␉␉␉/* Default width == 1 */␊ |
266 | ␉␉␉␉␉width = (flags & FL_WIDTH) ? width : 1;␊ |
267 | ␉␉␉␉␉if (flags & FL_SPLAT) {␊ |
268 | ␉␉␉␉␉␉while (width--) {␊ |
269 | ␉␉␉␉␉␉␉if (!*q) {␊ |
270 | ␉␉␉␉␉␉␉␉bail = bail_eof;␊ |
271 | ␉␉␉␉␉␉␉␉break;␊ |
272 | ␉␉␉␉␉␉␉}␊ |
273 | ␉␉␉␉␉␉}␊ |
274 | ␉␉␉␉␉} else {␊ |
275 | ␉␉␉␉␉␉sarg = va_arg(ap, char *);␊ |
276 | ␉␉␉␉␉␉while (width--) {␊ |
277 | ␉␉␉␉␉␉␉if (!*q) {␊ |
278 | ␉␉␉␉␉␉␉␉bail = bail_eof;␊ |
279 | ␉␉␉␉␉␉␉␉break;␊ |
280 | ␉␉␉␉␉␉␉}␊ |
281 | ␉␉␉␉␉␉␉*sarg++ = *q++;␊ |
282 | ␉␉␉␉␉␉}␊ |
283 | ␉␉␉␉␉␉if (!bail)␊ |
284 | ␉␉␉␉␉␉␉converted++;␊ |
285 | ␉␉␉␉␉}␊ |
286 | ␉␉␉␉␉break;␊ |
287 | ␊ |
288 | ␉␉␉␉case 's':␉/* String */␊ |
289 | ␉␉␉␉␉uc = 1;␉/* Anything nonzero */␊ |
290 | ␉␉␉␉␉if (flags & FL_SPLAT) {␊ |
291 | ␉␉␉␉␉␉while (width-- && (uc = *q) &&␊ |
292 | ␉␉␉␉␉␉ !isspace(uc)) {␊ |
293 | ␉␉␉␉␉␉␉q++;␊ |
294 | ␉␉␉␉␉␉}␊ |
295 | ␉␉␉␉␉} else {␊ |
296 | ␉␉␉␉␉␉char *sp;␊ |
297 | ␉␉␉␉␉␉sp = sarg = va_arg(ap, char *);␊ |
298 | ␉␉␉␉␉␉while (width-- && (uc = *q) &&␊ |
299 | ␉␉␉␉␉␉ !isspace(uc)) {␊ |
300 | ␉␉␉␉␉␉␉*sp++ = uc;␊ |
301 | ␉␉␉␉␉␉␉q++;␊ |
302 | ␉␉␉␉␉␉}␊ |
303 | ␉␉␉␉␉␉if (sarg != sp) {␊ |
304 | ␉␉␉␉␉␉␉/* Terminate output */␊ |
305 | ␉␉␉␉␉␉␉*sp = '\0';␊ |
306 | ␉␉␉␉␉␉␉converted++;␊ |
307 | ␉␉␉␉␉␉}␊ |
308 | ␉␉␉␉␉}␊ |
309 | ␉␉␉␉␉if (!uc)␊ |
310 | ␉␉␉␉␉␉bail = bail_eof;␊ |
311 | ␉␉␉␉␉break;␊ |
312 | ␊ |
313 | ␉␉␉␉case '[':␉/* Character range */␊ |
314 | ␉␉␉␉␉sarg = (flags & FL_SPLAT) ? NULL␊ |
315 | ␉␉␉␉␉␉: va_arg(ap, char *);␊ |
316 | ␉␉␉␉␉state = st_match_init;␊ |
317 | ␉␉␉␉␉matchinv = 0;␊ |
318 | ␉␉␉␉␉memset(matchmap, 0, sizeof matchmap);␊ |
319 | ␉␉␉␉␉break;␊ |
320 | ␊ |
321 | ␉␉␉␉case '%':␉/* %% sequence */␊ |
322 | ␉␉␉␉␉if (*q == '%')␊ |
323 | ␉␉␉␉␉␉q++;␊ |
324 | ␉␉␉␉␉else␊ |
325 | ␉␉␉␉␉␉bail = bail_err;␊ |
326 | ␉␉␉␉␉break;␊ |
327 | ␊ |
328 | ␉␉␉␉default:␉/* Anything else */␊ |
329 | ␉␉␉␉␉/* Unknown sequence */␊ |
330 | ␉␉␉␉␉bail = bail_err;␊ |
331 | ␉␉␉␉␉break;␊ |
332 | ␉␉␉␉}␊ |
333 | ␉␉␉}␊ |
334 | ␉␉␉break;␊ |
335 | ␊ |
336 | ␉␉case st_match_init:␉/* Initial state for %[ match */␊ |
337 | ␉␉␉if (ch == '^' && !(flags & FL_INV)) {␊ |
338 | ␉␉␉␉matchinv = 1;␊ |
339 | ␉␉␉} else {␊ |
340 | ␉␉␉␉set_bit(matchmap, (unsigned char)ch);␊ |
341 | ␉␉␉␉state = st_match;␊ |
342 | ␉␉␉}␊ |
343 | ␉␉␉break;␊ |
344 | ␊ |
345 | ␉␉case st_match:␉/* Main state for %[ match */␊ |
346 | ␉␉␉if (ch == ']') {␊ |
347 | ␉␉␉␉goto match_run;␊ |
348 | ␉␉␉} else if (ch == '-') {␊ |
349 | ␉␉␉␉range_start = (unsigned char)ch;␊ |
350 | ␉␉␉␉state = st_match_range;␊ |
351 | ␉␉␉} else {␊ |
352 | ␉␉␉␉set_bit(matchmap, (unsigned char)ch);␊ |
353 | ␉␉␉}␊ |
354 | ␉␉␉break;␊ |
355 | ␊ |
356 | ␉␉case st_match_range:␉/* %[ match after - */␊ |
357 | ␉␉␉if (ch == ']') {␊ |
358 | ␉␉␉␉/* - was last character */␊ |
359 | ␉␉␉␉set_bit(matchmap, (unsigned char)'-');␊ |
360 | ␉␉␉␉goto match_run;␊ |
361 | ␉␉␉} else {␊ |
362 | ␉␉␉␉int i;␊ |
363 | ␉␉␉␉for (i = range_start; i < (unsigned char)ch;␊ |
364 | ␉␉␉␉ i++)␊ |
365 | ␉␉␉␉␉set_bit(matchmap, i);␊ |
366 | ␉␉␉␉state = st_match;␊ |
367 | ␉␉␉}␊ |
368 | ␉␉␉break;␊ |
369 | ␊ |
370 | ␉␉ match_run:␉/* Match expression finished */␊ |
371 | ␉␉␉qq = q;␊ |
372 | ␉␉␉uc = 1;␉/* Anything nonzero */␊ |
373 | ␉␉␉while (width && (uc = *q)␊ |
374 | ␉␉␉ && test_bit(matchmap, uc)^matchinv) {␊ |
375 | ␉␉␉␉if (sarg)␊ |
376 | ␉␉␉␉␉*sarg++ = uc;␊ |
377 | ␉␉␉␉q++;␊ |
378 | ␉␉␉}␊ |
379 | ␉␉␉if (q != qq && sarg) {␊ |
380 | ␉␉␉␉*sarg = '\0';␊ |
381 | ␉␉␉␉converted++;␊ |
382 | ␉␉␉} else {␊ |
383 | ␉␉␉␉bail = bail_err;␊ |
384 | ␉␉␉}␊ |
385 | ␉␉␉if (!uc)␊ |
386 | ␉␉␉␉bail = bail_eof;␊ |
387 | ␉␉␉break;␊ |
388 | ␉␉}␊ |
389 | ␉}␊ |
390 | ␊ |
391 | ␉if (bail == bail_eof && !converted)␊ |
392 | ␉␉converted = -1;␉/* Return EOF (-1) */␊ |
393 | ␊ |
394 | ␉return converted;␊ |
395 | }␊ |
396 |