From bde20d5447c2f216e0389c10733315125359bdba Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Sun, 20 Nov 2016 22:06:37 +0100 Subject: [PATCH] printk: Add basic support for width modifier and zero padding This adds basic support for width modifier when printing integers. Supported specifiers are u,i,d,x,X. Width '*' is not supported. Flag '0' for left-pading number with zero is also supported. examples: printk("0x%x 0x%02x 0x%04x 0x%08x\n", 1, 1, 1, 1); 0x1 0x01 0x0001 0x00000001 printk("0x%x 0x%2x 0x%4x 0x%8x\n", 1, 1, 1, 1); 0x1 0x 1 0x 1 0x 1 This should make printk usable for pretty printing u8 and u16 integers. Change-Id: I58fa869e9c295a052f97fbf052291ef4d132811e Signed-off-by: Szymon Janc --- misc/printk.c | 63 +++++++++++++++++++++++---- tests/kernel/test_common/src/printk.c | 12 +++++ 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/misc/printk.c b/misc/printk.c index 5bcc761fc5c..b8b5baf1570 100644 --- a/misc/printk.c +++ b/misc/printk.c @@ -27,8 +27,10 @@ #include #include -static void _printk_dec_ulong(const unsigned long num); -static void _printk_hex_ulong(const unsigned long num); +static void _printk_dec_ulong(const unsigned long num, int pad_zero, + int min_width); +static void _printk_hex_ulong(const unsigned long num, int pad_zero, + int min_width); /** * @brief Default character output routine that does nothing @@ -73,6 +75,8 @@ void __printk_hook_install(int (*fn)(int)) static inline void _vprintk(const char *fmt, va_list ap) { int might_format = 0; /* 1 if encountered a '%' */ + int pad_zero = 0; + int min_width = -1; /* fmt has already been adjusted if needed */ @@ -82,9 +86,24 @@ static inline void _vprintk(const char *fmt, va_list ap) _char_out((int)*fmt); } else { might_format = 1; + min_width = -1; + pad_zero = 0; } } else { switch (*fmt) { + case '0': + if (min_width < 0 && pad_zero == 0) { + pad_zero = 1; + goto still_might_format; + } + /* Fall through */ + case '1' ... '9': + if (min_width < 0) { + min_width = *fmt - '0'; + } else { + min_width = 10 * min_width + *fmt - '0'; + } + goto still_might_format; case 'z': case 'l': case 'h': @@ -97,25 +116,29 @@ static inline void _vprintk(const char *fmt, va_list ap) if (d < 0) { _char_out((int)'-'); d = -d; + min_width--; } - _printk_dec_ulong(d); + _printk_dec_ulong(d, pad_zero, min_width); break; } case 'u': { unsigned long u = va_arg( ap, unsigned long); - _printk_dec_ulong(u); + _printk_dec_ulong(u, pad_zero, min_width); break; } case 'p': _char_out('0'); _char_out('x'); + /* left-pad pointers with zeros */ + pad_zero = 1; + min_width = 8; /* Fall through */ case 'x': case 'X': { unsigned long x = va_arg( ap, unsigned long); - _printk_hex_ulong(x); + _printk_hex_ulong(x, pad_zero, min_width); break; } case 's': { @@ -183,14 +206,26 @@ void printk(const char *fmt, ...) * * @return N/A */ -static void _printk_hex_ulong(const unsigned long num) +static void _printk_hex_ulong(const unsigned long num, int pad_zero, + int min_width) { int size = sizeof(num) * 2; + int found_largest_digit = 0; + int remaining = 8; /* 8 digits max */ for (; size; size--) { char nibble = (num >> ((size - 1) << 2) & 0xf); - nibble += nibble > 9 ? 87 : 48; - _char_out((int)nibble); + + if (nibble || found_largest_digit || size == 1) { + found_largest_digit = 1; + nibble += nibble > 9 ? 87 : 48; + _char_out((int)nibble); + continue; + } + + if (remaining-- <= min_width) { + _char_out((int)(pad_zero ? '0' : ' ')); + } } } @@ -203,17 +238,27 @@ static void _printk_hex_ulong(const unsigned long num) * * @return N/A */ -static void _printk_dec_ulong(const unsigned long num) +static void _printk_dec_ulong(const unsigned long num, int pad_zero, + int min_width) { unsigned long pos = 999999999; unsigned long remainder = num; int found_largest_digit = 0; + int remaining = 10; /* 10 digits max */ + + /* make sure we don't skip if value is zero */ + if (min_width <= 0) { + min_width = 1; + } while (pos >= 9) { if (found_largest_digit || remainder > pos) { found_largest_digit = 1; _char_out((int)((remainder / (pos + 1)) + 48)); + } else if (remaining <= min_width) { + _char_out((int)(pad_zero ? '0' : ' ')); } + remaining--; remainder %= (pos + 1); pos /= 10; } diff --git a/tests/kernel/test_common/src/printk.c b/tests/kernel/test_common/src/printk.c index 6e4b78196f3..c2d362d0da9 100644 --- a/tests/kernel/test_common/src/printk.c +++ b/tests/kernel/test_common/src/printk.c @@ -27,6 +27,12 @@ int (*_old_char_out)(int); char *expected = "22 113 10000 32768 40000 22\n" "p 112 -10000 -32768 -40000 -22\n" "0xcafebabe 0x0000beef\n" + "0x1 0x01 0x0001 0x00000001\n" + "0x1 0x 1 0x 1 0x 1\n" + "42 42 0042 00000042\n" + "-42 -42 -042 -0000042\n" + "42 42 42 42\n" + "42 42 0042 00000042\n" ; @@ -67,6 +73,12 @@ void printk_test(void) printk("%zu %hhu %hu %u %lu %llu\n", stv, uc, usi, ui, ul, ull); printk("%c %hhd %hd %d %ld %lld\n", c, c, ssi, si, sl, sll); printk("0x%x %p\n", hex, ptr); + printk("0x%x 0x%02x 0x%04x 0x%08x\n", 1, 1, 1, 1); + printk("0x%x 0x%2x 0x%4x 0x%8x\n", 1, 1, 1, 1); + printk("%d %02d %04d %08d\n", 42, 42, 42, 42); + printk("%d %02d %04d %08d\n", -42, -42, -42, -42); + printk("%u %2u %4u %8u\n", 42, 42, 42, 42); + printk("%u %02u %04u %08u\n", 42, 42, 42, 42); ram_console[pos] = '\0'; assert_true((strcmp(ram_console, expected) == 0), "printk failed");