summaryrefslogtreecommitdiffstats
path: root/src/include/k5-platform.h
diff options
context:
space:
mode:
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 */