-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Andrew Dunbar:
Hmm currently I'm using _vscprintf / vsprintf on Windows/MSVC inside #ifdef _WIN32 and vasprintf Ubuntu/gcc inside #else
But my C-fu is to puny to figure out what #ifdefs to use to detect what combination of C compiler and libc I'm compiling under.
Apparently it's important with snprintf since some implementations return "an unspecified return value less than 1" with size=0.
That's true, but no current Unix implementation should do that, since the return value of snprintf() is standardised in the current POSIX standard (IEEE 1003.1-2004) and in the C99 standard (ISO/IEC 9899:1999).
The following code should handle Windows and both old and new Unix, although it's completely untested and comes with no warranty:
/* Compile with "-D_XOPEN_SOURCE=600 -std=c99" */ int my_vasprintf(char **res, char const *fmt, va_list args) { int sz, r; #ifdef _WIN32 sz = _vscprintf(fmt, args); #else sz = snprintf(NULL, 0, fmt, args); #endif
#if defined(_WIN32) || (defined(__STDC__) && __STDC__ >= 199901L) \ || (defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 600)) if (sz < 0) return sz; if (sz >= 0) { #else if (sz >= 1) { #endif if ((*res = malloc(sz + 1)) == NULL) return -1;
if ((sz = sprintf(*res, fmt, args)) < 0) { free(*res); *res = NULL; }
return sz; } #define MAXLN 65535 *res = NULL; for (sz = 128; sz <= MAXLN; sz *= 2) { if ((*res = realloc(*res, sz)) == NULL) return -1; r = vsnprintf(*res, sz, fmt, args); if (r > 0 && r < sz) return r; } errno = ENOMEM;
if (*res) { free(*res); *res = NULL; }
return -1; }
Obviously, this will be slower than the modern implementation, and you may want to tune the initial buffer size for the expected string length.
- river.