1169695Skan/* Like vsprintf but provides a pointer to malloc'd storage, which must
2169695Skan   be freed by the caller.
3169695Skan   Copyright (C) 1994, 2003 Free Software Foundation, Inc.
4169695Skan
5169695SkanThis file is part of the libiberty library.
6169695SkanLibiberty is free software; you can redistribute it and/or
7169695Skanmodify it under the terms of the GNU Library General Public
8169695SkanLicense as published by the Free Software Foundation; either
9169695Skanversion 2 of the License, or (at your option) any later version.
10169695Skan
11169695SkanLibiberty is distributed in the hope that it will be useful,
12169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
13169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14169695SkanLibrary General Public License for more details.
15169695Skan
16169695SkanYou should have received a copy of the GNU Library General Public
17169695SkanLicense along with libiberty; see the file COPYING.LIB.  If
18169695Skannot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19169695SkanBoston, MA 02110-1301, USA.  */
20169695Skan
21169695Skan#ifdef HAVE_CONFIG_H
22169695Skan#include "config.h"
23169695Skan#endif
24169695Skan#include <ansidecl.h>
25169695Skan#include <stdarg.h>
26169695Skan#if !defined (va_copy) && defined (__va_copy)
27169695Skan# define va_copy(d,s)  __va_copy((d),(s))
28169695Skan#endif
29169695Skan#include <stdio.h>
30169695Skan#ifdef HAVE_STRING_H
31169695Skan#include <string.h>
32169695Skan#endif
33169695Skan#ifdef HAVE_STDLIB_H
34169695Skan#include <stdlib.h>
35169695Skan#else
36169695Skanextern unsigned long strtoul ();
37169695Skanextern PTR malloc ();
38169695Skan#endif
39169695Skan#include "libiberty.h"
40169695Skan
41169695Skan#ifdef TEST
42169695Skanint global_total_width;
43169695Skan#endif
44169695Skan
45169695Skan/*
46169695Skan
47169695Skan@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
48169695Skan
49169695SkanLike @code{vsprintf}, but instead of passing a pointer to a buffer,
50169695Skanyou pass a pointer to a pointer.  This function will compute the size
51169695Skanof the buffer needed, allocate memory with @code{malloc}, and store a
52169695Skanpointer to the allocated memory in @code{*@var{resptr}}.  The value
53169695Skanreturned is the same as @code{vsprintf} would return.  If memory could
54169695Skannot be allocated, minus one is returned and @code{NULL} is stored in
55169695Skan@code{*@var{resptr}}.
56169695Skan
57169695Skan@end deftypefn
58169695Skan
59169695Skan*/
60169695Skan
61169695Skanstatic int int_vasprintf (char **, const char *, va_list);
62169695Skan
63169695Skanstatic int
64169695Skanint_vasprintf (char **result, const char *format, va_list args)
65169695Skan{
66169695Skan  const char *p = format;
67169695Skan  /* Add one to make sure that it is never zero, which might cause malloc
68169695Skan     to return NULL.  */
69169695Skan  int total_width = strlen (format) + 1;
70169695Skan  va_list ap;
71169695Skan
72169695Skan#ifdef va_copy
73169695Skan  va_copy (ap, args);
74169695Skan#else
75169695Skan  memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
76169695Skan#endif
77169695Skan
78169695Skan  while (*p != '\0')
79169695Skan    {
80169695Skan      if (*p++ == '%')
81169695Skan	{
82169695Skan	  while (strchr ("-+ #0", *p))
83169695Skan	    ++p;
84169695Skan	  if (*p == '*')
85169695Skan	    {
86169695Skan	      ++p;
87169695Skan	      total_width += abs (va_arg (ap, int));
88169695Skan	    }
89169695Skan	  else
90169695Skan	    total_width += strtoul (p, (char **) &p, 10);
91169695Skan	  if (*p == '.')
92169695Skan	    {
93169695Skan	      ++p;
94169695Skan	      if (*p == '*')
95169695Skan		{
96169695Skan		  ++p;
97169695Skan		  total_width += abs (va_arg (ap, int));
98169695Skan		}
99169695Skan	      else
100169695Skan	      total_width += strtoul (p, (char **) &p, 10);
101169695Skan	    }
102169695Skan	  while (strchr ("hlL", *p))
103169695Skan	    ++p;
104169695Skan	  /* Should be big enough for any format specifier except %s and floats.  */
105169695Skan	  total_width += 30;
106169695Skan	  switch (*p)
107169695Skan	    {
108169695Skan	    case 'd':
109169695Skan	    case 'i':
110169695Skan	    case 'o':
111169695Skan	    case 'u':
112169695Skan	    case 'x':
113169695Skan	    case 'X':
114169695Skan	    case 'c':
115169695Skan	      (void) va_arg (ap, int);
116169695Skan	      break;
117169695Skan	    case 'f':
118169695Skan	    case 'e':
119169695Skan	    case 'E':
120169695Skan	    case 'g':
121169695Skan	    case 'G':
122169695Skan	      (void) va_arg (ap, double);
123169695Skan	      /* Since an ieee double can have an exponent of 307, we'll
124169695Skan		 make the buffer wide enough to cover the gross case. */
125169695Skan	      total_width += 307;
126169695Skan	      break;
127169695Skan	    case 's':
128169695Skan	      total_width += strlen (va_arg (ap, char *));
129169695Skan	      break;
130169695Skan	    case 'p':
131169695Skan	    case 'n':
132169695Skan	      (void) va_arg (ap, char *);
133169695Skan	      break;
134169695Skan	    }
135169695Skan	  p++;
136169695Skan	}
137169695Skan    }
138169695Skan#ifdef va_copy
139169695Skan  va_end (ap);
140169695Skan#endif
141169695Skan#ifdef TEST
142169695Skan  global_total_width = total_width;
143169695Skan#endif
144169695Skan  *result = (char *) malloc (total_width);
145169695Skan  if (*result != NULL)
146169695Skan    return vsprintf (*result, format, args);
147169695Skan  else
148169695Skan    return -1;
149169695Skan}
150169695Skan
151169695Skanint
152169695Skanvasprintf (char **result, const char *format,
153169695Skan#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
154169695Skan           _BSD_VA_LIST_ args)
155169695Skan#else
156169695Skan           va_list args)
157169695Skan#endif
158169695Skan{
159169695Skan  return int_vasprintf (result, format, args);
160169695Skan}
161169695Skan
162169695Skan#ifdef TEST
163169695Skanstatic void ATTRIBUTE_PRINTF_1
164169695Skancheckit (const char *format, ...)
165169695Skan{
166169695Skan  char *result;
167169695Skan  VA_OPEN (args, format);
168169695Skan  VA_FIXEDARG (args, const char *, format);
169169695Skan  vasprintf (&result, format, args);
170169695Skan  VA_CLOSE (args);
171169695Skan
172169695Skan  if (strlen (result) < (size_t) global_total_width)
173169695Skan    printf ("PASS: ");
174169695Skan  else
175169695Skan    printf ("FAIL: ");
176169695Skan  printf ("%d %s\n", global_total_width, result);
177169695Skan
178169695Skan  free (result);
179169695Skan}
180169695Skan
181169695Skanextern int main (void);
182169695Skan
183169695Skanint
184169695Skanmain (void)
185169695Skan{
186169695Skan  checkit ("%d", 0x12345678);
187169695Skan  checkit ("%200d", 5);
188169695Skan  checkit ("%.300d", 6);
189169695Skan  checkit ("%100.150d", 7);
190169695Skan  checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
191169695Skan777777777777777777333333333333366666666666622222222222777777777777733333");
192169695Skan  checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
193169695Skan
194169695Skan  return 0;
195169695Skan}
196169695Skan#endif /* TEST */
197