mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-04 00:00:14 -04:00
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.
This commit is contained in:
parent
ebca34d782
commit
cabe5c0ff4
@ -624,7 +624,7 @@ AC_CHECK_FUNC(
|
|||||||
[AC_DEFINE([HAVE_PRINTF_FUNCTION], [], [have register_printf_function()])],
|
[AC_DEFINE([HAVE_PRINTF_FUNCTION], [], [have register_printf_function()])],
|
||||||
[
|
[
|
||||||
AC_MSG_NOTICE([printf does not support custom format specifiers!])
|
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
|
if test x$vstr = xtrue; then
|
||||||
AC_CHECK_LIB([vstr],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([Vstr string library not found])],[])
|
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])
|
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
|
fi
|
||||||
|
|
||||||
if test x$gmp = xtrue; then
|
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_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_LIBCAP, test x$capabilities = xlibcap)
|
||||||
AM_CONDITIONAL(USE_VSTR, test x$vstr = xtrue)
|
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_SIMAKA, test x$simaka = xtrue)
|
||||||
AM_CONDITIONAL(USE_TLS, test x$tls = xtrue)
|
AM_CONDITIONAL(USE_TLS, test x$tls = xtrue)
|
||||||
AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue)
|
AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue)
|
||||||
|
@ -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/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/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \
|
||||||
utils/leak_detective.h utils/printf_hook/printf_hook.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
|
utils/settings.h utils/integrity_checker.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -119,9 +119,16 @@ if USE_VSTR
|
|||||||
libstrongswan_la_LIBADD += -lvstr
|
libstrongswan_la_LIBADD += -lvstr
|
||||||
endif
|
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
|
if !USE_VSTR
|
||||||
libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_glibc.c
|
libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_glibc.c
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_LIBCAP
|
if USE_LIBCAP
|
||||||
libstrongswan_la_LIBADD += -lcap
|
libstrongswan_la_LIBADD += -lcap
|
||||||
|
@ -31,6 +31,8 @@ typedef enum printf_hook_argtype_t printf_hook_argtype_t;
|
|||||||
|
|
||||||
#if defined(USE_VSTR)
|
#if defined(USE_VSTR)
|
||||||
# include "printf_hook_vstr.h"
|
# include "printf_hook_vstr.h"
|
||||||
|
#elif defined(USE_BUILTIN_PRINTF)
|
||||||
|
# include "printf_hook_builtin.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
933
src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
Normal file
933
src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
Normal file
@ -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;
|
||||||
|
}
|
82
src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
Normal file
82
src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
Normal file
@ -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_ @}*/
|
Loading…
x
Reference in New Issue
Block a user