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