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