oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
Log | Files | Tags

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