summary refs log tree commit diff
path: root/stdio-common/vfscanf.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-09-18 19:04:01 +0000
committerUlrich Drepper <drepper@redhat.com>2007-09-18 19:04:01 +0000
commit874aa52349cc111d1f6ea5dff24bb14c306714e0 (patch)
tree40cc28100e18b8b9d8311038b0d3f9dd38bcfe0f /stdio-common/vfscanf.c
parent883f7943f242c174c49bc82d51fe8332ad50d573 (diff)
downloadglibc-874aa52349cc111d1f6ea5dff24bb14c306714e0.tar.gz
glibc-874aa52349cc111d1f6ea5dff24bb14c306714e0.tar.xz
glibc-874aa52349cc111d1f6ea5dff24bb14c306714e0.zip
* include/stdio.h (__isoc99_fscanf, __isoc99_scanf,
	__isoc99_sscanf, __isoc99_vscanf): New prototypes.
	(__isoc99_vsscanf, __isoc99_vfscanf): New prototypes, add
	libc_hidden_proto.
	* include/wchar.h (__isoc99_fwscanf, __isoc99_wscanf,
	__isoc99_swscanf, __isoc99_vwscanf): New prototypes.
	(__isoc99_vswscanf, __isoc99_vfwscanf): New prototypes,
	add libc_hidden_proto.
	* libio/stdio.h (fscanf, scanf, sscanf, vfscanf, vscanf,
	vsscanf): Redirect to __isoc99_* if strict ISO C99 or POSIX
	conformance requested.
	* wcsmbs/wchar.h (fwscanf, wscanf, swscanf, vfwscanf, vwscanf,
	vswscanf): Redirect to __isoc99_* if strict ISO C99 or POSIX
	conformance requested.
	* libio/bits/stdio-ldbl.h (fscanf, scanf, sscanf, vfscanf, vscanf,
	vsscanf): Redirect to __nldbl___isoc99_* if strict ISO C99 or POSIX
	conformance requested.
	* wcsmbs/bits/wchar-ldbl.h (fwscanf, wscanf, swscanf, vfwscanf,
	vwscanf, vswscanf): Redirect to __nldbl___isoc99_* if strict
	ISO C99 or POSIX conformance requested.
	* stdio-common/Versions (libc): Export __isoc99_scanf@@GLIBC_2.7,
	__isoc99_vscanf@@GLIBC_2.7, __isoc99_fscanf@@GLIBC_2.7,
	__isoc99_vfscanf@@GLIBC_2.7, __isoc99_sscanf@@GLIBC_2.7
	and __isoc99_vsscanf@@GLIBC_2.7.
	* stdio-common/Makefile (routines): Add isoc99_scanf, isoc99_vscanf,
	isoc99_fscanf, isoc99_vfscanf, isoc99_sscanf and isoc99_vsscanf.
	(tests): Add scanf14.
	(CFLAGS-vfprintf.c, CFLAGS-fprintf.c, CFLAGS-printf.c,
	CFLAGS-vfwprintf.c, CFLAGS-vfscanf.c, CFLAGS-vfwscanf.c,
	CFLAGS-fscanf.c, CFLAGS-scanf.c, CFLAGS-isoc99_vfscanf.c,
	CFLAGS-isoc99_vscanf.c, CFLAGS-isoc99_fscanf.c,
	CFLAGS-isoc99_scanf.c): Add $(exceptions).
	(CFLAGS-scanf15.c): Add various -I paths to prevent the compiler
	from using internal headers.
	* wcsmbs/Versions (libc): Export __isoc99_wscanf@@GLIBC_2.7,
	__isoc99_vwscanf@@GLIBC_2.7, __isoc99_fwscanf@@GLIBC_2.7,
	__isoc99_vfwscanf@@GLIBC_2.7, __isoc99_swscanf@@GLIBC_2.7
	and __isoc99_vswscanf@@GLIBC_2.7.
	* wcsmbs/Makefile (routines): Add isoc99_wscanf, isoc99_vwscanf,
	isoc99_fwscanf, isoc99_vfwscanf, isoc99_swscanf and isoc99_vswscanf.
	(CFLAGS-isoc99_wscanf.c, CFLAGS-isoc99_fwscanf.c,
	CFLAGS-isoc99_vwscanf.c, CFLAGS-isoc99_vfwscanf.c): Add $(exceptions).
	(CPPFLAGS): Add -D_IO_MTSAFE_IO if needed.
	* stdio-common/isoc99_scanf.c: New file.
	* stdio-common/isoc99_vsscanf.c: New file.
	* stdio-common/isoc99_vscanf.c: New file.
	* stdio-common/isoc99_vfscanf.c: New file.
	* stdio-common/isoc99_fscanf.c: New file.
	* stdio-common/isoc99_sscanf.c: New file.
	* wcsmbs/isoc99_fwscanf.c: New file.
	* wcsmbs/isoc99_vswscanf.c: New file.
	* wcsmbs/isoc99_swscanf.c: New file.
	* wcsmbs/isoc99_wscanf.c: New file.
	* wcsmbs/isoc99_vwscanf.c: New file.
	* wcsmbs/isoc99_vfwscanf.c: New file.
	* libio/libio.h (_IO_FLAGS2_SCANF_STD): Define.
	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct): Also
	clear _IO_FLAGS2_SCANF_STD bit from _flags2.
	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Don't
	handle %as, %aS and %a[ if _IO_FLAGS2_SCANF_STD is set in _flags2.
	* stdio-common/scanf14.c: New test.
	* stdio-common/scanf15.c: New test.
	* sysdeps/ieee754/ldbl-opt/Makefile (libnldbl-calls): Add
	isoc99_scanf, isoc99_fscanf, isoc99_sscanf,
	isoc99_vscanf, isoc99_vfscanf, isoc99_vsscanf,
	isoc99_wscanf, isoc99_fwscanf, isoc99_swscanf,
	isoc99_vwscanf, isoc99_vfwscanf and isoc99_vswscanf.
	* sysdeps/ieee754/ldbl-opt/Versions (libc): Export
	__nldbl___isoc99_scanf@@GLIBC_2.7,
	__nldbl___isoc99_fscanf@@GLIBC_2.7,
	__nldbl___isoc99_sscanf@@GLIBC_2.7,
	__nldbl___isoc99_vscanf@@GLIBC_2.7,
	__nldbl___isoc99_vfscanf@@GLIBC_2.7,
	__nldbl___isoc99_vsscanf@@GLIBC_2.7,
	__nldbl___isoc99_wscanf@@GLIBC_2.7,
	__nldbl___isoc99_fwscanf@@GLIBC_2.7,
	__nldbl___isoc99_swscanf@@GLIBC_2.7,
	__nldbl___isoc99_vwscanf@@GLIBC_2.7,
	__nldbl___isoc99_vfwscanf@@GLIBC_2.7
	and __nldbl___isoc99_vswscanf@@GLIBC_2.7.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.h (__isoc99_scanf,
	__isoc99_fscanf, __isoc99_sscanf, __isoc99_vscanf,
	__isoc99_vfscanf, __isoc99_vsscanf, __isoc99_wscanf,
	__isoc99_fwscanf, __isoc99_swscanf, __isoc99_vwscanf,
	__isoc99_vfwscanf, __isoc99_vswscanf): Add NLDBL_DECL.
	* sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	(__nldbl___isoc99_scanf, __nldbl___isoc99_fscanf,
	__nldbl___isoc99_sscanf, __nldbl___isoc99_vscanf,
	__nldbl___isoc99_vfscanf, __nldbl___isoc99_vsscanf,
	__nldbl___isoc99_wscanf, __nldbl___isoc99_fwscanf,
	__nldbl___isoc99_swscanf, __nldbl___isoc99_vwscanf,
	__nldbl___isoc99_vfwscanf, __nldbl___isoc99_vswscanf): New
	functions.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vfscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_swscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vwscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_wscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_scanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_sscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vsscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_fwscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vfwscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vswscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vscanf.c: New file.
	* sysdeps/ieee754/ldbl-opt/nldbl-isoc99_fscanf.c: New file.

	* stdio-common/Makefile (tests): Add scanf13.
	(scanf13-ENV): New.
	* stdio-common/vfscanf.c (_IO_vfscanf_internal): Handle
	m modifier followed by l.
	(STRING_ARG): Add width argument.
	(_IO_vfscanf_internal) <case L_('c')>: Handle %mc.
	<case L_('C')>: Handle %mlc and %mC.
	<case L_('s'), case L_('S'), case L_('[')>: Adjust STRING_ARG
	arguments.
	* stdio-common/scanf13.c: New test.

	* libio/libioP.h (_IO_acquire_lock_clear_flags2_fct): Clear
	the _IO_FLAGS2_FORTIFY bit from _flags2 rather than _flags.

	type and __THROW marker of splice, vmsplice, and tee.
Diffstat (limited to 'stdio-common/vfscanf.c')
-rw-r--r--stdio-common/vfscanf.c273
1 files changed, 217 insertions, 56 deletions
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index ddf9a5ea31..e4728d00c9 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -514,13 +514,25 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	      --f;
 	      break;
 	    }
+	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
+	     supported at all.  */
+	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+	    {
+	      --f;
+	      break;
+	    }
 	  /* String conversions (%s, %[) take a `char **'
 	     arg and fill it in with a malloc'd pointer.  */
 	  flags |= GNU_MALLOC;
 	  break;
-        case L_('m'):
-          flags |= POSIX_MALLOC;
-          break;
+	case L_('m'):
+	  flags |= POSIX_MALLOC;
+	  if (*f == L_('l'))
+	    {
+	      ++f;
+	      flags |= LONG;
+	    }
+	  break;
 	case L_('z'):
 	  if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
 	    flags |= LONGDBL;
@@ -635,20 +647,46 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	case L_('c'):	/* Match characters.  */
 	  if ((flags & LONG) == 0)
 	    {
-	      if (!(flags & SUPPRESS))
-		{
-		  str = ARG (char *);
-		  if (str == NULL)
-		    conv_error ();
-		}
+	      if (width == -1)
+		width = 1;
+
+#define STRING_ARG(Str, Type, Width)					      \
+	      do if (!(flags & SUPPRESS))				      \
+		{							      \
+		  if (flags & MALLOC)					      \
+		    {							      \
+		      /* The string is to be stored in a malloc'd buffer.  */ \
+		      /* For %mS using char ** is actually wrong, but	      \
+			 shouldn't make a difference on any arch glibc	      \
+			 supports and would unnecessarily complicate	      \
+			 things. */					      \
+		      strptr = ARG (char **);				      \
+		      if (strptr == NULL)				      \
+			conv_error ();					      \
+		      /* Allocate an initial buffer.  */		      \
+		      strsize = Width;					      \
+		      *strptr = (char *) malloc (strsize * sizeof (Type));    \
+		      Str = (Type *) *strptr;				      \
+		      if (Str != NULL)					      \
+			add_ptr_to_free (strptr);			      \
+		      else if (flags & POSIX_MALLOC)			      \
+			goto reteof;					      \
+		    }							      \
+		  else							      \
+		    Str = ARG (Type *);					      \
+		  if (Str == NULL)					      \
+		    conv_error ();					      \
+		} while (0)
+#ifdef COMPILE_WSCANF
+	      STRING_ARG (str, char, 100);
+#else
+	      STRING_ARG (str, char, (width > 1024 ? 1024 : width));
+#endif
 
 	      c = inchar ();
 	      if (__builtin_expect (c == EOF, 0))
 		input_error ();
 
-	      if (width == -1)
-		width = 1;
-
 #ifdef COMPILE_WSCANF
 	      /* We have to convert the wide character(s) into multibyte
 		 characters and store the result.  */
@@ -658,6 +696,38 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		{
 		  size_t n;
 
+		  if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
+		      && str + MB_CUR_MAX >= *strptr + strsize)
+		    {
+		      /* We have to enlarge the buffer if the `m' flag
+			 was given.  */
+		      size_t strleng = str - *strptr;
+		      char *newstr;
+
+		      newstr = (char *) realloc (*strptr, strsize * 2);
+		      if (newstr == NULL)
+			{
+			  /* Can't allocate that much.  Last-ditch effort.  */
+			  newstr = (char *) realloc (*strptr,
+						     strleng + MB_CUR_MAX);
+			  if (newstr == NULL)
+			    /* c can't have `a' flag, only `m'.  */
+			    goto reteof;
+			  else
+			    {
+			      *strptr = newstr;
+			      str = newstr + strleng;
+			      strsize = strleng + MB_CUR_MAX;
+			    }
+			}
+		      else
+			{
+			  *strptr = newstr;
+			  str = newstr + strleng;
+			  strsize *= 2;
+			}
+		    }
+
 		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
 		  if (__builtin_expect (n == (size_t) -1, 0))
 		    /* No valid wide character.  */
@@ -672,7 +742,40 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	      if (!(flags & SUPPRESS))
 		{
 		  do
-		    *str++ = c;
+		    {
+		      if ((flags & MALLOC)
+			  && (char *) str == *strptr + strsize)
+			{
+			  /* Enlarge the buffer.  */
+			  size_t newsize
+			    = strsize
+			      + (strsize >= width ? width - 1 : strsize);
+
+			  str = (char *) realloc (*strptr, newsize);
+			  if (str == NULL)
+			    {
+			      /* Can't allocate that much.  Last-ditch
+				 effort.  */
+			      str = (char *) realloc (*strptr, strsize + 1);
+			      if (str == NULL)
+				/* c can't have `a' flag, only `m'.  */
+				goto reteof;
+			      else
+				{
+				  *strptr = (char *) str;
+				  str += strsize;
+				  ++strsize;
+				}
+			    }
+			  else
+			    {
+			      *strptr = (char *) str;
+			      str += strsize;
+			      strsize = newsize;
+			    }
+			}
+		      *str++ = c;
+		    }
 		  while (--width > 0 && inchar () != EOF);
 		}
 	      else
@@ -680,18 +783,25 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #endif
 
 	      if (!(flags & SUPPRESS))
-		++done;
+		{
+		  if ((flags & MALLOC) && str - *strptr != strsize)
+		    {
+		      char *cp = (char *) realloc (*strptr, str - *strptr);
+		      if (cp != NULL)
+			*strptr = cp;
+		    }
+		  strptr = NULL;
+		  ++done;
+		}
 
 	      break;
 	    }
 	  /* FALLTHROUGH */
 	case L_('C'):
-	  if (!(flags & SUPPRESS))
-	    {
-	      wstr = ARG (wchar_t *);
-	      if (wstr == NULL)
-		conv_error ();
-	    }
+	  if (width == -1)
+	    width = 1;
+
+	  STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
 
 	  c = inchar ();
 	  if (__builtin_expect (c == EOF, 0))
@@ -702,7 +812,40 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	  if (!(flags & SUPPRESS))
 	    {
 	      do
-		*wstr++ = c;
+		{
+		  if ((flags & MALLOC)
+		      && wstr == (wchar_t *) *strptr + strsize)
+		    {
+		      size_t newsize
+			= strsize + (strsize > width ? width - 1 : strsize);
+		      /* Enlarge the buffer.  */
+		      wstr = (wchar_t *) realloc (*strptr,
+						  newsize * sizeof (wchar_t));
+		      if (wstr == NULL)
+			{
+			  /* Can't allocate that much.  Last-ditch effort.  */
+			  wstr = (wchar_t *) realloc (*strptr,
+						      (strsize + 1)
+						      * sizeof (wchar_t));
+			  if (wstr == NULL)
+			    /* C or lc can't have `a' flag, only `m' flag.  */
+			    goto reteof;
+			  else
+			    {
+			      *strptr = (char *) wstr;
+			      wstr += strsize;
+			      ++strsize;
+			    }
+			}
+		      else
+			{
+			  *strptr = (char *) wstr;
+			  wstr += strsize;
+			  strsize = newsize;
+			}
+		    }
+		  *wstr++ = c;
+		}
 	      while (--width > 0 && inchar () != EOF);
 	    }
 	  else
@@ -721,6 +864,38 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		/* This is what we present the mbrtowc function first.  */
 		buf[0] = c;
 
+		if (!(flags & SUPPRESS) && (flags & MALLOC)
+		    && wstr == (wchar_t *) *strptr + strsize)
+		  {
+		    size_t newsize
+		      = strsize + (strsize > width ? width - 1 : strsize);
+		    /* Enlarge the buffer.  */
+		    wstr = (wchar_t *) realloc (*strptr,
+						newsize * sizeof (wchar_t));
+		    if (wstr == NULL)
+		      {
+			/* Can't allocate that much.  Last-ditch effort.  */
+			wstr = (wchar_t *) realloc (*strptr,
+						    ((strsize + 1)
+						     * sizeof (wchar_t)));
+			if (wstr == NULL)
+			  /* C or lc can't have `a' flag, only `m' flag.  */
+			  goto reteof;
+			else
+			  {
+			    *strptr = (char *) wstr;
+			    wstr += strsize;
+			    ++strsize;
+			  }
+		      }
+		    else
+		      {
+			*strptr = (char *) wstr;
+			wstr += strsize;
+			strsize = newsize;
+		      }
+		  }
+
 		while (1)
 		  {
 		    size_t n;
@@ -754,41 +929,27 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #endif
 
 	  if (!(flags & SUPPRESS))
-	    ++done;
+	    {
+	      if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
+		{
+		  wchar_t *cp = (wchar_t *) realloc (*strptr,
+						     ((wstr
+						       - (wchar_t *) *strptr)
+						      * sizeof (wchar_t)));
+		  if (cp != NULL)
+		    *strptr = (char *) cp;
+		}
+	      strptr = NULL;
+
+	      ++done;
+	    }
 
 	  break;
 
 	case L_('s'):		/* Read a string.  */
 	  if (!(flags & LONG))
 	    {
-#define STRING_ARG(Str, Type)						      \
-	      do if (!(flags & SUPPRESS))				      \
-		{							      \
-		  if (flags & MALLOC)					      \
-		    {							      \
-		      /* The string is to be stored in a malloc'd buffer.  */ \
-		      /* For %mS using char ** is actually wrong, but	      \
-			 shouldn't make a difference on any arch glibc	      \
-			 supports and would unnecessarily complicate	      \
-			 things. */					      \
-		      strptr = ARG (char **);				      \
-		      if (strptr == NULL)				      \
-			conv_error ();					      \
-		      /* Allocate an initial buffer.  */		      \
-		      strsize = 100;					      \
-		      *strptr = (char *) malloc (strsize * sizeof (Type));    \
-		      Str = (Type *) *strptr;				      \
-		      if (Str != NULL)					      \
-			add_ptr_to_free (strptr);			      \
-		      else if (flags & POSIX_MALLOC)			      \
-			goto reteof;					      \
-		    }							      \
-		  else							      \
-		    Str = ARG (Type *);					      \
-		  if (Str == NULL)					      \
-		    conv_error ();					      \
-		} while (0)
-	      STRING_ARG (str, char);
+	      STRING_ARG (str, char, 100);
 
 	      c = inchar ();
 	      if (__builtin_expect (c == EOF, 0))
@@ -816,8 +977,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		    if (!(flags & SUPPRESS) && (flags & MALLOC)
 			&& str + MB_CUR_MAX >= *strptr + strsize)
 		      {
-			/* We have to enlarge the buffer if the `a' flag
-			   was given.  */
+			/* We have to enlarge the buffer if the `a' or `m'
+			   flag was given.  */
 			size_t strleng = str - *strptr;
 			char *newstr;
 
@@ -969,7 +1130,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #endif
 
 	    /* Wide character string.  */
-	    STRING_ARG (wstr, wchar_t);
+	    STRING_ARG (wstr, wchar_t, 100);
 
 	    c = inchar ();
 	    if (__builtin_expect (c == EOF,  0))
@@ -1002,7 +1163,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			if (wstr == NULL)
 			  {
 			    /* Can't allocate that much.  Last-ditch
-                               effort.  */
+			       effort.  */
 			    wstr = (wchar_t *) realloc (*strptr,
 							(strsize + 1)
 							* sizeof (wchar_t));
@@ -2120,9 +2281,9 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 
 	case L_('['):	/* Character class.  */
 	  if (flags & LONG)
-	    STRING_ARG (wstr, wchar_t);
+	    STRING_ARG (wstr, wchar_t, 100);
 	  else
-	    STRING_ARG (str, char);
+	    STRING_ARG (str, char, 100);
 
 	  if (*f == L_('^'))
 	    {