1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include "../locale/localeinfo.h"
27 #include <libc-lock.h>
31 #define LONGLONG long long
36 /* Those are flags in the conversion format. */
37 # define LONG 0x001 /* l: long or double */
38 # define LONGDBL 0x002 /* L: long long or long double */
39 # define SHORT 0x004 /* h: short */
40 # define SUPPRESS 0x008 /* *: suppress assignment */
41 # define POINTER 0x010 /* weird %p pointer (`fake hex') */
42 # define NOSKIP 0x020 /* do not skip blanks */
43 # define WIDTH 0x040 /* width was given */
44 # define GROUP 0x080 /* ': group numbers */
45 # define MALLOC 0x100 /* a: malloc strings */
47 # define TYPEMOD (LONG|LONGDBL|SHORT)
55 # define va_list _IO_va_list
56 # define ungetc(c, s) (--read_in, _IO_ungetc (c, s))
57 # define inchar() ((c = _IO_getc_unlocked (s)), (void) ++read_in, c)
58 # define conv_error() do { \
59 if (errp != NULL) *errp |= 2; \
60 _IO_funlockfile (s); \
63 # define input_error() do { \
64 _IO_funlockfile (s); \
65 if (errp != NULL) *errp |= 1; \
68 # define memory_error() do { \
69 _IO_funlockfile (s); \
70 __set_errno (ENOMEM); \
73 # define ARGCHECK(s, format) \
76 /* Check file argument for consistence. */ \
77 CHECK_FILE (s, EOF); \
78 if (s->_flags & _IO_NO_READS || format == NULL) \
84 # define LOCK_STREAM(S) \
85 __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, (S)); \
87 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
89 # define ungetc(c, s) (--read_in, ungetc (c, s))
90 # define inchar() ((c = getc (s)), (void) ++read_in, c)
91 # define conv_error() do { \
95 # define input_error() do { \
99 # define memory_error() do { \
101 __set_errno (ENOMEM); \
104 # define ARGCHECK(s, format) \
107 /* Check file argument for consistence. */ \
108 if (!__validfp (s) || !s->__mode.__read || format == NULL) \
110 __set_errno (EINVAL); \
115 /* XXX For now !!! */
116 # define flockfile(S) /* nothing */
117 # define funlockfile(S) /* nothing */
118 # define LOCK_STREAM(S)
119 # define UNLOCK_STREAM
121 # define LOCK_STREAM(S) \
122 __libc_cleanup_region_start (&__funlockfile, (S)); \
124 # define UNLOCK_STREAM __libc_cleanup_region_end (1)
129 /* Read formatted input from S according to the format string
130 FORMAT, using the argument list in ARG.
131 Return the number of assignments made, or -1 for an input error. */
134 _IO_vfscanf (s
, format
, argptr
, errp
)
141 __vfscanf (FILE *s
, const char *format
, va_list argptr
)
144 va_list arg
= (va_list) argptr
;
146 register const char *f
= format
;
147 register unsigned char fc
; /* Current character of the format. */
148 register size_t done
= 0; /* Assignments done. */
149 register size_t read_in
= 0; /* Chars read in. */
150 register int c
; /* Last char read. */
151 register int width
; /* Maximum field width. */
152 register int flags
; /* Modifiers for current format element. */
154 /* Status for reading F-P nums. */
155 char got_dot
, got_e
, negative
;
156 /* If a [...] is a [^...]. */
158 /* Base for integral numbers. */
160 /* Signedness for integral numbers. */
162 /* Decimal point character. */
164 /* The thousands character of the current locale. */
166 /* Integral holding variables. */
170 unsigned long long int uq
;
172 unsigned long int ul
;
174 /* Character-buffer pointer. */
175 register char *str
, **strptr
;
177 /* We must not react on white spaces immediately because they can
178 possibly be matched even if in the input stream no character is
179 available anymore. */
182 char *tw
; /* Temporary pointer. */
183 char *wp
= NULL
; /* Workspace. */
184 size_t wpmax
= 0; /* Maximal size of workspace. */
185 size_t wpsize
; /* Currently used bytes in workspace. */
189 if (wpsize == wpmax) \
192 wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax; \
193 wp = (char *) alloca (wpmax); \
195 memcpy (wp, old, wpsize); \
197 wp[wpsize++] = (Ch); \
201 ARGCHECK (s
, format
);
203 /* Figure out the decimal point character. */
204 if (mbtowc (&decimal
, _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
),
205 strlen (_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
))) <= 0)
206 decimal
= (wchar_t) *_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
207 /* Figure out the thousands separator character. */
208 if (mbtowc (&thousands
, _NL_CURRENT (LC_NUMERIC
, THOUSANDS_SEP
),
209 strlen (_NL_CURRENT (LC_NUMERIC
, THOUSANDS_SEP
))) <= 0)
210 thousands
= (wchar_t) *_NL_CURRENT (LC_NUMERIC
, THOUSANDS_SEP
);
212 /* Lock the stream. */
215 /* Run through the format string. */
219 /* Extract the next argument, which is of type TYPE.
220 For a %N$... spec, this is the Nth argument from the beginning;
221 otherwise it is the next argument after the state now in ARG. */
223 /* XXX Possible optimization. */
224 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
225 ({ va_list arg = (va_list) argptr; \
226 arg = (va_list) ((char *) arg \
228 * __va_rounded_size (void *)); \
229 va_arg (arg, type); \
232 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
233 ({ unsigned int pos = argpos; \
234 va_list arg = (va_list) argptr; \
236 (void) va_arg (arg, void *); \
237 va_arg (arg, type); \
243 /* Non-ASCII, may be a multibyte. */
244 int len
= mblen (f
, strlen (f
));
266 /* Remember to skip spaces. */
273 /* Read a character. */
276 /* Characters other than format specs must just match. */
280 /* We saw white space char as the last character in the format
281 string. Now it's time to skip all leading white space. */
298 /* This is the start of the conversion string. */
301 /* Initialize state of modifiers. */
304 /* Prepare temporary buffer. */
307 /* Check for a positional parameter specification. */
312 argpos
= argpos
* 10 + (*f
++ - '0');
317 /* Oops; that was actually the field width. */
325 /* Check for the assignment-suppressant and the number grouping flag. */
326 while (*f
== '*' || *f
== '\'')
337 /* We have seen width. */
341 /* Find the maximum field width. */
352 /* Check for type modifiers. */
353 while (*f
== 'h' || *f
== 'l' || *f
== 'L' || *f
== 'a' || *f
== 'q')
357 /* int's are short int's. */
359 /* Signal illegal format element. */
364 if (flags
& (SHORT
|LONGDBL
))
366 else if (flags
& LONG
)
368 /* A double `l' is equivalent to an `L'. */
373 /* int's are long int's. */
378 /* double's are long double's, and int's are long long int's. */
380 /* Signal illegal format element. */
386 /* Signal illegal format element. */
388 /* String conversions (%s, %[) take a `char **'
389 arg and fill it in with a malloc'd pointer. */
394 /* End of the format string? */
398 /* Find the conversion specifier. */
400 if (skip_space
|| (fc
!= '[' && fc
!= 'c' && fc
!= 'n'))
402 /* Eat whitespace. */
412 case '%': /* Must match a literal '%'. */
421 case 'n': /* Answer number of assignments done. */
422 /* Corrigendum 1 to ISO C 1990 describes the allowed flags
423 with the 'n' conversion specifier. */
424 if (!(flags
& SUPPRESS
))
425 /* Don't count the read-ahead. */
427 *ARG (long long int *) = read_in
;
428 else if (flags
& LONG
)
429 *ARG (long int *) = read_in
;
430 else if (flags
& SHORT
)
431 *ARG (short int *) = read_in
;
433 *ARG (int *) = read_in
;
436 case 'c': /* Match characters. */
437 if (!(flags
& SUPPRESS
))
451 if (!(flags
& SUPPRESS
))
455 while (--width
> 0 && inchar () != EOF
);
458 while (--width
> 0 && inchar () != EOF
);
461 /* I.e., EOF was read. */
464 if (!(flags
& SUPPRESS
))
469 case 's': /* Read a string. */
471 if (!(flags & SUPPRESS)) \
473 if (flags & MALLOC) \
475 /* The string is to be stored in a malloc'd buffer. */ \
476 strptr = ARG (char **); \
477 if (strptr == NULL) \
479 /* Allocate an initial buffer. */ \
481 *strptr = str = malloc (strsize); \
484 str = ARG (char *); \
501 #define STRING_ADD_CHAR(c) \
502 if (!(flags & SUPPRESS)) \
505 if ((flags & MALLOC) && str == *strptr + strsize) \
507 /* Enlarge the buffer. */ \
508 str = realloc (*strptr, strsize * 2); \
511 /* Can't allocate that much. Last-ditch effort. */\
512 str = realloc (*strptr, strsize + 1); \
515 /* We lose. Oh well. \
516 Terminate the string and stop converting, \
517 so at least we don't skip any input. */ \
518 (*strptr)[strsize] = '\0'; \
538 } while ((width
<= 0 || --width
> 0) && inchar () != EOF
);
540 if (!(flags
& SUPPRESS
))
547 case 'x': /* Hexadecimal integer. */
548 case 'X': /* Ditto. */
553 case 'o': /* Octal integer. */
558 case 'u': /* Unsigned decimal integer. */
563 case 'd': /* Signed decimal integer. */
568 case 'i': /* Generic number. */
577 /* Check for a sign. */
578 if (c
== '-' || c
== '+')
586 /* Look for a leading indication of base. */
587 if (width
!= 0 && c
== '0')
595 if (width
!= 0 && tolower (c
) == 'x')
613 /* Read the number into workspace. */
614 while (c
!= EOF
&& width
!= 0)
616 if (base
== 16 ? !isxdigit (c
) :
617 ((!isdigit (c
) || c
- '0' >= base
) &&
618 !((flags
& GROUP
) && base
== 10 && c
== thousands
)))
627 /* The just read character is not part of the number anymore. */
631 (wpsize
== 1 && (wp
[0] == '+' || wp
[0] == '-')))
632 /* There was no number. */
635 /* Convert the number. */
640 num
.q
= __strtoq_internal (wp
, &tw
, base
, flags
& GROUP
);
642 num
.uq
= __strtouq_internal (wp
, &tw
, base
, flags
& GROUP
);
647 num
.l
= __strtol_internal (wp
, &tw
, base
, flags
& GROUP
);
649 num
.ul
= __strtoul_internal (wp
, &tw
, base
, flags
& GROUP
);
654 if (!(flags
& SUPPRESS
))
659 *ARG (unsigned LONGLONG
int *) = num
.uq
;
660 else if (flags
& LONG
)
661 *ARG (unsigned long int *) = num
.ul
;
662 else if (flags
& SHORT
)
663 *ARG (unsigned short int *)
664 = (unsigned short int) num
.ul
;
666 *ARG (unsigned int *) = (unsigned int) num
.ul
;
671 *ARG (LONGLONG
int *) = num
.q
;
672 else if (flags
& LONG
)
673 *ARG (long int *) = num
.l
;
674 else if (flags
& SHORT
)
675 *ARG (short int *) = (short int) num
.l
;
677 *ARG (int *) = (int) num
.l
;
683 case 'e': /* Floating-point numbers. */
692 /* Check for a sign. */
693 if (c
== '-' || c
== '+')
696 if (inchar () == EOF
)
697 /* EOF is only an input error before we read any chars. */
710 else if (got_e
&& wp
[wpsize
- 1] == 'e'
711 && (c
== '-' || c
== '+'))
713 else if (wpsize
> 0 && !got_e
&& tolower (c
) == 'e')
718 else if (c
== decimal
&& !got_dot
)
723 else if ((flags
& GROUP
) && c
== thousands
&& !got_dot
)
730 while (inchar () != EOF
&& width
!= 0);
732 /* The last read character is not part of the number anymore. */
738 /* Convert the number. */
742 long double d
= __strtold_internal (wp
, &tw
, flags
& GROUP
);
743 if (!(flags
& SUPPRESS
) && tw
!= wp
)
744 *ARG (long double *) = negative
? -d
: d
;
746 else if (flags
& LONG
)
748 double d
= __strtod_internal (wp
, &tw
, flags
& GROUP
);
749 if (!(flags
& SUPPRESS
) && tw
!= wp
)
750 *ARG (double *) = negative
? -d
: d
;
754 float d
= __strtof_internal (wp
, &tw
, flags
& GROUP
);
755 if (!(flags
& SUPPRESS
) && tw
!= wp
)
756 *ARG (float *) = negative
? -d
: d
;
762 if (!(flags
& SUPPRESS
))
766 case '[': /* Character class. */
781 /* Fill WP with byte flags indexed by character.
782 We will use this flag map for matching input characters. */
783 if (wpmax
< UCHAR_MAX
)
786 wp
= (char *) alloca (wpmax
);
788 memset (wp
, 0, UCHAR_MAX
);
791 if (fc
== ']' || fc
== '-')
793 /* If ] or - appears before any char in the set, it is not
794 the terminator or separator, but the first char in the
800 while ((fc
= *f
++) != '\0' && fc
!= ']')
802 if (fc
== '-' && *f
!= '\0' && *f
!= ']' &&
803 (unsigned char) f
[-2] <= (unsigned char) *f
)
805 /* Add all characters from the one before the '-'
806 up to (but not including) the next format char. */
807 for (fc
= f
[-2]; fc
< *f
; ++fc
)
811 /* Add the character to the flag map. */
820 num
.ul
= read_in
- 1; /* -1 because we already read one char. */
832 while (width
!= 0 && inchar () != EOF
);
834 if (read_in
== num
.ul
)
837 if (!(flags
& SUPPRESS
))
844 case 'p': /* Generic pointer. */
846 /* A PTR must be the same size as a `long int'. */
847 flags
&= ~(SHORT
|LONGDBL
);
854 /* The last thing we saw int the format string was a white space.
855 Consume the last white spaces. */
872 __vfscanf (FILE *s
, const char *format
, va_list argptr
)
874 return _IO_vfscanf (s
, format
, argptr
, NULL
);
878 weak_alias (__vfscanf
, vfscanf
)