summary refs log tree commit diff
path: root/stdio-common/vfscanf.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-11-20 03:48:11 +0000
committerRoland McGrath <roland@gnu.org>1995-11-20 03:48:11 +0000
commit96aa2d94a2355cdc55c96e808d14a0e7f2ebe77d (patch)
treef7c87e6742af0707b858a1387ca85b679aa8d13e /stdio-common/vfscanf.c
parenta5a81fecc7194d050066265a15b1ba8bc3abc627 (diff)
downloadglibc-96aa2d94a2355cdc55c96e808d14a0e7f2ebe77d.tar.gz
glibc-96aa2d94a2355cdc55c96e808d14a0e7f2ebe77d.tar.xz
glibc-96aa2d94a2355cdc55c96e808d14a0e7f2ebe77d.zip
Sat Nov 18 16:46:01 1995 Ulrich Drepper <drepper@gnu.ai.mit.edu>
	* libio/Makefile, libio/cleanup.c, libio/clearerr.c, libio/feof.c,
	libio/ferror.c, libio/fgetc.c, libio/filedoalloc.c, libio/fileno.c,
	libio/fileops.c, libio/fputc.c, libio/freopen.c, libio/fseek.c,
	libio/genops.c, libio/getc.c, libio/getchar.c, libio/iofclose.c,
	libio/iofdopen.c, libio/iofflush.c, libio/iofgetpos.c, libio/iofgets.c,
	libio/iofopen.c, libio/iofprintf.c, libio/iofputs.c, libio/iofread.c,
	libio/iofscanf.c, libio/iofsetpos.c, libio/ioftell.c, libio/iofwrite.c,
	libio/iogetdelim.c, libio/iogetline.c, libio/iogets.c, libio/iolibio.h,
	libio/iopadn.c, libio/ioprims.c, libio/ioputs.c, libio/ioseekoff.c,
	libio/ioseekpos.c, libio/iosetbuffer.c, libio/iosetvbuf.c,
	libio/iosprintf.c, libio/ioungetc.c, libio/iovsprintf.c,
	libio/iovsscanf.c, libio/libio.h, libio/libioP.h, libio/putc.c,
	libio/putchar.c, libio/rewind.c, libio/setbuf.c, libio/setlinebuf.c,
	libio/stdfiles.c, libio/stdio.c, libio/stdio.h, libio/strfile.h,
	libio/strops.c, libio/vasprintf.c, libio/vscanf.c, libio/vsnprintf.c:
	New files.  Slightly modified version from Linux libc.

	* libio/memstream.c, libio/vdprintf.c: New files for functions not
	(yet) part of GNU libio.

	* libio/iofopncook.c: Implementation of `fopencookie', mainly written
	by Per Bothner.

	* stdio-common/getline.c: Adapted to libio.
	* stdio-common/snprintf.c: Adapted to libio.
	* stdio-common/vfprintf.c: Adapted to libio.
	* stdio-common/vfscanf.c: Adapted to libio.
	* sysdeps/posix/tempname.c: Adapted to libio.
Diffstat (limited to 'stdio-common/vfscanf.c')
-rw-r--r--stdio-common/vfscanf.c224
1 files changed, 166 insertions, 58 deletions
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index a778346287..a3c058495e 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -34,23 +34,79 @@ Cambridge, MA 02139, USA.  */
 #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)
+#ifdef USE_IN_LIBIO
+# include <libioP.h>
+# include <libio.h>
+
+/* Those are flags in the conversion format. */
+# define LONG		0x01	/* l: long or double */
+# define LONGDBL	0x02	/* L: long long or long double */
+# define SHORT		0x04	/* h: short */
+# define SUPPRESS	0x08	/* suppress assignment */
+# define POINTER	0x10	/* weird %p pointer (`fake hex') */
+# define NOSKIP		0x20	/* do not skip blanks */
+# define WIDTH		0x40	/* width */
+
+
+# define va_list	_IO_va_list
+# define ungetc(c, s)	_IO_ungetc (c, s)
+# define inchar()	((c = _IO_getc(s)), ++read_in, c)
+# define conv_error()	return ((errp != NULL && (*errp |= 2)), \
+				(c == EOF || _IO_ungetc(c, s)), done)
+
+# define input_error()	return ((errp != NULL && (*errp |= 1)), \
+				done == 0 ? EOF : done)
+# define memory_error()	return ((errno = ENOMEM), EOF)
+# define ARGCHECK(s, format)						     \
+  do									     \
+    {									     \
+      /* Check file argument for consistence.  */			     \
+      CHECK_FILE (s, -1);						     \
+      if (s->_flags & _IO_NO_READS || format == NULL)			     \
+       {								     \
+         MAYBE_SET_EINVAL;						     \
+         return -1;							     \
+       }								     \
+    } while (0)
+#else
+# 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)
+# define ARGCHECK(s, format)						     \
+  do									     \
+    {									     \
+      /* Check file argument for consistence.  */			     \
+      if (!__validfp (s) || !s->__mode.__read || format == NULL)	     \
+	{								     \
+	  errno = EINVAL;						     \
+	  return -1;							     \
+	}								     \
+    } while (0)
+#endif
 
 
 /* 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.  */
+#ifdef USE_IN_LIBIO
 int
-DEFUN(__vfscanf, (s, format, arg),
-      FILE *s AND CONST char *format AND va_list argptr)
+_IO_vfscanf (s, format, argptr, errp)
+     _IO_FILE *s;
+     const char *format;
+     _IO_va_list argptr;
+     int *errp;
+#else
+int
+__vfscanf (s, format, arg)
+     FILE *s;
+     const char *format;
+     va_list argptr;
+#endif
 {
   va_list arg = (va_list) argptr;
 
-  register CONST char *f = format;
+  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.  */
@@ -58,14 +114,17 @@ DEFUN(__vfscanf, (s, format, arg),
   register int do_assign;	/* Whether to do an assignment.  */
   register int width;		/* Maximum field width.  */
   int group_flag;		/* %' modifier flag.  */
+#ifdef USE_IN_LIBIO
+  int flags;			/* Trace flags for current format element.  */
+#endif
 
   /* 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
+# define is_longlong	is_long_double
 #else
-#define	is_longlong	0
+# define is_longlong	0
 #endif
   int malloc_string;		/* Args are char ** to be filled in.  */
   /* Status for reading F-P nums.  */
@@ -92,18 +151,14 @@ DEFUN(__vfscanf, (s, format, arg),
   char *w;			/* Pointer into WORK.  */
   wchar_t decimal;		/* Decimal point character.  */
 
-  if (!__validfp(s) || !s->__mode.__read || format == NULL)
-    {
-      errno = EINVAL;
-      return EOF;
-    }
+  ARGCHECK (s, format);
 
   /* 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();
+  c = inchar ();
 
   /* Run through the format string.  */
   while (*f != '\0')
@@ -112,27 +167,38 @@ DEFUN(__vfscanf, (s, format, arg),
       /* 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) :		      \
+#if 0
+      /* XXX Possible optimization.  */
+# define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
+			 ({ va_list arg = (va_list) argptr;		      \
+			    arg = (va_list) ((char *) arg		      \
+					     + (argpos - 1)		      \
+					     * __va_rounded_size (void *));   \
+			    va_arg (arg, type);				      \
+			 }))
+#else
+# 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);				      \
 			  }))
+#endif
 
       if (!isascii (*f))
 	{
 	  /* Non-ASCII, may be a multibyte.  */
-	  int len = mblen (f, strlen(f));
+	  int len = mblen (f, strlen (f));
 	  if (len > 0)
 	    {
 	      while (len-- > 0)
 		if (c == EOF)
-		  input_error();
+		  input_error ();
 		else if (c == *f++)
-		  (void) inchar();
+		  (void) inchar ();
 		else
-		  conv_error();
+		  conv_error ();
 	      continue;
 	    }
 	}
@@ -142,8 +208,8 @@ DEFUN(__vfscanf, (s, format, arg),
 	{
 	  /* Characters other than format specs must just match.  */
 	  if (c == EOF)
-	    input_error();
-	  if (isspace(fc))
+	    input_error ();
+	  if (isspace (fc))
 	    {
 	      /* Whitespace characters match any amount of whitespace.  */
 	      while (isspace (c))
@@ -151,12 +217,17 @@ DEFUN(__vfscanf, (s, format, arg),
 	      continue;
 	    }
 	  else if (c == fc)
-	    (void) inchar();
+	    (void) inchar ();
 	  else
-	    conv_error();
+	    conv_error ();
 	  continue;
 	}
 
+#ifdef USE_IN_LIBIO
+      /* That is the start of the coversion string. */
+      flags = 0;
+#endif
+
       /* Initialize state of modifiers.  */
       argpos = 0;
       do_assign = 1;
@@ -185,6 +256,9 @@ DEFUN(__vfscanf, (s, format, arg),
 	switch (*f++)
 	  {
 	  case '*':
+#ifdef USE_IN_LIBIO
+	    flags = SUPPRESS;
+#endif
 	    do_assign = 0;
 	    break;
 	  case '\'':
@@ -192,9 +266,15 @@ DEFUN(__vfscanf, (s, format, arg),
 	    break;
 	  }
 
+#ifdef USE_IN_LIBIO
+      /* We have seen width. */
+      if (isdigit (*f))
+	flags |= WIDTH;
+#endif
+
       /* Find the maximum field width.  */
       width = 0;
-      while (isdigit(*f))
+      while (isdigit (*f))
 	{
 	  width *= 10;
 	  width += *f++ - '0';
@@ -209,19 +289,44 @@ DEFUN(__vfscanf, (s, format, arg),
 	  {
 	  case 'h':
 	    /* int's are short int's.  */
+#ifdef USE_IN_LIBIO
+	    if (flags & ~(SUPPRESS | WIDTH))
+	      /* Signal illegal format element.  */
+	      conv_error ();
+	    flags |= SHORT;
+#endif
 	    is_short = 1;
 	    break;
 	  case 'l':
 	    if (is_long)
-	      /* A double `l' is equivalent to an `L'.  */
-	      is_longlong = 1;
+	      {
+		/* A double `l' is equivalent to an `L'.  */
+#ifdef USE_IN_LIBIO
+		if ((flags & ~(SUPPRESS | WIDTH)) && (flags & LONGDBL))
+		  conv_error ();
+		flags &= ~LONG;
+		flags |= LONGDBL;
+#endif
+		is_longlong = 1;
+	      }
 	    else
-	      /* int's are long int's.  */
-	      is_long = 1;
+	      {
+		/* int's are long int's.  */
+#ifdef USE_IN_LIBIO
+		flags |= LONG;
+#endif
+		is_long = 1;
+	      }
 	    break;
 	  case 'q':
 	  case 'L':
 	    /* double's are long double's, and int's are long long int's.  */
+#ifdef USE_IN_LIBIO
+	    if (flags & ~(SUPPRESS | WIDTH))
+	      /* Signal illegal format element.  */
+	      conv_error ();
+	    flags |= LONGDBL;
+#endif
 	    is_long_double = 1;
 	    break;
 	  case 'a':
@@ -233,20 +338,20 @@ DEFUN(__vfscanf, (s, format, arg),
 
       /* End of the format string?  */
       if (*f == '\0')
-	conv_error();
+	conv_error ();
 
       /* Find the conversion specifier.  */
       w = work;
       fc = *f++;
       if (fc != '[' && fc != 'c' && fc != 'n')
 	/* Eat whitespace.  */
-	while (isspace(c))
-	  (void) inchar();
+	while (isspace (c))
+	  (void) inchar ();
       switch (fc)
 	{
 	case '%':	/* Must match a literal '%'.  */
 	  if (c != fc)
-	    conv_error();
+	    conv_error ();
 	  break;
 
 	case 'n':	/* Answer number of assignments done.  */
@@ -263,7 +368,7 @@ DEFUN(__vfscanf, (s, format, arg),
 	    }
 
 	  if (c == EOF)
-	    input_error();
+	    input_error ();
 
 	  if (width == -1)
 	    width = 1;
@@ -272,10 +377,10 @@ DEFUN(__vfscanf, (s, format, arg),
 	    {
 	      do
 		*str++ = c;
-	      while (inchar() != EOF && --width > 0);
+	      while (inchar () != EOF && --width > 0);
 	    }
 	  else
-	    while (inchar() != EOF && --width > 0);
+	    while (inchar () != EOF && --width > 0);
 
 	  if (do_assign)
 	    ++done;
@@ -289,7 +394,7 @@ DEFUN(__vfscanf, (s, format, arg),
 	      if (malloc_string)					      \
 		{							      \
 		  /* The string is to be stored in a malloc'd buffer.  */     \
-		  strptr = ARG (char **);			      \
+		  strptr = ARG (char **);				      \
 		  if (strptr == NULL)					      \
 		    conv_error ();					      \
 		  /* Allocate an initial buffer.  */			      \
@@ -297,7 +402,7 @@ DEFUN(__vfscanf, (s, format, arg),
 		  *strptr = str = malloc (strsize);			      \
 		}							      \
 	      else							      \
-		str = ARG (char *);				      \
+		str = ARG (char *);					      \
 	      if (str == NULL)						      \
 		conv_error ();						      \
 	    }
@@ -357,7 +462,7 @@ DEFUN(__vfscanf, (s, format, arg),
 	  break;
 
 	case 'x':	/* Hexadecimal integer.  */
-	case 'X':	/* Ditto.  */ 
+	case 'X':	/* Ditto.  */
 	  base = 16;
 	  number_signed = 0;
 	  goto number;
@@ -383,7 +488,7 @@ DEFUN(__vfscanf, (s, format, arg),
 
 	number:
 	  if (c == EOF)
-	    input_error();
+	    input_error ();
 
 	  /* Check for a sign.  */
 	  if (c == '-' || c == '+')
@@ -391,7 +496,7 @@ DEFUN(__vfscanf, (s, format, arg),
 	      *w++ = c;
 	      if (width > 0)
 		--width;
-	      (void) inchar();
+	      (void) inchar ();
 	    }
 
 	  /* Look for a leading indication of base.  */
@@ -401,9 +506,9 @@ DEFUN(__vfscanf, (s, format, arg),
 		--width;
 	      *w++ = '0';
 
-	      (void) inchar();
+	      (void) inchar ();
 
-	      if (tolower(c) == 'x')
+	      if (tolower (c) == 'x')
 		{
 		  if (base == 0)
 		    base = 16;
@@ -411,7 +516,7 @@ DEFUN(__vfscanf, (s, format, arg),
 		    {
 		      if (width > 0)
 			--width;
-		      (void) inchar();
+		      (void) inchar ();
 		    }
 		}
 	      else if (base == 0)
@@ -422,21 +527,21 @@ DEFUN(__vfscanf, (s, format, arg),
 	    base = 10;
 
 	  /* Read the number into WORK.  */
-	  while (width != 0 && c != EOF)
+	  do
 	    {
-	      if (base == 16 ? !isxdigit(c) :
-		  (!isdigit(c) || c - '0' >= base))
+	      if (base == 16 ? !isxdigit (c) :
+		  (!isdigit (c) || c - '0' >= base))
 		break;
 	      *w++ = c;
 	      if (width > 0)
 		--width;
-	      (void) inchar ();
 	    }
+	  while (inchar () != EOF && width != 0);
 
 	  if (w == work ||
 	      (w - work == 1 && (work[0] == '+' || work[0] == '-')))
 	    /* There was no number.  */
-	    conv_error();
+	    conv_error ();
 
 	  /* Convert the number.  */
 	  *w = '\0';
@@ -492,15 +597,15 @@ DEFUN(__vfscanf, (s, format, arg),
 	case 'g':
 	case 'G':
 	  if (c == EOF)
-	    input_error();
+	    input_error ();
 
 	  /* Check for a sign.  */
 	  if (c == '-' || c == '+')
 	    {
 	      *w++ = c;
-	      if (inchar() == EOF)
+	      if (inchar () == EOF)
 		/* EOF is only an input error before we read any chars.  */
-		conv_error();
+		conv_error ();
 	      if (width > 0)
 		--width;
 	    }
@@ -508,11 +613,11 @@ DEFUN(__vfscanf, (s, format, arg),
 	  got_dot = got_e = 0;
 	  do
 	    {
-	      if (isdigit(c))
+	      if (isdigit (c))
 		*w++ = c;
 	      else if (got_e && w[-1] == 'e' && (c == '-' || c == '+'))
 		*w++ = c;
-	      else if (!got_e && tolower(c) == 'e')
+	      else if (!got_e && tolower (c) == 'e')
 		{
 		  *w++ = 'e';
 		  got_e = got_dot = 1;
@@ -526,12 +631,12 @@ DEFUN(__vfscanf, (s, format, arg),
 		break;
 	      if (width > 0)
 		--width;
-	    } while (inchar() != EOF && width != 0);
+	    } while (inchar () != EOF && width != 0);
 
 	  if (w == work)
 	    conv_error();
 	  if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e')
-	    conv_error();
+	    conv_error ();
 
 	  /* Convert the number.  */
 	  *w = '\0';
@@ -614,11 +719,14 @@ DEFUN(__vfscanf, (s, format, arg),
 	  base = 16;
 	  /* A PTR must be the same size as a `long int'.  */
 	  is_long = 1;
+	  number_signed = 0;
 	  goto number;
 	}
     }
 
-  conv_error();
+  return ((c == EOF || ungetc (c, s)), done);
 }
 
+#ifndef USE_IN_LIBIO
 weak_alias (__vfscanf, vfscanf)
+#endif