133965Sjdp/* Like vsprintf but provides a pointer to malloc'd storage, which must 233965Sjdp be freed by the caller. 3130561Sobrien Copyright (C) 1994, 2003 Free Software Foundation, Inc. 433965Sjdp 533965SjdpThis file is part of the libiberty library. 633965SjdpLibiberty is free software; you can redistribute it and/or 733965Sjdpmodify it under the terms of the GNU Library General Public 833965SjdpLicense as published by the Free Software Foundation; either 933965Sjdpversion 2 of the License, or (at your option) any later version. 1033965Sjdp 1133965SjdpLibiberty is distributed in the hope that it will be useful, 1233965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1333965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1433965SjdpLibrary General Public License for more details. 1533965Sjdp 1633965SjdpYou should have received a copy of the GNU Library General Public 1733965SjdpLicense along with libiberty; see the file COPYING.LIB. If 18218822Sdimnot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 19218822SdimBoston, MA 02110-1301, USA. */ 2033965Sjdp 2177298Sobrien#ifdef HAVE_CONFIG_H 2277298Sobrien#include "config.h" 2377298Sobrien#endif 2477298Sobrien#include <ansidecl.h> 2533965Sjdp#include <stdarg.h> 26218822Sdim#if !defined (va_copy) && defined (__va_copy) 27218822Sdim# define va_copy(d,s) __va_copy((d),(s)) 2833965Sjdp#endif 2960484Sobrien#include <stdio.h> 3089857Sobrien#ifdef HAVE_STRING_H 3160484Sobrien#include <string.h> 3289857Sobrien#endif 3377298Sobrien#ifdef HAVE_STDLIB_H 3477298Sobrien#include <stdlib.h> 3577298Sobrien#else 3677298Sobrienextern unsigned long strtoul (); 3777298Sobrienextern PTR malloc (); 3877298Sobrien#endif 3977298Sobrien#include "libiberty.h" 4033965Sjdp 4133965Sjdp#ifdef TEST 4233965Sjdpint global_total_width; 4333965Sjdp#endif 4433965Sjdp 4589857Sobrien/* 4633965Sjdp 4789857Sobrien@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) 4889857Sobrien 4989857SobrienLike @code{vsprintf}, but instead of passing a pointer to a buffer, 5089857Sobrienyou pass a pointer to a pointer. This function will compute the size 5189857Sobrienof the buffer needed, allocate memory with @code{malloc}, and store a 5289857Sobrienpointer to the allocated memory in @code{*@var{resptr}}. The value 5389857Sobrienreturned is the same as @code{vsprintf} would return. If memory could 54130561Sobriennot be allocated, minus one is returned and @code{NULL} is stored in 5589857Sobrien@code{*@var{resptr}}. 5689857Sobrien 5789857Sobrien@end deftypefn 5889857Sobrien 5989857Sobrien*/ 6089857Sobrien 61218822Sdimstatic int int_vasprintf (char **, const char *, va_list); 6277298Sobrien 6333965Sjdpstatic int 64218822Sdimint_vasprintf (char **result, const char *format, va_list args) 6533965Sjdp{ 6633965Sjdp const char *p = format; 6733965Sjdp /* Add one to make sure that it is never zero, which might cause malloc 6833965Sjdp to return NULL. */ 6933965Sjdp int total_width = strlen (format) + 1; 7033965Sjdp va_list ap; 7133965Sjdp 72130561Sobrien#ifdef va_copy 73130561Sobrien va_copy (ap, args); 74130561Sobrien#else 75130561Sobrien memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); 76130561Sobrien#endif 7733965Sjdp 7833965Sjdp while (*p != '\0') 7933965Sjdp { 8033965Sjdp if (*p++ == '%') 8133965Sjdp { 8233965Sjdp while (strchr ("-+ #0", *p)) 8333965Sjdp ++p; 8433965Sjdp if (*p == '*') 8533965Sjdp { 8633965Sjdp ++p; 8733965Sjdp total_width += abs (va_arg (ap, int)); 8833965Sjdp } 8933965Sjdp else 9077298Sobrien total_width += strtoul (p, (char **) &p, 10); 9133965Sjdp if (*p == '.') 9233965Sjdp { 9333965Sjdp ++p; 9433965Sjdp if (*p == '*') 9533965Sjdp { 9633965Sjdp ++p; 9733965Sjdp total_width += abs (va_arg (ap, int)); 9833965Sjdp } 9933965Sjdp else 10077298Sobrien total_width += strtoul (p, (char **) &p, 10); 10133965Sjdp } 10233965Sjdp while (strchr ("hlL", *p)) 10333965Sjdp ++p; 10438889Sjdp /* Should be big enough for any format specifier except %s and floats. */ 10533965Sjdp total_width += 30; 10633965Sjdp switch (*p) 10733965Sjdp { 10833965Sjdp case 'd': 10933965Sjdp case 'i': 11033965Sjdp case 'o': 11133965Sjdp case 'u': 11233965Sjdp case 'x': 11333965Sjdp case 'X': 11433965Sjdp case 'c': 11533965Sjdp (void) va_arg (ap, int); 11633965Sjdp break; 11733965Sjdp case 'f': 11833965Sjdp case 'e': 11933965Sjdp case 'E': 12033965Sjdp case 'g': 12133965Sjdp case 'G': 12233965Sjdp (void) va_arg (ap, double); 12338889Sjdp /* Since an ieee double can have an exponent of 307, we'll 12438889Sjdp make the buffer wide enough to cover the gross case. */ 12538889Sjdp total_width += 307; 12633965Sjdp break; 12733965Sjdp case 's': 12833965Sjdp total_width += strlen (va_arg (ap, char *)); 12933965Sjdp break; 13033965Sjdp case 'p': 13133965Sjdp case 'n': 13233965Sjdp (void) va_arg (ap, char *); 13333965Sjdp break; 13433965Sjdp } 13560484Sobrien p++; 13633965Sjdp } 13733965Sjdp } 138130561Sobrien#ifdef va_copy 139130561Sobrien va_end (ap); 140130561Sobrien#endif 14133965Sjdp#ifdef TEST 14233965Sjdp global_total_width = total_width; 14333965Sjdp#endif 144130561Sobrien *result = (char *) malloc (total_width); 14533965Sjdp if (*result != NULL) 146130561Sobrien return vsprintf (*result, format, args); 14733965Sjdp else 148130561Sobrien return -1; 14933965Sjdp} 15033965Sjdp 15133965Sjdpint 152218822Sdimvasprintf (char **result, const char *format, 15338889Sjdp#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) 154218822Sdim _BSD_VA_LIST_ args) 15538889Sjdp#else 156218822Sdim va_list args) 15738889Sjdp#endif 15833965Sjdp{ 159130561Sobrien return int_vasprintf (result, format, args); 16033965Sjdp} 16133965Sjdp 16233965Sjdp#ifdef TEST 16389857Sobrienstatic void ATTRIBUTE_PRINTF_1 164218822Sdimcheckit (const char *format, ...) 16533965Sjdp{ 16633965Sjdp char *result; 16789857Sobrien VA_OPEN (args, format); 16889857Sobrien VA_FIXEDARG (args, const char *, format); 16989857Sobrien vasprintf (&result, format, args); 17089857Sobrien VA_CLOSE (args); 17133965Sjdp 17277298Sobrien if (strlen (result) < (size_t) global_total_width) 17333965Sjdp printf ("PASS: "); 17433965Sjdp else 17533965Sjdp printf ("FAIL: "); 17633965Sjdp printf ("%d %s\n", global_total_width, result); 17789857Sobrien 17889857Sobrien free (result); 17933965Sjdp} 18033965Sjdp 181218822Sdimextern int main (void); 18277298Sobrien 18333965Sjdpint 184218822Sdimmain (void) 18533965Sjdp{ 18633965Sjdp checkit ("%d", 0x12345678); 18733965Sjdp checkit ("%200d", 5); 18833965Sjdp checkit ("%.300d", 6); 18933965Sjdp checkit ("%100.150d", 7); 19033965Sjdp checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 19133965Sjdp777777777777777777333333333333366666666666622222222222777777777777733333"); 19233965Sjdp checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); 19377298Sobrien 19477298Sobrien return 0; 19533965Sjdp} 19633965Sjdp#endif /* TEST */ 197