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