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