Blame gl/printf-parse.c

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