1/* Like vsprintf but provides a pointer to malloc'd storage, which must 2 be freed by the caller. 3 Copyright (C) 1994, 2003 Free Software Foundation, Inc. 4 5This file is part of the libiberty library. 6Libiberty is free software; you can redistribute it and/or 7modify it under the terms of the GNU Library General Public 8License as published by the Free Software Foundation; either 9version 2 of the License, or (at your option) any later version. 10 11Libiberty is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14Library General Public License for more details. 15 16You should have received a copy of the GNU Library General Public 17License along with libiberty; see the file COPYING.LIB. If 18not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 19Boston, MA 02110-1301, USA. */ 20 21#ifdef HAVE_CONFIG_H 22#include "config.h" 23#endif 24#include <ansidecl.h> 25#include <stdarg.h> 26#if !defined (va_copy) && defined (__va_copy) 27# define va_copy(d,s) __va_copy((d),(s)) 28#endif 29#include <stdio.h> 30#ifdef HAVE_STRING_H 31#include <string.h> 32#endif 33#ifdef HAVE_STDLIB_H 34#include <stdlib.h> 35#else 36extern unsigned long strtoul (); 37extern PTR malloc (); 38#endif 39#include "libiberty.h" 40 41#ifdef TEST 42int global_total_width; 43#endif 44 45/* 46 47@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) 48 49Like @code{vsprintf}, but instead of passing a pointer to a buffer, 50you pass a pointer to a pointer. This function will compute the size 51of the buffer needed, allocate memory with @code{malloc}, and store a 52pointer to the allocated memory in @code{*@var{resptr}}. The value 53returned is the same as @code{vsprintf} would return. If memory could 54not be allocated, minus one is returned and @code{NULL} is stored in 55@code{*@var{resptr}}. 56 57@end deftypefn 58 59*/ 60 61static int int_vasprintf (char **, const char *, va_list); 62 63static int 64int_vasprintf (char **result, const char *format, va_list args) 65{ 66 const char *p = format; 67 /* Add one to make sure that it is never zero, which might cause malloc 68 to return NULL. */ 69 int total_width = strlen (format) + 1; 70 va_list ap; 71 72#ifdef va_copy 73 va_copy (ap, args); 74#else 75 memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); 76#endif 77 78 while (*p != '\0') 79 { 80 if (*p++ == '%') 81 { 82 while (strchr ("-+ #0", *p)) 83 ++p; 84 if (*p == '*') 85 { 86 ++p; 87 total_width += abs (va_arg (ap, int)); 88 } 89 else 90 total_width += strtoul (p, (char **) &p, 10); 91 if (*p == '.') 92 { 93 ++p; 94 if (*p == '*') 95 { 96 ++p; 97 total_width += abs (va_arg (ap, int)); 98 } 99 else 100 total_width += strtoul (p, (char **) &p, 10); 101 } 102 while (strchr ("hlL", *p)) 103 ++p; 104 /* Should be big enough for any format specifier except %s and floats. */ 105 total_width += 30; 106 switch (*p) 107 { 108 case 'd': 109 case 'i': 110 case 'o': 111 case 'u': 112 case 'x': 113 case 'X': 114 case 'c': 115 (void) va_arg (ap, int); 116 break; 117 case 'f': 118 case 'e': 119 case 'E': 120 case 'g': 121 case 'G': 122 (void) va_arg (ap, double); 123 /* Since an ieee double can have an exponent of 307, we'll 124 make the buffer wide enough to cover the gross case. */ 125 total_width += 307; 126 break; 127 case 's': 128 total_width += strlen (va_arg (ap, char *)); 129 break; 130 case 'p': 131 case 'n': 132 (void) va_arg (ap, char *); 133 break; 134 } 135 p++; 136 } 137 } 138#ifdef va_copy 139 va_end (ap); 140#endif 141#ifdef TEST 142 global_total_width = total_width; 143#endif 144 *result = (char *) malloc (total_width); 145 if (*result != NULL) 146 return vsprintf (*result, format, args); 147 else 148 return -1; 149} 150 151int 152vasprintf (char **result, const char *format, 153#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) 154 _BSD_VA_LIST_ args) 155#else 156 va_list args) 157#endif 158{ 159 return int_vasprintf (result, format, args); 160} 161 162#ifdef TEST 163static void ATTRIBUTE_PRINTF_1 164checkit (const char *format, ...) 165{ 166 char *result; 167 VA_OPEN (args, format); 168 VA_FIXEDARG (args, const char *, format); 169 vasprintf (&result, format, args); 170 VA_CLOSE (args); 171 172 if (strlen (result) < (size_t) global_total_width) 173 printf ("PASS: "); 174 else 175 printf ("FAIL: "); 176 printf ("%d %s\n", global_total_width, result); 177 178 free (result); 179} 180 181extern int main (void); 182 183int 184main (void) 185{ 186 checkit ("%d", 0x12345678); 187 checkit ("%200d", 5); 188 checkit ("%.300d", 6); 189 checkit ("%100.150d", 7); 190 checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 191777777777777777777333333333333366666666666622222222222777777777777733333"); 192 checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); 193 194 return 0; 195} 196#endif /* TEST */ 197