1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2004 Darren Tucker. 8 * Copyright 2022 Oxide Computer Company 9 * 10 * Based originally on asprintf.c from OpenBSD: 11 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> 12 * 13 * Permission to use, copy, modify, and distribute this software for any 14 * purpose with or without fee is hereby granted, provided that the above 15 * copyright notice and this permission notice appear in all copies. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 18 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 20 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 23 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 */ 25 26 #include <lint.h> 27 #include <stdio.h> 28 #include <stdarg.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <limits.h> 32 #include <errno.h> 33 34 #define INIT_SZ 128 35 36 int 37 vasprintf(char **str, const char *format, va_list ap) 38 { 39 char string[INIT_SZ]; 40 char *newstr; 41 int ret; 42 size_t len; 43 44 *str = NULL; 45 ret = vsnprintf(string, INIT_SZ, format, ap); 46 if (ret < 0) /* retain the value of errno from vsnprintf() */ 47 return (-1); 48 if (ret < INIT_SZ) { 49 len = ret + 1; 50 if ((newstr = malloc(len)) == NULL) 51 return (-1); /* retain errno from malloc() */ 52 /* 53 * Prior versions of this used strlcpy. This has two problems. 54 * One, it doesn't handle embedded '\0' characters. Secondly, 55 * it's recalculating the length we already know. Please do not 56 * use a string-based copying function. 57 */ 58 (void) memcpy(newstr, string, len); 59 *str = newstr; 60 return (ret); 61 } 62 /* 63 * We will perform this loop more than once only if some other 64 * thread modifies one of the vasprintf() arguments after our 65 * previous call to vsnprintf(). 66 */ 67 for (;;) { 68 if (ret == INT_MAX) { /* Bad length */ 69 errno = ENOMEM; 70 return (-1); 71 } 72 len = ret + 1; 73 if ((newstr = malloc(len)) == NULL) 74 return (-1); /* retain errno from malloc() */ 75 ret = vsnprintf(newstr, len, format, ap); 76 if (ret < 0) { /* retain errno from vsnprintf() */ 77 free(newstr); 78 return (-1); 79 } 80 if (ret < len) { 81 *str = newstr; 82 return (ret); 83 } 84 free(newstr); 85 } 86 } 87 88 int 89 asprintf(char **str, const char *format, ...) 90 { 91 va_list ap; 92 int ret; 93 94 *str = NULL; 95 va_start(ap, format); 96 ret = vasprintf(str, format, ap); 97 va_end(ap); 98 99 return (ret); 100 } 101