blob: c18e214a37555d48a2ad0cdc9f39a3305678835b [file] [log] [blame]
Elliott Hughesf1ada792014-05-02 17:56:56 -07001/* $OpenBSD: vfscanf.c,v 1.31 2014/03/19 05:17:01 guenther Exp $ */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002/*-
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <ctype.h>
35#include <inttypes.h>
36#include <stdarg.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <stdlib.h>
Elliott Hughes603332f2014-03-12 17:10:41 -070040#include <string.h>
Elliott Hughesc8f2c522017-10-31 13:07:51 -070041#include <wctype.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080042#include "local.h"
43
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#include "floatio.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080045
Elliott Hughesc8f2c522017-10-31 13:07:51 -070046#define BUF 513 /* Maximum length of numeric string. */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047
48/*
49 * Flags used during conversion.
50 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070051#define LONG 0x00001 /* l: long or double */
52#define LONGDBL 0x00002 /* L: long double */
53#define SHORT 0x00004 /* h: short */
54#define SHORTSHORT 0x00008 /* hh: 8 bit integer */
55#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
56#define POINTER 0x00020 /* p: void * (as hex) */
57#define SIZEINT 0x00040 /* z: (signed) size_t */
58#define MAXINT 0x00080 /* j: intmax_t */
59#define PTRINT 0x00100 /* t: ptrdiff_t */
60#define NOSKIP 0x00200 /* [ or c: do not skip blanks */
61#define SUPPRESS 0x00400 /* *: suppress assignment */
62#define UNSIGNED 0x00800 /* %[oupxX] conversions */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080063
64/*
65 * The following are used in numeric conversions only:
66 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
67 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
68 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070069#define SIGNOK 0x01000 /* +/- is (still) legal */
70#define HAVESIGN 0x02000 /* sign detected */
71#define NDIGITS 0x04000 /* no digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Elliott Hughesc8f2c522017-10-31 13:07:51 -070073#define DPTOK 0x08000 /* (float) decimal point is still legal */
74#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075
Elliott Hughesc8f2c522017-10-31 13:07:51 -070076#define PFXOK 0x08000 /* 0x prefix is (still) legal */
77#define NZDIGITS 0x10000 /* no zero digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080078
79/*
80 * Conversion types.
81 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070082#define CT_CHAR 0 /* %c conversion */
83#define CT_CCL 1 /* %[...] conversion */
84#define CT_STRING 2 /* %s conversion */
85#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
86#define CT_FLOAT 4 /* floating, i.e., strtod */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087
88#define u_char unsigned char
89#define u_long unsigned long
90
Elliott Hughesc8f2c522017-10-31 13:07:51 -070091static u_char* __sccl(char*, u_char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080092
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093/*
Elliott Hughes603332f2014-03-12 17:10:41 -070094 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080095 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070096int __svfscanf(FILE* fp, const char* fmt0, __va_list ap) {
97 u_char* fmt = (u_char*)fmt0;
98 int c; /* character from format, or conversion */
99 size_t width; /* field width, or 0 */
100 char* p; /* points into all kinds of strings */
101 int n; /* handy integer */
102 int flags; /* flags as defined above */
103 char* p0; /* saves original value of p when necessary */
104 int nassigned; /* number of fields assigned */
105 int nread; /* number of characters consumed from fp */
106 int base; /* base argument to strtoimax/strtouimax */
107 char ccltab[256]; /* character class table for %[...] */
108 char buf[BUF]; /* buffer for numeric conversions */
109 wchar_t* wcp; /* handy wide character pointer */
110 size_t nconv; /* length of multibyte sequence converted */
111 mbstate_t mbs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700113 /* `basefix' is used to avoid `if' tests in the integer scanner */
114 static short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700116 _SET_ORIENTATION(fp, -1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700118 nassigned = 0;
119 nread = 0;
120 base = 0; /* XXX just to keep gcc happy */
121 for (;;) {
122 c = *fmt++;
123 if (c == 0) return (nassigned);
124 if (isspace(c)) {
125 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++;
126 continue;
127 }
128 if (c != '%') goto literal;
129 width = 0;
130 flags = 0;
131 /*
132 * switch on the format. continue if done;
133 * break once format type is derived.
134 */
135 again:
136 c = *fmt++;
137 switch (c) {
138 case '%':
139 literal:
140 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
141 if (*fp->_p != c) goto match_failure;
142 fp->_r--, fp->_p++;
143 nread++;
144 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800145
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700146 case '*':
147 flags |= SUPPRESS;
148 goto again;
149 case 'j':
150 flags |= MAXINT;
151 goto again;
152 case 'L':
153 flags |= LONGDBL;
154 goto again;
155 case 'h':
156 if (*fmt == 'h') {
157 fmt++;
158 flags |= SHORTSHORT;
159 } else {
160 flags |= SHORT;
161 }
162 goto again;
163 case 'l':
164 if (*fmt == 'l') {
165 fmt++;
166 flags |= LLONG;
167 } else {
168 flags |= LONG;
169 }
170 goto again;
171 case 'q':
172 flags |= LLONG; /* deprecated */
173 goto again;
174 case 't':
175 flags |= PTRINT;
176 goto again;
177 case 'z':
178 flags |= SIZEINT;
179 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800180
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700181 case '0':
182 case '1':
183 case '2':
184 case '3':
185 case '4':
186 case '5':
187 case '6':
188 case '7':
189 case '8':
190 case '9':
191 width = width * 10 + c - '0';
192 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800193
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700194 /*
195 * Conversions.
196 * Those marked `compat' are for 4.[123]BSD compatibility.
197 *
198 * (According to ANSI, E and X formats are supposed
199 * to the same as e and x. Sorry about that.)
200 */
201 case 'D': /* compat */
202 flags |= LONG;
203 /* FALLTHROUGH */
204 case 'd':
205 c = CT_INT;
206 base = 10;
207 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800208
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700209 case 'i':
210 c = CT_INT;
211 base = 0;
212 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800213
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700214 case 'O': /* compat */
215 flags |= LONG;
216 /* FALLTHROUGH */
217 case 'o':
218 c = CT_INT;
219 flags |= UNSIGNED;
220 base = 8;
221 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800222
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700223 case 'u':
224 c = CT_INT;
225 flags |= UNSIGNED;
226 base = 10;
227 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800228
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700229 case 'X':
230 case 'x':
231 flags |= PFXOK; /* enable 0x prefixing */
232 c = CT_INT;
233 flags |= UNSIGNED;
234 base = 16;
235 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800236
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700237 case 'e':
238 case 'E':
239 case 'f':
240 case 'F':
241 case 'g':
242 case 'G':
243 case 'a':
244 case 'A':
245 c = CT_FLOAT;
246 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800247
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700248 case 's':
249 c = CT_STRING;
250 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800251
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700252 case '[':
253 fmt = __sccl(ccltab, fmt);
254 flags |= NOSKIP;
255 c = CT_CCL;
256 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700258 case 'c':
259 flags |= NOSKIP;
260 c = CT_CHAR;
261 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800262
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700263 case 'p': /* pointer format is like hex */
264 flags |= POINTER | PFXOK;
265 c = CT_INT;
266 flags |= UNSIGNED;
267 base = 16;
268 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700270 case 'n':
271 if (flags & SUPPRESS) continue;
272 if (flags & SHORTSHORT)
273 *va_arg(ap, signed char*) = nread;
274 else if (flags & SHORT)
275 *va_arg(ap, short*) = nread;
276 else if (flags & LONG)
277 *va_arg(ap, long*) = nread;
278 else if (flags & SIZEINT)
279 *va_arg(ap, ssize_t*) = nread;
280 else if (flags & PTRINT)
281 *va_arg(ap, ptrdiff_t*) = nread;
282 else if (flags & LLONG)
283 *va_arg(ap, long long*) = nread;
284 else if (flags & MAXINT)
285 *va_arg(ap, intmax_t*) = nread;
286 else
287 *va_arg(ap, int*) = nread;
288 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800289
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700290 /*
291 * Disgusting backwards compatibility hacks. XXX
292 */
293 case '\0': /* compat */
294 return (EOF);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800295
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700296 default: /* compat */
297 if (isupper(c)) flags |= LONG;
298 c = CT_INT;
299 base = 10;
300 break;
301 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800302
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700303 /*
304 * We have a conversion that requires input.
305 */
306 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800307
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700308 /*
309 * Consume leading white space, except for formats
310 * that suppress this.
311 */
312 if ((flags & NOSKIP) == 0) {
313 while (isspace(*fp->_p)) {
314 nread++;
315 if (--fp->_r > 0)
316 fp->_p++;
317 else if (__srefill(fp))
318 goto input_failure;
319 }
320 /*
321 * Note that there is at least one character in
322 * the buffer, so conversions that do not set NOSKIP
323 * ca no longer result in an input failure.
324 */
325 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800326
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700327 /*
328 * Do the conversion.
329 */
330 switch (c) {
331 case CT_CHAR:
332 /* scan arbitrary characters (sets NOSKIP) */
333 if (width == 0) width = 1;
334 if (flags & LONG) {
335 if ((flags & SUPPRESS) == 0)
336 wcp = va_arg(ap, wchar_t*);
337 else
338 wcp = NULL;
339 n = 0;
340 while (width != 0) {
341 if (n == (int)MB_CUR_MAX) {
342 fp->_flags |= __SERR;
343 goto input_failure;
344 }
345 buf[n++] = *fp->_p;
346 fp->_p++;
347 fp->_r--;
348 memset(&mbs, 0, sizeof(mbs));
349 nconv = mbrtowc(wcp, buf, n, &mbs);
350 if (nconv == (size_t)-1) {
351 fp->_flags |= __SERR;
352 goto input_failure;
353 }
354 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
355 if (nconv != (size_t)-2) {
356 nread += n;
357 width--;
358 if (!(flags & SUPPRESS)) wcp++;
359 n = 0;
360 }
361 if (fp->_r <= 0 && __srefill(fp)) {
362 if (n != 0) {
363 fp->_flags |= __SERR;
364 goto input_failure;
365 }
366 break;
367 }
368 }
369 if (!(flags & SUPPRESS)) nassigned++;
370 } else if (flags & SUPPRESS) {
371 size_t sum = 0;
372 for (;;) {
373 if ((n = fp->_r) < (int)width) {
374 sum += n;
375 width -= n;
376 fp->_p += n;
377 if (__srefill(fp)) {
378 if (sum == 0) goto input_failure;
379 break;
380 }
381 } else {
382 sum += width;
383 fp->_r -= width;
384 fp->_p += width;
385 break;
386 }
387 }
388 nread += sum;
389 } else {
390 size_t r = fread((void*)va_arg(ap, char*), 1, width, fp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800391
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700392 if (r == 0) goto input_failure;
393 nread += r;
394 nassigned++;
395 }
396 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800397
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700398 case CT_CCL:
399 /* scan a (nonempty) character class (sets NOSKIP) */
400 if (width == 0) width = (size_t)~0; /* `infinity' */
401 /* take only those things in the class */
402 if (flags & LONG) {
403 wchar_t twc;
404 int nchars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800405
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700406 if ((flags & SUPPRESS) == 0)
407 wcp = va_arg(ap, wchar_t*);
408 else
409 wcp = &twc;
410 n = 0;
411 nchars = 0;
412 while (width != 0) {
413 if (n == (int)MB_CUR_MAX) {
414 fp->_flags |= __SERR;
415 goto input_failure;
416 }
417 buf[n++] = *fp->_p;
418 fp->_p++;
419 fp->_r--;
420 memset(&mbs, 0, sizeof(mbs));
421 nconv = mbrtowc(wcp, buf, n, &mbs);
422 if (nconv == (size_t)-1) {
423 fp->_flags |= __SERR;
424 goto input_failure;
425 }
426 if (nconv == 0) *wcp = L'\0';
427 if (nconv != (size_t)-2) {
428 if (wctob(*wcp) != EOF && !ccltab[wctob(*wcp)]) {
429 while (n != 0) {
430 n--;
431 ungetc(buf[n], fp);
432 }
433 break;
434 }
435 nread += n;
436 width--;
437 if (!(flags & SUPPRESS)) wcp++;
438 nchars++;
439 n = 0;
440 }
441 if (fp->_r <= 0 && __srefill(fp)) {
442 if (n != 0) {
443 fp->_flags |= __SERR;
444 goto input_failure;
445 }
446 break;
447 }
448 }
449 if (n != 0) {
450 fp->_flags |= __SERR;
451 goto input_failure;
452 }
453 n = nchars;
454 if (n == 0) goto match_failure;
455 if (!(flags & SUPPRESS)) {
456 *wcp = L'\0';
457 nassigned++;
458 }
459 } else
460 /* take only those things in the class */
461 if (flags & SUPPRESS) {
462 n = 0;
463 while (ccltab[*fp->_p]) {
464 n++, fp->_r--, fp->_p++;
465 if (--width == 0) break;
466 if (fp->_r <= 0 && __srefill(fp)) {
467 if (n == 0) goto input_failure;
468 break;
469 }
470 }
471 if (n == 0) goto match_failure;
472 } else {
473 p0 = p = va_arg(ap, char*);
474 while (ccltab[*fp->_p]) {
475 fp->_r--;
476 *p++ = *fp->_p++;
477 if (--width == 0) break;
478 if (fp->_r <= 0 && __srefill(fp)) {
479 if (p == p0) goto input_failure;
480 break;
481 }
482 }
483 n = p - p0;
484 if (n == 0) goto match_failure;
485 *p = '\0';
486 nassigned++;
487 }
488 nread += n;
489 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700490
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700491 case CT_STRING:
492 /* like CCL, but zero-length string OK, & no NOSKIP */
493 if (width == 0) width = (size_t)~0;
494 if (flags & LONG) {
495 wchar_t twc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800496
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700497 if ((flags & SUPPRESS) == 0)
498 wcp = va_arg(ap, wchar_t*);
499 else
500 wcp = &twc;
501 n = 0;
502 while (!isspace(*fp->_p) && width != 0) {
503 if (n == (int)MB_CUR_MAX) {
504 fp->_flags |= __SERR;
505 goto input_failure;
506 }
507 buf[n++] = *fp->_p;
508 fp->_p++;
509 fp->_r--;
510 memset(&mbs, 0, sizeof(mbs));
511 nconv = mbrtowc(wcp, buf, n, &mbs);
512 if (nconv == (size_t)-1) {
513 fp->_flags |= __SERR;
514 goto input_failure;
515 }
516 if (nconv == 0) *wcp = L'\0';
517 if (nconv != (size_t)-2) {
518 if (iswspace(*wcp)) {
519 while (n != 0) {
520 n--;
521 ungetc(buf[n], fp);
522 }
523 break;
524 }
525 nread += n;
526 width--;
527 if (!(flags & SUPPRESS)) wcp++;
528 n = 0;
529 }
530 if (fp->_r <= 0 && __srefill(fp)) {
531 if (n != 0) {
532 fp->_flags |= __SERR;
533 goto input_failure;
534 }
535 break;
536 }
537 }
538 if (!(flags & SUPPRESS)) {
539 *wcp = L'\0';
540 nassigned++;
541 }
542 } else if (flags & SUPPRESS) {
543 n = 0;
544 while (!isspace(*fp->_p)) {
545 n++, fp->_r--, fp->_p++;
546 if (--width == 0) break;
547 if (fp->_r <= 0 && __srefill(fp)) break;
548 }
549 nread += n;
550 } else {
551 p0 = p = va_arg(ap, char*);
552 while (!isspace(*fp->_p)) {
553 fp->_r--;
554 *p++ = *fp->_p++;
555 if (--width == 0) break;
556 if (fp->_r <= 0 && __srefill(fp)) break;
557 }
558 *p = '\0';
559 nread += p - p0;
560 nassigned++;
561 }
562 continue;
Elliott Hughes603332f2014-03-12 17:10:41 -0700563
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700564 case CT_INT:
565 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800566#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700567 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800568#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700569 /* size_t is unsigned, hence this optimisation */
570 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
571 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800572#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700573 flags |= SIGNOK | NDIGITS | NZDIGITS;
574 for (p = buf; width; width--) {
575 c = *fp->_p;
576 /*
577 * Switch on the character; `goto ok'
578 * if we accept it as a part of number.
579 */
580 switch (c) {
581 /*
582 * The digit 0 is always legal, but is
583 * special. For %i conversions, if no
584 * digits (zero or nonzero) have been
585 * scanned (only signs), we will have
586 * base==0. In that case, we should set
587 * it to 8 and enable 0x prefixing.
588 * Also, if we have not scanned zero digits
589 * before this, do not turn off prefixing
590 * (someone else will turn it off if we
591 * have scanned any nonzero digits).
592 */
593 case '0':
594 if (base == 0) {
595 base = 8;
596 flags |= PFXOK;
597 }
598 if (flags & NZDIGITS)
599 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
600 else
601 flags &= ~(SIGNOK | PFXOK | NDIGITS);
602 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800603
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700604 /* 1 through 7 always legal */
605 case '1':
606 case '2':
607 case '3':
608 case '4':
609 case '5':
610 case '6':
611 case '7':
612 base = basefix[base];
613 flags &= ~(SIGNOK | PFXOK | NDIGITS);
614 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800615
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700616 /* digits 8 and 9 ok iff decimal or hex */
617 case '8':
618 case '9':
619 base = basefix[base];
620 if (base <= 8) break; /* not legal here */
621 flags &= ~(SIGNOK | PFXOK | NDIGITS);
622 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800623
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700624 /* letters ok iff hex */
625 case 'A':
626 case 'B':
627 case 'C':
628 case 'D':
629 case 'E':
630 case 'F':
631 case 'a':
632 case 'b':
633 case 'c':
634 case 'd':
635 case 'e':
636 case 'f':
637 /* no need to fix base here */
638 if (base <= 10) break; /* not legal here */
639 flags &= ~(SIGNOK | PFXOK | NDIGITS);
640 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800641
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700642 /* sign ok only as first character */
643 case '+':
644 case '-':
645 if (flags & SIGNOK) {
646 flags &= ~SIGNOK;
647 flags |= HAVESIGN;
648 goto ok;
649 }
650 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800651
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700652 /*
653 * x ok iff flag still set and 2nd char (or
654 * 3rd char if we have a sign).
655 */
656 case 'x':
657 case 'X':
658 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
659 base = 16; /* if %i */
660 flags &= ~PFXOK;
661 goto ok;
662 }
663 break;
664 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800665
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700666 /*
667 * If we got here, c is not a legal character
668 * for a number. Stop accumulating digits.
669 */
670 break;
671 ok:
672 /*
673 * c is legal: store it and look at the next.
674 */
675 *p++ = c;
676 if (--fp->_r > 0)
677 fp->_p++;
678 else if (__srefill(fp))
679 break; /* EOF */
680 }
681 /*
682 * If we had only a sign, it is no good; push
683 * back the sign. If the number ends in `x',
684 * it was [sign] '0' 'x', so push back the x
685 * and treat it as [sign] '0'.
686 */
687 if (flags & NDIGITS) {
688 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
689 goto match_failure;
690 }
691 c = ((u_char*)p)[-1];
692 if (c == 'x' || c == 'X') {
693 --p;
694 (void)ungetc(c, fp);
695 }
696 if ((flags & SUPPRESS) == 0) {
697 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800698
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700699 *p = '\0';
700 if (flags & UNSIGNED)
701 res = strtoumax(buf, NULL, base);
702 else
703 res = strtoimax(buf, NULL, base);
704 if (flags & POINTER)
705 *va_arg(ap, void**) = (void*)(uintptr_t)res;
706 else if (flags & MAXINT)
707 *va_arg(ap, intmax_t*) = res;
708 else if (flags & LLONG)
709 *va_arg(ap, long long*) = res;
710 else if (flags & SIZEINT)
711 *va_arg(ap, ssize_t*) = res;
712 else if (flags & PTRINT)
713 *va_arg(ap, ptrdiff_t*) = res;
714 else if (flags & LONG)
715 *va_arg(ap, long*) = res;
716 else if (flags & SHORT)
717 *va_arg(ap, short*) = res;
718 else if (flags & SHORTSHORT)
719 *va_arg(ap, signed char*) = res;
720 else
721 *va_arg(ap, int*) = res;
722 nassigned++;
723 }
724 nread += p - buf;
725 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800726
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700727 case CT_FLOAT:
728 /* scan a floating point number as if by strtod */
729 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
730 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
731 if ((flags & SUPPRESS) == 0) {
732 if (flags & LONGDBL) {
733 long double res = strtold(buf, &p);
734 *va_arg(ap, long double*) = res;
735 } else if (flags & LONG) {
736 double res = strtod(buf, &p);
737 *va_arg(ap, double*) = res;
738 } else {
739 float res = strtof(buf, &p);
740 *va_arg(ap, float*) = res;
741 }
742 if ((size_t)(p - buf) != width) abort();
743 nassigned++;
744 }
745 nread += width;
746 break;
747 }
748 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749input_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700750 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800751match_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700752 return (nassigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800753}
754
755/*
756 * Fill in the given table from the scanset at the given format
757 * (just after `['). Return a pointer to the character past the
758 * closing `]'. The table has a 1 wherever characters should be
759 * considered part of the scanset.
760 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700761static u_char* __sccl(char* tab, u_char* fmt) {
762 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800763
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700764 /* first `clear' the whole table */
765 c = *fmt++; /* first char hat => negated scanset */
766 if (c == '^') {
767 v = 1; /* default => accept */
768 c = *fmt++; /* get new first char */
769 } else
770 v = 0; /* default => reject */
771 /* should probably use memset here */
772 for (n = 0; n < 256; n++) tab[n] = v;
773 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800774
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700775 /*
776 * Now set the entries corresponding to the actual scanset
777 * to the opposite of the above.
778 *
779 * The first character may be ']' (or '-') without being special;
780 * the last character may be '-'.
781 */
782 v = 1 - v;
783 for (;;) {
784 tab[c] = v; /* take character c */
785 doswitch:
786 n = *fmt++; /* and examine the next */
787 switch (n) {
788 case 0: /* format ended too soon */
789 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800790
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700791 case '-':
792 /*
793 * A scanset of the form
794 * [01+-]
795 * is defined as `the digit 0, the digit 1,
796 * the character +, the character -', but
797 * the effect of a scanset such as
798 * [a-zA-Z0-9]
799 * is implementation defined. The V7 Unix
800 * scanf treats `a-z' as `the letters a through
801 * z', but treats `a-a' as `the letter a, the
802 * character -, and the letter a'.
803 *
804 * For compatibility, the `-' is not considerd
805 * to define a range if the character following
806 * it is either a close bracket (required by ANSI)
807 * or is not numerically greater than the character
808 * we just stored in the table (c).
809 */
810 n = *fmt;
811 if (n == ']' || n < c) {
812 c = '-';
813 break; /* resume the for(;;) */
814 }
815 fmt++;
816 do { /* fill in the range */
817 tab[++c] = v;
818 } while (c < n);
819#if 1 /* XXX another disgusting compatibility hack */
820 /*
821 * Alas, the V7 Unix scanf also treats formats
822 * such as [a-c-e] as `the letters a through e'.
823 * This too is permitted by the standard....
824 */
825 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800826#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700827 c = *fmt++;
828 if (c == 0) return (fmt - 1);
829 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800830#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700831 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800832
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700833 case ']': /* end of scanset */
834 return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800835
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700836 default: /* just another character */
837 c = n;
838 break;
839 }
840 }
841 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800842}
Elliott Hughes603332f2014-03-12 17:10:41 -0700843
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700844int vfscanf(FILE* fp, const char* fmt0, __va_list ap) {
845 int r;
Elliott Hughes603332f2014-03-12 17:10:41 -0700846
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700847 FLOCKFILE(fp);
848 r = __svfscanf(fp, fmt0, ap);
849 FUNLOCKFILE(fp);
850 return (r);
Elliott Hughes603332f2014-03-12 17:10:41 -0700851}