Back to index

tetex-bin  3.0
vasnprintf.c
Go to the documentation of this file.
00001 /* vsprintf with automatic memory allocation.
00002    Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify it
00005    under the terms of the GNU Library General Public License as published
00006    by the Free Software Foundation; either version 2, or (at your option)
00007    any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public
00015    License along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00017    USA.  */
00018 
00019 /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
00020    This must come before <config.h> because <config.h> may include
00021    <features.h>, and once <features.h> has been included, it's too late.  */
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE    1
00024 #endif
00025 
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 #ifndef IN_LIBINTL
00030 # include <alloca.h>
00031 #endif
00032 
00033 /* Specification.  */
00034 #if WIDE_CHAR_VERSION
00035 # include "vasnwprintf.h"
00036 #else
00037 # include "vasnprintf.h"
00038 #endif
00039 
00040 #include <stdio.h>   /* snprintf(), sprintf() */
00041 #include <stdlib.h>  /* abort(), malloc(), realloc(), free() */
00042 #include <string.h>  /* memcpy(), strlen() */
00043 #include <errno.h>   /* errno */
00044 #include <limits.h>  /* CHAR_BIT */
00045 #include <float.h>   /* DBL_MAX_EXP, LDBL_MAX_EXP */
00046 #if WIDE_CHAR_VERSION
00047 # include "wprintf-parse.h"
00048 #else
00049 # include "printf-parse.h"
00050 #endif
00051 
00052 /* Checked size_t computations.  */
00053 #include "xsize.h"
00054 
00055 #ifdef HAVE_WCHAR_T
00056 # ifdef HAVE_WCSLEN
00057 #  define local_wcslen wcslen
00058 # else
00059    /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
00060       a dependency towards this library, here is a local substitute.
00061       Define this substitute only once, even if this file is included
00062       twice in the same compilation unit.  */
00063 #  ifndef local_wcslen_defined
00064 #   define local_wcslen_defined 1
00065 static size_t
00066 local_wcslen (const wchar_t *s)
00067 {
00068   const wchar_t *ptr;
00069 
00070   for (ptr = s; *ptr != (wchar_t) 0; ptr++)
00071     ;
00072   return ptr - s;
00073 }
00074 #  endif
00075 # endif
00076 #endif
00077 
00078 #if WIDE_CHAR_VERSION
00079 # define VASNPRINTF vasnwprintf
00080 # define CHAR_T wchar_t
00081 # define DIRECTIVE wchar_t_directive
00082 # define DIRECTIVES wchar_t_directives
00083 # define PRINTF_PARSE wprintf_parse
00084 # define USE_SNPRINTF 1
00085 # if HAVE_DECL__SNWPRINTF
00086    /* On Windows, the function swprintf() has a different signature than
00087       on Unix; we use the _snwprintf() function instead.  */
00088 #  define SNPRINTF _snwprintf
00089 # else
00090    /* Unix.  */
00091 #  define SNPRINTF swprintf
00092 # endif
00093 #else
00094 # define VASNPRINTF vasnprintf
00095 # define CHAR_T char
00096 # define DIRECTIVE char_directive
00097 # define DIRECTIVES char_directives
00098 # define PRINTF_PARSE printf_parse
00099 # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
00100 # if HAVE_DECL__SNPRINTF
00101    /* Windows.  */
00102 #  define SNPRINTF _snprintf
00103 # else
00104    /* Unix.  */
00105 #  define SNPRINTF snprintf
00106 # endif
00107 #endif
00108 
00109 CHAR_T *
00110 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
00111 {
00112   DIRECTIVES d;
00113   arguments a;
00114 
00115   if (PRINTF_PARSE (format, &d, &a) < 0)
00116     {
00117       errno = EINVAL;
00118       return NULL;
00119     }
00120 
00121 #define CLEANUP() \
00122   free (d.dir);                                                       \
00123   if (a.arg)                                                   \
00124     free (a.arg);
00125 
00126   if (printf_fetchargs (args, &a) < 0)
00127     {
00128       CLEANUP ();
00129       errno = EINVAL;
00130       return NULL;
00131     }
00132 
00133   {
00134     size_t buf_neededlength;
00135     CHAR_T *buf;
00136     CHAR_T *buf_malloced;
00137     const CHAR_T *cp;
00138     size_t i;
00139     DIRECTIVE *dp;
00140     /* Output string accumulator.  */
00141     CHAR_T *result;
00142     size_t allocated;
00143     size_t length;
00144 
00145     /* Allocate a small buffer that will hold a directive passed to
00146        sprintf or snprintf.  */
00147     buf_neededlength =
00148       xsum4 (7, d.max_width_length, d.max_precision_length, 6);
00149 #if HAVE_ALLOCA
00150     if (buf_neededlength < 4000 / sizeof (CHAR_T))
00151       {
00152        buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
00153        buf_malloced = NULL;
00154       }
00155     else
00156 #endif
00157       {
00158        size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
00159        if (size_overflow_p (buf_memsize))
00160          goto out_of_memory_1;
00161        buf = (CHAR_T *) malloc (buf_memsize);
00162        if (buf == NULL)
00163          goto out_of_memory_1;
00164        buf_malloced = buf;
00165       }
00166 
00167     if (resultbuf != NULL)
00168       {
00169        result = resultbuf;
00170        allocated = *lengthp;
00171       }
00172     else
00173       {
00174        result = NULL;
00175        allocated = 0;
00176       }
00177     length = 0;
00178     /* Invariants:
00179        result is either == resultbuf or == NULL or malloc-allocated.
00180        If length > 0, then result != NULL.  */
00181 
00182     /* Ensures that allocated >= needed.  Aborts through a jump to
00183        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
00184 #define ENSURE_ALLOCATION(needed) \
00185     if ((needed) > allocated)                                              \
00186       {                                                                    \
00187        size_t memory_size;                                          \
00188        CHAR_T *memory;                                                     \
00189                                                                     \
00190        allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);           \
00191        if ((needed) > allocated)                                    \
00192          allocated = (needed);                                             \
00193        memory_size = xtimes (allocated, sizeof (CHAR_T));                  \
00194        if (size_overflow_p (memory_size))                           \
00195          goto out_of_memory;                                               \
00196        if (result == resultbuf || result == NULL)                          \
00197          memory = (CHAR_T *) malloc (memory_size);                         \
00198        else                                                         \
00199          memory = (CHAR_T *) realloc (result, memory_size);                \
00200        if (memory == NULL)                                          \
00201          goto out_of_memory;                                               \
00202        if (result == resultbuf && length > 0)                              \
00203          memcpy (memory, result, length * sizeof (CHAR_T));                \
00204        result = memory;                                             \
00205       }
00206 
00207     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
00208       {
00209        if (cp != dp->dir_start)
00210          {
00211            size_t n = dp->dir_start - cp;
00212            size_t augmented_length = xsum (length, n);
00213 
00214            ENSURE_ALLOCATION (augmented_length);
00215            memcpy (result + length, cp, n * sizeof (CHAR_T));
00216            length = augmented_length;
00217          }
00218        if (i == d.count)
00219          break;
00220 
00221        /* Execute a single directive.  */
00222        if (dp->conversion == '%')
00223          {
00224            size_t augmented_length;
00225 
00226            if (!(dp->arg_index == ARG_NONE))
00227              abort ();
00228            augmented_length = xsum (length, 1);
00229            ENSURE_ALLOCATION (augmented_length);
00230            result[length] = '%';
00231            length = augmented_length;
00232          }
00233        else
00234          {
00235            if (!(dp->arg_index != ARG_NONE))
00236              abort ();
00237 
00238            if (dp->conversion == 'n')
00239              {
00240               switch (a.arg[dp->arg_index].type)
00241                 {
00242                 case TYPE_COUNT_SCHAR_POINTER:
00243                   *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
00244                   break;
00245                 case TYPE_COUNT_SHORT_POINTER:
00246                   *a.arg[dp->arg_index].a.a_count_short_pointer = length;
00247                   break;
00248                 case TYPE_COUNT_INT_POINTER:
00249                   *a.arg[dp->arg_index].a.a_count_int_pointer = length;
00250                   break;
00251                 case TYPE_COUNT_LONGINT_POINTER:
00252                   *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
00253                   break;
00254 #ifdef HAVE_LONG_LONG
00255                 case TYPE_COUNT_LONGLONGINT_POINTER:
00256                   *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
00257                   break;
00258 #endif
00259                 default:
00260                   abort ();
00261                 }
00262              }
00263            else
00264              {
00265               arg_type type = a.arg[dp->arg_index].type;
00266               CHAR_T *p;
00267               unsigned int prefix_count;
00268               int prefixes[2];
00269 #if !USE_SNPRINTF
00270               size_t tmp_length;
00271               CHAR_T tmpbuf[700];
00272               CHAR_T *tmp;
00273 
00274               /* Allocate a temporary buffer of sufficient size for calling
00275                  sprintf.  */
00276               {
00277                 size_t width;
00278                 size_t precision;
00279 
00280                 width = 0;
00281                 if (dp->width_start != dp->width_end)
00282                   {
00283                     if (dp->width_arg_index != ARG_NONE)
00284                      {
00285                        int arg;
00286 
00287                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
00288                          abort ();
00289                        arg = a.arg[dp->width_arg_index].a.a_int;
00290                        width = (arg < 0 ? (unsigned int) (-arg) : arg);
00291                      }
00292                     else
00293                      {
00294                        const CHAR_T *digitp = dp->width_start;
00295 
00296                        do
00297                          width = xsum (xtimes (width, 10), *digitp++ - '0');
00298                        while (digitp != dp->width_end);
00299                      }
00300                   }
00301 
00302                 precision = 6;
00303                 if (dp->precision_start != dp->precision_end)
00304                   {
00305                     if (dp->precision_arg_index != ARG_NONE)
00306                      {
00307                        int arg;
00308 
00309                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
00310                          abort ();
00311                        arg = a.arg[dp->precision_arg_index].a.a_int;
00312                        precision = (arg < 0 ? 0 : arg);
00313                      }
00314                     else
00315                      {
00316                        const CHAR_T *digitp = dp->precision_start + 1;
00317 
00318                        precision = 0;
00319                        do
00320                          precision = xsum (xtimes (precision, 10), *digitp++ - '0');
00321                        while (digitp != dp->precision_end);
00322                      }
00323                   }
00324 
00325                 switch (dp->conversion)
00326                   {
00327 
00328                   case 'd': case 'i': case 'u':
00329 # ifdef HAVE_LONG_LONG
00330                     if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
00331                      tmp_length =
00332                        (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
00333                                      * 0.30103 /* binary -> decimal */
00334                                      * 2 /* estimate for FLAG_GROUP */
00335                                     )
00336                        + 1 /* turn floor into ceil */
00337                        + 1; /* account for leading sign */
00338                     else
00339 # endif
00340                     if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
00341                      tmp_length =
00342                        (unsigned int) (sizeof (unsigned long) * CHAR_BIT
00343                                      * 0.30103 /* binary -> decimal */
00344                                      * 2 /* estimate for FLAG_GROUP */
00345                                     )
00346                        + 1 /* turn floor into ceil */
00347                        + 1; /* account for leading sign */
00348                     else
00349                      tmp_length =
00350                        (unsigned int) (sizeof (unsigned int) * CHAR_BIT
00351                                      * 0.30103 /* binary -> decimal */
00352                                      * 2 /* estimate for FLAG_GROUP */
00353                                     )
00354                        + 1 /* turn floor into ceil */
00355                        + 1; /* account for leading sign */
00356                     break;
00357 
00358                   case 'o':
00359 # ifdef HAVE_LONG_LONG
00360                     if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
00361                      tmp_length =
00362                        (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
00363                                      * 0.333334 /* binary -> octal */
00364                                     )
00365                        + 1 /* turn floor into ceil */
00366                        + 1; /* account for leading sign */
00367                     else
00368 # endif
00369                     if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
00370                      tmp_length =
00371                        (unsigned int) (sizeof (unsigned long) * CHAR_BIT
00372                                      * 0.333334 /* binary -> octal */
00373                                     )
00374                        + 1 /* turn floor into ceil */
00375                        + 1; /* account for leading sign */
00376                     else
00377                      tmp_length =
00378                        (unsigned int) (sizeof (unsigned int) * CHAR_BIT
00379                                      * 0.333334 /* binary -> octal */
00380                                     )
00381                        + 1 /* turn floor into ceil */
00382                        + 1; /* account for leading sign */
00383                     break;
00384 
00385                   case 'x': case 'X':
00386 # ifdef HAVE_LONG_LONG
00387                     if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
00388                      tmp_length =
00389                        (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
00390                                      * 0.25 /* binary -> hexadecimal */
00391                                     )
00392                        + 1 /* turn floor into ceil */
00393                        + 2; /* account for leading sign or alternate form */
00394                     else
00395 # endif
00396                     if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
00397                      tmp_length =
00398                        (unsigned int) (sizeof (unsigned long) * CHAR_BIT
00399                                      * 0.25 /* binary -> hexadecimal */
00400                                     )
00401                        + 1 /* turn floor into ceil */
00402                        + 2; /* account for leading sign or alternate form */
00403                     else
00404                      tmp_length =
00405                        (unsigned int) (sizeof (unsigned int) * CHAR_BIT
00406                                      * 0.25 /* binary -> hexadecimal */
00407                                     )
00408                        + 1 /* turn floor into ceil */
00409                        + 2; /* account for leading sign or alternate form */
00410                     break;
00411 
00412                   case 'f': case 'F':
00413 # ifdef HAVE_LONG_DOUBLE
00414                     if (type == TYPE_LONGDOUBLE)
00415                      tmp_length =
00416                        (unsigned int) (LDBL_MAX_EXP
00417                                      * 0.30103 /* binary -> decimal */
00418                                      * 2 /* estimate for FLAG_GROUP */
00419                                     )
00420                        + 1 /* turn floor into ceil */
00421                        + 10; /* sign, decimal point etc. */
00422                     else
00423 # endif
00424                      tmp_length =
00425                        (unsigned int) (DBL_MAX_EXP
00426                                      * 0.30103 /* binary -> decimal */
00427                                      * 2 /* estimate for FLAG_GROUP */
00428                                     )
00429                        + 1 /* turn floor into ceil */
00430                        + 10; /* sign, decimal point etc. */
00431                     tmp_length = xsum (tmp_length, precision);
00432                     break;
00433 
00434                   case 'e': case 'E': case 'g': case 'G':
00435                   case 'a': case 'A':
00436                     tmp_length =
00437                      12; /* sign, decimal point, exponent etc. */
00438                     tmp_length = xsum (tmp_length, precision);
00439                     break;
00440 
00441                   case 'c':
00442 # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
00443                     if (type == TYPE_WIDE_CHAR)
00444                      tmp_length = MB_CUR_MAX;
00445                     else
00446 # endif
00447                      tmp_length = 1;
00448                     break;
00449 
00450                   case 's':
00451 # ifdef HAVE_WCHAR_T
00452                     if (type == TYPE_WIDE_STRING)
00453                      {
00454                        tmp_length =
00455                          local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
00456 
00457 #  if !WIDE_CHAR_VERSION
00458                        tmp_length = xtimes (tmp_length, MB_CUR_MAX);
00459 #  endif
00460                      }
00461                     else
00462 # endif
00463                      tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
00464                     break;
00465 
00466                   case 'p':
00467                     tmp_length =
00468                      (unsigned int) (sizeof (void *) * CHAR_BIT
00469                                    * 0.25 /* binary -> hexadecimal */
00470                                    )
00471                        + 1 /* turn floor into ceil */
00472                        + 2; /* account for leading 0x */
00473                     break;
00474 
00475                   default:
00476                     abort ();
00477                   }
00478 
00479                 if (tmp_length < width)
00480                   tmp_length = width;
00481 
00482                 tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
00483               }
00484 
00485               if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
00486                 tmp = tmpbuf;
00487               else
00488                 {
00489                   size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
00490 
00491                   if (size_overflow_p (tmp_memsize))
00492                     /* Overflow, would lead to out of memory.  */
00493                     goto out_of_memory;
00494                   tmp = (CHAR_T *) malloc (tmp_memsize);
00495                   if (tmp == NULL)
00496                     /* Out of memory.  */
00497                     goto out_of_memory;
00498                 }
00499 #endif
00500 
00501               /* Construct the format string for calling snprintf or
00502                  sprintf.  */
00503               p = buf;
00504               *p++ = '%';
00505               if (dp->flags & FLAG_GROUP)
00506                 *p++ = '\'';
00507               if (dp->flags & FLAG_LEFT)
00508                 *p++ = '-';
00509               if (dp->flags & FLAG_SHOWSIGN)
00510                 *p++ = '+';
00511               if (dp->flags & FLAG_SPACE)
00512                 *p++ = ' ';
00513               if (dp->flags & FLAG_ALT)
00514                 *p++ = '#';
00515               if (dp->flags & FLAG_ZERO)
00516                 *p++ = '0';
00517               if (dp->width_start != dp->width_end)
00518                 {
00519                   size_t n = dp->width_end - dp->width_start;
00520                   memcpy (p, dp->width_start, n * sizeof (CHAR_T));
00521                   p += n;
00522                 }
00523               if (dp->precision_start != dp->precision_end)
00524                 {
00525                   size_t n = dp->precision_end - dp->precision_start;
00526                   memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
00527                   p += n;
00528                 }
00529 
00530               switch (type)
00531                 {
00532 #ifdef HAVE_LONG_LONG
00533                 case TYPE_LONGLONGINT:
00534                 case TYPE_ULONGLONGINT:
00535                   *p++ = 'l';
00536                   /*FALLTHROUGH*/
00537 #endif
00538                 case TYPE_LONGINT:
00539                 case TYPE_ULONGINT:
00540 #ifdef HAVE_WINT_T
00541                 case TYPE_WIDE_CHAR:
00542 #endif
00543 #ifdef HAVE_WCHAR_T
00544                 case TYPE_WIDE_STRING:
00545 #endif
00546                   *p++ = 'l';
00547                   break;
00548 #ifdef HAVE_LONG_DOUBLE
00549                 case TYPE_LONGDOUBLE:
00550                   *p++ = 'L';
00551                   break;
00552 #endif
00553                 default:
00554                   break;
00555                 }
00556               *p = dp->conversion;
00557 #if USE_SNPRINTF
00558               p[1] = '%';
00559               p[2] = 'n';
00560               p[3] = '\0';
00561 #else
00562               p[1] = '\0';
00563 #endif
00564 
00565               /* Construct the arguments for calling snprintf or sprintf.  */
00566               prefix_count = 0;
00567               if (dp->width_arg_index != ARG_NONE)
00568                 {
00569                   if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
00570                     abort ();
00571                   prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
00572                 }
00573               if (dp->precision_arg_index != ARG_NONE)
00574                 {
00575                   if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
00576                     abort ();
00577                   prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
00578                 }
00579 
00580 #if USE_SNPRINTF
00581               /* Prepare checking whether snprintf returns the count
00582                  via %n.  */
00583               ENSURE_ALLOCATION (xsum (length, 1));
00584               result[length] = '\0';
00585 #endif
00586 
00587               for (;;)
00588                 {
00589                   size_t maxlen;
00590                   int count;
00591                   int retcount;
00592 
00593                   maxlen = allocated - length;
00594                   count = -1;
00595                   retcount = 0;
00596 
00597 #if USE_SNPRINTF
00598 # define SNPRINTF_BUF(arg) \
00599                   switch (prefix_count)                            \
00600                     {                                                     \
00601                     case 0:                                        \
00602                      retcount = SNPRINTF (result + length, maxlen, buf,  \
00603                                         arg, &count);              \
00604                      break;                                        \
00605                     case 1:                                        \
00606                      retcount = SNPRINTF (result + length, maxlen, buf,  \
00607                                         prefixes[0], arg, &count);        \
00608                      break;                                        \
00609                     case 2:                                        \
00610                      retcount = SNPRINTF (result + length, maxlen, buf,  \
00611                                         prefixes[0], prefixes[1], arg, \
00612                                         &count);                   \
00613                      break;                                        \
00614                     default:                                              \
00615                      abort ();                                     \
00616                     }
00617 #else
00618 # define SNPRINTF_BUF(arg) \
00619                   switch (prefix_count)                            \
00620                     {                                                     \
00621                     case 0:                                        \
00622                      count = sprintf (tmp, buf, arg);              \
00623                      break;                                        \
00624                     case 1:                                        \
00625                      count = sprintf (tmp, buf, prefixes[0], arg);        \
00626                      break;                                        \
00627                     case 2:                                        \
00628                      count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
00629                                     arg);                          \
00630                      break;                                        \
00631                     default:                                              \
00632                      abort ();                                     \
00633                     }
00634 #endif
00635 
00636                   switch (type)
00637                     {
00638                     case TYPE_SCHAR:
00639                      {
00640                        int arg = a.arg[dp->arg_index].a.a_schar;
00641                        SNPRINTF_BUF (arg);
00642                      }
00643                      break;
00644                     case TYPE_UCHAR:
00645                      {
00646                        unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
00647                        SNPRINTF_BUF (arg);
00648                      }
00649                      break;
00650                     case TYPE_SHORT:
00651                      {
00652                        int arg = a.arg[dp->arg_index].a.a_short;
00653                        SNPRINTF_BUF (arg);
00654                      }
00655                      break;
00656                     case TYPE_USHORT:
00657                      {
00658                        unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
00659                        SNPRINTF_BUF (arg);
00660                      }
00661                      break;
00662                     case TYPE_INT:
00663                      {
00664                        int arg = a.arg[dp->arg_index].a.a_int;
00665                        SNPRINTF_BUF (arg);
00666                      }
00667                      break;
00668                     case TYPE_UINT:
00669                      {
00670                        unsigned int arg = a.arg[dp->arg_index].a.a_uint;
00671                        SNPRINTF_BUF (arg);
00672                      }
00673                      break;
00674                     case TYPE_LONGINT:
00675                      {
00676                        long int arg = a.arg[dp->arg_index].a.a_longint;
00677                        SNPRINTF_BUF (arg);
00678                      }
00679                      break;
00680                     case TYPE_ULONGINT:
00681                      {
00682                        unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
00683                        SNPRINTF_BUF (arg);
00684                      }
00685                      break;
00686 #ifdef HAVE_LONG_LONG
00687                     case TYPE_LONGLONGINT:
00688                      {
00689                        long long int arg = a.arg[dp->arg_index].a.a_longlongint;
00690                        SNPRINTF_BUF (arg);
00691                      }
00692                      break;
00693                     case TYPE_ULONGLONGINT:
00694                      {
00695                        unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
00696                        SNPRINTF_BUF (arg);
00697                      }
00698                      break;
00699 #endif
00700                     case TYPE_DOUBLE:
00701                      {
00702                        double arg = a.arg[dp->arg_index].a.a_double;
00703                        SNPRINTF_BUF (arg);
00704                      }
00705                      break;
00706 #ifdef HAVE_LONG_DOUBLE
00707                     case TYPE_LONGDOUBLE:
00708                      {
00709                        long double arg = a.arg[dp->arg_index].a.a_longdouble;
00710                        SNPRINTF_BUF (arg);
00711                      }
00712                      break;
00713 #endif
00714                     case TYPE_CHAR:
00715                      {
00716                        int arg = a.arg[dp->arg_index].a.a_char;
00717                        SNPRINTF_BUF (arg);
00718                      }
00719                      break;
00720 #ifdef HAVE_WINT_T
00721                     case TYPE_WIDE_CHAR:
00722                      {
00723                        wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
00724                        SNPRINTF_BUF (arg);
00725                      }
00726                      break;
00727 #endif
00728                     case TYPE_STRING:
00729                      {
00730                        const char *arg = a.arg[dp->arg_index].a.a_string;
00731                        SNPRINTF_BUF (arg);
00732                      }
00733                      break;
00734 #ifdef HAVE_WCHAR_T
00735                     case TYPE_WIDE_STRING:
00736                      {
00737                        const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
00738                        SNPRINTF_BUF (arg);
00739                      }
00740                      break;
00741 #endif
00742                     case TYPE_POINTER:
00743                      {
00744                        void *arg = a.arg[dp->arg_index].a.a_pointer;
00745                        SNPRINTF_BUF (arg);
00746                      }
00747                      break;
00748                     default:
00749                      abort ();
00750                     }
00751 
00752 #if USE_SNPRINTF
00753                   /* Portability: Not all implementations of snprintf()
00754                      are ISO C 99 compliant.  Determine the number of
00755                      bytes that snprintf() has produced or would have
00756                      produced.  */
00757                   if (count >= 0)
00758                     {
00759                      /* Verify that snprintf() has NUL-terminated its
00760                         result.  */
00761                      if (count < maxlen && result[length + count] != '\0')
00762                        abort ();
00763                      /* Portability hack.  */
00764                      if (retcount > count)
00765                        count = retcount;
00766                     }
00767                   else
00768                     {
00769                      /* snprintf() doesn't understand the '%n'
00770                         directive.  */
00771                      if (p[1] != '\0')
00772                        {
00773                          /* Don't use the '%n' directive; instead, look
00774                             at the snprintf() return value.  */
00775                          p[1] = '\0';
00776                          continue;
00777                        }
00778                      else
00779                        {
00780                          /* Look at the snprintf() return value.  */
00781                          if (retcount < 0)
00782                            {
00783                             /* HP-UX 10.20 snprintf() is doubly deficient:
00784                                It doesn't understand the '%n' directive,
00785                                *and* it returns -1 (rather than the length
00786                                that would have been required) when the
00787                                buffer is too small.  */
00788                             size_t bigger_need =
00789                               xsum (xtimes (allocated, 2), 12);
00790                             ENSURE_ALLOCATION (bigger_need);
00791                             continue;
00792                            }
00793                          else
00794                            count = retcount;
00795                        }
00796                     }
00797 #endif
00798 
00799                   /* Attempt to handle failure.  */
00800                   if (count < 0)
00801                     {
00802                      if (!(result == resultbuf || result == NULL))
00803                        free (result);
00804                      if (buf_malloced != NULL)
00805                        free (buf_malloced);
00806                      CLEANUP ();
00807                      errno = EINVAL;
00808                      return NULL;
00809                     }
00810 
00811 #if !USE_SNPRINTF
00812                   if (count >= tmp_length)
00813                     /* tmp_length was incorrectly calculated - fix the
00814                       code above!  */
00815                     abort ();
00816 #endif
00817 
00818                   /* Make room for the result.  */
00819                   if (count >= maxlen)
00820                     {
00821                      /* Need at least count bytes.  But allocate
00822                         proportionally, to avoid looping eternally if
00823                         snprintf() reports a too small count.  */
00824                      size_t n =
00825                        xmax (xsum (length, count), xtimes (allocated, 2));
00826 
00827                      ENSURE_ALLOCATION (n);
00828 #if USE_SNPRINTF
00829                      continue;
00830 #endif
00831                     }
00832 
00833 #if USE_SNPRINTF
00834                   /* The snprintf() result did fit.  */
00835 #else
00836                   /* Append the sprintf() result.  */
00837                   memcpy (result + length, tmp, count * sizeof (CHAR_T));
00838                   if (tmp != tmpbuf)
00839                     free (tmp);
00840 #endif
00841 
00842                   length += count;
00843                   break;
00844                 }
00845              }
00846          }
00847       }
00848 
00849     /* Add the final NUL.  */
00850     ENSURE_ALLOCATION (xsum (length, 1));
00851     result[length] = '\0';
00852 
00853     if (result != resultbuf && length + 1 < allocated)
00854       {
00855        /* Shrink the allocated memory if possible.  */
00856        CHAR_T *memory;
00857 
00858        memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
00859        if (memory != NULL)
00860          result = memory;
00861       }
00862 
00863     if (buf_malloced != NULL)
00864       free (buf_malloced);
00865     CLEANUP ();
00866     *lengthp = length;
00867     return result;
00868 
00869   out_of_memory:
00870     if (!(result == resultbuf || result == NULL))
00871       free (result);
00872     if (buf_malloced != NULL)
00873       free (buf_malloced);
00874   out_of_memory_1:
00875     CLEANUP ();
00876     errno = ENOMEM;
00877     return NULL;
00878   }
00879 }
00880 
00881 #undef SNPRINTF
00882 #undef USE_SNPRINTF
00883 #undef PRINTF_PARSE
00884 #undef DIRECTIVES
00885 #undef DIRECTIVE
00886 #undef CHAR_T
00887 #undef VASNPRINTF