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 <szymon.janc@codecoup.pl>
This commit is contained in:
Szymon Janc 2016-11-20 22:06:37 +01:00 committed by Anas Nashif
commit bde20d5447
2 changed files with 66 additions and 9 deletions

View file

@ -27,8 +27,10 @@
#include <toolchain.h>
#include <sections.h>
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;
}

View file

@ -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");