1 /* Like vsprintf but provides a pointer to malloc'd storage, which must 2 be freed by the caller. 3 Copyright (C) 1994, 2003, 2011, 2013 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., 51 Franklin Street - Fifth Floor, 19 Boston, 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 36 extern unsigned long strtoul (); 37 extern PTR malloc (); 38 #endif 39 #include "libiberty.h" 40 41 #ifdef TEST 42 int global_total_width; 43 #endif 44 45 /* 46 47 @deftypefn Extension int vasprintf (char **@var{resptr}, @ 48 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 (char **, const char *, va_list); 63 64 static int 65 int_vasprintf (char **result, const char *format, va_list args) 66 { 67 const char *p = format; 68 /* Add one to make sure that it is never zero, which might cause malloc 69 to return NULL. */ 70 int total_width = strlen (format) + 1; 71 va_list ap; 72 73 #ifdef va_copy 74 va_copy (ap, args); 75 #else 76 memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); 77 #endif 78 79 while (*p != '\0') 80 { 81 if (*p++ == '%') 82 { 83 while (strchr ("-+ #0", *p)) 84 ++p; 85 if (*p == '*') 86 { 87 ++p; 88 total_width += abs (va_arg (ap, int)); 89 } 90 else 91 total_width += strtoul (p, (char **) &p, 10); 92 if (*p == '.') 93 { 94 ++p; 95 if (*p == '*') 96 { 97 ++p; 98 total_width += abs (va_arg (ap, int)); 99 } 100 else 101 total_width += strtoul (p, (char **) &p, 10); 102 } 103 while (strchr ("hlL", *p)) 104 ++p; 105 /* Should be big enough for any format specifier except %s and floats. */ 106 total_width += 30; 107 switch (*p) 108 { 109 case 'd': 110 case 'i': 111 case 'o': 112 case 'u': 113 case 'x': 114 case 'X': 115 case 'c': 116 (void) va_arg (ap, int); 117 break; 118 case 'f': 119 case 'e': 120 case 'E': 121 case 'g': 122 case 'G': 123 (void) va_arg (ap, double); 124 /* Since an ieee double can have an exponent of 307, we'll 125 make the buffer wide enough to cover the gross case. */ 126 total_width += 307; 127 break; 128 case 's': 129 total_width += strlen (va_arg (ap, char *)); 130 break; 131 case 'p': 132 case 'n': 133 (void) va_arg (ap, char *); 134 break; 135 } 136 p++; 137 } 138 } 139 #ifdef va_copy 140 va_end (ap); 141 #endif 142 #ifdef TEST 143 global_total_width = total_width; 144 #endif 145 *result = (char *) malloc (total_width); 146 if (*result != NULL) 147 return vsprintf (*result, format, args); 148 else 149 return -1; 150 } 151 152 int 153 vasprintf (char **result, const char *format, 154 #if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) 155 _BSD_VA_LIST_ args) 156 #else 157 va_list args) 158 #endif 159 { 160 return int_vasprintf (result, format, args); 161 } 162 163 #ifdef TEST 164 static void ATTRIBUTE_PRINTF_1 165 checkit (const char *format, ...) 166 { 167 char *result; 168 va_list args; 169 va_start (args, format); 170 vasprintf (&result, format, args); 171 va_end (args); 172 173 if (strlen (result) < (size_t) global_total_width) 174 printf ("PASS: "); 175 else 176 printf ("FAIL: "); 177 printf ("%d %s\n", global_total_width, result); 178 179 free (result); 180 } 181 182 extern int main (void); 183 184 int 185 main (void) 186 { 187 checkit ("%d", 0x12345678); 188 checkit ("%200d", 5); 189 checkit ("%.300d", 6); 190 checkit ("%100.150d", 7); 191 checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 192 777777777777777777333333333333366666666666622222222222777777777777733333"); 193 checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); 194 195 return 0; 196 } 197 #endif /* TEST */ 198