Home | History | Annotate | Line # | Download | only in lib
vasnprintf.c revision 1.1
      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