Move printFormat() to kstd
This commit is contained in:
parent
27fd989245
commit
7e266a2837
3 changed files with 45 additions and 30 deletions
338
src/kstd/PrintFormat.cc
Normal file
338
src/kstd/PrintFormat.cc
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/* PrintFormat.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Declares printFormat(), for writing formatted strings to the appropriate channel.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "Console.hh"
|
||||
#include "kstd/ASCII.hh"
|
||||
#include "kstd/CString.hh"
|
||||
#include "kstd/Types.hh"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Spec {
|
||||
enum class Size {
|
||||
Normal,
|
||||
DoubleShort,
|
||||
Short,
|
||||
Long,
|
||||
DoubleLong,
|
||||
};
|
||||
|
||||
enum class Type {
|
||||
Int,
|
||||
Unsigned,
|
||||
Hex,
|
||||
Char,
|
||||
String
|
||||
};
|
||||
|
||||
bool zeroPadded;
|
||||
bool capitalized;
|
||||
int width;
|
||||
Size size;
|
||||
Type type;
|
||||
|
||||
union Value {
|
||||
i8 hhd;
|
||||
i16 hd;
|
||||
i32 d;
|
||||
i64 ld;
|
||||
i64 lld;
|
||||
u8 hhu;
|
||||
u16 hu;
|
||||
u32 u;
|
||||
u64 lu;
|
||||
u64 llu;
|
||||
u8 hhx;
|
||||
u16 hx;
|
||||
u32 x;
|
||||
u64 lx;
|
||||
u64 llx;
|
||||
char c;
|
||||
char* s;
|
||||
} value;
|
||||
|
||||
void clear();
|
||||
int print(kernel::Console& console);
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Spec::clear()
|
||||
{
|
||||
zeroPadded = false;
|
||||
capitalized = false;
|
||||
width = 0;
|
||||
size = Size::Normal;
|
||||
type = Type::Int;
|
||||
value.llx = 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Spec::print(kernel::Console& console)
|
||||
{
|
||||
int nchars = 0;
|
||||
int length = 0;
|
||||
char buf[32];
|
||||
char pad = ' ';
|
||||
char *str;
|
||||
|
||||
/*
|
||||
* TypeChar is a special case because it will always be a single character
|
||||
* in length and there is no \0 to terminate it.
|
||||
*/
|
||||
if (type == Type::Char) {
|
||||
if (width == 0) {
|
||||
width = 1;
|
||||
}
|
||||
for (int i = 1; i < width; i++) {
|
||||
console.printChar(' ');
|
||||
}
|
||||
console.printChar(value.c);
|
||||
return width;
|
||||
}
|
||||
|
||||
if (type == Type::Int || type == Type::Hex) {
|
||||
if (zeroPadded) {
|
||||
pad = '0';
|
||||
}
|
||||
if (type == Type::Int) {
|
||||
switch (size) {
|
||||
case Size::Normal:
|
||||
length = kstd::CString::fromInteger(value.d, buf, 32);
|
||||
break;
|
||||
case Size::DoubleShort:
|
||||
length = kstd::CString::fromInteger(value.hhd, buf, 32);
|
||||
break;
|
||||
case Size::Short:
|
||||
length = kstd::CString::fromInteger(value.hd, buf, 32);
|
||||
break;
|
||||
case Size::Long:
|
||||
length = kstd::CString::fromInteger(value.ld, buf, 32);
|
||||
break;
|
||||
case Size::DoubleLong:
|
||||
length = kstd::CString::fromInteger(value.lld, buf, 32);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (size) {
|
||||
case Size::Normal:
|
||||
length = kstd::CString::fromUnsignedInteger(value.x, buf, 32, 16, capitalized);
|
||||
break;
|
||||
case Size::DoubleShort:
|
||||
length = kstd::CString::fromUnsignedInteger(value.hhx, buf, 32, 16, capitalized);
|
||||
break;
|
||||
case Size::Short:
|
||||
length = kstd::CString::fromUnsignedInteger(value.hx, buf, 32, 16, capitalized);
|
||||
break;
|
||||
case Size::Long:
|
||||
length = kstd::CString::fromUnsignedInteger(value.lx, buf, 32, 16, capitalized);
|
||||
break;
|
||||
case Size::DoubleLong:
|
||||
length = kstd::CString::fromUnsignedInteger(value.llx, buf, 32, 16, capitalized);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (width < length) {
|
||||
width = length;
|
||||
}
|
||||
str = buf;
|
||||
} else if (type == Type::String) {
|
||||
length = kstd::CString::length(value.s);
|
||||
if (width < length) {
|
||||
width = length;
|
||||
}
|
||||
str = value.s;
|
||||
} else {
|
||||
// Don't know how to print this.
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = width; i > 0; i--) {
|
||||
if (i <= length) {
|
||||
console.printChar(str[length - i]);
|
||||
}
|
||||
else if (i <= width) {
|
||||
console.printChar(pad);
|
||||
}
|
||||
}
|
||||
|
||||
return nchars;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
isSize(char c)
|
||||
{
|
||||
return c == 'h' || c == 'l';
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
isSpecifier(char c)
|
||||
{
|
||||
return c == 'd' || c == 'x' || c == 'X' || c == 'c' || c == 's';
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
|
||||
namespace kstd {
|
||||
|
||||
int
|
||||
printFormat(const char* format,
|
||||
va_list args)
|
||||
{
|
||||
enum {
|
||||
Default = 0,
|
||||
Percent,
|
||||
Width,
|
||||
Size
|
||||
} state = Default;
|
||||
|
||||
int nchars = 0;
|
||||
Spec spec;
|
||||
|
||||
for (const char* p = format; *p != 0; p++) {
|
||||
switch (state) {
|
||||
case Default:
|
||||
if (*p == '%') {
|
||||
state = Percent;
|
||||
spec.clear();
|
||||
} else {
|
||||
printChar(*p);
|
||||
nchars++;
|
||||
}
|
||||
break;
|
||||
case Percent:
|
||||
if (*p == '%') {
|
||||
state = Default;
|
||||
printChar(*p);
|
||||
nchars++;
|
||||
} else if (Char::isDigit(*p)) {
|
||||
if (*p == '0' && !spec.zeroPadded) {
|
||||
spec.zeroPadded = true;
|
||||
} else {
|
||||
state = Width;
|
||||
spec.width = *p - '0';
|
||||
}
|
||||
} else if (isSize(*p)) {
|
||||
goto state_size;
|
||||
} else if (isSpecifier(*p)) {
|
||||
goto state_specifier;
|
||||
}
|
||||
break;
|
||||
case Width:
|
||||
if (Char::isDigit(*p)) {
|
||||
spec.width = 10 * spec.width + (*p - '0');
|
||||
} else if (isSize(*p)) {
|
||||
state = Size;
|
||||
goto state_size;
|
||||
} else if (isSpecifier(*p)) {
|
||||
goto state_specifier;
|
||||
}
|
||||
break;
|
||||
case Size:
|
||||
if (isSize(*p)) {
|
||||
goto state_size;
|
||||
} else if (isSpecifier(*p)) {
|
||||
goto state_specifier;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printChar(*p);
|
||||
nchars++;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
state_size:
|
||||
if (*p == 'h') {
|
||||
spec.size = (spec.size == Spec::Size::Short) ? Spec::Size::DoubleShort : Spec::Size::Short;
|
||||
} else if (*p == 'l') {
|
||||
spec.size = (spec.size == Spec::Size::Long) ? Spec::Size::DoubleLong : Spec::Size::Long;
|
||||
}
|
||||
continue;
|
||||
|
||||
state_specifier:
|
||||
state = Default;
|
||||
switch (*p) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
switch (spec.size) {
|
||||
case Spec::Size::Normal:
|
||||
spec.value.d = va_arg(args, int);
|
||||
break;
|
||||
case Spec::Size::DoubleShort:
|
||||
spec.value.hhd = (signed char)va_arg(args, int);
|
||||
break;
|
||||
case Spec::Size::Short:
|
||||
spec.value.hd = (short int)va_arg(args, int);
|
||||
break;
|
||||
case Spec::Size::Long:
|
||||
spec.value.ld = va_arg(args, long int);
|
||||
break;
|
||||
case Spec::Size::DoubleLong:
|
||||
spec.value.lld = va_arg(args, long long int);
|
||||
break;
|
||||
}
|
||||
spec.type = Spec::Type::Int;
|
||||
break;
|
||||
case 'X':
|
||||
spec.capitalized = true;
|
||||
// fall through
|
||||
case 'x':
|
||||
switch (spec.size) {
|
||||
case Spec::Size::Normal:
|
||||
spec.value.x = va_arg(args, unsigned int);
|
||||
break;
|
||||
case Spec::Size::DoubleShort:
|
||||
spec.value.hhx = (unsigned char)va_arg(args, unsigned int);
|
||||
break;
|
||||
case Spec::Size::Short:
|
||||
spec.value.hx = (unsigned short int)va_arg(args, unsigned int);
|
||||
break;
|
||||
case Spec::Size::Long:
|
||||
spec.value.lx = va_arg(args, unsigned long int);
|
||||
break;
|
||||
case Spec::Size::DoubleLong:
|
||||
spec.value.llx = va_arg(args, unsigned long long int);
|
||||
break;
|
||||
}
|
||||
spec.type = Spec::Type::Hex;
|
||||
break;
|
||||
case 'c':
|
||||
spec.value.c = va_arg(args, int);
|
||||
spec.type = Spec::Type::Char;
|
||||
break;
|
||||
case 's':
|
||||
spec.value.s = va_arg(args, char*);
|
||||
spec.type = Spec::Type::String;
|
||||
break;
|
||||
}
|
||||
nchars += spec.print(*this);
|
||||
continue;
|
||||
}
|
||||
|
||||
return nchars;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
printFormat(const char* format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int nchars = printFormat(format, args);
|
||||
va_end(args);
|
||||
return nchars;
|
||||
}
|
||||
|
||||
} /* namespace kstd */
|
||||
22
src/kstd/PrintFormat.hh
Normal file
22
src/kstd/PrintFormat.hh
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* PrintFormat.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
/**
|
||||
* Declares printFormat(), for writing formatted strings to the appropriate channel.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace kstd {
|
||||
|
||||
/**
|
||||
* Write a format string to the appropriate output channel.
|
||||
* @return Number of characters printed
|
||||
* @{
|
||||
*/
|
||||
int printFormat(const char* format, ...) PRINTF(2,3);
|
||||
int printFormat(const char* format, va_list args);
|
||||
/** @} */
|
||||
|
||||
} /* namespace kstd */
|
||||
Loading…
Add table
Add a link
Reference in a new issue