blob: f0ed4ae71be59218f2158234c385f80a70c863d6 [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
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#include <inttypes.h>
35#include <stdarg.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
Elliott Hughes603332f2014-03-12 17:10:41 -070039#include <string.h>
Elliott Hughesc8f2c522017-10-31 13:07:51 -070040#include <wctype.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080041#include "local.h"
42
Elliott Hughes1133fec2017-12-19 16:30:55 -080043#include <private/bionic_ctype.h>
44
Elliott Hughesc8f2c522017-10-31 13:07:51 -070045#define BUF 513 /* Maximum length of numeric string. */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080046
47/*
48 * Flags used during conversion.
49 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070050#define LONG 0x00001 /* l: long or double */
51#define LONGDBL 0x00002 /* L: long double */
52#define SHORT 0x00004 /* h: short */
53#define SHORTSHORT 0x00008 /* hh: 8 bit integer */
54#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */
55#define POINTER 0x00020 /* p: void * (as hex) */
56#define SIZEINT 0x00040 /* z: (signed) size_t */
57#define MAXINT 0x00080 /* j: intmax_t */
58#define PTRINT 0x00100 /* t: ptrdiff_t */
59#define NOSKIP 0x00200 /* [ or c: do not skip blanks */
60#define SUPPRESS 0x00400 /* *: suppress assignment */
61#define UNSIGNED 0x00800 /* %[oupxX] conversions */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080062
63/*
64 * The following are used in numeric conversions only:
65 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
66 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
67 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070068#define SIGNOK 0x01000 /* +/- is (still) legal */
69#define HAVESIGN 0x02000 /* sign detected */
70#define NDIGITS 0x04000 /* no digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080071
Elliott Hughesc8f2c522017-10-31 13:07:51 -070072#define DPTOK 0x08000 /* (float) decimal point is still legal */
73#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080074
Elliott Hughesc8f2c522017-10-31 13:07:51 -070075#define PFXOK 0x08000 /* 0x prefix is (still) legal */
76#define NZDIGITS 0x10000 /* no zero digits detected */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080077
78/*
79 * Conversion types.
80 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070081#define CT_CHAR 0 /* %c conversion */
82#define CT_CCL 1 /* %[...] conversion */
83#define CT_STRING 2 /* %s conversion */
84#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */
85#define CT_FLOAT 4 /* floating, i.e., strtod */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080086
Elliott Hughesc8f2c522017-10-31 13:07:51 -070087static u_char* __sccl(char*, u_char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080089/*
Elliott Hughes603332f2014-03-12 17:10:41 -070090 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070092int __svfscanf(FILE* fp, const char* fmt0, __va_list ap) {
93 u_char* fmt = (u_char*)fmt0;
94 int c; /* character from format, or conversion */
95 size_t width; /* field width, or 0 */
96 char* p; /* points into all kinds of strings */
97 int n; /* handy integer */
98 int flags; /* flags as defined above */
99 char* p0; /* saves original value of p when necessary */
100 int nassigned; /* number of fields assigned */
101 int nread; /* number of characters consumed from fp */
102 int base; /* base argument to strtoimax/strtouimax */
103 char ccltab[256]; /* character class table for %[...] */
104 char buf[BUF]; /* buffer for numeric conversions */
105 wchar_t* wcp; /* handy wide character pointer */
106 size_t nconv; /* length of multibyte sequence converted */
107 mbstate_t mbs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800108
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700109 /* `basefix' is used to avoid `if' tests in the integer scanner */
110 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 -0800111
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700112 _SET_ORIENTATION(fp, -1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700114 nassigned = 0;
115 nread = 0;
116 base = 0; /* XXX just to keep gcc happy */
117 for (;;) {
118 c = *fmt++;
119 if (c == 0) return (nassigned);
Elliott Hughes1133fec2017-12-19 16:30:55 -0800120 if (IsSpace(c)) {
121 while ((fp->_r > 0 || __srefill(fp) == 0) && IsSpace(*fp->_p)) nread++, fp->_r--, fp->_p++;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700122 continue;
123 }
124 if (c != '%') goto literal;
125 width = 0;
126 flags = 0;
127 /*
128 * switch on the format. continue if done;
129 * break once format type is derived.
130 */
Elliott Hughes1133fec2017-12-19 16:30:55 -0800131again:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700132 c = *fmt++;
133 switch (c) {
134 case '%':
Elliott Hughes1133fec2017-12-19 16:30:55 -0800135literal:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700136 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
137 if (*fp->_p != c) goto match_failure;
138 fp->_r--, fp->_p++;
139 nread++;
140 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800141
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700142 case '*':
143 flags |= SUPPRESS;
144 goto again;
145 case 'j':
146 flags |= MAXINT;
147 goto again;
148 case 'L':
149 flags |= LONGDBL;
150 goto again;
151 case 'h':
152 if (*fmt == 'h') {
153 fmt++;
154 flags |= SHORTSHORT;
155 } else {
156 flags |= SHORT;
157 }
158 goto again;
159 case 'l':
160 if (*fmt == 'l') {
161 fmt++;
162 flags |= LLONG;
163 } else {
164 flags |= LONG;
165 }
166 goto again;
167 case 'q':
168 flags |= LLONG; /* deprecated */
169 goto again;
170 case 't':
171 flags |= PTRINT;
172 goto again;
173 case 'z':
174 flags |= SIZEINT;
175 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800176
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700177 case '0':
178 case '1':
179 case '2':
180 case '3':
181 case '4':
182 case '5':
183 case '6':
184 case '7':
185 case '8':
186 case '9':
187 width = width * 10 + c - '0';
188 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800189
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700190 /*
191 * Conversions.
192 * Those marked `compat' are for 4.[123]BSD compatibility.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700193 */
194 case 'D': /* compat */
195 flags |= LONG;
196 /* FALLTHROUGH */
197 case 'd':
198 c = CT_INT;
199 base = 10;
200 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700202 case 'i':
203 c = CT_INT;
204 base = 0;
205 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700207 case 'O': /* compat */
208 flags |= LONG;
209 /* FALLTHROUGH */
210 case 'o':
211 c = CT_INT;
212 flags |= UNSIGNED;
213 base = 8;
214 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800215
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700216 case 'u':
217 c = CT_INT;
218 flags |= UNSIGNED;
219 base = 10;
220 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800221
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700222 case 'X':
223 case 'x':
224 flags |= PFXOK; /* enable 0x prefixing */
225 c = CT_INT;
226 flags |= UNSIGNED;
227 base = 16;
228 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800229
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700230 case 'e':
231 case 'E':
232 case 'f':
233 case 'F':
234 case 'g':
235 case 'G':
236 case 'a':
237 case 'A':
238 c = CT_FLOAT;
239 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800240
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700241 case 's':
242 c = CT_STRING;
243 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800244
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700245 case '[':
246 fmt = __sccl(ccltab, fmt);
247 flags |= NOSKIP;
248 c = CT_CCL;
249 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800250
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700251 case 'c':
252 flags |= NOSKIP;
253 c = CT_CHAR;
254 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700256 case 'p': /* pointer format is like hex */
257 flags |= POINTER | PFXOK;
258 c = CT_INT;
259 flags |= UNSIGNED;
260 base = 16;
261 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800262
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700263 case 'n':
264 if (flags & SUPPRESS) continue;
265 if (flags & SHORTSHORT)
266 *va_arg(ap, signed char*) = nread;
267 else if (flags & SHORT)
268 *va_arg(ap, short*) = nread;
269 else if (flags & LONG)
270 *va_arg(ap, long*) = nread;
271 else if (flags & SIZEINT)
272 *va_arg(ap, ssize_t*) = nread;
273 else if (flags & PTRINT)
274 *va_arg(ap, ptrdiff_t*) = nread;
275 else if (flags & LLONG)
276 *va_arg(ap, long long*) = nread;
277 else if (flags & MAXINT)
278 *va_arg(ap, intmax_t*) = nread;
279 else
280 *va_arg(ap, int*) = nread;
281 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800282
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700283 /*
284 * Disgusting backwards compatibility hacks. XXX
285 */
286 case '\0': /* compat */
287 return (EOF);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800288
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700289 default: /* compat */
Elliott Hughes1133fec2017-12-19 16:30:55 -0800290 if (IsUpper(c)) flags |= LONG;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700291 c = CT_INT;
292 base = 10;
293 break;
294 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800295
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700296 /*
297 * We have a conversion that requires input.
298 */
299 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800300
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700301 /*
302 * Consume leading white space, except for formats
303 * that suppress this.
304 */
305 if ((flags & NOSKIP) == 0) {
Elliott Hughes1133fec2017-12-19 16:30:55 -0800306 while (IsSpace(*fp->_p)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700307 nread++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800308 if (--fp->_r > 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700309 fp->_p++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800310 } else if (__srefill(fp)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700311 goto input_failure;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800312 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700313 }
314 /*
315 * Note that there is at least one character in
316 * the buffer, so conversions that do not set NOSKIP
317 * ca no longer result in an input failure.
318 */
319 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800320
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700321 /*
322 * Do the conversion.
323 */
324 switch (c) {
325 case CT_CHAR:
326 /* scan arbitrary characters (sets NOSKIP) */
327 if (width == 0) width = 1;
328 if (flags & LONG) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800329 wcp = ((flags & SUPPRESS) == 0) ? va_arg(ap, wchar_t*) : NULL;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700330 n = 0;
331 while (width != 0) {
332 if (n == (int)MB_CUR_MAX) {
333 fp->_flags |= __SERR;
334 goto input_failure;
335 }
336 buf[n++] = *fp->_p;
337 fp->_p++;
338 fp->_r--;
339 memset(&mbs, 0, sizeof(mbs));
340 nconv = mbrtowc(wcp, buf, n, &mbs);
341 if (nconv == (size_t)-1) {
342 fp->_flags |= __SERR;
343 goto input_failure;
344 }
345 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
346 if (nconv != (size_t)-2) {
347 nread += n;
348 width--;
349 if (!(flags & SUPPRESS)) wcp++;
350 n = 0;
351 }
352 if (fp->_r <= 0 && __srefill(fp)) {
353 if (n != 0) {
354 fp->_flags |= __SERR;
355 goto input_failure;
356 }
357 break;
358 }
359 }
360 if (!(flags & SUPPRESS)) nassigned++;
361 } else if (flags & SUPPRESS) {
362 size_t sum = 0;
363 for (;;) {
364 if ((n = fp->_r) < (int)width) {
365 sum += n;
366 width -= n;
367 fp->_p += n;
368 if (__srefill(fp)) {
369 if (sum == 0) goto input_failure;
370 break;
371 }
372 } else {
373 sum += width;
374 fp->_r -= width;
375 fp->_p += width;
376 break;
377 }
378 }
379 nread += sum;
380 } else {
381 size_t r = fread((void*)va_arg(ap, char*), 1, width, fp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800382
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700383 if (r == 0) goto input_failure;
384 nread += r;
385 nassigned++;
386 }
387 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800388
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700389 case CT_CCL:
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800390 case CT_STRING:
391 // CT_CCL: scan a (nonempty) character class (sets NOSKIP).
392 // CT_STRING: like CCL, but zero-length string OK, & no NOSKIP.
393 if (width == 0) width = (size_t)~0; // 'infinity'.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700394 if (flags & LONG) {
395 wchar_t twc;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800396 int nchars = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800397
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800398 wcp = (flags & SUPPRESS) == 0 ? va_arg(ap, wchar_t*) : &twc;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700399 n = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800400 while ((c == CT_CCL || !IsSpace(*fp->_p)) && width != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700401 if (n == (int)MB_CUR_MAX) {
402 fp->_flags |= __SERR;
403 goto input_failure;
404 }
405 buf[n++] = *fp->_p;
406 fp->_p++;
407 fp->_r--;
408 memset(&mbs, 0, sizeof(mbs));
409 nconv = mbrtowc(wcp, buf, n, &mbs);
410 if (nconv == (size_t)-1) {
411 fp->_flags |= __SERR;
412 goto input_failure;
413 }
414 if (nconv == 0) *wcp = L'\0';
415 if (nconv != (size_t)-2) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800416 if ((c == CT_CCL && wctob(*wcp) != EOF && !ccltab[wctob(*wcp)]) || (c == CT_STRING && iswspace(*wcp))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700417 while (n != 0) {
418 n--;
419 ungetc(buf[n], fp);
420 }
421 break;
422 }
423 nread += n;
424 width--;
425 if (!(flags & SUPPRESS)) wcp++;
426 nchars++;
427 n = 0;
428 }
429 if (fp->_r <= 0 && __srefill(fp)) {
430 if (n != 0) {
431 fp->_flags |= __SERR;
432 goto input_failure;
433 }
434 break;
435 }
436 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800437 if (c == CT_CCL && n != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700438 fp->_flags |= __SERR;
439 goto input_failure;
440 }
441 n = nchars;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800442 } else if (flags & SUPPRESS) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700443 n = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800444 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !IsSpace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700445 n++, fp->_r--, fp->_p++;
446 if (--width == 0) break;
447 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800448 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700449 break;
450 }
451 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700452 } else {
453 p0 = p = va_arg(ap, char*);
Elliott Hughes1133fec2017-12-19 16:30:55 -0800454 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !IsSpace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700455 fp->_r--;
456 *p++ = *fp->_p++;
457 if (--width == 0) break;
458 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800459 if (c == CT_CCL && p == p0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700460 break;
461 }
462 }
463 n = p - p0;
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800464 }
465 if (c == CT_CCL && n == 0) goto match_failure;
466 if (!(flags & SUPPRESS)) {
467 if (flags & LONG) {
468 *wcp = L'\0';
469 } else {
470 *p = '\0';
471 }
472 ++nassigned;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700473 }
474 nread += n;
475 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700476
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700477 case CT_INT:
478 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800479#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700480 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800481#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700482 /* size_t is unsigned, hence this optimisation */
483 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
484 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800485#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700486 flags |= SIGNOK | NDIGITS | NZDIGITS;
487 for (p = buf; width; width--) {
488 c = *fp->_p;
489 /*
490 * Switch on the character; `goto ok'
491 * if we accept it as a part of number.
492 */
493 switch (c) {
494 /*
495 * The digit 0 is always legal, but is
496 * special. For %i conversions, if no
497 * digits (zero or nonzero) have been
498 * scanned (only signs), we will have
499 * base==0. In that case, we should set
500 * it to 8 and enable 0x prefixing.
501 * Also, if we have not scanned zero digits
502 * before this, do not turn off prefixing
503 * (someone else will turn it off if we
504 * have scanned any nonzero digits).
505 */
506 case '0':
507 if (base == 0) {
508 base = 8;
509 flags |= PFXOK;
510 }
511 if (flags & NZDIGITS)
512 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
513 else
514 flags &= ~(SIGNOK | PFXOK | NDIGITS);
515 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800516
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700517 /* 1 through 7 always legal */
518 case '1':
519 case '2':
520 case '3':
521 case '4':
522 case '5':
523 case '6':
524 case '7':
525 base = basefix[base];
526 flags &= ~(SIGNOK | PFXOK | NDIGITS);
527 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800528
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700529 /* digits 8 and 9 ok iff decimal or hex */
530 case '8':
531 case '9':
532 base = basefix[base];
533 if (base <= 8) break; /* not legal here */
534 flags &= ~(SIGNOK | PFXOK | NDIGITS);
535 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800536
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700537 /* letters ok iff hex */
538 case 'A':
539 case 'B':
540 case 'C':
541 case 'D':
542 case 'E':
543 case 'F':
544 case 'a':
545 case 'b':
546 case 'c':
547 case 'd':
548 case 'e':
549 case 'f':
550 /* no need to fix base here */
551 if (base <= 10) break; /* not legal here */
552 flags &= ~(SIGNOK | PFXOK | NDIGITS);
553 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800554
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700555 /* sign ok only as first character */
556 case '+':
557 case '-':
558 if (flags & SIGNOK) {
559 flags &= ~SIGNOK;
560 flags |= HAVESIGN;
561 goto ok;
562 }
563 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800564
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700565 /*
566 * x ok iff flag still set and 2nd char (or
567 * 3rd char if we have a sign).
568 */
569 case 'x':
570 case 'X':
571 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
572 base = 16; /* if %i */
573 flags &= ~PFXOK;
574 goto ok;
575 }
576 break;
577 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800578
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700579 /*
580 * If we got here, c is not a legal character
581 * for a number. Stop accumulating digits.
582 */
583 break;
584 ok:
585 /*
586 * c is legal: store it and look at the next.
587 */
588 *p++ = c;
589 if (--fp->_r > 0)
590 fp->_p++;
591 else if (__srefill(fp))
592 break; /* EOF */
593 }
594 /*
595 * If we had only a sign, it is no good; push
596 * back the sign. If the number ends in `x',
597 * it was [sign] '0' 'x', so push back the x
598 * and treat it as [sign] '0'.
599 */
600 if (flags & NDIGITS) {
601 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
602 goto match_failure;
603 }
604 c = ((u_char*)p)[-1];
605 if (c == 'x' || c == 'X') {
606 --p;
607 (void)ungetc(c, fp);
608 }
609 if ((flags & SUPPRESS) == 0) {
610 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800611
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700612 *p = '\0';
613 if (flags & UNSIGNED)
614 res = strtoumax(buf, NULL, base);
615 else
616 res = strtoimax(buf, NULL, base);
617 if (flags & POINTER)
618 *va_arg(ap, void**) = (void*)(uintptr_t)res;
619 else if (flags & MAXINT)
620 *va_arg(ap, intmax_t*) = res;
621 else if (flags & LLONG)
622 *va_arg(ap, long long*) = res;
623 else if (flags & SIZEINT)
624 *va_arg(ap, ssize_t*) = res;
625 else if (flags & PTRINT)
626 *va_arg(ap, ptrdiff_t*) = res;
627 else if (flags & LONG)
628 *va_arg(ap, long*) = res;
629 else if (flags & SHORT)
630 *va_arg(ap, short*) = res;
631 else if (flags & SHORTSHORT)
632 *va_arg(ap, signed char*) = res;
633 else
634 *va_arg(ap, int*) = res;
635 nassigned++;
636 }
637 nread += p - buf;
638 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800639
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700640 case CT_FLOAT:
641 /* scan a floating point number as if by strtod */
642 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
643 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
644 if ((flags & SUPPRESS) == 0) {
645 if (flags & LONGDBL) {
646 long double res = strtold(buf, &p);
647 *va_arg(ap, long double*) = res;
648 } else if (flags & LONG) {
649 double res = strtod(buf, &p);
650 *va_arg(ap, double*) = res;
651 } else {
652 float res = strtof(buf, &p);
653 *va_arg(ap, float*) = res;
654 }
655 if ((size_t)(p - buf) != width) abort();
656 nassigned++;
657 }
658 nread += width;
659 break;
660 }
661 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800662input_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700663 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800664match_failure:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700665 return (nassigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800666}
667
668/*
669 * Fill in the given table from the scanset at the given format
670 * (just after `['). Return a pointer to the character past the
671 * closing `]'. The table has a 1 wherever characters should be
672 * considered part of the scanset.
673 */
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700674static u_char* __sccl(char* tab, u_char* fmt) {
675 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800676
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700677 /* first `clear' the whole table */
678 c = *fmt++; /* first char hat => negated scanset */
679 if (c == '^') {
680 v = 1; /* default => accept */
681 c = *fmt++; /* get new first char */
682 } else
683 v = 0; /* default => reject */
684 /* should probably use memset here */
685 for (n = 0; n < 256; n++) tab[n] = v;
686 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800687
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700688 /*
689 * Now set the entries corresponding to the actual scanset
690 * to the opposite of the above.
691 *
692 * The first character may be ']' (or '-') without being special;
693 * the last character may be '-'.
694 */
695 v = 1 - v;
696 for (;;) {
697 tab[c] = v; /* take character c */
698 doswitch:
699 n = *fmt++; /* and examine the next */
700 switch (n) {
701 case 0: /* format ended too soon */
702 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800703
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700704 case '-':
705 /*
706 * A scanset of the form
707 * [01+-]
708 * is defined as `the digit 0, the digit 1,
709 * the character +, the character -', but
710 * the effect of a scanset such as
711 * [a-zA-Z0-9]
712 * is implementation defined. The V7 Unix
713 * scanf treats `a-z' as `the letters a through
714 * z', but treats `a-a' as `the letter a, the
715 * character -, and the letter a'.
716 *
717 * For compatibility, the `-' is not considerd
718 * to define a range if the character following
719 * it is either a close bracket (required by ANSI)
720 * or is not numerically greater than the character
721 * we just stored in the table (c).
722 */
723 n = *fmt;
724 if (n == ']' || n < c) {
725 c = '-';
726 break; /* resume the for(;;) */
727 }
728 fmt++;
729 do { /* fill in the range */
730 tab[++c] = v;
731 } while (c < n);
732#if 1 /* XXX another disgusting compatibility hack */
733 /*
734 * Alas, the V7 Unix scanf also treats formats
735 * such as [a-c-e] as `the letters a through e'.
736 * This too is permitted by the standard....
737 */
738 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800739#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700740 c = *fmt++;
741 if (c == 0) return (fmt - 1);
742 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800743#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700744 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800745
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700746 case ']': /* end of scanset */
747 return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800748
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700749 default: /* just another character */
750 c = n;
751 break;
752 }
753 }
754 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800755}