xref: /dflybsd-src/contrib/cvs-1.12/lib/printf-parse.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* Formatted output to strings.
286d7f5d3SJohn Marino    Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
386d7f5d3SJohn Marino 
486d7f5d3SJohn Marino    This program is free software; you can redistribute it and/or modify
586d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
686d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
786d7f5d3SJohn Marino    any later version.
886d7f5d3SJohn Marino 
986d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
1086d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1186d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1286d7f5d3SJohn Marino    GNU General Public License for more details.
1386d7f5d3SJohn Marino 
1486d7f5d3SJohn Marino    You should have received a copy of the GNU General Public License along
1586d7f5d3SJohn Marino    with this program; if not, write to the Free Software Foundation,
1686d7f5d3SJohn Marino    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
1986d7f5d3SJohn Marino # include <config.h>
2086d7f5d3SJohn Marino #endif
2186d7f5d3SJohn Marino 
2286d7f5d3SJohn Marino /* Specification.  */
2386d7f5d3SJohn Marino #if WIDE_CHAR_VERSION
2486d7f5d3SJohn Marino # include "wprintf-parse.h"
2586d7f5d3SJohn Marino #else
2686d7f5d3SJohn Marino # include "printf-parse.h"
2786d7f5d3SJohn Marino #endif
2886d7f5d3SJohn Marino 
2986d7f5d3SJohn Marino /* Get size_t, NULL.  */
3086d7f5d3SJohn Marino #include <stddef.h>
3186d7f5d3SJohn Marino 
3286d7f5d3SJohn Marino /* Get intmax_t.  */
3386d7f5d3SJohn Marino #if HAVE_STDINT_H_WITH_UINTMAX
3486d7f5d3SJohn Marino # include <stdint.h>
3586d7f5d3SJohn Marino #endif
3686d7f5d3SJohn Marino #if HAVE_INTTYPES_H_WITH_UINTMAX
3786d7f5d3SJohn Marino # include <inttypes.h>
3886d7f5d3SJohn Marino #endif
3986d7f5d3SJohn Marino 
4086d7f5d3SJohn Marino /* malloc(), realloc(), free().  */
4186d7f5d3SJohn Marino #include <stdlib.h>
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino /* Checked size_t computations.  */
4486d7f5d3SJohn Marino #include "xsize.h"
4586d7f5d3SJohn Marino 
4686d7f5d3SJohn Marino #if WIDE_CHAR_VERSION
4786d7f5d3SJohn Marino # define PRINTF_PARSE wprintf_parse
4886d7f5d3SJohn Marino # define CHAR_T wchar_t
4986d7f5d3SJohn Marino # define DIRECTIVE wchar_t_directive
5086d7f5d3SJohn Marino # define DIRECTIVES wchar_t_directives
5186d7f5d3SJohn Marino #else
5286d7f5d3SJohn Marino # define PRINTF_PARSE printf_parse
5386d7f5d3SJohn Marino # define CHAR_T char
5486d7f5d3SJohn Marino # define DIRECTIVE char_directive
5586d7f5d3SJohn Marino # define DIRECTIVES char_directives
5686d7f5d3SJohn Marino #endif
5786d7f5d3SJohn Marino 
5886d7f5d3SJohn Marino #ifdef STATIC
5986d7f5d3SJohn Marino STATIC
6086d7f5d3SJohn Marino #endif
6186d7f5d3SJohn Marino int
PRINTF_PARSE(const CHAR_T * format,DIRECTIVES * d,arguments * a)6286d7f5d3SJohn Marino PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
6386d7f5d3SJohn Marino {
6486d7f5d3SJohn Marino   const CHAR_T *cp = format;		/* pointer into format */
6586d7f5d3SJohn Marino   size_t arg_posn = 0;		/* number of regular arguments consumed */
6686d7f5d3SJohn Marino   size_t d_allocated;			/* allocated elements of d->dir */
6786d7f5d3SJohn Marino   size_t a_allocated;			/* allocated elements of a->arg */
6886d7f5d3SJohn Marino   size_t max_width_length = 0;
6986d7f5d3SJohn Marino   size_t max_precision_length = 0;
7086d7f5d3SJohn Marino 
7186d7f5d3SJohn Marino   d->count = 0;
7286d7f5d3SJohn Marino   d_allocated = 1;
7386d7f5d3SJohn Marino   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
7486d7f5d3SJohn Marino   if (d->dir == NULL)
7586d7f5d3SJohn Marino     /* Out of memory.  */
7686d7f5d3SJohn Marino     return -1;
7786d7f5d3SJohn Marino 
7886d7f5d3SJohn Marino   a->count = 0;
7986d7f5d3SJohn Marino   a_allocated = 0;
8086d7f5d3SJohn Marino   a->arg = NULL;
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino #define REGISTER_ARG(_index_,_type_) \
8386d7f5d3SJohn Marino   {									\
8486d7f5d3SJohn Marino     size_t n = (_index_);						\
8586d7f5d3SJohn Marino     if (n >= a_allocated)						\
8686d7f5d3SJohn Marino       {									\
8786d7f5d3SJohn Marino 	size_t memory_size;						\
8886d7f5d3SJohn Marino 	argument *memory;						\
8986d7f5d3SJohn Marino 									\
9086d7f5d3SJohn Marino 	a_allocated = xtimes (a_allocated, 2);				\
9186d7f5d3SJohn Marino 	if (a_allocated <= n)						\
9286d7f5d3SJohn Marino 	  a_allocated = xsum (n, 1);					\
9386d7f5d3SJohn Marino 	memory_size = xtimes (a_allocated, sizeof (argument));		\
9486d7f5d3SJohn Marino 	if (size_overflow_p (memory_size))				\
9586d7f5d3SJohn Marino 	  /* Overflow, would lead to out of memory.  */			\
9686d7f5d3SJohn Marino 	  goto error;							\
9786d7f5d3SJohn Marino 	memory = (a->arg						\
9886d7f5d3SJohn Marino 		  ? realloc (a->arg, memory_size)			\
9986d7f5d3SJohn Marino 		  : malloc (memory_size));				\
10086d7f5d3SJohn Marino 	if (memory == NULL)						\
10186d7f5d3SJohn Marino 	  /* Out of memory.  */						\
10286d7f5d3SJohn Marino 	  goto error;							\
10386d7f5d3SJohn Marino 	a->arg = memory;						\
10486d7f5d3SJohn Marino       }									\
10586d7f5d3SJohn Marino     while (a->count <= n)						\
10686d7f5d3SJohn Marino       a->arg[a->count++].type = TYPE_NONE;				\
10786d7f5d3SJohn Marino     if (a->arg[n].type == TYPE_NONE)					\
10886d7f5d3SJohn Marino       a->arg[n].type = (_type_);					\
10986d7f5d3SJohn Marino     else if (a->arg[n].type != (_type_))				\
11086d7f5d3SJohn Marino       /* Ambiguous type for positional argument.  */			\
11186d7f5d3SJohn Marino       goto error;							\
11286d7f5d3SJohn Marino   }
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino   while (*cp != '\0')
11586d7f5d3SJohn Marino     {
11686d7f5d3SJohn Marino       CHAR_T c = *cp++;
11786d7f5d3SJohn Marino       if (c == '%')
11886d7f5d3SJohn Marino 	{
11986d7f5d3SJohn Marino 	  size_t arg_index = ARG_NONE;
12086d7f5d3SJohn Marino 	  DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
12186d7f5d3SJohn Marino 
12286d7f5d3SJohn Marino 	  /* Initialize the next directive.  */
12386d7f5d3SJohn Marino 	  dp->dir_start = cp - 1;
12486d7f5d3SJohn Marino 	  dp->flags = 0;
12586d7f5d3SJohn Marino 	  dp->width_start = NULL;
12686d7f5d3SJohn Marino 	  dp->width_end = NULL;
12786d7f5d3SJohn Marino 	  dp->width_arg_index = ARG_NONE;
12886d7f5d3SJohn Marino 	  dp->precision_start = NULL;
12986d7f5d3SJohn Marino 	  dp->precision_end = NULL;
13086d7f5d3SJohn Marino 	  dp->precision_arg_index = ARG_NONE;
13186d7f5d3SJohn Marino 	  dp->arg_index = ARG_NONE;
13286d7f5d3SJohn Marino 
13386d7f5d3SJohn Marino 	  /* Test for positional argument.  */
13486d7f5d3SJohn Marino 	  if (*cp >= '0' && *cp <= '9')
13586d7f5d3SJohn Marino 	    {
13686d7f5d3SJohn Marino 	      const CHAR_T *np;
13786d7f5d3SJohn Marino 
13886d7f5d3SJohn Marino 	      for (np = cp; *np >= '0' && *np <= '9'; np++)
13986d7f5d3SJohn Marino 		;
14086d7f5d3SJohn Marino 	      if (*np == '$')
14186d7f5d3SJohn Marino 		{
14286d7f5d3SJohn Marino 		  size_t n = 0;
14386d7f5d3SJohn Marino 
14486d7f5d3SJohn Marino 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
14586d7f5d3SJohn Marino 		    n = xsum (xtimes (n, 10), *np - '0');
14686d7f5d3SJohn Marino 		  if (n == 0)
14786d7f5d3SJohn Marino 		    /* Positional argument 0.  */
14886d7f5d3SJohn Marino 		    goto error;
14986d7f5d3SJohn Marino 		  if (size_overflow_p (n))
15086d7f5d3SJohn Marino 		    /* n too large, would lead to out of memory later.  */
15186d7f5d3SJohn Marino 		    goto error;
15286d7f5d3SJohn Marino 		  arg_index = n - 1;
15386d7f5d3SJohn Marino 		  cp = np + 1;
15486d7f5d3SJohn Marino 		}
15586d7f5d3SJohn Marino 	    }
15686d7f5d3SJohn Marino 
15786d7f5d3SJohn Marino 	  /* Read the flags.  */
15886d7f5d3SJohn Marino 	  for (;;)
15986d7f5d3SJohn Marino 	    {
16086d7f5d3SJohn Marino 	      if (*cp == '\'')
16186d7f5d3SJohn Marino 		{
16286d7f5d3SJohn Marino 		  dp->flags |= FLAG_GROUP;
16386d7f5d3SJohn Marino 		  cp++;
16486d7f5d3SJohn Marino 		}
16586d7f5d3SJohn Marino 	      else if (*cp == '-')
16686d7f5d3SJohn Marino 		{
16786d7f5d3SJohn Marino 		  dp->flags |= FLAG_LEFT;
16886d7f5d3SJohn Marino 		  cp++;
16986d7f5d3SJohn Marino 		}
17086d7f5d3SJohn Marino 	      else if (*cp == '+')
17186d7f5d3SJohn Marino 		{
17286d7f5d3SJohn Marino 		  dp->flags |= FLAG_SHOWSIGN;
17386d7f5d3SJohn Marino 		  cp++;
17486d7f5d3SJohn Marino 		}
17586d7f5d3SJohn Marino 	      else if (*cp == ' ')
17686d7f5d3SJohn Marino 		{
17786d7f5d3SJohn Marino 		  dp->flags |= FLAG_SPACE;
17886d7f5d3SJohn Marino 		  cp++;
17986d7f5d3SJohn Marino 		}
18086d7f5d3SJohn Marino 	      else if (*cp == '#')
18186d7f5d3SJohn Marino 		{
18286d7f5d3SJohn Marino 		  dp->flags |= FLAG_ALT;
18386d7f5d3SJohn Marino 		  cp++;
18486d7f5d3SJohn Marino 		}
18586d7f5d3SJohn Marino 	      else if (*cp == '0')
18686d7f5d3SJohn Marino 		{
18786d7f5d3SJohn Marino 		  dp->flags |= FLAG_ZERO;
18886d7f5d3SJohn Marino 		  cp++;
18986d7f5d3SJohn Marino 		}
19086d7f5d3SJohn Marino 	      else
19186d7f5d3SJohn Marino 		break;
19286d7f5d3SJohn Marino 	    }
19386d7f5d3SJohn Marino 
19486d7f5d3SJohn Marino 	  /* Parse the field width.  */
19586d7f5d3SJohn Marino 	  if (*cp == '*')
19686d7f5d3SJohn Marino 	    {
19786d7f5d3SJohn Marino 	      dp->width_start = cp;
19886d7f5d3SJohn Marino 	      cp++;
19986d7f5d3SJohn Marino 	      dp->width_end = cp;
20086d7f5d3SJohn Marino 	      if (max_width_length < 1)
20186d7f5d3SJohn Marino 		max_width_length = 1;
20286d7f5d3SJohn Marino 
20386d7f5d3SJohn Marino 	      /* Test for positional argument.  */
20486d7f5d3SJohn Marino 	      if (*cp >= '0' && *cp <= '9')
20586d7f5d3SJohn Marino 		{
20686d7f5d3SJohn Marino 		  const CHAR_T *np;
20786d7f5d3SJohn Marino 
20886d7f5d3SJohn Marino 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
20986d7f5d3SJohn Marino 		    ;
21086d7f5d3SJohn Marino 		  if (*np == '$')
21186d7f5d3SJohn Marino 		    {
21286d7f5d3SJohn Marino 		      size_t n = 0;
21386d7f5d3SJohn Marino 
21486d7f5d3SJohn Marino 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
21586d7f5d3SJohn Marino 			n = xsum (xtimes (n, 10), *np - '0');
21686d7f5d3SJohn Marino 		      if (n == 0)
21786d7f5d3SJohn Marino 			/* Positional argument 0.  */
21886d7f5d3SJohn Marino 			goto error;
21986d7f5d3SJohn Marino 		      if (size_overflow_p (n))
22086d7f5d3SJohn Marino 			/* n too large, would lead to out of memory later.  */
22186d7f5d3SJohn Marino 			goto error;
22286d7f5d3SJohn Marino 		      dp->width_arg_index = n - 1;
22386d7f5d3SJohn Marino 		      cp = np + 1;
22486d7f5d3SJohn Marino 		    }
22586d7f5d3SJohn Marino 		}
22686d7f5d3SJohn Marino 	      if (dp->width_arg_index == ARG_NONE)
22786d7f5d3SJohn Marino 		{
22886d7f5d3SJohn Marino 		  dp->width_arg_index = arg_posn++;
22986d7f5d3SJohn Marino 		  if (dp->width_arg_index == ARG_NONE)
23086d7f5d3SJohn Marino 		    /* arg_posn wrapped around.  */
23186d7f5d3SJohn Marino 		    goto error;
23286d7f5d3SJohn Marino 		}
23386d7f5d3SJohn Marino 	      REGISTER_ARG (dp->width_arg_index, TYPE_INT);
23486d7f5d3SJohn Marino 	    }
23586d7f5d3SJohn Marino 	  else if (*cp >= '0' && *cp <= '9')
23686d7f5d3SJohn Marino 	    {
23786d7f5d3SJohn Marino 	      size_t width_length;
23886d7f5d3SJohn Marino 
23986d7f5d3SJohn Marino 	      dp->width_start = cp;
24086d7f5d3SJohn Marino 	      for (; *cp >= '0' && *cp <= '9'; cp++)
24186d7f5d3SJohn Marino 		;
24286d7f5d3SJohn Marino 	      dp->width_end = cp;
24386d7f5d3SJohn Marino 	      width_length = dp->width_end - dp->width_start;
24486d7f5d3SJohn Marino 	      if (max_width_length < width_length)
24586d7f5d3SJohn Marino 		max_width_length = width_length;
24686d7f5d3SJohn Marino 	    }
24786d7f5d3SJohn Marino 
24886d7f5d3SJohn Marino 	  /* Parse the precision.  */
24986d7f5d3SJohn Marino 	  if (*cp == '.')
25086d7f5d3SJohn Marino 	    {
25186d7f5d3SJohn Marino 	      cp++;
25286d7f5d3SJohn Marino 	      if (*cp == '*')
25386d7f5d3SJohn Marino 		{
25486d7f5d3SJohn Marino 		  dp->precision_start = cp - 1;
25586d7f5d3SJohn Marino 		  cp++;
25686d7f5d3SJohn Marino 		  dp->precision_end = cp;
25786d7f5d3SJohn Marino 		  if (max_precision_length < 2)
25886d7f5d3SJohn Marino 		    max_precision_length = 2;
25986d7f5d3SJohn Marino 
26086d7f5d3SJohn Marino 		  /* Test for positional argument.  */
26186d7f5d3SJohn Marino 		  if (*cp >= '0' && *cp <= '9')
26286d7f5d3SJohn Marino 		    {
26386d7f5d3SJohn Marino 		      const CHAR_T *np;
26486d7f5d3SJohn Marino 
26586d7f5d3SJohn Marino 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
26686d7f5d3SJohn Marino 			;
26786d7f5d3SJohn Marino 		      if (*np == '$')
26886d7f5d3SJohn Marino 			{
26986d7f5d3SJohn Marino 			  size_t n = 0;
27086d7f5d3SJohn Marino 
27186d7f5d3SJohn Marino 			  for (np = cp; *np >= '0' && *np <= '9'; np++)
27286d7f5d3SJohn Marino 			    n = xsum (xtimes (n, 10), *np - '0');
27386d7f5d3SJohn Marino 			  if (n == 0)
27486d7f5d3SJohn Marino 			    /* Positional argument 0.  */
27586d7f5d3SJohn Marino 			    goto error;
27686d7f5d3SJohn Marino 			  if (size_overflow_p (n))
27786d7f5d3SJohn Marino 			    /* n too large, would lead to out of memory
27886d7f5d3SJohn Marino 			       later.  */
27986d7f5d3SJohn Marino 			    goto error;
28086d7f5d3SJohn Marino 			  dp->precision_arg_index = n - 1;
28186d7f5d3SJohn Marino 			  cp = np + 1;
28286d7f5d3SJohn Marino 			}
28386d7f5d3SJohn Marino 		    }
28486d7f5d3SJohn Marino 		  if (dp->precision_arg_index == ARG_NONE)
28586d7f5d3SJohn Marino 		    {
28686d7f5d3SJohn Marino 		      dp->precision_arg_index = arg_posn++;
28786d7f5d3SJohn Marino 		      if (dp->precision_arg_index == ARG_NONE)
28886d7f5d3SJohn Marino 			/* arg_posn wrapped around.  */
28986d7f5d3SJohn Marino 			goto error;
29086d7f5d3SJohn Marino 		    }
29186d7f5d3SJohn Marino 		  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
29286d7f5d3SJohn Marino 		}
29386d7f5d3SJohn Marino 	      else
29486d7f5d3SJohn Marino 		{
29586d7f5d3SJohn Marino 		  size_t precision_length;
29686d7f5d3SJohn Marino 
29786d7f5d3SJohn Marino 		  dp->precision_start = cp - 1;
29886d7f5d3SJohn Marino 		  for (; *cp >= '0' && *cp <= '9'; cp++)
29986d7f5d3SJohn Marino 		    ;
30086d7f5d3SJohn Marino 		  dp->precision_end = cp;
30186d7f5d3SJohn Marino 		  precision_length = dp->precision_end - dp->precision_start;
30286d7f5d3SJohn Marino 		  if (max_precision_length < precision_length)
30386d7f5d3SJohn Marino 		    max_precision_length = precision_length;
30486d7f5d3SJohn Marino 		}
30586d7f5d3SJohn Marino 	    }
30686d7f5d3SJohn Marino 
30786d7f5d3SJohn Marino 	  {
30886d7f5d3SJohn Marino 	    arg_type type;
30986d7f5d3SJohn Marino 
31086d7f5d3SJohn Marino 	    /* Parse argument type/size specifiers.  */
31186d7f5d3SJohn Marino 	    {
31286d7f5d3SJohn Marino 	      int flags = 0;
31386d7f5d3SJohn Marino 
31486d7f5d3SJohn Marino 	      for (;;)
31586d7f5d3SJohn Marino 		{
31686d7f5d3SJohn Marino 		  if (*cp == 'h')
31786d7f5d3SJohn Marino 		    {
31886d7f5d3SJohn Marino 		      flags |= (1 << (flags & 1));
31986d7f5d3SJohn Marino 		      cp++;
32086d7f5d3SJohn Marino 		    }
32186d7f5d3SJohn Marino 		  else if (*cp == 'L')
32286d7f5d3SJohn Marino 		    {
32386d7f5d3SJohn Marino 		      flags |= 4;
32486d7f5d3SJohn Marino 		      cp++;
32586d7f5d3SJohn Marino 		    }
32686d7f5d3SJohn Marino 		  else if (*cp == 'l')
32786d7f5d3SJohn Marino 		    {
32886d7f5d3SJohn Marino 		      flags += 8;
32986d7f5d3SJohn Marino 		      cp++;
33086d7f5d3SJohn Marino 		    }
33186d7f5d3SJohn Marino #ifdef HAVE_INTMAX_T
33286d7f5d3SJohn Marino 		  else if (*cp == 'j')
33386d7f5d3SJohn Marino 		    {
33486d7f5d3SJohn Marino 		      if (sizeof (intmax_t) > sizeof (long))
33586d7f5d3SJohn Marino 			{
33686d7f5d3SJohn Marino 			  /* intmax_t = long long */
33786d7f5d3SJohn Marino 			  flags += 16;
33886d7f5d3SJohn Marino 			}
33986d7f5d3SJohn Marino 		      else if (sizeof (intmax_t) > sizeof (int))
34086d7f5d3SJohn Marino 			{
34186d7f5d3SJohn Marino 			  /* intmax_t = long */
34286d7f5d3SJohn Marino 			  flags += 8;
34386d7f5d3SJohn Marino 			}
34486d7f5d3SJohn Marino 		      cp++;
34586d7f5d3SJohn Marino 		    }
34686d7f5d3SJohn Marino #endif
34786d7f5d3SJohn Marino 		  else if (*cp == 'z' || *cp == 'Z')
34886d7f5d3SJohn Marino 		    {
34986d7f5d3SJohn Marino 		      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
35086d7f5d3SJohn Marino 			 because the warning facility in gcc-2.95.2 understands
35186d7f5d3SJohn Marino 			 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
35286d7f5d3SJohn Marino 		      if (sizeof (size_t) > sizeof (long))
35386d7f5d3SJohn Marino 			{
35486d7f5d3SJohn Marino 			  /* size_t = long long */
35586d7f5d3SJohn Marino 			  flags += 16;
35686d7f5d3SJohn Marino 			}
35786d7f5d3SJohn Marino 		      else if (sizeof (size_t) > sizeof (int))
35886d7f5d3SJohn Marino 			{
35986d7f5d3SJohn Marino 			  /* size_t = long */
36086d7f5d3SJohn Marino 			  flags += 8;
36186d7f5d3SJohn Marino 			}
36286d7f5d3SJohn Marino 		      cp++;
36386d7f5d3SJohn Marino 		    }
36486d7f5d3SJohn Marino 		  else if (*cp == 't')
36586d7f5d3SJohn Marino 		    {
36686d7f5d3SJohn Marino 		      if (sizeof (ptrdiff_t) > sizeof (long))
36786d7f5d3SJohn Marino 			{
36886d7f5d3SJohn Marino 			  /* ptrdiff_t = long long */
36986d7f5d3SJohn Marino 			  flags += 16;
37086d7f5d3SJohn Marino 			}
37186d7f5d3SJohn Marino 		      else if (sizeof (ptrdiff_t) > sizeof (int))
37286d7f5d3SJohn Marino 			{
37386d7f5d3SJohn Marino 			  /* ptrdiff_t = long */
37486d7f5d3SJohn Marino 			  flags += 8;
37586d7f5d3SJohn Marino 			}
37686d7f5d3SJohn Marino 		      cp++;
37786d7f5d3SJohn Marino 		    }
37886d7f5d3SJohn Marino 		  else
37986d7f5d3SJohn Marino 		    break;
38086d7f5d3SJohn Marino 		}
38186d7f5d3SJohn Marino 
38286d7f5d3SJohn Marino 	      /* Read the conversion character.  */
38386d7f5d3SJohn Marino 	      c = *cp++;
38486d7f5d3SJohn Marino 	      switch (c)
38586d7f5d3SJohn Marino 		{
38686d7f5d3SJohn Marino 		case 'd': case 'i':
38786d7f5d3SJohn Marino #ifdef HAVE_LONG_LONG
38886d7f5d3SJohn Marino 		  if (flags >= 16 || (flags & 4))
38986d7f5d3SJohn Marino 		    type = TYPE_LONGLONGINT;
39086d7f5d3SJohn Marino 		  else
39186d7f5d3SJohn Marino #endif
39286d7f5d3SJohn Marino 		  if (flags >= 8)
39386d7f5d3SJohn Marino 		    type = TYPE_LONGINT;
39486d7f5d3SJohn Marino 		  else if (flags & 2)
39586d7f5d3SJohn Marino 		    type = TYPE_SCHAR;
39686d7f5d3SJohn Marino 		  else if (flags & 1)
39786d7f5d3SJohn Marino 		    type = TYPE_SHORT;
39886d7f5d3SJohn Marino 		  else
39986d7f5d3SJohn Marino 		    type = TYPE_INT;
40086d7f5d3SJohn Marino 		  break;
40186d7f5d3SJohn Marino 		case 'o': case 'u': case 'x': case 'X':
40286d7f5d3SJohn Marino #ifdef HAVE_LONG_LONG
40386d7f5d3SJohn Marino 		  if (flags >= 16 || (flags & 4))
40486d7f5d3SJohn Marino 		    type = TYPE_ULONGLONGINT;
40586d7f5d3SJohn Marino 		  else
40686d7f5d3SJohn Marino #endif
40786d7f5d3SJohn Marino 		  if (flags >= 8)
40886d7f5d3SJohn Marino 		    type = TYPE_ULONGINT;
40986d7f5d3SJohn Marino 		  else if (flags & 2)
41086d7f5d3SJohn Marino 		    type = TYPE_UCHAR;
41186d7f5d3SJohn Marino 		  else if (flags & 1)
41286d7f5d3SJohn Marino 		    type = TYPE_USHORT;
41386d7f5d3SJohn Marino 		  else
41486d7f5d3SJohn Marino 		    type = TYPE_UINT;
41586d7f5d3SJohn Marino 		  break;
41686d7f5d3SJohn Marino 		case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
41786d7f5d3SJohn Marino 		case 'a': case 'A':
41886d7f5d3SJohn Marino #ifdef HAVE_LONG_DOUBLE
41986d7f5d3SJohn Marino 		  if (flags >= 16 || (flags & 4))
42086d7f5d3SJohn Marino 		    type = TYPE_LONGDOUBLE;
42186d7f5d3SJohn Marino 		  else
42286d7f5d3SJohn Marino #endif
42386d7f5d3SJohn Marino 		  type = TYPE_DOUBLE;
42486d7f5d3SJohn Marino 		  break;
42586d7f5d3SJohn Marino 		case 'c':
42686d7f5d3SJohn Marino 		  if (flags >= 8)
42786d7f5d3SJohn Marino #ifdef HAVE_WINT_T
42886d7f5d3SJohn Marino 		    type = TYPE_WIDE_CHAR;
42986d7f5d3SJohn Marino #else
43086d7f5d3SJohn Marino 		    goto error;
43186d7f5d3SJohn Marino #endif
43286d7f5d3SJohn Marino 		  else
43386d7f5d3SJohn Marino 		    type = TYPE_CHAR;
43486d7f5d3SJohn Marino 		  break;
43586d7f5d3SJohn Marino #ifdef HAVE_WINT_T
43686d7f5d3SJohn Marino 		case 'C':
43786d7f5d3SJohn Marino 		  type = TYPE_WIDE_CHAR;
43886d7f5d3SJohn Marino 		  c = 'c';
43986d7f5d3SJohn Marino 		  break;
44086d7f5d3SJohn Marino #endif
44186d7f5d3SJohn Marino 		case 's':
44286d7f5d3SJohn Marino 		  if (flags >= 8)
44386d7f5d3SJohn Marino #ifdef HAVE_WCHAR_T
44486d7f5d3SJohn Marino 		    type = TYPE_WIDE_STRING;
44586d7f5d3SJohn Marino #else
44686d7f5d3SJohn Marino 		    goto error;
44786d7f5d3SJohn Marino #endif
44886d7f5d3SJohn Marino 		  else
44986d7f5d3SJohn Marino 		    type = TYPE_STRING;
45086d7f5d3SJohn Marino 		  break;
45186d7f5d3SJohn Marino #ifdef HAVE_WCHAR_T
45286d7f5d3SJohn Marino 		case 'S':
45386d7f5d3SJohn Marino 		  type = TYPE_WIDE_STRING;
45486d7f5d3SJohn Marino 		  c = 's';
45586d7f5d3SJohn Marino 		  break;
45686d7f5d3SJohn Marino #endif
45786d7f5d3SJohn Marino 		case 'p':
45886d7f5d3SJohn Marino 		  type = TYPE_POINTER;
45986d7f5d3SJohn Marino 		  break;
46086d7f5d3SJohn Marino 		case 'n':
46186d7f5d3SJohn Marino #ifdef HAVE_LONG_LONG
46286d7f5d3SJohn Marino 		  if (flags >= 16 || (flags & 4))
46386d7f5d3SJohn Marino 		    type = TYPE_COUNT_LONGLONGINT_POINTER;
46486d7f5d3SJohn Marino 		  else
46586d7f5d3SJohn Marino #endif
46686d7f5d3SJohn Marino 		  if (flags >= 8)
46786d7f5d3SJohn Marino 		    type = TYPE_COUNT_LONGINT_POINTER;
46886d7f5d3SJohn Marino 		  else if (flags & 2)
46986d7f5d3SJohn Marino 		    type = TYPE_COUNT_SCHAR_POINTER;
47086d7f5d3SJohn Marino 		  else if (flags & 1)
47186d7f5d3SJohn Marino 		    type = TYPE_COUNT_SHORT_POINTER;
47286d7f5d3SJohn Marino 		  else
47386d7f5d3SJohn Marino 		    type = TYPE_COUNT_INT_POINTER;
47486d7f5d3SJohn Marino 		  break;
47586d7f5d3SJohn Marino 		case '%':
47686d7f5d3SJohn Marino 		  type = TYPE_NONE;
47786d7f5d3SJohn Marino 		  break;
47886d7f5d3SJohn Marino 		default:
47986d7f5d3SJohn Marino 		  /* Unknown conversion character.  */
48086d7f5d3SJohn Marino 		  goto error;
48186d7f5d3SJohn Marino 		}
48286d7f5d3SJohn Marino 	    }
48386d7f5d3SJohn Marino 
48486d7f5d3SJohn Marino 	    if (type != TYPE_NONE)
48586d7f5d3SJohn Marino 	      {
48686d7f5d3SJohn Marino 		dp->arg_index = arg_index;
48786d7f5d3SJohn Marino 		if (dp->arg_index == ARG_NONE)
48886d7f5d3SJohn Marino 		  {
48986d7f5d3SJohn Marino 		    dp->arg_index = arg_posn++;
49086d7f5d3SJohn Marino 		    if (dp->arg_index == ARG_NONE)
49186d7f5d3SJohn Marino 		      /* arg_posn wrapped around.  */
49286d7f5d3SJohn Marino 		      goto error;
49386d7f5d3SJohn Marino 		  }
49486d7f5d3SJohn Marino 		REGISTER_ARG (dp->arg_index, type);
49586d7f5d3SJohn Marino 	      }
49686d7f5d3SJohn Marino 	    dp->conversion = c;
49786d7f5d3SJohn Marino 	    dp->dir_end = cp;
49886d7f5d3SJohn Marino 	  }
49986d7f5d3SJohn Marino 
50086d7f5d3SJohn Marino 	  d->count++;
50186d7f5d3SJohn Marino 	  if (d->count >= d_allocated)
50286d7f5d3SJohn Marino 	    {
50386d7f5d3SJohn Marino 	      size_t memory_size;
50486d7f5d3SJohn Marino 	      DIRECTIVE *memory;
50586d7f5d3SJohn Marino 
50686d7f5d3SJohn Marino 	      d_allocated = xtimes (d_allocated, 2);
50786d7f5d3SJohn Marino 	      memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
50886d7f5d3SJohn Marino 	      if (size_overflow_p (memory_size))
50986d7f5d3SJohn Marino 		/* Overflow, would lead to out of memory.  */
51086d7f5d3SJohn Marino 		goto error;
51186d7f5d3SJohn Marino 	      memory = realloc (d->dir, memory_size);
51286d7f5d3SJohn Marino 	      if (memory == NULL)
51386d7f5d3SJohn Marino 		/* Out of memory.  */
51486d7f5d3SJohn Marino 		goto error;
51586d7f5d3SJohn Marino 	      d->dir = memory;
51686d7f5d3SJohn Marino 	    }
51786d7f5d3SJohn Marino 	}
51886d7f5d3SJohn Marino     }
51986d7f5d3SJohn Marino   d->dir[d->count].dir_start = cp;
52086d7f5d3SJohn Marino 
52186d7f5d3SJohn Marino   d->max_width_length = max_width_length;
52286d7f5d3SJohn Marino   d->max_precision_length = max_precision_length;
52386d7f5d3SJohn Marino   return 0;
52486d7f5d3SJohn Marino 
52586d7f5d3SJohn Marino error:
52686d7f5d3SJohn Marino   if (a->arg)
52786d7f5d3SJohn Marino     free (a->arg);
52886d7f5d3SJohn Marino   if (d->dir)
52986d7f5d3SJohn Marino     free (d->dir);
53086d7f5d3SJohn Marino   return -1;
53186d7f5d3SJohn Marino }
53286d7f5d3SJohn Marino 
53386d7f5d3SJohn Marino #undef DIRECTIVES
53486d7f5d3SJohn Marino #undef DIRECTIVE
53586d7f5d3SJohn Marino #undef CHAR_T
53686d7f5d3SJohn Marino #undef PRINTF_PARSE
537