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