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