1/*	$OpenBSD: asprintf.c,v 1.26 2019/01/25 00:19:25 millert Exp $	*/
2
3/*
4 * Copyright (c) 1997 Todd C. Miller <millert@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <errno.h>
23#include <stdarg.h>
24#include <unistd.h>
25#include "local.h"
26
27#define	INITIAL_SIZE	128
28
29int
30asprintf(char **str, const char *fmt, ...)
31{
32	int ret;
33	va_list ap;
34	FILE f;
35	struct __sfileext fext;
36	const int pgsz = getpagesize();
37
38	_FILEEXT_SETUP(&f, &fext);
39	f._file = -1;
40	f._flags = __SWR | __SSTR | __SALC;
41	f._bf._base = f._p = malloc(INITIAL_SIZE);
42	if (f._bf._base == NULL)
43		goto err;
44	f._bf._size = f._w = INITIAL_SIZE - 1;	/* leave room for the NUL */
45	va_start(ap, fmt);
46	ret = __vfprintf(&f, fmt, ap);
47	va_end(ap);
48	if (ret == -1)
49		goto err;
50	*f._p = '\0';
51	if (ret + 1 > INITIAL_SIZE && ret + 1 < pgsz / 2) {
52		/* midsize allocations can try to conserve memory */
53		unsigned char *_base = recallocarray(f._bf._base,
54		    f._bf._size + 1, ret + 1, 1);
55
56		if (_base == NULL)
57			goto err;
58		*str = (char *)_base;
59	} else
60		*str = (char *)f._bf._base;
61	return (ret);
62
63err:
64	free(f._bf._base);
65	f._bf._base = NULL;
66	*str = NULL;
67	errno = ENOMEM;
68	return (-1);
69}
70DEF_WEAK(asprintf);
71