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