Blame glib/gnulib/printf-parse.c

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