diff options
author | Akira TAGOH <akira@tagoh.org> | 2012-12-03 17:09:28 +0900 |
---|---|---|
committer | Akira TAGOH <akira@tagoh.org> | 2012-12-03 17:09:28 +0900 |
commit | 6af8dd1015917d572b43a6f0ed2cf00ac69abe72 (patch) | |
tree | 1fc39341d7fd3e545c5b55007695ae0992da0970 | |
parent | f23cacb49328af91eccd29bed5211997edf05257 (diff) |
Fix portability issue in vsnprintf
-rw-r--r-- | configure.ac | 33 | ||||
-rw-r--r-- | liblangtag/lt-utils.c | 74 |
2 files changed, 94 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac index c825a0b..96380b9 100644 --- a/configure.ac +++ b/configure.ac @@ -202,12 +202,43 @@ dnl functions testing dnl ====================================================================== AX_CREATE_STDINT_H([liblangtag/lt-stdint.h]) AC_CHECK_HEADERS([dirent.h execinfo.h libgen.h sys/param.h]) -AC_CHECK_FUNCS([backtrace dlopen strndup]) +AC_CHECK_FUNCS([backtrace dlopen strndup vasprintf vsnprintf]) AC_CHECK_VA_COPY if test "x$ac_cv_func_dlopen" != xyes; then enable_modules=no fi +if test "x$ac_cv_func_vsnprintf" = xyes; then + AC_CACHE_CHECK([Whether vsnprintf is C99-compliant], [lt_cv_c99_vsnprintf], + [AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include <stdarg.h> +int +foo(char *format, ...) +{ + va_list ap; + char c; + int retval = 0; + + va_start(ap, format); + if (vsnprintf(&c, 1, format, ap) < 0) { + retval = -1; + } + va_end(ap); + + return retval; +} +int +main(void) +{ + char c; + + return foo("foo: %s", "bar"); +}]])], + [lt_cv_c99_vsnprintf=yes],[lt_cv_c99_vsnprintf=no],[lt_cv_c99_vsnprintf=no])]) + if test "x$lt_cv_c99_vsnprintf" = xyes; then + AC_DEFINE(LT_HAVE_C99_VSNPRINTF, 1, [Have C99-compliant vsnprintf]) + fi +fi dnl ====================================================================== dnl gettext stuff diff --git a/liblangtag/lt-utils.c b/liblangtag/lt-utils.c index 82b253e..395263a 100644 --- a/liblangtag/lt-utils.c +++ b/liblangtag/lt-utils.c @@ -14,6 +14,10 @@ #include "config.h" #endif +#if HAVE_VASPRINTF +#define _GNU_SOURCE +#endif + #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -126,22 +130,68 @@ char * lt_strdup_vprintf(const char *format, va_list args) { - char *retval, c; - va_list ap; - int size; + char *retval; lt_return_val_if_fail (format != NULL, NULL); - va_copy(ap, args); - - size = vsnprintf(&c, 1, format, ap) + 1; - - va_end(ap); - - retval = malloc(sizeof (char) * size); - if (retval) { - vsprintf(retval, format, args); +#if HAVE_VASPRINTF + if (vasprintf(&retval, format, args) < 0) { + retval = NULL; } +#elif LT_HAVE_C99_VSNPRINTF + LT_STMT_START { + char c; + va_list ap; + int size; + + va_copy(ap, args); + + size = vsnprintf(&c, 1, format, ap) + 1; + + va_end(ap); + + retval = malloc(sizeof (char) * size); + if (retval) { + vsprintf(retval, format, args); + } + } LT_STMT_END; +#elif HAVE_VSNPRINTF + LT_STMT_START { + va_list ap; + int size = 1024, n; + char *p; + + retval = malloc(size); + if (!retval) + return NULL; + + while (1) { + va_copy(ap, args); + + n = vsnprintf(retval, size, format, ap); + + va_end(ap); + + if (n > -1 && n < size) + return retval; + + if (n > -1) + size = n + 1; + else + size *= 2; + + p = realloc(retval, size); + if (!p) { + free(retval); + retval = NULL; + break; + } + retval = p; + } + } LT_STMT_END; +#else +#error no vsnprintf function implemented. +#endif return retval; } |