]>
sourceware.org Git - glibc.git/blob - stdio/vfscanf.c
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 <localeinfo.h>
32 #define LONGLONG long long
38 #define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c))
39 #define conv_error() return ((c == EOF || 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. */
62 char is_short
, is_long
, is_long_double
;
64 /* We use the `L' modifier for `long long int'. */
65 #define is_longlong is_long_double
69 int malloc_string
; /* Args are char ** to be filled in. */
70 /* Status for reading F-P nums. */
72 /* If a [...] is a [^...]. */
74 /* Base for integral numbers. */
76 /* Signedness for integral numbers. */
78 /* Integral holding variables. */
80 unsigned long int unum
;
81 /* Character-buffer pointer. */
82 register char *str
, **strptr
;
86 char *w
; /* Pointer into WORK. */
87 wchar_t decimal
; /* Decimal point character. */
89 if (!__validfp(s
) || !s
->__mode
.__read
|| format
== NULL
)
95 /* Figure out the decimal point character. */
96 if (mbtowc(&decimal
, _numeric_info
->decimal_point
,
97 strlen(_numeric_info
->decimal_point
)) <= 0)
98 decimal
= (wchar_t) *_numeric_info
->decimal_point
;
102 /* Run through the format string. */
107 /* Non-ASCII, may be a multibyte. */
108 int len
= mblen(f
, strlen(f
));
125 /* Characters other than format specs must just match. */
130 /* Whitespace characters match any amount of whitespace. */
142 /* Check for the assignment-suppressant. */
151 /* Find the maximum field width. */
161 /* Check for type modifiers. */
162 is_short
= is_long
= is_long_double
= malloc_string
= 0;
163 while (*f
== 'h' || *f
== 'l' || *f
== 'L' || *f
== 'a' || *f
== 'q')
167 /* int's are short int's. */
172 /* A double `l' is equivalent to an `L'. */
175 /* int's are long int's. */
180 /* double's are long double's, and int's are long long int's. */
184 /* String conversions (%s, %[) take a `char **'
185 arg and fill it in with a malloc'd pointer. */
190 /* End of the format string? */
194 /* Find the conversion specifier. */
197 if (fc
!= '[' && fc
!= 'c' && fc
!= 'n')
198 /* Eat whitespace. */
203 case '%': /* Must match a literal '%'. */
208 case 'n': /* Answer number of assignments done. */
210 *va_arg(arg
, int *) = read_in
;
213 case 'c': /* Match characters. */
216 str
= va_arg (arg
, char *);
231 while (inchar() != EOF
&& --width
> 0);
234 while (inchar() != EOF
&& width
> 0)
242 case 's': /* Read a string. */
248 /* The string is to be stored in a malloc'd buffer. */ \
249 strptr = va_arg (arg, char **); \
250 if (strptr == NULL) \
252 /* Allocate an initial buffer. */ \
254 *strptr = str = malloc (strsize); \
257 str = va_arg (arg, char *); \
270 #define STRING_ADD_CHAR(c) \
274 if (malloc_string && str == *strptr + strsize) \
276 /* Enlarge the buffer. */ \
277 str = realloc (*strptr, strsize * 2); \
280 /* Can't allocate that much. Last-ditch effort. */\
281 str = realloc (*strptr, strsize + 1); \
284 /* We lose. Oh well. \
285 Terminate the string and stop converting, \
286 so at least we don't swallow any input. */ \
287 (*strptr)[strsize] = '\0'; \
307 } while (inchar () != EOF
&& (width
<= 0 || --width
> 0));
316 case 'x': /* Hexadecimal integer. */
317 case 'X': /* Ditto. */
322 case 'o': /* Octal integer. */
327 case 'u': /* Unsigned decimal integer. */
332 case 'd': /* Signed decimal integer. */
337 case 'i': /* Generic number. */
345 /* Check for a sign. */
346 if (c
== '-' || c
== '+')
354 /* Look for a leading indication of base. */
363 if (tolower(c
) == 'x')
381 /* Read the number into WORK. */
384 if (base
== 16 ? !isxdigit(c
) :
385 (!isdigit(c
) || c
- '0' >= base
))
390 } while (inchar() != EOF
&& width
!= 0);
393 (w
- work
== 1 && (work
[0] == '+' || work
[0] == '-')))
394 /* There was on number. */
397 /* Convert the number. */
400 num
= strtol (work
, &w
, base
);
402 unum
= strtoul (work
, &w
, base
);
411 *va_arg (arg
, unsigned LONGLONG
int *) = unum
;
413 *va_arg (arg
, unsigned long int *) = unum
;
415 *va_arg (arg
, unsigned short int *)
416 = (unsigned short int) unum
;
418 *va_arg(arg
, unsigned int *) = (unsigned int) unum
;
423 *va_arg(arg
, LONGLONG
int *) = num
;
425 *va_arg(arg
, long int *) = num
;
427 *va_arg(arg
, short int *) = (short int) num
;
429 *va_arg(arg
, int *) = (int) num
;
435 case 'e': /* Floating-point numbers. */
443 /* Check for a sign. */
444 if (c
== '-' || c
== '+')
448 /* EOF is only an input error before we read any chars. */
459 else if (got_e
&& w
[-1] == 'e' && (c
== '-' || c
== '+'))
461 else if (!got_e
&& tolower(c
) == 'e')
466 else if (c
== decimal
&& !got_dot
)
475 } while (inchar() != EOF
&& width
!= 0);
479 if (w
[-1] == '-' || w
[-1] == '+' || w
[-1] == 'e')
482 /* Convert the number. */
486 long double d
= __strtold (work
, &w
);
487 if (do_assign
&& w
!= work
)
488 *va_arg (arg
, long double *) = d
;
492 double d
= strtod (work
, &w
);
493 if (do_assign
&& w
!= work
)
494 *va_arg (arg
, double *) = d
;
498 float d
= __strtof (work
, &w
);
499 if (do_assign
&& w
!= work
)
500 *va_arg (arg
, float *) = d
;
510 case '[': /* Character class. */
524 while ((fc
= *f
++) != '\0' && fc
!= ']')
526 if (fc
== '-' && *f
!= '\0' && *f
!= ']' &&
527 w
> work
&& w
[-1] <= *f
)
528 /* Add all characters from the one before the '-'
529 up to (but not including) the next format char. */
530 for (fc
= w
[-1] + 1; fc
< *f
; ++fc
)
533 /* Add the character to the list. */
543 if ((strchr (work
, c
) == NULL
) != not_in
)
548 } while (inchar () != EOF
&& width
!= 0);
559 case 'p': /* Generic pointer. */
561 /* A PTR must be the same size as a `long int'. */
570 weak_alias (__vfscanf
, vfscanf
)
This page took 0.062412 seconds and 5 git commands to generate.