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