summaryrefslogtreecommitdiffstats
path: root/src/include/k5-platform.h
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2007-06-20 01:09:10 +0000
committerKen Raeburn <raeburn@mit.edu>2007-06-20 01:09:10 +0000
commitd275e06d0cb0f248aa54a6f134a59f84aa563e14 (patch)
tree908926aa3d5f3be981ceb9b6d6081d07d9f65cef /src/include/k5-platform.h
parent4711fe7c1cd4761c893c371b84757d6bfcda82e8 (diff)
downloadkrb5-d275e06d0cb0f248aa54a6f134a59f84aa563e14.tar.gz
krb5-d275e06d0cb0f248aa54a6f134a59f84aa563e14.tar.xz
krb5-d275e06d0cb0f248aa54a6f134a59f84aa563e14.zip
provide asprintf functionality for internal use
I plan to use asprintf in some gssapi error-message management routines, so let's make sure we have the functionality available, implementing it locally if necessary. This implementation assumes vsnprintf is available, an assumption that the support library is already making at the moment. Since this implementation requires calling vsnprintf potentially multiple times with the same va_list, use va_copy if it's available, or provide a hack version (which should work okay if va_list is a scalar or array type that requires no other special handling, and if va_end does nothing interesting, which is usually the case) if the compiler doesn't provide it. I also changed a couple bits of code to use asprintf, to make sure we exercise our implementation in testing. (C99 requires vsnprintf and va_copy; vasprintf is a GNU/BSD extension, but an oh so useful one....) * configure.in: Check for va_copy, or if va_list objects can be simply assigned. Define HAS_VA_COPY and CAN_COPY_VA_LIST as appropriate. * include/k5-platform.h: Define a va_copy macro if the compiler doesn't provide it. * include/k5-platform.h: If vsnprintf isn't available from the OS, abort compilation. If vasprintf isn't available from the OS, provide k5_{v,}asprintf based on vsnprintf and define {v,}asprintf macros. * lib/krb5/keytab/t_keytab.c (do_test): Use asprintf. * util/support/errors.c (krb5int_vset_error): Use asprintf unconditionally. ticket: new git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19595 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/include/k5-platform.h')
-rw-r--r--src/include/k5-platform.h95
1 files changed, 92 insertions, 3 deletions
diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h
index 757b122b3d..6cf4465066 100644
--- a/src/include/k5-platform.h
+++ b/src/include/k5-platform.h
@@ -1,7 +1,7 @@
/*
* k5-platform.h
*
- * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology.
+ * Copyright 2003, 2004, 2005, 2007 Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -33,14 +33,19 @@
* + SIZE_MAX
* + shared library init/fini hooks
* + consistent getpwnam/getpwuid interfaces
+ * + va_copy fudged if not provided
+ * + [v]asprintf
*/
#ifndef K5_PLATFORM_H
#define K5_PLATFORM_H
#include "autoconf.h"
-/* for memcpy */
#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
/* Initialization and finalization function support for libraries.
@@ -403,7 +408,6 @@ typedef struct { int error; unsigned char did_run; } k5_init_t;
# define UINT64_TYPE unsigned long long
#endif
-#include <limits.h>
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t)((size_t)0 - 1))
#endif
@@ -743,5 +747,90 @@ load_64_n (const unsigned char *p)
(*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
#endif
+/* Since the original ANSI C spec left it undefined whether or
+ how you could copy around a va_list, C 99 added va_copy.
+ For old implementations, let's do our best to fake it.
+
+ XXX Doesn't yet handle implementations with __va_copy (early draft)
+ or GCC's __builtin_va_copy. */
+#if defined(HAS_VA_COPY) || defined(va_copy)
+/* Do nothing. */
+#elif defined(CAN_COPY_VA_LIST)
+#define va_copy(dest, src) ((dest) = (src))
+#else
+/* Assume array type, but still simply copyable.
+
+ There is, theoretically, the possibility that va_start will
+ allocate some storage pointed to by the va_list, and in that case
+ we'll just lose. If anyone cares, we could try to devise a test
+ for that case. */
+#define va_copy(dest, src) memcmp(dest, src, sizeof(va_list))
+#endif
+
+/* Provide [v]asprintf interfaces. */
+#ifndef HAVE_VSNPRINTF
+#error We need an implementation of vsnprintf.
+#endif
+#ifndef HAVE_VASPRINTF
+#define vasprintf k5_vasprintf
+/* On error: BSD: Set *ret to NULL. GNU: *ret is undefined.
+
+ Since we want to be able to use the GNU version directly, we need
+ provide only the weaker guarantee in this version. */
+static inline int
+vasprintf(char **ret, const char *format, va_list ap)
+{
+ va_list ap2;
+ char *str = NULL, *nstr;
+ int len = 80, len2;
+
+ while (1) {
+ if (len < 0 || (size_t) len != len) {
+ free(str);
+ return -1;
+ }
+ nstr = realloc(str, (size_t) len);
+ if (nstr == NULL) {
+ free(str);
+ return -1;
+ }
+ str = nstr;
+ va_copy(ap2, ap);
+ len2 = vsnprintf(str, (size_t) len, format, ap2);
+ va_end(ap2);
+ if (len2 >= 0 && len2 < len) {
+ if (len2 < len-1) {
+ /* In a lot of cases, 80 will be quite a lot more than
+ we need. */
+ nstr = realloc(str, (size_t) len2+1);
+ if (nstr)
+ str = nstr;
+ }
+ *ret = str;
+ return len2;
+ }
+ /* ISO C vsnprintf returns the needed length. Some old
+ vsnprintf implementations return -1 on truncation. */
+ if (len2 >= len)
+ len = len2 + 1;
+ else
+ len *= 2;
+ }
+}
+/* Assume HAVE_ASPRINTF iff HAVE_VASPRINTF. */
+#define asprintf k5_asprintf
+static inline int
+k5_asprintf(char **ret, const char *format, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, format);
+ n = vasprintf(ret, format, ap);
+ va_end(ap);
+ return n;
+}
+#endif
+
#endif /* K5_PLATFORM_H */