1 /* Copyright (C) 1991, 1992, 1993, 1994, 1995 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. */
20 #include "../locale/localeinfo.h"
32 #define LONGLONG long long
41 /* Those are flags in the conversion format. */
42 # define LONG 0x01 /* l: long or double */
43 # define LONGDBL 0x02 /* L: long long or long double */
44 # define SHORT 0x04 /* h: short */
45 # define SUPPRESS 0x08 /* suppress assignment */
46 # define POINTER 0x10 /* weird %p pointer (`fake hex') */
47 # define NOSKIP 0x20 /* do not skip blanks */
48 # define WIDTH 0x40 /* width */
51 # define va_list _IO_va_list
52 # define ungetc(c, s) _IO_ungetc (c, s)
53 # define inchar() ((c = _IO_getc(s)), ++read_in, c)
54 # define conv_error() return ((errp != NULL && (*errp |= 2)), \
55 (c == EOF || _IO_ungetc(c, s)), done)
57 # define input_error() return ((errp != NULL && (*errp |= 1)), \
58 done == 0 ? EOF : done)
59 # define memory_error() return ((errno = ENOMEM), EOF)
60 # define ARGCHECK(s, format) \
63 /* Check file argument for consistence. */ \
65 if (s->_flags & _IO_NO_READS || format == NULL) \
72 # define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c))
73 # define conv_error() return (ungetc(c, s), done)
74 # define input_error() return (done == 0 ? EOF : done)
75 # define memory_error() return ((errno = ENOMEM), EOF)
76 # define ARGCHECK(s, format) \
79 /* Check file argument for consistence. */ \
80 if (!__validfp (s) || !s->__mode.__read || format == NULL) \
89 /* Read formatted input from S according to the format string
90 FORMAT, using the argument list in ARG.
91 Return the number of assignments made, or -1 for an input error. */
94 _IO_vfscanf (s
, format
, argptr
, errp
)
101 __vfscanf (FILE *s
, const char *format
, va_list argptr
)
104 va_list arg
= (va_list) argptr
;
106 register const char *f
= format
;
107 register char fc
; /* Current character of the format. */
108 register size_t done
= 0; /* Assignments done. */
109 register size_t read_in
= 0; /* Chars read in. */
110 register int c
; /* Last char read. */
111 register int do_assign
; /* Whether to do an assignment. */
112 register int width
; /* Maximum field width. */
113 int group_flag
; /* %' modifier flag. */
115 int flags
; /* Trace flags for current format element. */
118 /* Type modifiers. */
119 int is_short
, is_long
, is_long_double
;
121 /* We use the `L' modifier for `long long int'. */
122 # define is_longlong is_long_double
124 # define is_longlong 0
126 int malloc_string
; /* Args are char ** to be filled in. */
127 /* Status for reading F-P nums. */
129 /* If a [...] is a [^...]. */
131 /* Base for integral numbers. */
133 /* Signedness for integral numbers. */
135 /* Integral holding variables. */
139 unsigned long long int uq
;
141 unsigned long int ul
;
143 /* Character-buffer pointer. */
144 register char *str
, **strptr
;
148 char *w
; /* Pointer into WORK. */
149 wchar_t decimal
; /* Decimal point character. */
151 ARGCHECK (s
, format
);
153 /* Figure out the decimal point character. */
154 if (mbtowc (&decimal
, _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
),
155 strlen (_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
))) <= 0)
156 decimal
= (wchar_t) *_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
160 /* Run through the format string. */
164 /* Extract the next argument, which is of type TYPE.
165 For a %N$... spec, this is the Nth argument from the beginning;
166 otherwise it is the next argument after the state now in ARG. */
168 /* XXX Possible optimization. */
169 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
170 ({ va_list arg = (va_list) argptr; \
171 arg = (va_list) ((char *) arg \
173 * __va_rounded_size (void *)); \
174 va_arg (arg, type); \
177 # define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
178 ({ unsigned int pos = argpos; \
179 va_list arg = (va_list) argptr; \
181 (void) va_arg (arg, void *); \
182 va_arg (arg, type); \
188 /* Non-ASCII, may be a multibyte. */
189 int len
= mblen (f
, strlen (f
));
206 /* Characters other than format specs must just match. */
211 /* Whitespace characters match any amount of whitespace. */
224 /* That is the start of the coversion string. */
228 /* Initialize state of modifiers. */
232 is_short
= is_long
= is_long_double
= malloc_string
= 0;
234 /* Check for a positional parameter specification. */
239 argpos
= argpos
* 10 + (*f
++ - '0');
244 /* Oops; that was actually the field width. */
251 /* Check for the assignment-suppressant and the number grouping flag. */
252 while (*f
== '*' || *f
== '\'')
267 /* We have seen width. */
272 /* Find the maximum field width. */
283 /* Check for type modifiers. */
284 while (*f
== 'h' || *f
== 'l' || *f
== 'L' || *f
== 'a' || *f
== 'q')
288 /* int's are short int's. */
290 if (flags
& ~(SUPPRESS
| WIDTH
))
291 /* Signal illegal format element. */
300 /* A double `l' is equivalent to an `L'. */
302 if ((flags
& ~(SUPPRESS
| WIDTH
)) && (flags
& LONGDBL
))
311 /* int's are long int's. */
320 /* double's are long double's, and int's are long long int's. */
322 if (flags
& ~(SUPPRESS
| WIDTH
))
323 /* Signal illegal format element. */
330 /* String conversions (%s, %[) take a `char **'
331 arg and fill it in with a malloc'd pointer. */
336 /* End of the format string? */
340 /* Find the conversion specifier. */
343 if (fc
!= '[' && fc
!= 'c' && fc
!= 'n')
344 /* Eat whitespace. */
349 case '%': /* Must match a literal '%'. */
354 case 'n': /* Answer number of assignments done. */
356 *ARG (int *) = read_in
- 1; /* Don't count the read-ahead. */
359 case 'c': /* Match characters. */
377 while (inchar () != EOF
&& --width
> 0);
380 while (inchar () != EOF
&& --width
> 0);
387 case 's': /* Read a string. */
393 /* The string is to be stored in a malloc'd buffer. */ \
394 strptr = ARG (char **); \
395 if (strptr == NULL) \
397 /* Allocate an initial buffer. */ \
399 *strptr = str = malloc (strsize); \
402 str = ARG (char *); \
415 #define STRING_ADD_CHAR(c) \
419 if (malloc_string && str == *strptr + strsize) \
421 /* Enlarge the buffer. */ \
422 str = realloc (*strptr, strsize * 2); \
425 /* Can't allocate that much. Last-ditch effort. */\
426 str = realloc (*strptr, strsize + 1); \
429 /* We lose. Oh well. \
430 Terminate the string and stop converting, \
431 so at least we don't swallow any input. */ \
432 (*strptr)[strsize] = '\0'; \
452 } while (inchar () != EOF
&& (width
<= 0 || --width
> 0));
461 case 'x': /* Hexadecimal integer. */
462 case 'X': /* Ditto. */
467 case 'o': /* Octal integer. */
472 case 'u': /* Unsigned decimal integer. */
477 case 'd': /* Signed decimal integer. */
482 case 'i': /* Generic number. */
490 /* Check for a sign. */
491 if (c
== '-' || c
== '+')
499 /* Look for a leading indication of base. */
508 if (tolower (c
) == 'x')
526 /* Read the number into WORK. */
529 if (base
== 16 ? !isxdigit (c
) :
530 (!isdigit (c
) || c
- '0' >= base
))
536 while (inchar () != EOF
&& width
!= 0);
539 (w
- work
== 1 && (work
[0] == '+' || work
[0] == '-')))
540 /* There was no number. */
543 /* Convert the number. */
548 num
.q
= __strtoq_internal (work
, &w
, base
, group_flag
);
550 num
.uq
= __strtouq_internal (work
, &w
, base
, group_flag
);
555 num
.l
= __strtol_internal (work
, &w
, base
, group_flag
);
557 num
.ul
= __strtoul_internal (work
, &w
, base
, group_flag
);
567 *ARG (unsigned LONGLONG
int *) = num
.uq
;
569 *ARG (unsigned long int *) = num
.ul
;
571 *ARG (unsigned short int *)
572 = (unsigned short int) num
.ul
;
574 *ARG (unsigned int *) = (unsigned int) num
.ul
;
579 *ARG (LONGLONG
int *) = num
.q
;
581 *ARG (long int *) = num
.l
;
583 *ARG (short int *) = (short int) num
.l
;
585 *ARG (int *) = (int) num
.l
;
591 case 'e': /* Floating-point numbers. */
599 /* Check for a sign. */
600 if (c
== '-' || c
== '+')
603 if (inchar () == EOF
)
604 /* EOF is only an input error before we read any chars. */
615 else if (got_e
&& w
[-1] == 'e' && (c
== '-' || c
== '+'))
617 else if (!got_e
&& tolower (c
) == 'e')
622 else if (c
== decimal
&& !got_dot
)
631 } while (inchar () != EOF
&& width
!= 0);
635 if (w
[-1] == '-' || w
[-1] == '+' || w
[-1] == 'e')
638 /* Convert the number. */
642 long double d
= __strtold_internal (work
, &w
, group_flag
);
643 if (do_assign
&& w
!= work
)
644 *ARG (long double *) = d
;
648 double d
= __strtod_internal (work
, &w
, group_flag
);
649 if (do_assign
&& w
!= work
)
654 float d
= __strtof_internal (work
, &w
, group_flag
);
655 if (do_assign
&& w
!= work
)
666 case '[': /* Character class. */
680 while ((fc
= *f
++) != '\0' && fc
!= ']')
682 if (fc
== '-' && *f
!= '\0' && *f
!= ']' &&
683 w
> work
&& w
[-1] <= *f
)
684 /* Add all characters from the one before the '-'
685 up to (but not including) the next format char. */
686 for (fc
= w
[-1] + 1; fc
< *f
; ++fc
)
689 /* Add the character to the list. */
699 if ((strchr (work
, c
) == NULL
) != not_in
)
704 } while (inchar () != EOF
&& width
!= 0);
705 if (read_in
== num
.ul
)
715 case 'p': /* Generic pointer. */
717 /* A PTR must be the same size as a `long int'. */
724 return ((c
== EOF
|| ungetc (c
, s
)), done
);
729 __vfscanf (FILE *s
, const char *format
, va_list argptr
)
731 return _IO_vfscanf (s
, format
, argptr
, NULL
);
735 weak_alias (__vfscanf
, vfscanf
)