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