blob: 65f54a521daf7fe7b54c6802b5b5dc82571e40b8 [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
zijunzhao78904842023-05-09 00:54:00 +000034#include "scanf_common.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080035
Elliott Hughes38e4aef2018-01-18 10:21:29 -080036static const unsigned char* __sccl(char*, const unsigned char*);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038/*
Elliott Hughes603332f2014-03-12 17:10:41 -070039 * Internal, unlocked version of vfscanf
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -080041int __svfscanf(FILE* fp, const char* fmt0, va_list ap) {
42 const unsigned char* fmt = reinterpret_cast<const unsigned char*>(fmt0);
Elliott Hughesc8f2c522017-10-31 13:07:51 -070043 int c; /* character from format, or conversion */
44 size_t width; /* field width, or 0 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -080045 char* p;
46 wchar_t* wcp;
47 size_t n;
Elliott Hughesc8f2c522017-10-31 13:07:51 -070048 int flags; /* flags as defined above */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070049 int nassigned; /* number of fields assigned */
50 int nread; /* number of characters consumed from fp */
51 int base; /* base argument to strtoimax/strtouimax */
52 char ccltab[256]; /* character class table for %[...] */
53 char buf[BUF]; /* buffer for numeric conversions */
Elliott Hughesc8f2c522017-10-31 13:07:51 -070054 size_t nconv; /* length of multibyte sequence converted */
55 mbstate_t mbs;
Yi Kong32bc0fc2018-08-02 17:31:13 -070056 void* allocation = nullptr; // Allocated but unassigned result for %mc/%ms/%m[.
Elliott Hughes38e4aef2018-01-18 10:21:29 -080057 size_t capacity = 0; // Number of char/wchar_t units allocated in `allocation`.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080058
Elliott Hughes531199c2023-05-09 16:11:49 -070059 _SET_ORIENTATION(fp, ORIENT_BYTES);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060
Elliott Hughesc8f2c522017-10-31 13:07:51 -070061 nassigned = 0;
62 nread = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -070063 for (;;) {
64 c = *fmt++;
Elliott Hughes38e4aef2018-01-18 10:21:29 -080065 if (c == 0) return nassigned;
Elliott Hughesbf03c012020-02-05 11:38:29 -080066 if (isspace(c)) {
67 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++;
Elliott Hughesc8f2c522017-10-31 13:07:51 -070068 continue;
69 }
70 if (c != '%') goto literal;
71 width = 0;
72 flags = 0;
73 /*
74 * switch on the format. continue if done;
75 * break once format type is derived.
76 */
Elliott Hughes1133fec2017-12-19 16:30:55 -080077again:
Elliott Hughesc8f2c522017-10-31 13:07:51 -070078 c = *fmt++;
zijunzhao78904842023-05-09 00:54:00 +000079reswitch:
Elliott Hughesc8f2c522017-10-31 13:07:51 -070080 switch (c) {
81 case '%':
Elliott Hughes1133fec2017-12-19 16:30:55 -080082literal:
Elliott Hughesc8f2c522017-10-31 13:07:51 -070083 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
84 if (*fp->_p != c) goto match_failure;
85 fp->_r--, fp->_p++;
86 nread++;
87 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088
Elliott Hughesc8f2c522017-10-31 13:07:51 -070089 case '*':
90 flags |= SUPPRESS;
91 goto again;
92 case 'j':
93 flags |= MAXINT;
94 goto again;
95 case 'L':
96 flags |= LONGDBL;
97 goto again;
98 case 'h':
99 if (*fmt == 'h') {
100 fmt++;
101 flags |= SHORTSHORT;
102 } else {
103 flags |= SHORT;
104 }
105 goto again;
106 case 'l':
107 if (*fmt == 'l') {
108 fmt++;
109 flags |= LLONG;
110 } else {
111 flags |= LONG;
112 }
113 goto again;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800114 case 'm':
115 flags |= ALLOCATE;
116 goto again;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700117 case 'q':
118 flags |= LLONG; /* deprecated */
119 goto again;
120 case 't':
121 flags |= PTRINT;
122 goto again;
123 case 'z':
124 flags |= SIZEINT;
125 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800126
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700127 case '0':
128 case '1':
129 case '2':
130 case '3':
131 case '4':
132 case '5':
133 case '6':
134 case '7':
135 case '8':
136 case '9':
137 width = width * 10 + c - '0';
138 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700140 /*
141 * Conversions.
142 * Those marked `compat' are for 4.[123]BSD compatibility.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700143 */
Elliott Hughes1f462de2022-08-05 22:51:05 +0000144 case 'b':
145 c = CT_INT;
146 base = 2;
147 flags |= PFBOK; /* enable 0b prefixing */
148 break;
149
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700150 case 'D': /* compat */
151 flags |= LONG;
George Burgess IVfa5410f2018-08-13 17:44:06 -0700152 __BIONIC_FALLTHROUGH;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700153 case 'd':
154 c = CT_INT;
155 base = 10;
156 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700158 case 'i':
159 c = CT_INT;
160 base = 0;
161 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800162
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700163 case 'O': /* compat */
164 flags |= LONG;
George Burgess IVfa5410f2018-08-13 17:44:06 -0700165 __BIONIC_FALLTHROUGH;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700166 case 'o':
167 c = CT_INT;
168 flags |= UNSIGNED;
169 base = 8;
170 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800171
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700172 case 'u':
173 c = CT_INT;
174 flags |= UNSIGNED;
175 base = 10;
176 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800177
zijunzhao78904842023-05-09 00:54:00 +0000178 case 'w': {
179 int size = 0;
180 bool fast = false;
181 c = *fmt++;
182 while (is_digit(c)) {
183 APPEND_DIGIT(size, c);
184 c = *fmt++;
185 }
186 flags |= w_to_flag(size, fast);
187 goto reswitch;
188 }
189
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700190 case 'X':
191 case 'x':
192 flags |= PFXOK; /* enable 0x prefixing */
193 c = CT_INT;
194 flags |= UNSIGNED;
195 base = 16;
196 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800197
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700198 case 'e':
199 case 'E':
200 case 'f':
201 case 'F':
202 case 'g':
203 case 'G':
204 case 'a':
205 case 'A':
206 c = CT_FLOAT;
207 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800208
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700209 case 's':
Elliott Hughes3048a362018-01-19 17:58:07 -0800210 memset(ccltab, 1, 256);
211 ccltab['\t'] = ccltab['\n'] = ccltab['\v'] = ccltab['\f'] = ccltab['\r'] = ccltab[' '] = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700212 c = CT_STRING;
213 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800214
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700215 case '[':
216 fmt = __sccl(ccltab, fmt);
217 flags |= NOSKIP;
218 c = CT_CCL;
219 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700221 case 'c':
222 flags |= NOSKIP;
223 c = CT_CHAR;
224 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800225
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700226 case 'p': /* pointer format is like hex */
227 flags |= POINTER | PFXOK;
228 c = CT_INT;
229 flags |= UNSIGNED;
230 base = 16;
231 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800232
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700233 case 'n':
234 if (flags & SUPPRESS) continue;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800235 if (flags & SHORTSHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700236 *va_arg(ap, signed char*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800237 } else if (flags & SHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700238 *va_arg(ap, short*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800239 } else if (flags & LONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700240 *va_arg(ap, long*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800241 } else if (flags & SIZEINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700242 *va_arg(ap, ssize_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800243 } else if (flags & PTRINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700244 *va_arg(ap, ptrdiff_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800245 } else if (flags & LLONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700246 *va_arg(ap, long long*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800247 } else if (flags & MAXINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700248 *va_arg(ap, intmax_t*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800249 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700250 *va_arg(ap, int*) = nread;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800251 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700252 continue;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800253
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700254 /*
255 * Disgusting backwards compatibility hacks. XXX
256 */
257 case '\0': /* compat */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800258 return EOF;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700260 default: /* compat */
Elliott Hughesbf03c012020-02-05 11:38:29 -0800261 if (isupper(c)) flags |= LONG;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700262 c = CT_INT;
263 base = 10;
264 break;
265 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800266
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800267 if ((flags & ALLOCATE) != 0 && c > CT_STRING) {
268 __fortify_fatal("scanf 'm' only works with %%c/%%s/%%[");
269 }
270 if ((flags & (ALLOCATE|SUPPRESS)) == (ALLOCATE|SUPPRESS)) {
271 __fortify_fatal("scanf 'm' makes no sense with '*'");
272 }
273
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700274 /*
275 * We have a conversion that requires input.
276 */
277 if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800278
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700279 /*
280 * Consume leading white space, except for formats
281 * that suppress this.
282 */
283 if ((flags & NOSKIP) == 0) {
Elliott Hughesbf03c012020-02-05 11:38:29 -0800284 while (isspace(*fp->_p)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700285 nread++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800286 if (--fp->_r > 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700287 fp->_p++;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800288 } else if (__srefill(fp)) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700289 goto input_failure;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800290 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700291 }
292 /*
293 * Note that there is at least one character in
294 * the buffer, so conversions that do not set NOSKIP
295 * ca no longer result in an input failure.
296 */
297 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800298
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700299 /*
300 * Do the conversion.
301 */
302 switch (c) {
303 case CT_CHAR:
304 /* scan arbitrary characters (sets NOSKIP) */
305 if (width == 0) width = 1;
306 if (flags & LONG) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800307 if (flags & ALLOCATE) {
308 allocation = wcp = reinterpret_cast<wchar_t*>(malloc(width * sizeof(wchar_t)));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700309 if (allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800310 } else if (flags & SUPPRESS) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700311 wcp = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800312 } else {
313 wcp = va_arg(ap, wchar_t*);
314 }
315 size_t bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700316 while (width != 0) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800317 if (bytes == MB_CUR_MAX) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700318 fp->_flags |= __SERR;
319 goto input_failure;
320 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800321 buf[bytes++] = *fp->_p;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700322 fp->_p++;
323 fp->_r--;
324 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800325 nconv = mbrtowc(wcp, buf, bytes, &mbs);
326 if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700327 fp->_flags |= __SERR;
328 goto input_failure;
329 }
330 if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800331 if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
332 nread += bytes;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700333 width--;
334 if (!(flags & SUPPRESS)) wcp++;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800335 bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700336 }
337 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800338 if (bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700339 fp->_flags |= __SERR;
340 goto input_failure;
341 }
342 break;
343 }
344 }
Yi Kong32bc0fc2018-08-02 17:31:13 -0700345 if (allocation != nullptr) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800346 *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700347 allocation = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800348 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700349 if (!(flags & SUPPRESS)) nassigned++;
350 } else if (flags & SUPPRESS) {
351 size_t sum = 0;
352 for (;;) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800353 if ((n = fp->_r) < width) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700354 sum += n;
355 width -= n;
356 fp->_p += n;
357 if (__srefill(fp)) {
358 if (sum == 0) goto input_failure;
359 break;
360 }
361 } else {
362 sum += width;
363 fp->_r -= width;
364 fp->_p += width;
365 break;
366 }
367 }
368 nread += sum;
369 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800370 if (flags & ALLOCATE) {
371 allocation = p = reinterpret_cast<char*>(malloc(width));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700372 if (allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800373 } else {
374 p = va_arg(ap, char*);
375 }
376 size_t r = fread(p, 1, width, fp);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700377 if (r == 0) goto input_failure;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700378 if (allocation != nullptr) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800379 *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700380 allocation = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800381 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700382 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.
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800391 if (width == 0) width = SIZE_MAX;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700392 if (flags & LONG) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800393 // TODO: since no-one cares, replace this with a simple fgetwc loop?
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700394 n = 0;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800395 if (flags & ALLOCATE) {
396 capacity = MIN(width, 32);
397 allocation = wcp = reinterpret_cast<wchar_t*>(malloc(sizeof(wchar_t) * capacity));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700398 if (allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800399 } else if (flags & SUPPRESS) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700400 wcp = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800401 } else {
402 wcp = va_arg(ap, wchar_t*);
403 }
404 size_t bytes = 0;
Elliott Hughesbf03c012020-02-05 11:38:29 -0800405 while ((c == CT_CCL || !isspace(*fp->_p)) && width != 0) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800406 if (bytes == MB_CUR_MAX) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700407 fp->_flags |= __SERR;
408 goto input_failure;
409 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800410 buf[bytes++] = *fp->_p;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700411 fp->_p++;
412 fp->_r--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800413 wchar_t wc = L'\0';
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700414 memset(&mbs, 0, sizeof(mbs));
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800415 nconv = mbrtowc(&wc, buf, bytes, &mbs);
416 if (nconv == __MB_ERR_ILLEGAL_SEQUENCE) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700417 fp->_flags |= __SERR;
418 goto input_failure;
419 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800420 if (nconv != __MB_ERR_INCOMPLETE_SEQUENCE) {
421 if ((c == CT_CCL && wctob(wc) != EOF && !ccltab[wctob(wc)]) || (c == CT_STRING && iswspace(wc))) {
422 while (bytes != 0) {
423 bytes--;
424 ungetc(buf[bytes], fp);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700425 }
426 break;
427 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800428 if (wcp) wcp[n] = wc;
429 n++;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700430 if (allocation != nullptr && n == capacity) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800431 capacity *= 2;
432 wchar_t* new_allocation =
433 reinterpret_cast<wchar_t*>(realloc(allocation, sizeof(wchar_t) * capacity));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700434 if (new_allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800435 allocation = wcp = new_allocation;
436 }
437 nread += bytes;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700438 width--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800439 bytes = 0;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700440 }
441 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800442 if (bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700443 fp->_flags |= __SERR;
444 goto input_failure;
445 }
446 break;
447 }
448 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800449 if (c == CT_CCL && bytes != 0) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700450 fp->_flags |= __SERR;
451 goto input_failure;
452 }
Yi Kong32bc0fc2018-08-02 17:31:13 -0700453 if (allocation != nullptr) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800454 *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700455 allocation = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800456 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800457 } else if (flags & SUPPRESS) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700458 n = 0;
Elliott Hughes3048a362018-01-19 17:58:07 -0800459 while (ccltab[*fp->_p]) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700460 n++, fp->_r--, fp->_p++;
461 if (--width == 0) break;
462 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800463 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700464 break;
465 }
466 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800467 nread += n;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700468 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800469 if (flags & ALLOCATE) {
470 capacity = MIN(width, 32);
471 allocation = p = reinterpret_cast<char*>(malloc(capacity));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700472 if (allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800473 } else {
474 p = va_arg(ap, char*);
475 }
476 n = 0;
Elliott Hughes3048a362018-01-19 17:58:07 -0800477 while (ccltab[*fp->_p]) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700478 fp->_r--;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800479 p[n++] = *fp->_p++;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700480 if (allocation != nullptr && n == capacity) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800481 capacity *= 2;
482 char* new_allocation = reinterpret_cast<char*>(realloc(allocation, capacity));
Yi Kong32bc0fc2018-08-02 17:31:13 -0700483 if (new_allocation == nullptr) goto allocation_failure;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800484 allocation = p = new_allocation;
485 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700486 if (--width == 0) break;
487 if (fp->_r <= 0 && __srefill(fp)) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800488 if (c == CT_CCL && n == 0) goto input_failure;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700489 break;
490 }
491 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800492 nread += n;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700493 if (allocation != nullptr) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800494 *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700495 allocation = nullptr;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800496 }
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800497 }
498 if (c == CT_CCL && n == 0) goto match_failure;
499 if (!(flags & SUPPRESS)) {
500 if (flags & LONG) {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800501 wcp[n] = L'\0';
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800502 } else {
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800503 p[n] = '\0';
Elliott Hughesbf9cb9e2017-12-11 12:39:01 -0800504 }
505 ++nassigned;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700506 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700507 break;
Elliott Hughes603332f2014-03-12 17:10:41 -0700508
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700509 case CT_INT:
510 /* scan an integer as if by strtoimax/strtoumax */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800511#ifdef hardway
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700512 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800513#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700514 /* size_t is unsigned, hence this optimisation */
515 if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
516 width++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800517#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700518 flags |= SIGNOK | NDIGITS | NZDIGITS;
519 for (p = buf; width; width--) {
520 c = *fp->_p;
521 /*
522 * Switch on the character; `goto ok'
523 * if we accept it as a part of number.
524 */
525 switch (c) {
526 /*
527 * The digit 0 is always legal, but is
528 * special. For %i conversions, if no
529 * digits (zero or nonzero) have been
530 * scanned (only signs), we will have
531 * base==0. In that case, we should set
Elliott Hughes1f462de2022-08-05 22:51:05 +0000532 * it to 8 and enable 0b/0x prefixing.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700533 * Also, if we have not scanned zero digits
534 * before this, do not turn off prefixing
535 * (someone else will turn it off if we
536 * have scanned any nonzero digits).
537 */
538 case '0':
539 if (base == 0) {
540 base = 8;
Elliott Hughes1f462de2022-08-05 22:51:05 +0000541 flags |= PFBOK | PFXOK;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700542 }
Elliott Hughes1f462de2022-08-05 22:51:05 +0000543 if (flags & NZDIGITS) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700544 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
Elliott Hughes1f462de2022-08-05 22:51:05 +0000545 } else {
546 flags &= ~(SIGNOK | PFBOK | PFXOK | NDIGITS);
547 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700548 goto ok;
Elliott Hughes1f462de2022-08-05 22:51:05 +0000549 case 'B':
550 case 'b':
551 // Is this 'b' or 'B' potentially part of an "0b" prefix?
552 if ((flags & PFBOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
553 base = 2;
554 flags &= ~PFBOK;
555 goto ok;
556 }
557 // No? Fall through and see if it's a hex digit instead then...
558 __BIONIC_FALLTHROUGH;
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700559 case '1':
560 case '2':
561 case '3':
562 case '4':
563 case '5':
564 case '6':
565 case '7':
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700566 case '8':
567 case '9':
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700568 case 'A':
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700569 case 'C':
570 case 'D':
571 case 'E':
572 case 'F':
573 case 'a':
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700574 case 'c':
575 case 'd':
576 case 'e':
577 case 'f':
Elliott Hughes1f462de2022-08-05 22:51:05 +0000578 if (base == 0) base = 10;
579 if (base != 16 && (c - '0') >= base) break; /* not legal here */
580 flags &= ~(SIGNOK | PFBOK | PFXOK | NDIGITS);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700581 goto ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800582
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700583 /* sign ok only as first character */
584 case '+':
585 case '-':
586 if (flags & SIGNOK) {
587 flags &= ~SIGNOK;
588 flags |= HAVESIGN;
589 goto ok;
590 }
591 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800592
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700593 /*
594 * x ok iff flag still set and 2nd char (or
595 * 3rd char if we have a sign).
596 */
597 case 'x':
598 case 'X':
599 if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
600 base = 16; /* if %i */
601 flags &= ~PFXOK;
602 goto ok;
603 }
604 break;
605 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800606
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700607 /*
608 * If we got here, c is not a legal character
609 * for a number. Stop accumulating digits.
610 */
611 break;
612 ok:
613 /*
614 * c is legal: store it and look at the next.
615 */
616 *p++ = c;
617 if (--fp->_r > 0)
618 fp->_p++;
619 else if (__srefill(fp))
620 break; /* EOF */
621 }
622 /*
Elliott Hughes1f462de2022-08-05 22:51:05 +0000623 * If we had only a sign, it is no good; push back the sign.
624 * If the number was `[-+]0[BbXx]`, push back and treat it
625 * as `[-+]0`.
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700626 */
627 if (flags & NDIGITS) {
628 if (p > buf) (void)ungetc(*(u_char*)--p, fp);
629 goto match_failure;
630 }
631 c = ((u_char*)p)[-1];
Elliott Hughes1f462de2022-08-05 22:51:05 +0000632 if ((base == 2 && (c == 'b' || c == 'B')) || c == 'x' || c == 'X') {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700633 --p;
634 (void)ungetc(c, fp);
635 }
636 if ((flags & SUPPRESS) == 0) {
637 uintmax_t res;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800638
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700639 *p = '\0';
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800640 if (flags & UNSIGNED) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700641 res = strtoumax(buf, nullptr, base);
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800642 } else {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700643 res = strtoimax(buf, nullptr, base);
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800644 }
645 if (flags & POINTER) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700646 *va_arg(ap, void**) = (void*)(uintptr_t)res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800647 } else if (flags & MAXINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700648 *va_arg(ap, intmax_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800649 } else if (flags & LLONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700650 *va_arg(ap, long long*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800651 } else if (flags & SIZEINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700652 *va_arg(ap, ssize_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800653 } else if (flags & PTRINT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700654 *va_arg(ap, ptrdiff_t*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800655 } else if (flags & LONG) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700656 *va_arg(ap, long*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800657 } else if (flags & SHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700658 *va_arg(ap, short*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800659 } else if (flags & SHORTSHORT) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700660 *va_arg(ap, signed char*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800661 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700662 *va_arg(ap, int*) = res;
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800663 }
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700664 nassigned++;
665 }
666 nread += p - buf;
667 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800668
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700669 case CT_FLOAT:
670 /* scan a floating point number as if by strtod */
671 if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
672 if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
673 if ((flags & SUPPRESS) == 0) {
674 if (flags & LONGDBL) {
675 long double res = strtold(buf, &p);
676 *va_arg(ap, long double*) = res;
677 } else if (flags & LONG) {
678 double res = strtod(buf, &p);
679 *va_arg(ap, double*) = res;
680 } else {
681 float res = strtof(buf, &p);
682 *va_arg(ap, float*) = res;
683 }
684 if ((size_t)(p - buf) != width) abort();
685 nassigned++;
686 }
687 nread += width;
688 break;
689 }
690 }
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800691allocation_failure:
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800692input_failure:
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800693 free(allocation);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700694 if (nassigned == 0) nassigned = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800695match_failure:
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800696 return nassigned;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800697}
698
699/*
700 * Fill in the given table from the scanset at the given format
701 * (just after `['). Return a pointer to the character past the
702 * closing `]'. The table has a 1 wherever characters should be
703 * considered part of the scanset.
704 */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800705static const unsigned char* __sccl(char* tab, const unsigned char* fmt) {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700706 int c, n, v;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800707
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700708 /* first `clear' the whole table */
709 c = *fmt++; /* first char hat => negated scanset */
710 if (c == '^') {
711 v = 1; /* default => accept */
712 c = *fmt++; /* get new first char */
Elliott Hughes3048a362018-01-19 17:58:07 -0800713 } else {
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700714 v = 0; /* default => reject */
Elliott Hughes3048a362018-01-19 17:58:07 -0800715 }
716 memset(tab, v, 256);
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700717 if (c == 0) return (fmt - 1); /* format ended before closing ] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800718
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700719 /*
720 * Now set the entries corresponding to the actual scanset
721 * to the opposite of the above.
722 *
723 * The first character may be ']' (or '-') without being special;
724 * the last character may be '-'.
725 */
726 v = 1 - v;
727 for (;;) {
728 tab[c] = v; /* take character c */
729 doswitch:
730 n = *fmt++; /* and examine the next */
731 switch (n) {
732 case 0: /* format ended too soon */
733 return (fmt - 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800734
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700735 case '-':
736 /*
737 * A scanset of the form
738 * [01+-]
739 * is defined as `the digit 0, the digit 1,
740 * the character +, the character -', but
741 * the effect of a scanset such as
742 * [a-zA-Z0-9]
743 * is implementation defined. The V7 Unix
744 * scanf treats `a-z' as `the letters a through
745 * z', but treats `a-a' as `the letter a, the
746 * character -, and the letter a'.
747 *
748 * For compatibility, the `-' is not considerd
749 * to define a range if the character following
750 * it is either a close bracket (required by ANSI)
751 * or is not numerically greater than the character
752 * we just stored in the table (c).
753 */
754 n = *fmt;
755 if (n == ']' || n < c) {
756 c = '-';
757 break; /* resume the for(;;) */
758 }
759 fmt++;
760 do { /* fill in the range */
761 tab[++c] = v;
762 } while (c < n);
763#if 1 /* XXX another disgusting compatibility hack */
764 /*
765 * Alas, the V7 Unix scanf also treats formats
766 * such as [a-c-e] as `the letters a through e'.
767 * This too is permitted by the standard....
768 */
769 goto doswitch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800770#else
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700771 c = *fmt++;
772 if (c == 0) return (fmt - 1);
773 if (c == ']') return (fmt);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800774#endif
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700775 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800776
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700777 case ']': /* end of scanset */
Elliott Hughes38e4aef2018-01-18 10:21:29 -0800778 return fmt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800779
Elliott Hughesc8f2c522017-10-31 13:07:51 -0700780 default: /* just another character */
781 c = n;
782 break;
783 }
784 }
785 /* NOTREACHED */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800786}