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/>.
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.
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.
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.
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.
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.
57 #ifdef __UCLIBC_HAS_WCHAR__
58 #include <bits/uClibc_uwchar.h>
61 #endif /* __UCLIBC_HAS_WCHAR__ */
69 #ifdef __UCLIBC_HAS_THREADS__
70 #include <stdio_ext.h>
72 #endif /* __UCLIBC_HAS_THREADS__ */
74 #ifdef __UCLIBC_HAS_FLOATS__
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__)
86 unsigned char *bufread
; /* pointer to 1 past end of buffer */
87 unsigned char *bufpos
;
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)
102 #else /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
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)
112 #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
115 #error STRTOUIM conversion function is undefined!
118 /**********************************************************************/
120 /* The standards require EOF < 0. */
122 #define __isdigit_char_or_EOF(C) __isdigit_char((C))
124 #define __isdigit_char_or_EOF(C) __isdigit_int((C))
127 /**********************************************************************/
130 int fscanf(FILE * __restrict stream
, const char * __restrict format
, ...)
135 va_start(arg
, format
);
136 rv
= vfscanf(stream
, format
, arg
);
141 libc_hidden_def(fscanf
)
144 /**********************************************************************/
147 int scanf(const char * __restrict format
, ...)
152 va_start(arg
, format
);
153 rv
= vfscanf(stdin
, format
, arg
);
160 /**********************************************************************/
163 #ifdef __STDIO_HAS_VSSCANF
165 int sscanf(const char * __restrict str
, const char * __restrict format
, ...)
170 va_start(arg
, format
);
171 rv
= vsscanf(str
, format
, arg
);
176 libc_hidden_def(sscanf
)
178 #else /* __STDIO_HAS_VSSCANF */
179 #warning Skipping sscanf since no vsscanf!
180 #endif /* __STDIO_HAS_VSSCANF */
183 /**********************************************************************/
186 int vscanf(const char * __restrict format
, va_list arg
)
188 return vfscanf(stdin
, format
, arg
);
192 /**********************************************************************/
195 #ifdef __STDIO_BUFFERS
197 int vsscanf(const char *sp
, const char *fmt
, va_list ap
)
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;
207 #ifdef __STDIO_MBSTATE
208 __INIT_MBSTATE(&(f
.__state
));
211 #ifdef __UCLIBC_HAS_THREADS__
212 f
.__user_locking
= 1; /* Set user locking. */
213 STDIO_INIT_MUTEX(f
.__lock
);
217 /* Set these last since __bufgetc initialization depends on
218 * __user_locking and only gets set if user locking is on. */
220 f
.__bufpos
= (unsigned char *) ((void *) sp
);
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
)
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; */
245 #ifdef __STDIO_MBSTATE
246 #error __STDIO_MBSTATE is defined!
247 /* __INIT_MBSTATE(&(f.f.__state)); */
250 #ifdef __UCLIBC_HAS_THREADS__
251 f
.f
.__user_locking
= 1; /* Set user locking. */
252 STDIO_INIT_MUTEX(f
.f
.__lock
);
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
)
267 if ((f
= fmemopen((char *)sp
, strlen(sp
), "r")) != NULL
) {
268 rv
= vfscanf(f
, fmt
, ap
);
274 libc_hidden_def(vsscanf
)
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!
284 /**********************************************************************/
287 int fwscanf(FILE * __restrict stream
, const wchar_t * __restrict format
, ...)
292 va_start(arg
, format
);
293 rv
= vfwscanf(stream
, format
, arg
);
300 /**********************************************************************/
303 int wscanf(const wchar_t * __restrict format
, ...)
308 va_start(arg
, format
);
309 rv
= vfwscanf(stdin
, format
, arg
);
316 /**********************************************************************/
319 #ifdef __STDIO_BUFFERS
321 int swscanf(const wchar_t * __restrict str
, const wchar_t * __restrict format
,
327 va_start(arg
, format
);
328 rv
= vswscanf(str
, format
, arg
);
333 #else /* __STDIO_BUFFERS */
334 #warning Skipping swscanf since no buffering!
335 #endif /* __STDIO_BUFFERS */
338 /**********************************************************************/
341 int vwscanf(const wchar_t * __restrict format
, va_list arg
)
343 return vfwscanf(stdin
, format
, arg
);
347 /**********************************************************************/
350 #ifdef __STDIO_BUFFERS
352 int vswscanf(const wchar_t * __restrict str
, const wchar_t * __restrict format
,
358 f
.__bufpos
= (unsigned char *) str
;
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
);
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 */
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. */
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 }
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 }
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"
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'. */
462 /* #if LLONG_MAX != INTMAX_MAX */
463 /* #error fix QUAL_CHARS intmax_t entry 'j'! */
468 #error PDS already defined!
471 #error SS already defined!
474 #error IMS already defined!
477 #if PTRDIFF_MAX == INT_MAX
479 #elif PTRDIFF_MAX == LONG_MAX
481 #elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
484 #error fix QUAL_CHARS ptrdiff_t entry 't'!
487 #if SIZE_MAX == UINT_MAX
489 #elif SIZE_MAX == ULONG_MAX
491 #elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
494 #error fix QUAL_CHARS size_t entries 'z', 'Z'!
497 #if INTMAX_MAX == INT_MAX
499 #elif INTMAX_MAX == LONG_MAX
501 #elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
504 #error fix QUAL_CHARS intmax_t entry 'j'!
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!!! */ \
515 /**********************************************************************/
519 #error Unfortunately, we currently need wint_t to be able to store WEOF. Sorry.
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))
529 typedef unsigned char __uchar_t
;
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__ */
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__ */
559 #ifdef __UCLIBC_HAS_WCHAR__
560 char ungot_wflag
; /* vfwscanf */
561 char mb_fail
; /* vfscanf */
562 mbstate_t mbstate
; /* vfscanf */
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
;
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
;
580 #ifdef __UCLIBC_HAS_WCHAR__
582 #endif /* __UCLIBC_HAS_WCHAR__ */
583 const unsigned char *fake_decpt
;
584 #endif /* __UCLIBC_HAS_FLOATS__ */
589 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
591 #warning NL_ARGMAX > 10, and space is allocated on the stack for positional args.
593 void *pos_args
[NL_ARGMAX
];
594 int num_pos_args
; /* Must start at -1. */
596 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
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
[] = ".";
626 void attribute_hidden
__init_scan_cookie(register struct scan_cookie
*sc
,
632 sc
->app_ungot
= ((fp
->__modeflags
& __FLAG_UNGOT
) ? fp
->__ungot
[1] : 0);
633 #ifdef __UCLIBC_HAS_WCHAR__
634 sc
->ungot_wflag
= 0; /* vfwscanf */
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
;
655 #endif /* __UCLIBC_HAS_LOCALE__ */
656 #ifdef __UCLIBC_HAS_WCHAR__
657 #ifdef __UCLIBC_HAS_LOCALE__
658 sc
->decpt_wc
= __UCLIBC_CURLOCALE
->decimal_point_wc
;
662 #endif /* __UCLIBC_HAS_WCHAR__ */
663 #endif /* __UCLIBC_HAS_FLOATS__ */
667 int attribute_hidden
__scan_getc(register struct scan_cookie
*sc
)
671 #ifdef __UCLIBC_HAS_WCHAR__
672 assert(!sc
->mb_fail
);
673 #endif /* __UCLIBC_HAS_WCHAR__ */
677 if (--sc
->width
< 0) {
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
)) {
687 __FILE_vsscanf
*fv
= (__FILE_vsscanf
*)(sc
->fp
);
688 if (fv
->bufpos
< fv
->bufread
) {
692 sc
->fp
->__modeflags
|= __FLAG_EOF
;
700 if ((c
= GETC(sc
)) == EOF
) {
707 assert(sc
->ungot_flag
== 1);
712 return sc
->cc
= sc
->ungot_char
;
715 void attribute_hidden
__scan_ungetc(register struct scan_cookie
*sc
)
718 if (sc
->ungot_flag
== 2) { /* last was EOF */
720 sc
->cc
= sc
->ungot_char
;
721 } else if (sc
->ungot_flag
== 0) {
730 /**********************************************************************/
731 #ifdef L___psfs_parse_spec
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
;
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. */
759 /* parse the positional arg (or width) value */
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! */
771 psfs
->num_pos_args
= -2;
774 ++psfs
->fmt
; /* Advance past '$'. */
775 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
777 #if defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0))
779 #endif /* defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0)) */
784 if (*p
== *psfs
->fmt
) {
792 if (psfs
->flags
& FLAG_SURPRESS
) { /* Suppress assignment. */
796 #else /* SPEC_FLAGS */
797 if (*psfs
->fmt
== '*') { /* Suppress assignment. */
802 #endif /* SPEC_FLAGS */
805 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
807 /* Must be a non-positional arg */
808 if (psfs
->num_pos_args
>= 0) { /* Already saw a pos arg! */
811 psfs
->num_pos_args
= -2;
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. */
817 psfs
->cur_pos_arg
= i
;
819 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
822 for (i
= 0 ; __isdigit_char(*psfs
->fmt
) ; ) {
823 if (i
<= ((INT_MAX
- 9)/10)) {
824 i
= (i
* 10) + (*psfs
->fmt
++ - '0');
829 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
831 #endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
834 if (*psfs
->fmt
== *p
) {
839 if ((p
- qual_chars
< 2) && (*psfs
->fmt
== *p
)) {
840 p
+= ((sizeof(qual_chars
)-2) / 2);
843 psfs
->dataargtype
= ((int)(p
[(sizeof(qual_chars
)-2) / 2])) << 8;
847 if (*psfs
->fmt
== *p
) {
848 int p_m_spec_chars
= p
- spec_chars
;
851 (psfs
->fmt
[1] == '[' || psfs
->fmt
[1] == 'c' ||
852 /* Assumes ascii for 's' and 'S' test. */
853 (psfs
->fmt
[1] | 0x20) == 's'))
856 psfs
->flags
|= FLAG_MALLOC
;
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
)]
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
;
891 /**********************************************************************/
892 #if defined(L_vfscanf) || defined(L_vfwscanf)
894 #ifdef __UCLIBC_HAS_WCHAR__
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
)
908 if (--sc
->width
< 0) {
913 width
= sc
->width
; /* Preserve width. */
914 sc
->width
= INT_MAX
; /* MB_CUR_MAX can invoke a function. */
916 assert(!sc
->mb_fail
);
919 while (__scan_getc(sc
) >= 0) {
922 r
= mbrtowc(wc
, b
, 1, &sc
->mbstate
);
923 if (((ssize_t
) r
) >= 0) { /* Successful completion of a wc. */
926 } else if (r
== ((size_t) -2)) {
927 /* Potentially valid but incomplete. */
933 if (r
== ((size_t)(-3))) { /* EOF or ERROR on first read */
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. */
946 sc
->width
= width
; /* Restore width. */
948 return (int)((ssize_t
) r
);
951 #endif /* L_vfscanf */
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
)
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);
967 sc
->fp
->__modeflags
|= __FLAG_EOF
;
970 } else if ((wc
= fgetwc_unlocked(sc
->fp
)) == WEOF
) {
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
) {
982 #endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
983 #ifdef __UCLIBC_HAS_FLOATS__
984 if (wc
== sc
->decpt_wc
) {
987 #endif /* __UCLIBC_HAS_FLOATS__ */
988 sc
->wc
= sc
->ungot_char
= wc
;
993 static int scan_getwc(register struct scan_cookie
*sc
)
999 if (--sc
->width
< 0) {
1000 sc
->ungot_flag
|= 2;
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);
1010 sc
->ungot_flag
|= 2;
1013 } else if ((wc
= fgetwc_unlocked(sc
->fp
)) == WEOF
) {
1014 sc
->ungot_flag
|= 2;
1017 sc
->ungot_wflag
= 1;
1018 sc
->ungot_char
= wc
;
1019 sc
->ungot_wchar_width
= sc
->fp
->__ungot_width
[0];
1021 assert(sc
->ungot_flag
== 1);
1026 sc
->wc
= sc
->ungot_char
;
1032 #endif /* L_vfwscanf */
1033 #endif /* __UCLIBC_HAS_WCHAR__ */
1035 static __inline
void kill_scan_cookie(register struct scan_cookie
*sc
)
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
);
1045 ungetc(sc
->ungot_char
, sc
->fp
);
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. */
1051 sc
->fp
->__ungot
[1] = 0;
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. */
1066 sc
->fp
->__ungot
[1] = 0;
1068 sc
->fp
->__ungot_width
[1] = sc
->ungot_wchar_width
;
1075 int VFSCANF (FILE *__restrict fp
, const Wchar
*__restrict format
, va_list arg
)
1083 #endif /* L_vfwscanf */
1085 #if defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) || !defined(L_vfscanf)
1089 struct scan_cookie sc
;
1093 #define MAX_DIGITS 65 /* Allow one leading 0. */
1094 unsigned char buf
[MAX_DIGITS
+2];
1096 unsigned char scanset
[UCHAR_MAX
+ 1];
1097 unsigned char invert
= 0; /* Careful! Meaning changes. */
1098 #endif /* L_vfscanf */
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. */
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];
1134 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
1136 sc
.thousands_sep
= (const unsigned char *) ",";
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__ */
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 */) {
1165 psfs
.cur_ptr
= NULL
; /* Debugging aid. */
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
1175 * ((((__uwchar_t)wc) < UCHAR_MAX) && isspace(wc))
1176 * because wc might not be in the allowed domain. */
1177 if (ISSPACE(*fmt
)) {
1180 } while (ISSPACE(*fmt
));
1182 psfs
.conv_num
= CONV_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
;
1197 #else /* L_vfscanf */
1199 const __uwchar_t
*wf
= fmt
;
1202 while (*wf
&& __isascii(*wf
) && (b
< buf
+ sizeof(buf
) - 1)) {
1206 if (b
== buf
) { /* Bad conversion specifier! */
1210 #endif /* L_vfscanf */
1211 if ((i
= __psfs_parse_spec(&psfs
)) < 0) { /* Bad conversion specifier! */
1217 #if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
1218 if (psfs
.num_pos_args
== -2) {
1219 psfs
.cur_ptr
= va_arg(arg
, void *);
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) */
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
1238 while ((__scan_getc(&sc
) >= 0)
1241 #else /* L_vfscanf */
1243 #endif /* L_vfscanf */
1246 if (psfs
.conv_num
== CONV_whitespace
) {
1251 sc
.width
= psfs
.max_width
; /* Now limit the max width. */
1253 if (sc
.width
== 0) { /* 0 width is forbidden. */
1258 if (psfs
.conv_num
== CONV_percent
) {
1262 if (psfs
.conv_num
== CONV_n
) {
1263 /* zero_conversions = 0; */
1265 _store_inttype(psfs
.cur_ptr
, psfs
.dataargtype
,
1266 (uintmax_t) sc
.nread
);
1271 if (psfs
.conv_num
<= CONV_A
) { /* pointer, integer, or float spec */
1272 int r
= __psfs_do_numeric(&psfs
, &sc
);
1274 if (sc
.ungot_wflag
== 1) { /* fix up '?', '.', and ',' hacks */
1275 sc
.cc
= sc
.ungot_char
= sc
.ungot_wchar
;
1278 if (r
!= -1) { /* Either success or a matching failure. */
1279 zero_conversions
= 0;
1287 /* Do string conversions here since they are not common code. */
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 */
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 */
1307 if (psfs
.flags
& FLAG_MALLOC
) {
1315 if (psfs
.conv_num
== CONV_c
) {
1316 if (sc
.width
== INT_MAX
) {
1320 if (psfs
.flags
& FLAG_MALLOC
)
1321 b
= malloc(sc
.width
);
1324 while (__scan_getc(&sc
) >= 0) {
1325 zero_conversions
= 0;
1330 if (sc
.width
> 0) { /* Failed to read all required. */
1333 if (psfs
.flags
& FLAG_MALLOC
)
1335 psfs
.cnt
+= psfs
.store
;
1339 if (psfs
.conv_num
== CONV_s
) {
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;
1346 /* Pick a size that won't trigger a lot of
1347 * mallocs early on ... */
1349 b
= realloc(b
, len
+ 1);
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__ */
1366 if (*++fmt
== '^') {
1370 memset(scanset
, invert
, sizeof(scanset
));
1374 scanset
[(int)(']')] = invert
;
1378 while (*fmt
!= ']') {
1379 if (!*fmt
) { /* No closing ']'. */
1382 if ((*fmt
== '-') && (fmt
[1] != ']')
1383 && (fmt
[-1] < fmt
[1]) /* sorted? */
1387 /* Note: scanset[i] should already have been done
1388 * in the previous iteration. */
1390 scanset
[++i
] = invert
;
1392 /* Safe to fall through, and a bit smaller. */
1395 scanset
[(int) *fmt
] = invert
;
1399 #ifdef __UCLIBC_HAS_WCHAR__
1400 if (psfs
.conv_num
== CONV_LEFTBRACKET
) {
1401 goto DO_LEFTBRACKET
;
1403 #endif /* __UCLIBC_HAS_WCHAR__ */
1407 while (__scan_getc(&sc
) >= 0) {
1408 zero_conversions
= 0;
1409 if (!scanset
[sc
.cc
]) {
1413 /* Pick a size that won't trigger a lot of
1414 * mallocs early on ... */
1416 b
= realloc(b
, len
+ 1);
1423 /* Common tail for processing of %s and %[. */
1426 if (fail
) { /* nothing stored! */
1429 if (psfs
.flags
& FLAG_MALLOC
)
1432 *b
= 0; /* Nul-terminate string. */
1433 psfs
.cnt
+= psfs
.store
;
1437 #ifdef __UCLIBC_HAS_WCHAR__
1438 DO_LEFTBRACKET
: /* Need to do common wide init. */
1439 if (psfs
.conv_num
>= CONV_C
) {
1443 sc
.mbstate
.__mask
= 0;
1445 wb
= (psfs
.store
? ((wchar_t *) psfs
.cur_ptr
) : wbuf
);
1448 if (psfs
.conv_num
== CONV_C
) {
1449 if (sc
.width
== INT_MAX
) {
1453 while (scan_getwc(&sc
) >= 0) {
1454 zero_conversions
= 0;
1455 assert(sc
.width
>= 0);
1461 if (sc
.width
> 0) { /* Failed to read all required. */
1464 psfs
.cnt
+= psfs
.store
;
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
)) {
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
]) {
1489 } else if (invert
) {
1497 /* Common tail for processing of %ls and %l[. */
1500 if (fail
|| sc
.mb_fail
) { /* Nothing stored or mb error. */
1503 *wb
= 0; /* Nul-terminate string. */
1504 psfs
.cnt
+= psfs
.store
;
1509 #endif /* __UCLIBC_HAS_WCHAR__ */
1510 #else /* L_vfscanf */
1512 if (psfs
.conv_num
>= CONV_C
) {
1515 if (psfs
.conv_num
>= CONV_c
) {
1516 mbstate
.__mask
= 0; /* Initialize the mbstate. */
1518 b
= (unsigned char *) psfs
.cur_ptr
;
1522 wb
= (wchar_t *) psfs
.cur_ptr
;
1528 if ((psfs
.conv_num
== CONV_C
) || (psfs
.conv_num
== CONV_c
)) {
1529 if (sc
.width
== INT_MAX
) {
1533 while (scan_getwc(&sc
) >= 0) {
1534 zero_conversions
= 0;
1535 if (psfs
.conv_num
== CONV_C
) {
1539 i
= wcrtomb((char*) b
, sc
.wc
, &mbstate
);
1540 if (i
< 0) { /* Conversion failure. */
1549 if (sc
.width
> 0) { /* Failed to read all required. */
1552 psfs
.cnt
+= psfs
.store
;
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
)) {
1563 if (psfs
.conv_num
== CONV_S
) {
1567 i
= wcrtomb((char*) b
, sc
.wc
, &mbstate
);
1568 if (i
< 0) { /* Conversion failure. */
1580 unsigned char invert
= 0;
1582 assert((psfs
.conv_num
== CONV_LEFTBRACKET
)
1583 || (psfs
.conv_num
== CONV_leftbracket
));
1585 if (*++fmt
== '^') {
1589 sss
= (const wchar_t *) fmt
;
1593 while (*fmt
!= ']') {
1594 if (!*fmt
) { /* No closing ']'. */
1597 if ((*fmt
== '-') && (fmt
[1] != ']')
1598 && (fmt
[-1] < fmt
[1]) /* sorted? */
1604 /* Ok... a valid scanset spec. */
1606 while (scan_getwc(&sc
) >= 0) {
1607 zero_conversions
= 0;
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. */
1614 if ((++ssp
< (const wchar_t *) fmt
)
1615 && (ssp
[-2] < *ssp
) /* sorted? */
1617 if ((sc
.wc
>= ssp
[-2])
1618 && (sc
.wc
<= *ssp
)) {
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. */
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 */
1637 if (psfs
.conv_num
== CONV_LEFTBRACKET
) {
1641 i
= wcrtomb((char*) b
, sc
.wc
, &mbstate
);
1642 if (i
< 0) { /* Conversion failure. */
1652 /* Common tail for processing of %s and %[. */
1655 if (fail
) { /* nothing stored! */
1658 *wb
= 0; /* Nul-terminate string. */
1660 psfs
.cnt
+= psfs
.store
;
1664 #endif /* L_vfscanf */
1668 } /* conversion specification */
1671 if (__scan_getc(&sc
) != *fmt
) {
1674 #endif /* L_vfwscanf */
1681 if (__FERROR_UNLOCKED(fp
)) {
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
);
1699 libc_hidden_def(VFSCANF
)
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
)
1710 const unsigned char *p
;
1712 #ifdef __UCLIBC_HAS_FLOATS__
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 */
1727 base
= spec_base
[psfs
->conv_num
- CONV_p
];
1728 usflag
= (psfs
->conv_num
<= CONV_u
); /* (1)0 if (un)signed */
1732 if (psfs
->conv_num
== CONV_p
) { /* Pointer */
1735 if ((__scan_getc(sc
) < 0) || (*p
!= sc
->cc
)) {
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 */
1744 if (!*++p
) { /* Matched (nil), so no unget necessary. */
1747 _store_inttype(psfs
->cur_ptr
, psfs
->dataargtype
,
1758 return -1; /* Input failure (nothing read yet). */
1761 if ((sc
->cc
== '+') || (sc
->cc
== '-')) { /* Handle leading sign.*/
1766 if ((base
& 0xef) == 0) { /* 0xef is ~16, so 16 or 0. */
1767 if (sc
->cc
== '0') { /* Possibly set base and handle prefix. */
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
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. */
1783 #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
1784 } else { /* oops... back up */
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 */
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
;
1812 if (nbmax
< nblk2
) {
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
;
1834 if (sc
->cc
== '0') {
1836 *b
++ = '0'; /* Store the first 0. */
1838 do { /* But ignore all subsequent 0s. */
1840 } while (sc
->cc
== '0');
1847 while (__isdigit_char_or_EOF(sc
->cc
)) {
1849 if (i
== nbmax
) { /* too many digits for a block */
1850 #ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
1851 if (!pass
) { /* treat as nongrouped */
1855 goto DO_TRIM_LEADING_ZEROS
;
1858 if (nbmax
> nblk1
) {
1859 goto DONE_DO_UNGET
; /* matching failure */
1861 goto DONE_GROUPING_DO_UNGET
; /* nbmax == nblk1 */
1865 if (nonzero
|| (sc
->cc
!= '0')) {
1866 if (b
< buf
+ MAX_DIGITS
) {
1869 #ifdef __UCLIBC_HAS_FLOATS__
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) */
1889 if (!*++p
) { /* is a grouping mb char */
1898 /* bad grouping mb char! */
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
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 */
1916 p
= sc
->fake_decpt
+ k
;
1919 strcpy((char*) b
, (char*) sc
->decpt
);
1930 #endif /* __UCLIBC_HAS_FLOATS__ */
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. */
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') {
1959 *b
++ = '0'; /* Store the first 0. */
1960 do { /* But ignore all subsequent 0s. */
1962 } while (sc
->cc
== '0');
1965 #ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
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. */
1976 #ifdef __UCLIBC_HAS_FLOATS__
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 */
1989 *b
= 0; /* null-terminate */
1991 goto DONE
; /* No digits! */
1998 _store_inttype(psfs
->cur_ptr
, psfs
->dataargtype
,
1999 (uintmax_t) STRTOUIM((char *) buf
, NULL
, base
, 1-usflag
));
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__
2013 strcpy((char *) b
, (char *) sc
->decpt
);
2018 if (p
> sc
->fake_decpt
) {
2019 goto DONE_DO_UNGET
; /* matching failure (read some of decpt) */
2021 goto DO_DIGIT_CHECK
;
2027 #ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
2031 if (sc
->cc
== '0') {
2032 assert(exp_adjust
== 0);
2039 } while (sc
->cc
== '0');
2043 while (valid_digit(sc
->cc
,base
)) { /* Process fractional digits.*/
2044 if (b
- buf
< MAX_DIGITS
) {
2052 /* Hmm... no decimal point. */
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)*/
2062 #define TOLOWER(C) ((C)|0x20)
2064 switch (TOLOWER(sc
->cc
)) {
2066 p
= nan_inf_str
+ 3;
2072 /* No digits and not inf or nan. */
2080 if (TOLOWER(sc
->cc
) == *p
) {
2085 if (!*p
|| (p
== nan_inf_str
+ 5)) { /* match nan/infinity or inf */
2088 /* Unrecoverable. Even if on 1st char, we had no digits. */
2093 /* If we get here, we had some digits. */
2096 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
2097 ((base
== 16) && (((sc
->cc
)|0x20) == 'p')) ||
2099 (((sc
->cc
)|0x20) == 'e')
2100 ) { /* Process an exponent. */
2105 goto DONE_DO_UNGET
; /* matching failure.. no exponent digits */
2108 if ((sc
->cc
== '+') || (sc
->cc
== '-')) { /* Signed exponent? */
2113 #define MAX_EXP_DIGITS 20
2118 if (sc
->cc
== '0') {
2123 } while (sc
->cc
== '0');
2126 while (__isdigit_char_or_EOF(sc
->cc
)) { /* Exponent digits (base 10).*/
2127 if (seendigit
< MAX_EXP_DIGITS
) {
2134 if (!seendigit
) { /* No digits. Unrecoverable. */
2145 x
= __strtofpmax((char *) buf
, &e
, exp_adjust
);
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
;
2153 *((float *)psfs
->cur_ptr
) = (float) x
;
2160 #endif /* __UCLIBC_HAS_FLOATS__ */
2165 return -2; /* Matching failure. */
2169 /**********************************************************************/