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