On 11 April 2011 19:59, River Tarnell river.tarnell@wikimedia.de wrote:
-----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.
Thanks River, that's really helpful!
Andrew Dunbar (hippietrail)
- river. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (SunOS)
iEYEARECAAYFAk2i0QcACgkQIXd7fCuc5vI1ewCfTdlavg0rr56l7JzwAe5Oea9x 55sAnA4MIosJLfOnD/O3z/nkq0yqD5CE =AGMe -----END PGP SIGNATURE-----
Toolserver-l mailing list (Toolserver-l@lists.wikimedia.org) https://lists.wikimedia.org/mailman/listinfo/toolserver-l Posting guidelines for this list: https://wiki.toolserver.org/view/Mailing_list_etiquette