blob: c9e4385c84170b6cc0a15b1919f5a4c14788319a [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) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800327 wcp = ((flags & SUPPRESS) == 0) ? va_arg(ap, wchar_t*) : NULL;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700328 n = 0;
329 while (width != 0) {
330 if (n == (int)MB_CUR_MAX) {
331 fp->_flags |= __SERR;
332 goto input_failure;
333 }
334 buf[n++] = *fp->_p;
335 fp->_p++;
336 fp->_r--;
337 memset(&mbs, 0, sizeof(mbs));
338 nconv = mbrtowc(wcp, buf, n, &mbs);
339 if (nconv == (size_t)-1) {
340 fp->_flags |= __SERR;
341 goto input_failure;
342 }
343 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
344 if (nconv != (size_t)-2) {
345 nread += n;
346 width--;
347 if (!(flags & SUPPRESS)) wcp++;
348 n = 0;
349 }
350 if (fp->_r <= 0 && __srefill(fp)) {
351 if (n != 0) {
352 fp->_flags |= __SERR;
353 goto input_failure;
354 }
355 break;
356 }
357 }
358 if (!(flags & SUPPRESS)) nassigned++;
359 } else if (flags & SUPPRESS) {
360 size_t sum = 0;
361 for (;;) {
362 if ((n = fp->_r) < (int)width) {
363 sum += n;
364 width -= n;
365 fp->_p += n;
366 if (__srefill(fp)) {
367 if (sum == 0) goto input_failure;
368 break;
369 }
370 } else {
371 sum += width;
372 fp->_r -= width;
373 fp->_p += width;
374 break;
375 }
376 }
377 nread += sum;
378 } else {
379 size_t r = fread((void*)va_arg(ap, char*), 1, width, fp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800380
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700381 if (r == 0) goto input_failure;
382 nread += r;
383 nassigned++;
384 }
385 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800386
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700387 case CT_CCL:
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800388 case CT_STRING:
389 // CT_CCL: scan a (nonempty) character class (sets NOSKIP).
390 // CT_STRING: like CCL, but zero-length string OK, & no NOSKIP.
391 if (width == 0) width = (size_t)~0; // 'infinity'.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700392 if (flags & LONG) {
393 wchar_t twc;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800394 int nchars = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800395
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800396 wcp = (flags & SUPPRESS) == 0 ? va_arg(ap, wchar_t*) : &twc;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700397 n = 0;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800398 while ((c == CT_CCL || !isspace(*fp->_p)) && width != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700399 if (n == (int)MB_CUR_MAX) {
400 fp->_flags |= __SERR;
401 goto input_failure;
402 }
403 buf[n++] = *fp->_p;
404 fp->_p++;
405 fp->_r--;
406 memset(&mbs, 0, sizeof(mbs));
407 nconv = mbrtowc(wcp, buf, n, &mbs);
408 if (nconv == (size_t)-1) {
409 fp->_flags |= __SERR;
410 goto input_failure;
411 }
412 if (nconv == 0) *wcp = L'\0';
413 if (nconv != (size_t)-2) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800414 if ((c == CT_CCL && wctob(*wcp) != EOF && !ccltab[wctob(*wcp)]) || (c == CT_STRING && iswspace(*wcp))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700415 while (n != 0) {
416 n--;
417 ungetc(buf[n], fp);
418 }
419 break;
420 }
421 nread += n;
422 width--;
423 if (!(flags & SUPPRESS)) wcp++;
424 nchars++;
425 n = 0;
426 }
427 if (fp->_r <= 0 && __srefill(fp)) {
428 if (n != 0) {
429 fp->_flags |= __SERR;
430 goto input_failure;
431 }
432 break;
433 }
434 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800435 if (c == CT_CCL && n != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700436 fp->_flags |= __SERR;
437 goto input_failure;
438 }
439 n = nchars;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800440 } else if (flags & SUPPRESS) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700441 n = 0;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800442 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !isspace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700443 n++, fp->_r--, fp->_p++;
444 if (--width == 0) break;
445 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800446 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700447 break;
448 }
449 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700450 } else {
451 p0 = p = va_arg(ap, char*);
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800452 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !isspace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700453 fp->_r--;
454 *p++ = *fp->_p++;
455 if (--width == 0) break;
456 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800457 if (c == CT_CCL && p == p0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700458 break;
459 }
460 }
461 n = p - p0;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800462 }
463 if (c == CT_CCL && n == 0) goto match_failure;
464 if (!(flags & SUPPRESS)) {
465 if (flags & LONG) {
466 *wcp = L'\0';
467 } else {
468 *p = '\0';
469 }
470 ++nassigned;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700471 }
472 nread += n;
473 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700474
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700475 case CT_INT:
476 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800477#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700478 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800479#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700480 /* size_t is unsigned, hence this optimisation */
481 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
482 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800483#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700484 flags |= SIGNOK | NDIGITS | NZDIGITS;
485 for (p = buf; width; width--) {
486 c = *fp->_p;
487 /*
488 * Switch on the character; `goto ok'
489 * if we accept it as a part of number.
490 */
491 switch (c) {
492 /*
493 * The digit 0 is always legal, but is
494 * special. For %i conversions, if no
495 * digits (zero or nonzero) have been
496 * scanned (only signs), we will have
497 * base==0. In that case, we should set
498 * it to 8 and enable 0x prefixing.
499 * Also, if we have not scanned zero digits
500 * before this, do not turn off prefixing
501 * (someone else will turn it off if we
502 * have scanned any nonzero digits).
503 */
504 case '0':
505 if (base == 0) {
506 base = 8;
507 flags |= PFXOK;
508 }
509 if (flags & NZDIGITS)
510 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
511 else
512 flags &= ~(SIGNOK | PFXOK | NDIGITS);
513 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800514
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700515 /* 1 through 7 always legal */
516 case '1':
517 case '2':
518 case '3':
519 case '4':
520 case '5':
521 case '6':
522 case '7':
523 base = basefix[base];
524 flags &= ~(SIGNOK | PFXOK | NDIGITS);
525 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800526
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700527 /* digits 8 and 9 ok iff decimal or hex */
528 case '8':
529 case '9':
530 base = basefix[base];
531 if (base <= 8) break; /* not legal here */
532 flags &= ~(SIGNOK | PFXOK | NDIGITS);
533 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800534
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700535 /* letters ok iff hex */
536 case 'A':
537 case 'B':
538 case 'C':
539 case 'D':
540 case 'E':
541 case 'F':
542 case 'a':
543 case 'b':
544 case 'c':
545 case 'd':
546 case 'e':
547 case 'f':
548 /* no need to fix base here */
549 if (base <= 10) break; /* not legal here */
550 flags &= ~(SIGNOK | PFXOK | NDIGITS);
551 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800552
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700553 /* sign ok only as first character */
554 case '+':
555 case '-':
556 if (flags & SIGNOK) {
557 flags &= ~SIGNOK;
558 flags |= HAVESIGN;
559 goto ok;
560 }
561 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800562
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700563 /*
564 * x ok iff flag still set and 2nd char (or
565 * 3rd char if we have a sign).
566 */
567 case 'x':
568 case 'X':
569 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
570 base = 16; /* if %i */
571 flags &= ~PFXOK;
572 goto ok;
573 }
574 break;
575 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800576
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700577 /*
578 * If we got here, c is not a legal character
579 * for a number. Stop accumulating digits.
580 */
581 break;
582 ok:
583 /*
584 * c is legal: store it and look at the next.
585 */
586 *p++ = c;
587 if (--fp->_r > 0)
588 fp->_p++;
589 else if (__srefill(fp))
590 break; /* EOF */
591 }
592 /*
593 * If we had only a sign, it is no good; push
594 * back the sign. If the number ends in `x',
595 * it was [sign] '0' 'x', so push back the x
596 * and treat it as [sign] '0'.
597 */
598 if (flags & NDIGITS) {
599 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
600 goto match_failure;
601 }
602 c = ((u_char*)p)[-1];
603 if (c == 'x' || c == 'X') {
604 --p;
605 (void)ungetc(c, fp);
606 }
607 if ((flags & SUPPRESS) == 0) {
608 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800609
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700610 *p = '\0';
611 if (flags & UNSIGNED)
612 res = strtoumax(buf, NULL, base);
613 else
614 res = strtoimax(buf, NULL, base);
615 if (flags & POINTER)
616 *va_arg(ap, void**) = (void*)(uintptr_t)res;
617 else if (flags & MAXINT)
618 *va_arg(ap, intmax_t*) = res;
619 else if (flags & LLONG)
620 *va_arg(ap, long long*) = res;
621 else if (flags & SIZEINT)
622 *va_arg(ap, ssize_t*) = res;
623 else if (flags & PTRINT)
624 *va_arg(ap, ptrdiff_t*) = res;
625 else if (flags & LONG)
626 *va_arg(ap, long*) = res;
627 else if (flags & SHORT)
628 *va_arg(ap, short*) = res;
629 else if (flags & SHORTSHORT)
630 *va_arg(ap, signed char*) = res;
631 else
632 *va_arg(ap, int*) = res;
633 nassigned++;
634 }
635 nread += p - buf;
636 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800637
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700638 case CT_FLOAT:
639 /* scan a floating point number as if by strtod */
640 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
641 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
642 if ((flags & SUPPRESS) == 0) {
643 if (flags & LONGDBL) {
644 long double res = strtold(buf, &p);
645 *va_arg(ap, long double*) = res;
646 } else if (flags & LONG) {
647 double res = strtod(buf, &p);
648 *va_arg(ap, double*) = res;
649 } else {
650 float res = strtof(buf, &p);
651 *va_arg(ap, float*) = res;
652 }
653 if ((size_t)(p - buf) != width) abort();
654 nassigned++;
655 }
656 nread += width;
657 break;
658 }
659 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800660input_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700661 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800662match_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700663 return (nassigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800664}
665
666/*
667 * Fill in the given table from the scanset at the given format
668 * (just after `['). Return a pointer to the character past the
669 * closing `]'. The table has a 1 wherever characters should be
670 * considered part of the scanset.
671 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700672static u_char* __sccl(char* tab, u_char* fmt) {
673 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800674
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700675 /* first `clear' the whole table */
676 c = *fmt++; /* first char hat => negated scanset */
677 if (c == '^') {
678 v = 1; /* default => accept */
679 c = *fmt++; /* get new first char */
680 } else
681 v = 0; /* default => reject */
682 /* should probably use memset here */
683 for (n = 0; n < 256; n++) tab[n] = v;
684 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800685
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700686 /*
687 * Now set the entries corresponding to the actual scanset
688 * to the opposite of the above.
689 *
690 * The first character may be ']' (or '-') without being special;
691 * the last character may be '-'.
692 */
693 v = 1 - v;
694 for (;;) {
695 tab[c] = v; /* take character c */
696 doswitch:
697 n = *fmt++; /* and examine the next */
698 switch (n) {
699 case 0: /* format ended too soon */
700 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800701
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700702 case '-':
703 /*
704 * A scanset of the form
705 * [01+-]
706 * is defined as `the digit 0, the digit 1,
707 * the character +, the character -', but
708 * the effect of a scanset such as
709 * [a-zA-Z0-9]
710 * is implementation defined. The V7 Unix
711 * scanf treats `a-z' as `the letters a through
712 * z', but treats `a-a' as `the letter a, the
713 * character -, and the letter a'.
714 *
715 * For compatibility, the `-' is not considerd
716 * to define a range if the character following
717 * it is either a close bracket (required by ANSI)
718 * or is not numerically greater than the character
719 * we just stored in the table (c).
720 */
721 n = *fmt;
722 if (n == ']' || n < c) {
723 c = '-';
724 break; /* resume the for(;;) */
725 }
726 fmt++;
727 do { /* fill in the range */
728 tab[++c] = v;
729 } while (c < n);
730#if 1 /* XXX another disgusting compatibility hack */
731 /*
732 * Alas, the V7 Unix scanf also treats formats
733 * such as [a-c-e] as `the letters a through e'.
734 * This too is permitted by the standard....
735 */
736 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800737#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700738 c = *fmt++;
739 if (c == 0) return (fmt - 1);
740 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800741#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700742 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800743
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700744 case ']': /* end of scanset */
745 return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800746
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700747 default: /* just another character */
748 c = n;
749 break;
750 }
751 }
752 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800753}