Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
Am 09.04.2011 11:28, schrieb Ilmari Karonen: > char *vasprintf (const char *format, va_list ap) { > int len; char *buf; > len = vsnprintf(NULL, 0, format, ap); /* get needed size */ > if (len< 0) return NULL; > buf = malloc(len + 1); /* reserve 1 byte for trailing \0 */ > if (!len) return NULL; shouldn't that line read if (!buf) return NULL; > if (vsnprintf(buf, len + 1, format, ap) == len) return buf; > free(buf); /* something went wrong in second vsnprintf() */ > return NULL; > } Peter ___ 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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
On 11 April 2011 19:59, River Tarnell 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 > ___ 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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
-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. -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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
On 10 April 2011 00:09, River Tarnell wrote: > -BEGIN PGP SIGNED MESSAGE- > Hash: SHA1 > > Andrew Dunbar: >> I've got a little program to index dump files that supports Windows >> and Linux but it doesn't compile on the Toolserver with either cc or >> gcc due to the lack of the function vasprintf(). It's a GNU extension >> so I'm surprised it didn't work even with gcc. > >> Why doesn't the Toolserver gcc have it, and does anybody know of a >> workaround? > > *printf() is not part of the compiler, but the C library (libc); GNU > glibc (used on Linux) provides it, while Solaris doesn't. There's been > some discussion about it, but there are several incompatible asprintf() > interfaces around and it's not clear which one should be implemented. > > Someone else already provided a version using snprintf, but you could > also use g_vasprintf() from glib, or the version from gettext's > libintl.h (which means you need to include and link against > - -lasprintf, both of which live in /opt/ts/gettext). I personally find > the snprintf solution the best and this is what I use in my own code. 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. I don't want to have to use autoconf or swtich to a gcc on Windows. Andrew Dunbar (hippietrail) > - river. > -BEGIN PGP SIGNATURE- > Version: GnuPG v1.4.11 (SunOS) > > iEYEARECAAYFAk2gaJ4ACgkQIXd7fCuc5vKziwCfTbDgK0nX32jK8iJcLWl278BK > HNwAnRFW8/BhMUKS7zr6RRBcPlqCeWfj > =31oq > -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 > ___ 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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Andrew Dunbar: > I've got a little program to index dump files that supports Windows > and Linux but it doesn't compile on the Toolserver with either cc or > gcc due to the lack of the function vasprintf(). It's a GNU extension > so I'm surprised it didn't work even with gcc. > Why doesn't the Toolserver gcc have it, and does anybody know of a workaround? *printf() is not part of the compiler, but the C library (libc); GNU glibc (used on Linux) provides it, while Solaris doesn't. There's been some discussion about it, but there are several incompatible asprintf() interfaces around and it's not clear which one should be implemented. Someone else already provided a version using snprintf, but you could also use g_vasprintf() from glib, or the version from gettext's libintl.h (which means you need to include and link against - -lasprintf, both of which live in /opt/ts/gettext). I personally find the snprintf solution the best and this is what I use in my own code. - river. -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.11 (SunOS) iEYEARECAAYFAk2gaJ4ACgkQIXd7fCuc5vKziwCfTbDgK0nX32jK8iJcLWl278BK HNwAnRFW8/BhMUKS7zr6RRBcPlqCeWfj =31oq -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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
Andrew Dunbar wrote: > I've got a little program to index dump files that supports Windows > and Linux but it doesn't compile on the Toolserver with either cc or > gcc due to the lack of the function vasprintf(). It's a GNU extension > so I'm surprised it didn't work even with gcc. > > Why doesn't the Toolserver gcc have it, and does anybody know of a workaround? Did you do #define _GNU_SOURCE at the top of the source file? ___ 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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
On 9 April 2011 19:28, Ilmari Karonen wrote: > On 04/09/2011 10:29 AM, Andrew Dunbar wrote: >> I've got a little program to index dump files that supports Windows >> and Linux but it doesn't compile on the Toolserver with either cc or >> gcc due to the lack of the function vasprintf(). It's a GNU extension >> so I'm surprised it didn't work even with gcc. >> >> Why doesn't the Toolserver gcc have it, and does anybody know of a >> workaround? >> >> vasprintf() is a version of vsprintf() which writes to a memory buffer >> of just the right size that it allocates and which the caller must >> call free() on when done. > > You could try writing your own. Off the top of my head (untested): > > char *vasprintf (const char *format, va_list ap) { > int len; char *buf; > len = vsnprintf(NULL, 0, format, ap); /* get needed size */ > if (len < 0) return NULL; > buf = malloc(len + 1); /* reserve 1 byte for trailing \0 */ > if (!len) return NULL; > if (vsnprintf(buf, len + 1, format, ap) == len) return buf; > free(buf); /* something went wrong in second vsnprintf() */ > return NULL; > } > > I think the vsnprintf(NULL, 0, ...) trick should work, although I > haven't tried it. If it complains about the NULL, just use some valid > dummy pointer instead. You could probably trade some memory for speed > in some cases by guessing and allocating some reasonable initial size > for the buffer before the first vsnprintf() call and extending it only > if the first guess wasn't long enough. Aha thanks! I already use vsnprintf in the Windows version of the code but since the gcc on my Ubuntu 10 doesn't have it I didn't expect it to be on the Toolserver gcc. Any ideas how I can set up the #ifdefs to detect that it's compiling on the toolserver environment or that it has this function available? Andrew Dunbar (hippietrail) > -- > Ilmari Karonen > > ___ > 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 > ___ 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
Re: [Toolserver-l] Alternative C function to vasprintf() on Toolserver
On 04/09/2011 10:29 AM, Andrew Dunbar wrote: > I've got a little program to index dump files that supports Windows > and Linux but it doesn't compile on the Toolserver with either cc or > gcc due to the lack of the function vasprintf(). It's a GNU extension > so I'm surprised it didn't work even with gcc. > > Why doesn't the Toolserver gcc have it, and does anybody know of a workaround? > > vasprintf() is a version of vsprintf() which writes to a memory buffer > of just the right size that it allocates and which the caller must > call free() on when done. You could try writing your own. Off the top of my head (untested): char *vasprintf (const char *format, va_list ap) { int len; char *buf; len = vsnprintf(NULL, 0, format, ap); /* get needed size */ if (len < 0) return NULL; buf = malloc(len + 1); /* reserve 1 byte for trailing \0 */ if (!len) return NULL; if (vsnprintf(buf, len + 1, format, ap) == len) return buf; free(buf); /* something went wrong in second vsnprintf() */ return NULL; } I think the vsnprintf(NULL, 0, ...) trick should work, although I haven't tried it. If it complains about the NULL, just use some valid dummy pointer instead. You could probably trade some memory for speed in some cases by guessing and allocating some reasonable initial size for the buffer before the first vsnprintf() call and extending it only if the first guess wasn't long enough. -- Ilmari Karonen ___ 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
[Toolserver-l] Alternative C function to vasprintf() on Toolserver
I've got a little program to index dump files that supports Windows and Linux but it doesn't compile on the Toolserver with either cc or gcc due to the lack of the function vasprintf(). It's a GNU extension so I'm surprised it didn't work even with gcc. Why doesn't the Toolserver gcc have it, and does anybody know of a workaround? vasprintf() is a version of vsprintf() which writes to a memory buffer of just the right size that it allocates and which the caller must call free() on when done. Andrew Dunbar (hippietrail) ___ 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