vasprintf.c 4.71 KB
Newer Older
Jason Merrill committed
1 2
/* Like vsprintf but provides a pointer to malloc'd storage, which must
   be freed by the caller.
3
   Copyright (C) 1994, 2003 Free Software Foundation, Inc.
Jason Merrill committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17

This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB.  If
18 19
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.  */
Jason Merrill committed
20

Kaveh R. Ghazi committed
21 22 23 24
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ansidecl.h>
Jason Merrill committed
25
#include <stdarg.h>
26 27 28
#if !defined (va_copy) && defined (__va_copy)
# define va_copy(d,s)  __va_copy((d),(s))
#endif
29
#include <stdio.h>
30
#ifdef HAVE_STRING_H
31
#include <string.h>
32
#endif
Kaveh R. Ghazi committed
33 34 35 36 37 38 39
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
extern unsigned long strtoul ();
extern PTR malloc ();
#endif
#include "libiberty.h"
Jason Merrill committed
40 41 42 43 44

#ifdef TEST
int global_total_width;
#endif

45 46
/*

47
@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
48 49 50 51 52 53

Like @code{vsprintf}, but instead of passing a pointer to a buffer,
you pass a pointer to a pointer.  This function will compute the size
of the buffer needed, allocate memory with @code{malloc}, and store a
pointer to the allocated memory in @code{*@var{resptr}}.  The value
returned is the same as @code{vsprintf} would return.  If memory could
54
not be allocated, minus one is returned and @code{NULL} is stored in
55 56 57 58 59
@code{*@var{resptr}}.

@end deftypefn

*/
Kaveh R. Ghazi committed
60

61
static int int_vasprintf (char **, const char *, va_list);
Jason Merrill committed
62 63

static int
64
int_vasprintf (char **result, const char *format, va_list args)
Jason Merrill committed
65 66 67 68 69 70 71
{
  const char *p = format;
  /* Add one to make sure that it is never zero, which might cause malloc
     to return NULL.  */
  int total_width = strlen (format) + 1;
  va_list ap;

Josef Zlomek committed
72 73 74 75 76
#ifdef va_copy
  va_copy (ap, args);
#else
  memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
#endif
Jason Merrill committed
77 78 79 80 81 82 83 84 85 86 87 88 89

  while (*p != '\0')
    {
      if (*p++ == '%')
	{
	  while (strchr ("-+ #0", *p))
	    ++p;
	  if (*p == '*')
	    {
	      ++p;
	      total_width += abs (va_arg (ap, int));
	    }
	  else
Kaveh R. Ghazi committed
90
	    total_width += strtoul (p, (char **) &p, 10);
Jason Merrill committed
91 92 93 94 95 96 97 98 99
	  if (*p == '.')
	    {
	      ++p;
	      if (*p == '*')
		{
		  ++p;
		  total_width += abs (va_arg (ap, int));
		}
	      else
Kaveh R. Ghazi committed
100
	      total_width += strtoul (p, (char **) &p, 10);
Jason Merrill committed
101 102 103
	    }
	  while (strchr ("hlL", *p))
	    ++p;
104
	  /* Should be big enough for any format specifier except %s and floats.  */
Jason Merrill committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	  total_width += 30;
	  switch (*p)
	    {
	    case 'd':
	    case 'i':
	    case 'o':
	    case 'u':
	    case 'x':
	    case 'X':
	    case 'c':
	      (void) va_arg (ap, int);
	      break;
	    case 'f':
	    case 'e':
	    case 'E':
	    case 'g':
	    case 'G':
	      (void) va_arg (ap, double);
123 124 125
	      /* Since an ieee double can have an exponent of 307, we'll
		 make the buffer wide enough to cover the gross case. */
	      total_width += 307;
Jason Merrill committed
126 127 128 129 130 131 132 133 134
	      break;
	    case 's':
	      total_width += strlen (va_arg (ap, char *));
	      break;
	    case 'p':
	    case 'n':
	      (void) va_arg (ap, char *);
	      break;
	    }
135
	  p++;
Jason Merrill committed
136 137
	}
    }
Josef Zlomek committed
138 139 140
#ifdef va_copy
  va_end (ap);
#endif
Jason Merrill committed
141 142 143
#ifdef TEST
  global_total_width = total_width;
#endif
144
  *result = (char *) malloc (total_width);
Jason Merrill committed
145
  if (*result != NULL)
Josef Zlomek committed
146
    return vsprintf (*result, format, args);
Jason Merrill committed
147
  else
148
    return -1;
Jason Merrill committed
149 150 151
}

int
152
vasprintf (char **result, const char *format,
153
#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
154
           _BSD_VA_LIST_ args)
155
#else
156
           va_list args)
157
#endif
Jason Merrill committed
158
{
Josef Zlomek committed
159
  return int_vasprintf (result, format, args);
Jason Merrill committed
160 161 162
}

#ifdef TEST
163
static void ATTRIBUTE_PRINTF_1
164
checkit (const char *format, ...)
Jason Merrill committed
165 166
{
  char *result;
167 168
  VA_OPEN (args, format);
  VA_FIXEDARG (args, const char *, format);
Jason Merrill committed
169
  vasprintf (&result, format, args);
170 171
  VA_CLOSE (args);

Kaveh R. Ghazi committed
172
  if (strlen (result) < (size_t) global_total_width)
Jason Merrill committed
173 174 175 176
    printf ("PASS: ");
  else
    printf ("FAIL: ");
  printf ("%d %s\n", global_total_width, result);
177 178

  free (result);
Jason Merrill committed
179 180
}

181
extern int main (void);
Kaveh R. Ghazi committed
182

Jason Merrill committed
183
int
184
main (void)
Jason Merrill committed
185 186 187 188 189 190 191 192
{
  checkit ("%d", 0x12345678);
  checkit ("%200d", 5);
  checkit ("%.300d", 6);
  checkit ("%100.150d", 7);
  checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
777777777777777777333333333333366666666666622222222222777777777777733333");
  checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
Kaveh R. Ghazi committed
193 194

  return 0;
Jason Merrill committed
195 196
}
#endif /* TEST */