/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> * * GNU Library General Public License (LGPL) version 2 or later. * * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. */ #include <features.h> #ifdef __USE_GNU #include "_stdio.h" #include <stdarg.h> #include <bits/uClibc_va_copy.h> #ifndef __STDIO_HAS_VSNPRINTF #warning Skipping vasprintf since no vsnprintf! #else int vasprintf(char **__restrict buf, const char * __restrict format, va_list arg) { #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ FILE *f; size_t size; int rv = -1; *buf = NULL; if ((f = open_memstream(buf, &size)) != NULL) { rv = vfprintf(f, format, arg); fclose(f); if (rv < 0) { free(*buf); *buf = NULL; } else { *buf = realloc(*buf, rv + 1); } } assert(rv >= -1); return rv; #else /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */ /* This implementation actually calls the printf machinery twice, but * only does one malloc. This can be a problem though when custom printf * specs or the %m specifier are involved because the results of the * second call might be different from the first. */ va_list arg2; int rv; va_copy(arg2, arg); rv = vsnprintf(NULL, 0, format, arg2); va_end(arg2); *buf = NULL; if (rv >= 0) { if ((*buf = malloc(++rv)) != NULL) { if ((rv = vsnprintf(*buf, rv, format, arg)) < 0) { free(*buf); *buf = NULL; } } } assert(rv >= -1); return rv; #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */ } libc_hidden_def(vasprintf) #endif #endif