vasprintf.c revision 60484
1/* Like vsprintf but provides a pointer to malloc'd storage, which must 2 be freed by the caller. 3 Copyright (C) 1994 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., 59 Temple Place - Suite 330, 19Boston, MA 02111-1307, USA. */ 20 21#ifdef __STDC__ 22#include <stdarg.h> 23#else 24#include <varargs.h> 25#endif 26#include <stdio.h> 27#include <string.h> 28#include <ansidecl.h> 29 30#ifdef TEST 31int global_total_width; 32#endif 33 34unsigned long strtoul (); 35char *malloc (); 36 37static int 38int_vasprintf (result, format, args) 39 char **result; 40 const char *format; 41 va_list *args; 42{ 43 const char *p = format; 44 /* Add one to make sure that it is never zero, which might cause malloc 45 to return NULL. */ 46 int total_width = strlen (format) + 1; 47 va_list ap; 48 49 memcpy ((PTR) &ap, (PTR) args, sizeof (va_list)); 50 51 while (*p != '\0') 52 { 53 if (*p++ == '%') 54 { 55 while (strchr ("-+ #0", *p)) 56 ++p; 57 if (*p == '*') 58 { 59 ++p; 60 total_width += abs (va_arg (ap, int)); 61 } 62 else 63 total_width += strtoul (p, &p, 10); 64 if (*p == '.') 65 { 66 ++p; 67 if (*p == '*') 68 { 69 ++p; 70 total_width += abs (va_arg (ap, int)); 71 } 72 else 73 total_width += strtoul (p, &p, 10); 74 } 75 while (strchr ("hlL", *p)) 76 ++p; 77 /* Should be big enough for any format specifier except %s and floats. */ 78 total_width += 30; 79 switch (*p) 80 { 81 case 'd': 82 case 'i': 83 case 'o': 84 case 'u': 85 case 'x': 86 case 'X': 87 case 'c': 88 (void) va_arg (ap, int); 89 break; 90 case 'f': 91 case 'e': 92 case 'E': 93 case 'g': 94 case 'G': 95 (void) va_arg (ap, double); 96 /* Since an ieee double can have an exponent of 307, we'll 97 make the buffer wide enough to cover the gross case. */ 98 total_width += 307; 99 break; 100 case 's': 101 total_width += strlen (va_arg (ap, char *)); 102 break; 103 case 'p': 104 case 'n': 105 (void) va_arg (ap, char *); 106 break; 107 } 108 p++; 109 } 110 } 111#ifdef TEST 112 global_total_width = total_width; 113#endif 114 *result = malloc (total_width); 115 if (*result != NULL) 116 return vsprintf (*result, format, *args); 117 else 118 return 0; 119} 120 121int 122vasprintf (result, format, args) 123 char **result; 124 const char *format; 125#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) 126 _BSD_VA_LIST_ args; 127#else 128 va_list args; 129#endif 130{ 131 return int_vasprintf (result, format, &args); 132} 133 134#ifdef TEST 135void 136checkit 137#ifdef __STDC__ 138 (const char* format, ...) 139#else 140 (va_alist) 141 va_dcl 142#endif 143{ 144 va_list args; 145 char *result; 146 147#ifdef __STDC__ 148 va_start (args, format); 149#else 150 char *format; 151 va_start (args); 152 format = va_arg (args, char *); 153#endif 154 vasprintf (&result, format, args); 155 if (strlen (result) < global_total_width) 156 printf ("PASS: "); 157 else 158 printf ("FAIL: "); 159 printf ("%d %s\n", global_total_width, result); 160} 161 162int 163main () 164{ 165 checkit ("%d", 0x12345678); 166 checkit ("%200d", 5); 167 checkit ("%.300d", 6); 168 checkit ("%100.150d", 7); 169 checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 170777777777777777777333333333333366666666666622222222222777777777777733333"); 171 checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); 172} 173#endif /* TEST */ 174