1 /* Copyright (c) 2002,2004,2005 Joerg Wunsch
2    Copyright (c) 2008  Dmitry Xmelkov
3    All rights reserved.
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions are met:
7 
8    * Redistributions of source code must retain the above copyright
9      notice, this list of conditions and the following disclaimer.
10 
11    * Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in
13      the documentation and/or other materials provided with the
14      distribution.
15 
16    * Neither the name of the copyright holders nor the names of
17      contributors may be used to endorse or promote products derived
18      from this software without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 /* $Id: vfscanf.c 2191 2010-11-05 13:45:57Z arcanum $ */
34 
35 #include "stdio_private.h"
36 #include <wctype.h>
37 #include "scanf_private.h"
38 
39 /*
40  * Compute which features are required
41  */
42 
43 #ifdef _NEED_IO_LONG_LONG
44 typedef unsigned long long uint_scanf_t;
45 typedef long long int_scanf_t;
46 #else
47 typedef unsigned long uint_scanf_t;
48 typedef long int_scanf_t;
49 #endif
50 
51 /* Figure out which multi-byte char support we need */
52 #if defined(_NEED_IO_WCHAR) && defined(_MB_CAPABLE)
53 # ifdef WIDE_CHARS
54 /* need to convert wide chars to multi-byte chars */
55 #  define _NEED_IO_WIDETOMB
56 # else
57 /* need to convert multi-byte chars to wide chars */
58 #  define _NEED_IO_MBTOWIDE
59 # endif
60 #endif
61 
62 #ifdef WIDE_CHARS
63 # define INT wint_t
64 # define MY_EOF          WEOF
65 # define CHAR wchar_t
66 # define UCHAR wchar_t
67 # define GETC(s) getwc(s)
68 # define UNGETC(c,s) ungetwc(c,s)
69 # define ISSPACE(c) iswspace(c)
70 # undef vfscanf
71 # define vfscanf vfwscanf
72 # define IS_EOF(c)       ((c) == WEOF)
73 # define WINT            wint_t
74 # define IS_WEOF(c)      ((c) == WEOF)
75 # define ISWSPACE(c)     iswspace(c)
76 #else
77 # define INT int
78 # define MY_EOF          EOF
79 # define IS_EOF(c)       ((c) < 0)
80 # define CHAR char
81 # define UCHAR unsigned char
82 # define GETC(s) getc(s)
83 # define UNGETC(c,s) ungetc(c,s)
84 # define ISSPACE(c) isspace(c)
85 # ifdef _NEED_IO_MBTOWIDE
86 #  define WINT            wint_t
87 #  define MY_WEOF         WEOF
88 #  define IS_WEOF(c)      ((c) == WEOF)
89 #  define ISWSPACE(c)     iswspace(c)
90 # else
91 #  define WINT            int
92 #  define IS_WEOF(c)      IS_EOF(c)
93 #  define MY_WEOF         MY_EOF
94 #  define ISWSPACE(c)     ISSPACE(c)
95 # endif
96 #endif
97 
98 #ifdef WIDE_CHARS
99 typedef struct {
100     int         len;
101     INT         unget;
102 } scanf_context_t;
103 #define SCANF_CONTEXT_INIT { .len = 0, .unget = MY_EOF }
104 #define scanf_len(context) ((context)->len)
105 #else
106 typedef int scanf_context_t;
107 #define SCANF_CONTEXT_INIT 0
108 #define scanf_len(context) (*(context))
109 #endif
110 
111 static INT
scanf_getc(FILE * stream,scanf_context_t * context)112 scanf_getc(FILE *stream, scanf_context_t *context)
113 {
114     INT c;
115 #ifdef WIDE_CHARS
116     c = context->unget;
117     context->unget = MY_EOF;
118     if (IS_EOF(c))
119 #endif
120         c = GETC(stream);
121     if (!IS_EOF(c))
122         ++scanf_len(context);
123     return c;
124 }
125 
126 static void
scanf_ungetc(INT c,FILE * stream,scanf_context_t * context)127 scanf_ungetc(INT c, FILE *stream, scanf_context_t *context)
128 {
129     if (!IS_EOF(c))
130         --scanf_len(context);
131 #ifdef WIDE_CHARS
132     (void) stream;
133     context->unget = c;
134 #else
135     UNGETC(c, stream);
136 #endif
137 }
138 
139 #ifdef _NEED_IO_MBTOWIDE
140 static WINT
getmb(FILE * stream,scanf_context_t * context,mbstate_t * ps,uint16_t flags)141 getmb(FILE *stream, scanf_context_t *context, mbstate_t *ps, uint16_t flags)
142 {
143     INT         i;
144 
145     if (flags & FL_LONG) {
146         wchar_t     ch;
147         char        mb[MB_LEN_MAX];
148         size_t      n = 0;
149         size_t      s;
150         mbstate_t   save;
151 
152         while (n < MB_LEN_MAX) {
153             i = scanf_getc (stream, context);
154             if (IS_EOF(i))
155                 return WEOF;
156             mb[n++] = (char) i;
157             save = *ps;
158             s = mbrtowc(&ch, mb, n, ps);
159             switch (s) {
160             case (size_t) -1:
161                 return WEOF;
162             case (size_t) -2:
163                 *ps = save;
164                 break;
165             default:
166                 return (wint_t) ch;
167             }
168         }
169         return WEOF;
170     } else {
171         i = scanf_getc(stream, context);
172         if (IS_EOF(i))
173             return MY_WEOF;
174         return (WINT) i;
175     }
176 }
177 #else
178 #define getmb(s,c,p,f) scanf_getc(s,c)
179 #endif
180 
181 #ifdef _NEED_IO_WIDETOMB
182 static void *
_putmb(void * addr,wint_t wi,mbstate_t * ps,uint16_t flags)183 _putmb(void *addr, wint_t wi, mbstate_t *ps, uint16_t flags)
184 {
185     if (flags & FL_LONG) {
186         *(wchar_t *) addr = (wchar_t) wi;
187         addr = (wchar_t *) addr + 1;
188     } else {
189         size_t  s;
190         s = wcrtomb((char *) addr, (wchar_t) wi, ps);
191         if (s == (size_t) -1)
192             return NULL;
193         addr = (char *) addr + s;
194     }
195     return addr;
196 }
197 #define putmb(addr, wi, ps, flags, fail) do {   \
198         if (addr) {                             \
199             addr = _putmb(addr, wi, ps, flags); \
200             if (!addr) fail;                    \
201         }                                       \
202     } while(0);
203 #else
204 #ifdef _NEED_IO_WCHAR
205 static void *
_putmb(void * addr,wint_t wi,uint16_t flags)206 _putmb(void *addr, wint_t wi, uint16_t flags)
207 {
208     if (flags & FL_LONG) {
209         *(wchar_t *) addr = (wchar_t) wi;
210         addr = (wchar_t *) addr + 1;
211     } else {
212         *(char *) addr = (char) wi;
213         addr = (char *) addr + 1;
214     }
215     return addr;
216 }
217 #define putmb(addr, wi, ps, flags, fail) do {   \
218         if (addr) {                             \
219             addr = _putmb(addr, wi, flags);     \
220             if (!addr) fail;                    \
221         }                                       \
222     } while(0)
223 #else
224 #define putmb(addr, wi, ps, flags, fail) do {           \
225         if (addr) {                                     \
226             *(char *) addr = (char) wi;                 \
227             addr = (char *) addr + 1;                   \
228         }                                               \
229     } while(0)
230 #endif
231 #endif
232 
233 static void
putval(void * addr,int_scanf_t val,uint16_t flags)234 putval (void *addr, int_scanf_t val, uint16_t flags)
235 {
236     if (addr) {
237 	if (flags & FL_CHAR)
238 	    *(char *)addr = val;
239 #ifdef _NEED_IO_LONG_LONG
240         else if (flags & FL_LONGLONG)
241             *(long long *)addr = val;
242 #endif
243 	else if (flags & FL_LONG)
244 	    *(long *)addr = val;
245 	else if (flags & FL_SHORT)
246 	    *(short *)addr = val;
247 	else
248 	    *(int *)addr = val;
249     }
250 }
251 
252 static unsigned char
conv_int(FILE * stream,scanf_context_t * context,width_t width,void * addr,uint16_t flags,unsigned int base)253 conv_int (FILE *stream, scanf_context_t *context, width_t width, void *addr, uint16_t flags, unsigned int base)
254 {
255     uint_scanf_t val;
256     INT i;
257 
258     i = scanf_getc (stream, context);			/* after scanf_ungetc()	*/
259 
260     switch (i) {
261       case '-':
262         flags |= FL_MINUS;
263 	__PICOLIBC_FALLTHROUGH;
264       case '+':
265         if (!--width || IS_EOF(i = scanf_getc(stream, context)))
266 	    goto err;
267     }
268 
269     val = 0;
270 
271     /* Leading '0' digit -- check for base indication */
272     if (i == '0') {
273 	if (!--width || IS_EOF(i = scanf_getc (stream, context)))
274 	    goto putval;
275 
276         flags |= FL_ANY;
277 
278         if (TOLOWER(i) == 'x' && (base == 0 || base == 16)) {
279             base = 16;
280             if (!--width || IS_EOF(i = scanf_getc (stream, context)))
281 		goto putval;
282 #ifdef _NEED_IO_PERCENT_B
283         } else if (i == 'b' && base <= 2) {
284             base = 2;
285             if (!--width || IS_EOF(i = scanf_getc (stream, context)))
286 		goto putval;
287 #endif
288 	} else if (base == 0 || base == 8) {
289             base = 8;
290         }
291     } else if (base == 0)
292         base = 10;
293 
294     do {
295 	unsigned int c = digit_to_val(i);
296         if (c >= base) {
297             scanf_ungetc (i, stream, context);
298             break;
299 	}
300         flags |= FL_ANY;
301         val = val * base + c;
302 	if (!--width) goto putval;
303     } while (!IS_EOF(i = scanf_getc(stream, context)));
304     if (!(flags & FL_ANY))
305         goto err;
306 
307   putval:
308     if (flags & FL_MINUS) val = -val;
309     putval (addr, val, flags);
310     return 1;
311 
312   err:
313     return 0;
314 }
315 
316 #ifdef _NEED_IO_BRACKET
317 static const CHAR *
conv_brk(FILE * stream,scanf_context_t * context,width_t width,void * addr,const CHAR * _fmt,uint16_t flags)318 conv_brk (FILE *stream, scanf_context_t *context, width_t width, void *addr, const CHAR *_fmt, uint16_t flags)
319 {
320 #if defined(_NEED_IO_MBTOWIDE) || defined(_NEED_IO_WIDETOMB)
321     mbstate_t ps = {0};
322 #endif
323     const CHAR  *fmt;
324     UCHAR       f;
325     bool        fnegate = false;
326     bool        fany = false;
327 
328     (void) flags;
329     if (*_fmt == '^') {
330         fnegate = true;
331         _fmt++;
332     }
333     do {
334         WINT    wi = getmb (stream, context, &ps, flags);
335         UCHAR   cbelow;
336         UCHAR   cabove = 0;
337         bool    fmatch = false;
338         bool    frange = false;
339 
340         /*
341          * This is comically inefficient when matching a long string
342          * as we re-scan the format string for every input
343          * character. However, converting the specified scanset to a
344          * more efficient data structure would require an allocation.
345          */
346         fmt = _fmt;
347         for (;;) {
348             /*
349              * POSIX is very clear that the format string contains
350              * bytes, not multi-byte characters. Hence all that we can
351              * match are wide characters which happen to fall in a range
352              * which can be specified by byte values.
353              *
354              * glibc appears to parse the format string as multi-byte
355              * characters, which makes sense, but appears to violate the
356              * spec.
357              */
358             f = *fmt++;
359             if (!f)
360                 return NULL;
361             if (fmt != _fmt + 1) {
362                 if (f == ']')
363                     break;
364                 if (f == '-' && !frange) {
365                     frange = true;
366                     continue;
367                 }
368             }
369             cbelow = f;
370             if (frange) {
371                 cbelow = cabove;
372                 frange = false;
373             }
374             cabove = f;
375             if ((WINT) cbelow <= wi && wi <= (WINT) cabove)
376                 fmatch = true;
377         }
378 
379         if (IS_WEOF(wi))
380             break;
381 
382         if (fmatch == fnegate) {
383 	    scanf_ungetc (wi, stream, context);
384             break;
385         }
386 
387         fany = true;
388         putmb(addr, wi, &ps, flags, return NULL);
389         width--;
390     } while (width);
391 
392     if (!fany)
393         return NULL;
394     putmb(addr, 0, &ps, flags, return NULL);
395     return fmt;
396 }
397 #endif	/* _NEED_IO_BRACKET */
398 
399 #if defined(_NEED_IO_FLOAT) || defined(_NEED_IO_DOUBLE)
400 #include "conv_flt.c"
401 #endif
402 
skip_spaces(FILE * stream,scanf_context_t * context)403 static INT skip_spaces (FILE *stream, scanf_context_t *context)
404 {
405     INT i;
406     do {
407 	if (IS_EOF(i = scanf_getc (stream, context)))
408 	    return i;
409     } while (ISSPACE (i));
410     scanf_ungetc (i, stream, context);
411     return i;
412 }
413 
414 #ifdef _NEED_IO_POS_ARGS
415 
416 typedef struct {
417     va_list     ap;
418 } my_va_list;
419 
420 static void
skip_to_arg(my_va_list * ap,int target_argno)421 skip_to_arg(my_va_list *ap, int target_argno)
422 {
423     int current_argno = 1;
424 
425     /*
426      * Fortunately, all scanf args are pointers,
427      * and so are the same size as void *
428      */
429     while (current_argno < target_argno) {
430         (void) va_arg(ap->ap, void *);
431         current_argno++;
432     }
433 }
434 
435 #endif
436 
437 /**
438    Formatted input.  This function is the heart of the \b scanf family of
439    functions.
440 
441    Characters are read from \a stream and processed in a way described by
442    \a fmt.  Conversion results will be assigned to the parameters passed
443    via \a ap.
444 
445    The format string \a fmt is scanned for conversion specifications.
446    Anything that doesn't comprise a conversion specification is taken as
447    text that is matched literally against the input.  White space in the
448    format string will match any white space in the data (including none),
449    all other characters match only itself. Processing is aborted as soon
450    as the data and format string no longer match, or there is an error or
451    end-of-file condition on \a stream.
452 
453    Most conversions skip leading white space before starting the actual
454    conversion.
455 
456    Conversions are introduced with the character \b %.  Possible options
457    can follow the \b %:
458 
459    - a \c * indicating that the conversion should be performed but
460      the conversion result is to be discarded; no parameters will
461      be processed from \c ap,
462    - the character \c h indicating that the argument is a pointer
463      to <tt>short int</tt> (rather than <tt>int</tt>),
464    - the 2 characters \c hh indicating that the argument is a pointer
465      to <tt>char</tt> (rather than <tt>int</tt>).
466    - the character \c l indicating that the argument is a pointer
467      to <tt>long int</tt> (rather than <tt>int</tt>, for integer
468      type conversions), or a pointer to \c double (for floating
469      point conversions),
470 
471    In addition, a maximal field width may be specified as a nonzero
472    positive decimal integer, which will restrict the conversion to at
473    most this many characters from the input stream.  This field width is
474    limited to at most 255 characters which is also the default value
475    (except for the <tt>%c</tt> conversion that defaults to 1).
476 
477    The following conversion flags are supported:
478 
479    - \c % Matches a literal \c % character.  This is not a conversion.
480    - \c d Matches an optionally signed decimal integer; the next
481      pointer must be a pointer to \c int.
482    - \c i Matches an optionally signed integer; the next pointer must
483      be a pointer to \c int.  The integer is read in base 16 if it
484      begins with \b 0x or \b 0X, in base 8 if it begins with \b 0, and
485      in base 10 otherwise.  Only characters that correspond to the
486      base are used.
487    - \c o Matches an octal integer; the next pointer must be a pointer to
488      <tt>unsigned int</tt>.
489    - \c u Matches an optionally signed decimal integer; the next
490      pointer must be a pointer to <tt>unsigned int</tt>.
491    - \c x Matches an optionally signed hexadecimal integer; the next
492      pointer must be a pointer to <tt>unsigned int</tt>.
493    - \c f Matches an optionally signed floating-point number; the next
494      pointer must be a pointer to \c float.
495    - <tt>e, g, F, E, G</tt> Equivalent to \c f.
496    - \c s
497      Matches a sequence of non-white-space characters; the next pointer
498      must be a pointer to \c char, and the array must be large enough to
499      accept all the sequence and the terminating \c NUL character.  The
500      input string stops at white space or at the maximum field width,
501      whichever occurs first.
502    - \c c
503      Matches a sequence of width count characters (default 1); the next
504      pointer must be a pointer to \c char, and there must be enough room
505      for all the characters (no terminating \c NUL is added).  The usual
506      skip of leading white space is suppressed.  To skip white space
507      first, use an explicit space in the format.
508    - \c [
509      Matches a nonempty sequence of characters from the specified set
510      of accepted characters; the next pointer must be a pointer to \c
511      char, and there must be enough room for all the characters in the
512      string, plus a terminating \c NUL character.  The usual skip of
513      leading white space is suppressed.  The string is to be made up
514      of characters in (or not in) a particular set; the set is defined
515      by the characters between the open bracket \c [ character and a
516      close bracket \c ] character.  The set excludes those characters
517      if the first character after the open bracket is a circumflex
518      \c ^.  To include a close bracket in the set, make it the first
519      character after the open bracket or the circumflex; any other
520      position will end the set.  The hyphen character \c - is also
521      special; when placed between two other characters, it adds all
522      intervening characters to the set.  To include a hyphen, make it
523      the last character before the final close bracket.  For instance,
524      <tt>[^]0-9-]</tt> means the set of <em>everything except close
525      bracket, zero through nine, and hyphen</em>.  The string ends
526      with the appearance of a character not in the (or, with a
527      circumflex, in) set or when the field width runs out.  Note that
528      usage of this conversion enlarges the stack expense.
529    - \c p
530      Matches a pointer value (as printed by <tt>%p</tt> in printf()); the
531      next pointer must be a pointer to \c void.
532    - \c n
533      Nothing is expected; instead, the number of characters consumed
534      thus far from the input is stored through the next pointer, which
535      must be a pointer to \c int.  This is not a conversion, although it
536      can be suppressed with the \c * flag.
537 
538      These functions return the number of input items assigned, which can
539      be fewer than provided for, or even zero, in the event of a matching
540      failure.  Zero indicates that, while there was input available, no
541      conversions were assigned; typically this is due to an invalid input
542      character, such as an alphabetic character for a <tt>%d</tt>
543      conversion.  The value \c EOF is returned if an input failure occurs
544      before any conversion such as an end-of-file occurs.  If an error or
545      end-of-file occurs after conversion has begun, the number of
546      conversions which were successfully completed is returned.
547 
548      By default, all the conversions described above are available except
549      the floating-point conversions and the width is limited to 255
550      characters.  The float-point conversion will be available in the
551      extended version provided by the library \c libscanf_flt.a.  Also in
552      this case the width is not limited (exactly, it is limited to 65535
553      characters).  To link a program against the extended version, use the
554      following compiler flags in the link stage:
555 
556      \code
557      -Wl,-u,vfscanf -lscanf_flt -lm
558      \endcode
559 
560      A third version is available for environments that are tight on
561      space.  In addition to the restrictions of the standard one, this
562      version implements no <tt>%[</tt> specification.  This version is
563      provided in the library \c libscanf_min.a, and can be requested using
564      the following options in the link stage:
565 
566      \code
567      -Wl,-u,vfscanf -lscanf_min -lm
568      \endcode
569 */
vfscanf(FILE * stream,const CHAR * fmt,va_list ap_orig)570 int vfscanf (FILE * stream, const CHAR *fmt, va_list ap_orig)
571 {
572     unsigned char nconvs;
573     UCHAR c;
574     width_t width;
575     void *addr;
576 #ifdef _NEED_IO_POS_ARGS
577     my_va_list my_ap;
578 #define ap my_ap.ap
579     va_copy(ap, ap_orig);
580 #else
581 #define ap ap_orig
582 #endif
583     uint16_t flags;
584     INT i;
585     scanf_context_t context = SCANF_CONTEXT_INIT;
586 
587     nconvs = 0;
588 
589     /* Initialization of stream_flags at each pass simplifies the register
590        allocation with GCC 3.3 - 4.2.  Only the GCC 4.3 is good to move it
591        to the begin.	*/
592     while ((c = *fmt++) != 0) {
593 
594 	if (ISSPACE (c)) {
595 	    skip_spaces (stream, &context);
596 
597 	} else if (c != '%'
598 		   || (c = *fmt++) == '%')
599 	{
600 	    /* Ordinary character.	*/
601 	    if (IS_EOF(i = scanf_getc (stream, &context)))
602 		goto eof;
603 	    if ((UCHAR)i != c) {
604 		scanf_ungetc (i, stream, &context);
605 		break;
606 	    }
607 
608 	} else {
609 	    flags = 0;
610 
611 	    if (c == '*') {
612 		flags = FL_STAR;
613 		c = *fmt++;
614 	    }
615 
616             for (;;) {
617                 width = 0;
618                 while ((c -= '0') < 10) {
619                     flags |= FL_WIDTH;
620                     width = width * 10 + c;
621                     c = *fmt++;
622                 }
623                 c += '0';
624                 if (flags & FL_WIDTH) {
625 #ifdef _NEED_IO_POS_ARGS
626                     if (c == '$') {
627                         flags &= ~FL_WIDTH;
628                         va_end(ap);
629                         va_copy(ap, ap_orig);
630                         skip_to_arg(&my_ap, width);
631                         c = *fmt++;
632                         continue;
633                     }
634 #endif
635                     /* C99 says that width must be greater than zero.
636                        To simplify program do treat 0 as error in format.	*/
637                     if (!width) break;
638                 } else {
639                     width = ~0;
640                 }
641                 break;
642             }
643 
644 	    switch (c) {
645 	      case 'h':
646                 flags |= FL_SHORT;
647 		c = *fmt++;
648                 if (c == 'h') {
649                     flags |= FL_CHAR;
650                     c = *fmt++;
651                 }
652 		break;
653 	      case 'l':
654 		flags |= FL_LONG;
655 		c = *fmt++;
656                 if (c == 'l') {
657                     flags |= FL_LONGLONG;
658                     c = *fmt++;
659                 }
660 		break;
661               case 'L':
662                 flags |= FL_LONG|FL_LONGLONG;
663                 c = *fmt++;
664                 break;
665 #ifdef _NEED_IO_C99_FORMATS
666 #ifdef _NEED_IO_LONG_LONG
667 #define CHECK_LONGLONG(type)                                    \
668                 else if (sizeof(type) == sizeof(long long))     \
669                     flags |= FL_LONGLONG
670 #else
671 #define CHECK_LONGLONG(type)
672 #endif
673 
674 #define CHECK_INT_SIZE(letter, type)				\
675 	    case letter:					\
676 		if (sizeof(type) != sizeof(int)) {		\
677 		    if (sizeof(type) == sizeof(long))		\
678 			flags |= FL_LONG;                       \
679 		    else if (sizeof(type) == sizeof(short))     \
680 			flags |= FL_SHORT;                      \
681                     CHECK_LONGLONG(type);                       \
682 		}						\
683 		c = *fmt++;					\
684 		break;
685 
686 	    CHECK_INT_SIZE('j', intmax_t);
687 	    CHECK_INT_SIZE('z', size_t);
688 	    CHECK_INT_SIZE('t', ptrdiff_t);
689 #endif
690 	    }
691 
692 #ifdef _NEED_IO_PERCENT_B
693 #define CNV_BASE	"cdinopsuxXb"
694 #else
695 #define CNV_BASE	"cdinopsuxX"
696 #endif
697 
698 #ifdef _NEED_IO_BRACKET
699 # define CNV_BRACKET	"["
700 #else
701 # define CNV_BRACKET	""
702 #endif
703 #if defined(_NEED_IO_FLOAT) || defined(_NEED_IO_DOUBLE)
704 # define CNV_FLOAT	"aefgAEFG"
705 #else
706 # define CNV_FLOAT	""
707 #endif
708 #define CNV_LIST	CNV_BASE CNV_BRACKET CNV_FLOAT
709 	    if (!c || !strchr (CNV_LIST, c))
710 		break;
711 
712 	    addr = (flags & FL_STAR) ? 0 : va_arg (ap, void *);
713 
714 	    if (c == 'n') {
715 		putval (addr, (unsigned)scanf_len(&context), flags);
716 		continue;
717 	    }
718 
719 	    if (c == 'c') {
720 		if (!(flags & FL_WIDTH)) width = 1;
721 #if defined(_NEED_IO_MBTOWIDE) || defined(_NEED_IO_WIDETOMB)
722                 mbstate_t ps = {0};
723 #endif
724 		do {
725                     WINT        wi = getmb (stream, &context, &ps, flags);
726                     if(IS_WEOF(wi))
727                         goto eof;
728                     putmb(addr, wi, &ps, flags, goto eof);
729 		} while (--width);
730 		c = 1;			/* no matter with smart GCC	*/
731 
732 #ifdef _NEED_IO_BRACKET
733 	    } else if (c == '[') {
734 		fmt = conv_brk (stream, &context, width, addr, fmt, flags);
735 		c = (fmt != 0);
736 #endif
737 
738 	    } else {
739 
740                 unsigned int base = 0;
741 
742 		if (IS_EOF(skip_spaces (stream, &context)))
743 		    goto eof;
744 
745 		switch (c) {
746 
747                 case 's': {
748 #if defined(_NEED_IO_MBTOWIDE) || defined(_NEED_IO_WIDETOMB)
749                     mbstate_t ps = {0};
750 #endif
751 		    /* Now we have 1 nospace symbol.	*/
752 		    do {
753                         WINT wi = getmb(stream, &context, &ps, flags);
754 			if (IS_WEOF(wi))
755 			    break;
756 			if (ISWSPACE (wi)) {
757 			    scanf_ungetc (wi, stream, &context);
758 			    break;
759 			}
760                         putmb(addr, wi, &ps, flags, goto eof);
761 		    } while (--width);
762                     putmb(addr, 0, &ps, flags, goto eof);
763 		    c = 1;		/* no matter with smart GCC	*/
764 		    break;
765                 }
766 
767 #if defined(_NEED_IO_FLOAT) || defined(_NEED_IO_DOUBLE)
768 	          case 'p':
769                       if (sizeof(void *) > sizeof(int))
770                           flags |= FL_LONG;
771                       __PICOLIBC_FALLTHROUGH;
772 		  case 'x':
773 	          case 'X':
774                     base = 16;
775 		    goto conv_int;
776 
777 #ifdef _NEED_IO_PERCENT_B
778                   case 'b':
779                     base = 2;
780                     goto conv_int;
781 #endif
782 
783 	          case 'd':
784 		  case 'u':
785                     base = 10;
786 		    goto conv_int;
787 
788 	          case 'o':
789                     base = 8;
790 		    __PICOLIBC_FALLTHROUGH;
791 		  case 'i':
792 		  conv_int:
793                     c = conv_int (stream, &context, width, addr, flags, base);
794 		    break;
795 
796 	          default:		/* a,A,e,E,f,F,g,G */
797 		      c = conv_flt (stream, &context, width, addr, flags);
798 #else
799 	          case 'd':
800 		  case 'u':
801                     base = 10;
802 		    goto conv_int;
803 
804 #ifdef _NEED_IO_PERCENT_B
805                   case 'b':
806                     base = 2;
807                     goto conv_int;
808 #endif
809 
810 	          case 'o':
811                     base = 8;
812 		    __PICOLIBC_FALLTHROUGH;
813 		  case 'i':
814 		    goto conv_int;
815 
816                   case 'p':
817                       if (sizeof(void *) > sizeof(int))
818                           flags |= FL_LONG;
819                       __PICOLIBC_FALLTHROUGH;
820 		  default:			/* p,x,X	*/
821                     base = 16;
822 		  conv_int:
823 		    c = conv_int (stream, &context, width, addr, flags, base);
824 #endif
825 		}
826 	    } /* else */
827 
828 	    if (!c) {
829 		if (stream->flags & (__SERR | __SEOF))
830 		    goto eof;
831 		break;
832 	    }
833 	    if (!(flags & FL_STAR)) nconvs += 1;
834 	} /* else */
835     } /* while */
836 #ifdef _NEED_IO_POS_ARGS
837     va_end(ap);
838 #endif
839 #ifdef WIDE_CHARS
840     if (!IS_EOF(context.unget))
841         UNGETC(context.unget, stream);
842 #endif
843     return nconvs;
844 
845   eof:
846 #ifdef _NEED_IO_POS_ARGS
847     va_end(ap);
848 #endif
849 #ifdef WIDE_CHARS
850     if (!IS_EOF(context.unget))
851         UNGETC(context.unget, stream);
852 #endif
853     return nconvs ? nconvs : EOF;
854 }
855 
856 #undef ap
857 
858 #if defined(_FORMAT_DEFAULT_DOUBLE) && !defined(vfscanf)
859 #ifdef _HAVE_ALIAS_ATTRIBUTE
860 __strong_reference(vfscanf, __d_vfscanf);
861 #else
__d_vfscanf(FILE * stream,const char * fmt,va_list ap)862 int __d_vfscanf (FILE * stream, const char *fmt, va_list ap) { return vfscanf(stream, fmt, ap); }
863 #endif
864 #endif
865