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