1/* vsprintf with automatic memory allocation.
2   Copyright (C) 1999, 2002-2005 Free Software Foundation, Inc.
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License along
15   with this program; if not, write to the Free Software Foundation,
16   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17#include <sys/cdefs.h>
18__RCSID("$NetBSD: vasnprintf.c,v 1.4 2016/05/17 14:00:09 christos Exp $");
19
20
21/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
22   This must come before <config.h> because <config.h> may include
23   <features.h>, and once <features.h> has been included, it's too late.  */
24#ifndef _GNU_SOURCE
25# define _GNU_SOURCE    1
26#endif
27
28#ifdef HAVE_CONFIG_H
29# include <config.h>
30#endif
31#ifdef __SSP__
32#undef HAVE_ALLOCA
33#endif
34#ifndef __NetBSD__
35#ifndef IN_LIBINTL
36# include <alloca.h>
37#endif
38#endif
39
40/* Specification.  */
41#if WIDE_CHAR_VERSION
42# include "vasnwprintf.h"
43#else
44# include "vasnprintf.h"
45#endif
46
47#include <stdio.h>	/* snprintf(), sprintf() */
48#include <stdlib.h>	/* abort(), malloc(), realloc(), free() */
49#include <string.h>	/* memcpy(), strlen() */
50#include <errno.h>	/* errno */
51#include <limits.h>	/* CHAR_BIT, INT_MAX */
52#include <float.h>	/* DBL_MAX_EXP, LDBL_MAX_EXP */
53#if WIDE_CHAR_VERSION
54# include "wprintf-parse.h"
55#else
56# include "printf-parse.h"
57#endif
58
59/* Checked size_t computations.  */
60#include "xsize.h"
61
62/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
63#ifndef EOVERFLOW
64# define EOVERFLOW E2BIG
65#endif
66
67#ifdef HAVE_WCHAR_T
68# ifdef HAVE_WCSLEN
69#  define local_wcslen wcslen
70# else
71   /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
72      a dependency towards this library, here is a local substitute.
73      Define this substitute only once, even if this file is included
74      twice in the same compilation unit.  */
75#  ifndef local_wcslen_defined
76#   define local_wcslen_defined 1
77static size_t
78local_wcslen (const wchar_t *s)
79{
80  const wchar_t *ptr;
81
82  for (ptr = s; *ptr != (wchar_t) 0; ptr++)
83    ;
84  return ptr - s;
85}
86#  endif
87# endif
88#endif
89
90#if WIDE_CHAR_VERSION
91# define VASNPRINTF vasnwprintf
92# define CHAR_T wchar_t
93# define DIRECTIVE wchar_t_directive
94# define DIRECTIVES wchar_t_directives
95# define PRINTF_PARSE wprintf_parse
96# define USE_SNPRINTF 1
97# if HAVE_DECL__SNWPRINTF
98   /* On Windows, the function swprintf() has a different signature than
99      on Unix; we use the _snwprintf() function instead.  */
100#  define SNPRINTF _snwprintf
101# else
102   /* Unix.  */
103#  define SNPRINTF swprintf
104# endif
105#else
106# define VASNPRINTF vasnprintf
107# define CHAR_T char
108# define DIRECTIVE char_directive
109# define DIRECTIVES char_directives
110# define PRINTF_PARSE printf_parse
111# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
112# if HAVE_DECL__SNPRINTF
113   /* Windows.  */
114#  define SNPRINTF _snprintf
115# else
116   /* Unix.  */
117#  define SNPRINTF snprintf
118# endif
119#endif
120
121CHAR_T *
122VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
123{
124  DIRECTIVES d;
125  arguments a;
126
127  if (PRINTF_PARSE (format, &d, &a) < 0)
128    {
129      errno = EINVAL;
130      return NULL;
131    }
132
133#define CLEANUP() \
134  free (d.dir);								\
135  if (a.arg)								\
136    free (a.arg);
137
138  if (printf_fetchargs (args, &a) < 0)
139    {
140      CLEANUP ();
141      errno = EINVAL;
142      return NULL;
143    }
144
145  {
146    size_t buf_neededlength;
147    CHAR_T *buf;
148    CHAR_T *buf_malloced;
149    const CHAR_T *cp;
150    size_t i;
151    DIRECTIVE *dp;
152    /* Output string accumulator.  */
153    CHAR_T *result;
154    size_t allocated;
155    size_t length;
156
157    /* Allocate a small buffer that will hold a directive passed to
158       sprintf or snprintf.  */
159    buf_neededlength =
160      xsum4 (7, d.max_width_length, d.max_precision_length, 6);
161#if HAVE_ALLOCA
162    if (buf_neededlength < 4000 / sizeof (CHAR_T))
163      {
164	buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
165	buf_malloced = NULL;
166      }
167    else
168#endif
169      {
170	size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
171	if (size_overflow_p (buf_memsize))
172	  goto out_of_memory_1;
173	buf = (CHAR_T *) malloc (buf_memsize);
174	if (buf == NULL)
175	  goto out_of_memory_1;
176	buf_malloced = buf;
177      }
178
179    if (resultbuf != NULL)
180      {
181	result = resultbuf;
182	allocated = *lengthp;
183      }
184    else
185      {
186	result = NULL;
187	allocated = 0;
188      }
189    length = 0;
190    /* Invariants:
191       result is either == resultbuf or == NULL or malloc-allocated.
192       If length > 0, then result != NULL.  */
193
194    /* Ensures that allocated >= needed.  Aborts through a jump to
195       out_of_memory if needed is SIZE_MAX or otherwise too big.  */
196#define ENSURE_ALLOCATION(needed) \
197    if ((needed) > allocated)						     \
198      {									     \
199	size_t memory_size;						     \
200	CHAR_T *memory;							     \
201									     \
202	allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);	     \
203	if ((needed) > allocated)					     \
204	  allocated = (needed);						     \
205	memory_size = xtimes (allocated, sizeof (CHAR_T));		     \
206	if (size_overflow_p (memory_size))				     \
207	  goto out_of_memory;						     \
208	if (result == resultbuf || result == NULL)			     \
209	  memory = (CHAR_T *) malloc (memory_size);			     \
210	else								     \
211	  memory = (CHAR_T *) realloc (result, memory_size);		     \
212	if (memory == NULL)						     \
213	  goto out_of_memory;						     \
214	if (result == resultbuf && length > 0)				     \
215	  memcpy (memory, result, length * sizeof (CHAR_T));		     \
216	result = memory;						     \
217      }
218
219    for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
220      {
221	if (cp != dp->dir_start)
222	  {
223	    size_t n = dp->dir_start - cp;
224	    size_t augmented_length = xsum (length, n);
225
226	    ENSURE_ALLOCATION (augmented_length);
227	    memcpy (result + length, cp, n * sizeof (CHAR_T));
228	    length = augmented_length;
229	  }
230	if (i == d.count)
231	  break;
232
233	/* Execute a single directive.  */
234	if (dp->conversion == '%')
235	  {
236	    size_t augmented_length;
237
238	    if (!(dp->arg_index == ARG_NONE))
239	      abort ();
240	    augmented_length = xsum (length, 1);
241	    ENSURE_ALLOCATION (augmented_length);
242	    result[length] = '%';
243	    length = augmented_length;
244	  }
245	else
246	  {
247	    if (!(dp->arg_index != ARG_NONE))
248	      abort ();
249
250	    if (dp->conversion == 'n')
251	      {
252		switch (a.arg[dp->arg_index].type)
253		  {
254		  case TYPE_COUNT_SCHAR_POINTER:
255		    *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
256		    break;
257		  case TYPE_COUNT_SHORT_POINTER:
258		    *a.arg[dp->arg_index].a.a_count_short_pointer = length;
259		    break;
260		  case TYPE_COUNT_INT_POINTER:
261		    *a.arg[dp->arg_index].a.a_count_int_pointer = length;
262		    break;
263		  case TYPE_COUNT_LONGINT_POINTER:
264		    *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
265		    break;
266#ifdef HAVE_LONG_LONG
267		  case TYPE_COUNT_LONGLONGINT_POINTER:
268		    *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
269		    break;
270#endif
271		  default:
272		    abort ();
273		  }
274	      }
275	    else
276	      {
277		arg_type type = a.arg[dp->arg_index].type;
278		CHAR_T *p;
279		unsigned int prefix_count;
280		int prefixes[2];
281#if !USE_SNPRINTF
282		size_t tmp_length;
283		CHAR_T tmpbuf[700];
284		CHAR_T *tmp;
285
286		/* Allocate a temporary buffer of sufficient size for calling
287		   sprintf.  */
288		{
289		  size_t width;
290		  size_t precision;
291
292		  width = 0;
293		  if (dp->width_start != dp->width_end)
294		    {
295		      if (dp->width_arg_index != ARG_NONE)
296			{
297			  int arg;
298
299			  if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
300			    abort ();
301			  arg = a.arg[dp->width_arg_index].a.a_int;
302			  width = (arg < 0 ? (unsigned int) (-arg) : arg);
303			}
304		      else
305			{
306			  const CHAR_T *digitp = dp->width_start;
307
308			  do
309			    width = xsum (xtimes (width, 10), *digitp++ - '0');
310			  while (digitp != dp->width_end);
311			}
312		    }
313
314		  precision = 6;
315		  if (dp->precision_start != dp->precision_end)
316		    {
317		      if (dp->precision_arg_index != ARG_NONE)
318			{
319			  int arg;
320
321			  if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
322			    abort ();
323			  arg = a.arg[dp->precision_arg_index].a.a_int;
324			  precision = (arg < 0 ? 0 : arg);
325			}
326		      else
327			{
328			  const CHAR_T *digitp = dp->precision_start + 1;
329
330			  precision = 0;
331			  while (digitp != dp->precision_end)
332			    precision = xsum (xtimes (precision, 10), *digitp++ - '0');
333			}
334		    }
335
336		  switch (dp->conversion)
337		    {
338
339		    case 'd': case 'i': case 'u':
340# ifdef HAVE_LONG_LONG
341		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
342			tmp_length =
343			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
344					  * 0.30103 /* binary -> decimal */
345					  * 2 /* estimate for FLAG_GROUP */
346					 )
347			  + 1 /* turn floor into ceil */
348			  + 1; /* account for leading sign */
349		      else
350# endif
351		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
352			tmp_length =
353			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
354					  * 0.30103 /* binary -> decimal */
355					  * 2 /* estimate for FLAG_GROUP */
356					 )
357			  + 1 /* turn floor into ceil */
358			  + 1; /* account for leading sign */
359		      else
360			tmp_length =
361			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
362					  * 0.30103 /* binary -> decimal */
363					  * 2 /* estimate for FLAG_GROUP */
364					 )
365			  + 1 /* turn floor into ceil */
366			  + 1; /* account for leading sign */
367		      break;
368
369		    case 'o':
370# ifdef HAVE_LONG_LONG
371		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
372			tmp_length =
373			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
374					  * 0.333334 /* binary -> octal */
375					 )
376			  + 1 /* turn floor into ceil */
377			  + 1; /* account for leading sign */
378		      else
379# endif
380		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
381			tmp_length =
382			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
383					  * 0.333334 /* binary -> octal */
384					 )
385			  + 1 /* turn floor into ceil */
386			  + 1; /* account for leading sign */
387		      else
388			tmp_length =
389			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
390					  * 0.333334 /* binary -> octal */
391					 )
392			  + 1 /* turn floor into ceil */
393			  + 1; /* account for leading sign */
394		      break;
395
396		    case 'x': case 'X':
397# ifdef HAVE_LONG_LONG
398		      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
399			tmp_length =
400			  (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
401					  * 0.25 /* binary -> hexadecimal */
402					 )
403			  + 1 /* turn floor into ceil */
404			  + 2; /* account for leading sign or alternate form */
405		      else
406# endif
407		      if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
408			tmp_length =
409			  (unsigned int) (sizeof (unsigned long) * CHAR_BIT
410					  * 0.25 /* binary -> hexadecimal */
411					 )
412			  + 1 /* turn floor into ceil */
413			  + 2; /* account for leading sign or alternate form */
414		      else
415			tmp_length =
416			  (unsigned int) (sizeof (unsigned int) * CHAR_BIT
417					  * 0.25 /* binary -> hexadecimal */
418					 )
419			  + 1 /* turn floor into ceil */
420			  + 2; /* account for leading sign or alternate form */
421		      break;
422
423		    case 'f': case 'F':
424# ifdef HAVE_LONG_DOUBLE
425		      if (type == TYPE_LONGDOUBLE)
426			tmp_length =
427			  (unsigned int) (LDBL_MAX_EXP
428					  * 0.30103 /* binary -> decimal */
429					  * 2 /* estimate for FLAG_GROUP */
430					 )
431			  + 1 /* turn floor into ceil */
432			  + 10; /* sign, decimal point etc. */
433		      else
434# endif
435			tmp_length =
436			  (unsigned int) (DBL_MAX_EXP
437					  * 0.30103 /* binary -> decimal */
438					  * 2 /* estimate for FLAG_GROUP */
439					 )
440			  + 1 /* turn floor into ceil */
441			  + 10; /* sign, decimal point etc. */
442		      tmp_length = xsum (tmp_length, precision);
443		      break;
444
445		    case 'e': case 'E': case 'g': case 'G':
446		    case 'a': case 'A':
447		      tmp_length =
448			12; /* sign, decimal point, exponent etc. */
449		      tmp_length = xsum (tmp_length, precision);
450		      break;
451
452		    case 'c':
453# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
454		      if (type == TYPE_WIDE_CHAR)
455			tmp_length = MB_CUR_MAX;
456		      else
457# endif
458			tmp_length = 1;
459		      break;
460
461		    case 's':
462# ifdef HAVE_WCHAR_T
463		      if (type == TYPE_WIDE_STRING)
464			{
465			  tmp_length =
466			    local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
467
468#  if !WIDE_CHAR_VERSION
469			  tmp_length = xtimes (tmp_length, MB_CUR_MAX);
470#  endif
471			}
472		      else
473# endif
474			tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
475		      break;
476
477		    case 'p':
478		      tmp_length =
479			(unsigned int) (sizeof (void *) * CHAR_BIT
480					* 0.25 /* binary -> hexadecimal */
481				       )
482			  + 1 /* turn floor into ceil */
483			  + 2; /* account for leading 0x */
484		      break;
485
486		    default:
487		      abort ();
488		    }
489
490		  if (tmp_length < width)
491		    tmp_length = width;
492
493		  tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
494		}
495
496		if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
497		  tmp = tmpbuf;
498		else
499		  {
500		    size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
501
502		    if (size_overflow_p (tmp_memsize))
503		      /* Overflow, would lead to out of memory.  */
504		      goto out_of_memory;
505		    tmp = (CHAR_T *) malloc (tmp_memsize);
506		    if (tmp == NULL)
507		      /* Out of memory.  */
508		      goto out_of_memory;
509		  }
510#endif
511
512		/* Construct the format string for calling snprintf or
513		   sprintf.  */
514		p = buf;
515		*p++ = '%';
516		if (dp->flags & FLAG_GROUP)
517		  *p++ = '\'';
518		if (dp->flags & FLAG_LEFT)
519		  *p++ = '-';
520		if (dp->flags & FLAG_SHOWSIGN)
521		  *p++ = '+';
522		if (dp->flags & FLAG_SPACE)
523		  *p++ = ' ';
524		if (dp->flags & FLAG_ALT)
525		  *p++ = '#';
526		if (dp->flags & FLAG_ZERO)
527		  *p++ = '0';
528		if (dp->width_start != dp->width_end)
529		  {
530		    size_t n = dp->width_end - dp->width_start;
531		    memcpy (p, dp->width_start, n * sizeof (CHAR_T));
532		    p += n;
533		  }
534		if (dp->precision_start != dp->precision_end)
535		  {
536		    size_t n = dp->precision_end - dp->precision_start;
537		    memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
538		    p += n;
539		  }
540
541		switch (type)
542		  {
543#ifdef HAVE_LONG_LONG
544		  case TYPE_LONGLONGINT:
545		  case TYPE_ULONGLONGINT:
546		    *p++ = 'l';
547		    /*FALLTHROUGH*/
548#endif
549		  case TYPE_LONGINT:
550		  case TYPE_ULONGINT:
551#ifdef HAVE_WINT_T
552		  case TYPE_WIDE_CHAR:
553#endif
554#ifdef HAVE_WCHAR_T
555		  case TYPE_WIDE_STRING:
556#endif
557		    *p++ = 'l';
558		    break;
559#ifdef HAVE_LONG_DOUBLE
560		  case TYPE_LONGDOUBLE:
561		    *p++ = 'L';
562		    break;
563#endif
564		  default:
565		    break;
566		  }
567		*p = dp->conversion;
568		p[1] = '\0';
569
570		/* Construct the arguments for calling snprintf or sprintf.  */
571		prefix_count = 0;
572		if (dp->width_arg_index != ARG_NONE)
573		  {
574		    if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
575		      abort ();
576		    prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
577		  }
578		if (dp->precision_arg_index != ARG_NONE)
579		  {
580		    if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
581		      abort ();
582		    prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
583		  }
584
585#if USE_SNPRINTF
586		/* Prepare checking whether snprintf returns the count
587		   via %n.  */
588		ENSURE_ALLOCATION (xsum (length, 1));
589		result[length] = '\0';
590#endif
591
592		for (;;)
593		  {
594		    size_t maxlen;
595		    int count;
596
597		    maxlen = allocated - length;
598		    count = -1;
599
600#if USE_SNPRINTF
601# define SNPRINTF_BUF(arg) \
602		    switch (prefix_count)				    \
603		      {							    \
604		      case 0:						    \
605			count = SNPRINTF (result + length, maxlen, buf,     \
606					     arg);            		    \
607			break;						    \
608		      case 1:						    \
609			count = SNPRINTF (result + length, maxlen, buf,     \
610					     prefixes[0], arg);	            \
611			break;						    \
612		      case 2:						    \
613			count = SNPRINTF (result + length, maxlen, buf,     \
614					  prefixes[0], prefixes[1], arg);   \
615			break;						    \
616		      default:						    \
617			abort ();					    \
618		      }
619#else
620# define SNPRINTF_BUF(arg) \
621		    switch (prefix_count)				    \
622		      {							    \
623		      case 0:						    \
624			count = sprintf (tmp, buf, arg);		    \
625			break;						    \
626		      case 1:						    \
627			count = sprintf (tmp, buf, prefixes[0], arg);	    \
628			break;						    \
629		      case 2:						    \
630			count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
631					 arg);				    \
632			break;						    \
633		      default:						    \
634			abort ();					    \
635		      }
636#endif
637
638		    switch (type)
639		      {
640		      case TYPE_SCHAR:
641			{
642			  int arg = a.arg[dp->arg_index].a.a_schar;
643			  SNPRINTF_BUF (arg);
644			}
645			break;
646		      case TYPE_UCHAR:
647			{
648			  unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
649			  SNPRINTF_BUF (arg);
650			}
651			break;
652		      case TYPE_SHORT:
653			{
654			  int arg = a.arg[dp->arg_index].a.a_short;
655			  SNPRINTF_BUF (arg);
656			}
657			break;
658		      case TYPE_USHORT:
659			{
660			  unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
661			  SNPRINTF_BUF (arg);
662			}
663			break;
664		      case TYPE_INT:
665			{
666			  int arg = a.arg[dp->arg_index].a.a_int;
667			  SNPRINTF_BUF (arg);
668			}
669			break;
670		      case TYPE_UINT:
671			{
672			  unsigned int arg = a.arg[dp->arg_index].a.a_uint;
673			  SNPRINTF_BUF (arg);
674			}
675			break;
676		      case TYPE_LONGINT:
677			{
678			  long int arg = a.arg[dp->arg_index].a.a_longint;
679			  SNPRINTF_BUF (arg);
680			}
681			break;
682		      case TYPE_ULONGINT:
683			{
684			  unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
685			  SNPRINTF_BUF (arg);
686			}
687			break;
688#ifdef HAVE_LONG_LONG
689		      case TYPE_LONGLONGINT:
690			{
691			  long long int arg = a.arg[dp->arg_index].a.a_longlongint;
692			  SNPRINTF_BUF (arg);
693			}
694			break;
695		      case TYPE_ULONGLONGINT:
696			{
697			  unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
698			  SNPRINTF_BUF (arg);
699			}
700			break;
701#endif
702		      case TYPE_DOUBLE:
703			{
704			  double arg = a.arg[dp->arg_index].a.a_double;
705			  SNPRINTF_BUF (arg);
706			}
707			break;
708#ifdef HAVE_LONG_DOUBLE
709		      case TYPE_LONGDOUBLE:
710			{
711			  long double arg = a.arg[dp->arg_index].a.a_longdouble;
712			  SNPRINTF_BUF (arg);
713			}
714			break;
715#endif
716		      case TYPE_CHAR:
717			{
718			  int arg = a.arg[dp->arg_index].a.a_char;
719			  SNPRINTF_BUF (arg);
720			}
721			break;
722#ifdef HAVE_WINT_T
723		      case TYPE_WIDE_CHAR:
724			{
725			  wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
726			  SNPRINTF_BUF (arg);
727			}
728			break;
729#endif
730		      case TYPE_STRING:
731			{
732			  const char *arg = a.arg[dp->arg_index].a.a_string;
733			  SNPRINTF_BUF (arg);
734			}
735			break;
736#ifdef HAVE_WCHAR_T
737		      case TYPE_WIDE_STRING:
738			{
739			  const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
740			  SNPRINTF_BUF (arg);
741			}
742			break;
743#endif
744		      case TYPE_POINTER:
745			{
746			  void *arg = a.arg[dp->arg_index].a.a_pointer;
747			  SNPRINTF_BUF (arg);
748			}
749			break;
750		      default:
751			abort ();
752		      }
753
754#if USE_SNPRINTF
755		    /* Portability: Not all implementations of snprintf()
756		       are ISO C 99 compliant.  Determine the number of
757		       bytes that snprintf() has produced or would have
758		       produced.  */
759		    if (count >= 0)
760		      {
761			/* Verify that snprintf() has NUL-terminated its
762			   result.  */
763			if (count < maxlen && result[length + count] != '\0')
764			  abort ();
765		      }
766#endif
767
768		    /* Attempt to handle failure.  */
769		    if (count < 0)
770		      {
771			if (!(result == resultbuf || result == NULL))
772			  free (result);
773			if (buf_malloced != NULL)
774			  free (buf_malloced);
775			CLEANUP ();
776			errno = EINVAL;
777			return NULL;
778		      }
779
780#if !USE_SNPRINTF
781		    if (count >= tmp_length)
782		      /* tmp_length was incorrectly calculated - fix the
783			 code above!  */
784		      abort ();
785#endif
786
787		    /* Make room for the result.  */
788		    if (count >= maxlen)
789		      {
790			/* Need at least count bytes.  But allocate
791			   proportionally, to avoid looping eternally if
792			   snprintf() reports a too small count.  */
793			size_t n =
794			  xmax (xsum (length, count), xtimes (allocated, 2));
795
796			ENSURE_ALLOCATION (n);
797#if USE_SNPRINTF
798			continue;
799#endif
800		      }
801
802#if USE_SNPRINTF
803		    /* The snprintf() result did fit.  */
804#else
805		    /* Append the sprintf() result.  */
806		    memcpy (result + length, tmp, count * sizeof (CHAR_T));
807		    if (tmp != tmpbuf)
808		      free (tmp);
809#endif
810
811		    length += count;
812		    break;
813		  }
814	      }
815	  }
816      }
817
818    /* Add the final NUL.  */
819    ENSURE_ALLOCATION (xsum (length, 1));
820    result[length] = '\0';
821
822    if (result != resultbuf && length + 1 < allocated)
823      {
824	/* Shrink the allocated memory if possible.  */
825	CHAR_T *memory;
826
827	memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
828	if (memory != NULL)
829	  result = memory;
830      }
831
832    if (buf_malloced != NULL)
833      free (buf_malloced);
834    CLEANUP ();
835    *lengthp = length;
836    if (length > INT_MAX)
837      goto length_overflow;
838    return result;
839
840  length_overflow:
841    /* We could produce such a big string, but its length doesn't fit into
842       an 'int'.  POSIX says that snprintf() fails with errno = EOVERFLOW in
843       this case.  */
844    if (result != resultbuf)
845      free (result);
846    errno = EOVERFLOW;
847    return NULL;
848
849  out_of_memory:
850    if (!(result == resultbuf || result == NULL))
851      free (result);
852    if (buf_malloced != NULL)
853      free (buf_malloced);
854  out_of_memory_1:
855    CLEANUP ();
856    errno = ENOMEM;
857    return NULL;
858  }
859}
860
861#undef SNPRINTF
862#undef USE_SNPRINTF
863#undef PRINTF_PARSE
864#undef DIRECTIVES
865#undef DIRECTIVE
866#undef CHAR_T
867#undef VASNPRINTF
868