What do you do if you are writing something on Irix, Solairs, HP-UX or AIX in the
21st century you might find the string functions anemic? You could always just
commit to a religious devotion to mallocing string buffers (as you should have if you
were writing stuff 20 years ago) or you could give up, hang your head and upgrade
to linux. If only there were a way to use asprintf. But that
is only in the GNU C library and what if you are just using native tools. Boy that is
a lot of what ifs
, but anyways there is a lot of stuff out there (much
of it old) but the most functional I found was
There are quite a few but the most reasonable was based on the openssh portable library
https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bsd-asprintf.c
Briefly,
#include <errno.h>
#include <stdarg.h>
#define INIT_SZ 128
#ifndef VA_COPY
# ifdef HAVE_VA_COPY
# define VA_COPY(dest, src) va_copy(dest, src)
# else
# ifdef HAVE___VA_COPY
# define VA_COPY(dest, src) __va_copy(dest, src)
# else
# define VA_COPY(dest, src) (dest) = (src)
# endif
# endif
#endif
int
vasprintf(char **str, const char *fmt, va_list ap)
{
int ret = -1;
va_list ap2;
char *string, *newstr;
size_t len;
VA_COPY(ap2, ap);
if ((string = malloc(INIT_SZ)) == NULL)
goto fail;
ret = vsnprintf(string, INIT_SZ, fmt, ap2);
if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
*str = string;
} else if (ret == INT_MAX || ret < 0) { /* Bad length */
free(string);
goto fail;
} else { /* bigger than initial, realloc allowing for nul */
len = (size_t)ret + 1;
if ((newstr = realloc(string, len)) == NULL) {
free(string);
goto fail;
} else {
va_end(ap2);
VA_COPY(ap2, ap);
ret = vsnprintf(newstr, len, fmt, ap2);
if (ret >= 0 && (size_t)ret < len) {
*str = newstr;
} else { /* failed with realloc'ed string, give up */
free(newstr);
goto fail;
}
}
}
va_end(ap2);
return (ret);
fail:
*str = NULL;
errno = ENOMEM;
va_end(ap2);
return (-1);
}
#ifndef HAVE_ASPRINTF
int asprintf(char **str, const char *fmt, ...)
{
va_list ap;
int ret;
*str = NULL;
va_start(ap, fmt);
ret = vasprintf(str, fmt, ap);
va_end(ap);
return ret;
}
#endif