Imported Upstream version 3.2.0
[debian/amanda] / gnulib / printf-parse.c
index 2e679809779bf325d6b193e7c403e0d30773a672..f612beb5b7ac11d1f165e2763cc62722a91723da 100644 (file)
@@ -1,9 +1,9 @@
 /* Formatted output to strings.
 /* Formatted output to strings.
-   Copyright (C) 1999-2000, 2002-2003, 2006-2007 Free Software Foundation, Inc.
+   Copyright (C) 1999-2000, 2002-2003, 2006-2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
    any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -49,7 +49,7 @@
 #include <stddef.h>
 
 /* Get intmax_t.  */
 #include <stddef.h>
 
 /* Get intmax_t.  */
-#ifdef IN_LIBINTL
+#if defined IN_LIBINTL || defined IN_LIBASPRINTF
 # if HAVE_STDINT_H_WITH_UINTMAX
 #  include <stdint.h>
 # endif
 # if HAVE_STDINT_H_WITH_UINTMAX
 #  include <stdint.h>
 # endif
@@ -63,6 +63,9 @@
 /* malloc(), realloc(), free().  */
 #include <stdlib.h>
 
 /* malloc(), realloc(), free().  */
 #include <stdlib.h>
 
+/* errno.  */
+#include <errno.h>
+
 /* Checked size_t computations.  */
 #include "xsize.h"
 
 /* Checked size_t computations.  */
 #include "xsize.h"
 
@@ -77,10 +80,10 @@ STATIC
 int
 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
 {
 int
 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
 {
-  const CHAR_T *cp = format;           /* pointer into format */
-  size_t arg_posn = 0;         /* number of regular arguments consumed */
-  size_t d_allocated;                  /* allocated elements of d->dir */
-  size_t a_allocated;                  /* allocated elements of a->arg */
+  const CHAR_T *cp = format;            /* pointer into format */
+  size_t arg_posn = 0;          /* number of regular arguments consumed */
+  size_t d_allocated;                   /* allocated elements of d->dir */
+  size_t a_allocated;                   /* allocated elements of a->arg */
   size_t max_width_length = 0;
   size_t max_precision_length = 0;
 
   size_t max_width_length = 0;
   size_t max_precision_length = 0;
 
@@ -89,470 +92,508 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
   d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
   if (d->dir == NULL)
     /* Out of memory.  */
   d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
   if (d->dir == NULL)
     /* Out of memory.  */
-    return -1;
+    goto out_of_memory_1;
 
   a->count = 0;
   a_allocated = 0;
   a->arg = NULL;
 
 #define REGISTER_ARG(_index_,_type_) \
 
   a->count = 0;
   a_allocated = 0;
   a->arg = NULL;
 
 #define REGISTER_ARG(_index_,_type_) \
-  {                                                                    \
-    size_t n = (_index_);                                              \
-    if (n >= a_allocated)                                              \
-      {                                                                        \
-       size_t memory_size;                                             \
-       argument *memory;                                               \
-                                                                       \
-       a_allocated = xtimes (a_allocated, 2);                          \
-       if (a_allocated <= n)                                           \
-         a_allocated = xsum (n, 1);                                    \
-       memory_size = xtimes (a_allocated, sizeof (argument));          \
-       if (size_overflow_p (memory_size))                              \
-         /* Overflow, would lead to out of memory.  */                 \
-         goto error;                                                   \
-       memory = (argument *) (a->arg                                   \
-                              ? realloc (a->arg, memory_size)          \
-                              : malloc (memory_size));                 \
-       if (memory == NULL)                                             \
-         /* Out of memory.  */                                         \
-         goto error;                                                   \
-       a->arg = memory;                                                \
-      }                                                                        \
-    while (a->count <= n)                                              \
-      a->arg[a->count++].type = TYPE_NONE;                             \
-    if (a->arg[n].type == TYPE_NONE)                                   \
-      a->arg[n].type = (_type_);                                       \
-    else if (a->arg[n].type != (_type_))                               \
-      /* Ambiguous type for positional argument.  */                   \
-      goto error;                                                      \
+  {                                                                     \
+    size_t n = (_index_);                                               \
+    if (n >= a_allocated)                                               \
+      {                                                                 \
+        size_t memory_size;                                             \
+        argument *memory;                                               \
+                                                                        \
+        a_allocated = xtimes (a_allocated, 2);                          \
+        if (a_allocated <= n)                                           \
+          a_allocated = xsum (n, 1);                                    \
+        memory_size = xtimes (a_allocated, sizeof (argument));          \
+        if (size_overflow_p (memory_size))                              \
+          /* Overflow, would lead to out of memory.  */                 \
+          goto out_of_memory;                                           \
+        memory = (argument *) (a->arg                                   \
+                               ? realloc (a->arg, memory_size)          \
+                               : malloc (memory_size));                 \
+        if (memory == NULL)                                             \
+          /* Out of memory.  */                                         \
+          goto out_of_memory;                                           \
+        a->arg = memory;                                                \
+      }                                                                 \
+    while (a->count <= n)                                               \
+      a->arg[a->count++].type = TYPE_NONE;                              \
+    if (a->arg[n].type == TYPE_NONE)                                    \
+      a->arg[n].type = (_type_);                                        \
+    else if (a->arg[n].type != (_type_))                                \
+      /* Ambiguous type for positional argument.  */                    \
+      goto error;                                                       \
   }
 
   while (*cp != '\0')
     {
       CHAR_T c = *cp++;
       if (c == '%')
   }
 
   while (*cp != '\0')
     {
       CHAR_T c = *cp++;
       if (c == '%')
-       {
-         size_t arg_index = ARG_NONE;
-         DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
-
-         /* Initialize the next directive.  */
-         dp->dir_start = cp - 1;
-         dp->flags = 0;
-         dp->width_start = NULL;
-         dp->width_end = NULL;
-         dp->width_arg_index = ARG_NONE;
-         dp->precision_start = NULL;
-         dp->precision_end = NULL;
-         dp->precision_arg_index = ARG_NONE;
-         dp->arg_index = ARG_NONE;
-
-         /* Test for positional argument.  */
-         if (*cp >= '0' && *cp <= '9')
-           {
-             const CHAR_T *np;
-
-             for (np = cp; *np >= '0' && *np <= '9'; np++)
-               ;
-             if (*np == '$')
-               {
-                 size_t n = 0;
-
-                 for (np = cp; *np >= '0' && *np <= '9'; np++)
-                   n = xsum (xtimes (n, 10), *np - '0');
-                 if (n == 0)
-                   /* Positional argument 0.  */
-                   goto error;
-                 if (size_overflow_p (n))
-                   /* n too large, would lead to out of memory later.  */
-                   goto error;
-                 arg_index = n - 1;
-                 cp = np + 1;
-               }
-           }
-
-         /* Read the flags.  */
-         for (;;)
-           {
-             if (*cp == '\'')
-               {
-                 dp->flags |= FLAG_GROUP;
-                 cp++;
-               }
-             else if (*cp == '-')
-               {
-                 dp->flags |= FLAG_LEFT;
-                 cp++;
-               }
-             else if (*cp == '+')
-               {
-                 dp->flags |= FLAG_SHOWSIGN;
-                 cp++;
-               }
-             else if (*cp == ' ')
-               {
-                 dp->flags |= FLAG_SPACE;
-                 cp++;
-               }
-             else if (*cp == '#')
-               {
-                 dp->flags |= FLAG_ALT;
-                 cp++;
-               }
-             else if (*cp == '0')
-               {
-                 dp->flags |= FLAG_ZERO;
-                 cp++;
-               }
-             else
-               break;
-           }
-
-         /* Parse the field width.  */
-         if (*cp == '*')
-           {
-             dp->width_start = cp;
-             cp++;
-             dp->width_end = cp;
-             if (max_width_length < 1)
-               max_width_length = 1;
-
-             /* Test for positional argument.  */
-             if (*cp >= '0' && *cp <= '9')
-               {
-                 const CHAR_T *np;
-
-                 for (np = cp; *np >= '0' && *np <= '9'; np++)
-                   ;
-                 if (*np == '$')
-                   {
-                     size_t n = 0;
-
-                     for (np = cp; *np >= '0' && *np <= '9'; np++)
-                       n = xsum (xtimes (n, 10), *np - '0');
-                     if (n == 0)
-                       /* Positional argument 0.  */
-                       goto error;
-                     if (size_overflow_p (n))
-                       /* n too large, would lead to out of memory later.  */
-                       goto error;
-                     dp->width_arg_index = n - 1;
-                     cp = np + 1;
-                   }
-               }
-             if (dp->width_arg_index == ARG_NONE)
-               {
-                 dp->width_arg_index = arg_posn++;
-                 if (dp->width_arg_index == ARG_NONE)
-                   /* arg_posn wrapped around.  */
-                   goto error;
-               }
-             REGISTER_ARG (dp->width_arg_index, TYPE_INT);
-           }
-         else if (*cp >= '0' && *cp <= '9')
-           {
-             size_t width_length;
-
-             dp->width_start = cp;
-             for (; *cp >= '0' && *cp <= '9'; cp++)
-               ;
-             dp->width_end = cp;
-             width_length = dp->width_end - dp->width_start;
-             if (max_width_length < width_length)
-               max_width_length = width_length;
-           }
-
-         /* Parse the precision.  */
-         if (*cp == '.')
-           {
-             cp++;
-             if (*cp == '*')
-               {
-                 dp->precision_start = cp - 1;
-                 cp++;
-                 dp->precision_end = cp;
-                 if (max_precision_length < 2)
-                   max_precision_length = 2;
-
-                 /* Test for positional argument.  */
-                 if (*cp >= '0' && *cp <= '9')
-                   {
-                     const CHAR_T *np;
-
-                     for (np = cp; *np >= '0' && *np <= '9'; np++)
-                       ;
-                     if (*np == '$')
-                       {
-                         size_t n = 0;
-
-                         for (np = cp; *np >= '0' && *np <= '9'; np++)
-                           n = xsum (xtimes (n, 10), *np - '0');
-                         if (n == 0)
-                           /* Positional argument 0.  */
-                           goto error;
-                         if (size_overflow_p (n))
-                           /* n too large, would lead to out of memory
-                              later.  */
-                           goto error;
-                         dp->precision_arg_index = n - 1;
-                         cp = np + 1;
-                       }
-                   }
-                 if (dp->precision_arg_index == ARG_NONE)
-                   {
-                     dp->precision_arg_index = arg_posn++;
-                     if (dp->precision_arg_index == ARG_NONE)
-                       /* arg_posn wrapped around.  */
-                       goto error;
-                   }
-                 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
-               }
-             else
-               {
-                 size_t precision_length;
-
-                 dp->precision_start = cp - 1;
-                 for (; *cp >= '0' && *cp <= '9'; cp++)
-                   ;
-                 dp->precision_end = cp;
-                 precision_length = dp->precision_end - dp->precision_start;
-                 if (max_precision_length < precision_length)
-                   max_precision_length = precision_length;
-               }
-           }
-
-         {
-           arg_type type;
-
-           /* Parse argument type/size specifiers.  */
-           {
-             int flags = 0;
-
-             for (;;)
-               {
-                 if (*cp == 'h')
-                   {
-                     flags |= (1 << (flags & 1));
-                     cp++;
-                   }
-                 else if (*cp == 'L')
-                   {
-                     flags |= 4;
-                     cp++;
-                   }
-                 else if (*cp == 'l')
-                   {
-                     flags += 8;
-                     cp++;
-                   }
-                 else if (*cp == 'j')
-                   {
-                     if (sizeof (intmax_t) > sizeof (long))
-                       {
-                         /* intmax_t = long long */
-                         flags += 16;
-                       }
-                     else if (sizeof (intmax_t) > sizeof (int))
-                       {
-                         /* intmax_t = long */
-                         flags += 8;
-                       }
-                     cp++;
-                   }
-                 else if (*cp == 'z' || *cp == 'Z')
-                   {
-                     /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
-                        because the warning facility in gcc-2.95.2 understands
-                        only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
-                     if (sizeof (size_t) > sizeof (long))
-                       {
-                         /* size_t = long long */
-                         flags += 16;
-                       }
-                     else if (sizeof (size_t) > sizeof (int))
-                       {
-                         /* size_t = long */
-                         flags += 8;
-                       }
-                     cp++;
-                   }
-                 else if (*cp == 't')
-                   {
-                     if (sizeof (ptrdiff_t) > sizeof (long))
-                       {
-                         /* ptrdiff_t = long long */
-                         flags += 16;
-                       }
-                     else if (sizeof (ptrdiff_t) > sizeof (int))
-                       {
-                         /* ptrdiff_t = long */
-                         flags += 8;
-                       }
-                     cp++;
-                   }
-                 else
-                   break;
-               }
-
-             /* Read the conversion character.  */
-             c = *cp++;
-             switch (c)
-               {
-               case 'd': case 'i':
+        {
+          size_t arg_index = ARG_NONE;
+          DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
+
+          /* Initialize the next directive.  */
+          dp->dir_start = cp - 1;
+          dp->flags = 0;
+          dp->width_start = NULL;
+          dp->width_end = NULL;
+          dp->width_arg_index = ARG_NONE;
+          dp->precision_start = NULL;
+          dp->precision_end = NULL;
+          dp->precision_arg_index = ARG_NONE;
+          dp->arg_index = ARG_NONE;
+
+          /* Test for positional argument.  */
+          if (*cp >= '0' && *cp <= '9')
+            {
+              const CHAR_T *np;
+
+              for (np = cp; *np >= '0' && *np <= '9'; np++)
+                ;
+              if (*np == '$')
+                {
+                  size_t n = 0;
+
+                  for (np = cp; *np >= '0' && *np <= '9'; np++)
+                    n = xsum (xtimes (n, 10), *np - '0');
+                  if (n == 0)
+                    /* Positional argument 0.  */
+                    goto error;
+                  if (size_overflow_p (n))
+                    /* n too large, would lead to out of memory later.  */
+                    goto error;
+                  arg_index = n - 1;
+                  cp = np + 1;
+                }
+            }
+
+          /* Read the flags.  */
+          for (;;)
+            {
+              if (*cp == '\'')
+                {
+                  dp->flags |= FLAG_GROUP;
+                  cp++;
+                }
+              else if (*cp == '-')
+                {
+                  dp->flags |= FLAG_LEFT;
+                  cp++;
+                }
+              else if (*cp == '+')
+                {
+                  dp->flags |= FLAG_SHOWSIGN;
+                  cp++;
+                }
+              else if (*cp == ' ')
+                {
+                  dp->flags |= FLAG_SPACE;
+                  cp++;
+                }
+              else if (*cp == '#')
+                {
+                  dp->flags |= FLAG_ALT;
+                  cp++;
+                }
+              else if (*cp == '0')
+                {
+                  dp->flags |= FLAG_ZERO;
+                  cp++;
+                }
+              else
+                break;
+            }
+
+          /* Parse the field width.  */
+          if (*cp == '*')
+            {
+              dp->width_start = cp;
+              cp++;
+              dp->width_end = cp;
+              if (max_width_length < 1)
+                max_width_length = 1;
+
+              /* Test for positional argument.  */
+              if (*cp >= '0' && *cp <= '9')
+                {
+                  const CHAR_T *np;
+
+                  for (np = cp; *np >= '0' && *np <= '9'; np++)
+                    ;
+                  if (*np == '$')
+                    {
+                      size_t n = 0;
+
+                      for (np = cp; *np >= '0' && *np <= '9'; np++)
+                        n = xsum (xtimes (n, 10), *np - '0');
+                      if (n == 0)
+                        /* Positional argument 0.  */
+                        goto error;
+                      if (size_overflow_p (n))
+                        /* n too large, would lead to out of memory later.  */
+                        goto error;
+                      dp->width_arg_index = n - 1;
+                      cp = np + 1;
+                    }
+                }
+              if (dp->width_arg_index == ARG_NONE)
+                {
+                  dp->width_arg_index = arg_posn++;
+                  if (dp->width_arg_index == ARG_NONE)
+                    /* arg_posn wrapped around.  */
+                    goto error;
+                }
+              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
+            }
+          else if (*cp >= '0' && *cp <= '9')
+            {
+              size_t width_length;
+
+              dp->width_start = cp;
+              for (; *cp >= '0' && *cp <= '9'; cp++)
+                ;
+              dp->width_end = cp;
+              width_length = dp->width_end - dp->width_start;
+              if (max_width_length < width_length)
+                max_width_length = width_length;
+            }
+
+          /* Parse the precision.  */
+          if (*cp == '.')
+            {
+              cp++;
+              if (*cp == '*')
+                {
+                  dp->precision_start = cp - 1;
+                  cp++;
+                  dp->precision_end = cp;
+                  if (max_precision_length < 2)
+                    max_precision_length = 2;
+
+                  /* Test for positional argument.  */
+                  if (*cp >= '0' && *cp <= '9')
+                    {
+                      const CHAR_T *np;
+
+                      for (np = cp; *np >= '0' && *np <= '9'; np++)
+                        ;
+                      if (*np == '$')
+                        {
+                          size_t n = 0;
+
+                          for (np = cp; *np >= '0' && *np <= '9'; np++)
+                            n = xsum (xtimes (n, 10), *np - '0');
+                          if (n == 0)
+                            /* Positional argument 0.  */
+                            goto error;
+                          if (size_overflow_p (n))
+                            /* n too large, would lead to out of memory
+                               later.  */
+                            goto error;
+                          dp->precision_arg_index = n - 1;
+                          cp = np + 1;
+                        }
+                    }
+                  if (dp->precision_arg_index == ARG_NONE)
+                    {
+                      dp->precision_arg_index = arg_posn++;
+                      if (dp->precision_arg_index == ARG_NONE)
+                        /* arg_posn wrapped around.  */
+                        goto error;
+                    }
+                  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
+                }
+              else
+                {
+                  size_t precision_length;
+
+                  dp->precision_start = cp - 1;
+                  for (; *cp >= '0' && *cp <= '9'; cp++)
+                    ;
+                  dp->precision_end = cp;
+                  precision_length = dp->precision_end - dp->precision_start;
+                  if (max_precision_length < precision_length)
+                    max_precision_length = precision_length;
+                }
+            }
+
+          {
+            arg_type type;
+
+            /* Parse argument type/size specifiers.  */
+            {
+              int flags = 0;
+
+              for (;;)
+                {
+                  if (*cp == 'h')
+                    {
+                      flags |= (1 << (flags & 1));
+                      cp++;
+                    }
+                  else if (*cp == 'L')
+                    {
+                      flags |= 4;
+                      cp++;
+                    }
+                  else if (*cp == 'l')
+                    {
+                      flags += 8;
+                      cp++;
+                    }
+                  else if (*cp == 'j')
+                    {
+                      if (sizeof (intmax_t) > sizeof (long))
+                        {
+                          /* intmax_t = long long */
+                          flags += 16;
+                        }
+                      else if (sizeof (intmax_t) > sizeof (int))
+                        {
+                          /* intmax_t = long */
+                          flags += 8;
+                        }
+                      cp++;
+                    }
+                  else if (*cp == 'z' || *cp == 'Z')
+                    {
+                      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
+                         because the warning facility in gcc-2.95.2 understands
+                         only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
+                      if (sizeof (size_t) > sizeof (long))
+                        {
+                          /* size_t = long long */
+                          flags += 16;
+                        }
+                      else if (sizeof (size_t) > sizeof (int))
+                        {
+                          /* size_t = long */
+                          flags += 8;
+                        }
+                      cp++;
+                    }
+                  else if (*cp == 't')
+                    {
+                      if (sizeof (ptrdiff_t) > sizeof (long))
+                        {
+                          /* ptrdiff_t = long long */
+                          flags += 16;
+                        }
+                      else if (sizeof (ptrdiff_t) > sizeof (int))
+                        {
+                          /* ptrdiff_t = long */
+                          flags += 8;
+                        }
+                      cp++;
+                    }
+#if defined __APPLE__ && defined __MACH__
+                  /* On MacOS X 10.3, PRIdMAX is defined as "qd".
+                     We cannot change it to "lld" because PRIdMAX must also
+                     be understood by the system's printf routines.  */
+                  else if (*cp == 'q')
+                    {
+                      if (64 / 8 > sizeof (long))
+                        {
+                          /* int64_t = long long */
+                          flags += 16;
+                        }
+                      else
+                        {
+                          /* int64_t = long */
+                          flags += 8;
+                        }
+                      cp++;
+                    }
+#endif
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+                  /* On native Win32, PRIdMAX is defined as "I64d".
+                     We cannot change it to "lld" because PRIdMAX must also
+                     be understood by the system's printf routines.  */
+                  else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
+                    {
+                      if (64 / 8 > sizeof (long))
+                        {
+                          /* __int64 = long long */
+                          flags += 16;
+                        }
+                      else
+                        {
+                          /* __int64 = long */
+                          flags += 8;
+                        }
+                      cp += 3;
+                    }
+#endif
+                  else
+                    break;
+                }
+
+              /* Read the conversion character.  */
+              c = *cp++;
+              switch (c)
+                {
+                case 'd': case 'i':
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                 /* If 'long long' exists and is larger than 'long':  */
-                 if (flags >= 16 || (flags & 4))
-                   type = TYPE_LONGLONGINT;
-                 else
+                  /* If 'long long' exists and is larger than 'long':  */
+                  if (flags >= 16 || (flags & 4))
+                    type = TYPE_LONGLONGINT;
+                  else
 #endif
 #endif
-                 /* If 'long long' exists and is the same as 'long', we parse
-                    "lld" into TYPE_LONGINT.  */
-                 if (flags >= 8)
-                   type = TYPE_LONGINT;
-                 else if (flags & 2)
-                   type = TYPE_SCHAR;
-                 else if (flags & 1)
-                   type = TYPE_SHORT;
-                 else
-                   type = TYPE_INT;
-                 break;
-               case 'o': case 'u': case 'x': case 'X':
+                  /* If 'long long' exists and is the same as 'long', we parse
+                     "lld" into TYPE_LONGINT.  */
+                  if (flags >= 8)
+                    type = TYPE_LONGINT;
+                  else if (flags & 2)
+                    type = TYPE_SCHAR;
+                  else if (flags & 1)
+                    type = TYPE_SHORT;
+                  else
+                    type = TYPE_INT;
+                  break;
+                case 'o': case 'u': case 'x': case 'X':
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                 /* If 'long long' exists and is larger than 'long':  */
-                 if (flags >= 16 || (flags & 4))
-                   type = TYPE_ULONGLONGINT;
-                 else
+                  /* If 'long long' exists and is larger than 'long':  */
+                  if (flags >= 16 || (flags & 4))
+                    type = TYPE_ULONGLONGINT;
+                  else
 #endif
 #endif
-                 /* If 'unsigned long long' exists and is the same as
-                    'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
-                 if (flags >= 8)
-                   type = TYPE_ULONGINT;
-                 else if (flags & 2)
-                   type = TYPE_UCHAR;
-                 else if (flags & 1)
-                   type = TYPE_USHORT;
-                 else
-                   type = TYPE_UINT;
-                 break;
-               case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
-               case 'a': case 'A':
-                 if (flags >= 16 || (flags & 4))
-                   type = TYPE_LONGDOUBLE;
-                 else
-                   type = TYPE_DOUBLE;
-                 break;
-               case 'c':
-                 if (flags >= 8)
+                  /* If 'unsigned long long' exists and is the same as
+                     'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
+                  if (flags >= 8)
+                    type = TYPE_ULONGINT;
+                  else if (flags & 2)
+                    type = TYPE_UCHAR;
+                  else if (flags & 1)
+                    type = TYPE_USHORT;
+                  else
+                    type = TYPE_UINT;
+                  break;
+                case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+                case 'a': case 'A':
+                  if (flags >= 16 || (flags & 4))
+                    type = TYPE_LONGDOUBLE;
+                  else
+                    type = TYPE_DOUBLE;
+                  break;
+                case 'c':
+                  if (flags >= 8)
 #if HAVE_WINT_T
 #if HAVE_WINT_T
-                   type = TYPE_WIDE_CHAR;
+                    type = TYPE_WIDE_CHAR;
 #else
 #else
-                   goto error;
+                    goto error;
 #endif
 #endif
-                 else
-                   type = TYPE_CHAR;
-                 break;
+                  else
+                    type = TYPE_CHAR;
+                  break;
 #if HAVE_WINT_T
 #if HAVE_WINT_T
-               case 'C':
-                 type = TYPE_WIDE_CHAR;
-                 c = 'c';
-                 break;
+                case 'C':
+                  type = TYPE_WIDE_CHAR;
+                  c = 'c';
+                  break;
 #endif
 #endif
-               case 's':
-                 if (flags >= 8)
+                case 's':
+                  if (flags >= 8)
 #if HAVE_WCHAR_T
 #if HAVE_WCHAR_T
-                   type = TYPE_WIDE_STRING;
+                    type = TYPE_WIDE_STRING;
 #else
 #else
-                   goto error;
+                    goto error;
 #endif
 #endif
-                 else
-                   type = TYPE_STRING;
-                 break;
+                  else
+                    type = TYPE_STRING;
+                  break;
 #if HAVE_WCHAR_T
 #if HAVE_WCHAR_T
-               case 'S':
-                 type = TYPE_WIDE_STRING;
-                 c = 's';
-                 break;
+                case 'S':
+                  type = TYPE_WIDE_STRING;
+                  c = 's';
+                  break;
 #endif
 #endif
-               case 'p':
-                 type = TYPE_POINTER;
-                 break;
-               case 'n':
+                case 'p':
+                  type = TYPE_POINTER;
+                  break;
+                case 'n':
 #if HAVE_LONG_LONG_INT
 #if HAVE_LONG_LONG_INT
-                 /* If 'long long' exists and is larger than 'long':  */
-                 if (flags >= 16 || (flags & 4))
-                   type = TYPE_COUNT_LONGLONGINT_POINTER;
-                 else
+                  /* If 'long long' exists and is larger than 'long':  */
+                  if (flags >= 16 || (flags & 4))
+                    type = TYPE_COUNT_LONGLONGINT_POINTER;
+                  else
 #endif
 #endif
-                 /* If 'long long' exists and is the same as 'long', we parse
-                    "lln" into TYPE_COUNT_LONGINT_POINTER.  */
-                 if (flags >= 8)
-                   type = TYPE_COUNT_LONGINT_POINTER;
-                 else if (flags & 2)
-                   type = TYPE_COUNT_SCHAR_POINTER;
-                 else if (flags & 1)
-                   type = TYPE_COUNT_SHORT_POINTER;
-                 else
-                   type = TYPE_COUNT_INT_POINTER;
-                 break;
+                  /* If 'long long' exists and is the same as 'long', we parse
+                     "lln" into TYPE_COUNT_LONGINT_POINTER.  */
+                  if (flags >= 8)
+                    type = TYPE_COUNT_LONGINT_POINTER;
+                  else if (flags & 2)
+                    type = TYPE_COUNT_SCHAR_POINTER;
+                  else if (flags & 1)
+                    type = TYPE_COUNT_SHORT_POINTER;
+                  else
+                    type = TYPE_COUNT_INT_POINTER;
+                  break;
 #if ENABLE_UNISTDIO
 #if ENABLE_UNISTDIO
-               /* The unistdio extensions.  */
-               case 'U':
-                 if (flags >= 16)
-                   type = TYPE_U32_STRING;
-                 else if (flags >= 8)
-                   type = TYPE_U16_STRING;
-                 else
-                   type = TYPE_U8_STRING;
-                 break;
+                /* The unistdio extensions.  */
+                case 'U':
+                  if (flags >= 16)
+                    type = TYPE_U32_STRING;
+                  else if (flags >= 8)
+                    type = TYPE_U16_STRING;
+                  else
+                    type = TYPE_U8_STRING;
+                  break;
 #endif
 #endif
-               case '%':
-                 type = TYPE_NONE;
-                 break;
-               default:
-                 /* Unknown conversion character.  */
-                 goto error;
-               }
-           }
-
-           if (type != TYPE_NONE)
-             {
-               dp->arg_index = arg_index;
-               if (dp->arg_index == ARG_NONE)
-                 {
-                   dp->arg_index = arg_posn++;
-                   if (dp->arg_index == ARG_NONE)
-                     /* arg_posn wrapped around.  */
-                     goto error;
-                 }
-               REGISTER_ARG (dp->arg_index, type);
-             }
-           dp->conversion = c;
-           dp->dir_end = cp;
-         }
-
-         d->count++;
-         if (d->count >= d_allocated)
-           {
-             size_t memory_size;
-             DIRECTIVE *memory;
-
-             d_allocated = xtimes (d_allocated, 2);
-             memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
-             if (size_overflow_p (memory_size))
-               /* Overflow, would lead to out of memory.  */
-               goto error;
-             memory = (DIRECTIVE *) realloc (d->dir, memory_size);
-             if (memory == NULL)
-               /* Out of memory.  */
-               goto error;
-             d->dir = memory;
-           }
-       }
+                case '%':
+                  type = TYPE_NONE;
+                  break;
+                default:
+                  /* Unknown conversion character.  */
+                  goto error;
+                }
+            }
+
+            if (type != TYPE_NONE)
+              {
+                dp->arg_index = arg_index;
+                if (dp->arg_index == ARG_NONE)
+                  {
+                    dp->arg_index = arg_posn++;
+                    if (dp->arg_index == ARG_NONE)
+                      /* arg_posn wrapped around.  */
+                      goto error;
+                  }
+                REGISTER_ARG (dp->arg_index, type);
+              }
+            dp->conversion = c;
+            dp->dir_end = cp;
+          }
+
+          d->count++;
+          if (d->count >= d_allocated)
+            {
+              size_t memory_size;
+              DIRECTIVE *memory;
+
+              d_allocated = xtimes (d_allocated, 2);
+              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
+              if (size_overflow_p (memory_size))
+                /* Overflow, would lead to out of memory.  */
+                goto out_of_memory;
+              memory = (DIRECTIVE *) realloc (d->dir, memory_size);
+              if (memory == NULL)
+                /* Out of memory.  */
+                goto out_of_memory;
+              d->dir = memory;
+            }
+        }
 #if CHAR_T_ONLY_ASCII
       else if (!c_isascii (c))
 #if CHAR_T_ONLY_ASCII
       else if (!c_isascii (c))
-       {
-         /* Non-ASCII character.  Not supported.  */
-         goto error;
-       }
+        {
+          /* Non-ASCII character.  Not supported.  */
+          goto error;
+        }
 #endif
     }
   d->dir[d->count].dir_start = cp;
 #endif
     }
   d->dir[d->count].dir_start = cp;
@@ -566,6 +607,16 @@ error:
     free (a->arg);
   if (d->dir)
     free (d->dir);
     free (a->arg);
   if (d->dir)
     free (d->dir);
+  errno = EINVAL;
+  return -1;
+
+out_of_memory:
+  if (a->arg)
+    free (a->arg);
+  if (d->dir)
+    free (d->dir);
+out_of_memory_1:
+  errno = ENOMEM;
   return -1;
 }
 
   return -1;
 }