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