vasnprintf.c

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

Generated on Fri Oct 5 18:20:27 2007 for WvStreams by  doxygen 1.5.3