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