]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Stdio/vfscanf.c
2 Implementation of scanf internals for <stdio.h>.
4 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License that accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 Copyright (c) 1990, 1993
14 The Regents of the University of California. All rights reserved.
16 This code is derived from software contributed to Berkeley by
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions
22 - Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24 - Redistributions in binary form must reproduce the above copyright
25 notice, this list of conditions and the following disclaimer in the
26 documentation and/or other materials provided with the distribution.
27 - Neither the name of the University nor the names of its contributors
28 may be used to endorse or promote products derived from this software
29 without specific prior written permission.
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
35 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 POSSIBILITY OF SUCH DAMAGE.
43 NetBSD: vfscanf.c,v 1.37.4.1 2007/05/07 19:49:08 pavel Exp
44 FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.41 2007/01/09 00:28:07 imp Exp
45 vfscanf.c 8.1 (Berkeley) 6/4/93
47 //#include <Uefi.h> // REMOVE, For DEBUG only
48 //#include <Library/UefiLib.h> // REMOVE, For DEBUG only
50 #include <LibConfig.h>
52 #include "namespace.h"
61 #include <sys/types.h>
65 #include "reentrant.h"
68 #ifndef NO_FLOATING_POINT
73 * Provide an external name for vfscanf. Note, we don't use the normal
74 * namespace.h method; stdio routines explicitly use the internal name
78 __weak_alias(vfscanf
,__svfscanf
)
81 #define BUF 513 /* Maximum length of numeric string. */
84 * Flags used during conversion.
86 #define LONG 0x0001 /* l: long or double */
87 #define LONGDBL 0x0002 /* L: long double */
88 #define SHORT 0x0004 /* h: short */
89 #define SUPPRESS 0x0008 /* *: suppress assignment */
90 #define POINTER 0x0010 /* p: void * (as hex) */
91 #define NOSKIP 0x0020 /* [ or c: do not skip blanks */
92 #define LONGLONG 0x0400 /* ll: long long (+ deprecated q: quad) */
93 #define INTMAXT 0x0800 /* j: intmax_t */
94 #define PTRDIFFT 0x1000 /* t: ptrdiff_t */
95 #define SIZET 0x2000 /* z: size_t */
96 #define SHORTSHORT 0x4000 /* hh: char */
97 #define UNSIGNED 0x8000 /* %[oupxX] conversions */
100 * The following are used in integral conversions only:
101 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
103 #define SIGNOK 0x00040 /* +/- is (still) legal */
104 #define NDIGITS 0x00080 /* no digits detected */
105 #define PFXOK 0x00100 /* 0x prefix is (still) legal */
106 #define NZDIGITS 0x00200 /* no zero digits detected */
107 #define HAVESIGN 0x10000 /* sign detected */
112 #define CT_CHAR 0 /* %c conversion */
113 #define CT_CCL 1 /* %[...] conversion */
114 #define CT_STRING 2 /* %s conversion */
115 #define CT_INT 3 /* %[dioupxX] conversion */
116 #define CT_FLOAT 4 /* %[efgEFG] conversion */
118 static const u_char
*__sccl(char *, const u_char
*);
119 #ifndef NO_FLOATING_POINT
120 static int parsefloat(FILE *, char *, char *);
123 int __scanfdebug
= 0;
125 #define __collate_load_error /*CONSTCOND*/0
127 __collate_range_cmp(int c1
, int c2
)
129 static char s1
[2], s2
[2];
133 return strcoll(s1
, s2
);
138 * __svfscanf - MT-safe version
141 __svfscanf(FILE *fp
, char const *fmt0
, va_list ap
)
146 ret
= __svfscanf_unlocked(fp
, fmt0
, ap
);
152 * __svfscanf_unlocked - non-MT-safe version of __svfscanf
155 __svfscanf_unlocked(FILE *fp
, const char *fmt0
, va_list ap
)
157 const u_char
*fmt
= (const u_char
*)fmt0
;
158 int c
; /* character from format, or conversion */
159 size_t width
; /* field width, or 0 */
160 char *p
; /* points into all kinds of strings */
161 size_t n
; /* handy size_t */
162 int flags
; /* flags as defined above */
163 char *p0
; /* saves original value of p when necessary */
164 int nassigned
; /* number of fields assigned */
165 int nconversions
; /* number of conversions */
166 int nread
; /* number of characters consumed from fp */
167 int base
; /* base argument to conversion function */
168 char ccltab
[256]; /* character class table for %[...] */
169 char buf
[BUF
]; /* buffer for numeric and mb conversions */
170 wchar_t *wcp
; /* handy wide character pointer */
171 size_t nconv
; /* length of multibyte sequence converted */
172 static const mbstate_t initial
= { 0 };
175 /* `basefix' is used to avoid `if' tests in the integer scanner */
176 static const short basefix
[17] =
177 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
179 _DIAGASSERT(fp
!= NULL
);
180 _DIAGASSERT(fmt0
!= NULL
);
182 _SET_ORIENTATION(fp
, -1);
184 //Print(L"%a( %d, \"%a\", ...)\n", __func__, fp->_file, fmt0);
190 c
= (unsigned char)*fmt
++;
194 while ((fp
->_r
> 0 || __srefill(fp
) == 0) &&
196 nread
++, fp
->_r
--, fp
->_p
++;
199 //Print(L"%a: %d\n", __func__, __LINE__);
205 * switch on the format. continue if done;
206 * break once format type is derived.
209 //Print(L"%a: %d\n", __func__, __LINE__);
213 //Print(L"%a: %d\n", __func__, __LINE__);
214 if (fp
->_r
<= 0 && __srefill(fp
))
236 flags
|= LONGLONG
; /* not quite */
255 case '0': case '1': case '2': case '3': case '4':
256 case '5': case '6': case '7': case '8': case '9':
257 width
= width
* 10 + c
- '0';
287 flags
|= PFXOK
; /* enable 0x prefixing */
293 #ifndef NO_FLOATING_POINT
294 case 'A': case 'E': case 'F': case 'G':
295 case 'a': case 'e': case 'f': case 'g':
308 fmt
= __sccl(ccltab
, fmt
);
321 case 'p': /* pointer format is like hex */
322 flags
|= POINTER
| PFXOK
;
323 c
= CT_INT
; /* assumes sizeof(uintmax_t) */
324 flags
|= UNSIGNED
; /* >= sizeof(uintptr_t) */
330 if (flags
& SUPPRESS
) /* ??? */
332 if (flags
& SHORTSHORT
)
333 *va_arg(ap
, char *) = (char)nread
;
334 else if (flags
& SHORT
)
335 *va_arg(ap
, short *) = (short)nread
;
336 else if (flags
& LONG
)
337 *va_arg(ap
, long *) = nread
;
338 else if (flags
& LONGLONG
)
339 *va_arg(ap
, long long *) = nread
;
340 else if (flags
& INTMAXT
)
341 *va_arg(ap
, intmax_t *) = nread
;
342 else if (flags
& SIZET
)
343 *va_arg(ap
, size_t *) = nread
;
344 else if (flags
& PTRDIFFT
)
345 *va_arg(ap
, ptrdiff_t *) = nread
;
347 *va_arg(ap
, int *) = nread
;
354 * Disgusting backwards compatibility hack. XXX
356 case '\0': /* compat */
359 //Print(L"%a: %d\n", __func__, __LINE__);
362 * We have a conversion that requires input.
364 if (fp
->_r
<= 0 && __srefill(fp
))
366 //Print(L"%a: %d\n", __func__, __LINE__);
371 * Consume leading white space, except for formats
372 * that suppress this.
374 if ((flags
& NOSKIP
) == 0) {
375 while (isspace(*fp
->_p
)) {
379 else if (__srefill(fp
))
381 //Print(L"%a: %d\n", __func__, __LINE__);
386 * Note that there is at least one character in
387 * the buffer, so conversions that do not set NOSKIP
388 * ca no longer result in an input failure.
395 //Print(L"%a: %d\n", __func__, __LINE__);
399 /* scan arbitrary characters (sets NOSKIP) */
403 if ((flags
& SUPPRESS
) == 0)
404 wcp
= va_arg(ap
, wchar_t *);
409 if (n
== MB_CUR_MAX
) {
410 fp
->_flags
|= __SERR
;
417 nconv
= mbrtowc(wcp
, buf
, n
, &mbs
);
418 if (nconv
== (size_t)-1) {
419 fp
->_flags
|= __SERR
;
422 if (nconv
== 0 && !(flags
& SUPPRESS
))
424 if (nconv
!= (size_t)-2) {
427 if (!(flags
& SUPPRESS
))
431 if (fp
->_r
<= 0 && __srefill(fp
)) {
433 fp
->_flags
|= __SERR
;
439 if (!(flags
& SUPPRESS
))
441 } else if (flags
& SUPPRESS
) {
444 if ((n
= fp
->_r
) < width
) {
455 fp
->_r
-= (int)width
;
462 size_t r
= fread(va_arg(ap
, char *), 1,
474 /* scan a (nonempty) character class (sets NOSKIP) */
476 width
= (size_t)~0; /* `infinity' */
477 /* take only those things in the class */
482 if ((flags
& SUPPRESS
) == 0)
483 wcp
= va_arg(ap
, wchar_t *);
489 if (n
== MB_CUR_MAX
) {
490 fp
->_flags
|= __SERR
;
497 nconv
= mbrtowc(wcp
, buf
, n
, &mbs
);
498 if (nconv
== (size_t)-1) {
499 fp
->_flags
|= __SERR
;
504 if (nconv
!= (size_t)-2) {
505 if (wctob(*wcp
) != EOF
&&
506 !ccltab
[wctob(*wcp
)]) {
516 if (!(flags
& SUPPRESS
))
521 if (fp
->_r
<= 0 && __srefill(fp
)) {
523 fp
->_flags
|= __SERR
;
530 fp
->_flags
|= __SERR
;
536 if (!(flags
& SUPPRESS
)) {
540 } else if (flags
& SUPPRESS
) {
542 while (ccltab
[*fp
->_p
]) {
543 n
++, fp
->_r
--, fp
->_p
++;
546 if (fp
->_r
<= 0 && __srefill(fp
)) {
555 p0
= p
= va_arg(ap
, char *);
556 while (ccltab
[*fp
->_p
]) {
561 if (fp
->_r
<= 0 && __srefill(fp
)) {
578 /* like CCL, but zero-length string OK, & no NOSKIP */
584 if ((flags
& SUPPRESS
) == 0)
585 wcp
= va_arg(ap
, wchar_t *);
589 while (!isspace(*fp
->_p
) && width
!= 0) {
590 if (n
== MB_CUR_MAX
) {
591 fp
->_flags
|= __SERR
;
598 nconv
= mbrtowc(wcp
, buf
, n
, &mbs
);
599 if (nconv
== (size_t)-1) {
600 fp
->_flags
|= __SERR
;
605 if (nconv
!= (size_t)-2) {
606 if (iswspace(*wcp
)) {
616 if (!(flags
& SUPPRESS
))
620 if (fp
->_r
<= 0 && __srefill(fp
)) {
622 fp
->_flags
|= __SERR
;
628 if (!(flags
& SUPPRESS
)) {
632 } else if (flags
& SUPPRESS
) {
634 while (!isspace(*fp
->_p
)) {
635 n
++, fp
->_r
--, fp
->_p
++;
638 if (fp
->_r
<= 0 && __srefill(fp
))
643 p0
= p
= va_arg(ap
, char *);
644 while (!isspace(*fp
->_p
)) {
649 if (fp
->_r
<= 0 && __srefill(fp
))
653 nread
+= (int)(p
- p0
);
660 //Print(L"%a: %d\n", __func__, __LINE__);
661 /* scan an integer as if by the conversion function */
663 if (width
== 0 || width
> sizeof(buf
) - 1)
664 width
= sizeof(buf
) - 1;
666 /* size_t is unsigned, hence this optimisation */
667 if (--width
> sizeof(buf
) - 2)
668 width
= sizeof(buf
) - 2;
671 flags
|= SIGNOK
| NDIGITS
| NZDIGITS
;
672 for (p
= buf
; width
; width
--) {
675 * Switch on the character; `goto ok'
676 * if we accept it as a part of number.
681 * The digit 0 is always legal, but is
682 * special. For %i conversions, if no
683 * digits (zero or nonzero) have been
684 * scanned (only signs), we will have
685 * base==0. In that case, we should set
686 * it to 8 and enable 0x prefixing.
687 * Also, if we have not scanned zero digits
688 * before this, do not turn off prefixing
689 * (someone else will turn it off if we
690 * have scanned any nonzero digits).
697 if (flags
& NZDIGITS
)
698 flags
&= ~(SIGNOK
|NZDIGITS
|NDIGITS
);
700 flags
&= ~(SIGNOK
|PFXOK
|NDIGITS
);
703 /* 1 through 7 always legal */
704 case '1': case '2': case '3':
705 case '4': case '5': case '6': case '7':
706 base
= basefix
[base
];
707 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
710 /* digits 8 and 9 ok iff decimal or hex */
712 base
= basefix
[base
];
714 break; /* not legal here */
715 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
718 /* letters ok iff hex */
719 case 'A': case 'B': case 'C':
720 case 'D': case 'E': case 'F':
721 case 'a': case 'b': case 'c':
722 case 'd': case 'e': case 'f':
723 /* no need to fix base here */
725 break; /* not legal here */
726 flags
&= ~(SIGNOK
| PFXOK
| NDIGITS
);
729 /* sign ok only as first character */
731 if (flags
& SIGNOK
) {
739 * x ok iff flag still set & 2nd char (or
740 * 3rd char if we have a sign).
743 if (flags
& PFXOK
&& p
==
744 buf
+ 1 + !!(flags
& HAVESIGN
)) {
745 base
= 16; /* if %i */
753 * If we got here, c is not a legal character
754 * for a number. Stop accumulating digits.
759 * c is legal: store it and look at the next.
764 else if (__srefill(fp
))
768 * If we had only a sign, it is no good; push
769 * back the sign. If the number ends in `x',
770 * it was [sign] '0' 'x', so push back the x
771 * and treat it as [sign] '0'.
773 if (flags
& NDIGITS
) {
775 (void)ungetc(*(u_char
*)--p
, fp
);
778 c
= ((u_char
*)p
)[-1];
779 if (c
== 'x' || c
== 'X') {
783 if ((flags
& SUPPRESS
) == 0) {
785 // Use a union to get around the truncation warnings.
800 if ((flags
& UNSIGNED
) == 0)
801 res
.imax
= strtoimax(buf
, (char **)NULL
, base
);
803 res
.umax
= strtoumax(buf
, (char **)NULL
, base
);
805 *va_arg(ap
, void **) = res
.vp
;
806 //(void *)((uintptr_t)res);
807 else if (flags
& SHORTSHORT
)
808 *va_arg(ap
, char *) = res
.ch
;
809 else if (flags
& SHORT
)
810 *va_arg(ap
, short *) = res
.hw
;
811 else if (flags
& LONG
)
812 *va_arg(ap
, long *) = res
.lo
;
813 else if (flags
& LONGLONG
)
814 *va_arg(ap
, long long *) = res
.ll
;
815 else if (flags
& INTMAXT
)
816 *va_arg(ap
, intmax_t *) = res
.imax
;
817 else if (flags
& PTRDIFFT
)
818 *va_arg(ap
, ptrdiff_t *) = res
.pdt
;
820 else if (flags
& SIZET
)
821 *va_arg(ap
, size_t *) = res
.sz
;
823 *va_arg(ap
, int *) = res
.in
;
826 nread
+= (int)(p
- buf
);
828 //Print(L"%a: %d\n", __func__, __LINE__);
831 #ifndef NO_FLOATING_POINT
833 /* scan a floating point number as if by strtod */
834 if (width
== 0 || width
> sizeof(buf
) - 1)
835 width
= sizeof(buf
) - 1;
836 if ((width
= parsefloat(fp
, buf
, buf
+ width
)) == 0)
838 if ((flags
& SUPPRESS
) == 0) {
839 if (flags
& LONGDBL
) {
840 /*dvm*/ long double **mp
= (long double **)ap
;
841 long double res
= strtold(buf
, &p
);
843 /*dvm*/ *(*mp
) = res
;
844 /*dvm*/ ap
+= sizeof(long double *);
845 /*dvm*/ //*va_arg(ap, long double *) = res;
846 } else if (flags
& LONG
) {
847 double res
= strtod(buf
, &p
);
848 *va_arg(ap
, double *) = res
;
850 float res
= strtof(buf
, &p
);
851 *va_arg(ap
, float *) = res
;
853 if (__scanfdebug
&& p
- buf
!= (ptrdiff_t)width
)
860 #endif /* !NO_FLOATING_POINT */
864 //Print(L"%a: %d\n", __func__, __LINE__);
865 return (nconversions
!= 0 ? nassigned
: EOF
);
871 * Fill in the given table from the scanset at the given format
872 * (just after `['). Return a pointer to the character past the
873 * closing `]'. The table has a 1 wherever characters should be
874 * considered part of the scanset.
876 static const u_char
*
877 __sccl(char *tab
, const u_char
*fmt
)
881 _DIAGASSERT(tab
!= NULL
);
882 _DIAGASSERT(fmt
!= NULL
);
883 /* first `clear' the whole table */
884 c
= *fmt
++; /* first char hat => negated scanset */
886 v
= 1; /* default => accept */
887 c
= *fmt
++; /* get new first char */
889 v
= 0; /* default => reject */
891 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
892 (void)memset(tab
, v
, 256);
895 return (fmt
- 1);/* format ended before closing ] */
898 * Now set the entries corresponding to the actual scanset
899 * to the opposite of the above.
901 * The first character may be ']' (or '-') without being special;
902 * the last character may be '-'.
906 tab
[c
] = (char)v
; /* take character c */
908 n
= *fmt
++; /* and examine the next */
911 case 0: /* format ended too soon */
916 * A scanset of the form
918 * is defined as `the digit 0, the digit 1,
919 * the character +, the character -', but
920 * the effect of a scanset such as
922 * is implementation defined. The V7 Unix
923 * scanf treats `a-z' as `the letters a through
924 * z', but treats `a-a' as `the letter a, the
925 * character -, and the letter a'.
927 * For compatibility, the `-' is not considerd
928 * to define a range if the character following
929 * it is either a close bracket (required by ANSI)
930 * or is not numerically greater than the character
931 * we just stored in the table (c).
934 if (n
== ']' || (__collate_load_error
? n
< c
:
935 __collate_range_cmp(n
, c
) < 0)) {
937 break; /* resume the for(;;) */
940 /* fill in the range */
941 if (__collate_load_error
) {
946 for (i
= 0; i
< 256; i
++)
947 if (__collate_range_cmp(c
, i
) < 0 &&
948 __collate_range_cmp(i
, n
) <= 0)
951 #if 1 /* XXX another disgusting compatibility hack */
954 * Alas, the V7 Unix scanf also treats formats
955 * such as [a-c-e] as `the letters a through e'.
956 * This too is permitted by the standard....
967 case ']': /* end of scanset */
970 default: /* just another character */
978 #ifndef NO_FLOATING_POINT
980 parsefloat(FILE *fp
, char *buf
, char *end
)
985 S_START
, S_GOTSIGN
, S_INF
, S_NAN
, S_MAYBEHEX
,
986 S_DIGITS
, S_FRAC
, S_EXP
, S_EXPDIGITS
989 char decpt
= *localeconv()->decimal_point
;
990 _Bool gotmantdig
= 0, ishex
= 0;
993 * We set commit = p whenever the string we have read so far
994 * constitutes a valid representation of a floating point
995 * number by itself. At some point, the parse will complete
996 * or fail, and we will ungetc() back to the last commit point.
997 * To ensure that the file offset gets updated properly, it is
998 * always necessary to read at least one character that doesn't
999 * match; thus, we can't short-circuit "infinity" or "nan(...)".
1002 for (p
= buf
; p
< end
; ) {
1008 if (c
== '-' || c
== '+')
1032 if (infnanpos
> 6 ||
1033 (c
!= "nfinity"[infnanpos
] &&
1034 c
!= "NFINITY"[infnanpos
]))
1036 if (infnanpos
== 1 || infnanpos
== 6)
1037 commit
= p
; /* inf or infinity */
1041 switch (infnanpos
) {
1042 case -1: /* XXX kludge to deal with nan(...) */
1045 if (c
!= 'A' && c
!= 'a')
1049 if (c
!= 'N' && c
!= 'n')
1062 } else if (!isalnum(c
) && c
!= '_')
1070 if (c
== 'X' || c
== 'x') {
1073 } else { /* we saw a '0', but no 'x' */
1078 if ((ishex
&& isxdigit(c
)) || isdigit(c
))
1089 if (((c
== 'E' || c
== 'e') && !ishex
) ||
1090 ((c
== 'P' || c
== 'p') && ishex
)) {
1095 } else if ((ishex
&& isxdigit(c
)) || isdigit(c
)) {
1102 state
= S_EXPDIGITS
;
1103 if (c
== '-' || c
== '+')
1119 else if (__srefill(fp
))
1124 while (commit
< --p
)
1125 (void)ungetc(*(u_char
*)p
, fp
);
1127 return (int)(commit
- buf
);