From 37d92a552ef9afbef4095f2aff83587f5ebf204d Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 19 May 2010 16:41:11 -0500 Subject: Full vargs printk. --- src/kernel/console.C | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 2 deletions(-) (limited to 'src/kernel/console.C') diff --git a/src/kernel/console.C b/src/kernel/console.C index a2ad0ffe2..06cd98e2b 100644 --- a/src/kernel/console.C +++ b/src/kernel/console.C @@ -1,5 +1,6 @@ #include #include +#include static char kernel_printk_buffer[Console::BUFFER_SIZE]; @@ -17,12 +18,240 @@ int Console::putc(int c) } } -void printk(const char* str) +class ConsoleTraits { + public: + enum trait { NONE, HEX, DEC, }; +}; + +template +class ConsoleDisplay +{ + public: + static void display(Console& c, _T value) {}; +}; + +template <> +class ConsoleDisplay +{ + public: + static void display(Console&c, char value) + { + c.putc(value); + } +}; + +template +class ConsoleDisplay<_T, ConsoleTraits::DEC> +{ + public: + static void display(Console&c, _T value) + { + if (value == 0) + { + c.putc('0'); + } + else if (value < 0) + { + c.putc('-'); + value *= -1; + } + else + subdisplay(c, value); + } + + static void subdisplay(Console&c, _T value) + { + if (value != 0) + { + subdisplay(c, value / 10); + c.putc('0' + (value % 10)); + } + } +}; + +template +class ConsoleDisplay<_T, ConsoleTraits::HEX> +{ + public: + static void display(Console&c, _T value) + { + size_t length = sizeof(_T) * 2; + subdisplay(c, value, length); + } + + static void subdisplay(Console&c, _T value, size_t length) + { + if (length == 0) return; + subdisplay(c, value / 16, length-1); + char nibble = value % 16; + if (nibble >= 0x0a) + c.putc('A' + (nibble - 0x0a)); + else + c.putc('0' + nibble); + } +}; + +void printk(const char* str, ...) +{ + va_list args; + va_start(args, str); + Console& console = Singleton::instance(); + + bool format = false; + int size; + while('\0' != *str) { - console.putc(*str); + if (('%' == *str) || (format)) + switch (*str) + { + case '%': + { + if (format) + { + ConsoleDisplay::display(console, '%'); + } + else + { + format = true; + size = 2; + } + break; + } + case 'c': + { + format = false; + ConsoleDisplay + ::display(console, + (char)va_arg(args,int)); + break; + } + case 'h': + { + size--; + break; + } + case 'l': + { + size++; + break; + } + case 'd': // decimal + { + format = false; + switch(size) + { + case 0: + ConsoleDisplay + ::display(console, + (char)va_arg(args,int)); + break; + + case 1: + ConsoleDisplay + ::display(console, + (short)va_arg(args,int)); + break; + + case 2: + case 3: + ConsoleDisplay + ::display(console, + va_arg(args,int)); + break; + + case 4: + ConsoleDisplay + ::display(console, + va_arg(args,long)); + break; + } + break; + } + case 'u': // unsigned decimal + { + format = false; + switch(size) + { + case 0: + ConsoleDisplay + ::display(console, + (unsigned char) + va_arg(args,unsigned int)); + break; + + case 1: + ConsoleDisplay + ::display(console, + (unsigned short) + va_arg(args,unsigned int)); + break; + + case 2: + case 3: + ConsoleDisplay + ::display(console, + va_arg(args,unsigned int)); + break; + + case 4: + ConsoleDisplay + ::display(console, + va_arg(args,unsigned long)); + break; + } + break; + } + case 'x': // unsigned hex + case 'X': + { + format = false; + switch(size) + { + case 0: + ConsoleDisplay + ::display(console, + (unsigned char) + va_arg(args,unsigned int)); + break; + + case 1: + ConsoleDisplay + ::display(console, + (unsigned short) + va_arg(args,unsigned int)); + break; + + case 2: + case 3: + ConsoleDisplay + ::display(console, + va_arg(args,unsigned int)); + break; + + case 4: + ConsoleDisplay + ::display(console, + va_arg(args,unsigned long)); + break; + } + break; + } + case 's': // string + { + format = false; + ConsoleDisplay::display(console, + (char*)va_arg(args,void*)); + break; + } + } + else + ConsoleDisplay::display(console, *str); + str++; } + + va_end(args); } -- cgit v1.2.3