diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/tests/test_printf.c | 29 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_builtin.c | 196 |
2 files changed, 223 insertions, 2 deletions
diff --git a/src/libstrongswan/tests/test_printf.c b/src/libstrongswan/tests/test_printf.c index 60655de8a..f822e5f4b 100644 --- a/src/libstrongswan/tests/test_printf.c +++ b/src/libstrongswan/tests/test_printf.c @@ -91,6 +91,31 @@ START_TEST(test_printf_hex) } END_TEST +START_TEST(test_printf_float) +{ + verify("0.000000", "%f", 0.0); + verify("1.000000", "%f", 1.0); + verify("12345.1", "%.1f", 12345.123); + verify("1", "%.0f", 1.0); + verify("1.4", "%.1f", 1.456789); + verify("1.34", "%.2f", 1.3456789); + verify("1.234", "%.3f", 1.23456789); + verify("1.1234", "%.4f", 1.123456789); + + verify("-1.000000", "%f", -1.0); + verify("-12345.1", "%.1f", -12345.123); + verify("-1", "%.0f", -1.0); + verify("-1.4", "%.1f", -1.456789); + verify("-1.34", "%.2f", -1.3456789); + verify("-1.234", "%.3f", -1.23456789); + verify("-1.1234", "%.4f", -1.123456789); + + verify(" 1.2", "%5.1f", 1.234); + verify("001.2", "%05.1f", 1.234); + verify("1.2 ", "%-5.1f", 1.234); +} +END_TEST + Suite *printf_suite_create() { Suite *s; @@ -118,5 +143,9 @@ Suite *printf_suite_create() tcase_add_test(tc, test_printf_hex); suite_add_tcase(s, tc); + tc = tcase_create("float"); + tcase_add_test(tc, test_printf_float); + suite_add_tcase(s, tc); + return s; } diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c index 1c266d454..6ba4841cd 100644 --- a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c +++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c @@ -47,6 +47,7 @@ #include <stdarg.h> #include <string.h> #include <errno.h> +#include <math.h> #define PRINTF_BUF_LEN 8192 #define ARGS_MAX 3 @@ -222,14 +223,15 @@ typedef enum { #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; }) +static const char lcdigits[] = "0123456789abcdef"; +static const char ucdigits[] = "0123456789ABCDEF"; + /** * 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; @@ -393,6 +395,155 @@ static size_t format_int(char *q, size_t n, uintmax_t val, bpf_flag_t flags, return o; } +/** + * Write an double argument to q, using flags, base, width and precision + */ +static size_t format_double(char *q, size_t n, double val, bpf_flag_t flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + if (prec < 0) + { + /* default precision */ + prec = 6; + } + if (val < 0) + { + minus = 1; + } + + tmpval = (uintmax_t)fabs(val); + while (tmpval) + { + tmpval /= base; + ndigits++; + } + if (val == 0) + { + ndigits++; + } + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if (prec) + { + /* Space for decimal-point and digits after that */ + nchars += prec + 1; + } + 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; + + tmpval = (uintmax_t)fabs(val); + while (ndigits > 0) + { + qq--; + oo--; + ndigits--; + if (oo < n) + { + *qq = digits[tmpval % base]; + } + tmpval /= base; + } + + if (prec) + { + EMIT('.'); + + q += prec; + o += prec; + qq = q; + oo = o; + + while (prec > 0) + { + tmpval = (uintmax_t)(fabs(val) * pow(base, prec)); + qq--; + oo--; + prec--; + if (oo < n) + { + *qq = digits[tmpval % 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; @@ -724,6 +875,47 @@ int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap) } break; } + case 'A': + { + base = 16; + flags |= FL_UPPER; + goto is_double; + } + case 'E': + case 'G': + { + /* currently not supported, fall */ + } + case 'F': + { + base = 10; + flags |= FL_UPPER; + goto is_double; + } + case 'a': + { + base = 16; + goto is_double; + } + case 'e': + case 'g': + { + /* currently not supported, fall */ + } + case 'f': + { + base = 10; + goto is_double; + } + is_double: + { + sz = format_double(q, (o < n) ? n - o : 0, + va_arg(ap, double), + flags, base, width, prec); + q += sz; + o += sz; + break; + } case 'n': { /* Output the number of characters written */ |