blob: c09132f3d3b09900f22b10a306bdd3725c6f1067 [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
Elliott Hughesc8f2c522017-10-31 13:07:51 -070044#define BUF 513 /* Maximum length of numeric string. */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080045
46/*
47 * Flags used during conversion.
48 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070049#define LONG 0x00001 /* l: long or double */
50#define LONGDBL 0x00002 /* L: long double */
51#define SHORT 0x00004 /* h: short */
52#define SHORTSHORT 0x00008 /* hh: 8 bit integer */
53#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
54#define POINTER 0x00020 /* p: void * (as hex) */
55#define SIZEINT 0x00040 /* z: (signed) size_t */
56#define MAXINT 0x00080 /* j: intmax_t */
57#define PTRINT 0x00100 /* t: ptrdiff_t */
58#define NOSKIP 0x00200 /* [ or c: do not skip blanks */
59#define SUPPRESS 0x00400 /* *: suppress assignment */
60#define UNSIGNED 0x00800 /* %[oupxX] conversions */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080061
62/*
63 * The following are used in numeric conversions only:
64 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
65 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
66 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070067#define SIGNOK 0x01000 /* +/- is (still) legal */
68#define HAVESIGN 0x02000 /* sign detected */
69#define NDIGITS 0x04000 /* no digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080070
Elliott Hughesc8f2c522017-10-31 13:07:51 -070071#define DPTOK 0x08000 /* (float) decimal point is still legal */
72#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080073
Elliott Hughesc8f2c522017-10-31 13:07:51 -070074#define PFXOK 0x08000 /* 0x prefix is (still) legal */
75#define NZDIGITS 0x10000 /* no zero digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076
77/*
78 * Conversion types.
79 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070080#define CT_CHAR 0 /* %c conversion */
81#define CT_CCL 1 /* %[...] conversion */
82#define CT_STRING 2 /* %s conversion */
83#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
84#define CT_FLOAT 4 /* floating, i.e., strtod */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080085
86#define u_char unsigned char
87#define u_long unsigned long
88
Elliott Hughesc8f2c522017-10-31 13:07:51 -070089static u_char* __sccl(char*, u_char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080090
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091/*
Elliott Hughes603332f2014-03-12 17:10:41 -070092 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080093 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070094int __svfscanf(FILE* fp, const char* fmt0, __va_list ap) {
95 u_char* fmt = (u_char*)fmt0;
96 int c; /* character from format, or conversion */
97 size_t width; /* field width, or 0 */
98 char* p; /* points into all kinds of strings */
99 int n; /* handy integer */
100 int flags; /* flags as defined above */
101 char* p0; /* saves original value of p when necessary */
102 int nassigned; /* number of fields assigned */
103 int nread; /* number of characters consumed from fp */
104 int base; /* base argument to strtoimax/strtouimax */
105 char ccltab[256]; /* character class table for %[...] */
106 char buf[BUF]; /* buffer for numeric conversions */
107 wchar_t* wcp; /* handy wide character pointer */
108 size_t nconv; /* length of multibyte sequence converted */
109 mbstate_t mbs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800110
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700111 /* `basefix' is used to avoid `if' tests in the integer scanner */
112 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 -0800113
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700114 _SET_ORIENTATION(fp, -1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700116 nassigned = 0;
117 nread = 0;
118 base = 0; /* XXX just to keep gcc happy */
119 for (;;) {
120 c = *fmt++;
121 if (c == 0) return (nassigned);
122 if (isspace(c)) {
123 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++;
124 continue;
125 }
126 if (c != '%') goto literal;
127 width = 0;
128 flags = 0;
129 /*
130 * switch on the format. continue if done;
131 * break once format type is derived.
132 */
133 again:
134 c = *fmt++;
135 switch (c) {
136 case '%':
137 literal:
138 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
139 if (*fp->_p != c) goto match_failure;
140 fp->_r--, fp->_p++;
141 nread++;
142 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800143
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700144 case '*':
145 flags |= SUPPRESS;
146 goto again;
147 case 'j':
148 flags |= MAXINT;
149 goto again;
150 case 'L':
151 flags |= LONGDBL;
152 goto again;
153 case 'h':
154 if (*fmt == 'h') {
155 fmt++;
156 flags |= SHORTSHORT;
157 } else {
158 flags |= SHORT;
159 }
160 goto again;
161 case 'l':
162 if (*fmt == 'l') {
163 fmt++;
164 flags |= LLONG;
165 } else {
166 flags |= LONG;
167 }
168 goto again;
169 case 'q':
170 flags |= LLONG; /* deprecated */
171 goto again;
172 case 't':
173 flags |= PTRINT;
174 goto again;
175 case 'z':
176 flags |= SIZEINT;
177 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800178
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700179 case '0':
180 case '1':
181 case '2':
182 case '3':
183 case '4':
184 case '5':
185 case '6':
186 case '7':
187 case '8':
188 case '9':
189 width = width * 10 + c - '0';
190 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700192 /*
193 * Conversions.
194 * Those marked `compat' are for 4.[123]BSD compatibility.
195 *
196 * (According to ANSI, E and X formats are supposed
197 * to the same as e and x. Sorry about that.)
198 */
199 case 'D': /* compat */
200 flags |= LONG;
201 /* FALLTHROUGH */
202 case 'd':
203 c = CT_INT;
204 base = 10;
205 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700207 case 'i':
208 c = CT_INT;
209 base = 0;
210 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800211
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700212 case 'O': /* compat */
213 flags |= LONG;
214 /* FALLTHROUGH */
215 case 'o':
216 c = CT_INT;
217 flags |= UNSIGNED;
218 base = 8;
219 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700221 case 'u':
222 c = CT_INT;
223 flags |= UNSIGNED;
224 base = 10;
225 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800226
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700227 case 'X':
228 case 'x':
229 flags |= PFXOK; /* enable 0x prefixing */
230 c = CT_INT;
231 flags |= UNSIGNED;
232 base = 16;
233 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800234
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700235 case 'e':
236 case 'E':
237 case 'f':
238 case 'F':
239 case 'g':
240 case 'G':
241 case 'a':
242 case 'A':
243 c = CT_FLOAT;
244 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800245
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700246 case 's':
247 c = CT_STRING;
248 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800249
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700250 case '[':
251 fmt = __sccl(ccltab, fmt);
252 flags |= NOSKIP;
253 c = CT_CCL;
254 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700256 case 'c':
257 flags |= NOSKIP;
258 c = CT_CHAR;
259 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800260
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700261 case 'p': /* pointer format is like hex */
262 flags |= POINTER | PFXOK;
263 c = CT_INT;
264 flags |= UNSIGNED;
265 base = 16;
266 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800267
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700268 case 'n':
269 if (flags & SUPPRESS) continue;
270 if (flags & SHORTSHORT)
271 *va_arg(ap, signed char*) = nread;
272 else if (flags & SHORT)
273 *va_arg(ap, short*) = nread;
274 else if (flags & LONG)
275 *va_arg(ap, long*) = nread;
276 else if (flags & SIZEINT)
277 *va_arg(ap, ssize_t*) = nread;
278 else if (flags & PTRINT)
279 *va_arg(ap, ptrdiff_t*) = nread;
280 else if (flags & LLONG)
281 *va_arg(ap, long long*) = nread;
282 else if (flags & MAXINT)
283 *va_arg(ap, intmax_t*) = nread;
284 else
285 *va_arg(ap, int*) = nread;
286 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700288 /*
289 * Disgusting backwards compatibility hacks. XXX
290 */
291 case '\0': /* compat */
292 return (EOF);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800293
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700294 default: /* compat */
295 if (isupper(c)) flags |= LONG;
296 c = CT_INT;
297 base = 10;
298 break;
299 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800300
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700301 /*
302 * We have a conversion that requires input.
303 */
304 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800305
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700306 /*
307 * Consume leading white space, except for formats
308 * that suppress this.
309 */
310 if ((flags & NOSKIP) == 0) {
311 while (isspace(*fp->_p)) {
312 nread++;
313 if (--fp->_r > 0)
314 fp->_p++;
315 else if (__srefill(fp))
316 goto input_failure;
317 }
318 /*
319 * Note that there is at least one character in
320 * the buffer, so conversions that do not set NOSKIP
321 * ca no longer result in an input failure.
322 */
323 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800324
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700325 /*
326 * Do the conversion.
327 */
328 switch (c) {
329 case CT_CHAR:
330 /* scan arbitrary characters (sets NOSKIP) */
331 if (width == 0) width = 1;
332 if (flags & LONG) {
333 if ((flags & SUPPRESS) == 0)
334 wcp = va_arg(ap, wchar_t*);
335 else
336 wcp = NULL;
337 n = 0;
338 while (width != 0) {
339 if (n == (int)MB_CUR_MAX) {
340 fp->_flags |= __SERR;
341 goto input_failure;
342 }
343 buf[n++] = *fp->_p;
344 fp->_p++;
345 fp->_r--;
346 memset(&mbs, 0, sizeof(mbs));
347 nconv = mbrtowc(wcp, buf, n, &mbs);
348 if (nconv == (size_t)-1) {
349 fp->_flags |= __SERR;
350 goto input_failure;
351 }
352 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
353 if (nconv != (size_t)-2) {
354 nread += n;
355 width--;
356 if (!(flags & SUPPRESS)) wcp++;
357 n = 0;
358 }
359 if (fp->_r <= 0 && __srefill(fp)) {
360 if (n != 0) {
361 fp->_flags |= __SERR;
362 goto input_failure;
363 }
364 break;
365 }
366 }
367 if (!(flags & SUPPRESS)) nassigned++;
368 } else if (flags & SUPPRESS) {
369 size_t sum = 0;
370 for (;;) {
371 if ((n = fp->_r) < (int)width) {
372 sum += n;
373 width -= n;
374 fp->_p += n;
375 if (__srefill(fp)) {
376 if (sum == 0) goto input_failure;
377 break;
378 }
379 } else {
380 sum += width;
381 fp->_r -= width;
382 fp->_p += width;
383 break;
384 }
385 }
386 nread += sum;
387 } else {
388 size_t r = fread((void*)va_arg(ap, char*), 1, width, fp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800389
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700390 if (r == 0) goto input_failure;
391 nread += r;
392 nassigned++;
393 }
394 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800395
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700396 case CT_CCL:
397 /* scan a (nonempty) character class (sets NOSKIP) */
398 if (width == 0) width = (size_t)~0; /* `infinity' */
399 /* take only those things in the class */
400 if (flags & LONG) {
401 wchar_t twc;
402 int nchars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800403
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700404 if ((flags & SUPPRESS) == 0)
405 wcp = va_arg(ap, wchar_t*);
406 else
407 wcp = &twc;
408 n = 0;
409 nchars = 0;
410 while (width != 0) {
411 if (n == (int)MB_CUR_MAX) {
412 fp->_flags |= __SERR;
413 goto input_failure;
414 }
415 buf[n++] = *fp->_p;
416 fp->_p++;
417 fp->_r--;
418 memset(&mbs, 0, sizeof(mbs));
419 nconv = mbrtowc(wcp, buf, n, &mbs);
420 if (nconv == (size_t)-1) {
421 fp->_flags |= __SERR;
422 goto input_failure;
423 }
424 if (nconv == 0) *wcp = L'\0';
425 if (nconv != (size_t)-2) {
426 if (wctob(*wcp) != EOF && !ccltab[wctob(*wcp)]) {
427 while (n != 0) {
428 n--;
429 ungetc(buf[n], fp);
430 }
431 break;
432 }
433 nread += n;
434 width--;
435 if (!(flags & SUPPRESS)) wcp++;
436 nchars++;
437 n = 0;
438 }
439 if (fp->_r <= 0 && __srefill(fp)) {
440 if (n != 0) {
441 fp->_flags |= __SERR;
442 goto input_failure;
443 }
444 break;
445 }
446 }
447 if (n != 0) {
448 fp->_flags |= __SERR;
449 goto input_failure;
450 }
451 n = nchars;
452 if (n == 0) goto match_failure;
453 if (!(flags & SUPPRESS)) {
454 *wcp = L'\0';
455 nassigned++;
456 }
457 } else
458 /* take only those things in the class */
459 if (flags & SUPPRESS) {
460 n = 0;
461 while (ccltab[*fp->_p]) {
462 n++, fp->_r--, fp->_p++;
463 if (--width == 0) break;
464 if (fp->_r <= 0 && __srefill(fp)) {
465 if (n == 0) goto input_failure;
466 break;
467 }
468 }
469 if (n == 0) goto match_failure;
470 } else {
471 p0 = p = va_arg(ap, char*);
472 while (ccltab[*fp->_p]) {
473 fp->_r--;
474 *p++ = *fp->_p++;
475 if (--width == 0) break;
476 if (fp->_r <= 0 && __srefill(fp)) {
477 if (p == p0) goto input_failure;
478 break;
479 }
480 }
481 n = p - p0;
482 if (n == 0) goto match_failure;
483 *p = '\0';
484 nassigned++;
485 }
486 nread += n;
487 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700488
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700489 case CT_STRING:
490 /* like CCL, but zero-length string OK, & no NOSKIP */
491 if (width == 0) width = (size_t)~0;
492 if (flags & LONG) {
493 wchar_t twc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800494
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700495 if ((flags & SUPPRESS) == 0)
496 wcp = va_arg(ap, wchar_t*);
497 else
498 wcp = &twc;
499 n = 0;
500 while (!isspace(*fp->_p) && width != 0) {
501 if (n == (int)MB_CUR_MAX) {
502 fp->_flags |= __SERR;
503 goto input_failure;
504 }
505 buf[n++] = *fp->_p;
506 fp->_p++;
507 fp->_r--;
508 memset(&mbs, 0, sizeof(mbs));
509 nconv = mbrtowc(wcp, buf, n, &mbs);
510 if (nconv == (size_t)-1) {
511 fp->_flags |= __SERR;
512 goto input_failure;
513 }
514 if (nconv == 0) *wcp = L'\0';
515 if (nconv != (size_t)-2) {
516 if (iswspace(*wcp)) {
517 while (n != 0) {
518 n--;
519 ungetc(buf[n], fp);
520 }
521 break;
522 }
523 nread += n;
524 width--;
525 if (!(flags & SUPPRESS)) wcp++;
526 n = 0;
527 }
528 if (fp->_r <= 0 && __srefill(fp)) {
529 if (n != 0) {
530 fp->_flags |= __SERR;
531 goto input_failure;
532 }
533 break;
534 }
535 }
536 if (!(flags & SUPPRESS)) {
537 *wcp = L'\0';
538 nassigned++;
539 }
540 } else if (flags & SUPPRESS) {
541 n = 0;
542 while (!isspace(*fp->_p)) {
543 n++, fp->_r--, fp->_p++;
544 if (--width == 0) break;
545 if (fp->_r <= 0 && __srefill(fp)) break;
546 }
547 nread += n;
548 } else {
549 p0 = p = va_arg(ap, char*);
550 while (!isspace(*fp->_p)) {
551 fp->_r--;
552 *p++ = *fp->_p++;
553 if (--width == 0) break;
554 if (fp->_r <= 0 && __srefill(fp)) break;
555 }
556 *p = '\0';
557 nread += p - p0;
558 nassigned++;
559 }
560 continue;
Elliott Hughes603332f2014-03-12 17:10:41 -0700561
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700562 case CT_INT:
563 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800564#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700565 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800566#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700567 /* size_t is unsigned, hence this optimisation */
568 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
569 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800570#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700571 flags |= SIGNOK | NDIGITS | NZDIGITS;
572 for (p = buf; width; width--) {
573 c = *fp->_p;
574 /*
575 * Switch on the character; `goto ok'
576 * if we accept it as a part of number.
577 */
578 switch (c) {
579 /*
580 * The digit 0 is always legal, but is
581 * special. For %i conversions, if no
582 * digits (zero or nonzero) have been
583 * scanned (only signs), we will have
584 * base==0. In that case, we should set
585 * it to 8 and enable 0x prefixing.
586 * Also, if we have not scanned zero digits
587 * before this, do not turn off prefixing
588 * (someone else will turn it off if we
589 * have scanned any nonzero digits).
590 */
591 case '0':
592 if (base == 0) {
593 base = 8;
594 flags |= PFXOK;
595 }
596 if (flags & NZDIGITS)
597 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
598 else
599 flags &= ~(SIGNOK | PFXOK | NDIGITS);
600 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800601
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700602 /* 1 through 7 always legal */
603 case '1':
604 case '2':
605 case '3':
606 case '4':
607 case '5':
608 case '6':
609 case '7':
610 base = basefix[base];
611 flags &= ~(SIGNOK | PFXOK | NDIGITS);
612 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800613
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700614 /* digits 8 and 9 ok iff decimal or hex */
615 case '8':
616 case '9':
617 base = basefix[base];
618 if (base <= 8) break; /* not legal here */
619 flags &= ~(SIGNOK | PFXOK | NDIGITS);
620 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800621
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700622 /* letters ok iff hex */
623 case 'A':
624 case 'B':
625 case 'C':
626 case 'D':
627 case 'E':
628 case 'F':
629 case 'a':
630 case 'b':
631 case 'c':
632 case 'd':
633 case 'e':
634 case 'f':
635 /* no need to fix base here */
636 if (base <= 10) break; /* not legal here */
637 flags &= ~(SIGNOK | PFXOK | NDIGITS);
638 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800639
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700640 /* sign ok only as first character */
641 case '+':
642 case '-':
643 if (flags & SIGNOK) {
644 flags &= ~SIGNOK;
645 flags |= HAVESIGN;
646 goto ok;
647 }
648 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800649
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700650 /*
651 * x ok iff flag still set and 2nd char (or
652 * 3rd char if we have a sign).
653 */
654 case 'x':
655 case 'X':
656 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
657 base = 16; /* if %i */
658 flags &= ~PFXOK;
659 goto ok;
660 }
661 break;
662 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800663
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700664 /*
665 * If we got here, c is not a legal character
666 * for a number. Stop accumulating digits.
667 */
668 break;
669 ok:
670 /*
671 * c is legal: store it and look at the next.
672 */
673 *p++ = c;
674 if (--fp->_r > 0)
675 fp->_p++;
676 else if (__srefill(fp))
677 break; /* EOF */
678 }
679 /*
680 * If we had only a sign, it is no good; push
681 * back the sign. If the number ends in `x',
682 * it was [sign] '0' 'x', so push back the x
683 * and treat it as [sign] '0'.
684 */
685 if (flags & NDIGITS) {
686 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
687 goto match_failure;
688 }
689 c = ((u_char*)p)[-1];
690 if (c == 'x' || c == 'X') {
691 --p;
692 (void)ungetc(c, fp);
693 }
694 if ((flags & SUPPRESS) == 0) {
695 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800696
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700697 *p = '\0';
698 if (flags & UNSIGNED)
699 res = strtoumax(buf, NULL, base);
700 else
701 res = strtoimax(buf, NULL, base);
702 if (flags & POINTER)
703 *va_arg(ap, void**) = (void*)(uintptr_t)res;
704 else if (flags & MAXINT)
705 *va_arg(ap, intmax_t*) = res;
706 else if (flags & LLONG)
707 *va_arg(ap, long long*) = res;
708 else if (flags & SIZEINT)
709 *va_arg(ap, ssize_t*) = res;
710 else if (flags & PTRINT)
711 *va_arg(ap, ptrdiff_t*) = res;
712 else if (flags & LONG)
713 *va_arg(ap, long*) = res;
714 else if (flags & SHORT)
715 *va_arg(ap, short*) = res;
716 else if (flags & SHORTSHORT)
717 *va_arg(ap, signed char*) = res;
718 else
719 *va_arg(ap, int*) = res;
720 nassigned++;
721 }
722 nread += p - buf;
723 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800724
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700725 case CT_FLOAT:
726 /* scan a floating point number as if by strtod */
727 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
728 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
729 if ((flags & SUPPRESS) == 0) {
730 if (flags & LONGDBL) {
731 long double res = strtold(buf, &p);
732 *va_arg(ap, long double*) = res;
733 } else if (flags & LONG) {
734 double res = strtod(buf, &p);
735 *va_arg(ap, double*) = res;
736 } else {
737 float res = strtof(buf, &p);
738 *va_arg(ap, float*) = res;
739 }
740 if ((size_t)(p - buf) != width) abort();
741 nassigned++;
742 }
743 nread += width;
744 break;
745 }
746 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800747input_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700748 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749match_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700750 return (nassigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800751}
752
753/*
754 * Fill in the given table from the scanset at the given format
755 * (just after `['). Return a pointer to the character past the
756 * closing `]'. The table has a 1 wherever characters should be
757 * considered part of the scanset.
758 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700759static u_char* __sccl(char* tab, u_char* fmt) {
760 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800761
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700762 /* first `clear' the whole table */
763 c = *fmt++; /* first char hat => negated scanset */
764 if (c == '^') {
765 v = 1; /* default => accept */
766 c = *fmt++; /* get new first char */
767 } else
768 v = 0; /* default => reject */
769 /* should probably use memset here */
770 for (n = 0; n < 256; n++) tab[n] = v;
771 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800772
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700773 /*
774 * Now set the entries corresponding to the actual scanset
775 * to the opposite of the above.
776 *
777 * The first character may be ']' (or '-') without being special;
778 * the last character may be '-'.
779 */
780 v = 1 - v;
781 for (;;) {
782 tab[c] = v; /* take character c */
783 doswitch:
784 n = *fmt++; /* and examine the next */
785 switch (n) {
786 case 0: /* format ended too soon */
787 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800788
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700789 case '-':
790 /*
791 * A scanset of the form
792 * [01+-]
793 * is defined as `the digit 0, the digit 1,
794 * the character +, the character -', but
795 * the effect of a scanset such as
796 * [a-zA-Z0-9]
797 * is implementation defined. The V7 Unix
798 * scanf treats `a-z' as `the letters a through
799 * z', but treats `a-a' as `the letter a, the
800 * character -, and the letter a'.
801 *
802 * For compatibility, the `-' is not considerd
803 * to define a range if the character following
804 * it is either a close bracket (required by ANSI)
805 * or is not numerically greater than the character
806 * we just stored in the table (c).
807 */
808 n = *fmt;
809 if (n == ']' || n < c) {
810 c = '-';
811 break; /* resume the for(;;) */
812 }
813 fmt++;
814 do { /* fill in the range */
815 tab[++c] = v;
816 } while (c < n);
817#if 1 /* XXX another disgusting compatibility hack */
818 /*
819 * Alas, the V7 Unix scanf also treats formats
820 * such as [a-c-e] as `the letters a through e'.
821 * This too is permitted by the standard....
822 */
823 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800824#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700825 c = *fmt++;
826 if (c == 0) return (fmt - 1);
827 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800828#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700829 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800830
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700831 case ']': /* end of scanset */
832 return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800833
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700834 default: /* just another character */
835 c = n;
836 break;
837 }
838 }
839 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800840}
Elliott Hughes603332f2014-03-12 17:10:41 -0700841
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700842int vfscanf(FILE* fp, const char* fmt0, __va_list ap) {
843 int r;
Elliott Hughes603332f2014-03-12 17:10:41 -0700844
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700845 FLOCKFILE(fp);
846 r = __svfscanf(fp, fmt0, ap);
847 FUNLOCKFILE(fp);
848 return (r);
Elliott Hughes603332f2014-03-12 17:10:41 -0700849}