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