Back to index

cell-binutils  2.17cvs20070401
vasprintf.c
Go to the documentation of this file.
00001 /* Like vsprintf but provides a pointer to malloc'd storage, which must
00002    be freed by the caller.
00003    Copyright (C) 1994, 2003 Free Software Foundation, Inc.
00004 
00005 This file is part of the libiberty library.
00006 Libiberty is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Library General Public
00008 License as published by the Free Software Foundation; either
00009 version 2 of the License, or (at your option) any later version.
00010 
00011 Libiberty is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Library General Public License for more details.
00015 
00016 You should have received a copy of the GNU Library General Public
00017 License along with libiberty; see the file COPYING.LIB.  If
00018 not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019 Boston, MA 02110-1301, USA.  */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 #include <ansidecl.h>
00025 #include <stdarg.h>
00026 #if !defined (va_copy) && defined (__va_copy)
00027 # define va_copy(d,s)  __va_copy((d),(s))
00028 #endif
00029 #include <stdio.h>
00030 #ifdef HAVE_STRING_H
00031 #include <string.h>
00032 #endif
00033 #ifdef HAVE_STDLIB_H
00034 #include <stdlib.h>
00035 #else
00036 extern unsigned long strtoul ();
00037 extern PTR malloc ();
00038 #endif
00039 #include "libiberty.h"
00040 
00041 #ifdef TEST
00042 int global_total_width;
00043 #endif
00044 
00045 /*
00046 
00047 @deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
00048 
00049 Like @code{vsprintf}, but instead of passing a pointer to a buffer,
00050 you pass a pointer to a pointer.  This function will compute the size
00051 of the buffer needed, allocate memory with @code{malloc}, and store a
00052 pointer to the allocated memory in @code{*@var{resptr}}.  The value
00053 returned is the same as @code{vsprintf} would return.  If memory could
00054 not be allocated, minus one is returned and @code{NULL} is stored in
00055 @code{*@var{resptr}}.
00056 
00057 @end deftypefn
00058 
00059 */
00060 
00061 static int int_vasprintf (char **, const char *, va_list);
00062 
00063 static int
00064 int_vasprintf (char **result, const char *format, va_list args)
00065 {
00066   const char *p = format;
00067   /* Add one to make sure that it is never zero, which might cause malloc
00068      to return NULL.  */
00069   int total_width = strlen (format) + 1;
00070   va_list ap;
00071 
00072 #ifdef va_copy
00073   va_copy (ap, args);
00074 #else
00075   memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
00076 #endif
00077 
00078   while (*p != '\0')
00079     {
00080       if (*p++ == '%')
00081        {
00082          while (strchr ("-+ #0", *p))
00083            ++p;
00084          if (*p == '*')
00085            {
00086              ++p;
00087              total_width += abs (va_arg (ap, int));
00088            }
00089          else
00090            total_width += strtoul (p, (char **) &p, 10);
00091          if (*p == '.')
00092            {
00093              ++p;
00094              if (*p == '*')
00095               {
00096                 ++p;
00097                 total_width += abs (va_arg (ap, int));
00098               }
00099              else
00100              total_width += strtoul (p, (char **) &p, 10);
00101            }
00102          while (strchr ("hlL", *p))
00103            ++p;
00104          /* Should be big enough for any format specifier except %s and floats.  */
00105          total_width += 30;
00106          switch (*p)
00107            {
00108            case 'd':
00109            case 'i':
00110            case 'o':
00111            case 'u':
00112            case 'x':
00113            case 'X':
00114            case 'c':
00115              (void) va_arg (ap, int);
00116              break;
00117            case 'f':
00118            case 'e':
00119            case 'E':
00120            case 'g':
00121            case 'G':
00122              (void) va_arg (ap, double);
00123              /* Since an ieee double can have an exponent of 307, we'll
00124                make the buffer wide enough to cover the gross case. */
00125              total_width += 307;
00126              break;
00127            case 's':
00128              total_width += strlen (va_arg (ap, char *));
00129              break;
00130            case 'p':
00131            case 'n':
00132              (void) va_arg (ap, char *);
00133              break;
00134            }
00135          p++;
00136        }
00137     }
00138 #ifdef va_copy
00139   va_end (ap);
00140 #endif
00141 #ifdef TEST
00142   global_total_width = total_width;
00143 #endif
00144   *result = (char *) malloc (total_width);
00145   if (*result != NULL)
00146     return vsprintf (*result, format, args);
00147   else
00148     return -1;
00149 }
00150 
00151 int
00152 vasprintf (char **result, const char *format,
00153 #if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
00154            _BSD_VA_LIST_ args)
00155 #else
00156            va_list args)
00157 #endif
00158 {
00159   return int_vasprintf (result, format, args);
00160 }
00161 
00162 #ifdef TEST
00163 static void ATTRIBUTE_PRINTF_1
00164 checkit (const char *format, ...)
00165 {
00166   char *result;
00167   VA_OPEN (args, format);
00168   VA_FIXEDARG (args, const char *, format);
00169   vasprintf (&result, format, args);
00170   VA_CLOSE (args);
00171 
00172   if (strlen (result) < (size_t) global_total_width)
00173     printf ("PASS: ");
00174   else
00175     printf ("FAIL: ");
00176   printf ("%d %s\n", global_total_width, result);
00177 
00178   free (result);
00179 }
00180 
00181 extern int main (void);
00182 
00183 int
00184 main (void)
00185 {
00186   checkit ("%d", 0x12345678);
00187   checkit ("%200d", 5);
00188   checkit ("%.300d", 6);
00189   checkit ("%100.150d", 7);
00190   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
00191 777777777777777777333333333333366666666666622222222222777777777777733333");
00192   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
00193 
00194   return 0;
00195 }
00196 #endif /* TEST */