1*bf198cc6Smillert /* $OpenBSD: asprintf.c,v 1.26 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>
2378f54e55Smillert #include <stdarg.h>
242abfd297Smillert #include <unistd.h>
25685aea3cSespie #include "local.h"
2678f54e55Smillert
272abfd297Smillert #define INITIAL_SIZE 128
2832722613Smillert
2978f54e55Smillert int
asprintf(char ** str,const char * fmt,...)309e895940Spat asprintf(char **str, const char *fmt, ...)
3178f54e55Smillert {
3278f54e55Smillert int ret;
3378f54e55Smillert va_list ap;
3478f54e55Smillert FILE f;
35685aea3cSespie struct __sfileext fext;
362abfd297Smillert const int pgsz = getpagesize();
3778f54e55Smillert
38685aea3cSespie _FILEEXT_SETUP(&f, &fext);
39a4a741f7Smillert f._file = -1;
4078f54e55Smillert f._flags = __SWR | __SSTR | __SALC;
412abfd297Smillert f._bf._base = f._p = malloc(INITIAL_SIZE);
422bbfee11Smillert if (f._bf._base == NULL)
432bbfee11Smillert goto err;
442abfd297Smillert f._bf._size = f._w = INITIAL_SIZE - 1; /* leave room for the NUL */
4503358690Smillert va_start(ap, fmt);
46c5acf43aSkurt ret = __vfprintf(&f, fmt, ap);
4703358690Smillert va_end(ap);
482bbfee11Smillert if (ret == -1)
492bbfee11Smillert goto err;
502bbfee11Smillert *f._p = '\0';
512abfd297Smillert if (ret + 1 > INITIAL_SIZE && ret + 1 < pgsz / 2) {
522abfd297Smillert /* midsize allocations can try to conserve memory */
53977aa0f2Sderaadt unsigned char *_base = recallocarray(f._bf._base,
54977aa0f2Sderaadt f._bf._size + 1, ret + 1, 1);
55977aa0f2Sderaadt
562bbfee11Smillert if (_base == NULL)
572bbfee11Smillert goto err;
582bbfee11Smillert *str = (char *)_base;
592abfd297Smillert } else
602abfd297Smillert *str = (char *)f._bf._base;
612bbfee11Smillert return (ret);
622bbfee11Smillert
632bbfee11Smillert err:
642bbfee11Smillert free(f._bf._base);
652bbfee11Smillert f._bf._base = NULL;
6678f54e55Smillert *str = NULL;
6778f54e55Smillert errno = ENOMEM;
6878f54e55Smillert return (-1);
6978f54e55Smillert }
709b9d2a55Sguenther DEF_WEAK(asprintf);
71