Back to index

tetex-bin  3.0
Defines | Functions
vasnprintf.c File Reference
#include <alloca.h>
#include "vasnprintf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <float.h>
#include "printf-parse.h"
#include "xsize.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define _GNU_SOURCE   1
#define VASNPRINTF   vasnprintf
#define CHAR_T   char
#define DIRECTIVE   char_directive
#define DIRECTIVES   char_directives
#define PRINTF_PARSE   printf_parse
#define USE_SNPRINTF   (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
#define SNPRINTF   snprintf
#define CLEANUP()
#define ENSURE_ALLOCATION(needed)
#define SNPRINTF_BUF(arg)

Functions

CHAR_TVASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)

Define Documentation

#define _GNU_SOURCE   1

Definition at line 23 of file vasnprintf.c.

#define CHAR_T   char

Definition at line 95 of file vasnprintf.c.

#define CLEANUP ( )
Value:
free (d.dir);                                                  \
  if (a.arg)                                                   \
    free (a.arg);
#define DIRECTIVE   char_directive

Definition at line 96 of file vasnprintf.c.

Definition at line 97 of file vasnprintf.c.

#define ENSURE_ALLOCATION (   needed)
Value:
if ((needed) > allocated)                                           \
      {                                                                    \
       size_t memory_size;                                          \
       CHAR_T *memory;                                                     \
                                                                    \
       allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);           \
       if ((needed) > allocated)                                    \
         allocated = (needed);                                             \
       memory_size = xtimes (allocated, sizeof (CHAR_T));                  \
       if (size_overflow_p (memory_size))                           \
         goto out_of_memory;                                               \
       if (result == resultbuf || result == NULL)                          \
         memory = (CHAR_T *) malloc (memory_size);                         \
       else                                                         \
         memory = (CHAR_T *) realloc (result, memory_size);                \
       if (memory == NULL)                                          \
         goto out_of_memory;                                               \
       if (result == resultbuf && length > 0)                              \
         memcpy (memory, result, length * sizeof (CHAR_T));                \
       result = memory;                                             \
      }
#define PRINTF_PARSE   printf_parse

Definition at line 98 of file vasnprintf.c.

#define SNPRINTF   snprintf

Definition at line 105 of file vasnprintf.c.

#define SNPRINTF_BUF (   arg)
Value:
switch (prefix_count)                                \
                    {                                                     \
                    case 0:                                        \
                     count = sprintf (tmp, buf, arg);              \
                     break;                                        \
                    case 1:                                        \
                     count = sprintf (tmp, buf, prefixes[0], arg);        \
                     break;                                        \
                    case 2:                                        \
                     count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
                                    arg);                          \
                     break;                                        \
                    default:                                              \
                     abort ();                                     \
                    }
#define USE_SNPRINTF   (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)

Definition at line 99 of file vasnprintf.c.

#define VASNPRINTF   vasnprintf

Definition at line 94 of file vasnprintf.c.


Function Documentation

CHAR_T* VASNPRINTF ( CHAR_T resultbuf,
size_t lengthp,
const CHAR_T format,
va_list  args 
)

Definition at line 110 of file vasnprintf.c.

{
  DIRECTIVES d;
  arguments a;

  if (PRINTF_PARSE (format, &d, &a) < 0)
    {
      errno = EINVAL;
      return NULL;
    }

#define CLEANUP() \
  free (d.dir);                                                       \
  if (a.arg)                                                   \
    free (a.arg);

  if (printf_fetchargs (args, &a) < 0)
    {
      CLEANUP ();
      errno = EINVAL;
      return NULL;
    }

  {
    size_t buf_neededlength;
    CHAR_T *buf;
    CHAR_T *buf_malloced;
    const CHAR_T *cp;
    size_t i;
    DIRECTIVE *dp;
    /* Output string accumulator.  */
    CHAR_T *result;
    size_t allocated;
    size_t length;

    /* Allocate a small buffer that will hold a directive passed to
       sprintf or snprintf.  */
    buf_neededlength =
      xsum4 (7, d.max_width_length, d.max_precision_length, 6);
#if HAVE_ALLOCA
    if (buf_neededlength < 4000 / sizeof (CHAR_T))
      {
       buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
       buf_malloced = NULL;
      }
    else
#endif
      {
       size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
       if (size_overflow_p (buf_memsize))
         goto out_of_memory_1;
       buf = (CHAR_T *) malloc (buf_memsize);
       if (buf == NULL)
         goto out_of_memory_1;
       buf_malloced = buf;
      }

    if (resultbuf != NULL)
      {
       result = resultbuf;
       allocated = *lengthp;
      }
    else
      {
       result = NULL;
       allocated = 0;
      }
    length = 0;
    /* Invariants:
       result is either == resultbuf or == NULL or malloc-allocated.
       If length > 0, then result != NULL.  */

    /* Ensures that allocated >= needed.  Aborts through a jump to
       out_of_memory if needed is SIZE_MAX or otherwise too big.  */
#define ENSURE_ALLOCATION(needed) \
    if ((needed) > allocated)                                              \
      {                                                                    \
       size_t memory_size;                                          \
       CHAR_T *memory;                                                     \
                                                                    \
       allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);           \
       if ((needed) > allocated)                                    \
         allocated = (needed);                                             \
       memory_size = xtimes (allocated, sizeof (CHAR_T));                  \
       if (size_overflow_p (memory_size))                           \
         goto out_of_memory;                                               \
       if (result == resultbuf || result == NULL)                          \
         memory = (CHAR_T *) malloc (memory_size);                         \
       else                                                         \
         memory = (CHAR_T *) realloc (result, memory_size);                \
       if (memory == NULL)                                          \
         goto out_of_memory;                                               \
       if (result == resultbuf && length > 0)                              \
         memcpy (memory, result, length * sizeof (CHAR_T));                \
       result = memory;                                             \
      }

    for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
      {
       if (cp != dp->dir_start)
         {
           size_t n = dp->dir_start - cp;
           size_t augmented_length = xsum (length, n);

           ENSURE_ALLOCATION (augmented_length);
           memcpy (result + length, cp, n * sizeof (CHAR_T));
           length = augmented_length;
         }
       if (i == d.count)
         break;

       /* Execute a single directive.  */
       if (dp->conversion == '%')
         {
           size_t augmented_length;

           if (!(dp->arg_index == ARG_NONE))
             abort ();
           augmented_length = xsum (length, 1);
           ENSURE_ALLOCATION (augmented_length);
           result[length] = '%';
           length = augmented_length;
         }
       else
         {
           if (!(dp->arg_index != ARG_NONE))
             abort ();

           if (dp->conversion == 'n')
             {
              switch (a.arg[dp->arg_index].type)
                {
                case TYPE_COUNT_SCHAR_POINTER:
                  *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
                  break;
                case TYPE_COUNT_SHORT_POINTER:
                  *a.arg[dp->arg_index].a.a_count_short_pointer = length;
                  break;
                case TYPE_COUNT_INT_POINTER:
                  *a.arg[dp->arg_index].a.a_count_int_pointer = length;
                  break;
                case TYPE_COUNT_LONGINT_POINTER:
                  *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
                  break;
#ifdef HAVE_LONG_LONG
                case TYPE_COUNT_LONGLONGINT_POINTER:
                  *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
                  break;
#endif
                default:
                  abort ();
                }
             }
           else
             {
              arg_type type = a.arg[dp->arg_index].type;
              CHAR_T *p;
              unsigned int prefix_count;
              int prefixes[2];
#if !USE_SNPRINTF
              size_t tmp_length;
              CHAR_T tmpbuf[700];
              CHAR_T *tmp;

              /* Allocate a temporary buffer of sufficient size for calling
                 sprintf.  */
              {
                size_t width;
                size_t precision;

                width = 0;
                if (dp->width_start != dp->width_end)
                  {
                    if (dp->width_arg_index != ARG_NONE)
                     {
                       int arg;

                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                         abort ();
                       arg = a.arg[dp->width_arg_index].a.a_int;
                       width = (arg < 0 ? (unsigned int) (-arg) : arg);
                     }
                    else
                     {
                       const CHAR_T *digitp = dp->width_start;

                       do
                         width = xsum (xtimes (width, 10), *digitp++ - '0');
                       while (digitp != dp->width_end);
                     }
                  }

                precision = 6;
                if (dp->precision_start != dp->precision_end)
                  {
                    if (dp->precision_arg_index != ARG_NONE)
                     {
                       int arg;

                       if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
                         abort ();
                       arg = a.arg[dp->precision_arg_index].a.a_int;
                       precision = (arg < 0 ? 0 : arg);
                     }
                    else
                     {
                       const CHAR_T *digitp = dp->precision_start + 1;

                       precision = 0;
                       do
                         precision = xsum (xtimes (precision, 10), *digitp++ - '0');
                       while (digitp != dp->precision_end);
                     }
                  }

                switch (dp->conversion)
                  {

                  case 'd': case 'i': case 'u':
# ifdef HAVE_LONG_LONG
                    if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
                                     * 0.30103 /* binary -> decimal */
                                     * 2 /* estimate for FLAG_GROUP */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    else
# endif
                    if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long) * CHAR_BIT
                                     * 0.30103 /* binary -> decimal */
                                     * 2 /* estimate for FLAG_GROUP */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    else
                     tmp_length =
                       (unsigned int) (sizeof (unsigned int) * CHAR_BIT
                                     * 0.30103 /* binary -> decimal */
                                     * 2 /* estimate for FLAG_GROUP */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    break;

                  case 'o':
# ifdef HAVE_LONG_LONG
                    if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
                                     * 0.333334 /* binary -> octal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    else
# endif
                    if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long) * CHAR_BIT
                                     * 0.333334 /* binary -> octal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    else
                     tmp_length =
                       (unsigned int) (sizeof (unsigned int) * CHAR_BIT
                                     * 0.333334 /* binary -> octal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 1; /* account for leading sign */
                    break;

                  case 'x': case 'X':
# ifdef HAVE_LONG_LONG
                    if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
                                     * 0.25 /* binary -> hexadecimal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 2; /* account for leading sign or alternate form */
                    else
# endif
                    if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
                     tmp_length =
                       (unsigned int) (sizeof (unsigned long) * CHAR_BIT
                                     * 0.25 /* binary -> hexadecimal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 2; /* account for leading sign or alternate form */
                    else
                     tmp_length =
                       (unsigned int) (sizeof (unsigned int) * CHAR_BIT
                                     * 0.25 /* binary -> hexadecimal */
                                    )
                       + 1 /* turn floor into ceil */
                       + 2; /* account for leading sign or alternate form */
                    break;

                  case 'f': case 'F':
# ifdef HAVE_LONG_DOUBLE
                    if (type == TYPE_LONGDOUBLE)
                     tmp_length =
                       (unsigned int) (LDBL_MAX_EXP
                                     * 0.30103 /* binary -> decimal */
                                     * 2 /* estimate for FLAG_GROUP */
                                    )
                       + 1 /* turn floor into ceil */
                       + 10; /* sign, decimal point etc. */
                    else
# endif
                     tmp_length =
                       (unsigned int) (DBL_MAX_EXP
                                     * 0.30103 /* binary -> decimal */
                                     * 2 /* estimate for FLAG_GROUP */
                                    )
                       + 1 /* turn floor into ceil */
                       + 10; /* sign, decimal point etc. */
                    tmp_length = xsum (tmp_length, precision);
                    break;

                  case 'e': case 'E': case 'g': case 'G':
                  case 'a': case 'A':
                    tmp_length =
                     12; /* sign, decimal point, exponent etc. */
                    tmp_length = xsum (tmp_length, precision);
                    break;

                  case 'c':
# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
                    if (type == TYPE_WIDE_CHAR)
                     tmp_length = MB_CUR_MAX;
                    else
# endif
                     tmp_length = 1;
                    break;

                  case 's':
# ifdef HAVE_WCHAR_T
                    if (type == TYPE_WIDE_STRING)
                     {
                       tmp_length =
                         local_wcslen (a.arg[dp->arg_index].a.a_wide_string);

#  if !WIDE_CHAR_VERSION
                       tmp_length = xtimes (tmp_length, MB_CUR_MAX);
#  endif
                     }
                    else
# endif
                     tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
                    break;

                  case 'p':
                    tmp_length =
                     (unsigned int) (sizeof (void *) * CHAR_BIT
                                   * 0.25 /* binary -> hexadecimal */
                                   )
                       + 1 /* turn floor into ceil */
                       + 2; /* account for leading 0x */
                    break;

                  default:
                    abort ();
                  }

                if (tmp_length < width)
                  tmp_length = width;

                tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
              }

              if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
                tmp = tmpbuf;
              else
                {
                  size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));

                  if (size_overflow_p (tmp_memsize))
                    /* Overflow, would lead to out of memory.  */
                    goto out_of_memory;
                  tmp = (CHAR_T *) malloc (tmp_memsize);
                  if (tmp == NULL)
                    /* Out of memory.  */
                    goto out_of_memory;
                }
#endif

              /* Construct the format string for calling snprintf or
                 sprintf.  */
              p = buf;
              *p++ = '%';
              if (dp->flags & FLAG_GROUP)
                *p++ = '\'';
              if (dp->flags & FLAG_LEFT)
                *p++ = '-';
              if (dp->flags & FLAG_SHOWSIGN)
                *p++ = '+';
              if (dp->flags & FLAG_SPACE)
                *p++ = ' ';
              if (dp->flags & FLAG_ALT)
                *p++ = '#';
              if (dp->flags & FLAG_ZERO)
                *p++ = '0';
              if (dp->width_start != dp->width_end)
                {
                  size_t n = dp->width_end - dp->width_start;
                  memcpy (p, dp->width_start, n * sizeof (CHAR_T));
                  p += n;
                }
              if (dp->precision_start != dp->precision_end)
                {
                  size_t n = dp->precision_end - dp->precision_start;
                  memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
                  p += n;
                }

              switch (type)
                {
#ifdef HAVE_LONG_LONG
                case TYPE_LONGLONGINT:
                case TYPE_ULONGLONGINT:
                  *p++ = 'l';
                  /*FALLTHROUGH*/
#endif
                case TYPE_LONGINT:
                case TYPE_ULONGINT:
#ifdef HAVE_WINT_T
                case TYPE_WIDE_CHAR:
#endif
#ifdef HAVE_WCHAR_T
                case TYPE_WIDE_STRING:
#endif
                  *p++ = 'l';
                  break;
#ifdef HAVE_LONG_DOUBLE
                case TYPE_LONGDOUBLE:
                  *p++ = 'L';
                  break;
#endif
                default:
                  break;
                }
              *p = dp->conversion;
#if USE_SNPRINTF
              p[1] = '%';
              p[2] = 'n';
              p[3] = '\0';
#else
              p[1] = '\0';
#endif

              /* Construct the arguments for calling snprintf or sprintf.  */
              prefix_count = 0;
              if (dp->width_arg_index != ARG_NONE)
                {
                  if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
                    abort ();
                  prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
                }
              if (dp->precision_arg_index != ARG_NONE)
                {
                  if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
                    abort ();
                  prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
                }

#if USE_SNPRINTF
              /* Prepare checking whether snprintf returns the count
                 via %n.  */
              ENSURE_ALLOCATION (xsum (length, 1));
              result[length] = '\0';
#endif

              for (;;)
                {
                  size_t maxlen;
                  int count;
                  int retcount;

                  maxlen = allocated - length;
                  count = -1;
                  retcount = 0;

#if USE_SNPRINTF
# define SNPRINTF_BUF(arg) \
                  switch (prefix_count)                            \
                    {                                                     \
                    case 0:                                        \
                     retcount = SNPRINTF (result + length, maxlen, buf,  \
                                        arg, &count);              \
                     break;                                        \
                    case 1:                                        \
                     retcount = SNPRINTF (result + length, maxlen, buf,  \
                                        prefixes[0], arg, &count);        \
                     break;                                        \
                    case 2:                                        \
                     retcount = SNPRINTF (result + length, maxlen, buf,  \
                                        prefixes[0], prefixes[1], arg, \
                                        &count);                   \
                     break;                                        \
                    default:                                              \
                     abort ();                                     \
                    }
#else
# define SNPRINTF_BUF(arg) \
                  switch (prefix_count)                            \
                    {                                                     \
                    case 0:                                        \
                     count = sprintf (tmp, buf, arg);              \
                     break;                                        \
                    case 1:                                        \
                     count = sprintf (tmp, buf, prefixes[0], arg);        \
                     break;                                        \
                    case 2:                                        \
                     count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
                                    arg);                          \
                     break;                                        \
                    default:                                              \
                     abort ();                                     \
                    }
#endif

                  switch (type)
                    {
                    case TYPE_SCHAR:
                     {
                       int arg = a.arg[dp->arg_index].a.a_schar;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_UCHAR:
                     {
                       unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_SHORT:
                     {
                       int arg = a.arg[dp->arg_index].a.a_short;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_USHORT:
                     {
                       unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_INT:
                     {
                       int arg = a.arg[dp->arg_index].a.a_int;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_UINT:
                     {
                       unsigned int arg = a.arg[dp->arg_index].a.a_uint;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_LONGINT:
                     {
                       long int arg = a.arg[dp->arg_index].a.a_longint;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_ULONGINT:
                     {
                       unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#ifdef HAVE_LONG_LONG
                    case TYPE_LONGLONGINT:
                     {
                       long long int arg = a.arg[dp->arg_index].a.a_longlongint;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    case TYPE_ULONGLONGINT:
                     {
                       unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#endif
                    case TYPE_DOUBLE:
                     {
                       double arg = a.arg[dp->arg_index].a.a_double;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#ifdef HAVE_LONG_DOUBLE
                    case TYPE_LONGDOUBLE:
                     {
                       long double arg = a.arg[dp->arg_index].a.a_longdouble;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#endif
                    case TYPE_CHAR:
                     {
                       int arg = a.arg[dp->arg_index].a.a_char;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#ifdef HAVE_WINT_T
                    case TYPE_WIDE_CHAR:
                     {
                       wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#endif
                    case TYPE_STRING:
                     {
                       const char *arg = a.arg[dp->arg_index].a.a_string;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#ifdef HAVE_WCHAR_T
                    case TYPE_WIDE_STRING:
                     {
                       const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
                       SNPRINTF_BUF (arg);
                     }
                     break;
#endif
                    case TYPE_POINTER:
                     {
                       void *arg = a.arg[dp->arg_index].a.a_pointer;
                       SNPRINTF_BUF (arg);
                     }
                     break;
                    default:
                     abort ();
                    }

#if USE_SNPRINTF
                  /* Portability: Not all implementations of snprintf()
                     are ISO C 99 compliant.  Determine the number of
                     bytes that snprintf() has produced or would have
                     produced.  */
                  if (count >= 0)
                    {
                     /* Verify that snprintf() has NUL-terminated its
                        result.  */
                     if (count < maxlen && result[length + count] != '\0')
                       abort ();
                     /* Portability hack.  */
                     if (retcount > count)
                       count = retcount;
                    }
                  else
                    {
                     /* snprintf() doesn't understand the '%n'
                        directive.  */
                     if (p[1] != '\0')
                       {
                         /* Don't use the '%n' directive; instead, look
                            at the snprintf() return value.  */
                         p[1] = '\0';
                         continue;
                       }
                     else
                       {
                         /* Look at the snprintf() return value.  */
                         if (retcount < 0)
                           {
                            /* HP-UX 10.20 snprintf() is doubly deficient:
                               It doesn't understand the '%n' directive,
                               *and* it returns -1 (rather than the length
                               that would have been required) when the
                               buffer is too small.  */
                            size_t bigger_need =
                              xsum (xtimes (allocated, 2), 12);
                            ENSURE_ALLOCATION (bigger_need);
                            continue;
                           }
                         else
                           count = retcount;
                       }
                    }
#endif

                  /* Attempt to handle failure.  */
                  if (count < 0)
                    {
                     if (!(result == resultbuf || result == NULL))
                       free (result);
                     if (buf_malloced != NULL)
                       free (buf_malloced);
                     CLEANUP ();
                     errno = EINVAL;
                     return NULL;
                    }

#if !USE_SNPRINTF
                  if (count >= tmp_length)
                    /* tmp_length was incorrectly calculated - fix the
                      code above!  */
                    abort ();
#endif

                  /* Make room for the result.  */
                  if (count >= maxlen)
                    {
                     /* Need at least count bytes.  But allocate
                        proportionally, to avoid looping eternally if
                        snprintf() reports a too small count.  */
                     size_t n =
                       xmax (xsum (length, count), xtimes (allocated, 2));

                     ENSURE_ALLOCATION (n);
#if USE_SNPRINTF
                     continue;
#endif
                    }

#if USE_SNPRINTF
                  /* The snprintf() result did fit.  */
#else
                  /* Append the sprintf() result.  */
                  memcpy (result + length, tmp, count * sizeof (CHAR_T));
                  if (tmp != tmpbuf)
                    free (tmp);
#endif

                  length += count;
                  break;
                }
             }
         }
      }

    /* Add the final NUL.  */
    ENSURE_ALLOCATION (xsum (length, 1));
    result[length] = '\0';

    if (result != resultbuf && length + 1 < allocated)
      {
       /* Shrink the allocated memory if possible.  */
       CHAR_T *memory;

       memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
       if (memory != NULL)
         result = memory;
      }

    if (buf_malloced != NULL)
      free (buf_malloced);
    CLEANUP ();
    *lengthp = length;
    return result;

  out_of_memory:
    if (!(result == resultbuf || result == NULL))
      free (result);
    if (buf_malloced != NULL)
      free (buf_malloced);
  out_of_memory_1:
    CLEANUP ();
    errno = ENOMEM;
    return NULL;
  }
}

Here is the call graph for this function: