michael@574: /* Like vsprintf but provides a pointer to malloc'd storage, which must michael@574: be freed by the caller. michael@574: Copyright (C) 1994, 2003 Free Software Foundation, Inc. michael@574: michael@574: This file is part of the libiberty library. michael@574: Libiberty is free software; you can redistribute it and/or michael@574: modify it under the terms of the GNU Library General Public michael@574: License as published by the Free Software Foundation; either michael@574: version 2 of the License, or (at your option) any later version. michael@574: michael@574: Libiberty is distributed in the hope that it will be useful, michael@574: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@574: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@574: Library General Public License for more details. michael@574: michael@574: You should have received a copy of the GNU Library General Public michael@574: License along with libiberty; see the file COPYING.LIB. If michael@574: not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, michael@574: Boston, MA 02111-1307, USA. */ michael@574: michael@574: #include michael@574: #include michael@574: #include michael@574: #include michael@574: #include "vasprintf.h" michael@574: michael@574: /* michael@574: michael@574: @deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args}) michael@574: michael@574: Like @code{vsprintf}, but instead of passing a pointer to a buffer, michael@574: you pass a pointer to a pointer. This function will compute the size michael@574: of the buffer needed, allocate memory with @code{malloc}, and store a michael@574: pointer to the allocated memory in @code{*@var{resptr}}. The value michael@574: returned is the same as @code{vsprintf} would return. If memory could michael@574: not be allocated, minus one is returned and @code{NULL} is stored in michael@574: @code{*@var{resptr}}. michael@574: michael@574: @end deftypefn michael@574: michael@574: */ michael@574: michael@574: static int int_vasprintf(char **, const char *, va_list); michael@574: michael@574: static int michael@574: int_vasprintf (result, format, args) michael@574: char **result; michael@574: const char *format; michael@574: va_list args; michael@574: { michael@574: const char *p = format; michael@574: /* Add one to make sure that it is never zero, which might cause malloc michael@574: to return NULL. */ michael@574: int total_width = strlen (format) + 1; michael@574: va_list ap; michael@574: michael@574: memcpy ((void *) &ap, (const void *) &args, sizeof (va_list)); michael@574: michael@574: while (*p != '\0') michael@574: { michael@574: if (*p++ == '%') michael@574: { michael@574: while (strchr ("-+ #0", *p)) michael@574: ++p; michael@574: if (*p == '*') michael@574: { michael@574: ++p; michael@574: total_width += abs (va_arg (ap, int)); michael@574: } michael@574: else michael@574: total_width += strtoul (p, (char **) &p, 10); michael@574: if (*p == '.') michael@574: { michael@574: ++p; michael@574: if (*p == '*') michael@574: { michael@574: ++p; michael@574: total_width += abs (va_arg (ap, int)); michael@574: } michael@574: else michael@574: total_width += strtoul (p, (char **) &p, 10); michael@574: } michael@574: while (strchr ("hlL", *p)) michael@574: ++p; michael@574: /* Should be big enough for any format specifier except %s and floats. */ michael@574: total_width += 30; michael@574: switch (*p) michael@574: { michael@574: case 'd': michael@574: case 'i': michael@574: case 'o': michael@574: case 'u': michael@574: case 'x': michael@574: case 'X': michael@574: case 'c': michael@574: (void) va_arg (ap, int); michael@574: break; michael@574: case 'f': michael@574: case 'e': michael@574: case 'E': michael@574: case 'g': michael@574: case 'G': michael@574: (void) va_arg (ap, double); michael@574: /* Since an ieee double can have an exponent of 307, we'll michael@574: make the buffer wide enough to cover the gross case. */ michael@574: total_width += 307; michael@574: break; michael@574: case 's': michael@574: total_width += strlen (va_arg (ap, char *)); michael@574: break; michael@574: case 'p': michael@574: case 'n': michael@574: (void) va_arg (ap, char *); michael@574: break; michael@574: } michael@574: p++; michael@574: } michael@574: } michael@574: *result = (char *) malloc (total_width); michael@574: if (*result != NULL) michael@574: return vsprintf (*result, format, args); michael@574: else michael@574: return -1; michael@574: } michael@574: michael@574: int michael@574: vasprintf (result, format, args) michael@574: char **result; michael@574: const char *format; michael@574: va_list args; michael@574: { michael@574: return int_vasprintf (result, format, args); michael@574: }