blob: f2e136c68a2d14bfa50095dfce4e1991d8ce7a2b [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 Hughes38e4aef2018-01-18 10:21:29 -080040#include <sys/param.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 Hughes1133fec2017-12-19 16:30:55 -080044#include <private/bionic_ctype.h>
Elliott Hughes38e4aef2018-01-18 10:21:29 -080045#include <private/bionic_fortify.h>
46#include <private/bionic_mbstate.h>
Elliott Hughes1133fec2017-12-19 16:30:55 -080047
Elliott Hughesc8f2c522017-10-31 13:07:51 -070048#define BUF 513 /* Maximum length of numeric string. */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080049
Elliott Hughes38e4aef2018-01-18 10:21:29 -080050// Flags used during conversion.
51// Size/type:
52#define LONG 0x00001 // l: long or double
53#define LONGDBL 0x00002 // L: long double
54#define SHORT 0x00004 // h: short
55#define SHORTSHORT 0x00008 // hh: 8 bit integer
56#define LLONG 0x00010 // ll: long long (+ deprecated q: quad)
57#define POINTER 0x00020 // p: void* (as hex)
58#define SIZEINT 0x00040 // z: (signed) size_t
59#define MAXINT 0x00080 // j: intmax_t
60#define PTRINT 0x00100 // t: ptrdiff_t
61#define NOSKIP 0x00200 // [ or c: do not skip blanks
62// Modifiers:
63#define SUPPRESS 0x00400 // *: suppress assignment
64#define UNSIGNED 0x00800 // %[oupxX] conversions
65#define ALLOCATE 0x01000 // m: allocate a char*
66// Internal use during integer parsing:
67#define SIGNOK 0x02000 // +/- is (still) legal
68#define HAVESIGN 0x04000 // Sign detected
69#define NDIGITS 0x08000 // No digits detected
70#define PFXOK 0x10000 // "0x" prefix is (still) legal
71#define NZDIGITS 0x20000 // No zero digits detected
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Elliott Hughes38e4aef2018-01-18 10:21:29 -080073// Conversion types.
74#define CT_CHAR 0 // %c conversion
75#define CT_CCL 1 // %[...] conversion
76#define CT_STRING 2 // %s conversion
77#define CT_INT 3 // Integer: strtoimax/strtoumax
78#define CT_FLOAT 4 // Float: strtod
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080079
Elliott Hughes38e4aef2018-01-18 10:21:29 -080080static const unsigned char* __sccl(char*, const unsigned char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080082/*
Elliott Hughes603332f2014-03-12 17:10:41 -070083 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -080085int __svfscanf(FILE* fp, const char* fmt0, va_list ap) {
86 const unsigned char* fmt = reinterpret_cast<const unsigned char*>(fmt0);
Elliott Hughesc8f2c522017-10-31 13:07:51 -070087 int c; /* character from format, or conversion */
88 size_t width; /* field width, or 0 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -080089 char* p;
90 wchar_t* wcp;
91 size_t n;
Elliott Hughesc8f2c522017-10-31 13:07:51 -070092 int flags; /* flags as defined above */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070093 int nassigned; /* number of fields assigned */
94 int nread; /* number of characters consumed from fp */
95 int base; /* base argument to strtoimax/strtouimax */
96 char ccltab[256]; /* character class table for %[...] */
97 char buf[BUF]; /* buffer for numeric conversions */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070098 size_t nconv; /* length of multibyte sequence converted */
99 mbstate_t mbs;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800100 void* allocation = NULL; // Allocated but unassigned result for %mc/%ms/%m[.
101 size_t capacity = 0; // Number of char/wchar_t units allocated in `allocation`.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800102
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700103 /* `basefix' is used to avoid `if' tests in the integer scanner */
104 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 -0800105
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700106 _SET_ORIENTATION(fp, -1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700108 nassigned = 0;
109 nread = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700110 for (;;) {
111 c = *fmt++;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800112 if (c == 0) return nassigned;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800113 if (IsSpace(c)) {
114 while ((fp->_r > 0 || __srefill(fp) == 0) && IsSpace(*fp->_p)) nread++, fp->_r--, fp->_p++;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700115 continue;
116 }
117 if (c != '%') goto literal;
118 width = 0;
119 flags = 0;
120 /*
121 * switch on the format. continue if done;
122 * break once format type is derived.
123 */
Elliott Hughes1133fec2017-12-19 16:30:55 -0800124again:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700125 c = *fmt++;
126 switch (c) {
127 case '%':
Elliott Hughes1133fec2017-12-19 16:30:55 -0800128literal:
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700129 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
130 if (*fp->_p != c) goto match_failure;
131 fp->_r--, fp->_p++;
132 nread++;
133 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800134
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700135 case '*':
136 flags |= SUPPRESS;
137 goto again;
138 case 'j':
139 flags |= MAXINT;
140 goto again;
141 case 'L':
142 flags |= LONGDBL;
143 goto again;
144 case 'h':
145 if (*fmt == 'h') {
146 fmt++;
147 flags |= SHORTSHORT;
148 } else {
149 flags |= SHORT;
150 }
151 goto again;
152 case 'l':
153 if (*fmt == 'l') {
154 fmt++;
155 flags |= LLONG;
156 } else {
157 flags |= LONG;
158 }
159 goto again;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800160 case 'm':
161 flags |= ALLOCATE;
162 goto again;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700163 case 'q':
164 flags |= LLONG; /* deprecated */
165 goto again;
166 case 't':
167 flags |= PTRINT;
168 goto again;
169 case 'z':
170 flags |= SIZEINT;
171 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700173 case '0':
174 case '1':
175 case '2':
176 case '3':
177 case '4':
178 case '5':
179 case '6':
180 case '7':
181 case '8':
182 case '9':
183 width = width * 10 + c - '0';
184 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800185
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700186 /*
187 * Conversions.
188 * Those marked `compat' are for 4.[123]BSD compatibility.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700189 */
190 case 'D': /* compat */
191 flags |= LONG;
192 /* FALLTHROUGH */
193 case 'd':
194 c = CT_INT;
195 base = 10;
196 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800197
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700198 case 'i':
199 c = CT_INT;
200 base = 0;
201 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800202
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700203 case 'O': /* compat */
204 flags |= LONG;
205 /* FALLTHROUGH */
206 case 'o':
207 c = CT_INT;
208 flags |= UNSIGNED;
209 base = 8;
210 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800211
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700212 case 'u':
213 c = CT_INT;
214 flags |= UNSIGNED;
215 base = 10;
216 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800217
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700218 case 'X':
219 case 'x':
220 flags |= PFXOK; /* enable 0x prefixing */
221 c = CT_INT;
222 flags |= UNSIGNED;
223 base = 16;
224 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800225
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700226 case 'e':
227 case 'E':
228 case 'f':
229 case 'F':
230 case 'g':
231 case 'G':
232 case 'a':
233 case 'A':
234 c = CT_FLOAT;
235 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800236
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700237 case 's':
238 c = CT_STRING;
239 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800240
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700241 case '[':
242 fmt = __sccl(ccltab, fmt);
243 flags |= NOSKIP;
244 c = CT_CCL;
245 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800246
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700247 case 'c':
248 flags |= NOSKIP;
249 c = CT_CHAR;
250 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800251
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700252 case 'p': /* pointer format is like hex */
253 flags |= POINTER | PFXOK;
254 c = CT_INT;
255 flags |= UNSIGNED;
256 base = 16;
257 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800258
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700259 case 'n':
260 if (flags & SUPPRESS) continue;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800261 if (flags & SHORTSHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700262 *va_arg(ap, signed char*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800263 } else if (flags & SHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700264 *va_arg(ap, short*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800265 } else if (flags & LONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700266 *va_arg(ap, long*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800267 } else if (flags & SIZEINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700268 *va_arg(ap, ssize_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800269 } else if (flags & PTRINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700270 *va_arg(ap, ptrdiff_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800271 } else if (flags & LLONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700272 *va_arg(ap, long long*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800273 } else if (flags & MAXINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700274 *va_arg(ap, intmax_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800275 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700276 *va_arg(ap, int*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800277 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700278 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800279
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700280 /*
281 * Disgusting backwards compatibility hacks. XXX
282 */
283 case '\0': /* compat */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800284 return EOF;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800285
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700286 default: /* compat */
Elliott Hughes1133fec2017-12-19 16:30:55 -0800287 if (IsUpper(c)) flags |= LONG;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700288 c = CT_INT;
289 base = 10;
290 break;
291 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800292
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800293 if ((flags & ALLOCATE) != 0 && c > CT_STRING) {
294 __fortify_fatal("scanf 'm' only works with %%c/%%s/%%[");
295 }
296 if ((flags & (ALLOCATE|SUPPRESS)) == (ALLOCATE|SUPPRESS)) {
297 __fortify_fatal("scanf 'm' makes no sense with '*'");
298 }
299
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700300 /*
301 * We have a conversion that requires input.
302 */
303 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800304
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700305 /*
306 * Consume leading white space, except for formats
307 * that suppress this.
308 */
309 if ((flags & NOSKIP) == 0) {
Elliott Hughes1133fec2017-12-19 16:30:55 -0800310 while (IsSpace(*fp->_p)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700311 nread++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800312 if (--fp->_r > 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700313 fp->_p++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800314 } else if (__srefill(fp)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700315 goto input_failure;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800316 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700317 }
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) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800333 if (flags & ALLOCATE) {
334 allocation = wcp = reinterpret_cast<wchar_t*>(malloc(width * sizeof(wchar_t)));
335 if (allocation == NULL) goto allocation_failure;
336 } else if (flags & SUPPRESS) {
337 wcp = NULL;
338 } else {
339 wcp = va_arg(ap, wchar_t*);
340 }
341 size_t bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700342 while (width != 0) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800343 if (bytes == MB_CUR_MAX) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700344 fp->_flags |= __SERR;
345 goto input_failure;
346 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800347 buf[bytes++] = *fp->_p;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700348 fp->_p++;
349 fp->_r--;
350 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800351 nconv = mbrtowc(wcp, buf, bytes, &mbs);
352 if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700353 fp->_flags |= __SERR;
354 goto input_failure;
355 }
356 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800357 if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
358 nread += bytes;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700359 width--;
360 if (!(flags & SUPPRESS)) wcp++;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800361 bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700362 }
363 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800364 if (bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700365 fp->_flags |= __SERR;
366 goto input_failure;
367 }
368 break;
369 }
370 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800371 if (allocation != NULL) {
372 *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
373 allocation = NULL;
374 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700375 if (!(flags & SUPPRESS)) nassigned++;
376 } else if (flags & SUPPRESS) {
377 size_t sum = 0;
378 for (;;) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800379 if ((n = fp->_r) < width) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700380 sum += n;
381 width -= n;
382 fp->_p += n;
383 if (__srefill(fp)) {
384 if (sum == 0) goto input_failure;
385 break;
386 }
387 } else {
388 sum += width;
389 fp->_r -= width;
390 fp->_p += width;
391 break;
392 }
393 }
394 nread += sum;
395 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800396 if (flags & ALLOCATE) {
397 allocation = p = reinterpret_cast<char*>(malloc(width));
398 if (allocation == NULL) goto allocation_failure;
399 } else {
400 p = va_arg(ap, char*);
401 }
402 size_t r = fread(p, 1, width, fp);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700403 if (r == 0) goto input_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800404 if (allocation != NULL) {
405 *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
406 allocation = NULL;
407 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700408 nread += r;
409 nassigned++;
410 }
411 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800412
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700413 case CT_CCL:
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800414 case CT_STRING:
415 // CT_CCL: scan a (nonempty) character class (sets NOSKIP).
416 // CT_STRING: like CCL, but zero-length string OK, & no NOSKIP.
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800417 if (width == 0) width = SIZE_MAX;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700418 if (flags & LONG) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800419 // TODO: since no-one cares, replace this with a simple fgetwc loop?
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700420 n = 0;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800421 if (flags & ALLOCATE) {
422 capacity = MIN(width, 32);
423 allocation = wcp = reinterpret_cast<wchar_t*>(malloc(sizeof(wchar_t) * capacity));
424 if (allocation == NULL) goto allocation_failure;
425 } else if (flags & SUPPRESS) {
426 wcp = NULL;
427 } else {
428 wcp = va_arg(ap, wchar_t*);
429 }
430 size_t bytes = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800431 while ((c == CT_CCL || !IsSpace(*fp->_p)) && width != 0) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800432 if (bytes == MB_CUR_MAX) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700433 fp->_flags |= __SERR;
434 goto input_failure;
435 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800436 buf[bytes++] = *fp->_p;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700437 fp->_p++;
438 fp->_r--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800439 wchar_t wc = L'\0';
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700440 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800441 nconv = mbrtowc(&wc, buf, bytes, &mbs);
442 if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700443 fp->_flags |= __SERR;
444 goto input_failure;
445 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800446 if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
447 if ((c == CT_CCL && wctob(wc) != EOF && !ccltab[wctob(wc)]) || (c == CT_STRING && iswspace(wc))) {
448 while (bytes != 0) {
449 bytes--;
450 ungetc(buf[bytes], fp);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700451 }
452 break;
453 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800454 if (wcp) wcp[n] = wc;
455 n++;
456 if (allocation != NULL && n == capacity) {
457 capacity *= 2;
458 wchar_t* new_allocation =
459 reinterpret_cast<wchar_t*>(realloc(allocation, sizeof(wchar_t) * capacity));
460 if (new_allocation == NULL) goto allocation_failure;
461 allocation = wcp = new_allocation;
462 }
463 nread += bytes;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700464 width--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800465 bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700466 }
467 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800468 if (bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700469 fp->_flags |= __SERR;
470 goto input_failure;
471 }
472 break;
473 }
474 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800475 if (c == CT_CCL && bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700476 fp->_flags |= __SERR;
477 goto input_failure;
478 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800479 if (allocation != NULL) {
480 *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
481 allocation = NULL;
482 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800483 } else if (flags & SUPPRESS) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700484 n = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800485 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !IsSpace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700486 n++, fp->_r--, fp->_p++;
487 if (--width == 0) break;
488 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800489 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700490 break;
491 }
492 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800493 nread += n;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700494 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800495 if (flags & ALLOCATE) {
496 capacity = MIN(width, 32);
497 allocation = p = reinterpret_cast<char*>(malloc(capacity));
498 if (allocation == NULL) goto allocation_failure;
499 } else {
500 p = va_arg(ap, char*);
501 }
502 n = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800503 while ((c == CT_CCL && ccltab[*fp->_p]) || (c == CT_STRING && !IsSpace(*fp->_p))) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700504 fp->_r--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800505 p[n++] = *fp->_p++;
506 if (allocation != NULL && n == capacity) {
507 capacity *= 2;
508 char* new_allocation = reinterpret_cast<char*>(realloc(allocation, capacity));
509 if (new_allocation == NULL) goto allocation_failure;
510 allocation = p = new_allocation;
511 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700512 if (--width == 0) break;
513 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800514 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700515 break;
516 }
517 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800518 nread += n;
519 if (allocation != NULL) {
520 *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
521 allocation = NULL;
522 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800523 }
524 if (c == CT_CCL && n == 0) goto match_failure;
525 if (!(flags & SUPPRESS)) {
526 if (flags & LONG) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800527 wcp[n] = L'\0';
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800528 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800529 p[n] = '\0';
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800530 }
531 ++nassigned;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700532 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700533 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700534
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700535 case CT_INT:
536 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800537#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700538 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800539#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700540 /* size_t is unsigned, hence this optimisation */
541 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
542 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800543#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700544 flags |= SIGNOK | NDIGITS | NZDIGITS;
545 for (p = buf; width; width--) {
546 c = *fp->_p;
547 /*
548 * Switch on the character; `goto ok'
549 * if we accept it as a part of number.
550 */
551 switch (c) {
552 /*
553 * The digit 0 is always legal, but is
554 * special. For %i conversions, if no
555 * digits (zero or nonzero) have been
556 * scanned (only signs), we will have
557 * base==0. In that case, we should set
558 * it to 8 and enable 0x prefixing.
559 * Also, if we have not scanned zero digits
560 * before this, do not turn off prefixing
561 * (someone else will turn it off if we
562 * have scanned any nonzero digits).
563 */
564 case '0':
565 if (base == 0) {
566 base = 8;
567 flags |= PFXOK;
568 }
569 if (flags & NZDIGITS)
570 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
571 else
572 flags &= ~(SIGNOK | PFXOK | NDIGITS);
573 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800574
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700575 /* 1 through 7 always legal */
576 case '1':
577 case '2':
578 case '3':
579 case '4':
580 case '5':
581 case '6':
582 case '7':
583 base = basefix[base];
584 flags &= ~(SIGNOK | PFXOK | NDIGITS);
585 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800586
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700587 /* digits 8 and 9 ok iff decimal or hex */
588 case '8':
589 case '9':
590 base = basefix[base];
591 if (base <= 8) break; /* not legal here */
592 flags &= ~(SIGNOK | PFXOK | NDIGITS);
593 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800594
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700595 /* letters ok iff hex */
596 case 'A':
597 case 'B':
598 case 'C':
599 case 'D':
600 case 'E':
601 case 'F':
602 case 'a':
603 case 'b':
604 case 'c':
605 case 'd':
606 case 'e':
607 case 'f':
608 /* no need to fix base here */
609 if (base <= 10) break; /* not legal here */
610 flags &= ~(SIGNOK | PFXOK | NDIGITS);
611 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800612
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700613 /* sign ok only as first character */
614 case '+':
615 case '-':
616 if (flags & SIGNOK) {
617 flags &= ~SIGNOK;
618 flags |= HAVESIGN;
619 goto ok;
620 }
621 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800622
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700623 /*
624 * x ok iff flag still set and 2nd char (or
625 * 3rd char if we have a sign).
626 */
627 case 'x':
628 case 'X':
629 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
630 base = 16; /* if %i */
631 flags &= ~PFXOK;
632 goto ok;
633 }
634 break;
635 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800636
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700637 /*
638 * If we got here, c is not a legal character
639 * for a number. Stop accumulating digits.
640 */
641 break;
642 ok:
643 /*
644 * c is legal: store it and look at the next.
645 */
646 *p++ = c;
647 if (--fp->_r > 0)
648 fp->_p++;
649 else if (__srefill(fp))
650 break; /* EOF */
651 }
652 /*
653 * If we had only a sign, it is no good; push
654 * back the sign. If the number ends in `x',
655 * it was [sign] '0' 'x', so push back the x
656 * and treat it as [sign] '0'.
657 */
658 if (flags & NDIGITS) {
659 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
660 goto match_failure;
661 }
662 c = ((u_char*)p)[-1];
663 if (c == 'x' || c == 'X') {
664 --p;
665 (void)ungetc(c, fp);
666 }
667 if ((flags & SUPPRESS) == 0) {
668 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800669
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700670 *p = '\0';
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800671 if (flags & UNSIGNED) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700672 res = strtoumax(buf, NULL, base);
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800673 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700674 res = strtoimax(buf, NULL, base);
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800675 }
676 if (flags & POINTER) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700677 *va_arg(ap, void**) = (void*)(uintptr_t)res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800678 } else if (flags & MAXINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700679 *va_arg(ap, intmax_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800680 } else if (flags & LLONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700681 *va_arg(ap, long long*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800682 } else if (flags & SIZEINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700683 *va_arg(ap, ssize_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800684 } else if (flags & PTRINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700685 *va_arg(ap, ptrdiff_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800686 } else if (flags & LONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700687 *va_arg(ap, long*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800688 } else if (flags & SHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700689 *va_arg(ap, short*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800690 } else if (flags & SHORTSHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700691 *va_arg(ap, signed char*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800692 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700693 *va_arg(ap, int*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800694 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700695 nassigned++;
696 }
697 nread += p - buf;
698 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800699
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700700 case CT_FLOAT:
701 /* scan a floating point number as if by strtod */
702 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
703 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
704 if ((flags & SUPPRESS) == 0) {
705 if (flags & LONGDBL) {
706 long double res = strtold(buf, &p);
707 *va_arg(ap, long double*) = res;
708 } else if (flags & LONG) {
709 double res = strtod(buf, &p);
710 *va_arg(ap, double*) = res;
711 } else {
712 float res = strtof(buf, &p);
713 *va_arg(ap, float*) = res;
714 }
715 if ((size_t)(p - buf) != width) abort();
716 nassigned++;
717 }
718 nread += width;
719 break;
720 }
721 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800722allocation_failure:
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800723input_failure:
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800724 free(allocation);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700725 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800726match_failure:
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800727 return nassigned;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800728}
729
730/*
731 * Fill in the given table from the scanset at the given format
732 * (just after `['). Return a pointer to the character past the
733 * closing `]'. The table has a 1 wherever characters should be
734 * considered part of the scanset.
735 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800736static const unsigned char* __sccl(char* tab, const unsigned char* fmt) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700737 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800738
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700739 /* first `clear' the whole table */
740 c = *fmt++; /* first char hat => negated scanset */
741 if (c == '^') {
742 v = 1; /* default => accept */
743 c = *fmt++; /* get new first char */
744 } else
745 v = 0; /* default => reject */
746 /* should probably use memset here */
747 for (n = 0; n < 256; n++) tab[n] = v;
748 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700750 /*
751 * Now set the entries corresponding to the actual scanset
752 * to the opposite of the above.
753 *
754 * The first character may be ']' (or '-') without being special;
755 * the last character may be '-'.
756 */
757 v = 1 - v;
758 for (;;) {
759 tab[c] = v; /* take character c */
760 doswitch:
761 n = *fmt++; /* and examine the next */
762 switch (n) {
763 case 0: /* format ended too soon */
764 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800765
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700766 case '-':
767 /*
768 * A scanset of the form
769 * [01+-]
770 * is defined as `the digit 0, the digit 1,
771 * the character +, the character -', but
772 * the effect of a scanset such as
773 * [a-zA-Z0-9]
774 * is implementation defined. The V7 Unix
775 * scanf treats `a-z' as `the letters a through
776 * z', but treats `a-a' as `the letter a, the
777 * character -, and the letter a'.
778 *
779 * For compatibility, the `-' is not considerd
780 * to define a range if the character following
781 * it is either a close bracket (required by ANSI)
782 * or is not numerically greater than the character
783 * we just stored in the table (c).
784 */
785 n = *fmt;
786 if (n == ']' || n < c) {
787 c = '-';
788 break; /* resume the for(;;) */
789 }
790 fmt++;
791 do { /* fill in the range */
792 tab[++c] = v;
793 } while (c < n);
794#if 1 /* XXX another disgusting compatibility hack */
795 /*
796 * Alas, the V7 Unix scanf also treats formats
797 * such as [a-c-e] as `the letters a through e'.
798 * This too is permitted by the standard....
799 */
800 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800801#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700802 c = *fmt++;
803 if (c == 0) return (fmt - 1);
804 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800805#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700806 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800807
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700808 case ']': /* end of scanset */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800809 return fmt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800810
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700811 default: /* just another character */
812 c = n;
813 break;
814 }
815 }
816 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800817}