diff options
Diffstat (limited to 'stdio/vfscanf.c')
-rw-r--r-- | stdio/vfscanf.c | 624 |
1 files changed, 0 insertions, 624 deletions
diff --git a/stdio/vfscanf.c b/stdio/vfscanf.c deleted file mode 100644 index a778346287..0000000000 --- a/stdio/vfscanf.c +++ /dev/null @@ -1,624 +0,0 @@ -/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#include <ansidecl.h> -#include "../locale/localeinfo.h" -#include <errno.h> -#include <limits.h> -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - -#ifdef __GNUC__ -#define HAVE_LONGLONG -#define LONGLONG long long -#else -#define LONGLONG long -#endif - - -#define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c)) -#define conv_error() return (ungetc(c, s), done) -#define input_error() return (done == 0 ? EOF : done) -#define memory_error() return ((errno = ENOMEM), EOF) - - -/* Read formatted input from S according to the format string - FORMAT, using the argument list in ARG. - Return the number of assignments made, or -1 for an input error. */ -int -DEFUN(__vfscanf, (s, format, arg), - FILE *s AND CONST char *format AND va_list argptr) -{ - va_list arg = (va_list) argptr; - - register CONST char *f = format; - register char fc; /* Current character of the format. */ - register size_t done = 0; /* Assignments done. */ - register size_t read_in = 0; /* Chars read in. */ - register int c; /* Last char read. */ - register int do_assign; /* Whether to do an assignment. */ - register int width; /* Maximum field width. */ - int group_flag; /* %' modifier flag. */ - - /* Type modifiers. */ - int is_short, is_long, is_long_double; -#ifdef HAVE_LONGLONG - /* We use the `L' modifier for `long long int'. */ -#define is_longlong is_long_double -#else -#define is_longlong 0 -#endif - int malloc_string; /* Args are char ** to be filled in. */ - /* Status for reading F-P nums. */ - char got_dot, got_e; - /* If a [...] is a [^...]. */ - char not_in; - /* Base for integral numbers. */ - int base; - /* Signedness for integral numbers. */ - int number_signed; - /* Integral holding variables. */ - union - { - long long int q; - unsigned long long int uq; - long int l; - unsigned long int ul; - } num; - /* Character-buffer pointer. */ - register char *str, **strptr; - size_t strsize; - /* Workspace. */ - char work[200]; - char *w; /* Pointer into WORK. */ - wchar_t decimal; /* Decimal point character. */ - - if (!__validfp(s) || !s->__mode.__read || format == NULL) - { - errno = EINVAL; - return EOF; - } - - /* Figure out the decimal point character. */ - if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT), - strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0) - decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); - - c = inchar(); - - /* Run through the format string. */ - while (*f != '\0') - { - unsigned int argpos; - /* Extract the next argument, which is of type TYPE. - For a %N$... spec, this is the Nth argument from the beginning; - otherwise it is the next argument after the state now in ARG. */ -#define ARG(type) (argpos == 0 ? va_arg (arg, type) : \ - ({ unsigned int pos = argpos; \ - va_list arg = (va_list) argptr; \ - while (--pos > 0) \ - (void) va_arg (arg, void *); \ - va_arg (arg, type); \ - })) - - if (!isascii (*f)) - { - /* Non-ASCII, may be a multibyte. */ - int len = mblen (f, strlen(f)); - if (len > 0) - { - while (len-- > 0) - if (c == EOF) - input_error(); - else if (c == *f++) - (void) inchar(); - else - conv_error(); - continue; - } - } - - fc = *f++; - if (fc != '%') - { - /* Characters other than format specs must just match. */ - if (c == EOF) - input_error(); - if (isspace(fc)) - { - /* Whitespace characters match any amount of whitespace. */ - while (isspace (c)) - inchar (); - continue; - } - else if (c == fc) - (void) inchar(); - else - conv_error(); - continue; - } - - /* Initialize state of modifiers. */ - argpos = 0; - do_assign = 1; - group_flag = 0; - is_short = is_long = is_long_double = malloc_string = 0; - - /* Check for a positional parameter specification. */ - if (isdigit (*f)) - { - argpos = *f++ - '0'; - while (isdigit (*f)) - argpos = argpos * 10 + (*f++ - '0'); - if (*f == '$') - ++f; - else - { - /* Oops; that was actually the field width. */ - width = argpos; - argpos = 0; - goto got_width; - } - } - - /* Check for the assignment-suppressant and the number grouping flag. */ - while (*f == '*' || *f == '\'') - switch (*f++) - { - case '*': - do_assign = 0; - break; - case '\'': - group_flag = 1; - break; - } - - /* Find the maximum field width. */ - width = 0; - while (isdigit(*f)) - { - width *= 10; - width += *f++ - '0'; - } - got_width: - if (width == 0) - width = -1; - - /* Check for type modifiers. */ - while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q') - switch (*f++) - { - case 'h': - /* int's are short int's. */ - is_short = 1; - break; - case 'l': - if (is_long) - /* A double `l' is equivalent to an `L'. */ - is_longlong = 1; - else - /* int's are long int's. */ - is_long = 1; - break; - case 'q': - case 'L': - /* double's are long double's, and int's are long long int's. */ - is_long_double = 1; - break; - case 'a': - /* String conversions (%s, %[) take a `char **' - arg and fill it in with a malloc'd pointer. */ - malloc_string = 1; - break; - } - - /* End of the format string? */ - if (*f == '\0') - conv_error(); - - /* Find the conversion specifier. */ - w = work; - fc = *f++; - if (fc != '[' && fc != 'c' && fc != 'n') - /* Eat whitespace. */ - while (isspace(c)) - (void) inchar(); - switch (fc) - { - case '%': /* Must match a literal '%'. */ - if (c != fc) - conv_error(); - break; - - case 'n': /* Answer number of assignments done. */ - if (do_assign) - *ARG (int *) = read_in - 1; /* Don't count the read-ahead. */ - break; - - case 'c': /* Match characters. */ - if (do_assign) - { - str = ARG (char *); - if (str == NULL) - conv_error (); - } - - if (c == EOF) - input_error(); - - if (width == -1) - width = 1; - - if (do_assign) - { - do - *str++ = c; - while (inchar() != EOF && --width > 0); - } - else - while (inchar() != EOF && --width > 0); - - if (do_assign) - ++done; - - break; - - case 's': /* Read a string. */ -#define STRING_ARG \ - if (do_assign) \ - { \ - if (malloc_string) \ - { \ - /* The string is to be stored in a malloc'd buffer. */ \ - strptr = ARG (char **); \ - if (strptr == NULL) \ - conv_error (); \ - /* Allocate an initial buffer. */ \ - strsize = 100; \ - *strptr = str = malloc (strsize); \ - } \ - else \ - str = ARG (char *); \ - if (str == NULL) \ - conv_error (); \ - } - STRING_ARG; - - if (c == EOF) - input_error (); - - do - { - if (isspace (c)) - break; -#define STRING_ADD_CHAR(c) \ - if (do_assign) \ - { \ - *str++ = c; \ - if (malloc_string && str == *strptr + strsize) \ - { \ - /* Enlarge the buffer. */ \ - str = realloc (*strptr, strsize * 2); \ - if (str == NULL) \ - { \ - /* Can't allocate that much. Last-ditch effort. */\ - str = realloc (*strptr, strsize + 1); \ - if (str == NULL) \ - { \ - /* We lose. Oh well. \ - Terminate the string and stop converting, \ - so at least we don't swallow any input. */ \ - (*strptr)[strsize] = '\0'; \ - ++done; \ - conv_error (); \ - } \ - else \ - { \ - *strptr = str; \ - str += strsize; \ - ++strsize; \ - } \ - } \ - else \ - { \ - *strptr = str; \ - str += strsize; \ - strsize *= 2; \ - } \ - } \ - } - STRING_ADD_CHAR (c); - } while (inchar () != EOF && (width <= 0 || --width > 0)); - - if (do_assign) - { - *str = '\0'; - ++done; - } - break; - - case 'x': /* Hexadecimal integer. */ - case 'X': /* Ditto. */ - base = 16; - number_signed = 0; - goto number; - - case 'o': /* Octal integer. */ - base = 8; - number_signed = 0; - goto number; - - case 'u': /* Unsigned decimal integer. */ - base = 10; - number_signed = 0; - goto number; - - case 'd': /* Signed decimal integer. */ - base = 10; - number_signed = 1; - goto number; - - case 'i': /* Generic number. */ - base = 0; - number_signed = 1; - - number: - if (c == EOF) - input_error(); - - /* Check for a sign. */ - if (c == '-' || c == '+') - { - *w++ = c; - if (width > 0) - --width; - (void) inchar(); - } - - /* Look for a leading indication of base. */ - if (c == '0') - { - if (width > 0) - --width; - *w++ = '0'; - - (void) inchar(); - - if (tolower(c) == 'x') - { - if (base == 0) - base = 16; - if (base == 16) - { - if (width > 0) - --width; - (void) inchar(); - } - } - else if (base == 0) - base = 8; - } - - if (base == 0) - base = 10; - - /* Read the number into WORK. */ - while (width != 0 && c != EOF) - { - if (base == 16 ? !isxdigit(c) : - (!isdigit(c) || c - '0' >= base)) - break; - *w++ = c; - if (width > 0) - --width; - (void) inchar (); - } - - if (w == work || - (w - work == 1 && (work[0] == '+' || work[0] == '-'))) - /* There was no number. */ - conv_error(); - - /* Convert the number. */ - *w = '\0'; - if (is_longlong) - { - if (number_signed) - num.q = __strtoq_internal (work, &w, base, group_flag); - else - num.uq = __strtouq_internal (work, &w, base, group_flag); - } - else - { - if (number_signed) - num.l = __strtol_internal (work, &w, base, group_flag); - else - num.ul = __strtoul_internal (work, &w, base, group_flag); - } - if (w == work) - conv_error (); - - if (do_assign) - { - if (! number_signed) - { - if (is_longlong) - *ARG (unsigned LONGLONG int *) = num.uq; - else if (is_long) - *ARG (unsigned long int *) = num.ul; - else if (is_short) - *ARG (unsigned short int *) - = (unsigned short int) num.ul; - else - *ARG (unsigned int *) = (unsigned int) num.ul; - } - else - { - if (is_longlong) - *ARG (LONGLONG int *) = num.q; - else if (is_long) - *ARG (long int *) = num.l; - else if (is_short) - *ARG (short int *) = (short int) num.l; - else - *ARG (int *) = (int) num.l; - } - ++done; - } - break; - - case 'e': /* Floating-point numbers. */ - case 'E': - case 'f': - case 'g': - case 'G': - if (c == EOF) - input_error(); - - /* Check for a sign. */ - if (c == '-' || c == '+') - { - *w++ = c; - if (inchar() == EOF) - /* EOF is only an input error before we read any chars. */ - conv_error(); - if (width > 0) - --width; - } - - got_dot = got_e = 0; - do - { - if (isdigit(c)) - *w++ = c; - else if (got_e && w[-1] == 'e' && (c == '-' || c == '+')) - *w++ = c; - else if (!got_e && tolower(c) == 'e') - { - *w++ = 'e'; - got_e = got_dot = 1; - } - else if (c == decimal && !got_dot) - { - *w++ = c; - got_dot = 1; - } - else - break; - if (width > 0) - --width; - } while (inchar() != EOF && width != 0); - - if (w == work) - conv_error(); - if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e') - conv_error(); - - /* Convert the number. */ - *w = '\0'; - if (is_long_double) - { - long double d = __strtold_internal (work, &w, group_flag); - if (do_assign && w != work) - *ARG (long double *) = d; - } - else if (is_long) - { - double d = __strtod_internal (work, &w, group_flag); - if (do_assign && w != work) - *ARG (double *) = d; - } - else - { - float d = __strtof_internal (work, &w, group_flag); - if (do_assign && w != work) - *ARG (float *) = d; - } - - if (w == work) - conv_error (); - - if (do_assign) - ++done; - break; - - case '[': /* Character class. */ - STRING_ARG; - - if (c == EOF) - input_error(); - - if (*f == '^') - { - ++f; - not_in = 1; - } - else - not_in = 0; - - while ((fc = *f++) != '\0' && fc != ']') - { - if (fc == '-' && *f != '\0' && *f != ']' && - w > work && w[-1] <= *f) - /* Add all characters from the one before the '-' - up to (but not including) the next format char. */ - for (fc = w[-1] + 1; fc < *f; ++fc) - *w++ = fc; - else - /* Add the character to the list. */ - *w++ = fc; - } - if (fc == '\0') - conv_error(); - - *w = '\0'; - num.ul = read_in; - do - { - if ((strchr (work, c) == NULL) != not_in) - break; - STRING_ADD_CHAR (c); - if (width > 0) - --width; - } while (inchar () != EOF && width != 0); - if (read_in == num.ul) - conv_error (); - - if (do_assign) - { - *str = '\0'; - ++done; - } - break; - - case 'p': /* Generic pointer. */ - base = 16; - /* A PTR must be the same size as a `long int'. */ - is_long = 1; - goto number; - } - } - - conv_error(); -} - -weak_alias (__vfscanf, vfscanf) |