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