asprintf on Irix

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

social