arc: clone: Simplify CLONE_THREAD detection
[uclibc-ng.git] / libc / stdio / _scanf.c
blob3f3000d6f7baa38fac6df1fbcfa9263729d06777
1 /* Copyright (C) 2002-2004 Manuel Novoa III
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, see
15 * <http://www.gnu.org/licenses/>.
18 /* Aug 1, 2003
19 * New *scanf implementation with lots of bug fixes and *wscanf support.
20 * Also now optionally supports hexadecimal float notation, positional
21 * args, and glibc locale-specific digit grouping. Should now be
22 * standards compliant.
24 * Aug 18, 2003
25 * Bug fix: scanf %lc,%ls,%l[ would always set mb_fail on eof or error,
26 * even when just starting a new mb char.
27 * Bug fix: wscanf would incorrectly unget in certain situations.
29 * Sep 5, 2003
30 * Bug fix: store flag wasn't respected if no positional args.
31 * Implement vs{n}scanf for the non-buffered stdio no-wchar case.
33 * Sep 13, 2003
34 * Bug fix: Fix a problem reported by Atsushi Nemoto <anemo@mba.ocn.ne.jp>
35 * for environments where long and long long are the same.
37 * Sep 21, 2003
38 * Ugh... EOF handling by scanf was completely broken. :-( Regretably,
39 * I got my mind fixed in one mode and didn't comply with the standards.
40 * Things should be fixed now, but comparision testing is difficult when
41 * glibc's scanf is broken and they stubbornly refuse to even acknowledge
42 * that it is... even when confronted by specific examples from the C99
43 * standards and from an official C standard defect report.
46 #include <features.h>
47 #include "_stdio.h"
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <ctype.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <stdint.h>
54 #include <errno.h>
55 #include <printf.h>
57 #ifdef __UCLIBC_HAS_WCHAR__
58 #include <bits/uClibc_uwchar.h>
59 #include <wchar.h>
60 #include <wctype.h>
61 #endif /* __UCLIBC_HAS_WCHAR__ */
63 #include <langinfo.h>
64 #include <locale.h>
66 #include <assert.h>
67 #include <limits.h>
69 #ifdef __UCLIBC_HAS_THREADS__
70 #include <stdio_ext.h>
71 #include <pthread.h>
72 #endif /* __UCLIBC_HAS_THREADS__ */
74 #ifdef __UCLIBC_HAS_FLOATS__
75 #include <float.h>
76 #include <bits/uClibc_fpmax.h>
77 #endif /* __UCLIBC_HAS_FLOATS__ */
79 #undef __STDIO_HAS_VSSCANF
80 #if defined(__STDIO_BUFFERS) || !defined(__UCLIBC_HAS_WCHAR__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
81 #define __STDIO_HAS_VSSCANF 1
83 #if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
84 typedef struct {
85 FILE f;
86 unsigned char *bufread; /* pointer to 1 past end of buffer */
87 unsigned char *bufpos;
88 } __FILE_vsscanf;
89 #endif
91 #endif
93 #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
95 extern unsigned long long
96 _stdlib_strto_ll(register const char * __restrict str,
97 char ** __restrict endptr, int base, int sflag);
98 #if (ULLONG_MAX == UINTMAX_MAX)
99 #define STRTOUIM(s,e,b,sf) _stdlib_strto_ll(s,e,b,sf)
100 #endif
102 #else /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
104 extern unsigned long
105 _stdlib_strto_l(register const char * __restrict str,
106 char ** __restrict endptr, int base, int sflag);
108 #if (ULONG_MAX == UINTMAX_MAX)
109 #define STRTOUIM(s,e,b,sf) _stdlib_strto_l(s,e,b,sf)
110 #endif
112 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
114 #ifndef STRTOUIM
115 #error STRTOUIM conversion function is undefined!
116 #endif
118 /**********************************************************************/
120 /* The standards require EOF < 0. */
121 #if EOF >= CHAR_MIN
122 #define __isdigit_char_or_EOF(C) __isdigit_char((C))
123 #else
124 #define __isdigit_char_or_EOF(C) __isdigit_int((C))
125 #endif
127 /**********************************************************************/
128 #ifdef L_fscanf
130 int fscanf(FILE * __restrict stream, const char * __restrict format, ...)
132 va_list arg;
133 int rv;
135 va_start(arg, format);
136 rv = vfscanf(stream, format, arg);
137 va_end(arg);
139 return rv;
141 libc_hidden_def(fscanf)
143 #endif
144 /**********************************************************************/
145 #ifdef L_scanf
147 int scanf(const char * __restrict format, ...)
149 va_list arg;
150 int rv;
152 va_start(arg, format);
153 rv = vfscanf(stdin, format, arg);
154 va_end(arg);
156 return rv;
159 #endif
160 /**********************************************************************/
161 #ifdef L_sscanf
163 #ifdef __STDIO_HAS_VSSCANF
165 int sscanf(const char * __restrict str, const char * __restrict format, ...)
167 va_list arg;
168 int rv;
170 va_start(arg, format);
171 rv = vsscanf(str, format, arg);
172 va_end(arg);
174 return rv;
176 libc_hidden_def(sscanf)
178 #else /* __STDIO_HAS_VSSCANF */
179 #warning Skipping sscanf since no vsscanf!
180 #endif /* __STDIO_HAS_VSSCANF */
182 #endif
183 /**********************************************************************/
184 #ifdef L_vscanf
186 int vscanf(const char * __restrict format, va_list arg)
188 return vfscanf(stdin, format, arg);
191 #endif
192 /**********************************************************************/
193 #ifdef L_vsscanf
195 #ifdef __STDIO_BUFFERS
197 int vsscanf(const char *sp, const char *fmt, va_list ap)
199 FILE f;
201 f.__filedes = __STDIO_STREAM_FAKE_VSSCANF_FILEDES;
202 f.__modeflags = (__FLAG_NARROW|__FLAG_READONLY|__FLAG_READING);
204 #ifdef __UCLIBC_HAS_WCHAR__
205 f.__ungot_width[0] = 0;
206 #endif
207 #ifdef __STDIO_MBSTATE
208 __INIT_MBSTATE(&(f.__state));
209 #endif
211 #ifdef __UCLIBC_HAS_THREADS__
212 f.__user_locking = 1; /* Set user locking. */
213 STDIO_INIT_MUTEX(f.__lock);
214 #endif
215 f.__nextopen = NULL;
217 /* Set these last since __bufgetc initialization depends on
218 * __user_locking and only gets set if user locking is on. */
219 f.__bufstart =
220 f.__bufpos = (unsigned char *) ((void *) sp);
221 f.__bufread =
222 f.__bufend = f.__bufstart + strlen(sp);
223 __STDIO_STREAM_ENABLE_GETC(&f);
224 __STDIO_STREAM_DISABLE_PUTC(&f);
226 return vfscanf(&f, fmt, ap);
228 libc_hidden_def(vsscanf)
230 #elif !defined(__UCLIBC_HAS_WCHAR__)
232 int vsscanf(const char *sp, const char *fmt, va_list ap)
234 __FILE_vsscanf f;
236 f.bufpos = (unsigned char *) ((void *) sp);
237 f.bufread = f.bufpos + strlen(sp);
239 f.f.__filedes = __STDIO_STREAM_FAKE_VSSCANF_FILEDES_NB;
240 f.f.__modeflags = (__FLAG_NARROW|__FLAG_READONLY|__FLAG_READING);
242 /* #ifdef __UCLIBC_HAS_WCHAR__ */
243 /* f.f.__ungot_width[0] = 0; */
244 /* #endif */
245 #ifdef __STDIO_MBSTATE
246 #error __STDIO_MBSTATE is defined!
247 /* __INIT_MBSTATE(&(f.f.__state)); */
248 #endif
250 #ifdef __UCLIBC_HAS_THREADS__
251 f.f.__user_locking = 1; /* Set user locking. */
252 STDIO_INIT_MUTEX(f.f.__lock);
253 #endif
254 f.f.__nextopen = NULL;
256 return vfscanf(&f.f, fmt, ap);
258 libc_hidden_def(vsscanf)
260 #elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
262 int vsscanf(const char *sp, const char *fmt, va_list ap)
264 FILE *f;
265 int rv = EOF;
267 if ((f = fmemopen((char *)sp, strlen(sp), "r")) != NULL) {
268 rv = vfscanf(f, fmt, ap);
269 fclose(f);
272 return rv;
274 libc_hidden_def(vsscanf)
276 #else
277 #warning Skipping vsscanf since no buffering, no custom streams, and wchar enabled!
278 #ifdef __STDIO_HAS_VSSCANF
279 #error WHOA! __STDIO_HAS_VSSCANF is defined!
280 #endif
281 #endif
283 #endif
284 /**********************************************************************/
285 #ifdef L_fwscanf
287 int fwscanf(FILE * __restrict stream, const wchar_t * __restrict format, ...)
289 va_list arg;
290 int rv;
292 va_start(arg, format);
293 rv = vfwscanf(stream, format, arg);
294 va_end(arg);
296 return rv;
299 #endif
300 /**********************************************************************/
301 #ifdef L_wscanf
303 int wscanf(const wchar_t * __restrict format, ...)
305 va_list arg;
306 int rv;
308 va_start(arg, format);
309 rv = vfwscanf(stdin, format, arg);
310 va_end(arg);
312 return rv;
315 #endif
316 /**********************************************************************/
317 #ifdef L_swscanf
319 #ifdef __STDIO_BUFFERS
321 int swscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
322 ...)
324 va_list arg;
325 int rv;
327 va_start(arg, format);
328 rv = vswscanf(str, format, arg);
329 va_end(arg);
331 return rv;
333 #else /* __STDIO_BUFFERS */
334 #warning Skipping swscanf since no buffering!
335 #endif /* __STDIO_BUFFERS */
337 #endif
338 /**********************************************************************/
339 #ifdef L_vwscanf
341 int vwscanf(const wchar_t * __restrict format, va_list arg)
343 return vfwscanf(stdin, format, arg);
346 #endif
347 /**********************************************************************/
348 #ifdef L_vswscanf
350 #ifdef __STDIO_BUFFERS
352 int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
353 va_list arg)
355 FILE f;
357 f.__bufstart =
358 f.__bufpos = (unsigned char *) str;
359 f.__bufread =
360 f.__bufend = (unsigned char *)(str + wcslen(str));
361 __STDIO_STREAM_DISABLE_GETC(&f);
362 __STDIO_STREAM_DISABLE_PUTC(&f);
364 f.__filedes = __STDIO_STREAM_FAKE_VSWSCANF_FILEDES;
365 f.__modeflags = (__FLAG_WIDE|__FLAG_READONLY|__FLAG_READING);
367 #ifdef __UCLIBC_HAS_WCHAR__
368 f.__ungot_width[0] = 0;
369 #endif /* __UCLIBC_HAS_WCHAR__ */
370 #ifdef __STDIO_MBSTATE
371 __INIT_MBSTATE(&(f.__state));
372 #endif /* __STDIO_MBSTATE */
374 #ifdef __UCLIBC_HAS_THREADS__
375 f.__user_locking = 1; /* Set user locking. */
376 STDIO_INIT_MUTEX(f.__lock);
377 #endif
378 f.__nextopen = NULL;
380 return vfwscanf(&f, format, arg);
382 libc_hidden_def(vswscanf)
383 #else /* __STDIO_BUFFERS */
384 #warning Skipping vswscanf since no buffering!
385 #endif /* __STDIO_BUFFERS */
387 #endif
388 /**********************************************************************/
389 /**********************************************************************/
393 /* float layout 0123456789012345678901 repeat n for "l[" */
394 #define SPEC_CHARS "npxXoudifFeEgGaACSnmcs["
395 /* npxXoudif eEgG CS cs[ */
396 /* NOTE: the 'm' flag must come before any convs that support it */
398 /* NOTE: Ordering is important! The CONV_{C,S,LEFTBRACKET} must map
399 simply to their lowercase equivalents. */
401 enum {
402 CONV_n = 0,
403 CONV_p,
404 CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
405 CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
406 CONV_C, CONV_S, CONV_LEFTBRACKET, CONV_m, CONV_c, CONV_s, CONV_leftbracket,
407 CONV_percent, CONV_whitespace /* not in SPEC_* and no flags */
410 #ifdef __UCLIBC_HAS_FLOATS__
411 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
412 /* p x X o u d i f F e E g G a A */
413 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
414 #else
415 /* p x X o u d i f F e E g G a A */
416 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, 10 }
417 #endif
418 #else /* __UCLIBC_HAS_FLOATS__ */
419 /* p x X o u d i f F e E g G a A */
420 #define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0 }
421 #endif /* __UCLIBC_HAS_FLOATS__ */
423 #define SPEC_FLAGS "*'I"
425 enum {
426 FLAG_SURPRESS = 0x10, /* MUST BE 1ST!! See DO_FLAGS. */
427 FLAG_THOUSANDS = 0x20,
428 FLAG_I18N = 0x40, /* only works for d, i, u */
429 FLAG_MALLOC = 0x80, /* only works for c, s, S, and [ (and l[)*/
433 #define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
434 CONV_C, CONV_LEFTBRACKET, \
435 CONV_c, CONV_leftbracket }
437 /* Note: We treat L and ll as synonymous... for ints and floats. */
439 #define SPEC_ALLOWED_FLAGS { \
440 /* n */ (0x0f|FLAG_SURPRESS), \
441 /* p */ ( 0|FLAG_SURPRESS), \
442 /* oxXudi */ (0x0f|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \
443 /* fFeEgGaA */ (0x0c|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \
444 /* C */ ( 0|FLAG_SURPRESS), \
445 /* S and l[ */ ( 0|FLAG_SURPRESS|FLAG_MALLOC), \
446 /* c */ (0x04|FLAG_SURPRESS|FLAG_MALLOC), \
447 /* s and [ */ (0x04|FLAG_SURPRESS|FLAG_MALLOC), \
451 /**********************************************************************/
453 * In order to ease translation to what arginfo and _print_info._flags expect,
454 * we map: 0:int 1:char 2:longlong 4:long 8:short
455 * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
458 /* TODO -- Fix the table below to take into account stdint.h. */
459 /* #ifndef LLONG_MAX */
460 /* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
461 /* #else */
462 /* #if LLONG_MAX != INTMAX_MAX */
463 /* #error fix QUAL_CHARS intmax_t entry 'j'! */
464 /* #endif */
465 /* #endif */
467 #ifdef PDS
468 #error PDS already defined!
469 #endif
470 #ifdef SS
471 #error SS already defined!
472 #endif
473 #ifdef IMS
474 #error IMS already defined!
475 #endif
477 #if PTRDIFF_MAX == INT_MAX
478 #define PDS 0
479 #elif PTRDIFF_MAX == LONG_MAX
480 #define PDS 4
481 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
482 #define PDS 8
483 #else
484 #error fix QUAL_CHARS ptrdiff_t entry 't'!
485 #endif
487 #if SIZE_MAX == UINT_MAX
488 #define SS 0
489 #elif SIZE_MAX == ULONG_MAX
490 #define SS 4
491 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
492 #define SS 8
493 #else
494 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
495 #endif
497 #if INTMAX_MAX == INT_MAX
498 #define IMS 0
499 #elif INTMAX_MAX == LONG_MAX
500 #define IMS 4
501 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
502 #define IMS 8
503 #else
504 #error fix QUAL_CHARS intmax_t entry 'j'!
505 #endif
507 #define QUAL_CHARS { \
508 /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int q:long_long */ \
509 'h', 'l', 'L', 'j', 'z', 't', 'q', 0, \
510 2, 4, 8, IMS, SS, PDS, 8, 0, /* TODO -- fix!!! */ \
511 1, 8 \
515 /**********************************************************************/
517 #ifdef L_vfwscanf
518 #if WINT_MIN > WEOF
519 #error Unfortunately, we currently need wint_t to be able to store WEOF. Sorry.
520 #endif
521 #define W_EOF WEOF
522 #define Wint wint_t
523 #define Wchar wchar_t
524 #define Wuchar __uwchar_t
525 #define ISSPACE(C) iswspace((C))
526 #define VFSCANF vfwscanf
527 #define GETC(SC) (SC)->sc_getc((SC))
528 #else
529 typedef unsigned char __uchar_t;
530 #define W_EOF EOF
531 #define Wint int
532 #define Wchar char
533 #define Wuchar __uchar_t
534 #define ISSPACE(C) isspace((C))
535 #define VFSCANF vfscanf
536 #ifdef __UCLIBC_HAS_WCHAR__
537 #define GETC(SC) (SC)->sc_getc((SC))
538 #else /* __UCLIBC_HAS_WCHAR__ */
539 #define GETC(SC) getc_unlocked((SC)->fp)
540 #endif /* __UCLIBC_HAS_WCHAR__ */
541 #endif
543 struct scan_cookie {
544 Wint cc;
545 Wint ungot_char;
546 FILE *fp;
547 int nread;
548 int width;
550 #ifdef __UCLIBC_HAS_WCHAR__
551 wchar_t app_ungot; /* Match FILE struct member type. */
552 unsigned char ungot_wchar_width;
553 #else /* __UCLIBC_HAS_WCHAR__ */
554 unsigned char app_ungot; /* Match FILE struct member type. */
555 #endif /* __UCLIBC_HAS_WCHAR__ */
557 char ungot_flag;
559 #ifdef __UCLIBC_HAS_WCHAR__
560 char ungot_wflag; /* vfwscanf */
561 char mb_fail; /* vfscanf */
562 mbstate_t mbstate; /* vfscanf */
563 wint_t wc;
564 wint_t ungot_wchar; /* to support __scan_getc */
565 int (*sc_getc)(struct scan_cookie *);
566 #endif /* __UCLIBC_HAS_WCHAR__ */
568 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
569 const char *grouping;
570 const unsigned char *thousands_sep;
571 int tslen;
572 #ifdef __UCLIBC_HAS_WCHAR__
573 wchar_t thousands_sep_wc;
574 #endif /* __UCLIBC_HAS_WCHAR__ */
575 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
577 #ifdef __UCLIBC_HAS_FLOATS__
578 const unsigned char *decpt;
579 int decpt_len;
580 #ifdef __UCLIBC_HAS_WCHAR__
581 wchar_t decpt_wc;
582 #endif /* __UCLIBC_HAS_WCHAR__ */
583 const unsigned char *fake_decpt;
584 #endif /* __UCLIBC_HAS_FLOATS__ */
588 typedef struct {
589 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
590 #if NL_ARGMAX > 10
591 #warning NL_ARGMAX > 10, and space is allocated on the stack for positional args.
592 #endif
593 void *pos_args[NL_ARGMAX];
594 int num_pos_args; /* Must start at -1. */
595 int cur_pos_arg;
596 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
597 void *cur_ptr;
598 const unsigned char *fmt;
599 int cnt, dataargtype, conv_num, max_width;
600 unsigned char store, flags;
601 } psfs_t; /* parse scanf format state */
604 /**********************************************************************/
605 /**********************************************************************/
607 extern void __init_scan_cookie(register struct scan_cookie *sc,
608 register FILE *fp) attribute_hidden;
609 extern int __scan_getc(register struct scan_cookie *sc) attribute_hidden;
610 extern void __scan_ungetc(register struct scan_cookie *sc) attribute_hidden;
612 #ifdef __UCLIBC_HAS_FLOATS__
613 extern int __scan_strtold(long double *ld, struct scan_cookie *sc);
614 #endif /* __UCLIBC_HAS_FLOATS__ */
616 extern int __psfs_parse_spec(psfs_t *psfs) attribute_hidden;
617 extern int __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc) attribute_hidden;
619 /**********************************************************************/
620 #ifdef L___scan_cookie
622 #ifndef __UCLIBC_HAS_LOCALE__
623 static const char decpt_str[] = ".";
624 #endif
626 void attribute_hidden __init_scan_cookie(register struct scan_cookie *sc,
627 register FILE *fp)
629 sc->fp = fp;
630 sc->nread = 0;
631 sc->ungot_flag = 0;
632 sc->app_ungot = ((fp->__modeflags & __FLAG_UNGOT) ? fp->__ungot[1] : 0);
633 #ifdef __UCLIBC_HAS_WCHAR__
634 sc->ungot_wflag = 0; /* vfwscanf */
635 sc->mb_fail = 0;
636 #endif /* __UCLIBC_HAS_WCHAR__ */
638 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
639 if (*(sc->grouping = __UCLIBC_CURLOCALE->grouping)) {
640 sc->thousands_sep = (const unsigned char *) __UCLIBC_CURLOCALE->thousands_sep;
641 sc->tslen = __UCLIBC_CURLOCALE->thousands_sep_len;
642 #ifdef __UCLIBC_HAS_WCHAR__
643 sc->thousands_sep_wc = __UCLIBC_CURLOCALE->thousands_sep_wc;
644 #endif /* __UCLIBC_HAS_WCHAR__ */
646 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
648 #ifdef __UCLIBC_HAS_FLOATS__
649 #ifdef __UCLIBC_HAS_LOCALE__
650 sc->decpt = (const unsigned char *) __UCLIBC_CURLOCALE->decimal_point;
651 sc->decpt_len = __UCLIBC_CURLOCALE->decimal_point_len;
652 #else /* __UCLIBC_HAS_LOCALE__ */
653 sc->fake_decpt = sc->decpt = (unsigned char *) decpt_str;
654 sc->decpt_len = 1;
655 #endif /* __UCLIBC_HAS_LOCALE__ */
656 #ifdef __UCLIBC_HAS_WCHAR__
657 #ifdef __UCLIBC_HAS_LOCALE__
658 sc->decpt_wc = __UCLIBC_CURLOCALE->decimal_point_wc;
659 #else
660 sc->decpt_wc = '.';
661 #endif
662 #endif /* __UCLIBC_HAS_WCHAR__ */
663 #endif /* __UCLIBC_HAS_FLOATS__ */
667 int attribute_hidden __scan_getc(register struct scan_cookie *sc)
669 int c;
671 #ifdef __UCLIBC_HAS_WCHAR__
672 assert(!sc->mb_fail);
673 #endif /* __UCLIBC_HAS_WCHAR__ */
675 sc->cc = EOF;
677 if (--sc->width < 0) {
678 sc->ungot_flag |= 2;
679 return -1;
682 if (sc->ungot_flag == 0) {
683 #if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
684 if (!__STDIO_STREAM_IS_FAKE_VSSCANF_NB(sc->fp)) {
685 c = GETC(sc);
686 } else {
687 __FILE_vsscanf *fv = (__FILE_vsscanf *)(sc->fp);
688 if (fv->bufpos < fv->bufread) {
689 c = *fv->bufpos++;
690 } else {
691 c = EOF;
692 sc->fp->__modeflags |= __FLAG_EOF;
695 if (c == EOF) {
696 sc->ungot_flag |= 2;
697 return -1;
699 #else
700 if ((c = GETC(sc)) == EOF) {
701 sc->ungot_flag |= 2;
702 return -1;
704 #endif
705 sc->ungot_char = c;
706 } else {
707 assert(sc->ungot_flag == 1);
708 sc->ungot_flag = 0;
711 ++sc->nread;
712 return sc->cc = sc->ungot_char;
715 void attribute_hidden __scan_ungetc(register struct scan_cookie *sc)
717 ++sc->width;
718 if (sc->ungot_flag == 2) { /* last was EOF */
719 sc->ungot_flag = 0;
720 sc->cc = sc->ungot_char;
721 } else if (sc->ungot_flag == 0) {
722 sc->ungot_flag = 1;
723 --sc->nread;
724 } else {
725 assert(0);
729 #endif
730 /**********************************************************************/
731 #ifdef L___psfs_parse_spec
733 #ifdef SPEC_FLAGS
734 static const unsigned char spec_flags[] = SPEC_FLAGS;
735 #endif /* SPEC_FLAGS */
736 static const unsigned char spec_chars[] = SPEC_CHARS;
737 static const unsigned char qual_chars[] = QUAL_CHARS;
738 static const unsigned char spec_ranges[] = SPEC_RANGES;
739 static const unsigned short spec_allowed[] = SPEC_ALLOWED_FLAGS;
741 int attribute_hidden __psfs_parse_spec(register psfs_t *psfs)
743 const unsigned char *p;
744 const unsigned char *fmt0 = psfs->fmt;
745 int i;
746 #ifdef SPEC_FLAGS
747 int j;
748 #endif
749 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
750 unsigned char fail = 0;
752 i = 0; /* Do this here to avoid a warning. */
754 if (!__isdigit_char(*psfs->fmt)) { /* Not a positional arg. */
755 fail = 1;
756 goto DO_FLAGS;
759 /* parse the positional arg (or width) value */
760 do {
761 if (i <= ((INT_MAX - 9)/10)) {
762 i = (i * 10) + (*psfs->fmt++ - '0');
764 } while (__isdigit_char(*psfs->fmt));
766 if (*psfs->fmt != '$') { /* This is a max field width. */
767 if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */
768 goto ERROR_EINVAL;
770 psfs->max_width = i;
771 psfs->num_pos_args = -2;
772 goto DO_QUALIFIER;
774 ++psfs->fmt; /* Advance past '$'. */
775 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
777 #if defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0))
778 DO_FLAGS:
779 #endif /* defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0)) */
780 #ifdef SPEC_FLAGS
781 p = spec_flags;
782 j = FLAG_SURPRESS;
783 do {
784 if (*p == *psfs->fmt) {
785 ++psfs->fmt;
786 psfs->flags |= j;
787 goto DO_FLAGS;
789 j += j;
790 } while (*++p);
792 if (psfs->flags & FLAG_SURPRESS) { /* Suppress assignment. */
793 psfs->store = 0;
794 goto DO_WIDTH;
796 #else /* SPEC_FLAGS */
797 if (*psfs->fmt == '*') { /* Suppress assignment. */
798 ++psfs->fmt;
799 psfs->store = 0;
800 goto DO_WIDTH;
802 #endif /* SPEC_FLAGS */
805 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
806 if (fail) {
807 /* Must be a non-positional arg */
808 if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */
809 goto ERROR_EINVAL;
811 psfs->num_pos_args = -2;
812 } else {
813 if ((psfs->num_pos_args == -2) || (((unsigned int)(--i)) >= NL_ARGMAX)) {
814 /* Already saw a non-pos arg or (0-based) num too large. */
815 goto ERROR_EINVAL;
817 psfs->cur_pos_arg = i;
819 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
821 DO_WIDTH:
822 for (i = 0 ; __isdigit_char(*psfs->fmt) ; ) {
823 if (i <= ((INT_MAX - 9)/10)) {
824 i = (i * 10) + (*psfs->fmt++ - '0');
825 psfs->max_width = i;
829 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
830 DO_QUALIFIER:
831 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
832 p = qual_chars;
833 do {
834 if (*psfs->fmt == *p) {
835 ++psfs->fmt;
836 break;
838 } while (*++p);
839 if ((p - qual_chars < 2) && (*psfs->fmt == *p)) {
840 p += ((sizeof(qual_chars)-2) / 2);
841 ++psfs->fmt;
843 psfs->dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
845 p = spec_chars;
846 do {
847 if (*psfs->fmt == *p) {
848 int p_m_spec_chars = p - spec_chars;
850 if (*p == 'm' &&
851 (psfs->fmt[1] == '[' || psfs->fmt[1] == 'c' ||
852 /* Assumes ascii for 's' and 'S' test. */
853 (psfs->fmt[1] | 0x20) == 's'))
855 if (psfs->store)
856 psfs->flags |= FLAG_MALLOC;
857 ++psfs->fmt;
858 ++p;
859 continue; /* The related conversions follow 'm'. */
862 for (p = spec_ranges; p_m_spec_chars > *p ; ++p) {}
863 if (((psfs->dataargtype >> 8) | psfs->flags)
864 & ~spec_allowed[(int)(p - spec_ranges)]
866 goto ERROR_EINVAL;
869 if (p_m_spec_chars == CONV_p) {
870 /* a pointer has the same size as 'long int' */
871 psfs->dataargtype = PA_FLAG_LONG;
872 } else if ((p_m_spec_chars >= CONV_c)
873 && (psfs->dataargtype & PA_FLAG_LONG)) {
874 p_m_spec_chars -= CONV_c - CONV_C; /* lc -> C, ls -> S, l[ -> ?? */
877 psfs->conv_num = p_m_spec_chars;
878 return psfs->fmt - fmt0;
880 if (!*++p) {
881 ERROR_EINVAL:
882 __set_errno(EINVAL);
883 return -1;
885 } while(1);
887 assert(0);
890 #endif
891 /**********************************************************************/
892 #if defined(L_vfscanf) || defined(L_vfwscanf)
894 #ifdef __UCLIBC_HAS_WCHAR__
895 #ifdef L_vfscanf
896 static int sc_getc(register struct scan_cookie *sc)
898 return (getc_unlocked)(sc->fp); /* Disable the macro. */
901 static int scan_getwc(register struct scan_cookie *sc)
903 size_t r;
904 int width;
905 wchar_t wc[1];
906 char b[1];
908 if (--sc->width < 0) {
909 sc->ungot_flag |= 2;
910 return -1;
913 width = sc->width; /* Preserve width. */
914 sc->width = INT_MAX; /* MB_CUR_MAX can invoke a function. */
916 assert(!sc->mb_fail);
918 r = (size_t)(-3);
919 while (__scan_getc(sc) >= 0) {
920 *b = sc->cc;
922 r = mbrtowc(wc, b, 1, &sc->mbstate);
923 if (((ssize_t) r) >= 0) { /* Successful completion of a wc. */
924 sc->wc = *wc;
925 goto SUCCESS;
926 } else if (r == ((size_t) -2)) {
927 /* Potentially valid but incomplete. */
928 continue;
930 break;
933 if (r == ((size_t)(-3))) { /* EOF or ERROR on first read */
934 sc->wc = WEOF;
935 r = (size_t)(-1);
936 } else {
937 /* If we reach here, either r == ((size_t)-1) and
938 * mbrtowc set errno to EILSEQ, or r == ((size_t)-2)
939 * and stream is in an error state or at EOF with a
940 * partially complete wchar. */
941 __set_errno(EILSEQ); /* In case of incomplete conversion. */
942 sc->mb_fail = 1;
945 SUCCESS:
946 sc->width = width; /* Restore width. */
948 return (int)((ssize_t) r);
951 #endif /* L_vfscanf */
953 #ifdef L_vfwscanf
955 /* This gets called by __scan_getc. __scan_getc is called by vfwscanf
956 * when the next wide char is expected to be valid ascii (digits).
958 static int sc_getc(register struct scan_cookie *sc)
960 wint_t wc;
962 if (__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp)) {
963 if (sc->fp->__bufpos < sc->fp->__bufend) {
964 wc = *((wchar_t *)(sc->fp->__bufpos));
965 sc->fp->__bufpos += sizeof(wchar_t);
966 } else {
967 sc->fp->__modeflags |= __FLAG_EOF;
968 return EOF;
970 } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) {
971 return EOF;
974 sc->ungot_wflag = 1;
975 sc->ungot_wchar = wc;
976 sc->ungot_wchar_width = sc->fp->__ungot_width[0];
978 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
979 if (wc == sc->thousands_sep_wc) {
980 wc = ',';
981 } else
982 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
983 #ifdef __UCLIBC_HAS_FLOATS__
984 if (wc == sc->decpt_wc) {
985 wc = '.';
986 } else
987 #endif /* __UCLIBC_HAS_FLOATS__ */
988 sc->wc = sc->ungot_char = wc;
990 return (int) wc;
993 static int scan_getwc(register struct scan_cookie *sc)
995 wint_t wc;
997 sc->wc = WEOF;
999 if (--sc->width < 0) {
1000 sc->ungot_flag |= 2;
1001 return -1;
1004 if (sc->ungot_flag == 0) {
1005 if (__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp)) {
1006 if (sc->fp->__bufpos < sc->fp->__bufend) {
1007 wc = *((wchar_t *)(sc->fp->__bufpos));
1008 sc->fp->__bufpos += sizeof(wchar_t);
1009 } else {
1010 sc->ungot_flag |= 2;
1011 return -1;
1013 } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) {
1014 sc->ungot_flag |= 2;
1015 return -1;
1017 sc->ungot_wflag = 1;
1018 sc->ungot_char = wc;
1019 sc->ungot_wchar_width = sc->fp->__ungot_width[0];
1020 } else {
1021 assert(sc->ungot_flag == 1);
1022 sc->ungot_flag = 0;
1025 ++sc->nread;
1026 sc->wc = sc->ungot_char;
1028 return 0;
1032 #endif /* L_vfwscanf */
1033 #endif /* __UCLIBC_HAS_WCHAR__ */
1035 static __inline void kill_scan_cookie(register struct scan_cookie *sc)
1037 #ifdef L_vfscanf
1039 if (sc->ungot_flag & 1) {
1040 #if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
1041 if (!__STDIO_STREAM_IS_FAKE_VSSCANF_NB(sc->fp)) {
1042 ungetc(sc->ungot_char, sc->fp);
1044 #else
1045 ungetc(sc->ungot_char, sc->fp);
1046 #endif
1047 /* Deal with distiction between user and scanf ungots. */
1048 if (sc->nread == 0) { /* Only one char was read... app ungot? */
1049 sc->fp->__ungot[1] = sc->app_ungot; /* restore ungot state. */
1050 } else {
1051 sc->fp->__ungot[1] = 0;
1055 #else
1057 if ((sc->ungot_flag & 1) && (sc->ungot_wflag & 1)
1058 && !__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp)
1059 && (sc->fp->__state.__mask == 0)
1061 ungetwc(sc->ungot_char, sc->fp);
1062 /* Deal with distiction between user and scanf ungots. */
1063 if (sc->nread == 0) { /* Only one char was read... app ungot? */
1064 sc->fp->__ungot[1] = sc->app_ungot; /* restore ungot state. */
1065 } else {
1066 sc->fp->__ungot[1] = 0;
1068 sc->fp->__ungot_width[1] = sc->ungot_wchar_width;
1071 #endif
1075 int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)
1077 const Wuchar *fmt;
1078 unsigned char *b;
1080 #ifdef L_vfwscanf
1081 wchar_t wbuf[1];
1082 wchar_t *wb;
1083 #endif /* L_vfwscanf */
1085 #if defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) || !defined(L_vfscanf)
1086 mbstate_t mbstate;
1087 #endif
1089 struct scan_cookie sc;
1090 psfs_t psfs;
1091 int i;
1093 #define MAX_DIGITS 65 /* Allow one leading 0. */
1094 unsigned char buf[MAX_DIGITS+2];
1095 #ifdef L_vfscanf
1096 unsigned char scanset[UCHAR_MAX + 1];
1097 unsigned char invert = 0; /* Careful! Meaning changes. */
1098 #endif /* L_vfscanf */
1099 unsigned char fail;
1100 unsigned char zero_conversions = 1;
1101 __STDIO_AUTO_THREADLOCK_VAR;
1103 /* To support old programs, don't check mb validity if in C locale. */
1104 #if defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf)
1105 /* ANSI/ISO C99 requires format string to be a valid multibyte string
1106 * beginning and ending in its initial shift state. */
1107 if (__UCLIBC_CURLOCALE->encoding != __ctype_encoding_7_bit) {
1108 const char *p = format;
1109 mbstate.__mask = 0; /* Initialize the mbstate. */
1110 if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
1111 __set_errno(EINVAL); /* Format string is invalid. */
1112 return 0;
1115 #endif /* defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) */
1117 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
1118 psfs.num_pos_args = -1; /* Must start at -1. */
1119 /* Initialize positional arg ptrs to NULL. */
1120 memset(psfs.pos_args, 0, sizeof(psfs.pos_args));
1121 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
1123 __STDIO_AUTO_THREADLOCK(fp);
1125 __STDIO_STREAM_VALIDATE(fp);
1127 __init_scan_cookie(&sc,fp);
1128 #ifdef __UCLIBC_HAS_WCHAR__
1129 sc.sc_getc = sc_getc;
1130 sc.ungot_wchar_width = sc.fp->__ungot_width[1];
1132 #ifdef L_vfwscanf
1134 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1135 if (*sc.grouping) {
1136 sc.thousands_sep = (const unsigned char *) ",";
1137 sc.tslen = 1;
1139 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1141 #ifdef __UCLIBC_HAS_FLOATS__
1142 sc.fake_decpt = (const unsigned char *) ".";
1143 #endif /* __UCLIBC_HAS_FLOATS__ */
1145 #else /* L_vfwscanf */
1147 #ifdef __UCLIBC_HAS_FLOATS__
1148 sc.fake_decpt = sc.decpt;
1149 #endif /* __UCLIBC_HAS_FLOATS__ */
1151 #endif /* L_vfwscanf */
1153 #endif /* __UCLIBC_HAS_WCHAR__ */
1154 psfs.cnt = 0;
1156 /* Note: If we ever wanted to support non-nice codesets, we
1157 * would really need to do a mb->wc conversion here in the
1158 * vfscanf case. Related changes would have to be made in
1159 * the code that follows... basicly wherever fmt appears. */
1160 for (fmt = (const Wuchar *) format ; *fmt ; /* ++fmt */) {
1162 psfs.store = 1;
1163 psfs.flags = 0;
1164 #ifndef NDEBUG
1165 psfs.cur_ptr = NULL; /* Debugging aid. */
1166 #endif /* NDEBUG */
1169 sc.ungot_flag &= 1; /* Clear (possible fake) EOF. */
1170 sc.width = psfs.max_width = INT_MAX;
1172 /* Note: According to the standards, vfscanf does use isspace
1173 * here. So, if we did a mb->wc conversion, we would have to do
1174 * something like
1175 * ((((__uwchar_t)wc) < UCHAR_MAX) && isspace(wc))
1176 * because wc might not be in the allowed domain. */
1177 if (ISSPACE(*fmt)) {
1178 do {
1179 ++fmt;
1180 } while (ISSPACE(*fmt));
1181 --fmt;
1182 psfs.conv_num = CONV_whitespace;
1183 goto DO_WHITESPACE;
1186 if (*fmt == '%') { /* Conversion specification. */
1187 if (*++fmt == '%') { /* Remember, '%' eats whitespace too. */
1188 /* Note: The standard says no conversion occurs.
1189 * So do not reset zero_conversions flag. */
1190 psfs.conv_num = CONV_percent;
1191 goto DO_CONVERSION;
1195 #ifdef L_vfscanf
1196 psfs.fmt = fmt;
1197 #else /* L_vfscanf */
1199 const __uwchar_t *wf = fmt;
1200 psfs.fmt = b = buf;
1202 while (*wf && __isascii(*wf) && (b < buf + sizeof(buf) - 1)) {
1203 *b++ = *wf++;
1205 *b = 0;
1206 if (b == buf) { /* Bad conversion specifier! */
1207 goto DONE;
1210 #endif /* L_vfscanf */
1211 if ((i = __psfs_parse_spec(&psfs)) < 0) { /* Bad conversion specifier! */
1212 goto DONE;
1214 fmt += i;
1216 if (psfs.store) {
1217 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
1218 if (psfs.num_pos_args == -2) {
1219 psfs.cur_ptr = va_arg(arg, void *);
1220 } else {
1221 while (psfs.cur_pos_arg > psfs.num_pos_args) {
1222 psfs.pos_args[++psfs.num_pos_args] = va_arg(arg, void *);
1224 psfs.cur_ptr = psfs.pos_args[psfs.cur_pos_arg];
1226 #else /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
1227 psfs.cur_ptr = va_arg(arg, void *);
1228 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
1231 DO_CONVERSION:
1232 /* First, consume white-space if not n, c, [, C, or l[. */
1233 if ((((1L << CONV_n)|(1L << CONV_C)|(1L << CONV_c)
1234 |(1L << CONV_LEFTBRACKET)|(1L << CONV_leftbracket))
1235 & (1L << psfs.conv_num)) == 0
1237 DO_WHITESPACE:
1238 while ((__scan_getc(&sc) >= 0)
1239 #ifdef L_vfscanf
1240 && isspace(sc.cc)
1241 #else /* L_vfscanf */
1242 && iswspace(sc.wc)
1243 #endif /* L_vfscanf */
1244 ) {}
1245 __scan_ungetc(&sc);
1246 if (psfs.conv_num == CONV_whitespace) {
1247 goto NEXT_FMT;
1251 sc.width = psfs.max_width; /* Now limit the max width. */
1253 if (sc.width == 0) { /* 0 width is forbidden. */
1254 goto DONE;
1258 if (psfs.conv_num == CONV_percent) {
1259 goto MATCH_CHAR;
1262 if (psfs.conv_num == CONV_n) {
1263 /* zero_conversions = 0; */
1264 if (psfs.store) {
1265 _store_inttype(psfs.cur_ptr, psfs.dataargtype,
1266 (uintmax_t) sc.nread);
1268 goto NEXT_FMT;
1271 if (psfs.conv_num <= CONV_A) { /* pointer, integer, or float spec */
1272 int r = __psfs_do_numeric(&psfs, &sc);
1273 #ifndef L_vfscanf
1274 if (sc.ungot_wflag == 1) { /* fix up '?', '.', and ',' hacks */
1275 sc.cc = sc.ungot_char = sc.ungot_wchar;
1277 #endif
1278 if (r != -1) { /* Either success or a matching failure. */
1279 zero_conversions = 0;
1281 if (r < 0) {
1282 goto DONE;
1284 goto NEXT_FMT;
1287 /* Do string conversions here since they are not common code. */
1290 #ifdef L_vfscanf
1293 #ifdef __UCLIBC_HAS_WCHAR__
1294 (psfs.conv_num >= CONV_LEFTBRACKET)
1295 #else /* __UCLIBC_HAS_WCHAR__ */
1296 (psfs.conv_num >= CONV_c)
1297 #endif /* __UCLIBC_HAS_WCHAR__ */
1299 /* We might have to handle the allocation ourselves */
1300 int len;
1301 unsigned char **ptr;
1303 b = (psfs.store ? ((unsigned char *) psfs.cur_ptr) : buf);
1304 /* With 'm', we actually got a pointer to a pointer */
1305 ptr = (void *)b;
1307 if (psfs.flags & FLAG_MALLOC) {
1308 len = 0;
1309 b = NULL;
1310 } else
1311 len = -1;
1313 fail = 1;
1315 if (psfs.conv_num == CONV_c) {
1316 if (sc.width == INT_MAX) {
1317 sc.width = 1;
1320 if (psfs.flags & FLAG_MALLOC)
1321 b = malloc(sc.width);
1323 i = 0;
1324 while (__scan_getc(&sc) >= 0) {
1325 zero_conversions = 0;
1326 b[i] = sc.cc;
1327 i += psfs.store;
1329 __scan_ungetc(&sc);
1330 if (sc.width > 0) { /* Failed to read all required. */
1331 goto DONE;
1333 if (psfs.flags & FLAG_MALLOC)
1334 *ptr = b;
1335 psfs.cnt += psfs.store;
1336 goto NEXT_FMT;
1339 if (psfs.conv_num == CONV_s) {
1341 i = 0;
1342 /* Yes, believe it or not, a %s conversion can store nuls. */
1343 while ((__scan_getc(&sc) >= 0) && !isspace(sc.cc)) {
1344 zero_conversions = 0;
1345 if (i == len) {
1346 /* Pick a size that won't trigger a lot of
1347 * mallocs early on ... */
1348 len += 256;
1349 b = realloc(b, len + 1);
1351 b[i] = sc.cc;
1352 i += psfs.store;
1353 fail = 0;
1356 } else {
1357 #ifdef __UCLIBC_HAS_WCHAR__
1358 assert((psfs.conv_num == CONV_LEFTBRACKET) || \
1359 (psfs.conv_num == CONV_leftbracket));
1360 #else /* __UCLIBC_HAS_WCHAR__ */
1361 assert((psfs.conv_num == CONV_leftbracket));
1362 #endif /* __UCLIBC_HAS_WCHAR__ */
1364 invert = 0;
1366 if (*++fmt == '^') {
1367 ++fmt;
1368 invert = 1;
1370 memset(scanset, invert, sizeof(scanset));
1371 invert = 1-invert;
1373 if (*fmt == ']') {
1374 scanset[(int)(']')] = invert;
1375 ++fmt;
1378 while (*fmt != ']') {
1379 if (!*fmt) { /* No closing ']'. */
1380 goto DONE;
1382 if ((*fmt == '-') && (fmt[1] != ']')
1383 && (fmt[-1] < fmt[1]) /* sorted? */
1384 ) { /* range */
1385 ++fmt;
1386 i = fmt[-2];
1387 /* Note: scanset[i] should already have been done
1388 * in the previous iteration. */
1389 do {
1390 scanset[++i] = invert;
1391 } while (i < *fmt);
1392 /* Safe to fall through, and a bit smaller. */
1394 /* literal char */
1395 scanset[(int) *fmt] = invert;
1396 ++fmt;
1399 #ifdef __UCLIBC_HAS_WCHAR__
1400 if (psfs.conv_num == CONV_LEFTBRACKET) {
1401 goto DO_LEFTBRACKET;
1403 #endif /* __UCLIBC_HAS_WCHAR__ */
1406 i = 0;
1407 while (__scan_getc(&sc) >= 0) {
1408 zero_conversions = 0;
1409 if (!scanset[sc.cc]) {
1410 break;
1412 if (i == len) {
1413 /* Pick a size that won't trigger a lot of
1414 * mallocs early on ... */
1415 len += 256;
1416 b = realloc(b, len + 1);
1418 b[i] = sc.cc;
1419 i += psfs.store;
1420 fail = 0;
1423 /* Common tail for processing of %s and %[. */
1425 __scan_ungetc(&sc);
1426 if (fail) { /* nothing stored! */
1427 goto DONE;
1429 if (psfs.flags & FLAG_MALLOC)
1430 *ptr = b;
1431 b += i;
1432 *b = 0; /* Nul-terminate string. */
1433 psfs.cnt += psfs.store;
1434 goto NEXT_FMT;
1437 #ifdef __UCLIBC_HAS_WCHAR__
1438 DO_LEFTBRACKET: /* Need to do common wide init. */
1439 if (psfs.conv_num >= CONV_C) {
1440 wchar_t wbuf[1];
1441 wchar_t *wb;
1443 sc.mbstate.__mask = 0;
1445 wb = (psfs.store ? ((wchar_t *) psfs.cur_ptr) : wbuf);
1446 fail = 1;
1448 if (psfs.conv_num == CONV_C) {
1449 if (sc.width == INT_MAX) {
1450 sc.width = 1;
1453 while (scan_getwc(&sc) >= 0) {
1454 zero_conversions = 0;
1455 assert(sc.width >= 0);
1456 *wb = sc.wc;
1457 wb += psfs.store;
1460 __scan_ungetc(&sc);
1461 if (sc.width > 0) { /* Failed to read all required. */
1462 goto DONE;
1464 psfs.cnt += psfs.store;
1465 goto NEXT_FMT;
1469 if (psfs.conv_num == CONV_S) {
1470 /* Yes, believe it or not, a %s conversion can store nuls. */
1471 while (scan_getwc(&sc) >= 0) {
1472 zero_conversions = 0;
1473 if ((((__uwchar_t)(sc.wc)) <= UCHAR_MAX) && isspace(sc.wc)) {
1474 break;
1476 *wb = sc.wc;
1477 wb += psfs.store;
1478 fail = 0;
1480 } else {
1481 assert(psfs.conv_num == CONV_LEFTBRACKET);
1483 while (scan_getwc(&sc) >= 0) {
1484 zero_conversions = 0;
1485 if (((__uwchar_t) sc.wc) <= UCHAR_MAX) {
1486 if (!scanset[sc.wc]) {
1487 break;
1489 } else if (invert) {
1490 break;
1492 *wb = sc.wc;
1493 wb += psfs.store;
1494 fail = 0;
1497 /* Common tail for processing of %ls and %l[. */
1499 __scan_ungetc(&sc);
1500 if (fail || sc.mb_fail) { /* Nothing stored or mb error. */
1501 goto DONE;
1503 *wb = 0; /* Nul-terminate string. */
1504 psfs.cnt += psfs.store;
1505 goto NEXT_FMT;
1509 #endif /* __UCLIBC_HAS_WCHAR__ */
1510 #else /* L_vfscanf */
1512 if (psfs.conv_num >= CONV_C) {
1513 b = buf;
1514 wb = wbuf;
1515 if (psfs.conv_num >= CONV_c) {
1516 mbstate.__mask = 0; /* Initialize the mbstate. */
1517 if (psfs.store) {
1518 b = (unsigned char *) psfs.cur_ptr;
1520 } else {
1521 if (psfs.store) {
1522 wb = (wchar_t *) psfs.cur_ptr;
1525 fail = 1;
1528 if ((psfs.conv_num == CONV_C) || (psfs.conv_num == CONV_c)) {
1529 if (sc.width == INT_MAX) {
1530 sc.width = 1;
1533 while (scan_getwc(&sc) >= 0) {
1534 zero_conversions = 0;
1535 if (psfs.conv_num == CONV_C) {
1536 *wb = sc.wc;
1537 wb += psfs.store;
1538 } else {
1539 i = wcrtomb((char*) b, sc.wc, &mbstate);
1540 if (i < 0) { /* Conversion failure. */
1541 goto DONE_DO_UNGET;
1543 if (psfs.store) {
1544 b += i;
1548 __scan_ungetc(&sc);
1549 if (sc.width > 0) { /* Failed to read all required. */
1550 goto DONE;
1552 psfs.cnt += psfs.store;
1553 goto NEXT_FMT;
1556 if ((psfs.conv_num == CONV_S) || (psfs.conv_num == CONV_s)) {
1557 /* Yes, believe it or not, a %s conversion can store nuls. */
1558 while (scan_getwc(&sc) >= 0) {
1559 zero_conversions = 0;
1560 if (iswspace(sc.wc)) {
1561 break;
1563 if (psfs.conv_num == CONV_S) {
1564 *wb = sc.wc;
1565 wb += psfs.store;
1566 } else {
1567 i = wcrtomb((char*) b, sc.wc, &mbstate);
1568 if (i < 0) { /* Conversion failure. */
1569 goto DONE_DO_UNGET;
1571 if (psfs.store) {
1572 b += i;
1575 fail = 0;
1577 } else {
1578 const wchar_t *sss;
1579 const wchar_t *ssp;
1580 unsigned char invert = 0;
1582 assert((psfs.conv_num == CONV_LEFTBRACKET)
1583 || (psfs.conv_num == CONV_leftbracket));
1585 if (*++fmt == '^') {
1586 ++fmt;
1587 invert = 1;
1589 sss = (const wchar_t *) fmt;
1590 if (*fmt == ']') {
1591 ++fmt;
1593 while (*fmt != ']') {
1594 if (!*fmt) { /* No closing ']'. */
1595 goto DONE;
1597 if ((*fmt == '-') && (fmt[1] != ']')
1598 && (fmt[-1] < fmt[1]) /* sorted? */
1599 ) { /* range */
1600 ++fmt;
1602 ++fmt;
1604 /* Ok... a valid scanset spec. */
1606 while (scan_getwc(&sc) >= 0) {
1607 zero_conversions = 0;
1608 ssp = sss;
1609 do { /* We know sss < fmt. */
1610 if (*ssp == '-') { /* possible range... */
1611 /* Note: We accept a-c-e (ordered) as
1612 * equivalent to a-e. */
1613 if (ssp > sss) {
1614 if ((++ssp < (const wchar_t *) fmt)
1615 && (ssp[-2] < *ssp) /* sorted? */
1616 ) { /* yes */
1617 if ((sc.wc >= ssp[-2])
1618 && (sc.wc <= *ssp)) {
1619 break;
1621 continue; /* not in range */
1623 --ssp; /* oops... '-' at end, so back up */
1625 /* false alarm... a literal '-' */
1627 if (sc.wc == *ssp) { /* Matched literal char. */
1628 break;
1630 } while (++ssp < (const wchar_t *) fmt);
1632 if ((ssp == (const wchar_t *) fmt) ^ invert) {
1633 /* no match and not inverting
1634 * or match and inverting */
1635 break;
1637 if (psfs.conv_num == CONV_LEFTBRACKET) {
1638 *wb = sc.wc;
1639 wb += psfs.store;
1640 } else {
1641 i = wcrtomb((char*) b, sc.wc, &mbstate);
1642 if (i < 0) { /* Conversion failure. */
1643 goto DONE_DO_UNGET;
1645 if (psfs.store) {
1646 b += i;
1649 fail = 0;
1652 /* Common tail for processing of %s and %[. */
1654 __scan_ungetc(&sc);
1655 if (fail) { /* nothing stored! */
1656 goto DONE;
1658 *wb = 0; /* Nul-terminate string. */
1659 *b = 0;
1660 psfs.cnt += psfs.store;
1661 goto NEXT_FMT;
1664 #endif /* L_vfscanf */
1666 assert(0);
1667 goto DONE;
1668 } /* conversion specification */
1670 MATCH_CHAR:
1671 if (__scan_getc(&sc) != *fmt) {
1672 #ifdef L_vfwscanf
1673 DONE_DO_UNGET:
1674 #endif /* L_vfwscanf */
1675 __scan_ungetc(&sc);
1676 goto DONE;
1679 NEXT_FMT:
1680 ++fmt;
1681 if (__FERROR_UNLOCKED(fp)) {
1682 break;
1686 DONE:
1687 if (__FERROR_UNLOCKED(fp) || (*fmt && zero_conversions && __FEOF_UNLOCKED(fp))) {
1688 psfs.cnt = EOF; /* Yes, vfwscanf also returns EOF. */
1691 kill_scan_cookie(&sc);
1693 __STDIO_STREAM_VALIDATE(fp);
1695 __STDIO_AUTO_THREADUNLOCK(fp);
1697 return psfs.cnt;
1699 libc_hidden_def(VFSCANF)
1700 #endif
1701 /**********************************************************************/
1702 #ifdef L___psfs_do_numeric
1704 static const unsigned char spec_base[] = SPEC_BASE;
1705 static const unsigned char nil_string[] = "(nil)";
1707 int attribute_hidden __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc)
1709 unsigned char *b;
1710 const unsigned char *p;
1712 #ifdef __UCLIBC_HAS_FLOATS__
1713 int exp_adjust = 0;
1714 #endif
1715 #define MAX_DIGITS 65 /* Allow one leading 0. */
1716 unsigned char buf[MAX_DIGITS+2+ 100];
1717 unsigned char usflag, base;
1718 unsigned char nonzero = 0;
1719 unsigned char seendigit = 0;
1721 #ifndef __UCLIBC_HAS_FLOATS__
1722 if (psfs->conv_num > CONV_i) { /* floating point */
1723 goto DONE;
1725 #endif
1727 base = spec_base[psfs->conv_num - CONV_p];
1728 usflag = (psfs->conv_num <= CONV_u); /* (1)0 if (un)signed */
1729 b = buf;
1732 if (psfs->conv_num == CONV_p) { /* Pointer */
1733 p = nil_string;
1734 do {
1735 if ((__scan_getc(sc) < 0) || (*p != sc->cc)) {
1736 __scan_ungetc(sc);
1737 if (p > nil_string) {
1738 /* We matched at least the '(' so even if we
1739 * are at eof, we can not match a pointer. */
1740 return -2; /* Matching failure */
1742 break;
1744 if (!*++p) { /* Matched (nil), so no unget necessary. */
1745 if (psfs->store) {
1746 ++psfs->cnt;
1747 _store_inttype(psfs->cur_ptr, psfs->dataargtype,
1748 (uintmax_t)0);
1750 return 0;
1752 } while (1);
1756 __scan_getc(sc);
1757 if (sc->cc < 0) {
1758 return -1; /* Input failure (nothing read yet). */
1761 if ((sc->cc == '+') || (sc->cc == '-')) { /* Handle leading sign.*/
1762 *b++ = sc->cc;
1763 __scan_getc(sc);
1766 if ((base & 0xef) == 0) { /* 0xef is ~16, so 16 or 0. */
1767 if (sc->cc == '0') { /* Possibly set base and handle prefix. */
1768 __scan_getc(sc);
1769 if ((sc->cc|0x20) == 'x') { /* Assumes ascii.. x or X. */
1770 if (__scan_getc(sc) < 0) {
1771 /* Either EOF or error (including wc outside char range).
1772 * If EOF or error, this is a matching failure (we read 0x).
1773 * If wc outside char range, this is also a matching failure.
1774 * Hence, we do an unget (although not really necessary here
1775 * and fail. */
1776 goto DONE_DO_UNGET; /* matching failure */
1778 base = 16; /* Base 16 for sure now. */
1779 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
1780 /* The prefix is required for hexadecimal floats. */
1781 *b++ = '0';
1782 *b++ = 'x';
1783 #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1784 } else { /* oops... back up */
1785 __scan_ungetc(sc);
1786 sc->cc = '0'; /* NASTY HACK! */
1788 base = (base >> 1) + 8; /* 0->8, 16->16. no 'if' */
1789 #ifdef __UCLIBC_HAS_FLOATS__
1790 if (psfs->conv_num > CONV_i) { /* floating point */
1791 base = 10;
1793 #endif
1795 } else if (!base) {
1796 base = 10;
1800 /***************** digit grouping **********************/
1801 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1803 if ((psfs->flags & FLAG_THOUSANDS) && (base == 10)
1804 && *(p = (const unsigned char *) sc->grouping)
1807 int nblk1, nblk2, nbmax, lastblock, pass, i;
1809 nbmax = nblk2 = nblk1 = *p;
1810 if (*++p) {
1811 nblk2 = *p;
1812 if (nbmax < nblk2) {
1813 nbmax = nblk2;
1815 assert(!p[1]);
1818 /* Note: for printf, if 0 and \' flags appear then
1819 * grouping is done before 0-padding. Should we
1820 * strip leading 0's first? Or add a 0 flag? */
1822 /* For vfwscanf, sc_getc translates, so the value of sc->cc is
1823 * either EOF or a char. */
1825 if (!__isdigit_char_or_EOF(sc->cc)) { /* No starting digit! */
1826 #ifdef __UCLIBC_HAS_FLOATS__
1827 if (psfs->conv_num > CONV_i) { /* floating point */
1828 goto NO_STARTING_DIGIT;
1830 #endif
1831 goto DONE_DO_UNGET;
1834 if (sc->cc == '0') {
1835 seendigit = 1;
1836 *b++ = '0'; /* Store the first 0. */
1837 #if 0
1838 do { /* But ignore all subsequent 0s. */
1839 __scan_getc(sc);
1840 } while (sc->cc == '0');
1841 #endif
1843 pass = 0;
1844 lastblock = 0;
1845 do {
1846 i = 0;
1847 while (__isdigit_char_or_EOF(sc->cc)) {
1848 seendigit = 1;
1849 if (i == nbmax) { /* too many digits for a block */
1850 #ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
1851 if (!pass) { /* treat as nongrouped */
1852 if (nonzero) {
1853 goto DO_NO_GROUP;
1855 goto DO_TRIM_LEADING_ZEROS;
1857 #endif
1858 if (nbmax > nblk1) {
1859 goto DONE_DO_UNGET; /* matching failure */
1861 goto DONE_GROUPING_DO_UNGET; /* nbmax == nblk1 */
1863 ++i;
1865 if (nonzero || (sc->cc != '0')) {
1866 if (b < buf + MAX_DIGITS) {
1867 *b++ = sc->cc;
1868 nonzero = 1;
1869 #ifdef __UCLIBC_HAS_FLOATS__
1870 } else {
1871 ++exp_adjust;
1872 #endif
1876 __scan_getc(sc);
1879 if (i) { /* we saw digits digits */
1880 if ((i == nblk2) || ((i < nblk2) && !pass)) {
1881 /* (possible) outer grp */
1882 p = sc->thousands_sep;
1883 if (*p == sc->cc) { /* first byte matches... */
1884 /* so check if grouping mb char */
1885 /* Since 1st matched, either match or fail now
1886 * unless EOF (yuk) */
1887 __scan_getc(sc);
1888 MBG_LOOP:
1889 if (!*++p) { /* is a grouping mb char */
1890 lastblock = i;
1891 ++pass;
1892 continue;
1894 if (*p == sc->cc) {
1895 __scan_getc(sc);
1896 goto MBG_LOOP;
1898 /* bad grouping mb char! */
1899 __scan_ungetc(sc);
1900 if ((sc->cc >= 0) || (p > sc->thousands_sep + 1)) {
1901 #ifdef __UCLIBC_HAS_FLOATS__
1902 /* We failed to match a thousep mb char, and
1903 * we've read too much to recover. But if
1904 * this is a floating point conversion and
1905 * the initial portion of the decpt mb char
1906 * matches, then we may still be able to
1907 * recover. */
1908 int k = p - sc->thousands_sep - 1;
1910 if ((psfs->conv_num > CONV_i) /* float conversion */
1911 && (!pass || (i == nblk1)) /* possible last */
1912 && !memcmp(sc->thousands_sep, sc->fake_decpt, k)
1913 /* and prefix matched, so could be decpt */
1915 __scan_getc(sc);
1916 p = sc->fake_decpt + k;
1917 do {
1918 if (!*++p) {
1919 strcpy((char*) b, (char*) sc->decpt);
1920 b += sc->decpt_len;
1921 goto GOT_DECPT;
1923 if (*p != sc->cc) {
1924 __scan_ungetc(sc);
1925 break; /* failed */
1927 __scan_getc(sc);
1928 } while (1);
1930 #endif /* __UCLIBC_HAS_FLOATS__ */
1931 goto DONE;
1933 /* was EOF and 1st, so recoverable. */
1936 if ((i == nblk1) || ((i < nblk1) && !pass)) {
1937 /* got an inner group */
1938 goto DONE_GROUPING_DO_UNGET;
1940 goto DONE_DO_UNGET; /* Matching failure. */
1941 } /* i != 0 */
1943 assert(pass);
1945 goto DONE_DO_UNGET;
1946 } while (1);
1948 assert(0); /* Should never get here. */
1951 #endif /***************** digit grouping **********************/
1953 /* Not grouping so first trim all but one leading 0. */
1954 #ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
1955 DO_TRIM_LEADING_ZEROS:
1956 #endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */
1957 if (sc->cc == '0') {
1958 seendigit = 1;
1959 *b++ = '0'; /* Store the first 0. */
1960 do { /* But ignore all subsequent 0s. */
1961 __scan_getc(sc);
1962 } while (sc->cc == '0');
1965 #ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
1966 DO_NO_GROUP:
1967 #endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */
1968 /* At this point, we're ready to start reading digits. */
1970 #define valid_digit(cc,base) (isxdigit(cc) && ((base == 16) || (cc - '0' < base)))
1972 while (valid_digit(sc->cc,base)) { /* Now for significant digits.*/
1973 if (b - buf < MAX_DIGITS) {
1974 nonzero = seendigit = 1; /* Set nonzero too 0s trimmed above. */
1975 *b++ = sc->cc;
1976 #ifdef __UCLIBC_HAS_FLOATS__
1977 } else {
1978 ++exp_adjust;
1979 #endif
1981 __scan_getc(sc);
1984 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1985 DONE_GROUPING_DO_UNGET:
1986 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
1987 if (psfs->conv_num <= CONV_i) { /* integer conversion */
1988 __scan_ungetc(sc);
1989 *b = 0; /* null-terminate */
1990 if (!seendigit) {
1991 goto DONE; /* No digits! */
1993 if (psfs->store) {
1994 if (*buf == '-') {
1995 usflag = 0;
1997 ++psfs->cnt;
1998 _store_inttype(psfs->cur_ptr, psfs->dataargtype,
1999 (uintmax_t) STRTOUIM((char *) buf, NULL, base, 1-usflag));
2001 return 0;
2004 #ifdef __UCLIBC_HAS_FLOATS__
2006 /* At this point, we have everything left of the decimal point or exponent. */
2007 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2008 NO_STARTING_DIGIT:
2009 #endif
2010 p = sc->fake_decpt;
2011 do {
2012 if (!*p) {
2013 strcpy((char *) b, (char *) sc->decpt);
2014 b += sc->decpt_len;
2015 break;
2017 if (*p != sc->cc) {
2018 if (p > sc->fake_decpt) {
2019 goto DONE_DO_UNGET; /* matching failure (read some of decpt) */
2021 goto DO_DIGIT_CHECK;
2023 ++p;
2024 __scan_getc(sc);
2025 } while (1);
2027 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2028 GOT_DECPT:
2029 #endif
2030 if (!nonzero) {
2031 if (sc->cc == '0') {
2032 assert(exp_adjust == 0);
2033 *b++ = '0';
2034 ++exp_adjust;
2035 seendigit = 1;
2036 do {
2037 --exp_adjust;
2038 __scan_getc(sc);
2039 } while (sc->cc == '0');
2043 while (valid_digit(sc->cc,base)) { /* Process fractional digits.*/
2044 if (b - buf < MAX_DIGITS) {
2045 seendigit = 1;
2046 *b++ = sc->cc;
2048 __scan_getc(sc);
2051 DO_DIGIT_CHECK:
2052 /* Hmm... no decimal point. */
2053 if (!seendigit) {
2054 static const unsigned char nan_inf_str[] = "an\0nfinity";
2056 if (base == 16) { /* We had a prefix, but no digits! */
2057 goto DONE_DO_UNGET; /* matching failure */
2060 /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/
2061 #undef TOLOWER
2062 #define TOLOWER(C) ((C)|0x20)
2064 switch (TOLOWER(sc->cc)) {
2065 case 'i':
2066 p = nan_inf_str + 3;
2067 break;
2068 case 'n':
2069 p = nan_inf_str;
2070 break;
2071 default:
2072 /* No digits and not inf or nan. */
2073 goto DONE_DO_UNGET;
2076 *b++ = sc->cc;
2078 do {
2079 __scan_getc(sc);
2080 if (TOLOWER(sc->cc) == *p) {
2081 *b++ = sc->cc;
2082 ++p;
2083 continue;
2085 if (!*p || (p == nan_inf_str + 5)) { /* match nan/infinity or inf */
2086 goto GOT_FLOAT;
2088 /* Unrecoverable. Even if on 1st char, we had no digits. */
2089 goto DONE_DO_UNGET;
2090 } while (1);
2093 /* If we get here, we had some digits. */
2095 if (
2096 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2097 ((base == 16) && (((sc->cc)|0x20) == 'p')) ||
2098 #endif
2099 (((sc->cc)|0x20) == 'e')
2100 ) { /* Process an exponent. */
2101 *b++ = sc->cc;
2103 __scan_getc(sc);
2104 if (sc->cc < 0) {
2105 goto DONE_DO_UNGET; /* matching failure.. no exponent digits */
2108 if ((sc->cc == '+') || (sc->cc == '-')) { /* Signed exponent? */
2109 *b++ = sc->cc;
2110 __scan_getc(sc);
2113 #define MAX_EXP_DIGITS 20
2114 assert(seendigit);
2115 seendigit = 0;
2116 nonzero = 0;
2118 if (sc->cc == '0') {
2119 seendigit = 1;
2120 *b++ = '0';
2121 do {
2122 __scan_getc(sc);
2123 } while (sc->cc == '0');
2126 while (__isdigit_char_or_EOF(sc->cc)) { /* Exponent digits (base 10).*/
2127 if (seendigit < MAX_EXP_DIGITS) {
2128 ++seendigit;
2129 *b++ = sc->cc;
2131 __scan_getc(sc);
2134 if (!seendigit) { /* No digits. Unrecoverable. */
2135 goto DONE_DO_UNGET;
2140 GOT_FLOAT:
2141 *b = 0;
2143 __fpmax_t x;
2144 char *e;
2145 x = __strtofpmax((char *) buf, &e, exp_adjust);
2146 assert(!*e);
2147 if (psfs->store) {
2148 if (psfs->dataargtype & PA_FLAG_LONG_LONG) {
2149 *((long double *)psfs->cur_ptr) = (long double) x;
2150 } else if (psfs->dataargtype & PA_FLAG_LONG) {
2151 *((double *)psfs->cur_ptr) = (double) x;
2152 } else {
2153 *((float *)psfs->cur_ptr) = (float) x;
2155 ++psfs->cnt;
2157 __scan_ungetc(sc);
2158 return 0;
2160 #endif /* __UCLIBC_HAS_FLOATS__ */
2162 DONE_DO_UNGET:
2163 __scan_ungetc(sc);
2164 DONE:
2165 return -2; /* Matching failure. */
2168 #endif
2169 /**********************************************************************/