1*2ccfa855SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2004 Darren Tucker.
3*2ccfa855SEd Maste *
4*2ccfa855SEd Maste * Based originally on asprintf.c from OpenBSD:
5*2ccfa855SEd Maste * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
6*2ccfa855SEd Maste *
7*2ccfa855SEd Maste * Permission to use, copy, modify, and distribute this software for any
8*2ccfa855SEd Maste * purpose with or without fee is hereby granted, provided that the above
9*2ccfa855SEd Maste * copyright notice and this permission notice appear in all copies.
10*2ccfa855SEd Maste *
11*2ccfa855SEd Maste * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*2ccfa855SEd Maste * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*2ccfa855SEd Maste * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*2ccfa855SEd Maste * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*2ccfa855SEd Maste * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*2ccfa855SEd Maste * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*2ccfa855SEd Maste * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*2ccfa855SEd Maste */
19*2ccfa855SEd Maste
20*2ccfa855SEd Maste #include "openbsd-compat.h"
21*2ccfa855SEd Maste
22*2ccfa855SEd Maste #ifndef HAVE_ASPRINTF
23*2ccfa855SEd Maste
24*2ccfa855SEd Maste #include <errno.h>
25*2ccfa855SEd Maste #include <limits.h> /* for INT_MAX */
26*2ccfa855SEd Maste #include <stdarg.h>
27*2ccfa855SEd Maste #include <stdio.h> /* for vsnprintf */
28*2ccfa855SEd Maste #include <stdlib.h>
29*2ccfa855SEd Maste
30*2ccfa855SEd Maste #define VA_COPY(dest, src) va_copy(dest, src)
31*2ccfa855SEd Maste
32*2ccfa855SEd Maste #define INIT_SZ 128
33*2ccfa855SEd Maste
34*2ccfa855SEd Maste int
vasprintf(char ** str,const char * fmt,va_list ap)35*2ccfa855SEd Maste vasprintf(char **str, const char *fmt, va_list ap)
36*2ccfa855SEd Maste {
37*2ccfa855SEd Maste int ret;
38*2ccfa855SEd Maste va_list ap2;
39*2ccfa855SEd Maste char *string, *newstr;
40*2ccfa855SEd Maste size_t len;
41*2ccfa855SEd Maste
42*2ccfa855SEd Maste if ((string = malloc(INIT_SZ)) == NULL)
43*2ccfa855SEd Maste goto fail;
44*2ccfa855SEd Maste
45*2ccfa855SEd Maste VA_COPY(ap2, ap);
46*2ccfa855SEd Maste ret = vsnprintf(string, INIT_SZ, fmt, ap2);
47*2ccfa855SEd Maste va_end(ap2);
48*2ccfa855SEd Maste if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
49*2ccfa855SEd Maste *str = string;
50*2ccfa855SEd Maste } else if (ret == INT_MAX || ret < 0) { /* Bad length */
51*2ccfa855SEd Maste free(string);
52*2ccfa855SEd Maste goto fail;
53*2ccfa855SEd Maste } else { /* bigger than initial, realloc allowing for nul */
54*2ccfa855SEd Maste len = (size_t)ret + 1;
55*2ccfa855SEd Maste if ((newstr = realloc(string, len)) == NULL) {
56*2ccfa855SEd Maste free(string);
57*2ccfa855SEd Maste goto fail;
58*2ccfa855SEd Maste }
59*2ccfa855SEd Maste VA_COPY(ap2, ap);
60*2ccfa855SEd Maste ret = vsnprintf(newstr, len, fmt, ap2);
61*2ccfa855SEd Maste va_end(ap2);
62*2ccfa855SEd Maste if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */
63*2ccfa855SEd Maste free(newstr);
64*2ccfa855SEd Maste goto fail;
65*2ccfa855SEd Maste }
66*2ccfa855SEd Maste *str = newstr;
67*2ccfa855SEd Maste }
68*2ccfa855SEd Maste return (ret);
69*2ccfa855SEd Maste
70*2ccfa855SEd Maste fail:
71*2ccfa855SEd Maste *str = NULL;
72*2ccfa855SEd Maste errno = ENOMEM;
73*2ccfa855SEd Maste return (-1);
74*2ccfa855SEd Maste }
75*2ccfa855SEd Maste
asprintf(char ** str,const char * fmt,...)76*2ccfa855SEd Maste int asprintf(char **str, const char *fmt, ...)
77*2ccfa855SEd Maste {
78*2ccfa855SEd Maste va_list ap;
79*2ccfa855SEd Maste int ret;
80*2ccfa855SEd Maste
81*2ccfa855SEd Maste *str = NULL;
82*2ccfa855SEd Maste va_start(ap, fmt);
83*2ccfa855SEd Maste ret = vasprintf(str, fmt, ap);
84*2ccfa855SEd Maste va_end(ap);
85*2ccfa855SEd Maste
86*2ccfa855SEd Maste return ret;
87*2ccfa855SEd Maste }
88*2ccfa855SEd Maste #endif
89