From c899cd0d121da04308e8221109119b51d23bd612 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Nov 2016 10:31:18 +0200 Subject: [PATCH] printk: Add APIs to print into strings instead of default output These correspond to the libc snprintf and vsnprintf APIs. Change-Id: If3944972ed95934a4967756593bb2932c3359b72 Signed-off-by: Johan Hedberg --- include/misc/printk.h | 23 ++++++++++++ misc/printk.c | 50 +++++++++++++++++++++++++++ tests/kernel/test_common/src/printk.c | 28 +++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/include/misc/printk.h b/include/misc/printk.h index d97fd5c379a..9754686dc80 100644 --- a/include/misc/printk.h +++ b/include/misc/printk.h @@ -19,6 +19,8 @@ #define _PRINTK_H_ #include +#include +#include #ifdef __cplusplus extern "C" { @@ -50,12 +52,33 @@ extern "C" { */ #ifdef CONFIG_PRINTK extern __printf_like(1, 2) int printk(const char *fmt, ...); +extern __printf_like(3, 4) int snprintk(char *str, size_t size, + const char *fmt, ...); +extern int vsnprintk(char *str, size_t size, const char *fmt, va_list ap); #else static inline __printf_like(1, 2) int printk(const char *fmt, ...) { ARG_UNUSED(fmt); return 0; } + +static inline __printf_like(3, 4) int snprintk(char *str, size_t size, + const char *fmt, ...) +{ + ARG_UNUSED(str); + ARG_UNUSED(size); + ARG_UNUSED(fmt); + return 0; +} + +static inline int vsnprintk(char *str, size_t size, const char *fmt, + va_list ap) +{ + ARG_UNUSED(str); + ARG_UNUSED(size); + ARG_UNUSED(fmt); + return 0; +} #endif #ifdef __cplusplus diff --git a/misc/printk.c b/misc/printk.c index 0bc4b95ffd7..bb965f49b55 100644 --- a/misc/printk.c +++ b/misc/printk.c @@ -287,3 +287,53 @@ static void _printk_dec_ulong(out_func_t out, void *ctx, out((int)(remainder + 48), ctx); } +struct str_context { + char *str; + int max; + int count; +}; + +static int str_out(int c, struct str_context *ctx) +{ + if (!ctx->str || ctx->count >= ctx->max) { + ctx->count++; + return c; + } + + if (ctx->count == ctx->max - 1) { + ctx->str[ctx->count++] = '\0'; + } else { + ctx->str[ctx->count++] = c; + } + + return c; +} + +int snprintk(char *str, size_t size, const char *fmt, ...) +{ + struct str_context ctx = { str, size, 0 }; + va_list ap; + + va_start(ap, fmt); + _vprintk((out_func_t)str_out, &ctx, fmt, ap); + va_end(ap); + + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return ctx.count; +} + +int vsnprintk(char *str, size_t size, const char *fmt, va_list ap) +{ + struct str_context ctx = { str, size, 0 }; + + _vprintk((out_func_t)str_out, &ctx, fmt, ap); + + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return ctx.count; +} diff --git a/tests/kernel/test_common/src/printk.c b/tests/kernel/test_common/src/printk.c index c2d362d0da9..bad44220fff 100644 --- a/tests/kernel/test_common/src/printk.c +++ b/tests/kernel/test_common/src/printk.c @@ -67,6 +67,8 @@ static int ram_console_out(int character) void printk_test(void) { + int count; + _old_char_out = _char_out; _char_out = ram_console_out; @@ -82,4 +84,30 @@ void printk_test(void) ram_console[pos] = '\0'; assert_true((strcmp(ram_console, expected) == 0), "printk failed"); + + memset(ram_console, 0, sizeof(ram_console)); + count = 0; + + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%zu %hhu %hu %u %lu %llu\n", + stv, uc, usi, ui, ul, ull); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%c %hhd %hd %d %ld %lld\n", c, c, ssi, si, sl, sll); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "0x%x %p\n", hex, ptr); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "0x%x 0x%02x 0x%04x 0x%08x\n", 1, 1, 1, 1); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "0x%x 0x%2x 0x%4x 0x%8x\n", 1, 1, 1, 1); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%d %02d %04d %08d\n", 42, 42, 42, 42); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%d %02d %04d %08d\n", -42, -42, -42, -42); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%u %2u %4u %8u\n", 42, 42, 42, 42); + count += snprintk(ram_console + count, sizeof(ram_console) - count, + "%u %02u %04u %08u\n", 42, 42, 42, 42); + + ram_console[count] = '\0'; + assert_true((strcmp(ram_console, expected) == 0), "snprintk failed"); }