]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
steal openconnect's vasprintf() implementation
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 4 Sep 2014 11:48:20 +0000 (13:48 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 4 Sep 2014 11:55:01 +0000 (13:55 +0200)
configure.ac
lib/vasprintf.c

index 8a776d520059a40ddb43c3070eea8a8e0b21d8e0..65eade2d7b33897289b36bfc304ac42643177a8b 100644 (file)
@@ -156,6 +156,29 @@ AC_C_BIGENDIAN
 dnl No fork on MinGW, disable some self-tests until we fix them.
 dnl Check clock_gettime and pthread_mutex_lock in libc (avoid linking to other libs)
 AC_CHECK_FUNCS([fork inet_ntop inet_pton getrusage getpwuid_r nanosleep daemon getpid clock_gettime iconv localtime vasprintf],,)
+if test "$ac_cv_func_vasprintf" != "yes";then
+  AC_MSG_CHECKING([for va_copy])
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([
+       #include <stdarg.h>
+       va_list a;],[
+       va_list b;
+       va_copy(b,a);
+       va_end(b);])],
+       [AC_DEFINE(HAVE_VA_COPY, 1, [Have va_copy()])
+       AC_MSG_RESULT(va_copy)],
+       [AC_LINK_IFELSE([AC_LANG_PROGRAM([
+               #include <stdarg.h>
+               va_list a;],[
+               va_list b;
+               __va_copy(b,a);
+               va_end(b);])],
+               [AC_DEFINE(HAVE___VA_COPY, 1, [Have __va_copy()])
+               AC_MSG_RESULT(__va_copy)],
+               [AC_MSG_RESULT(no)
+               AC_MSG_ERROR([Your system lacks vasprintf() and va_copy()])])
+       ])
+fi
+
 AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no")
 
 AC_CHECK_FUNCS([pthread_atfork __register_atfork],,)
index f2eeb89b4f027b597c78aa3b7558aa0dc42e4ab3..8362942a20353abbcaa6fdd53cd6a7ecf3f483ef 100644 (file)
@@ -1,31 +1,83 @@
+/*
+ * Copyright © 2008-2014 Intel Corporation.
+ *
+ * Authors: David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
 #include <config.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
 #include "vasprintf.h"
 
 #ifndef HAVE_VASPRINTF
 
-#define MAX_BSIZE 1024
-#define NO_MORE_MAX (16*MAX_BSIZE)
-
 int _gnutls_vasprintf(char **strp, const char *fmt, va_list ap)
 {
-       char *buf;
-       int ret, max;
+       va_list ap2;
+       char *res = NULL;
+       int len = 160, len2;
+       int ret = 0;
+       int errno_save = -ENOMEM;
 
-       max = MAX_BSIZE / 2;
+       res = malloc(160);
+       if (!res)
+               goto err;
 
-       do {
-               max *= 2;
-
-               buf = malloc(max);
-               if (buf == NULL)
-                       return -1;
+       /* Use a copy of 'ap', preserving it in case we need to retry into
+          a larger buffer. 160 characters should be sufficient for most
+          strings in openconnect. */
+#ifdef HAVE_VA_COPY
+       va_copy(ap2, ap);
+#elif defined(HAVE___VA_COPY)
+       __va_copy(ap2, ap);
+#else
+#error No va_copy()!
+       /* You could try this. */
+       ap2 = ap;
+       /* Or this */
+       *ap2 = *ap;
+#endif
+       len = vsnprintf(res, 160, fmt, ap2);
+       va_end(ap2);
 
-               ret = vsnprintf(buf, max, fmt, ap);
+       if (len < 0) {
+       printf_err:
+               errno_save = errno;
+               free(res);
+               res = NULL;
+               goto err;
        }
-       while (ret > max && max < NO_MORE_MAX);
-       *strp = buf;
+       if (len >= 0 && len < 160)
+               goto out;
+
+       free(res);
+       res = malloc(len+1);
+       if (!res)
+               goto err;
+
+       len2 = vsnprintf(res, len+1, fmt, ap);
+       if (len2 < 0 || len2 > len)
+               goto printf_err;
+
+       ret = 0;
+       goto out;
 
+ err:
+       errno = errno_save;
+       ret = -1;
+ out:
+       *strp = res;
        return ret;
 }