1*63eb84d1Schristos /* Formatted output to strings.
2*63eb84d1Schristos    Copyright (C) 1999-2000, 2002-2003, 2006 Free Software Foundation, Inc.
3*63eb84d1Schristos 
4*63eb84d1Schristos    This program is free software; you can redistribute it and/or modify it
5*63eb84d1Schristos    under the terms of the GNU Library General Public License as published
6*63eb84d1Schristos    by the Free Software Foundation; either version 2, or (at your option)
7*63eb84d1Schristos    any later version.
8*63eb84d1Schristos 
9*63eb84d1Schristos    This program is distributed in the hope that it will be useful,
10*63eb84d1Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*63eb84d1Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*63eb84d1Schristos    Library General Public License for more details.
13*63eb84d1Schristos 
14*63eb84d1Schristos    You should have received a copy of the GNU Library General Public
15*63eb84d1Schristos    License along with this program; if not, write to the Free Software
16*63eb84d1Schristos    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17*63eb84d1Schristos    USA.  */
18*63eb84d1Schristos 
19*63eb84d1Schristos #include <config.h>
20*63eb84d1Schristos 
21*63eb84d1Schristos /* Specification.  */
22*63eb84d1Schristos #if WIDE_CHAR_VERSION
23*63eb84d1Schristos # include "wprintf-parse.h"
24*63eb84d1Schristos #else
25*63eb84d1Schristos # include "printf-parse.h"
26*63eb84d1Schristos #endif
27*63eb84d1Schristos 
28*63eb84d1Schristos /* Get size_t, NULL.  */
29*63eb84d1Schristos #include <stddef.h>
30*63eb84d1Schristos 
31*63eb84d1Schristos /* Get intmax_t.  */
32*63eb84d1Schristos #if HAVE_STDINT_H_WITH_UINTMAX
33*63eb84d1Schristos # include <stdint.h>
34*63eb84d1Schristos #endif
35*63eb84d1Schristos #if HAVE_INTTYPES_H_WITH_UINTMAX
36*63eb84d1Schristos # include <inttypes.h>
37*63eb84d1Schristos #endif
38*63eb84d1Schristos 
39*63eb84d1Schristos /* malloc(), realloc(), free().  */
40*63eb84d1Schristos #include <stdlib.h>
41*63eb84d1Schristos 
42*63eb84d1Schristos /* Checked size_t computations.  */
43*63eb84d1Schristos #include "xsize.h"
44*63eb84d1Schristos 
45*63eb84d1Schristos #if WIDE_CHAR_VERSION
46*63eb84d1Schristos # define PRINTF_PARSE wprintf_parse
47*63eb84d1Schristos # define CHAR_T wchar_t
48*63eb84d1Schristos # define DIRECTIVE wchar_t_directive
49*63eb84d1Schristos # define DIRECTIVES wchar_t_directives
50*63eb84d1Schristos #else
51*63eb84d1Schristos # define PRINTF_PARSE printf_parse
52*63eb84d1Schristos # define CHAR_T char
53*63eb84d1Schristos # define DIRECTIVE char_directive
54*63eb84d1Schristos # define DIRECTIVES char_directives
55*63eb84d1Schristos #endif
56*63eb84d1Schristos 
57*63eb84d1Schristos #ifdef STATIC
58*63eb84d1Schristos STATIC
59*63eb84d1Schristos #endif
60*63eb84d1Schristos int
PRINTF_PARSE(const CHAR_T * format,DIRECTIVES * d,arguments * a)61*63eb84d1Schristos PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
62*63eb84d1Schristos {
63*63eb84d1Schristos   const CHAR_T *cp = format;		/* pointer into format */
64*63eb84d1Schristos   size_t arg_posn = 0;		/* number of regular arguments consumed */
65*63eb84d1Schristos   size_t d_allocated;			/* allocated elements of d->dir */
66*63eb84d1Schristos   size_t a_allocated;			/* allocated elements of a->arg */
67*63eb84d1Schristos   size_t max_width_length = 0;
68*63eb84d1Schristos   size_t max_precision_length = 0;
69*63eb84d1Schristos 
70*63eb84d1Schristos   d->count = 0;
71*63eb84d1Schristos   d_allocated = 1;
72*63eb84d1Schristos   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
73*63eb84d1Schristos   if (d->dir == NULL)
74*63eb84d1Schristos     /* Out of memory.  */
75*63eb84d1Schristos     return -1;
76*63eb84d1Schristos 
77*63eb84d1Schristos   a->count = 0;
78*63eb84d1Schristos   a_allocated = 0;
79*63eb84d1Schristos   a->arg = NULL;
80*63eb84d1Schristos 
81*63eb84d1Schristos #define REGISTER_ARG(_index_,_type_) \
82*63eb84d1Schristos   {									\
83*63eb84d1Schristos     size_t n = (_index_);						\
84*63eb84d1Schristos     if (n >= a_allocated)						\
85*63eb84d1Schristos       {									\
86*63eb84d1Schristos 	size_t memory_size;						\
87*63eb84d1Schristos 	argument *memory;						\
88*63eb84d1Schristos 									\
89*63eb84d1Schristos 	a_allocated = xtimes (a_allocated, 2);				\
90*63eb84d1Schristos 	if (a_allocated <= n)						\
91*63eb84d1Schristos 	  a_allocated = xsum (n, 1);					\
92*63eb84d1Schristos 	memory_size = xtimes (a_allocated, sizeof (argument));		\
93*63eb84d1Schristos 	if (size_overflow_p (memory_size))				\
94*63eb84d1Schristos 	  /* Overflow, would lead to out of memory.  */			\
95*63eb84d1Schristos 	  goto error;							\
96*63eb84d1Schristos 	memory = (a->arg						\
97*63eb84d1Schristos 		  ? realloc (a->arg, memory_size)			\
98*63eb84d1Schristos 		  : malloc (memory_size));				\
99*63eb84d1Schristos 	if (memory == NULL)						\
100*63eb84d1Schristos 	  /* Out of memory.  */						\
101*63eb84d1Schristos 	  goto error;							\
102*63eb84d1Schristos 	a->arg = memory;						\
103*63eb84d1Schristos       }									\
104*63eb84d1Schristos     while (a->count <= n)						\
105*63eb84d1Schristos       a->arg[a->count++].type = TYPE_NONE;				\
106*63eb84d1Schristos     if (a->arg[n].type == TYPE_NONE)					\
107*63eb84d1Schristos       a->arg[n].type = (_type_);					\
108*63eb84d1Schristos     else if (a->arg[n].type != (_type_))				\
109*63eb84d1Schristos       /* Ambiguous type for positional argument.  */			\
110*63eb84d1Schristos       goto error;							\
111*63eb84d1Schristos   }
112*63eb84d1Schristos 
113*63eb84d1Schristos   while (*cp != '\0')
114*63eb84d1Schristos     {
115*63eb84d1Schristos       CHAR_T c = *cp++;
116*63eb84d1Schristos       if (c == '%')
117*63eb84d1Schristos 	{
118*63eb84d1Schristos 	  size_t arg_index = ARG_NONE;
119*63eb84d1Schristos 	  DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
120*63eb84d1Schristos 
121*63eb84d1Schristos 	  /* Initialize the next directive.  */
122*63eb84d1Schristos 	  dp->dir_start = cp - 1;
123*63eb84d1Schristos 	  dp->flags = 0;
124*63eb84d1Schristos 	  dp->width_start = NULL;
125*63eb84d1Schristos 	  dp->width_end = NULL;
126*63eb84d1Schristos 	  dp->width_arg_index = ARG_NONE;
127*63eb84d1Schristos 	  dp->precision_start = NULL;
128*63eb84d1Schristos 	  dp->precision_end = NULL;
129*63eb84d1Schristos 	  dp->precision_arg_index = ARG_NONE;
130*63eb84d1Schristos 	  dp->arg_index = ARG_NONE;
131*63eb84d1Schristos 
132*63eb84d1Schristos 	  /* Test for positional argument.  */
133*63eb84d1Schristos 	  if (*cp >= '0' && *cp <= '9')
134*63eb84d1Schristos 	    {
135*63eb84d1Schristos 	      const CHAR_T *np;
136*63eb84d1Schristos 
137*63eb84d1Schristos 	      for (np = cp; *np >= '0' && *np <= '9'; np++)
138*63eb84d1Schristos 		;
139*63eb84d1Schristos 	      if (*np == '$')
140*63eb84d1Schristos 		{
141*63eb84d1Schristos 		  size_t n = 0;
142*63eb84d1Schristos 
143*63eb84d1Schristos 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
144*63eb84d1Schristos 		    n = xsum (xtimes (n, 10), *np - '0');
145*63eb84d1Schristos 		  if (n == 0)
146*63eb84d1Schristos 		    /* Positional argument 0.  */
147*63eb84d1Schristos 		    goto error;
148*63eb84d1Schristos 		  if (size_overflow_p (n))
149*63eb84d1Schristos 		    /* n too large, would lead to out of memory later.  */
150*63eb84d1Schristos 		    goto error;
151*63eb84d1Schristos 		  arg_index = n - 1;
152*63eb84d1Schristos 		  cp = np + 1;
153*63eb84d1Schristos 		}
154*63eb84d1Schristos 	    }
155*63eb84d1Schristos 
156*63eb84d1Schristos 	  /* Read the flags.  */
157*63eb84d1Schristos 	  for (;;)
158*63eb84d1Schristos 	    {
159*63eb84d1Schristos 	      if (*cp == '\'')
160*63eb84d1Schristos 		{
161*63eb84d1Schristos 		  dp->flags |= FLAG_GROUP;
162*63eb84d1Schristos 		  cp++;
163*63eb84d1Schristos 		}
164*63eb84d1Schristos 	      else if (*cp == '-')
165*63eb84d1Schristos 		{
166*63eb84d1Schristos 		  dp->flags |= FLAG_LEFT;
167*63eb84d1Schristos 		  cp++;
168*63eb84d1Schristos 		}
169*63eb84d1Schristos 	      else if (*cp == '+')
170*63eb84d1Schristos 		{
171*63eb84d1Schristos 		  dp->flags |= FLAG_SHOWSIGN;
172*63eb84d1Schristos 		  cp++;
173*63eb84d1Schristos 		}
174*63eb84d1Schristos 	      else if (*cp == ' ')
175*63eb84d1Schristos 		{
176*63eb84d1Schristos 		  dp->flags |= FLAG_SPACE;
177*63eb84d1Schristos 		  cp++;
178*63eb84d1Schristos 		}
179*63eb84d1Schristos 	      else if (*cp == '#')
180*63eb84d1Schristos 		{
181*63eb84d1Schristos 		  dp->flags |= FLAG_ALT;
182*63eb84d1Schristos 		  cp++;
183*63eb84d1Schristos 		}
184*63eb84d1Schristos 	      else if (*cp == '0')
185*63eb84d1Schristos 		{
186*63eb84d1Schristos 		  dp->flags |= FLAG_ZERO;
187*63eb84d1Schristos 		  cp++;
188*63eb84d1Schristos 		}
189*63eb84d1Schristos 	      else
190*63eb84d1Schristos 		break;
191*63eb84d1Schristos 	    }
192*63eb84d1Schristos 
193*63eb84d1Schristos 	  /* Parse the field width.  */
194*63eb84d1Schristos 	  if (*cp == '*')
195*63eb84d1Schristos 	    {
196*63eb84d1Schristos 	      dp->width_start = cp;
197*63eb84d1Schristos 	      cp++;
198*63eb84d1Schristos 	      dp->width_end = cp;
199*63eb84d1Schristos 	      if (max_width_length < 1)
200*63eb84d1Schristos 		max_width_length = 1;
201*63eb84d1Schristos 
202*63eb84d1Schristos 	      /* Test for positional argument.  */
203*63eb84d1Schristos 	      if (*cp >= '0' && *cp <= '9')
204*63eb84d1Schristos 		{
205*63eb84d1Schristos 		  const CHAR_T *np;
206*63eb84d1Schristos 
207*63eb84d1Schristos 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
208*63eb84d1Schristos 		    ;
209*63eb84d1Schristos 		  if (*np == '$')
210*63eb84d1Schristos 		    {
211*63eb84d1Schristos 		      size_t n = 0;
212*63eb84d1Schristos 
213*63eb84d1Schristos 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
214*63eb84d1Schristos 			n = xsum (xtimes (n, 10), *np - '0');
215*63eb84d1Schristos 		      if (n == 0)
216*63eb84d1Schristos 			/* Positional argument 0.  */
217*63eb84d1Schristos 			goto error;
218*63eb84d1Schristos 		      if (size_overflow_p (n))
219*63eb84d1Schristos 			/* n too large, would lead to out of memory later.  */
220*63eb84d1Schristos 			goto error;
221*63eb84d1Schristos 		      dp->width_arg_index = n - 1;
222*63eb84d1Schristos 		      cp = np + 1;
223*63eb84d1Schristos 		    }
224*63eb84d1Schristos 		}
225*63eb84d1Schristos 	      if (dp->width_arg_index == ARG_NONE)
226*63eb84d1Schristos 		{
227*63eb84d1Schristos 		  dp->width_arg_index = arg_posn++;
228*63eb84d1Schristos 		  if (dp->width_arg_index == ARG_NONE)
229*63eb84d1Schristos 		    /* arg_posn wrapped around.  */
230*63eb84d1Schristos 		    goto error;
231*63eb84d1Schristos 		}
232*63eb84d1Schristos 	      REGISTER_ARG (dp->width_arg_index, TYPE_INT);
233*63eb84d1Schristos 	    }
234*63eb84d1Schristos 	  else if (*cp >= '0' && *cp <= '9')
235*63eb84d1Schristos 	    {
236*63eb84d1Schristos 	      size_t width_length;
237*63eb84d1Schristos 
238*63eb84d1Schristos 	      dp->width_start = cp;
239*63eb84d1Schristos 	      for (; *cp >= '0' && *cp <= '9'; cp++)
240*63eb84d1Schristos 		;
241*63eb84d1Schristos 	      dp->width_end = cp;
242*63eb84d1Schristos 	      width_length = dp->width_end - dp->width_start;
243*63eb84d1Schristos 	      if (max_width_length < width_length)
244*63eb84d1Schristos 		max_width_length = width_length;
245*63eb84d1Schristos 	    }
246*63eb84d1Schristos 
247*63eb84d1Schristos 	  /* Parse the precision.  */
248*63eb84d1Schristos 	  if (*cp == '.')
249*63eb84d1Schristos 	    {
250*63eb84d1Schristos 	      cp++;
251*63eb84d1Schristos 	      if (*cp == '*')
252*63eb84d1Schristos 		{
253*63eb84d1Schristos 		  dp->precision_start = cp - 1;
254*63eb84d1Schristos 		  cp++;
255*63eb84d1Schristos 		  dp->precision_end = cp;
256*63eb84d1Schristos 		  if (max_precision_length < 2)
257*63eb84d1Schristos 		    max_precision_length = 2;
258*63eb84d1Schristos 
259*63eb84d1Schristos 		  /* Test for positional argument.  */
260*63eb84d1Schristos 		  if (*cp >= '0' && *cp <= '9')
261*63eb84d1Schristos 		    {
262*63eb84d1Schristos 		      const CHAR_T *np;
263*63eb84d1Schristos 
264*63eb84d1Schristos 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
265*63eb84d1Schristos 			;
266*63eb84d1Schristos 		      if (*np == '$')
267*63eb84d1Schristos 			{
268*63eb84d1Schristos 			  size_t n = 0;
269*63eb84d1Schristos 
270*63eb84d1Schristos 			  for (np = cp; *np >= '0' && *np <= '9'; np++)
271*63eb84d1Schristos 			    n = xsum (xtimes (n, 10), *np - '0');
272*63eb84d1Schristos 			  if (n == 0)
273*63eb84d1Schristos 			    /* Positional argument 0.  */
274*63eb84d1Schristos 			    goto error;
275*63eb84d1Schristos 			  if (size_overflow_p (n))
276*63eb84d1Schristos 			    /* n too large, would lead to out of memory
277*63eb84d1Schristos 			       later.  */
278*63eb84d1Schristos 			    goto error;
279*63eb84d1Schristos 			  dp->precision_arg_index = n - 1;
280*63eb84d1Schristos 			  cp = np + 1;
281*63eb84d1Schristos 			}
282*63eb84d1Schristos 		    }
283*63eb84d1Schristos 		  if (dp->precision_arg_index == ARG_NONE)
284*63eb84d1Schristos 		    {
285*63eb84d1Schristos 		      dp->precision_arg_index = arg_posn++;
286*63eb84d1Schristos 		      if (dp->precision_arg_index == ARG_NONE)
287*63eb84d1Schristos 			/* arg_posn wrapped around.  */
288*63eb84d1Schristos 			goto error;
289*63eb84d1Schristos 		    }
290*63eb84d1Schristos 		  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
291*63eb84d1Schristos 		}
292*63eb84d1Schristos 	      else
293*63eb84d1Schristos 		{
294*63eb84d1Schristos 		  size_t precision_length;
295*63eb84d1Schristos 
296*63eb84d1Schristos 		  dp->precision_start = cp - 1;
297*63eb84d1Schristos 		  for (; *cp >= '0' && *cp <= '9'; cp++)
298*63eb84d1Schristos 		    ;
299*63eb84d1Schristos 		  dp->precision_end = cp;
300*63eb84d1Schristos 		  precision_length = dp->precision_end - dp->precision_start;
301*63eb84d1Schristos 		  if (max_precision_length < precision_length)
302*63eb84d1Schristos 		    max_precision_length = precision_length;
303*63eb84d1Schristos 		}
304*63eb84d1Schristos 	    }
305*63eb84d1Schristos 
306*63eb84d1Schristos 	  {
307*63eb84d1Schristos 	    arg_type type;
308*63eb84d1Schristos 
309*63eb84d1Schristos 	    /* Parse argument type/size specifiers.  */
310*63eb84d1Schristos 	    {
311*63eb84d1Schristos 	      int flags = 0;
312*63eb84d1Schristos 
313*63eb84d1Schristos 	      for (;;)
314*63eb84d1Schristos 		{
315*63eb84d1Schristos 		  if (*cp == 'h')
316*63eb84d1Schristos 		    {
317*63eb84d1Schristos 		      flags |= (1 << (flags & 1));
318*63eb84d1Schristos 		      cp++;
319*63eb84d1Schristos 		    }
320*63eb84d1Schristos 		  else if (*cp == 'L')
321*63eb84d1Schristos 		    {
322*63eb84d1Schristos 		      flags |= 4;
323*63eb84d1Schristos 		      cp++;
324*63eb84d1Schristos 		    }
325*63eb84d1Schristos 		  else if (*cp == 'l')
326*63eb84d1Schristos 		    {
327*63eb84d1Schristos 		      flags += 8;
328*63eb84d1Schristos 		      cp++;
329*63eb84d1Schristos 		    }
330*63eb84d1Schristos #ifdef HAVE_INTMAX_T
331*63eb84d1Schristos 		  else if (*cp == 'j')
332*63eb84d1Schristos 		    {
333*63eb84d1Schristos 		      if (sizeof (intmax_t) > sizeof (long))
334*63eb84d1Schristos 			{
335*63eb84d1Schristos 			  /* intmax_t = long long */
336*63eb84d1Schristos 			  flags += 16;
337*63eb84d1Schristos 			}
338*63eb84d1Schristos 		      else if (sizeof (intmax_t) > sizeof (int))
339*63eb84d1Schristos 			{
340*63eb84d1Schristos 			  /* intmax_t = long */
341*63eb84d1Schristos 			  flags += 8;
342*63eb84d1Schristos 			}
343*63eb84d1Schristos 		      cp++;
344*63eb84d1Schristos 		    }
345*63eb84d1Schristos #endif
346*63eb84d1Schristos 		  else if (*cp == 'z' || *cp == 'Z')
347*63eb84d1Schristos 		    {
348*63eb84d1Schristos 		      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
349*63eb84d1Schristos 			 because the warning facility in gcc-2.95.2 understands
350*63eb84d1Schristos 			 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
351*63eb84d1Schristos 		      if (sizeof (size_t) > sizeof (long))
352*63eb84d1Schristos 			{
353*63eb84d1Schristos 			  /* size_t = long long */
354*63eb84d1Schristos 			  flags += 16;
355*63eb84d1Schristos 			}
356*63eb84d1Schristos 		      else if (sizeof (size_t) > sizeof (int))
357*63eb84d1Schristos 			{
358*63eb84d1Schristos 			  /* size_t = long */
359*63eb84d1Schristos 			  flags += 8;
360*63eb84d1Schristos 			}
361*63eb84d1Schristos 		      cp++;
362*63eb84d1Schristos 		    }
363*63eb84d1Schristos 		  else if (*cp == 't')
364*63eb84d1Schristos 		    {
365*63eb84d1Schristos 		      if (sizeof (ptrdiff_t) > sizeof (long))
366*63eb84d1Schristos 			{
367*63eb84d1Schristos 			  /* ptrdiff_t = long long */
368*63eb84d1Schristos 			  flags += 16;
369*63eb84d1Schristos 			}
370*63eb84d1Schristos 		      else if (sizeof (ptrdiff_t) > sizeof (int))
371*63eb84d1Schristos 			{
372*63eb84d1Schristos 			  /* ptrdiff_t = long */
373*63eb84d1Schristos 			  flags += 8;
374*63eb84d1Schristos 			}
375*63eb84d1Schristos 		      cp++;
376*63eb84d1Schristos 		    }
377*63eb84d1Schristos 		  else
378*63eb84d1Schristos 		    break;
379*63eb84d1Schristos 		}
380*63eb84d1Schristos 
381*63eb84d1Schristos 	      /* Read the conversion character.  */
382*63eb84d1Schristos 	      c = *cp++;
383*63eb84d1Schristos 	      switch (c)
384*63eb84d1Schristos 		{
385*63eb84d1Schristos 		case 'd': case 'i':
386*63eb84d1Schristos #ifdef HAVE_LONG_LONG_INT
387*63eb84d1Schristos 		  /* If 'long long' exists and is larger than 'long':  */
388*63eb84d1Schristos 		  if (flags >= 16 || (flags & 4))
389*63eb84d1Schristos 		    type = TYPE_LONGLONGINT;
390*63eb84d1Schristos 		  else
391*63eb84d1Schristos #endif
392*63eb84d1Schristos 		  /* If 'long long' exists and is the same as 'long', we parse
393*63eb84d1Schristos 		     "lld" into TYPE_LONGINT.  */
394*63eb84d1Schristos 		  if (flags >= 8)
395*63eb84d1Schristos 		    type = TYPE_LONGINT;
396*63eb84d1Schristos 		  else if (flags & 2)
397*63eb84d1Schristos 		    type = TYPE_SCHAR;
398*63eb84d1Schristos 		  else if (flags & 1)
399*63eb84d1Schristos 		    type = TYPE_SHORT;
400*63eb84d1Schristos 		  else
401*63eb84d1Schristos 		    type = TYPE_INT;
402*63eb84d1Schristos 		  break;
403*63eb84d1Schristos 		case 'o': case 'u': case 'x': case 'X':
404*63eb84d1Schristos #ifdef HAVE_LONG_LONG_INT
405*63eb84d1Schristos 		  /* If 'long long' exists and is larger than 'long':  */
406*63eb84d1Schristos 		  if (flags >= 16 || (flags & 4))
407*63eb84d1Schristos 		    type = TYPE_ULONGLONGINT;
408*63eb84d1Schristos 		  else
409*63eb84d1Schristos #endif
410*63eb84d1Schristos 		  /* If 'unsigned long long' exists and is the same as
411*63eb84d1Schristos 		     'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
412*63eb84d1Schristos 		  if (flags >= 8)
413*63eb84d1Schristos 		    type = TYPE_ULONGINT;
414*63eb84d1Schristos 		  else if (flags & 2)
415*63eb84d1Schristos 		    type = TYPE_UCHAR;
416*63eb84d1Schristos 		  else if (flags & 1)
417*63eb84d1Schristos 		    type = TYPE_USHORT;
418*63eb84d1Schristos 		  else
419*63eb84d1Schristos 		    type = TYPE_UINT;
420*63eb84d1Schristos 		  break;
421*63eb84d1Schristos 		case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
422*63eb84d1Schristos 		case 'a': case 'A':
423*63eb84d1Schristos #ifdef HAVE_LONG_DOUBLE
424*63eb84d1Schristos 		  if (flags >= 16 || (flags & 4))
425*63eb84d1Schristos 		    type = TYPE_LONGDOUBLE;
426*63eb84d1Schristos 		  else
427*63eb84d1Schristos #endif
428*63eb84d1Schristos 		  type = TYPE_DOUBLE;
429*63eb84d1Schristos 		  break;
430*63eb84d1Schristos 		case 'c':
431*63eb84d1Schristos 		  if (flags >= 8)
432*63eb84d1Schristos #ifdef HAVE_WINT_T
433*63eb84d1Schristos 		    type = TYPE_WIDE_CHAR;
434*63eb84d1Schristos #else
435*63eb84d1Schristos 		    goto error;
436*63eb84d1Schristos #endif
437*63eb84d1Schristos 		  else
438*63eb84d1Schristos 		    type = TYPE_CHAR;
439*63eb84d1Schristos 		  break;
440*63eb84d1Schristos #ifdef HAVE_WINT_T
441*63eb84d1Schristos 		case 'C':
442*63eb84d1Schristos 		  type = TYPE_WIDE_CHAR;
443*63eb84d1Schristos 		  c = 'c';
444*63eb84d1Schristos 		  break;
445*63eb84d1Schristos #endif
446*63eb84d1Schristos 		case 's':
447*63eb84d1Schristos 		  if (flags >= 8)
448*63eb84d1Schristos #ifdef HAVE_WCHAR_T
449*63eb84d1Schristos 		    type = TYPE_WIDE_STRING;
450*63eb84d1Schristos #else
451*63eb84d1Schristos 		    goto error;
452*63eb84d1Schristos #endif
453*63eb84d1Schristos 		  else
454*63eb84d1Schristos 		    type = TYPE_STRING;
455*63eb84d1Schristos 		  break;
456*63eb84d1Schristos #ifdef HAVE_WCHAR_T
457*63eb84d1Schristos 		case 'S':
458*63eb84d1Schristos 		  type = TYPE_WIDE_STRING;
459*63eb84d1Schristos 		  c = 's';
460*63eb84d1Schristos 		  break;
461*63eb84d1Schristos #endif
462*63eb84d1Schristos 		case 'p':
463*63eb84d1Schristos 		  type = TYPE_POINTER;
464*63eb84d1Schristos 		  break;
465*63eb84d1Schristos 		case 'n':
466*63eb84d1Schristos #ifdef HAVE_LONG_LONG_INT
467*63eb84d1Schristos 		  /* If 'long long' exists and is larger than 'long':  */
468*63eb84d1Schristos 		  if (flags >= 16 || (flags & 4))
469*63eb84d1Schristos 		    type = TYPE_COUNT_LONGLONGINT_POINTER;
470*63eb84d1Schristos 		  else
471*63eb84d1Schristos #endif
472*63eb84d1Schristos 		  /* If 'long long' exists and is the same as 'long', we parse
473*63eb84d1Schristos 		     "lln" into TYPE_COUNT_LONGINT_POINTER.  */
474*63eb84d1Schristos 		  if (flags >= 8)
475*63eb84d1Schristos 		    type = TYPE_COUNT_LONGINT_POINTER;
476*63eb84d1Schristos 		  else if (flags & 2)
477*63eb84d1Schristos 		    type = TYPE_COUNT_SCHAR_POINTER;
478*63eb84d1Schristos 		  else if (flags & 1)
479*63eb84d1Schristos 		    type = TYPE_COUNT_SHORT_POINTER;
480*63eb84d1Schristos 		  else
481*63eb84d1Schristos 		    type = TYPE_COUNT_INT_POINTER;
482*63eb84d1Schristos 		  break;
483*63eb84d1Schristos 		case '%':
484*63eb84d1Schristos 		  type = TYPE_NONE;
485*63eb84d1Schristos 		  break;
486*63eb84d1Schristos 		default:
487*63eb84d1Schristos 		  /* Unknown conversion character.  */
488*63eb84d1Schristos 		  goto error;
489*63eb84d1Schristos 		}
490*63eb84d1Schristos 	    }
491*63eb84d1Schristos 
492*63eb84d1Schristos 	    if (type != TYPE_NONE)
493*63eb84d1Schristos 	      {
494*63eb84d1Schristos 		dp->arg_index = arg_index;
495*63eb84d1Schristos 		if (dp->arg_index == ARG_NONE)
496*63eb84d1Schristos 		  {
497*63eb84d1Schristos 		    dp->arg_index = arg_posn++;
498*63eb84d1Schristos 		    if (dp->arg_index == ARG_NONE)
499*63eb84d1Schristos 		      /* arg_posn wrapped around.  */
500*63eb84d1Schristos 		      goto error;
501*63eb84d1Schristos 		  }
502*63eb84d1Schristos 		REGISTER_ARG (dp->arg_index, type);
503*63eb84d1Schristos 	      }
504*63eb84d1Schristos 	    dp->conversion = c;
505*63eb84d1Schristos 	    dp->dir_end = cp;
506*63eb84d1Schristos 	  }
507*63eb84d1Schristos 
508*63eb84d1Schristos 	  d->count++;
509*63eb84d1Schristos 	  if (d->count >= d_allocated)
510*63eb84d1Schristos 	    {
511*63eb84d1Schristos 	      size_t memory_size;
512*63eb84d1Schristos 	      DIRECTIVE *memory;
513*63eb84d1Schristos 
514*63eb84d1Schristos 	      d_allocated = xtimes (d_allocated, 2);
515*63eb84d1Schristos 	      memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
516*63eb84d1Schristos 	      if (size_overflow_p (memory_size))
517*63eb84d1Schristos 		/* Overflow, would lead to out of memory.  */
518*63eb84d1Schristos 		goto error;
519*63eb84d1Schristos 	      memory = realloc (d->dir, memory_size);
520*63eb84d1Schristos 	      if (memory == NULL)
521*63eb84d1Schristos 		/* Out of memory.  */
522*63eb84d1Schristos 		goto error;
523*63eb84d1Schristos 	      d->dir = memory;
524*63eb84d1Schristos 	    }
525*63eb84d1Schristos 	}
526*63eb84d1Schristos     }
527*63eb84d1Schristos   d->dir[d->count].dir_start = cp;
528*63eb84d1Schristos 
529*63eb84d1Schristos   d->max_width_length = max_width_length;
530*63eb84d1Schristos   d->max_precision_length = max_precision_length;
531*63eb84d1Schristos   return 0;
532*63eb84d1Schristos 
533*63eb84d1Schristos error:
534*63eb84d1Schristos   if (a->arg)
535*63eb84d1Schristos     free (a->arg);
536*63eb84d1Schristos   if (d->dir)
537*63eb84d1Schristos     free (d->dir);
538*63eb84d1Schristos   return -1;
539*63eb84d1Schristos }
540*63eb84d1Schristos 
541*63eb84d1Schristos #undef DIRECTIVES
542*63eb84d1Schristos #undef DIRECTIVE
543*63eb84d1Schristos #undef CHAR_T
544*63eb84d1Schristos #undef PRINTF_PARSE
545