diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-09-04 13:48:20 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-09-04 13:57:21 +0200 |
commit | b0a0688340e20a682c3602eb6d591077a23d38b9 (patch) | |
tree | 8467345ccfc380c198014812cba23ff2f4768954 | |
parent | 9c3dea74c45f2feeda85483d92383460ff20d513 (diff) | |
download | gnutls-b0a0688340e20a682c3602eb6d591077a23d38b9.tar.gz |
steal openconnect's vasprintf() implementation
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | lib/vasprintf.c | 82 |
2 files changed, 90 insertions, 15 deletions
diff --git a/configure.ac b/configure.ac index b082047860..ecb69acc73 100644 --- a/configure.ac +++ b/configure.ac @@ -152,6 +152,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_LIB_HAVE_LINKFLAGS(rt,, [#include <time.h> diff --git a/lib/vasprintf.c b/lib/vasprintf.c index f2eeb89b4f..8362942a20 100644 --- a/lib/vasprintf.c +++ b/lib/vasprintf.c @@ -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; } |