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