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