aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-10-11 11:06:02 +0200
committerMartin Willi <martin@revosec.ch>2013-10-11 11:06:02 +0200
commitcabe5c0ff40f3a67d0d091d1bfdc2948b203737d (patch)
tree62df7243a5579a6e7e0c5987ecbaf6585b7e49f8
parentebca34d782fef5fe9ff930301079f5e119983c9e (diff)
downloadstrongswan-cabe5c0ff40f3a67d0d091d1bfdc2948b203737d.tar.bz2
strongswan-cabe5c0ff40f3a67d0d091d1bfdc2948b203737d.tar.xz
printf-hook-builtin: Add a new "builtin" backend using its own printf() routines
Overloads printf C library functions by a self-contained implementation, based on klibc. Does not yet feature all the required default formatters, including those for floating point values.
-rw-r--r--configure.ac8
-rw-r--r--src/libstrongswan/Makefile.am9
-rw-r--r--src/libstrongswan/utils/printf_hook/printf_hook.h2
-rw-r--r--src/libstrongswan/utils/printf_hook/printf_hook_builtin.c933
-rw-r--r--src/libstrongswan/utils/printf_hook/printf_hook_builtin.h82
5 files changed, 1032 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index 472c539e3..0f558161e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -624,7 +624,7 @@ AC_CHECK_FUNC(
[AC_DEFINE([HAVE_PRINTF_FUNCTION], [], [have register_printf_function()])],
[
AC_MSG_NOTICE([printf does not support custom format specifiers!])
- vstr=true
+ builtin_printf=true
]
)]
)
@@ -632,6 +632,11 @@ AC_CHECK_FUNC(
if test x$vstr = xtrue; then
AC_CHECK_LIB([vstr],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([Vstr string library not found])],[])
AC_DEFINE([USE_VSTR], [], [use vstring library for printf hooks])
+ builtin_printf=false
+fi
+
+if test x$builtin_printf = xtrue; then
+ AC_DEFINE([USE_BUILTIN_PRINTF], [], [using builtin printf for printf hooks])
fi
if test x$gmp = xtrue; then
@@ -1278,6 +1283,7 @@ AM_CONDITIONAL(USE_FILE_CONFIG, test x$stroke = xtrue)
AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$stroke = xtrue -o x$tools = xtrue -o x$conftest = xtrue)
AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap)
AM_CONDITIONAL(USE_VSTR, test x$vstr = xtrue)
+AM_CONDITIONAL(USE_BUILTIN_PRINTF, test x$builtin_printf = xtrue)
AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue)
AM_CONDITIONAL(USE_TLS, test x$tls = xtrue)
AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue)
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index c0f8c39dc..54b19e139 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -79,7 +79,7 @@ threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \
utils/utils.h utils/chunk.h utils/debug.h utils/enum.h utils/identification.h \
utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \
utils/leak_detective.h utils/printf_hook/printf_hook.h \
-utils/printf_hook/printf_hook_vstr.h \
+utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \
utils/settings.h utils/integrity_checker.h
endif
@@ -119,9 +119,16 @@ if USE_VSTR
libstrongswan_la_LIBADD += -lvstr
endif
+if USE_BUILTIN_PRINTF
+ libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_builtin.c
+ libstrongswan_la_LIBADD += -lm
+endif
+
+if !USE_BUILTIN_PRINTF
if !USE_VSTR
libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_glibc.c
endif
+endif
if USE_LIBCAP
libstrongswan_la_LIBADD += -lcap
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook.h b/src/libstrongswan/utils/printf_hook/printf_hook.h
index 5520de154..c1d6fa90d 100644
--- a/src/libstrongswan/utils/printf_hook/printf_hook.h
+++ b/src/libstrongswan/utils/printf_hook/printf_hook.h
@@ -31,6 +31,8 @@ typedef enum printf_hook_argtype_t printf_hook_argtype_t;
#if defined(USE_VSTR)
# include "printf_hook_vstr.h"
+#elif defined(USE_BUILTIN_PRINTF)
+# include "printf_hook_builtin.h"
#endif
/**
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
new file mode 100644
index 000000000..5f4907979
--- /dev/null
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 General Public License
+ * for more details.
+ */
+
+/**
+ * Copyright (C) 2002-2006 H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "printf_hook.h"
+
+#include <utils/utils.h>
+#include <utils/debug.h>
+#include <collections/hashtable.h>
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define PRINTF_BUF_LEN 8192
+#define ARGS_MAX 3
+
+typedef struct private_printf_hook_t private_printf_hook_t;
+typedef struct printf_hook_handler_t printf_hook_handler_t;
+
+/**
+ * private data of printf_hook
+ */
+struct private_printf_hook_t {
+
+ /**
+ * public functions
+ */
+ printf_hook_t public;
+};
+
+/**
+ * struct with information about a registered handler
+ */
+struct printf_hook_handler_t {
+
+ /**
+ * callback function
+ */
+ printf_hook_function_t hook;
+
+ /**
+ * number of arguments
+ */
+ int numargs;
+
+ /**
+ * types of the arguments
+ */
+ int argtypes[ARGS_MAX];
+};
+
+/**
+ * Data to pass to a printf hook.
+ */
+struct printf_hook_data_t {
+
+ /**
+ * Output buffer
+ */
+ char *q;
+
+ /**
+ * Remaining bytes in q
+ */
+ size_t n;
+};
+
+/**
+ * Registered hooks (char => printf_hook_handler_t)
+ */
+static hashtable_t *hooks;
+
+/**
+ * builtin-printf variant of print_in_hook()
+ */
+size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, fmt);
+ written = builtin_vsnprintf(data->q, data->n, fmt, args);
+ va_end(args);
+
+ if (written > data->n)
+ {
+ written = data->n;
+ }
+ data->q += written;
+ data->n += written;
+ return written;
+}
+
+METHOD(printf_hook_t, add_handler, void,
+ private_printf_hook_t *this, char spec, printf_hook_function_t hook, ...)
+{
+ int i = -1;
+ bool failed = FALSE;
+ printf_hook_handler_t *handler;
+ printf_hook_argtype_t argtype;
+ va_list args;
+
+ INIT(handler,
+ .hook = hook,
+ );
+
+ va_start(args, hook);
+ while (!failed)
+ {
+ argtype = va_arg(args, printf_hook_argtype_t);
+
+ if (argtype == PRINTF_HOOK_ARGTYPE_END)
+ {
+ break;
+ }
+ if (++i >= countof(handler->argtypes))
+ {
+ DBG1(DBG_LIB, "Too many arguments for printf hook with "
+ "specifier '%c', not registered!", spec);
+ failed = TRUE;
+ break;
+ }
+ handler->argtypes[i] = argtype;
+ }
+ va_end(args);
+
+ handler->numargs = i + 1;
+ if (!failed && handler->numargs > 0)
+ {
+ free(hooks->put(hooks, (void*)(uintptr_t)spec, handler));
+ }
+ else
+ {
+ free(handler);
+ }
+}
+
+/**
+ * Printf format modifier flags
+ */
+typedef enum {
+ FL_ZERO = 0x01,
+ FL_MINUS = 0x02,
+ FL_PLUS = 0x04,
+ FL_TICK = 0x08,
+ FL_SPACE = 0x10,
+ FL_HASH = 0x20,
+ FL_SIGNED = 0x40,
+ FL_UPPER = 0x80,
+} bpf_flag_t;
+
+/**
+ * Size of format string arguments
+ */
+typedef enum {
+ RNK_CHAR = -2,
+ RNK_SHORT = -1,
+ RNK_INT = 0,
+ RNK_LONG = 1,
+ RNK_LONGLONG = 2,
+
+ RNK_INTMAX = RNK_LONGLONG,
+ RNK_SIZE_T = RNK_LONG,
+ RNK_PTRDIFF_T = RNK_LONG,
+
+ RNK_MIN = RNK_CHAR,
+ RNK_MAX = RNK_LONGLONG,
+} bpf_rank_t;
+
+/**
+ * Printf specifier Parser state
+ */
+typedef enum {
+ /* Ground state */
+ ST_NORMAL,
+ /* Special flags */
+ ST_FLAGS,
+ /* Field width */
+ ST_WIDTH,
+ /* Field precision */
+ ST_PREC,
+ /* Length or conversion modifiers */
+ ST_MODIFIERS,
+} bpf_state_t;
+
+#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
+
+/**
+ * Write an integer argument to q, using flags, base, width and precision
+ */
+static size_t format_int(char *q, size_t n, uintmax_t val, bpf_flag_t flags,
+ int base, int width, int prec)
+{
+ static const char lcdigits[] = "0123456789abcdef";
+ static const char ucdigits[] = "0123456789ABCDEF";
+ char *qq;
+ size_t o = 0, oo;
+ const char *digits;
+ uintmax_t tmpval;
+ int minus = 0;
+ int ndigits = 0, nchars;
+ int tickskip, b4tick;
+
+ /* Select type of digits */
+ digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
+
+ /* If signed, separate out the minus */
+ if (flags & FL_SIGNED && (intmax_t) val < 0)
+ {
+ minus = 1;
+ val = (uintmax_t) (-(intmax_t) val);
+ }
+
+ /* Count the number of digits needed. This returns zero for 0. */
+ tmpval = val;
+ while (tmpval)
+ {
+ tmpval /= base;
+ ndigits++;
+ }
+
+ /* Adjust ndigits for size of output */
+ if (flags & FL_HASH && base == 8)
+ {
+ if (prec < ndigits + 1)
+ {
+ prec = ndigits + 1;
+ }
+ }
+
+ if (ndigits < prec)
+ {
+ /* Mandatory number padding */
+ ndigits = prec;
+ }
+ else if (val == 0)
+ {
+ /* Zero still requires space */
+ ndigits = 1;
+ }
+
+ /* For ', figure out what the skip should be */
+ if (flags & FL_TICK)
+ {
+ if (base == 16)
+ {
+ tickskip = 4;
+ }
+ else
+ {
+ tickskip = 3;
+ }
+ }
+ else
+ {
+ /* No tick marks */
+ tickskip = ndigits;
+ }
+
+ /* Tick marks aren't digits, but generated by the number converter */
+ ndigits += (ndigits - 1) / tickskip;
+
+ /* Now compute the number of nondigits */
+ nchars = ndigits;
+
+ if (minus || (flags & (FL_PLUS | FL_SPACE)))
+ {
+ /* Need space for sign */
+ nchars++;
+ }
+ if ((flags & FL_HASH) && base == 16)
+ {
+ /* Add 0x for hex */
+ nchars += 2;
+ }
+
+ /* Emit early space padding */
+ if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars)
+ {
+ while (width > nchars)
+ {
+ EMIT(' ');
+ width--;
+ }
+ }
+
+ /* Emit nondigits */
+ if (minus)
+ {
+ EMIT('-');
+ }
+ else if (flags & FL_PLUS)
+ {
+ EMIT('+');
+ }
+ else if (flags & FL_SPACE)
+ {
+ EMIT(' ');
+ }
+
+ if ((flags & FL_HASH) && base == 16)
+ {
+ EMIT('0');
+ EMIT((flags & FL_UPPER) ? 'X' : 'x');
+ }
+
+ /* Emit zero padding */
+ if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits)
+ {
+ while (width > nchars)
+ {
+ EMIT('0');
+ width--;
+ }
+ }
+
+ /* Generate the number. This is done from right to left. */
+ /* Advance the pointer to end of number */
+ q += ndigits;
+ o += ndigits;
+ /* Temporary values */
+ qq = q;
+ oo = o;
+
+ b4tick = tickskip;
+ while (ndigits > 0)
+ {
+ if (!b4tick--)
+ {
+ qq--;
+ oo--;
+ ndigits--;
+ if (oo < n)
+ {
+ *qq = '_';
+ }
+ b4tick = tickskip - 1;
+ }
+ qq--;
+ oo--;
+ ndigits--;
+ if (oo < n)
+ {
+ *qq = digits[val % base];
+ }
+ val /= base;
+ }
+
+ /* Emit late space padding */
+ while ((flags & FL_MINUS) && width > nchars)
+ {
+ EMIT(' ');
+ width--;
+ }
+
+ return o;
+}
+
+int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ char *q = buffer;
+ /* Number of characters output */
+ size_t o = 0;
+ uintmax_t val = 0;
+ /* Default rank */
+ int rank = RNK_INT;
+ int width = 0;
+ int prec = -1;
+ int base;
+ size_t sz;
+ bpf_flag_t flags = 0;
+ bpf_state_t state = ST_NORMAL;
+ /* %s string argument */
+ const char *sarg;
+ /* %c char argument */
+ char carg;
+ /* String length */
+ int slen;
+
+ while ((ch = *p++))
+ {
+ switch (state)
+ {
+ case ST_NORMAL:
+ {
+ if (ch == '%')
+ {
+ state = ST_FLAGS;
+ flags = 0;
+ rank = RNK_INT;
+ width = 0;
+ prec = -1;
+ }
+ else
+ {
+ EMIT(ch);
+ }
+ break;
+ }
+ case ST_FLAGS:
+ {
+ switch (ch)
+ {
+ case '-':
+ flags |= FL_MINUS;
+ break;
+ case '+':
+ flags |= FL_PLUS;
+ break;
+ case '\'':
+ flags |= FL_TICK;
+ break;
+ case ' ':
+ flags |= FL_SPACE;
+ break;
+ case '#':
+ flags |= FL_HASH;
+ break;
+ case '0':
+ flags |= FL_ZERO;
+ break;
+ default:
+ state = ST_WIDTH;
+ /* Process this character again */
+ p--;
+ break;
+ }
+ break;
+ }
+ case ST_WIDTH:
+ {
+ if (ch >= '0' && ch <= '9')
+ {
+ width = width * 10 + (ch - '0');
+ }
+ else if (ch == '*')
+ {
+ width = va_arg(ap, int);
+ if (width < 0)
+ {
+ width = -width;
+ flags |= FL_MINUS;
+ }
+ }
+ else if (ch == '.')
+ {
+ /* Precision given */
+ prec = 0;
+ state = ST_PREC;
+ }
+ else
+ {
+ state = ST_MODIFIERS;
+ /* Process this character again */
+ p--;
+ }
+ break;
+ }
+ case ST_PREC:
+ {
+ if (ch >= '0' && ch <= '9')
+ {
+ prec = prec * 10 + (ch - '0');
+ }
+ else if (ch == '*')
+ {
+ prec = va_arg(ap, int);
+ if (prec < 0)
+ {
+ prec = -1;
+ }
+ }
+ else
+ {
+ state = ST_MODIFIERS;
+ /* Process this character again */
+ p--;
+ }
+ break;
+ }
+ case ST_MODIFIERS:
+ {
+ switch (ch)
+ {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--;
+ break;
+ case 'l':
+ rank++;
+ break;
+ case 'j':
+ rank = RNK_INTMAX;
+ break;
+ case 'z':
+ rank = RNK_SIZE_T;
+ break;
+ case 't':
+ rank = RNK_PTRDIFF_T;
+ break;
+ case 'L':
+ case 'q':
+ rank += 2;
+ break;
+ default:
+ {
+ /* Output modifiers - terminal sequences */
+
+ /* Next state will be normal */
+ state = ST_NORMAL;
+
+ /* Canonicalize rank */
+ if (rank < RNK_MIN)
+ {
+ rank = RNK_MIN;
+ }
+ else if (rank > RNK_MAX)
+ {
+ rank = RNK_MAX;
+ }
+
+ switch (ch)
+ {
+ case 'P':
+ {
+ /* Upper case pointer */
+ flags |= FL_UPPER;
+ /* fall through */
+ }
+ case 'p':
+ {
+ /* Pointer */
+ base = 16;
+ prec = (CHAR_BIT*sizeof(void *)+3)/4;
+ flags |= FL_HASH;
+ val = (uintmax_t)(uintptr_t)
+ va_arg(ap, void *);
+ goto is_integer;
+ }
+ case 'd':
+ case 'i':
+ {
+ /* Signed decimal output */
+ base = 10;
+ flags |= FL_SIGNED;
+ switch (rank)
+ {
+ case RNK_CHAR:
+ /* Yes, all these casts are
+ needed... */
+ val = (uintmax_t)(intmax_t)(signed char)
+ va_arg(ap, signed int);
+ break;
+ case RNK_SHORT:
+ val = (uintmax_t)(intmax_t)(signed short)
+ va_arg(ap, signed int);
+ break;
+ case RNK_INT:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap, signed int);
+ break;
+ case RNK_LONG:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap, signed long);
+ break;
+ case RNK_LONGLONG:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap, signed long long);
+ break;
+ }
+ goto is_integer;
+ }
+ case 'o':
+ {
+ /* Octal */
+ base = 8;
+ goto is_unsigned;
+ }
+ case 'u':
+ {
+ /* Unsigned decimal */
+ base = 10;
+ goto is_unsigned;
+ }
+ case 'X':
+ {
+ /* Upper case hexadecimal */
+ flags |= FL_UPPER;
+ /* fall through */
+ }
+ case 'x':
+ {
+ /* Hexadecimal */
+ base = 16;
+ goto is_unsigned;
+ }
+ is_unsigned:
+ {
+ switch (rank) {
+ case RNK_CHAR:
+ val = (uintmax_t)(unsigned char)
+ va_arg(ap, unsigned int);
+ break;
+ case RNK_SHORT:
+ val = (uintmax_t)(unsigned short)
+ va_arg(ap, unsigned int);
+ break;
+ case RNK_INT:
+ val = (uintmax_t)
+ va_arg(ap, unsigned int);
+ break;
+ case RNK_LONG:
+ val = (uintmax_t)
+ va_arg(ap, unsigned long);
+ break;
+ case RNK_LONGLONG:
+ val = (uintmax_t)
+ va_arg(ap, unsigned long long);
+ break;
+ }
+ goto is_integer;
+ }
+ is_integer:
+ {
+ sz = format_int(q, (o < n) ? n - o : 0,
+ val, flags, base, width, prec);
+ q += sz;
+ o += sz;
+ break;
+ }
+ case 'c':
+ {
+ /* Character */
+ carg = (char)va_arg(ap, int);
+ sarg = &carg;
+ slen = 1;
+ goto is_string;
+ }
+ case 's':
+ {
+ /* String */
+ sarg = va_arg(ap, const char *);
+ sarg = sarg ? sarg : "(null)";
+ slen = strlen(sarg);
+ goto is_string;
+ }
+ is_string:
+ {
+ char sch;
+ int i;
+
+ if (prec != -1 && slen > prec)
+ {
+ slen = prec;
+ }
+
+ if (width > slen && !(flags & FL_MINUS))
+ {
+ char pad = (flags & FL_ZERO) ? '0' : ' ';
+ while (width > slen)
+ {
+ EMIT(pad);
+ width--;
+ }
+ }
+ for (i = slen; i; i--)
+ {
+ sch = *sarg++;
+ EMIT(sch);
+ }
+ if (width > slen && (flags & FL_MINUS))
+ {
+ while (width > slen)
+ {
+ EMIT(' ');
+ width--;
+ }
+ }
+ break;
+ }
+ case 'n':
+ {
+ /* Output the number of characters written */
+ switch (rank)
+ {
+ case RNK_CHAR:
+ *va_arg(ap, signed char *) = o;
+ break;
+ case RNK_SHORT:
+ *va_arg(ap, signed short *) = o;
+ break;
+ case RNK_INT:
+ *va_arg(ap, signed int *) = o;
+ break;
+ case RNK_LONG:
+ *va_arg(ap, signed long *) = o;
+ break;
+ case RNK_LONGLONG:
+ *va_arg(ap, signed long long *) = o;
+ break;
+ }
+ break;
+ }
+ default:
+ {
+ printf_hook_handler_t *handler;
+
+ handler = hooks->get(hooks, (void*)(uintptr_t)ch);
+ if (handler)
+ {
+ const void *args[ARGS_MAX];
+ int i, iargs[ARGS_MAX];
+ void *pargs[ARGS_MAX];
+ printf_hook_spec_t spec = {
+ .hash = flags & FL_HASH,
+ .plus = flags & FL_PLUS,
+ .minus = flags & FL_MINUS,
+ .width = width,
+ };
+ printf_hook_data_t data = {
+ .q = q,
+ .n = (o < n) ? n - o : 0,
+ };
+
+ for (i = 0; i < handler->numargs; i++)
+ {
+ switch (handler->argtypes[i])
+ {
+ case PRINTF_HOOK_ARGTYPE_INT:
+ iargs[i] = va_arg(ap, int);
+ args[i] = &iargs[i];
+ break;
+ case PRINTF_HOOK_ARGTYPE_POINTER:
+ pargs[i] = va_arg(ap, void*);
+ args[i] = &pargs[i];
+ break;
+ }
+ }
+ sz = handler->hook(&data, &spec, args);
+ q += sz;
+ o += sz;
+ }
+ else
+ {
+ /* Anything else, including % */
+ EMIT(ch);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Null-terminate the string */
+ if (o < n)
+ {
+ /* No overflow */
+ *q = '\0';
+ }
+ else if (n > 0)
+ {
+ /* Overflow - terminate at end of buffer */
+ buffer[n - 1] = '\0';
+ }
+ return o;
+}
+
+int builtin_printf(const char *format, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, format);
+ written = builtin_vprintf(format, args);
+ va_end(args);
+
+ return written;
+}
+
+int builtin_fprintf(FILE *stream, const char *format, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, format);
+ written = builtin_vfprintf(stream, format, args);
+ va_end(args);
+
+ return written;
+}
+
+int builtin_sprintf(char *str, const char *format, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, format);
+ written = builtin_vsnprintf(str, ~(size_t)0, format, args);
+ va_end(args);
+
+ return written;
+}
+
+int builtin_snprintf(char *str, size_t size, const char *format, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, format);
+ written = builtin_vsnprintf(str, size, format, args);
+ va_end(args);
+
+ return written;
+}
+
+int builtin_asprintf(char **str, const char *format, ...)
+{
+ int written;
+ va_list args;
+
+ va_start(args, format);
+ written = builtin_vasprintf(str, format, args);
+ va_end(args);
+
+ return written;
+}
+
+int builtin_vprintf(const char *format, va_list ap)
+{
+ return builtin_vfprintf(stdout, format, ap);
+}
+
+int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
+{
+ char buf[PRINTF_BUF_LEN];
+ int len;
+
+ len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
+ return fwrite(buf, 1, len, stream);
+}
+
+int builtin_vsprintf(char *str, const char *format, va_list ap)
+{
+ return builtin_vsnprintf(str, ~(size_t)0, format, ap);
+}
+
+int builtin_vasprintf(char **str, const char *format, va_list ap)
+{
+ char buf[PRINTF_BUF_LEN];
+ int len;
+
+ len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
+ *str = strdup(buf);
+ return len;
+}
+
+METHOD(printf_hook_t, destroy, void,
+ private_printf_hook_t *this)
+{
+ enumerator_t *enumerator;
+ printf_hook_handler_t *handler;
+
+ enumerator = hooks->create_enumerator(hooks);
+ while (enumerator->enumerate(enumerator, NULL, &handler))
+ {
+ free(handler);
+ }
+ enumerator->destroy(enumerator);
+
+ hooks->destroy(hooks);
+
+ free(this);
+}
+
+/*
+ * see header file
+ */
+printf_hook_t *printf_hook_create()
+{
+ private_printf_hook_t *this;
+
+ INIT(this,
+ .public = {
+ .add_handler = _add_handler,
+ .destroy = _destroy,
+ },
+ );
+
+ hooks = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8);
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
new file mode 100644
index 000000000..409b5bf3d
--- /dev/null
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup printf_hook_builtin printf_hook_builtin
+ * @{ @ingroup utils
+ */
+
+#ifndef PRINTF_HOOK_BUILTIN_H_
+#define PRINTF_HOOK_BUILTIN_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int builtin_printf(const char *format, ...);
+int builtin_fprintf(FILE *stream, const char *format, ...);
+int builtin_sprintf(char *str, const char *format, ...);
+int builtin_snprintf(char *str, size_t size, const char *format, ...);
+int builtin_asprintf(char **str, const char *format, ...);
+
+int builtin_vprintf(const char *format, va_list ap);
+int builtin_vfprintf(FILE *stream, const char *format, va_list ap);
+int builtin_vsprintf(char *str, const char *format, va_list ap);
+int builtin_vsnprintf(char *str, size_t size, const char *format, va_list ap);
+int builtin_vasprintf(char **str, const char *format, va_list ap);
+
+#ifdef printf
+#undef printf
+#endif
+#ifdef fprintf
+#undef fprintf
+#endif
+#ifdef sprintf
+#undef sprintf
+#endif
+#ifdef snprintf
+#undef snprintf
+#endif
+#ifdef asprintf
+#undef asprintf
+#endif
+#ifdef vprintf
+#undef vprintf
+#endif
+#ifdef vfprintf
+#undef vfprintf
+#endif
+#ifdef vsprintf
+#undef vsprintf
+#endif
+#ifdef vsnprintf
+#undef vsnprintf
+#endif
+#ifdef vasprintf
+#undef vasprintf
+#endif
+
+#define printf builtin_printf
+#define fprintf builtin_fprintf
+#define sprintf builtin_sprintf
+#define snprintf builtin_snprintf
+#define asprintf builtin_asprintf
+
+#define vprintf builtin_vprintf
+#define vfprintf builtin_vfprintf
+#define vsprintf builtin_vsprintf
+#define vsnprintf builtin_vsnprintf
+#define vasprintf builtin_vasprintf
+
+#endif /** PRINTF_HOOK_BUILTIN_H_ @}*/