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