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
38 #define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c))
39 #define conv_error() return (ungetc(c, s), done)
40 #define input_error() return (done == 0 ? EOF : done)
41 #define memory_error() return ((errno = ENOMEM), EOF)
44 /* Read formatted input from S according to the format string
45 FORMAT, using the argument list in ARG.
46 Return the number of assignments made, or -1 for an input error. */
48 DEFUN(__vfscanf
, (s
, format
, arg
),
49 FILE *s AND CONST
char *format AND
va_list argptr
)
51 va_list arg
= (va_list) argptr
;
53 register CONST
char *f
= format
;
54 register char fc
; /* Current character of the format. */
55 register size_t done
= 0; /* Assignments done. */
56 register size_t read_in
= 0; /* Chars read in. */
57 register int c
; /* Last char read. */
58 register int do_assign
; /* Whether to do an assignment. */
59 register int width
; /* Maximum field width. */
60 int group_flag
; /* %' modifier flag. */
63 int is_short
, is_long
, is_long_double
;
65 /* We use the `L' modifier for `long long int'. */
66 #define is_longlong is_long_double
70 int malloc_string
; /* Args are char ** to be filled in. */
71 /* Status for reading F-P nums. */
73 /* If a [...] is a [^...]. */
75 /* Base for integral numbers. */
77 /* Signedness for integral numbers. */
79 /* Integral holding variables. */
83 unsigned long long int uq
;
87 /* Character-buffer pointer. */
88 register char *str
, **strptr
;
92 char *w
; /* Pointer into WORK. */
93 wchar_t decimal
; /* Decimal point character. */
95 if (!__validfp(s
) || !s
->__mode
.__read
|| format
== NULL
)
101 /* Figure out the decimal point character. */
102 if (mbtowc (&decimal
, _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
),
103 strlen (_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
))) <= 0)
104 decimal
= (wchar_t) *_NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
108 /* Run through the format string. */
112 /* Extract the next argument, which is of type TYPE.
113 For a %N$... spec, this is the Nth argument from the beginning;
114 otherwise it is the next argument after the state now in ARG. */
115 #define ARG(type) (argpos == 0 ? va_arg (arg, type) : \
116 ({ unsigned int pos = argpos; \
117 va_list arg = (va_list) argptr; \
119 (void) va_arg (arg, void *); \
120 va_arg (arg, type); \
125 /* Non-ASCII, may be a multibyte. */
126 int len
= mblen (f
, strlen(f
));
143 /* Characters other than format specs must just match. */
148 /* Whitespace characters match any amount of whitespace. */
160 /* Initialize state of modifiers. */
164 is_short
= is_long
= is_long_double
= malloc_string
= 0;
166 /* Check for a positional parameter specification. */
171 argpos
= argpos
* 10 + (*f
++ - '0');
176 /* Oops; that was actually the field width. */
183 /* Check for the assignment-suppressant and the number grouping flag. */
184 while (*f
== '*' || *f
== '\'')
195 /* Find the maximum field width. */
206 /* Check for type modifiers. */
207 while (*f
== 'h' || *f
== 'l' || *f
== 'L' || *f
== 'a' || *f
== 'q')
211 /* int's are short int's. */
216 /* A double `l' is equivalent to an `L'. */
219 /* int's are long int's. */
224 /* double's are long double's, and int's are long long int's. */
228 /* String conversions (%s, %[) take a `char **'
229 arg and fill it in with a malloc'd pointer. */
234 /* End of the format string? */
238 /* Find the conversion specifier. */
241 if (fc
!= '[' && fc
!= 'c' && fc
!= 'n')
242 /* Eat whitespace. */
247 case '%': /* Must match a literal '%'. */
252 case 'n': /* Answer number of assignments done. */
254 *ARG (int *) = read_in
- 1; /* Don't count the read-ahead. */
257 case 'c': /* Match characters. */
275 while (inchar() != EOF
&& --width
> 0);
278 while (inchar() != EOF
&& --width
> 0);
285 case 's': /* Read a string. */
291 /* The string is to be stored in a malloc'd buffer. */ \
292 strptr = ARG (char **); \
293 if (strptr == NULL) \
295 /* Allocate an initial buffer. */ \
297 *strptr = str = malloc (strsize); \
300 str = ARG (char *); \
313 #define STRING_ADD_CHAR(c) \
317 if (malloc_string && str == *strptr + strsize) \
319 /* Enlarge the buffer. */ \
320 str = realloc (*strptr, strsize * 2); \
323 /* Can't allocate that much. Last-ditch effort. */\
324 str = realloc (*strptr, strsize + 1); \
327 /* We lose. Oh well. \
328 Terminate the string and stop converting, \
329 so at least we don't swallow any input. */ \
330 (*strptr)[strsize] = '\0'; \
350 } while (inchar () != EOF
&& (width
<= 0 || --width
> 0));
359 case 'x': /* Hexadecimal integer. */
360 case 'X': /* Ditto. */
365 case 'o': /* Octal integer. */
370 case 'u': /* Unsigned decimal integer. */
375 case 'd': /* Signed decimal integer. */
380 case 'i': /* Generic number. */
388 /* Check for a sign. */
389 if (c
== '-' || c
== '+')
397 /* Look for a leading indication of base. */
406 if (tolower(c
) == 'x')
424 /* Read the number into WORK. */
425 while (width
!= 0 && c
!= EOF
)
427 if (base
== 16 ? !isxdigit(c
) :
428 (!isdigit(c
) || c
- '0' >= base
))
437 (w
- work
== 1 && (work
[0] == '+' || work
[0] == '-')))
438 /* There was no number. */
441 /* Convert the number. */
446 num
.q
= __strtoq_internal (work
, &w
, base
, group_flag
);
448 num
.uq
= __strtouq_internal (work
, &w
, base
, group_flag
);
453 num
.l
= __strtol_internal (work
, &w
, base
, group_flag
);
455 num
.ul
= __strtoul_internal (work
, &w
, base
, group_flag
);
465 *ARG (unsigned LONGLONG
int *) = num
.uq
;
467 *ARG (unsigned long int *) = num
.ul
;
469 *ARG (unsigned short int *)
470 = (unsigned short int) num
.ul
;
472 *ARG (unsigned int *) = (unsigned int) num
.ul
;
477 *ARG (LONGLONG
int *) = num
.q
;
479 *ARG (long int *) = num
.l
;
481 *ARG (short int *) = (short int) num
.l
;
483 *ARG (int *) = (int) num
.l
;
489 case 'e': /* Floating-point numbers. */
497 /* Check for a sign. */
498 if (c
== '-' || c
== '+')
502 /* EOF is only an input error before we read any chars. */
513 else if (got_e
&& w
[-1] == 'e' && (c
== '-' || c
== '+'))
515 else if (!got_e
&& tolower(c
) == 'e')
520 else if (c
== decimal
&& !got_dot
)
529 } while (inchar() != EOF
&& width
!= 0);
533 if (w
[-1] == '-' || w
[-1] == '+' || w
[-1] == 'e')
536 /* Convert the number. */
540 long double d
= __strtold_internal (work
, &w
, group_flag
);
541 if (do_assign
&& w
!= work
)
542 *ARG (long double *) = d
;
546 double d
= __strtod_internal (work
, &w
, group_flag
);
547 if (do_assign
&& w
!= work
)
552 float d
= __strtof_internal (work
, &w
, group_flag
);
553 if (do_assign
&& w
!= work
)
564 case '[': /* Character class. */
578 while ((fc
= *f
++) != '\0' && fc
!= ']')
580 if (fc
== '-' && *f
!= '\0' && *f
!= ']' &&
581 w
> work
&& w
[-1] <= *f
)
582 /* Add all characters from the one before the '-'
583 up to (but not including) the next format char. */
584 for (fc
= w
[-1] + 1; fc
< *f
; ++fc
)
587 /* Add the character to the list. */
597 if ((strchr (work
, c
) == NULL
) != not_in
)
602 } while (inchar () != EOF
&& width
!= 0);
603 if (read_in
== num
.ul
)
613 case 'p': /* Generic pointer. */
615 /* A PTR must be the same size as a `long int'. */
624 weak_alias (__vfscanf
, vfscanf
)