Home | History | Annotate | Download | only in intl
      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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     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
     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 *
    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