157f3915bSDamien Miller /*
257f3915bSDamien Miller  * Copyright (c) 2004 Darren Tucker.
357f3915bSDamien Miller  *
457f3915bSDamien Miller  * Based originally on asprintf.c from OpenBSD:
557f3915bSDamien Miller  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
657f3915bSDamien Miller  *
757f3915bSDamien Miller  * Permission to use, copy, modify, and distribute this software for any
857f3915bSDamien Miller  * purpose with or without fee is hereby granted, provided that the above
957f3915bSDamien Miller  * copyright notice and this permission notice appear in all copies.
1057f3915bSDamien Miller  *
1157f3915bSDamien Miller  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1257f3915bSDamien Miller  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1357f3915bSDamien Miller  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1457f3915bSDamien Miller  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1557f3915bSDamien Miller  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1657f3915bSDamien Miller  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1757f3915bSDamien Miller  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1857f3915bSDamien Miller  */
1957f3915bSDamien Miller 
2057f3915bSDamien Miller #include "includes.h"
2157f3915bSDamien Miller 
22*797cdd9cSDarren Tucker /*
23*797cdd9cSDarren Tucker  * Don't let systems with broken printf(3) avoid our replacements
24*797cdd9cSDarren Tucker  * via asprintf(3)/vasprintf(3) calling libc internally.
25*797cdd9cSDarren Tucker  */
26*797cdd9cSDarren Tucker #if defined(BROKEN_SNPRINTF)
27*797cdd9cSDarren Tucker # undef HAVE_VASPRINTF
28*797cdd9cSDarren Tucker # undef HAVE_ASPRINTF
29*797cdd9cSDarren Tucker #endif
30*797cdd9cSDarren Tucker 
3157f3915bSDamien Miller #ifndef HAVE_VASPRINTF
3257f3915bSDamien Miller 
332eaea990SDarren Tucker #include <errno.h>
342eaea990SDarren Tucker #include <stdarg.h>
35f78fb544SDarren Tucker #include <stdlib.h>
362eaea990SDarren Tucker 
3757f3915bSDamien Miller #define INIT_SZ	128
3857f3915bSDamien Miller 
39be6db834SDamien Miller int
vasprintf(char ** str,const char * fmt,va_list ap)40be6db834SDamien Miller vasprintf(char **str, const char *fmt, va_list ap)
4157f3915bSDamien Miller {
4257f3915bSDamien Miller 	int ret = -1;
4357f3915bSDamien Miller 	va_list ap2;
4457f3915bSDamien Miller 	char *string, *newstr;
4557f3915bSDamien Miller 	size_t len;
4657f3915bSDamien Miller 
4757f3915bSDamien Miller 	VA_COPY(ap2, ap);
4857f3915bSDamien Miller 	if ((string = malloc(INIT_SZ)) == NULL)
4957f3915bSDamien Miller 		goto fail;
5057f3915bSDamien Miller 
5157f3915bSDamien Miller 	ret = vsnprintf(string, INIT_SZ, fmt, ap2);
5257f3915bSDamien Miller 	if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
5357f3915bSDamien Miller 		*str = string;
54be6db834SDamien Miller 	} else if (ret == INT_MAX || ret < 0) { /* Bad length */
5584287b83SDarren Tucker 		free(string);
5657f3915bSDamien Miller 		goto fail;
5757f3915bSDamien Miller 	} else {	/* bigger than initial, realloc allowing for nul */
5857f3915bSDamien Miller 		len = (size_t)ret + 1;
5957f3915bSDamien Miller 		if ((newstr = realloc(string, len)) == NULL) {
6057f3915bSDamien Miller 			free(string);
6157f3915bSDamien Miller 			goto fail;
6257f3915bSDamien Miller 		} else {
6357f3915bSDamien Miller 			va_end(ap2);
6457f3915bSDamien Miller 			VA_COPY(ap2, ap);
6557f3915bSDamien Miller 			ret = vsnprintf(newstr, len, fmt, ap2);
6657f3915bSDamien Miller 			if (ret >= 0 && (size_t)ret < len) {
6757f3915bSDamien Miller 				*str = newstr;
6857f3915bSDamien Miller 			} else { /* failed with realloc'ed string, give up */
6957f3915bSDamien Miller 				free(newstr);
7057f3915bSDamien Miller 				goto fail;
7157f3915bSDamien Miller 			}
7257f3915bSDamien Miller 		}
7357f3915bSDamien Miller 	}
7457f3915bSDamien Miller 	va_end(ap2);
7557f3915bSDamien Miller 	return (ret);
7657f3915bSDamien Miller 
7757f3915bSDamien Miller fail:
7857f3915bSDamien Miller 	*str = NULL;
7957f3915bSDamien Miller 	errno = ENOMEM;
8057f3915bSDamien Miller 	va_end(ap2);
8157f3915bSDamien Miller 	return (-1);
8257f3915bSDamien Miller }
8357f3915bSDamien Miller #endif
8457f3915bSDamien Miller 
8557f3915bSDamien Miller #ifndef HAVE_ASPRINTF
asprintf(char ** str,const char * fmt,...)8657f3915bSDamien Miller int asprintf(char **str, const char *fmt, ...)
8757f3915bSDamien Miller {
8857f3915bSDamien Miller 	va_list ap;
8957f3915bSDamien Miller 	int ret;
9057f3915bSDamien Miller 
9157f3915bSDamien Miller 	*str = NULL;
9257f3915bSDamien Miller 	va_start(ap, fmt);
9357f3915bSDamien Miller 	ret = vasprintf(str, fmt, ap);
9457f3915bSDamien Miller 	va_end(ap);
9557f3915bSDamien Miller 
9657f3915bSDamien Miller 	return ret;
9757f3915bSDamien Miller }
9857f3915bSDamien Miller #endif
99