2 * Copyright (c) 1996 Peter Wemm <peter@freebsd.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #if defined(LIBC_RCS) && !defined(lint)
27 static char rcsid[] = "$Id: vasprintf.c,v 1.6 1997/07/06 07:54:56 peter Exp $";
28 #endif /* LIBC_RCS and not lint */
39 #define CHUNK_SPARE 128 /* how much spare to allocate to avoid realloc calls */
42 char *base; /* start of buffer */
47 static int writehook __P((void *cookie, const char *, int));
50 writehook(cookie, buf, len)
55 struct bufcookie *h = (struct bufcookie *)cookie;
62 /* grow malloc region */
64 * XXX this is linearly expanded, which is slow for obscenely
67 h->left = h->left + len + CHUNK_SPARE;
68 h->size = h->size + len + CHUNK_SPARE;
69 newbuf = realloc(h->base, h->size);
78 (void)memcpy(h->base + h->size - h->left, buf, (size_t)len);
85 vasprintf(str, fmt, ap)
94 h.base = malloc(CHUNK_SPARE);
100 f = funopen(&h, NULL, writehook, NULL, NULL);
105 ret = vfprintf(f, fmt, ap);
109 * clean up the wreckage. Did writehook fail or did something else
110 * in stdio explode perhaps?
112 if (h.base == NULL) /* realloc failed in writehook */
114 if (ret < 0) { /* something else? */
120 * At this point, we have a non-null terminated string in a
121 * buffer. There may not be enough room to null-terminate it
122 * (h.left == 0) - if realloc failes to expand it, it's fatal.
123 * If we were merely trying to shrink the buffer, a realloc failure
124 * is not [yet] fatal. Note that when realloc returns NULL,
125 * the original buffer is left allocated and valid.
127 if (h.left == 1) /* exact fit, do not realloc */
130 *str = realloc(h.base, (size_t)(h.size - h.left + 1));
132 /* failed to expand? - fatal */
137 *str = h.base; /* use oversize original buffer */
140 (*str)[h.size - h.left] = '\0';