1169695Skan/* Like vsprintf but provides a pointer to malloc'd storage, which must 2169695Skan be freed by the caller. 3169695Skan Copyright (C) 1994, 2003 Free Software Foundation, Inc. 4169695Skan 5169695SkanThis file is part of the libiberty library. 6169695SkanLibiberty is free software; you can redistribute it and/or 7169695Skanmodify it under the terms of the GNU Library General Public 8169695SkanLicense as published by the Free Software Foundation; either 9169695Skanversion 2 of the License, or (at your option) any later version. 10169695Skan 11169695SkanLibiberty is distributed in the hope that it will be useful, 12169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 13169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14169695SkanLibrary General Public License for more details. 15169695Skan 16169695SkanYou should have received a copy of the GNU Library General Public 17169695SkanLicense along with libiberty; see the file COPYING.LIB. If 18169695Skannot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 19169695SkanBoston, MA 02110-1301, USA. */ 20169695Skan 21169695Skan#ifdef HAVE_CONFIG_H 22169695Skan#include "config.h" 23169695Skan#endif 24169695Skan#include <ansidecl.h> 25169695Skan#include <stdarg.h> 26169695Skan#if !defined (va_copy) && defined (__va_copy) 27169695Skan# define va_copy(d,s) __va_copy((d),(s)) 28169695Skan#endif 29169695Skan#include <stdio.h> 30169695Skan#ifdef HAVE_STRING_H 31169695Skan#include <string.h> 32169695Skan#endif 33169695Skan#ifdef HAVE_STDLIB_H 34169695Skan#include <stdlib.h> 35169695Skan#else 36169695Skanextern unsigned long strtoul (); 37169695Skanextern PTR malloc (); 38169695Skan#endif 39169695Skan#include "libiberty.h" 40169695Skan 41169695Skan#ifdef TEST 42169695Skanint global_total_width; 43169695Skan#endif 44169695Skan 45169695Skan/* 46169695Skan 47169695Skan@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) 48169695Skan 49169695SkanLike @code{vsprintf}, but instead of passing a pointer to a buffer, 50169695Skanyou pass a pointer to a pointer. This function will compute the size 51169695Skanof the buffer needed, allocate memory with @code{malloc}, and store a 52169695Skanpointer to the allocated memory in @code{*@var{resptr}}. The value 53169695Skanreturned is the same as @code{vsprintf} would return. If memory could 54169695Skannot be allocated, minus one is returned and @code{NULL} is stored in 55169695Skan@code{*@var{resptr}}. 56169695Skan 57169695Skan@end deftypefn 58169695Skan 59169695Skan*/ 60169695Skan 61169695Skanstatic int int_vasprintf (char **, const char *, va_list); 62169695Skan 63169695Skanstatic int 64169695Skanint_vasprintf (char **result, const char *format, va_list args) 65169695Skan{ 66169695Skan const char *p = format; 67169695Skan /* Add one to make sure that it is never zero, which might cause malloc 68169695Skan to return NULL. */ 69169695Skan int total_width = strlen (format) + 1; 70169695Skan va_list ap; 71169695Skan 72169695Skan#ifdef va_copy 73169695Skan va_copy (ap, args); 74169695Skan#else 75169695Skan memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); 76169695Skan#endif 77169695Skan 78169695Skan while (*p != '\0') 79169695Skan { 80169695Skan if (*p++ == '%') 81169695Skan { 82169695Skan while (strchr ("-+ #0", *p)) 83169695Skan ++p; 84169695Skan if (*p == '*') 85169695Skan { 86169695Skan ++p; 87169695Skan total_width += abs (va_arg (ap, int)); 88169695Skan } 89169695Skan else 90169695Skan total_width += strtoul (p, (char **) &p, 10); 91169695Skan if (*p == '.') 92169695Skan { 93169695Skan ++p; 94169695Skan if (*p == '*') 95169695Skan { 96169695Skan ++p; 97169695Skan total_width += abs (va_arg (ap, int)); 98169695Skan } 99169695Skan else 100169695Skan total_width += strtoul (p, (char **) &p, 10); 101169695Skan } 102169695Skan while (strchr ("hlL", *p)) 103169695Skan ++p; 104169695Skan /* Should be big enough for any format specifier except %s and floats. */ 105169695Skan total_width += 30; 106169695Skan switch (*p) 107169695Skan { 108169695Skan case 'd': 109169695Skan case 'i': 110169695Skan case 'o': 111169695Skan case 'u': 112169695Skan case 'x': 113169695Skan case 'X': 114169695Skan case 'c': 115169695Skan (void) va_arg (ap, int); 116169695Skan break; 117169695Skan case 'f': 118169695Skan case 'e': 119169695Skan case 'E': 120169695Skan case 'g': 121169695Skan case 'G': 122169695Skan (void) va_arg (ap, double); 123169695Skan /* Since an ieee double can have an exponent of 307, we'll 124169695Skan make the buffer wide enough to cover the gross case. */ 125169695Skan total_width += 307; 126169695Skan break; 127169695Skan case 's': 128169695Skan total_width += strlen (va_arg (ap, char *)); 129169695Skan break; 130169695Skan case 'p': 131169695Skan case 'n': 132169695Skan (void) va_arg (ap, char *); 133169695Skan break; 134169695Skan } 135169695Skan p++; 136169695Skan } 137169695Skan } 138169695Skan#ifdef va_copy 139169695Skan va_end (ap); 140169695Skan#endif 141169695Skan#ifdef TEST 142169695Skan global_total_width = total_width; 143169695Skan#endif 144169695Skan *result = (char *) malloc (total_width); 145169695Skan if (*result != NULL) 146169695Skan return vsprintf (*result, format, args); 147169695Skan else 148169695Skan return -1; 149169695Skan} 150169695Skan 151169695Skanint 152169695Skanvasprintf (char **result, const char *format, 153169695Skan#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) 154169695Skan _BSD_VA_LIST_ args) 155169695Skan#else 156169695Skan va_list args) 157169695Skan#endif 158169695Skan{ 159169695Skan return int_vasprintf (result, format, args); 160169695Skan} 161169695Skan 162169695Skan#ifdef TEST 163169695Skanstatic void ATTRIBUTE_PRINTF_1 164169695Skancheckit (const char *format, ...) 165169695Skan{ 166169695Skan char *result; 167169695Skan VA_OPEN (args, format); 168169695Skan VA_FIXEDARG (args, const char *, format); 169169695Skan vasprintf (&result, format, args); 170169695Skan VA_CLOSE (args); 171169695Skan 172169695Skan if (strlen (result) < (size_t) global_total_width) 173169695Skan printf ("PASS: "); 174169695Skan else 175169695Skan printf ("FAIL: "); 176169695Skan printf ("%d %s\n", global_total_width, result); 177169695Skan 178169695Skan free (result); 179169695Skan} 180169695Skan 181169695Skanextern int main (void); 182169695Skan 183169695Skanint 184169695Skanmain (void) 185169695Skan{ 186169695Skan checkit ("%d", 0x12345678); 187169695Skan checkit ("%200d", 5); 188169695Skan checkit ("%.300d", 6); 189169695Skan checkit ("%100.150d", 7); 190169695Skan checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 191169695Skan777777777777777777333333333333366666666666622222222222777777777777733333"); 192169695Skan checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); 193169695Skan 194169695Skan return 0; 195169695Skan} 196169695Skan#endif /* TEST */ 197