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