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