xref: /aosp_15_r20/bionic/libc/stdio/vfscanf.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*	$OpenBSD: vfscanf.c,v 1.31 2014/03/19 05:17:01 guenther Exp $ */
2*8d67ca89SAndroid Build Coastguard Worker /*-
3*8d67ca89SAndroid Build Coastguard Worker  * Copyright (c) 1990, 1993
4*8d67ca89SAndroid Build Coastguard Worker  *	The Regents of the University of California.  All rights reserved.
5*8d67ca89SAndroid Build Coastguard Worker  *
6*8d67ca89SAndroid Build Coastguard Worker  * This code is derived from software contributed to Berkeley by
7*8d67ca89SAndroid Build Coastguard Worker  * Chris Torek.
8*8d67ca89SAndroid Build Coastguard Worker  *
9*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
10*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
11*8d67ca89SAndroid Build Coastguard Worker  * are met:
12*8d67ca89SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
13*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
14*8d67ca89SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
15*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
16*8d67ca89SAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
17*8d67ca89SAndroid Build Coastguard Worker  * 3. Neither the name of the University nor the names of its contributors
18*8d67ca89SAndroid Build Coastguard Worker  *    may be used to endorse or promote products derived from this software
19*8d67ca89SAndroid Build Coastguard Worker  *    without specific prior written permission.
20*8d67ca89SAndroid Build Coastguard Worker  *
21*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*8d67ca89SAndroid Build Coastguard Worker  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*8d67ca89SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*8d67ca89SAndroid Build Coastguard Worker  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*8d67ca89SAndroid Build Coastguard Worker  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*8d67ca89SAndroid Build Coastguard Worker  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*8d67ca89SAndroid Build Coastguard Worker  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*8d67ca89SAndroid Build Coastguard Worker  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*8d67ca89SAndroid Build Coastguard Worker  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*8d67ca89SAndroid Build Coastguard Worker  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
32*8d67ca89SAndroid Build Coastguard Worker  */
33*8d67ca89SAndroid Build Coastguard Worker 
34*8d67ca89SAndroid Build Coastguard Worker #include "scanf_common.h"
35*8d67ca89SAndroid Build Coastguard Worker 
36*8d67ca89SAndroid Build Coastguard Worker static const unsigned char* __sccl(char*, const unsigned char*);
37*8d67ca89SAndroid Build Coastguard Worker 
38*8d67ca89SAndroid Build Coastguard Worker /*
39*8d67ca89SAndroid Build Coastguard Worker  * Internal, unlocked version of vfscanf
40*8d67ca89SAndroid Build Coastguard Worker  */
__svfscanf(FILE * fp,const char * fmt0,va_list ap)41*8d67ca89SAndroid Build Coastguard Worker int __svfscanf(FILE* fp, const char* fmt0, va_list ap) {
42*8d67ca89SAndroid Build Coastguard Worker   const unsigned char* fmt = reinterpret_cast<const unsigned char*>(fmt0);
43*8d67ca89SAndroid Build Coastguard Worker   int c;            /* character from format, or conversion */
44*8d67ca89SAndroid Build Coastguard Worker   size_t width;     /* field width, or 0 */
45*8d67ca89SAndroid Build Coastguard Worker   char* p;
46*8d67ca89SAndroid Build Coastguard Worker   wchar_t* wcp;
47*8d67ca89SAndroid Build Coastguard Worker   size_t n;
48*8d67ca89SAndroid Build Coastguard Worker   int flags;        /* flags as defined above */
49*8d67ca89SAndroid Build Coastguard Worker   int nassigned;    /* number of fields assigned */
50*8d67ca89SAndroid Build Coastguard Worker   int nread;        /* number of characters consumed from fp */
51*8d67ca89SAndroid Build Coastguard Worker   int base;         /* base argument to strtoimax/strtouimax */
52*8d67ca89SAndroid Build Coastguard Worker   char ccltab[256]; /* character class table for %[...] */
53*8d67ca89SAndroid Build Coastguard Worker   char buf[BUF];    /* buffer for numeric conversions */
54*8d67ca89SAndroid Build Coastguard Worker   size_t nconv;     /* length of multibyte sequence converted */
55*8d67ca89SAndroid Build Coastguard Worker   mbstate_t mbs;
56*8d67ca89SAndroid Build Coastguard Worker   void* allocation = nullptr; // Allocated but unassigned result for %mc/%ms/%m[.
57*8d67ca89SAndroid Build Coastguard Worker   size_t capacity = 0; // Number of char/wchar_t units allocated in `allocation`.
58*8d67ca89SAndroid Build Coastguard Worker 
59*8d67ca89SAndroid Build Coastguard Worker   _SET_ORIENTATION(fp, ORIENT_BYTES);
60*8d67ca89SAndroid Build Coastguard Worker 
61*8d67ca89SAndroid Build Coastguard Worker   nassigned = 0;
62*8d67ca89SAndroid Build Coastguard Worker   nread = 0;
63*8d67ca89SAndroid Build Coastguard Worker   for (;;) {
64*8d67ca89SAndroid Build Coastguard Worker     c = *fmt++;
65*8d67ca89SAndroid Build Coastguard Worker     if (c == 0) return nassigned;
66*8d67ca89SAndroid Build Coastguard Worker     if (isspace(c)) {
67*8d67ca89SAndroid Build Coastguard Worker       while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++;
68*8d67ca89SAndroid Build Coastguard Worker       continue;
69*8d67ca89SAndroid Build Coastguard Worker     }
70*8d67ca89SAndroid Build Coastguard Worker     if (c != '%') goto literal;
71*8d67ca89SAndroid Build Coastguard Worker     width = 0;
72*8d67ca89SAndroid Build Coastguard Worker     flags = 0;
73*8d67ca89SAndroid Build Coastguard Worker     /*
74*8d67ca89SAndroid Build Coastguard Worker      * switch on the format.  continue if done;
75*8d67ca89SAndroid Build Coastguard Worker      * break once format type is derived.
76*8d67ca89SAndroid Build Coastguard Worker      */
77*8d67ca89SAndroid Build Coastguard Worker again:
78*8d67ca89SAndroid Build Coastguard Worker     c = *fmt++;
79*8d67ca89SAndroid Build Coastguard Worker reswitch:
80*8d67ca89SAndroid Build Coastguard Worker     switch (c) {
81*8d67ca89SAndroid Build Coastguard Worker       case '%':
82*8d67ca89SAndroid Build Coastguard Worker literal:
83*8d67ca89SAndroid Build Coastguard Worker         if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
84*8d67ca89SAndroid Build Coastguard Worker         if (*fp->_p != c) goto match_failure;
85*8d67ca89SAndroid Build Coastguard Worker         fp->_r--, fp->_p++;
86*8d67ca89SAndroid Build Coastguard Worker         nread++;
87*8d67ca89SAndroid Build Coastguard Worker         continue;
88*8d67ca89SAndroid Build Coastguard Worker 
89*8d67ca89SAndroid Build Coastguard Worker       case '*':
90*8d67ca89SAndroid Build Coastguard Worker         flags |= SUPPRESS;
91*8d67ca89SAndroid Build Coastguard Worker         goto again;
92*8d67ca89SAndroid Build Coastguard Worker       case 'j':
93*8d67ca89SAndroid Build Coastguard Worker         flags |= MAXINT;
94*8d67ca89SAndroid Build Coastguard Worker         goto again;
95*8d67ca89SAndroid Build Coastguard Worker       case 'L':
96*8d67ca89SAndroid Build Coastguard Worker         flags |= LONGDBL;
97*8d67ca89SAndroid Build Coastguard Worker         goto again;
98*8d67ca89SAndroid Build Coastguard Worker       case 'h':
99*8d67ca89SAndroid Build Coastguard Worker         if (*fmt == 'h') {
100*8d67ca89SAndroid Build Coastguard Worker           fmt++;
101*8d67ca89SAndroid Build Coastguard Worker           flags |= SHORTSHORT;
102*8d67ca89SAndroid Build Coastguard Worker         } else {
103*8d67ca89SAndroid Build Coastguard Worker           flags |= SHORT;
104*8d67ca89SAndroid Build Coastguard Worker         }
105*8d67ca89SAndroid Build Coastguard Worker         goto again;
106*8d67ca89SAndroid Build Coastguard Worker       case 'l':
107*8d67ca89SAndroid Build Coastguard Worker         if (*fmt == 'l') {
108*8d67ca89SAndroid Build Coastguard Worker           fmt++;
109*8d67ca89SAndroid Build Coastguard Worker           flags |= LLONG;
110*8d67ca89SAndroid Build Coastguard Worker         } else {
111*8d67ca89SAndroid Build Coastguard Worker           flags |= LONG;
112*8d67ca89SAndroid Build Coastguard Worker         }
113*8d67ca89SAndroid Build Coastguard Worker         goto again;
114*8d67ca89SAndroid Build Coastguard Worker       case 'm':
115*8d67ca89SAndroid Build Coastguard Worker         flags |= ALLOCATE;
116*8d67ca89SAndroid Build Coastguard Worker         goto again;
117*8d67ca89SAndroid Build Coastguard Worker       case 'q':
118*8d67ca89SAndroid Build Coastguard Worker         flags |= LLONG; /* deprecated */
119*8d67ca89SAndroid Build Coastguard Worker         goto again;
120*8d67ca89SAndroid Build Coastguard Worker       case 't':
121*8d67ca89SAndroid Build Coastguard Worker         flags |= PTRINT;
122*8d67ca89SAndroid Build Coastguard Worker         goto again;
123*8d67ca89SAndroid Build Coastguard Worker       case 'z':
124*8d67ca89SAndroid Build Coastguard Worker         flags |= SIZEINT;
125*8d67ca89SAndroid Build Coastguard Worker         goto again;
126*8d67ca89SAndroid Build Coastguard Worker 
127*8d67ca89SAndroid Build Coastguard Worker       case '0':
128*8d67ca89SAndroid Build Coastguard Worker       case '1':
129*8d67ca89SAndroid Build Coastguard Worker       case '2':
130*8d67ca89SAndroid Build Coastguard Worker       case '3':
131*8d67ca89SAndroid Build Coastguard Worker       case '4':
132*8d67ca89SAndroid Build Coastguard Worker       case '5':
133*8d67ca89SAndroid Build Coastguard Worker       case '6':
134*8d67ca89SAndroid Build Coastguard Worker       case '7':
135*8d67ca89SAndroid Build Coastguard Worker       case '8':
136*8d67ca89SAndroid Build Coastguard Worker       case '9':
137*8d67ca89SAndroid Build Coastguard Worker         width = width * 10 + c - '0';
138*8d67ca89SAndroid Build Coastguard Worker         goto again;
139*8d67ca89SAndroid Build Coastguard Worker 
140*8d67ca89SAndroid Build Coastguard Worker       /*
141*8d67ca89SAndroid Build Coastguard Worker        * Conversions.
142*8d67ca89SAndroid Build Coastguard Worker        * Those marked `compat' are for 4.[123]BSD compatibility.
143*8d67ca89SAndroid Build Coastguard Worker        */
144*8d67ca89SAndroid Build Coastguard Worker       case 'b':
145*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
146*8d67ca89SAndroid Build Coastguard Worker         base = 2;
147*8d67ca89SAndroid Build Coastguard Worker         flags |= PFBOK; /* enable 0b prefixing */
148*8d67ca89SAndroid Build Coastguard Worker         break;
149*8d67ca89SAndroid Build Coastguard Worker 
150*8d67ca89SAndroid Build Coastguard Worker       case 'D': /* compat */
151*8d67ca89SAndroid Build Coastguard Worker         flags |= LONG;
152*8d67ca89SAndroid Build Coastguard Worker         __BIONIC_FALLTHROUGH;
153*8d67ca89SAndroid Build Coastguard Worker       case 'd':
154*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
155*8d67ca89SAndroid Build Coastguard Worker         base = 10;
156*8d67ca89SAndroid Build Coastguard Worker         break;
157*8d67ca89SAndroid Build Coastguard Worker 
158*8d67ca89SAndroid Build Coastguard Worker       case 'i':
159*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
160*8d67ca89SAndroid Build Coastguard Worker         base = 0;
161*8d67ca89SAndroid Build Coastguard Worker         break;
162*8d67ca89SAndroid Build Coastguard Worker 
163*8d67ca89SAndroid Build Coastguard Worker       case 'O': /* compat */
164*8d67ca89SAndroid Build Coastguard Worker         flags |= LONG;
165*8d67ca89SAndroid Build Coastguard Worker         __BIONIC_FALLTHROUGH;
166*8d67ca89SAndroid Build Coastguard Worker       case 'o':
167*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
168*8d67ca89SAndroid Build Coastguard Worker         flags |= UNSIGNED;
169*8d67ca89SAndroid Build Coastguard Worker         base = 8;
170*8d67ca89SAndroid Build Coastguard Worker         break;
171*8d67ca89SAndroid Build Coastguard Worker 
172*8d67ca89SAndroid Build Coastguard Worker       case 'u':
173*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
174*8d67ca89SAndroid Build Coastguard Worker         flags |= UNSIGNED;
175*8d67ca89SAndroid Build Coastguard Worker         base = 10;
176*8d67ca89SAndroid Build Coastguard Worker         break;
177*8d67ca89SAndroid Build Coastguard Worker 
178*8d67ca89SAndroid Build Coastguard Worker       case 'w': {
179*8d67ca89SAndroid Build Coastguard Worker         int size = 0;
180*8d67ca89SAndroid Build Coastguard Worker         bool fast = false;
181*8d67ca89SAndroid Build Coastguard Worker         c = *fmt++;
182*8d67ca89SAndroid Build Coastguard Worker         if (c == 'f') {
183*8d67ca89SAndroid Build Coastguard Worker           fast = true;
184*8d67ca89SAndroid Build Coastguard Worker           c = *fmt++;
185*8d67ca89SAndroid Build Coastguard Worker         }
186*8d67ca89SAndroid Build Coastguard Worker         while (is_digit(c)) {
187*8d67ca89SAndroid Build Coastguard Worker           APPEND_DIGIT(size, c);
188*8d67ca89SAndroid Build Coastguard Worker           c = *fmt++;
189*8d67ca89SAndroid Build Coastguard Worker         }
190*8d67ca89SAndroid Build Coastguard Worker         flags |= w_to_flag(size, fast);
191*8d67ca89SAndroid Build Coastguard Worker         goto reswitch;
192*8d67ca89SAndroid Build Coastguard Worker       }
193*8d67ca89SAndroid Build Coastguard Worker 
194*8d67ca89SAndroid Build Coastguard Worker       case 'X':
195*8d67ca89SAndroid Build Coastguard Worker       case 'x':
196*8d67ca89SAndroid Build Coastguard Worker         flags |= PFXOK; /* enable 0x prefixing */
197*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
198*8d67ca89SAndroid Build Coastguard Worker         flags |= UNSIGNED;
199*8d67ca89SAndroid Build Coastguard Worker         base = 16;
200*8d67ca89SAndroid Build Coastguard Worker         break;
201*8d67ca89SAndroid Build Coastguard Worker 
202*8d67ca89SAndroid Build Coastguard Worker       case 'e':
203*8d67ca89SAndroid Build Coastguard Worker       case 'E':
204*8d67ca89SAndroid Build Coastguard Worker       case 'f':
205*8d67ca89SAndroid Build Coastguard Worker       case 'F':
206*8d67ca89SAndroid Build Coastguard Worker       case 'g':
207*8d67ca89SAndroid Build Coastguard Worker       case 'G':
208*8d67ca89SAndroid Build Coastguard Worker       case 'a':
209*8d67ca89SAndroid Build Coastguard Worker       case 'A':
210*8d67ca89SAndroid Build Coastguard Worker         c = CT_FLOAT;
211*8d67ca89SAndroid Build Coastguard Worker         break;
212*8d67ca89SAndroid Build Coastguard Worker 
213*8d67ca89SAndroid Build Coastguard Worker       case 's':
214*8d67ca89SAndroid Build Coastguard Worker         memset(ccltab, 1, 256);
215*8d67ca89SAndroid Build Coastguard Worker         ccltab['\t'] = ccltab['\n'] = ccltab['\v'] = ccltab['\f'] = ccltab['\r'] = ccltab[' '] = 0;
216*8d67ca89SAndroid Build Coastguard Worker         c = CT_STRING;
217*8d67ca89SAndroid Build Coastguard Worker         break;
218*8d67ca89SAndroid Build Coastguard Worker 
219*8d67ca89SAndroid Build Coastguard Worker       case '[':
220*8d67ca89SAndroid Build Coastguard Worker         fmt = __sccl(ccltab, fmt);
221*8d67ca89SAndroid Build Coastguard Worker         flags |= NOSKIP;
222*8d67ca89SAndroid Build Coastguard Worker         c = CT_CCL;
223*8d67ca89SAndroid Build Coastguard Worker         break;
224*8d67ca89SAndroid Build Coastguard Worker 
225*8d67ca89SAndroid Build Coastguard Worker       case 'c':
226*8d67ca89SAndroid Build Coastguard Worker         flags |= NOSKIP;
227*8d67ca89SAndroid Build Coastguard Worker         c = CT_CHAR;
228*8d67ca89SAndroid Build Coastguard Worker         break;
229*8d67ca89SAndroid Build Coastguard Worker 
230*8d67ca89SAndroid Build Coastguard Worker       case 'p': /* pointer format is like hex */
231*8d67ca89SAndroid Build Coastguard Worker         flags |= POINTER | PFXOK;
232*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
233*8d67ca89SAndroid Build Coastguard Worker         flags |= UNSIGNED;
234*8d67ca89SAndroid Build Coastguard Worker         base = 16;
235*8d67ca89SAndroid Build Coastguard Worker         break;
236*8d67ca89SAndroid Build Coastguard Worker 
237*8d67ca89SAndroid Build Coastguard Worker       case 'n':
238*8d67ca89SAndroid Build Coastguard Worker         if (flags & SUPPRESS) continue;
239*8d67ca89SAndroid Build Coastguard Worker         if (flags & SHORTSHORT) {
240*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, signed char*) = nread;
241*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & SHORT) {
242*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, short*) = nread;
243*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & LONG) {
244*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, long*) = nread;
245*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & SIZEINT) {
246*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, ssize_t*) = nread;
247*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & PTRINT) {
248*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, ptrdiff_t*) = nread;
249*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & LLONG) {
250*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, long long*) = nread;
251*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & MAXINT) {
252*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, intmax_t*) = nread;
253*8d67ca89SAndroid Build Coastguard Worker         } else {
254*8d67ca89SAndroid Build Coastguard Worker           *va_arg(ap, int*) = nread;
255*8d67ca89SAndroid Build Coastguard Worker         }
256*8d67ca89SAndroid Build Coastguard Worker         continue;
257*8d67ca89SAndroid Build Coastguard Worker 
258*8d67ca89SAndroid Build Coastguard Worker       /*
259*8d67ca89SAndroid Build Coastguard Worker        * Disgusting backwards compatibility hacks.	XXX
260*8d67ca89SAndroid Build Coastguard Worker        */
261*8d67ca89SAndroid Build Coastguard Worker       case '\0': /* compat */
262*8d67ca89SAndroid Build Coastguard Worker         return EOF;
263*8d67ca89SAndroid Build Coastguard Worker 
264*8d67ca89SAndroid Build Coastguard Worker       default: /* compat */
265*8d67ca89SAndroid Build Coastguard Worker         if (isupper(c)) flags |= LONG;
266*8d67ca89SAndroid Build Coastguard Worker         c = CT_INT;
267*8d67ca89SAndroid Build Coastguard Worker         base = 10;
268*8d67ca89SAndroid Build Coastguard Worker         break;
269*8d67ca89SAndroid Build Coastguard Worker     }
270*8d67ca89SAndroid Build Coastguard Worker 
271*8d67ca89SAndroid Build Coastguard Worker     if ((flags & ALLOCATE) != 0 && c > CT_STRING) {
272*8d67ca89SAndroid Build Coastguard Worker       __fortify_fatal("scanf 'm' only works with %%c/%%s/%%[");
273*8d67ca89SAndroid Build Coastguard Worker     }
274*8d67ca89SAndroid Build Coastguard Worker     if ((flags & (ALLOCATE|SUPPRESS)) == (ALLOCATE|SUPPRESS)) {
275*8d67ca89SAndroid Build Coastguard Worker       __fortify_fatal("scanf 'm' makes no sense with '*'");
276*8d67ca89SAndroid Build Coastguard Worker     }
277*8d67ca89SAndroid Build Coastguard Worker 
278*8d67ca89SAndroid Build Coastguard Worker     /*
279*8d67ca89SAndroid Build Coastguard Worker      * We have a conversion that requires input.
280*8d67ca89SAndroid Build Coastguard Worker      */
281*8d67ca89SAndroid Build Coastguard Worker     if (fp->_r <= 0 && __srefill(fp)) goto input_failure;
282*8d67ca89SAndroid Build Coastguard Worker 
283*8d67ca89SAndroid Build Coastguard Worker     /*
284*8d67ca89SAndroid Build Coastguard Worker      * Consume leading white space, except for formats
285*8d67ca89SAndroid Build Coastguard Worker      * that suppress this.
286*8d67ca89SAndroid Build Coastguard Worker      */
287*8d67ca89SAndroid Build Coastguard Worker     if ((flags & NOSKIP) == 0) {
288*8d67ca89SAndroid Build Coastguard Worker       while (isspace(*fp->_p)) {
289*8d67ca89SAndroid Build Coastguard Worker         nread++;
290*8d67ca89SAndroid Build Coastguard Worker         if (--fp->_r > 0) {
291*8d67ca89SAndroid Build Coastguard Worker           fp->_p++;
292*8d67ca89SAndroid Build Coastguard Worker         } else if (__srefill(fp)) {
293*8d67ca89SAndroid Build Coastguard Worker           goto input_failure;
294*8d67ca89SAndroid Build Coastguard Worker         }
295*8d67ca89SAndroid Build Coastguard Worker       }
296*8d67ca89SAndroid Build Coastguard Worker       /*
297*8d67ca89SAndroid Build Coastguard Worker        * Note that there is at least one character in
298*8d67ca89SAndroid Build Coastguard Worker        * the buffer, so conversions that do not set NOSKIP
299*8d67ca89SAndroid Build Coastguard Worker        * ca no longer result in an input failure.
300*8d67ca89SAndroid Build Coastguard Worker        */
301*8d67ca89SAndroid Build Coastguard Worker     }
302*8d67ca89SAndroid Build Coastguard Worker 
303*8d67ca89SAndroid Build Coastguard Worker     /*
304*8d67ca89SAndroid Build Coastguard Worker      * Do the conversion.
305*8d67ca89SAndroid Build Coastguard Worker      */
306*8d67ca89SAndroid Build Coastguard Worker     switch (c) {
307*8d67ca89SAndroid Build Coastguard Worker       case CT_CHAR:
308*8d67ca89SAndroid Build Coastguard Worker         /* scan arbitrary characters (sets NOSKIP) */
309*8d67ca89SAndroid Build Coastguard Worker         if (width == 0) width = 1;
310*8d67ca89SAndroid Build Coastguard Worker         if (flags & LONG) {
311*8d67ca89SAndroid Build Coastguard Worker           if (flags & ALLOCATE) {
312*8d67ca89SAndroid Build Coastguard Worker             allocation = wcp = reinterpret_cast<wchar_t*>(malloc(width * sizeof(wchar_t)));
313*8d67ca89SAndroid Build Coastguard Worker             if (allocation == nullptr) goto allocation_failure;
314*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & SUPPRESS) {
315*8d67ca89SAndroid Build Coastguard Worker             wcp = nullptr;
316*8d67ca89SAndroid Build Coastguard Worker           } else {
317*8d67ca89SAndroid Build Coastguard Worker             wcp = va_arg(ap, wchar_t*);
318*8d67ca89SAndroid Build Coastguard Worker           }
319*8d67ca89SAndroid Build Coastguard Worker           size_t bytes = 0;
320*8d67ca89SAndroid Build Coastguard Worker           while (width != 0) {
321*8d67ca89SAndroid Build Coastguard Worker             if (bytes == MB_CUR_MAX) {
322*8d67ca89SAndroid Build Coastguard Worker               fp->_flags |= __SERR;
323*8d67ca89SAndroid Build Coastguard Worker               goto input_failure;
324*8d67ca89SAndroid Build Coastguard Worker             }
325*8d67ca89SAndroid Build Coastguard Worker             buf[bytes++] = *fp->_p;
326*8d67ca89SAndroid Build Coastguard Worker             fp->_p++;
327*8d67ca89SAndroid Build Coastguard Worker             fp->_r--;
328*8d67ca89SAndroid Build Coastguard Worker             memset(&mbs, 0, sizeof(mbs));
329*8d67ca89SAndroid Build Coastguard Worker             nconv = mbrtowc(wcp, buf, bytes, &mbs);
330*8d67ca89SAndroid Build Coastguard Worker             if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
331*8d67ca89SAndroid Build Coastguard Worker               fp->_flags |= __SERR;
332*8d67ca89SAndroid Build Coastguard Worker               goto input_failure;
333*8d67ca89SAndroid Build Coastguard Worker             }
334*8d67ca89SAndroid Build Coastguard Worker             if (nconv == 0 && !(flags & SUPPRESS)) *wcp = L'\0';
335*8d67ca89SAndroid Build Coastguard Worker             if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
336*8d67ca89SAndroid Build Coastguard Worker               nread += bytes;
337*8d67ca89SAndroid Build Coastguard Worker               width--;
338*8d67ca89SAndroid Build Coastguard Worker               if (!(flags & SUPPRESS)) wcp++;
339*8d67ca89SAndroid Build Coastguard Worker               bytes = 0;
340*8d67ca89SAndroid Build Coastguard Worker             }
341*8d67ca89SAndroid Build Coastguard Worker             if (fp->_r <= 0 && __srefill(fp)) {
342*8d67ca89SAndroid Build Coastguard Worker               if (bytes != 0) {
343*8d67ca89SAndroid Build Coastguard Worker                 fp->_flags |= __SERR;
344*8d67ca89SAndroid Build Coastguard Worker                 goto input_failure;
345*8d67ca89SAndroid Build Coastguard Worker               }
346*8d67ca89SAndroid Build Coastguard Worker               break;
347*8d67ca89SAndroid Build Coastguard Worker             }
348*8d67ca89SAndroid Build Coastguard Worker           }
349*8d67ca89SAndroid Build Coastguard Worker           if (allocation != nullptr) {
350*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
351*8d67ca89SAndroid Build Coastguard Worker             allocation = nullptr;
352*8d67ca89SAndroid Build Coastguard Worker           }
353*8d67ca89SAndroid Build Coastguard Worker           if (!(flags & SUPPRESS)) nassigned++;
354*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & SUPPRESS) {
355*8d67ca89SAndroid Build Coastguard Worker           size_t sum = 0;
356*8d67ca89SAndroid Build Coastguard Worker           for (;;) {
357*8d67ca89SAndroid Build Coastguard Worker             if ((n = fp->_r) < width) {
358*8d67ca89SAndroid Build Coastguard Worker               sum += n;
359*8d67ca89SAndroid Build Coastguard Worker               width -= n;
360*8d67ca89SAndroid Build Coastguard Worker               fp->_p += n;
361*8d67ca89SAndroid Build Coastguard Worker               if (__srefill(fp)) {
362*8d67ca89SAndroid Build Coastguard Worker                 if (sum == 0) goto input_failure;
363*8d67ca89SAndroid Build Coastguard Worker                 break;
364*8d67ca89SAndroid Build Coastguard Worker               }
365*8d67ca89SAndroid Build Coastguard Worker             } else {
366*8d67ca89SAndroid Build Coastguard Worker               sum += width;
367*8d67ca89SAndroid Build Coastguard Worker               fp->_r -= width;
368*8d67ca89SAndroid Build Coastguard Worker               fp->_p += width;
369*8d67ca89SAndroid Build Coastguard Worker               break;
370*8d67ca89SAndroid Build Coastguard Worker             }
371*8d67ca89SAndroid Build Coastguard Worker           }
372*8d67ca89SAndroid Build Coastguard Worker           nread += sum;
373*8d67ca89SAndroid Build Coastguard Worker         } else {
374*8d67ca89SAndroid Build Coastguard Worker           if (flags & ALLOCATE) {
375*8d67ca89SAndroid Build Coastguard Worker             allocation = p = reinterpret_cast<char*>(malloc(width));
376*8d67ca89SAndroid Build Coastguard Worker             if (allocation == nullptr) goto allocation_failure;
377*8d67ca89SAndroid Build Coastguard Worker           } else {
378*8d67ca89SAndroid Build Coastguard Worker             p = va_arg(ap, char*);
379*8d67ca89SAndroid Build Coastguard Worker           }
380*8d67ca89SAndroid Build Coastguard Worker           size_t r = fread(p, 1, width, fp);
381*8d67ca89SAndroid Build Coastguard Worker           if (r == 0) goto input_failure;
382*8d67ca89SAndroid Build Coastguard Worker           if (allocation != nullptr) {
383*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
384*8d67ca89SAndroid Build Coastguard Worker             allocation = nullptr;
385*8d67ca89SAndroid Build Coastguard Worker           }
386*8d67ca89SAndroid Build Coastguard Worker           nread += r;
387*8d67ca89SAndroid Build Coastguard Worker           nassigned++;
388*8d67ca89SAndroid Build Coastguard Worker         }
389*8d67ca89SAndroid Build Coastguard Worker         break;
390*8d67ca89SAndroid Build Coastguard Worker 
391*8d67ca89SAndroid Build Coastguard Worker       case CT_CCL:
392*8d67ca89SAndroid Build Coastguard Worker       case CT_STRING:
393*8d67ca89SAndroid Build Coastguard Worker         // CT_CCL: scan a (nonempty) character class (sets NOSKIP).
394*8d67ca89SAndroid Build Coastguard Worker         // CT_STRING: like CCL, but zero-length string OK, & no NOSKIP.
395*8d67ca89SAndroid Build Coastguard Worker         if (width == 0) width = SIZE_MAX;
396*8d67ca89SAndroid Build Coastguard Worker         if (flags & LONG) {
397*8d67ca89SAndroid Build Coastguard Worker           // TODO: since no-one cares, replace this with a simple fgetwc loop?
398*8d67ca89SAndroid Build Coastguard Worker           n = 0;
399*8d67ca89SAndroid Build Coastguard Worker           if (flags & ALLOCATE) {
400*8d67ca89SAndroid Build Coastguard Worker             capacity = MIN(width, 32);
401*8d67ca89SAndroid Build Coastguard Worker             allocation = wcp = reinterpret_cast<wchar_t*>(malloc(sizeof(wchar_t) * capacity));
402*8d67ca89SAndroid Build Coastguard Worker             if (allocation == nullptr) goto allocation_failure;
403*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & SUPPRESS) {
404*8d67ca89SAndroid Build Coastguard Worker             wcp = nullptr;
405*8d67ca89SAndroid Build Coastguard Worker           } else {
406*8d67ca89SAndroid Build Coastguard Worker             wcp = va_arg(ap, wchar_t*);
407*8d67ca89SAndroid Build Coastguard Worker           }
408*8d67ca89SAndroid Build Coastguard Worker           size_t bytes = 0;
409*8d67ca89SAndroid Build Coastguard Worker           while ((c == CT_CCL || !isspace(*fp->_p)) && width != 0) {
410*8d67ca89SAndroid Build Coastguard Worker             if (bytes == MB_CUR_MAX) {
411*8d67ca89SAndroid Build Coastguard Worker               fp->_flags |= __SERR;
412*8d67ca89SAndroid Build Coastguard Worker               goto input_failure;
413*8d67ca89SAndroid Build Coastguard Worker             }
414*8d67ca89SAndroid Build Coastguard Worker             buf[bytes++] = *fp->_p;
415*8d67ca89SAndroid Build Coastguard Worker             fp->_p++;
416*8d67ca89SAndroid Build Coastguard Worker             fp->_r--;
417*8d67ca89SAndroid Build Coastguard Worker             wchar_t wc = L'\0';
418*8d67ca89SAndroid Build Coastguard Worker             memset(&mbs, 0, sizeof(mbs));
419*8d67ca89SAndroid Build Coastguard Worker             nconv = mbrtowc(&wc, buf, bytes, &mbs);
420*8d67ca89SAndroid Build Coastguard Worker             if (nconv == BIONIC_MULTIBYTE_RESULT_ILLEGAL_SEQUENCE) {
421*8d67ca89SAndroid Build Coastguard Worker               fp->_flags |= __SERR;
422*8d67ca89SAndroid Build Coastguard Worker               goto input_failure;
423*8d67ca89SAndroid Build Coastguard Worker             }
424*8d67ca89SAndroid Build Coastguard Worker             if (nconv != BIONIC_MULTIBYTE_RESULT_INCOMPLETE_SEQUENCE) {
425*8d67ca89SAndroid Build Coastguard Worker               if ((c == CT_CCL && wctob(wc) != EOF && !ccltab[wctob(wc)]) || (c == CT_STRING && iswspace(wc))) {
426*8d67ca89SAndroid Build Coastguard Worker                 while (bytes != 0) {
427*8d67ca89SAndroid Build Coastguard Worker                   bytes--;
428*8d67ca89SAndroid Build Coastguard Worker                   ungetc(buf[bytes], fp);
429*8d67ca89SAndroid Build Coastguard Worker                 }
430*8d67ca89SAndroid Build Coastguard Worker                 break;
431*8d67ca89SAndroid Build Coastguard Worker               }
432*8d67ca89SAndroid Build Coastguard Worker               if (wcp) wcp[n] = wc;
433*8d67ca89SAndroid Build Coastguard Worker               n++;
434*8d67ca89SAndroid Build Coastguard Worker               if (allocation != nullptr && n == capacity) {
435*8d67ca89SAndroid Build Coastguard Worker                 capacity *= 2;
436*8d67ca89SAndroid Build Coastguard Worker                 wchar_t* new_allocation =
437*8d67ca89SAndroid Build Coastguard Worker                     reinterpret_cast<wchar_t*>(realloc(allocation, sizeof(wchar_t) * capacity));
438*8d67ca89SAndroid Build Coastguard Worker                 if (new_allocation == nullptr) goto allocation_failure;
439*8d67ca89SAndroid Build Coastguard Worker                 allocation = wcp = new_allocation;
440*8d67ca89SAndroid Build Coastguard Worker               }
441*8d67ca89SAndroid Build Coastguard Worker               nread += bytes;
442*8d67ca89SAndroid Build Coastguard Worker               width--;
443*8d67ca89SAndroid Build Coastguard Worker               bytes = 0;
444*8d67ca89SAndroid Build Coastguard Worker             }
445*8d67ca89SAndroid Build Coastguard Worker             if (fp->_r <= 0 && __srefill(fp)) {
446*8d67ca89SAndroid Build Coastguard Worker               if (bytes != 0) {
447*8d67ca89SAndroid Build Coastguard Worker                 fp->_flags |= __SERR;
448*8d67ca89SAndroid Build Coastguard Worker                 goto input_failure;
449*8d67ca89SAndroid Build Coastguard Worker               }
450*8d67ca89SAndroid Build Coastguard Worker               break;
451*8d67ca89SAndroid Build Coastguard Worker             }
452*8d67ca89SAndroid Build Coastguard Worker           }
453*8d67ca89SAndroid Build Coastguard Worker           if (c == CT_CCL && bytes != 0) {
454*8d67ca89SAndroid Build Coastguard Worker             fp->_flags |= __SERR;
455*8d67ca89SAndroid Build Coastguard Worker             goto input_failure;
456*8d67ca89SAndroid Build Coastguard Worker           }
457*8d67ca89SAndroid Build Coastguard Worker           if (allocation != nullptr) {
458*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, wchar_t**) = reinterpret_cast<wchar_t*>(allocation);
459*8d67ca89SAndroid Build Coastguard Worker             allocation = nullptr;
460*8d67ca89SAndroid Build Coastguard Worker           }
461*8d67ca89SAndroid Build Coastguard Worker         } else if (flags & SUPPRESS) {
462*8d67ca89SAndroid Build Coastguard Worker           n = 0;
463*8d67ca89SAndroid Build Coastguard Worker           while (ccltab[*fp->_p]) {
464*8d67ca89SAndroid Build Coastguard Worker             n++, fp->_r--, fp->_p++;
465*8d67ca89SAndroid Build Coastguard Worker             if (--width == 0) break;
466*8d67ca89SAndroid Build Coastguard Worker             if (fp->_r <= 0 && __srefill(fp)) {
467*8d67ca89SAndroid Build Coastguard Worker               if (c == CT_CCL && n == 0) goto input_failure;
468*8d67ca89SAndroid Build Coastguard Worker               break;
469*8d67ca89SAndroid Build Coastguard Worker             }
470*8d67ca89SAndroid Build Coastguard Worker           }
471*8d67ca89SAndroid Build Coastguard Worker           nread += n;
472*8d67ca89SAndroid Build Coastguard Worker         } else {
473*8d67ca89SAndroid Build Coastguard Worker           if (flags & ALLOCATE) {
474*8d67ca89SAndroid Build Coastguard Worker             capacity = MIN(width, 32);
475*8d67ca89SAndroid Build Coastguard Worker             allocation = p = reinterpret_cast<char*>(malloc(capacity));
476*8d67ca89SAndroid Build Coastguard Worker             if (allocation == nullptr) goto allocation_failure;
477*8d67ca89SAndroid Build Coastguard Worker           } else {
478*8d67ca89SAndroid Build Coastguard Worker             p = va_arg(ap, char*);
479*8d67ca89SAndroid Build Coastguard Worker           }
480*8d67ca89SAndroid Build Coastguard Worker           n = 0;
481*8d67ca89SAndroid Build Coastguard Worker           while (ccltab[*fp->_p]) {
482*8d67ca89SAndroid Build Coastguard Worker             fp->_r--;
483*8d67ca89SAndroid Build Coastguard Worker             p[n++] = *fp->_p++;
484*8d67ca89SAndroid Build Coastguard Worker             if (allocation != nullptr && n == capacity) {
485*8d67ca89SAndroid Build Coastguard Worker               capacity *= 2;
486*8d67ca89SAndroid Build Coastguard Worker               char* new_allocation = reinterpret_cast<char*>(realloc(allocation, capacity));
487*8d67ca89SAndroid Build Coastguard Worker               if (new_allocation == nullptr) goto allocation_failure;
488*8d67ca89SAndroid Build Coastguard Worker               allocation = p = new_allocation;
489*8d67ca89SAndroid Build Coastguard Worker             }
490*8d67ca89SAndroid Build Coastguard Worker             if (--width == 0) break;
491*8d67ca89SAndroid Build Coastguard Worker             if (fp->_r <= 0 && __srefill(fp)) {
492*8d67ca89SAndroid Build Coastguard Worker               if (c == CT_CCL && n == 0) goto input_failure;
493*8d67ca89SAndroid Build Coastguard Worker               break;
494*8d67ca89SAndroid Build Coastguard Worker             }
495*8d67ca89SAndroid Build Coastguard Worker           }
496*8d67ca89SAndroid Build Coastguard Worker           nread += n;
497*8d67ca89SAndroid Build Coastguard Worker           if (allocation != nullptr) {
498*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, char**) = reinterpret_cast<char*>(allocation);
499*8d67ca89SAndroid Build Coastguard Worker             allocation = nullptr;
500*8d67ca89SAndroid Build Coastguard Worker           }
501*8d67ca89SAndroid Build Coastguard Worker         }
502*8d67ca89SAndroid Build Coastguard Worker         if (c == CT_CCL && n == 0) goto match_failure;
503*8d67ca89SAndroid Build Coastguard Worker         if (!(flags & SUPPRESS)) {
504*8d67ca89SAndroid Build Coastguard Worker           if (flags & LONG) {
505*8d67ca89SAndroid Build Coastguard Worker             wcp[n] = L'\0';
506*8d67ca89SAndroid Build Coastguard Worker           } else {
507*8d67ca89SAndroid Build Coastguard Worker             p[n] = '\0';
508*8d67ca89SAndroid Build Coastguard Worker           }
509*8d67ca89SAndroid Build Coastguard Worker           ++nassigned;
510*8d67ca89SAndroid Build Coastguard Worker         }
511*8d67ca89SAndroid Build Coastguard Worker         break;
512*8d67ca89SAndroid Build Coastguard Worker 
513*8d67ca89SAndroid Build Coastguard Worker       case CT_INT:
514*8d67ca89SAndroid Build Coastguard Worker         /* scan an integer as if by strtoimax/strtoumax */
515*8d67ca89SAndroid Build Coastguard Worker #ifdef hardway
516*8d67ca89SAndroid Build Coastguard Worker         if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
517*8d67ca89SAndroid Build Coastguard Worker #else
518*8d67ca89SAndroid Build Coastguard Worker         /* size_t is unsigned, hence this optimisation */
519*8d67ca89SAndroid Build Coastguard Worker         if (--width > sizeof(buf) - 2) width = sizeof(buf) - 2;
520*8d67ca89SAndroid Build Coastguard Worker         width++;
521*8d67ca89SAndroid Build Coastguard Worker #endif
522*8d67ca89SAndroid Build Coastguard Worker         flags |= SIGNOK | NDIGITS | NZDIGITS;
523*8d67ca89SAndroid Build Coastguard Worker         for (p = buf; width; width--) {
524*8d67ca89SAndroid Build Coastguard Worker           c = *fp->_p;
525*8d67ca89SAndroid Build Coastguard Worker           /*
526*8d67ca89SAndroid Build Coastguard Worker            * Switch on the character; `goto ok'
527*8d67ca89SAndroid Build Coastguard Worker            * if we accept it as a part of number.
528*8d67ca89SAndroid Build Coastguard Worker            */
529*8d67ca89SAndroid Build Coastguard Worker           switch (c) {
530*8d67ca89SAndroid Build Coastguard Worker             /*
531*8d67ca89SAndroid Build Coastguard Worker              * The digit 0 is always legal, but is
532*8d67ca89SAndroid Build Coastguard Worker              * special.  For %i conversions, if no
533*8d67ca89SAndroid Build Coastguard Worker              * digits (zero or nonzero) have been
534*8d67ca89SAndroid Build Coastguard Worker              * scanned (only signs), we will have
535*8d67ca89SAndroid Build Coastguard Worker              * base==0.  In that case, we should set
536*8d67ca89SAndroid Build Coastguard Worker              * it to 8 and enable 0b/0x prefixing.
537*8d67ca89SAndroid Build Coastguard Worker              * Also, if we have not scanned zero digits
538*8d67ca89SAndroid Build Coastguard Worker              * before this, do not turn off prefixing
539*8d67ca89SAndroid Build Coastguard Worker              * (someone else will turn it off if we
540*8d67ca89SAndroid Build Coastguard Worker              * have scanned any nonzero digits).
541*8d67ca89SAndroid Build Coastguard Worker              */
542*8d67ca89SAndroid Build Coastguard Worker             case '0':
543*8d67ca89SAndroid Build Coastguard Worker               if (base == 0) {
544*8d67ca89SAndroid Build Coastguard Worker                 base = 8;
545*8d67ca89SAndroid Build Coastguard Worker                 flags |= PFBOK | PFXOK;
546*8d67ca89SAndroid Build Coastguard Worker               }
547*8d67ca89SAndroid Build Coastguard Worker               if (flags & NZDIGITS) {
548*8d67ca89SAndroid Build Coastguard Worker                 flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
549*8d67ca89SAndroid Build Coastguard Worker               } else {
550*8d67ca89SAndroid Build Coastguard Worker                 flags &= ~(SIGNOK | PFBOK | PFXOK | NDIGITS);
551*8d67ca89SAndroid Build Coastguard Worker               }
552*8d67ca89SAndroid Build Coastguard Worker               goto ok;
553*8d67ca89SAndroid Build Coastguard Worker             case 'B':
554*8d67ca89SAndroid Build Coastguard Worker             case 'b':
555*8d67ca89SAndroid Build Coastguard Worker               // Is this 'b' or 'B' potentially part of an "0b" prefix?
556*8d67ca89SAndroid Build Coastguard Worker               if ((flags & PFBOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
557*8d67ca89SAndroid Build Coastguard Worker                 base = 2;
558*8d67ca89SAndroid Build Coastguard Worker                 flags &= ~PFBOK;
559*8d67ca89SAndroid Build Coastguard Worker                 goto ok;
560*8d67ca89SAndroid Build Coastguard Worker               }
561*8d67ca89SAndroid Build Coastguard Worker               // No? Fall through and see if it's a hex digit instead then...
562*8d67ca89SAndroid Build Coastguard Worker               __BIONIC_FALLTHROUGH;
563*8d67ca89SAndroid Build Coastguard Worker             case '1':
564*8d67ca89SAndroid Build Coastguard Worker             case '2':
565*8d67ca89SAndroid Build Coastguard Worker             case '3':
566*8d67ca89SAndroid Build Coastguard Worker             case '4':
567*8d67ca89SAndroid Build Coastguard Worker             case '5':
568*8d67ca89SAndroid Build Coastguard Worker             case '6':
569*8d67ca89SAndroid Build Coastguard Worker             case '7':
570*8d67ca89SAndroid Build Coastguard Worker             case '8':
571*8d67ca89SAndroid Build Coastguard Worker             case '9':
572*8d67ca89SAndroid Build Coastguard Worker             case 'A':
573*8d67ca89SAndroid Build Coastguard Worker             case 'C':
574*8d67ca89SAndroid Build Coastguard Worker             case 'D':
575*8d67ca89SAndroid Build Coastguard Worker             case 'E':
576*8d67ca89SAndroid Build Coastguard Worker             case 'F':
577*8d67ca89SAndroid Build Coastguard Worker             case 'a':
578*8d67ca89SAndroid Build Coastguard Worker             case 'c':
579*8d67ca89SAndroid Build Coastguard Worker             case 'd':
580*8d67ca89SAndroid Build Coastguard Worker             case 'e':
581*8d67ca89SAndroid Build Coastguard Worker             case 'f':
582*8d67ca89SAndroid Build Coastguard Worker               if (base == 0) base = 10;
583*8d67ca89SAndroid Build Coastguard Worker               if (base != 16 && (c - '0') >= base) break; /* not legal here */
584*8d67ca89SAndroid Build Coastguard Worker               flags &= ~(SIGNOK | PFBOK | PFXOK | NDIGITS);
585*8d67ca89SAndroid Build Coastguard Worker               goto ok;
586*8d67ca89SAndroid Build Coastguard Worker 
587*8d67ca89SAndroid Build Coastguard Worker             /* sign ok only as first character */
588*8d67ca89SAndroid Build Coastguard Worker             case '+':
589*8d67ca89SAndroid Build Coastguard Worker             case '-':
590*8d67ca89SAndroid Build Coastguard Worker               if (flags & SIGNOK) {
591*8d67ca89SAndroid Build Coastguard Worker                 flags &= ~SIGNOK;
592*8d67ca89SAndroid Build Coastguard Worker                 flags |= HAVESIGN;
593*8d67ca89SAndroid Build Coastguard Worker                 goto ok;
594*8d67ca89SAndroid Build Coastguard Worker               }
595*8d67ca89SAndroid Build Coastguard Worker               break;
596*8d67ca89SAndroid Build Coastguard Worker 
597*8d67ca89SAndroid Build Coastguard Worker             /*
598*8d67ca89SAndroid Build Coastguard Worker              * x ok iff flag still set and 2nd char (or
599*8d67ca89SAndroid Build Coastguard Worker              * 3rd char if we have a sign).
600*8d67ca89SAndroid Build Coastguard Worker              */
601*8d67ca89SAndroid Build Coastguard Worker             case 'x':
602*8d67ca89SAndroid Build Coastguard Worker             case 'X':
603*8d67ca89SAndroid Build Coastguard Worker               if ((flags & PFXOK) && p == buf + 1 + !!(flags & HAVESIGN)) {
604*8d67ca89SAndroid Build Coastguard Worker                 base = 16; /* if %i */
605*8d67ca89SAndroid Build Coastguard Worker                 flags &= ~PFXOK;
606*8d67ca89SAndroid Build Coastguard Worker                 goto ok;
607*8d67ca89SAndroid Build Coastguard Worker               }
608*8d67ca89SAndroid Build Coastguard Worker               break;
609*8d67ca89SAndroid Build Coastguard Worker           }
610*8d67ca89SAndroid Build Coastguard Worker 
611*8d67ca89SAndroid Build Coastguard Worker           /*
612*8d67ca89SAndroid Build Coastguard Worker            * If we got here, c is not a legal character
613*8d67ca89SAndroid Build Coastguard Worker            * for a number.  Stop accumulating digits.
614*8d67ca89SAndroid Build Coastguard Worker            */
615*8d67ca89SAndroid Build Coastguard Worker           break;
616*8d67ca89SAndroid Build Coastguard Worker         ok:
617*8d67ca89SAndroid Build Coastguard Worker           /*
618*8d67ca89SAndroid Build Coastguard Worker            * c is legal: store it and look at the next.
619*8d67ca89SAndroid Build Coastguard Worker            */
620*8d67ca89SAndroid Build Coastguard Worker           *p++ = c;
621*8d67ca89SAndroid Build Coastguard Worker           if (--fp->_r > 0)
622*8d67ca89SAndroid Build Coastguard Worker             fp->_p++;
623*8d67ca89SAndroid Build Coastguard Worker           else if (__srefill(fp))
624*8d67ca89SAndroid Build Coastguard Worker             break; /* EOF */
625*8d67ca89SAndroid Build Coastguard Worker         }
626*8d67ca89SAndroid Build Coastguard Worker         /*
627*8d67ca89SAndroid Build Coastguard Worker          * If we had only a sign, it is no good; push back the sign.
628*8d67ca89SAndroid Build Coastguard Worker          * If the number was `[-+]0[BbXx]`, push back and treat it
629*8d67ca89SAndroid Build Coastguard Worker          * as `[-+]0`.
630*8d67ca89SAndroid Build Coastguard Worker          */
631*8d67ca89SAndroid Build Coastguard Worker         if (flags & NDIGITS) {
632*8d67ca89SAndroid Build Coastguard Worker           if (p > buf) ungetc(*reinterpret_cast<u_char*>(--p), fp);
633*8d67ca89SAndroid Build Coastguard Worker           goto match_failure;
634*8d67ca89SAndroid Build Coastguard Worker         }
635*8d67ca89SAndroid Build Coastguard Worker         c = reinterpret_cast<u_char*>(p)[-1];
636*8d67ca89SAndroid Build Coastguard Worker         if ((base == 2 && (c == 'b' || c == 'B')) || c == 'x' || c == 'X') {
637*8d67ca89SAndroid Build Coastguard Worker           --p;
638*8d67ca89SAndroid Build Coastguard Worker           (void)ungetc(c, fp);
639*8d67ca89SAndroid Build Coastguard Worker         }
640*8d67ca89SAndroid Build Coastguard Worker         if ((flags & SUPPRESS) == 0) {
641*8d67ca89SAndroid Build Coastguard Worker           uintmax_t res;
642*8d67ca89SAndroid Build Coastguard Worker 
643*8d67ca89SAndroid Build Coastguard Worker           *p = '\0';
644*8d67ca89SAndroid Build Coastguard Worker           if (flags & UNSIGNED) {
645*8d67ca89SAndroid Build Coastguard Worker             res = strtoumax(buf, nullptr, base);
646*8d67ca89SAndroid Build Coastguard Worker           } else {
647*8d67ca89SAndroid Build Coastguard Worker             res = strtoimax(buf, nullptr, base);
648*8d67ca89SAndroid Build Coastguard Worker           }
649*8d67ca89SAndroid Build Coastguard Worker           if (flags & POINTER) {
650*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, void**) = reinterpret_cast<void*>(res);
651*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & MAXINT) {
652*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, intmax_t*) = res;
653*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & LLONG) {
654*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, long long*) = res;
655*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & SIZEINT) {
656*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, ssize_t*) = res;
657*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & PTRINT) {
658*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, ptrdiff_t*) = res;
659*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & LONG) {
660*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, long*) = res;
661*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & SHORT) {
662*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, short*) = res;
663*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & SHORTSHORT) {
664*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, signed char*) = res;
665*8d67ca89SAndroid Build Coastguard Worker           } else {
666*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, int*) = res;
667*8d67ca89SAndroid Build Coastguard Worker           }
668*8d67ca89SAndroid Build Coastguard Worker           nassigned++;
669*8d67ca89SAndroid Build Coastguard Worker         }
670*8d67ca89SAndroid Build Coastguard Worker         nread += p - buf;
671*8d67ca89SAndroid Build Coastguard Worker         break;
672*8d67ca89SAndroid Build Coastguard Worker 
673*8d67ca89SAndroid Build Coastguard Worker       case CT_FLOAT:
674*8d67ca89SAndroid Build Coastguard Worker         /* scan a floating point number as if by strtod */
675*8d67ca89SAndroid Build Coastguard Worker         if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1;
676*8d67ca89SAndroid Build Coastguard Worker         if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure;
677*8d67ca89SAndroid Build Coastguard Worker         if ((flags & SUPPRESS) == 0) {
678*8d67ca89SAndroid Build Coastguard Worker           if (flags & LONGDBL) {
679*8d67ca89SAndroid Build Coastguard Worker             long double res = strtold(buf, &p);
680*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, long double*) = res;
681*8d67ca89SAndroid Build Coastguard Worker           } else if (flags & LONG) {
682*8d67ca89SAndroid Build Coastguard Worker             double res = strtod(buf, &p);
683*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, double*) = res;
684*8d67ca89SAndroid Build Coastguard Worker           } else {
685*8d67ca89SAndroid Build Coastguard Worker             float res = strtof(buf, &p);
686*8d67ca89SAndroid Build Coastguard Worker             *va_arg(ap, float*) = res;
687*8d67ca89SAndroid Build Coastguard Worker           }
688*8d67ca89SAndroid Build Coastguard Worker           if (static_cast<size_t>(p - buf) != width) abort();
689*8d67ca89SAndroid Build Coastguard Worker           nassigned++;
690*8d67ca89SAndroid Build Coastguard Worker         }
691*8d67ca89SAndroid Build Coastguard Worker         nread += width;
692*8d67ca89SAndroid Build Coastguard Worker         break;
693*8d67ca89SAndroid Build Coastguard Worker     }
694*8d67ca89SAndroid Build Coastguard Worker   }
695*8d67ca89SAndroid Build Coastguard Worker allocation_failure:
696*8d67ca89SAndroid Build Coastguard Worker input_failure:
697*8d67ca89SAndroid Build Coastguard Worker   free(allocation);
698*8d67ca89SAndroid Build Coastguard Worker   if (nassigned == 0) nassigned = -1;
699*8d67ca89SAndroid Build Coastguard Worker match_failure:
700*8d67ca89SAndroid Build Coastguard Worker   return nassigned;
701*8d67ca89SAndroid Build Coastguard Worker }
702*8d67ca89SAndroid Build Coastguard Worker 
703*8d67ca89SAndroid Build Coastguard Worker /*
704*8d67ca89SAndroid Build Coastguard Worker  * Fill in the given table from the scanset at the given format
705*8d67ca89SAndroid Build Coastguard Worker  * (just after `[').  Return a pointer to the character past the
706*8d67ca89SAndroid Build Coastguard Worker  * closing `]'.  The table has a 1 wherever characters should be
707*8d67ca89SAndroid Build Coastguard Worker  * considered part of the scanset.
708*8d67ca89SAndroid Build Coastguard Worker  */
__sccl(char * tab,const unsigned char * fmt)709*8d67ca89SAndroid Build Coastguard Worker static const unsigned char* __sccl(char* tab, const unsigned char* fmt) {
710*8d67ca89SAndroid Build Coastguard Worker   int c, n, v;
711*8d67ca89SAndroid Build Coastguard Worker 
712*8d67ca89SAndroid Build Coastguard Worker   /* first `clear' the whole table */
713*8d67ca89SAndroid Build Coastguard Worker   c = *fmt++; /* first char hat => negated scanset */
714*8d67ca89SAndroid Build Coastguard Worker   if (c == '^') {
715*8d67ca89SAndroid Build Coastguard Worker     v = 1;      /* default => accept */
716*8d67ca89SAndroid Build Coastguard Worker     c = *fmt++; /* get new first char */
717*8d67ca89SAndroid Build Coastguard Worker   } else {
718*8d67ca89SAndroid Build Coastguard Worker     v = 0; /* default => reject */
719*8d67ca89SAndroid Build Coastguard Worker   }
720*8d67ca89SAndroid Build Coastguard Worker   memset(tab, v, 256);
721*8d67ca89SAndroid Build Coastguard Worker   if (c == 0) return (fmt - 1); /* format ended before closing ] */
722*8d67ca89SAndroid Build Coastguard Worker 
723*8d67ca89SAndroid Build Coastguard Worker   /*
724*8d67ca89SAndroid Build Coastguard Worker    * Now set the entries corresponding to the actual scanset
725*8d67ca89SAndroid Build Coastguard Worker    * to the opposite of the above.
726*8d67ca89SAndroid Build Coastguard Worker    *
727*8d67ca89SAndroid Build Coastguard Worker    * The first character may be ']' (or '-') without being special;
728*8d67ca89SAndroid Build Coastguard Worker    * the last character may be '-'.
729*8d67ca89SAndroid Build Coastguard Worker    */
730*8d67ca89SAndroid Build Coastguard Worker   v = 1 - v;
731*8d67ca89SAndroid Build Coastguard Worker   for (;;) {
732*8d67ca89SAndroid Build Coastguard Worker     tab[c] = v; /* take character c */
733*8d67ca89SAndroid Build Coastguard Worker   doswitch:
734*8d67ca89SAndroid Build Coastguard Worker     n = *fmt++; /* and examine the next */
735*8d67ca89SAndroid Build Coastguard Worker     switch (n) {
736*8d67ca89SAndroid Build Coastguard Worker       case 0: /* format ended too soon */
737*8d67ca89SAndroid Build Coastguard Worker         return (fmt - 1);
738*8d67ca89SAndroid Build Coastguard Worker 
739*8d67ca89SAndroid Build Coastguard Worker       case '-':
740*8d67ca89SAndroid Build Coastguard Worker         /*
741*8d67ca89SAndroid Build Coastguard Worker          * A scanset of the form
742*8d67ca89SAndroid Build Coastguard Worker          *	[01+-]
743*8d67ca89SAndroid Build Coastguard Worker          * is defined as `the digit 0, the digit 1,
744*8d67ca89SAndroid Build Coastguard Worker          * the character +, the character -', but
745*8d67ca89SAndroid Build Coastguard Worker          * the effect of a scanset such as
746*8d67ca89SAndroid Build Coastguard Worker          *	[a-zA-Z0-9]
747*8d67ca89SAndroid Build Coastguard Worker          * is implementation defined.  The V7 Unix
748*8d67ca89SAndroid Build Coastguard Worker          * scanf treats `a-z' as `the letters a through
749*8d67ca89SAndroid Build Coastguard Worker          * z', but treats `a-a' as `the letter a, the
750*8d67ca89SAndroid Build Coastguard Worker          * character -, and the letter a'.
751*8d67ca89SAndroid Build Coastguard Worker          *
752*8d67ca89SAndroid Build Coastguard Worker          * For compatibility, the `-' is not considerd
753*8d67ca89SAndroid Build Coastguard Worker          * to define a range if the character following
754*8d67ca89SAndroid Build Coastguard Worker          * it is either a close bracket (required by ANSI)
755*8d67ca89SAndroid Build Coastguard Worker          * or is not numerically greater than the character
756*8d67ca89SAndroid Build Coastguard Worker          * we just stored in the table (c).
757*8d67ca89SAndroid Build Coastguard Worker          */
758*8d67ca89SAndroid Build Coastguard Worker         n = *fmt;
759*8d67ca89SAndroid Build Coastguard Worker         if (n == ']' || n < c) {
760*8d67ca89SAndroid Build Coastguard Worker           c = '-';
761*8d67ca89SAndroid Build Coastguard Worker           break; /* resume the for(;;) */
762*8d67ca89SAndroid Build Coastguard Worker         }
763*8d67ca89SAndroid Build Coastguard Worker         fmt++;
764*8d67ca89SAndroid Build Coastguard Worker         do { /* fill in the range */
765*8d67ca89SAndroid Build Coastguard Worker           tab[++c] = v;
766*8d67ca89SAndroid Build Coastguard Worker         } while (c < n);
767*8d67ca89SAndroid Build Coastguard Worker #if 1 /* XXX another disgusting compatibility hack */
768*8d67ca89SAndroid Build Coastguard Worker         /*
769*8d67ca89SAndroid Build Coastguard Worker          * Alas, the V7 Unix scanf also treats formats
770*8d67ca89SAndroid Build Coastguard Worker          * such as [a-c-e] as `the letters a through e'.
771*8d67ca89SAndroid Build Coastguard Worker          * This too is permitted by the standard....
772*8d67ca89SAndroid Build Coastguard Worker          */
773*8d67ca89SAndroid Build Coastguard Worker         goto doswitch;
774*8d67ca89SAndroid Build Coastguard Worker #else
775*8d67ca89SAndroid Build Coastguard Worker         c = *fmt++;
776*8d67ca89SAndroid Build Coastguard Worker         if (c == 0) return (fmt - 1);
777*8d67ca89SAndroid Build Coastguard Worker         if (c == ']') return (fmt);
778*8d67ca89SAndroid Build Coastguard Worker #endif
779*8d67ca89SAndroid Build Coastguard Worker         break;
780*8d67ca89SAndroid Build Coastguard Worker 
781*8d67ca89SAndroid Build Coastguard Worker       case ']': /* end of scanset */
782*8d67ca89SAndroid Build Coastguard Worker         return fmt;
783*8d67ca89SAndroid Build Coastguard Worker 
784*8d67ca89SAndroid Build Coastguard Worker       default: /* just another character */
785*8d67ca89SAndroid Build Coastguard Worker         c = n;
786*8d67ca89SAndroid Build Coastguard Worker         break;
787*8d67ca89SAndroid Build Coastguard Worker     }
788*8d67ca89SAndroid Build Coastguard Worker   }
789*8d67ca89SAndroid Build Coastguard Worker   /* NOTREACHED */
790*8d67ca89SAndroid Build Coastguard Worker }
791