summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira TAGOH <akira@tagoh.org>2012-12-03 17:09:28 +0900
committerAkira TAGOH <akira@tagoh.org>2012-12-03 17:09:28 +0900
commit6af8dd1015917d572b43a6f0ed2cf00ac69abe72 (patch)
tree1fc39341d7fd3e545c5b55007695ae0992da0970
parentf23cacb49328af91eccd29bed5211997edf05257 (diff)
Fix portability issue in vsnprintf
-rw-r--r--configure.ac33
-rw-r--r--liblangtag/lt-utils.c74
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;
}