xref: /openbsd/gnu/lib/libiberty/src/vasprintf.c (revision 150b7e42)
100bf4279Sespie /* Like vsprintf but provides a pointer to malloc'd storage, which must
200bf4279Sespie    be freed by the caller.
3*150b7e42Smiod    Copyright (C) 1994, 2003 Free Software Foundation, Inc.
400bf4279Sespie 
500bf4279Sespie This file is part of the libiberty library.
600bf4279Sespie Libiberty is free software; you can redistribute it and/or
700bf4279Sespie modify it under the terms of the GNU Library General Public
800bf4279Sespie License as published by the Free Software Foundation; either
900bf4279Sespie version 2 of the License, or (at your option) any later version.
1000bf4279Sespie 
1100bf4279Sespie Libiberty is distributed in the hope that it will be useful,
1200bf4279Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
1300bf4279Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1400bf4279Sespie Library General Public License for more details.
1500bf4279Sespie 
1600bf4279Sespie You should have received a copy of the GNU Library General Public
1700bf4279Sespie License along with libiberty; see the file COPYING.LIB.  If
18*150b7e42Smiod not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19*150b7e42Smiod Boston, MA 02110-1301, USA.  */
2000bf4279Sespie 
2137c53322Sespie #ifdef HAVE_CONFIG_H
2237c53322Sespie #include "config.h"
2337c53322Sespie #endif
2437c53322Sespie #include <ansidecl.h>
2500bf4279Sespie #include <stdarg.h>
26*150b7e42Smiod #if !defined (va_copy) && defined (__va_copy)
27*150b7e42Smiod # define va_copy(d,s)  __va_copy((d),(s))
2800bf4279Sespie #endif
2900bf4279Sespie #include <stdio.h>
3037c53322Sespie #ifdef HAVE_STRING_H
3100bf4279Sespie #include <string.h>
3237c53322Sespie #endif
3337c53322Sespie #ifdef HAVE_STDLIB_H
3437c53322Sespie #include <stdlib.h>
3537c53322Sespie #else
3637c53322Sespie extern unsigned long strtoul ();
3737c53322Sespie extern PTR malloc ();
3837c53322Sespie #endif
3937c53322Sespie #include "libiberty.h"
4000bf4279Sespie 
4100bf4279Sespie #ifdef TEST
4200bf4279Sespie int global_total_width;
4300bf4279Sespie #endif
4400bf4279Sespie 
4537c53322Sespie /*
4637c53322Sespie 
4737c53322Sespie @deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
4837c53322Sespie 
4937c53322Sespie Like @code{vsprintf}, but instead of passing a pointer to a buffer,
5037c53322Sespie you pass a pointer to a pointer.  This function will compute the size
5137c53322Sespie of the buffer needed, allocate memory with @code{malloc}, and store a
5237c53322Sespie pointer to the allocated memory in @code{*@var{resptr}}.  The value
5337c53322Sespie returned is the same as @code{vsprintf} would return.  If memory could
54*150b7e42Smiod not be allocated, minus one is returned and @code{NULL} is stored in
5537c53322Sespie @code{*@var{resptr}}.
5637c53322Sespie 
5737c53322Sespie @end deftypefn
5837c53322Sespie 
5937c53322Sespie */
6037c53322Sespie 
61*150b7e42Smiod static int int_vasprintf (char **, const char *, va_list);
6200bf4279Sespie 
6300bf4279Sespie static int
int_vasprintf(char ** result,const char * format,va_list args)64*150b7e42Smiod int_vasprintf (char **result, const char *format, va_list args)
6500bf4279Sespie {
6600bf4279Sespie   const char *p = format;
6700bf4279Sespie   /* Add one to make sure that it is never zero, which might cause malloc
6800bf4279Sespie      to return NULL.  */
6900bf4279Sespie   int total_width = strlen (format) + 1;
7000bf4279Sespie   va_list ap;
7100bf4279Sespie 
72*150b7e42Smiod #ifdef va_copy
73*150b7e42Smiod   va_copy (ap, args);
74*150b7e42Smiod #else
75*150b7e42Smiod   memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
76*150b7e42Smiod #endif
7700bf4279Sespie 
7800bf4279Sespie   while (*p != '\0')
7900bf4279Sespie     {
8000bf4279Sespie       if (*p++ == '%')
8100bf4279Sespie 	{
8200bf4279Sespie 	  while (strchr ("-+ #0", *p))
8300bf4279Sespie 	    ++p;
8400bf4279Sespie 	  if (*p == '*')
8500bf4279Sespie 	    {
8600bf4279Sespie 	      ++p;
8700bf4279Sespie 	      total_width += abs (va_arg (ap, int));
8800bf4279Sespie 	    }
8900bf4279Sespie 	  else
9037c53322Sespie 	    total_width += strtoul (p, (char **) &p, 10);
9100bf4279Sespie 	  if (*p == '.')
9200bf4279Sespie 	    {
9300bf4279Sespie 	      ++p;
9400bf4279Sespie 	      if (*p == '*')
9500bf4279Sespie 		{
9600bf4279Sespie 		  ++p;
9700bf4279Sespie 		  total_width += abs (va_arg (ap, int));
9800bf4279Sespie 		}
9900bf4279Sespie 	      else
10037c53322Sespie 	      total_width += strtoul (p, (char **) &p, 10);
10100bf4279Sespie 	    }
10200bf4279Sespie 	  while (strchr ("hlL", *p))
10300bf4279Sespie 	    ++p;
10400bf4279Sespie 	  /* Should be big enough for any format specifier except %s and floats.  */
10500bf4279Sespie 	  total_width += 30;
10600bf4279Sespie 	  switch (*p)
10700bf4279Sespie 	    {
10800bf4279Sespie 	    case 'd':
10900bf4279Sespie 	    case 'i':
11000bf4279Sespie 	    case 'o':
11100bf4279Sespie 	    case 'u':
11200bf4279Sespie 	    case 'x':
11300bf4279Sespie 	    case 'X':
11400bf4279Sespie 	    case 'c':
11500bf4279Sespie 	      (void) va_arg (ap, int);
11600bf4279Sespie 	      break;
11700bf4279Sespie 	    case 'f':
11800bf4279Sespie 	    case 'e':
11900bf4279Sespie 	    case 'E':
12000bf4279Sespie 	    case 'g':
12100bf4279Sespie 	    case 'G':
12200bf4279Sespie 	      (void) va_arg (ap, double);
12300bf4279Sespie 	      /* Since an ieee double can have an exponent of 307, we'll
12400bf4279Sespie 		 make the buffer wide enough to cover the gross case. */
12500bf4279Sespie 	      total_width += 307;
12600bf4279Sespie 	      break;
12700bf4279Sespie 	    case 's':
12800bf4279Sespie 	      total_width += strlen (va_arg (ap, char *));
12900bf4279Sespie 	      break;
13000bf4279Sespie 	    case 'p':
13100bf4279Sespie 	    case 'n':
13200bf4279Sespie 	      (void) va_arg (ap, char *);
13300bf4279Sespie 	      break;
13400bf4279Sespie 	    }
13500bf4279Sespie 	  p++;
13600bf4279Sespie 	}
13700bf4279Sespie     }
138*150b7e42Smiod #ifdef va_copy
139*150b7e42Smiod   va_end (ap);
140*150b7e42Smiod #endif
14100bf4279Sespie #ifdef TEST
14200bf4279Sespie   global_total_width = total_width;
14300bf4279Sespie #endif
14437c53322Sespie   *result = (char *) malloc (total_width);
14500bf4279Sespie   if (*result != NULL)
146*150b7e42Smiod     return vsprintf (*result, format, args);
14700bf4279Sespie   else
148*150b7e42Smiod     return -1;
14900bf4279Sespie }
15000bf4279Sespie 
15100bf4279Sespie int
vasprintf(char ** result,const char * format,_BSD_VA_LIST_ args)152*150b7e42Smiod vasprintf (char **result, const char *format,
15300bf4279Sespie #if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
154*150b7e42Smiod            _BSD_VA_LIST_ args)
15500bf4279Sespie #else
156*150b7e42Smiod            va_list args)
15700bf4279Sespie #endif
15800bf4279Sespie {
159*150b7e42Smiod   return int_vasprintf (result, format, args);
16000bf4279Sespie }
16100bf4279Sespie 
16200bf4279Sespie #ifdef TEST
16337c53322Sespie static void ATTRIBUTE_PRINTF_1
checkit(const char * format,...)164*150b7e42Smiod checkit (const char *format, ...)
16500bf4279Sespie {
16600bf4279Sespie   char *result;
16737c53322Sespie   VA_OPEN (args, format);
16837c53322Sespie   VA_FIXEDARG (args, const char *, format);
16900bf4279Sespie   vasprintf (&result, format, args);
17037c53322Sespie   VA_CLOSE (args);
17137c53322Sespie 
17237c53322Sespie   if (strlen (result) < (size_t) global_total_width)
17300bf4279Sespie     printf ("PASS: ");
17400bf4279Sespie   else
17500bf4279Sespie     printf ("FAIL: ");
17600bf4279Sespie   printf ("%d %s\n", global_total_width, result);
17737c53322Sespie 
17837c53322Sespie   free (result);
17900bf4279Sespie }
18000bf4279Sespie 
181*150b7e42Smiod extern int main (void);
18237c53322Sespie 
18300bf4279Sespie int
main(void)184*150b7e42Smiod main (void)
18500bf4279Sespie {
18600bf4279Sespie   checkit ("%d", 0x12345678);
18700bf4279Sespie   checkit ("%200d", 5);
18800bf4279Sespie   checkit ("%.300d", 6);
18900bf4279Sespie   checkit ("%100.150d", 7);
19000bf4279Sespie   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
19100bf4279Sespie 777777777777777777333333333333366666666666622222222222777777777777733333");
19200bf4279Sespie   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
19337c53322Sespie 
19437c53322Sespie   return 0;
19500bf4279Sespie }
19600bf4279Sespie #endif /* TEST */
197