Blame intl/printf-parse.c

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