vasprintf.c revision 16586
1/*- 2 * Copyright (c) 1996 Peter Wemm <peter@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 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. 12 * 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 23 * SUCH DAMAGE. 24 */ 25 26#if defined(LIBC_RCS) && !defined(lint) 27static char rcsid[] = "$Id: vasprintf.c,v 1.1 1996/05/27 10:49:43 peter Exp $"; 28#endif /* LIBC_RCS and not lint */ 29 30#include <stdio.h> 31#include <stdlib.h> 32 33#if __STDC__ 34#include <stdarg.h> 35#else 36#include <varargs.h> 37#endif 38 39#define CHUNK_SPARE 128 /* how much spare to allocate to avoid realloc calls */ 40 41struct bufcookie { 42 char *base; /* start of buffer */ 43 int size; 44 int left; 45}; 46 47static int writehook __P((void *cookie, const char *, int)); 48 49static int 50writehook(cookie, buf, len) 51 void *cookie; 52 const char *buf; 53 int len; 54{ 55 struct bufcookie *h = (struct bufcookie *)cookie; 56 57 if (len == 0) 58 return 0; 59 60 if (len > h->left) { 61 /* grow malloc region */ 62 h->left = h->left + len + CHUNK_SPARE; 63 h->size = h->size + len + CHUNK_SPARE; 64 h->base = realloc(h->base, (size_t)h->size); 65 if (h->base == NULL) 66 return (-1); 67 } 68 /* "write" it */ 69 (void)memcpy(h->base + h->size - h->left, buf, (size_t)len); 70 h->left -= len; 71 return (0); 72} 73 74 75int 76vasprintf(str, fmt, ap) 77 char **str; 78 const char *fmt; 79 va_list ap; 80{ 81 int ret; 82 FILE *f; 83 struct bufcookie h; 84 85 h.base = malloc(CHUNK_SPARE); 86 if (h.base == NULL) 87 return (-1); 88 h.size = CHUNK_SPARE; 89 h.left = CHUNK_SPARE; 90 91 f = funopen(&h, NULL, writehook, NULL, NULL); 92 if (f == NULL) { 93 free(h.base); 94 return (-1); 95 } 96 ret = vfprintf(f, fmt, ap); 97 fclose(f); 98 if (ret < 0) { 99 free(h.base); 100 return (-1); 101 } 102 if (h.base == NULL) /* failed to realloc in writehook */ 103 return (-1); 104 105 h.base[h.size - h.left] = '\0'; 106 *str = realloc(h.base, (size_t)(h.size - h.left + 1)); 107 if (*str == NULL) /* failed to realloc it to actual size */ 108 return -1; 109 return (ret); 110} 111