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