(_IO_vfscanf_internal): Don't handle %as, %aS and %a[ if
authordrepper <drepper>
Tue, 18 Sep 2007 18:56:29 +0000 (18:56 +0000)
committerdrepper <drepper>
Tue, 18 Sep 2007 18:56:29 +0000 (18:56 +0000)
_IO_FLAGS2_SCANF_STD is set in _flags2.

stdio-common/vfscanf.c

index ddf9a5e..e4728d0 100644 (file)
@@ -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_('^'))
            {