blob: 887b4350d423d9af6740ae625b026e5b5944d017 [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
Elliott Hughesc8f2c522017-10-31 13:07:51 -070086static u_char* __sccl(char*, u_char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088/*
Elliott Hughes603332f2014-03-12 17:10:41 -070089 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080090 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070091int __svfscanf(FILE* fp, const char* fmt0, __va_list ap) {
92 u_char* fmt = (u_char*)fmt0;
93 int c; /* character from format, or conversion */
94 size_t width; /* field width, or 0 */
95 char* p; /* points into all kinds of strings */
96 int n; /* handy integer */
97 int flags; /* flags as defined above */
98 char* p0; /* saves original value of p when necessary */
99 int nassigned; /* number of fields assigned */
100 int nread; /* number of characters consumed from fp */
101 int base; /* base argument to strtoimax/strtouimax */
102 char ccltab[256]; /* character class table for %[...] */
103 char buf[BUF]; /* buffer for numeric conversions */
104 wchar_t* wcp; /* handy wide character pointer */
105 size_t nconv; /* length of multibyte sequence converted */
106 mbstate_t mbs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700108 /* `basefix' is used to avoid `if' tests in the integer scanner */
109 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 -0800110
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700111 _SET_ORIENTATION(fp, -1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700113 nassigned = 0;
114 nread = 0;
115 base = 0; /* XXX just to keep gcc happy */
116 for (;;) {
117 c = *fmt++;
118 if (c == 0) return (nassigned);
119 if (isspace(c)) {
120 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++;
121 continue;
122 }
123 if (c != '%') goto literal;
124 width = 0;
125 flags = 0;
126 /*
127 * switch on the format. continue if done;
128 * break once format type is derived.
129 */
130 again:
131 c = *fmt++;
132 switch (c) {
133 case '%':
134 literal:
135 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
136 if (*fp->_p != c) goto match_failure;
137 fp->_r--, fp->_p++;
138 nread++;
139 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800140
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700141 case '*':
142 flags |= SUPPRESS;
143 goto again;
144 case 'j':
145 flags |= MAXINT;
146 goto again;
147 case 'L':
148 flags |= LONGDBL;
149 goto again;
150 case 'h':
151 if (*fmt == 'h') {
152 fmt++;
153 flags |= SHORTSHORT;
154 } else {
155 flags |= SHORT;
156 }
157 goto again;
158 case 'l':
159 if (*fmt == 'l') {
160 fmt++;
161 flags |= LLONG;
162 } else {
163 flags |= LONG;
164 }
165 goto again;
166 case 'q':
167 flags |= LLONG; /* deprecated */
168 goto again;
169 case 't':
170 flags |= PTRINT;
171 goto again;
172 case 'z':
173 flags |= SIZEINT;
174 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800175
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700176 case '0':
177 case '1':
178 case '2':
179 case '3':
180 case '4':
181 case '5':
182 case '6':
183 case '7':
184 case '8':
185 case '9':
186 width = width * 10 + c - '0';
187 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800188
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700189 /*
190 * Conversions.
191 * Those marked `compat' are for 4.[123]BSD compatibility.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700192 */
193 case 'D': /* compat */
194 flags |= LONG;
195 /* FALLTHROUGH */
196 case 'd':
197 c = CT_INT;
198 base = 10;
199 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800200
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700201 case 'i':
202 c = CT_INT;
203 base = 0;
204 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800205
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700206 case 'O': /* compat */
207 flags |= LONG;
208 /* FALLTHROUGH */
209 case 'o':
210 c = CT_INT;
211 flags |= UNSIGNED;
212 base = 8;
213 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800214
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700215 case 'u':
216 c = CT_INT;
217 flags |= UNSIGNED;
218 base = 10;
219 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700221 case 'X':
222 case 'x':
223 flags |= PFXOK; /* enable 0x prefixing */
224 c = CT_INT;
225 flags |= UNSIGNED;
226 base = 16;
227 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800228
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700229 case 'e':
230 case 'E':
231 case 'f':
232 case 'F':
233 case 'g':
234 case 'G':
235 case 'a':
236 case 'A':
237 c = CT_FLOAT;
238 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800239
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700240 case 's':
241 c = CT_STRING;
242 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800243
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700244 case '[':
245 fmt = __sccl(ccltab, fmt);
246 flags |= NOSKIP;
247 c = CT_CCL;
248 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800249
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700250 case 'c':
251 flags |= NOSKIP;
252 c = CT_CHAR;
253 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800254
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700255 case 'p': /* pointer format is like hex */
256 flags |= POINTER | PFXOK;
257 c = CT_INT;
258 flags |= UNSIGNED;
259 base = 16;
260 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800261
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700262 case 'n':
263 if (flags & SUPPRESS) continue;
264 if (flags & SHORTSHORT)
265 *va_arg(ap, signed char*) = nread;
266 else if (flags & SHORT)
267 *va_arg(ap, short*) = nread;
268 else if (flags & LONG)
269 *va_arg(ap, long*) = nread;
270 else if (flags & SIZEINT)
271 *va_arg(ap, ssize_t*) = nread;
272 else if (flags & PTRINT)
273 *va_arg(ap, ptrdiff_t*) = nread;
274 else if (flags & LLONG)
275 *va_arg(ap, long long*) = nread;
276 else if (flags & MAXINT)
277 *va_arg(ap, intmax_t*) = nread;
278 else
279 *va_arg(ap, int*) = nread;
280 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800281
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700282 /*
283 * Disgusting backwards compatibility hacks. XXX
284 */
285 case '\0': /* compat */
286 return (EOF);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700288 default: /* compat */
289 if (isupper(c)) flags |= LONG;
290 c = CT_INT;
291 base = 10;
292 break;
293 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800294
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700295 /*
296 * We have a conversion that requires input.
297 */
298 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800299
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700300 /*
301 * Consume leading white space, except for formats
302 * that suppress this.
303 */
304 if ((flags & NOSKIP) == 0) {
305 while (isspace(*fp->_p)) {
306 nread++;
307 if (--fp->_r > 0)
308 fp->_p++;
309 else if (__srefill(fp))
310 goto input_failure;
311 }
312 /*
313 * Note that there is at least one character in
314 * the buffer, so conversions that do not set NOSKIP
315 * ca no longer result in an input failure.
316 */
317 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800318
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700319 /*
320 * Do the conversion.
321 */
322 switch (c) {
323 case CT_CHAR:
324 /* scan arbitrary characters (sets NOSKIP) */
325 if (width == 0) width = 1;
326 if (flags & LONG) {
327 if ((flags & SUPPRESS) == 0)
328 wcp = va_arg(ap, wchar_t*);
329 else
330 wcp = NULL;
331 n = 0;
332 while (width != 0) {
333 if (n == (int)MB_CUR_MAX) {
334 fp->_flags |= __SERR;
335 goto input_failure;
336 }
337 buf[n++] = *fp->_p;
338 fp->_p++;
339 fp->_r--;
340 memset(&mbs, 0, sizeof(mbs));
341 nconv = mbrtowc(wcp, buf, n, &mbs);
342 if (nconv == (size_t)-1) {
343 fp->_flags |= __SERR;
344 goto input_failure;
345 }
346 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
347 if (nconv != (size_t)-2) {
348 nread += n;
349 width--;
350 if (!(flags & SUPPRESS)) wcp++;
351 n = 0;
352 }
353 if (fp->_r <= 0 && __srefill(fp)) {
354 if (n != 0) {
355 fp->_flags |= __SERR;
356 goto input_failure;
357 }
358 break;
359 }
360 }
361 if (!(flags & SUPPRESS)) nassigned++;
362 } else if (flags & SUPPRESS) {
363 size_t sum = 0;
364 for (;;) {
365 if ((n = fp->_r) < (int)width) {
366 sum += n;
367 width -= n;
368 fp->_p += n;
369 if (__srefill(fp)) {
370 if (sum == 0) goto input_failure;
371 break;
372 }
373 } else {
374 sum += width;
375 fp->_r -= width;
376 fp->_p += width;
377 break;
378 }
379 }
380 nread += sum;
381 } else {
382 size_t r = fread((void*)va_arg(ap, char*), 1, width, fp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800383
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700384 if (r == 0) goto input_failure;
385 nread += r;
386 nassigned++;
387 }
388 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800389
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700390 case CT_CCL:
391 /* scan a (nonempty) character class (sets NOSKIP) */
392 if (width == 0) width = (size_t)~0; /* `infinity' */
393 /* take only those things in the class */
394 if (flags & LONG) {
395 wchar_t twc;
396 int nchars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800397
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700398 if ((flags & SUPPRESS) == 0)
399 wcp = va_arg(ap, wchar_t*);
400 else
401 wcp = &twc;
402 n = 0;
403 nchars = 0;
404 while (width != 0) {
405 if (n == (int)MB_CUR_MAX) {
406 fp->_flags |= __SERR;
407 goto input_failure;
408 }
409 buf[n++] = *fp->_p;
410 fp->_p++;
411 fp->_r--;
412 memset(&mbs, 0, sizeof(mbs));
413 nconv = mbrtowc(wcp, buf, n, &mbs);
414 if (nconv == (size_t)-1) {
415 fp->_flags |= __SERR;
416 goto input_failure;
417 }
418 if (nconv == 0) *wcp = L'\0';
419 if (nconv != (size_t)-2) {
420 if (wctob(*wcp) != EOF && !ccltab[wctob(*wcp)]) {
421 while (n != 0) {
422 n--;
423 ungetc(buf[n], fp);
424 }
425 break;
426 }
427 nread += n;
428 width--;
429 if (!(flags & SUPPRESS)) wcp++;
430 nchars++;
431 n = 0;
432 }
433 if (fp->_r <= 0 && __srefill(fp)) {
434 if (n != 0) {
435 fp->_flags |= __SERR;
436 goto input_failure;
437 }
438 break;
439 }
440 }
441 if (n != 0) {
442 fp->_flags |= __SERR;
443 goto input_failure;
444 }
445 n = nchars;
446 if (n == 0) goto match_failure;
447 if (!(flags & SUPPRESS)) {
448 *wcp = L'\0';
449 nassigned++;
450 }
451 } else
452 /* take only those things in the class */
453 if (flags & SUPPRESS) {
454 n = 0;
455 while (ccltab[*fp->_p]) {
456 n++, fp->_r--, fp->_p++;
457 if (--width == 0) break;
458 if (fp->_r <= 0 && __srefill(fp)) {
459 if (n == 0) goto input_failure;
460 break;
461 }
462 }
463 if (n == 0) goto match_failure;
464 } else {
465 p0 = p = va_arg(ap, char*);
466 while (ccltab[*fp->_p]) {
467 fp->_r--;
468 *p++ = *fp->_p++;
469 if (--width == 0) break;
470 if (fp->_r <= 0 && __srefill(fp)) {
471 if (p == p0) goto input_failure;
472 break;
473 }
474 }
475 n = p - p0;
476 if (n == 0) goto match_failure;
477 *p = '\0';
478 nassigned++;
479 }
480 nread += n;
481 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700482
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700483 case CT_STRING:
484 /* like CCL, but zero-length string OK, & no NOSKIP */
485 if (width == 0) width = (size_t)~0;
486 if (flags & LONG) {
487 wchar_t twc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800488
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700489 if ((flags & SUPPRESS) == 0)
490 wcp = va_arg(ap, wchar_t*);
491 else
492 wcp = &twc;
493 n = 0;
494 while (!isspace(*fp->_p) && width != 0) {
495 if (n == (int)MB_CUR_MAX) {
496 fp->_flags |= __SERR;
497 goto input_failure;
498 }
499 buf[n++] = *fp->_p;
500 fp->_p++;
501 fp->_r--;
502 memset(&mbs, 0, sizeof(mbs));
503 nconv = mbrtowc(wcp, buf, n, &mbs);
504 if (nconv == (size_t)-1) {
505 fp->_flags |= __SERR;
506 goto input_failure;
507 }
508 if (nconv == 0) *wcp = L'\0';
509 if (nconv != (size_t)-2) {
510 if (iswspace(*wcp)) {
511 while (n != 0) {
512 n--;
513 ungetc(buf[n], fp);
514 }
515 break;
516 }
517 nread += n;
518 width--;
519 if (!(flags & SUPPRESS)) wcp++;
520 n = 0;
521 }
522 if (fp->_r <= 0 && __srefill(fp)) {
523 if (n != 0) {
524 fp->_flags |= __SERR;
525 goto input_failure;
526 }
527 break;
528 }
529 }
530 if (!(flags & SUPPRESS)) {
531 *wcp = L'\0';
532 nassigned++;
533 }
534 } else if (flags & SUPPRESS) {
535 n = 0;
536 while (!isspace(*fp->_p)) {
537 n++, fp->_r--, fp->_p++;
538 if (--width == 0) break;
539 if (fp->_r <= 0 && __srefill(fp)) break;
540 }
541 nread += n;
542 } else {
543 p0 = p = va_arg(ap, char*);
544 while (!isspace(*fp->_p)) {
545 fp->_r--;
546 *p++ = *fp->_p++;
547 if (--width == 0) break;
548 if (fp->_r <= 0 && __srefill(fp)) break;
549 }
550 *p = '\0';
551 nread += p - p0;
552 nassigned++;
553 }
554 continue;
Elliott Hughes603332f2014-03-12 17:10:41 -0700555
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700556 case CT_INT:
557 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800558#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700559 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800560#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700561 /* size_t is unsigned, hence this optimisation */
562 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
563 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800564#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700565 flags |= SIGNOK | NDIGITS | NZDIGITS;
566 for (p = buf; width; width--) {
567 c = *fp->_p;
568 /*
569 * Switch on the character; `goto ok'
570 * if we accept it as a part of number.
571 */
572 switch (c) {
573 /*
574 * The digit 0 is always legal, but is
575 * special. For %i conversions, if no
576 * digits (zero or nonzero) have been
577 * scanned (only signs), we will have
578 * base==0. In that case, we should set
579 * it to 8 and enable 0x prefixing.
580 * Also, if we have not scanned zero digits
581 * before this, do not turn off prefixing
582 * (someone else will turn it off if we
583 * have scanned any nonzero digits).
584 */
585 case '0':
586 if (base == 0) {
587 base = 8;
588 flags |= PFXOK;
589 }
590 if (flags & NZDIGITS)
591 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
592 else
593 flags &= ~(SIGNOK | PFXOK | NDIGITS);
594 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800595
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700596 /* 1 through 7 always legal */
597 case '1':
598 case '2':
599 case '3':
600 case '4':
601 case '5':
602 case '6':
603 case '7':
604 base = basefix[base];
605 flags &= ~(SIGNOK | PFXOK | NDIGITS);
606 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800607
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700608 /* digits 8 and 9 ok iff decimal or hex */
609 case '8':
610 case '9':
611 base = basefix[base];
612 if (base <= 8) break; /* not legal here */
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 /* letters ok iff hex */
617 case 'A':
618 case 'B':
619 case 'C':
620 case 'D':
621 case 'E':
622 case 'F':
623 case 'a':
624 case 'b':
625 case 'c':
626 case 'd':
627 case 'e':
628 case 'f':
629 /* no need to fix base here */
630 if (base <= 10) break; /* not legal here */
631 flags &= ~(SIGNOK | PFXOK | NDIGITS);
632 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800633
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700634 /* sign ok only as first character */
635 case '+':
636 case '-':
637 if (flags & SIGNOK) {
638 flags &= ~SIGNOK;
639 flags |= HAVESIGN;
640 goto ok;
641 }
642 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800643
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700644 /*
645 * x ok iff flag still set and 2nd char (or
646 * 3rd char if we have a sign).
647 */
648 case 'x':
649 case 'X':
650 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
651 base = 16; /* if %i */
652 flags &= ~PFXOK;
653 goto ok;
654 }
655 break;
656 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800657
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700658 /*
659 * If we got here, c is not a legal character
660 * for a number. Stop accumulating digits.
661 */
662 break;
663 ok:
664 /*
665 * c is legal: store it and look at the next.
666 */
667 *p++ = c;
668 if (--fp->_r > 0)
669 fp->_p++;
670 else if (__srefill(fp))
671 break; /* EOF */
672 }
673 /*
674 * If we had only a sign, it is no good; push
675 * back the sign. If the number ends in `x',
676 * it was [sign] '0' 'x', so push back the x
677 * and treat it as [sign] '0'.
678 */
679 if (flags & NDIGITS) {
680 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
681 goto match_failure;
682 }
683 c = ((u_char*)p)[-1];
684 if (c == 'x' || c == 'X') {
685 --p;
686 (void)ungetc(c, fp);
687 }
688 if ((flags & SUPPRESS) == 0) {
689 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800690
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700691 *p = '\0';
692 if (flags & UNSIGNED)
693 res = strtoumax(buf, NULL, base);
694 else
695 res = strtoimax(buf, NULL, base);
696 if (flags & POINTER)
697 *va_arg(ap, void**) = (void*)(uintptr_t)res;
698 else if (flags & MAXINT)
699 *va_arg(ap, intmax_t*) = res;
700 else if (flags & LLONG)
701 *va_arg(ap, long long*) = res;
702 else if (flags & SIZEINT)
703 *va_arg(ap, ssize_t*) = res;
704 else if (flags & PTRINT)
705 *va_arg(ap, ptrdiff_t*) = res;
706 else if (flags & LONG)
707 *va_arg(ap, long*) = res;
708 else if (flags & SHORT)
709 *va_arg(ap, short*) = res;
710 else if (flags & SHORTSHORT)
711 *va_arg(ap, signed char*) = res;
712 else
713 *va_arg(ap, int*) = res;
714 nassigned++;
715 }
716 nread += p - buf;
717 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800718
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700719 case CT_FLOAT:
720 /* scan a floating point number as if by strtod */
721 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
722 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
723 if ((flags & SUPPRESS) == 0) {
724 if (flags & LONGDBL) {
725 long double res = strtold(buf, &p);
726 *va_arg(ap, long double*) = res;
727 } else if (flags & LONG) {
728 double res = strtod(buf, &p);
729 *va_arg(ap, double*) = res;
730 } else {
731 float res = strtof(buf, &p);
732 *va_arg(ap, float*) = res;
733 }
734 if ((size_t)(p - buf) != width) abort();
735 nassigned++;
736 }
737 nread += width;
738 break;
739 }
740 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800741input_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700742 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800743match_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700744 return (nassigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800745}
746
747/*
748 * Fill in the given table from the scanset at the given format
749 * (just after `['). Return a pointer to the character past the
750 * closing `]'. The table has a 1 wherever characters should be
751 * considered part of the scanset.
752 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700753static u_char* __sccl(char* tab, u_char* fmt) {
754 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800755
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700756 /* first `clear' the whole table */
757 c = *fmt++; /* first char hat => negated scanset */
758 if (c == '^') {
759 v = 1; /* default => accept */
760 c = *fmt++; /* get new first char */
761 } else
762 v = 0; /* default => reject */
763 /* should probably use memset here */
764 for (n = 0; n < 256; n++) tab[n] = v;
765 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800766
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700767 /*
768 * Now set the entries corresponding to the actual scanset
769 * to the opposite of the above.
770 *
771 * The first character may be ']' (or '-') without being special;
772 * the last character may be '-'.
773 */
774 v = 1 - v;
775 for (;;) {
776 tab[c] = v; /* take character c */
777 doswitch:
778 n = *fmt++; /* and examine the next */
779 switch (n) {
780 case 0: /* format ended too soon */
781 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800782
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700783 case '-':
784 /*
785 * A scanset of the form
786 * [01+-]
787 * is defined as `the digit 0, the digit 1,
788 * the character +, the character -', but
789 * the effect of a scanset such as
790 * [a-zA-Z0-9]
791 * is implementation defined. The V7 Unix
792 * scanf treats `a-z' as `the letters a through
793 * z', but treats `a-a' as `the letter a, the
794 * character -, and the letter a'.
795 *
796 * For compatibility, the `-' is not considerd
797 * to define a range if the character following
798 * it is either a close bracket (required by ANSI)
799 * or is not numerically greater than the character
800 * we just stored in the table (c).
801 */
802 n = *fmt;
803 if (n == ']' || n < c) {
804 c = '-';
805 break; /* resume the for(;;) */
806 }
807 fmt++;
808 do { /* fill in the range */
809 tab[++c] = v;
810 } while (c < n);
811#if 1 /* XXX another disgusting compatibility hack */
812 /*
813 * Alas, the V7 Unix scanf also treats formats
814 * such as [a-c-e] as `the letters a through e'.
815 * This too is permitted by the standard....
816 */
817 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800818#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700819 c = *fmt++;
820 if (c == 0) return (fmt - 1);
821 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800822#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700823 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800824
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700825 case ']': /* end of scanset */
826 return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800827
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700828 default: /* just another character */
829 c = n;
830 break;
831 }
832 }
833 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800834}