xref: /openbsd-src/lib/libc/stdio/vasprintf.c (revision bf198cc6eba0ca1f6d79f71e8e2243d386241fa8)
1*bf198cc6Smillert /*	$OpenBSD: vasprintf.c,v 1.23 2019/01/25 00:19:25 millert Exp $	*/
278f54e55Smillert 
378f54e55Smillert /*
4*bf198cc6Smillert  * Copyright (c) 1997 Todd C. Miller <millert@openbsd.org>
578f54e55Smillert  *
606f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert  * copyright notice and this permission notice appear in all copies.
978f54e55Smillert  *
10328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1778f54e55Smillert  */
1878f54e55Smillert 
1978f54e55Smillert #include <stdio.h>
2078f54e55Smillert #include <stdlib.h>
21ffd953dfSespie #include <string.h>
2278f54e55Smillert #include <errno.h>
232abfd297Smillert #include <unistd.h>
24685aea3cSespie #include "local.h"
2578f54e55Smillert 
262abfd297Smillert #define	INITIAL_SIZE	128
2732722613Smillert 
2878f54e55Smillert int
vasprintf(char ** str,const char * fmt,__va_list ap)29c916d948Smillert vasprintf(char **str, const char *fmt, __va_list ap)
3078f54e55Smillert {
3178f54e55Smillert 	int ret;
3278f54e55Smillert 	FILE f;
33685aea3cSespie 	struct __sfileext fext;
342abfd297Smillert 	const int pgsz = getpagesize();
3578f54e55Smillert 
36685aea3cSespie 	_FILEEXT_SETUP(&f, &fext);
37a4a741f7Smillert 	f._file = -1;
3878f54e55Smillert 	f._flags = __SWR | __SSTR | __SALC;
392abfd297Smillert 	f._bf._base = f._p = malloc(INITIAL_SIZE);
402bbfee11Smillert 	if (f._bf._base == NULL)
412bbfee11Smillert 		goto err;
422abfd297Smillert 	f._bf._size = f._w = INITIAL_SIZE - 1;	/* leave room for the NUL */
43c5acf43aSkurt 	ret = __vfprintf(&f, fmt, ap);
442bbfee11Smillert 	if (ret == -1)
452bbfee11Smillert 		goto err;
462bbfee11Smillert 	*f._p = '\0';
472abfd297Smillert 	if (ret + 1 > INITIAL_SIZE && ret + 1 < pgsz / 2) {
482abfd297Smillert 		/* midsize allocations can try to conserve memory */
49977aa0f2Sderaadt 		unsigned char *_base = recallocarray(f._bf._base,
50977aa0f2Sderaadt 		    f._bf._size + 1, ret + 1, 1);
51977aa0f2Sderaadt 
522bbfee11Smillert 		if (_base == NULL)
532bbfee11Smillert 			goto err;
542bbfee11Smillert 		*str = (char *)_base;
552abfd297Smillert 	} else
562abfd297Smillert 		*str = (char *)f._bf._base;
572bbfee11Smillert 	return (ret);
582bbfee11Smillert 
592bbfee11Smillert err:
602bbfee11Smillert 	free(f._bf._base);
612bbfee11Smillert 	f._bf._base = NULL;
6278f54e55Smillert 	*str = NULL;
6378f54e55Smillert 	errno = ENOMEM;
6478f54e55Smillert 	return (-1);
6578f54e55Smillert }
669b9d2a55Sguenther DEF_WEAK(vasprintf);
67