Blame lib/printf-parse.c

Packit 33f14e
/* Formatted output to strings.
Packit 33f14e
   Copyright (C) 1999-2000, 2002-2003, 2006-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software; you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3, or (at your option)
Packit 33f14e
   any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License along
Packit 33f14e
   with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
/* This file can be parametrized with the following macros:
Packit 33f14e
     CHAR_T             The element type of the format string.
Packit 33f14e
     CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
Packit 33f14e
                        in the format string are ASCII.
Packit 33f14e
     DIRECTIVE          Structure denoting a format directive.
Packit 33f14e
                        Depends on CHAR_T.
Packit 33f14e
     DIRECTIVES         Structure denoting the set of format directives of a
Packit 33f14e
                        format string.  Depends on CHAR_T.
Packit 33f14e
     PRINTF_PARSE       Function that parses a format string.
Packit 33f14e
                        Depends on CHAR_T.
Packit 33f14e
     STATIC             Set to 'static' to declare the function static.
Packit 33f14e
     ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
Packit 33f14e
Packit 33f14e
#ifndef PRINTF_PARSE
Packit 33f14e
# include <config.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Specification.  */
Packit 33f14e
#ifndef PRINTF_PARSE
Packit 33f14e
# include "printf-parse.h"
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Default parameters.  */
Packit 33f14e
#ifndef PRINTF_PARSE
Packit 33f14e
# define PRINTF_PARSE printf_parse
Packit 33f14e
# define CHAR_T char
Packit 33f14e
# define DIRECTIVE char_directive
Packit 33f14e
# define DIRECTIVES char_directives
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Get size_t, NULL.  */
Packit 33f14e
#include <stddef.h>
Packit 33f14e
Packit 33f14e
/* Get intmax_t.  */
Packit 33f14e
#if defined IN_LIBINTL || defined IN_LIBASPRINTF
Packit 33f14e
# if HAVE_STDINT_H_WITH_UINTMAX
Packit 33f14e
#  include <stdint.h>
Packit 33f14e
# endif
Packit 33f14e
# if HAVE_INTTYPES_H_WITH_UINTMAX
Packit 33f14e
#  include <inttypes.h>
Packit 33f14e
# endif
Packit 33f14e
#else
Packit 33f14e
# include <stdint.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* malloc(), realloc(), free().  */
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
Packit 33f14e
/* memcpy().  */
Packit 33f14e
#include <string.h>
Packit 33f14e
Packit 33f14e
/* errno.  */
Packit 33f14e
#include <errno.h>
Packit 33f14e
Packit 33f14e
/* Checked size_t computations.  */
Packit 33f14e
#include "xsize.h"
Packit 33f14e
Packit 33f14e
#if CHAR_T_ONLY_ASCII
Packit 33f14e
/* c_isascii().  */
Packit 33f14e
# include "c-ctype.h"
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#ifdef STATIC
Packit 33f14e
STATIC
Packit 33f14e
#endif
Packit 33f14e
int
Packit 33f14e
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
Packit 33f14e
{
Packit 33f14e
  const CHAR_T *cp = format;    /* pointer into format */
Packit 33f14e
  size_t arg_posn = 0;          /* number of regular arguments consumed */
Packit 33f14e
  size_t d_allocated;           /* allocated elements of d->dir */
Packit 33f14e
  size_t a_allocated;           /* allocated elements of a->arg */
Packit 33f14e
  size_t max_width_length = 0;
Packit 33f14e
  size_t max_precision_length = 0;
Packit 33f14e
Packit 33f14e
  d->count = 0;
Packit 33f14e
  d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
Packit 33f14e
  d->dir = d->direct_alloc_dir;
Packit 33f14e
Packit 33f14e
  a->count = 0;
Packit 33f14e
  a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
Packit 33f14e
  a->arg = a->direct_alloc_arg;
Packit 33f14e
Packit 33f14e
#define REGISTER_ARG(_index_,_type_) \
Packit 33f14e
  {                                                                     \
Packit 33f14e
    size_t n = (_index_);                                               \
Packit 33f14e
    if (n >= a_allocated)                                               \
Packit 33f14e
      {                                                                 \
Packit 33f14e
        size_t memory_size;                                             \
Packit 33f14e
        argument *memory;                                               \
Packit 33f14e
                                                                        \
Packit 33f14e
        a_allocated = xtimes (a_allocated, 2);                          \
Packit 33f14e
        if (a_allocated <= n)                                           \
Packit 33f14e
          a_allocated = xsum (n, 1);                                    \
Packit 33f14e
        memory_size = xtimes (a_allocated, sizeof (argument));          \
Packit 33f14e
        if (size_overflow_p (memory_size))                              \
Packit 33f14e
          /* Overflow, would lead to out of memory.  */                 \
Packit 33f14e
          goto out_of_memory;                                           \
Packit 33f14e
        memory = (argument *) (a->arg != a->direct_alloc_arg            \
Packit 33f14e
                               ? realloc (a->arg, memory_size)          \
Packit 33f14e
                               : malloc (memory_size));                 \
Packit 33f14e
        if (memory == NULL)                                             \
Packit 33f14e
          /* Out of memory.  */                                         \
Packit 33f14e
          goto out_of_memory;                                           \
Packit 33f14e
        if (a->arg == a->direct_alloc_arg)                              \
Packit 33f14e
          memcpy (memory, a->arg, a->count * sizeof (argument));        \
Packit 33f14e
        a->arg = memory;                                                \
Packit 33f14e
      }                                                                 \
Packit 33f14e
    while (a->count <= n)                                               \
Packit 33f14e
      a->arg[a->count++].type = TYPE_NONE;                              \
Packit 33f14e
    if (a->arg[n].type == TYPE_NONE)                                    \
Packit 33f14e
      a->arg[n].type = (_type_);                                        \
Packit 33f14e
    else if (a->arg[n].type != (_type_))                                \
Packit 33f14e
      /* Ambiguous type for positional argument.  */                    \
Packit 33f14e
      goto error;                                                       \
Packit 33f14e
  }
Packit 33f14e
Packit 33f14e
  while (*cp != '\0')
Packit 33f14e
    {
Packit 33f14e
      CHAR_T c = *cp++;
Packit 33f14e
      if (c == '%')
Packit 33f14e
        {
Packit 33f14e
          size_t arg_index = ARG_NONE;
Packit 33f14e
          DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
Packit 33f14e
Packit 33f14e
          /* Initialize the next directive.  */
Packit 33f14e
          dp->dir_start = cp - 1;
Packit 33f14e
          dp->flags = 0;
Packit 33f14e
          dp->width_start = NULL;
Packit 33f14e
          dp->width_end = NULL;
Packit 33f14e
          dp->width_arg_index = ARG_NONE;
Packit 33f14e
          dp->precision_start = NULL;
Packit 33f14e
          dp->precision_end = NULL;
Packit 33f14e
          dp->precision_arg_index = ARG_NONE;
Packit 33f14e
          dp->arg_index = ARG_NONE;
Packit 33f14e
Packit 33f14e
          /* Test for positional argument.  */
Packit 33f14e
          if (*cp >= '0' && *cp <= '9')
Packit 33f14e
            {
Packit 33f14e
              const CHAR_T *np;
Packit 33f14e
Packit 33f14e
              for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                ;
Packit 33f14e
              if (*np == '$')
Packit 33f14e
                {
Packit 33f14e
                  size_t n = 0;
Packit 33f14e
Packit 33f14e
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                    n = xsum (xtimes (n, 10), *np - '0');
Packit 33f14e
                  if (n == 0)
Packit 33f14e
                    /* Positional argument 0.  */
Packit 33f14e
                    goto error;
Packit 33f14e
                  if (size_overflow_p (n))
Packit 33f14e
                    /* n too large, would lead to out of memory later.  */
Packit 33f14e
                    goto error;
Packit 33f14e
                  arg_index = n - 1;
Packit 33f14e
                  cp = np + 1;
Packit 33f14e
                }
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          /* Read the flags.  */
Packit 33f14e
          for (;;)
Packit 33f14e
            {
Packit 33f14e
              if (*cp == '\'')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_GROUP;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
              else if (*cp == '-')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_LEFT;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
              else if (*cp == '+')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_SHOWSIGN;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
              else if (*cp == ' ')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_SPACE;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
              else if (*cp == '#')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_ALT;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
              else if (*cp == '0')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_ZERO;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
#if __GLIBC__ >= 2 && !defined __UCLIBC__
Packit 33f14e
              else if (*cp == 'I')
Packit 33f14e
                {
Packit 33f14e
                  dp->flags |= FLAG_LOCALIZED;
Packit 33f14e
                  cp++;
Packit 33f14e
                }
Packit 33f14e
#endif
Packit 33f14e
              else
Packit 33f14e
                break;
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          /* Parse the field width.  */
Packit 33f14e
          if (*cp == '*')
Packit 33f14e
            {
Packit 33f14e
              dp->width_start = cp;
Packit 33f14e
              cp++;
Packit 33f14e
              dp->width_end = cp;
Packit 33f14e
              if (max_width_length < 1)
Packit 33f14e
                max_width_length = 1;
Packit 33f14e
Packit 33f14e
              /* Test for positional argument.  */
Packit 33f14e
              if (*cp >= '0' && *cp <= '9')
Packit 33f14e
                {
Packit 33f14e
                  const CHAR_T *np;
Packit 33f14e
Packit 33f14e
                  for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                    ;
Packit 33f14e
                  if (*np == '$')
Packit 33f14e
                    {
Packit 33f14e
                      size_t n = 0;
Packit 33f14e
Packit 33f14e
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                        n = xsum (xtimes (n, 10), *np - '0');
Packit 33f14e
                      if (n == 0)
Packit 33f14e
                        /* Positional argument 0.  */
Packit 33f14e
                        goto error;
Packit 33f14e
                      if (size_overflow_p (n))
Packit 33f14e
                        /* n too large, would lead to out of memory later.  */
Packit 33f14e
                        goto error;
Packit 33f14e
                      dp->width_arg_index = n - 1;
Packit 33f14e
                      cp = np + 1;
Packit 33f14e
                    }
Packit 33f14e
                }
Packit 33f14e
              if (dp->width_arg_index == ARG_NONE)
Packit 33f14e
                {
Packit 33f14e
                  dp->width_arg_index = arg_posn++;
Packit 33f14e
                  if (dp->width_arg_index == ARG_NONE)
Packit 33f14e
                    /* arg_posn wrapped around.  */
Packit 33f14e
                    goto error;
Packit 33f14e
                }
Packit 33f14e
              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
Packit 33f14e
            }
Packit 33f14e
          else if (*cp >= '0' && *cp <= '9')
Packit 33f14e
            {
Packit 33f14e
              size_t width_length;
Packit 33f14e
Packit 33f14e
              dp->width_start = cp;
Packit 33f14e
              for (; *cp >= '0' && *cp <= '9'; cp++)
Packit 33f14e
                ;
Packit 33f14e
              dp->width_end = cp;
Packit 33f14e
              width_length = dp->width_end - dp->width_start;
Packit 33f14e
              if (max_width_length < width_length)
Packit 33f14e
                max_width_length = width_length;
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          /* Parse the precision.  */
Packit 33f14e
          if (*cp == '.')
Packit 33f14e
            {
Packit 33f14e
              cp++;
Packit 33f14e
              if (*cp == '*')
Packit 33f14e
                {
Packit 33f14e
                  dp->precision_start = cp - 1;
Packit 33f14e
                  cp++;
Packit 33f14e
                  dp->precision_end = cp;
Packit 33f14e
                  if (max_precision_length < 2)
Packit 33f14e
                    max_precision_length = 2;
Packit 33f14e
Packit 33f14e
                  /* Test for positional argument.  */
Packit 33f14e
                  if (*cp >= '0' && *cp <= '9')
Packit 33f14e
                    {
Packit 33f14e
                      const CHAR_T *np;
Packit 33f14e
Packit 33f14e
                      for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                        ;
Packit 33f14e
                      if (*np == '$')
Packit 33f14e
                        {
Packit 33f14e
                          size_t n = 0;
Packit 33f14e
Packit 33f14e
                          for (np = cp; *np >= '0' && *np <= '9'; np++)
Packit 33f14e
                            n = xsum (xtimes (n, 10), *np - '0');
Packit 33f14e
                          if (n == 0)
Packit 33f14e
                            /* Positional argument 0.  */
Packit 33f14e
                            goto error;
Packit 33f14e
                          if (size_overflow_p (n))
Packit 33f14e
                            /* n too large, would lead to out of memory
Packit 33f14e
                               later.  */
Packit 33f14e
                            goto error;
Packit 33f14e
                          dp->precision_arg_index = n - 1;
Packit 33f14e
                          cp = np + 1;
Packit 33f14e
                        }
Packit 33f14e
                    }
Packit 33f14e
                  if (dp->precision_arg_index == ARG_NONE)
Packit 33f14e
                    {
Packit 33f14e
                      dp->precision_arg_index = arg_posn++;
Packit 33f14e
                      if (dp->precision_arg_index == ARG_NONE)
Packit 33f14e
                        /* arg_posn wrapped around.  */
Packit 33f14e
                        goto error;
Packit 33f14e
                    }
Packit 33f14e
                  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
Packit 33f14e
                }
Packit 33f14e
              else
Packit 33f14e
                {
Packit 33f14e
                  size_t precision_length;
Packit 33f14e
Packit 33f14e
                  dp->precision_start = cp - 1;
Packit 33f14e
                  for (; *cp >= '0' && *cp <= '9'; cp++)
Packit 33f14e
                    ;
Packit 33f14e
                  dp->precision_end = cp;
Packit 33f14e
                  precision_length = dp->precision_end - dp->precision_start;
Packit 33f14e
                  if (max_precision_length < precision_length)
Packit 33f14e
                    max_precision_length = precision_length;
Packit 33f14e
                }
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          {
Packit 33f14e
            arg_type type;
Packit 33f14e
Packit 33f14e
            /* Parse argument type/size specifiers.  */
Packit 33f14e
            {
Packit 33f14e
              int flags = 0;
Packit 33f14e
Packit 33f14e
              for (;;)
Packit 33f14e
                {
Packit 33f14e
                  if (*cp == 'h')
Packit 33f14e
                    {
Packit 33f14e
                      flags |= (1 << (flags & 1));
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
                  else if (*cp == 'L')
Packit 33f14e
                    {
Packit 33f14e
                      flags |= 4;
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
                  else if (*cp == 'l')
Packit 33f14e
                    {
Packit 33f14e
                      flags += 8;
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
                  else if (*cp == 'j')
Packit 33f14e
                    {
Packit 33f14e
                      if (sizeof (intmax_t) > sizeof (long))
Packit 33f14e
                        {
Packit 33f14e
                          /* intmax_t = long long */
Packit 33f14e
                          flags += 16;
Packit 33f14e
                        }
Packit 33f14e
                      else if (sizeof (intmax_t) > sizeof (int))
Packit 33f14e
                        {
Packit 33f14e
                          /* intmax_t = long */
Packit 33f14e
                          flags += 8;
Packit 33f14e
                        }
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
                  else if (*cp == 'z' || *cp == 'Z')
Packit 33f14e
                    {
Packit 33f14e
                      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
Packit 33f14e
                         because the warning facility in gcc-2.95.2 understands
Packit 33f14e
                         only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
Packit 33f14e
                      if (sizeof (size_t) > sizeof (long))
Packit 33f14e
                        {
Packit 33f14e
                          /* size_t = long long */
Packit 33f14e
                          flags += 16;
Packit 33f14e
                        }
Packit 33f14e
                      else if (sizeof (size_t) > sizeof (int))
Packit 33f14e
                        {
Packit 33f14e
                          /* size_t = long */
Packit 33f14e
                          flags += 8;
Packit 33f14e
                        }
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
                  else if (*cp == 't')
Packit 33f14e
                    {
Packit 33f14e
                      if (sizeof (ptrdiff_t) > sizeof (long))
Packit 33f14e
                        {
Packit 33f14e
                          /* ptrdiff_t = long long */
Packit 33f14e
                          flags += 16;
Packit 33f14e
                        }
Packit 33f14e
                      else if (sizeof (ptrdiff_t) > sizeof (int))
Packit 33f14e
                        {
Packit 33f14e
                          /* ptrdiff_t = long */
Packit 33f14e
                          flags += 8;
Packit 33f14e
                        }
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
#if defined __APPLE__ && defined __MACH__
Packit 33f14e
                  /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
Packit 33f14e
                     We cannot change it to "lld" because PRIdMAX must also
Packit 33f14e
                     be understood by the system's printf routines.  */
Packit 33f14e
                  else if (*cp == 'q')
Packit 33f14e
                    {
Packit 33f14e
                      if (64 / 8 > sizeof (long))
Packit 33f14e
                        {
Packit 33f14e
                          /* int64_t = long long */
Packit 33f14e
                          flags += 16;
Packit 33f14e
                        }
Packit 33f14e
                      else
Packit 33f14e
                        {
Packit 33f14e
                          /* int64_t = long */
Packit 33f14e
                          flags += 8;
Packit 33f14e
                        }
Packit 33f14e
                      cp++;
Packit 33f14e
                    }
Packit 33f14e
#endif
Packit 33f14e
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit 33f14e
                  /* On native Windows, PRIdMAX is defined as "I64d".
Packit 33f14e
                     We cannot change it to "lld" because PRIdMAX must also
Packit 33f14e
                     be understood by the system's printf routines.  */
Packit 33f14e
                  else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
Packit 33f14e
                    {
Packit 33f14e
                      if (64 / 8 > sizeof (long))
Packit 33f14e
                        {
Packit 33f14e
                          /* __int64 = long long */
Packit 33f14e
                          flags += 16;
Packit 33f14e
                        }
Packit 33f14e
                      else
Packit 33f14e
                        {
Packit 33f14e
                          /* __int64 = long */
Packit 33f14e
                          flags += 8;
Packit 33f14e
                        }
Packit 33f14e
                      cp += 3;
Packit 33f14e
                    }
Packit 33f14e
#endif
Packit 33f14e
                  else
Packit 33f14e
                    break;
Packit 33f14e
                }
Packit 33f14e
Packit 33f14e
              /* Read the conversion character.  */
Packit 33f14e
              c = *cp++;
Packit 33f14e
              switch (c)
Packit 33f14e
                {
Packit 33f14e
                case 'd': case 'i':
Packit 33f14e
#if HAVE_LONG_LONG_INT
Packit 33f14e
                  /* If 'long long' exists and is larger than 'long':  */
Packit 33f14e
                  if (flags >= 16 || (flags & 4))
Packit 33f14e
                    type = TYPE_LONGLONGINT;
Packit 33f14e
                  else
Packit 33f14e
#endif
Packit 33f14e
                  /* If 'long long' exists and is the same as 'long', we parse
Packit 33f14e
                     "lld" into TYPE_LONGINT.  */
Packit 33f14e
                  if (flags >= 8)
Packit 33f14e
                    type = TYPE_LONGINT;
Packit 33f14e
                  else if (flags & 2)
Packit 33f14e
                    type = TYPE_SCHAR;
Packit 33f14e
                  else if (flags & 1)
Packit 33f14e
                    type = TYPE_SHORT;
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_INT;
Packit 33f14e
                  break;
Packit 33f14e
                case 'o': case 'u': case 'x': case 'X':
Packit 33f14e
#if HAVE_LONG_LONG_INT
Packit 33f14e
                  /* If 'long long' exists and is larger than 'long':  */
Packit 33f14e
                  if (flags >= 16 || (flags & 4))
Packit 33f14e
                    type = TYPE_ULONGLONGINT;
Packit 33f14e
                  else
Packit 33f14e
#endif
Packit 33f14e
                  /* If 'unsigned long long' exists and is the same as
Packit 33f14e
                     'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
Packit 33f14e
                  if (flags >= 8)
Packit 33f14e
                    type = TYPE_ULONGINT;
Packit 33f14e
                  else if (flags & 2)
Packit 33f14e
                    type = TYPE_UCHAR;
Packit 33f14e
                  else if (flags & 1)
Packit 33f14e
                    type = TYPE_USHORT;
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_UINT;
Packit 33f14e
                  break;
Packit 33f14e
                case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
Packit 33f14e
                case 'a': case 'A':
Packit 33f14e
                  if (flags >= 16 || (flags & 4))
Packit 33f14e
                    type = TYPE_LONGDOUBLE;
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_DOUBLE;
Packit 33f14e
                  break;
Packit 33f14e
                case 'c':
Packit 33f14e
                  if (flags >= 8)
Packit 33f14e
#if HAVE_WINT_T
Packit 33f14e
                    type = TYPE_WIDE_CHAR;
Packit 33f14e
#else
Packit 33f14e
                    goto error;
Packit 33f14e
#endif
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_CHAR;
Packit 33f14e
                  break;
Packit 33f14e
#if HAVE_WINT_T
Packit 33f14e
                case 'C':
Packit 33f14e
                  type = TYPE_WIDE_CHAR;
Packit 33f14e
                  c = 'c';
Packit 33f14e
                  break;
Packit 33f14e
#endif
Packit 33f14e
                case 's':
Packit 33f14e
                  if (flags >= 8)
Packit 33f14e
#if HAVE_WCHAR_T
Packit 33f14e
                    type = TYPE_WIDE_STRING;
Packit 33f14e
#else
Packit 33f14e
                    goto error;
Packit 33f14e
#endif
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_STRING;
Packit 33f14e
                  break;
Packit 33f14e
#if HAVE_WCHAR_T
Packit 33f14e
                case 'S':
Packit 33f14e
                  type = TYPE_WIDE_STRING;
Packit 33f14e
                  c = 's';
Packit 33f14e
                  break;
Packit 33f14e
#endif
Packit 33f14e
                case 'p':
Packit 33f14e
                  type = TYPE_POINTER;
Packit 33f14e
                  break;
Packit 33f14e
                case 'n':
Packit 33f14e
#if HAVE_LONG_LONG_INT
Packit 33f14e
                  /* If 'long long' exists and is larger than 'long':  */
Packit 33f14e
                  if (flags >= 16 || (flags & 4))
Packit 33f14e
                    type = TYPE_COUNT_LONGLONGINT_POINTER;
Packit 33f14e
                  else
Packit 33f14e
#endif
Packit 33f14e
                  /* If 'long long' exists and is the same as 'long', we parse
Packit 33f14e
                     "lln" into TYPE_COUNT_LONGINT_POINTER.  */
Packit 33f14e
                  if (flags >= 8)
Packit 33f14e
                    type = TYPE_COUNT_LONGINT_POINTER;
Packit 33f14e
                  else if (flags & 2)
Packit 33f14e
                    type = TYPE_COUNT_SCHAR_POINTER;
Packit 33f14e
                  else if (flags & 1)
Packit 33f14e
                    type = TYPE_COUNT_SHORT_POINTER;
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_COUNT_INT_POINTER;
Packit 33f14e
                  break;
Packit 33f14e
#if ENABLE_UNISTDIO
Packit 33f14e
                /* The unistdio extensions.  */
Packit 33f14e
                case 'U':
Packit 33f14e
                  if (flags >= 16)
Packit 33f14e
                    type = TYPE_U32_STRING;
Packit 33f14e
                  else if (flags >= 8)
Packit 33f14e
                    type = TYPE_U16_STRING;
Packit 33f14e
                  else
Packit 33f14e
                    type = TYPE_U8_STRING;
Packit 33f14e
                  break;
Packit 33f14e
#endif
Packit 33f14e
                case '%':
Packit 33f14e
                  type = TYPE_NONE;
Packit 33f14e
                  break;
Packit 33f14e
                default:
Packit 33f14e
                  /* Unknown conversion character.  */
Packit 33f14e
                  goto error;
Packit 33f14e
                }
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
            if (type != TYPE_NONE)
Packit 33f14e
              {
Packit 33f14e
                dp->arg_index = arg_index;
Packit 33f14e
                if (dp->arg_index == ARG_NONE)
Packit 33f14e
                  {
Packit 33f14e
                    dp->arg_index = arg_posn++;
Packit 33f14e
                    if (dp->arg_index == ARG_NONE)
Packit 33f14e
                      /* arg_posn wrapped around.  */
Packit 33f14e
                      goto error;
Packit 33f14e
                  }
Packit 33f14e
                REGISTER_ARG (dp->arg_index, type);
Packit 33f14e
              }
Packit 33f14e
            dp->conversion = c;
Packit 33f14e
            dp->dir_end = cp;
Packit 33f14e
          }
Packit 33f14e
Packit 33f14e
          d->count++;
Packit 33f14e
          if (d->count >= d_allocated)
Packit 33f14e
            {
Packit 33f14e
              size_t memory_size;
Packit 33f14e
              DIRECTIVE *memory;
Packit 33f14e
Packit 33f14e
              d_allocated = xtimes (d_allocated, 2);
Packit 33f14e
              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
Packit 33f14e
              if (size_overflow_p (memory_size))
Packit 33f14e
                /* Overflow, would lead to out of memory.  */
Packit 33f14e
                goto out_of_memory;
Packit 33f14e
              memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
Packit 33f14e
                                      ? realloc (d->dir, memory_size)
Packit 33f14e
                                      : malloc (memory_size));
Packit 33f14e
              if (memory == NULL)
Packit 33f14e
                /* Out of memory.  */
Packit 33f14e
                goto out_of_memory;
Packit 33f14e
              if (d->dir == d->direct_alloc_dir)
Packit 33f14e
                memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
Packit 33f14e
              d->dir = memory;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
#if CHAR_T_ONLY_ASCII
Packit 33f14e
      else if (!c_isascii (c))
Packit 33f14e
        {
Packit 33f14e
          /* Non-ASCII character.  Not supported.  */
Packit 33f14e
          goto error;
Packit 33f14e
        }
Packit 33f14e
#endif
Packit 33f14e
    }
Packit 33f14e
  d->dir[d->count].dir_start = cp;
Packit 33f14e
Packit 33f14e
  d->max_width_length = max_width_length;
Packit 33f14e
  d->max_precision_length = max_precision_length;
Packit 33f14e
  return 0;
Packit 33f14e
Packit 33f14e
error:
Packit 33f14e
  if (a->arg != a->direct_alloc_arg)
Packit 33f14e
    free (a->arg);
Packit 33f14e
  if (d->dir != d->direct_alloc_dir)
Packit 33f14e
    free (d->dir);
Packit 33f14e
  errno = EINVAL;
Packit 33f14e
  return -1;
Packit 33f14e
Packit 33f14e
out_of_memory:
Packit 33f14e
  if (a->arg != a->direct_alloc_arg)
Packit 33f14e
    free (a->arg);
Packit 33f14e
  if (d->dir != d->direct_alloc_dir)
Packit 33f14e
    free (d->dir);
Packit 33f14e
  errno = ENOMEM;
Packit 33f14e
  return -1;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#undef PRINTF_PARSE
Packit 33f14e
#undef DIRECTIVES
Packit 33f14e
#undef DIRECTIVE
Packit 33f14e
#undef CHAR_T_ONLY_ASCII
Packit 33f14e
#undef CHAR_T