Blame gl/printf-parse.c

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