#include <config.h>
#include <machine/io.h>
#ifdef CONFIG_PRINTING
#include <stdarg.h>
void
putchar(char c)
{
putConsoleChar(c);
if (c == '\n') {
putConsoleChar('\r');
}
}
static unsigned int
print_string(const char *s)
{
unsigned int n;
for (n = 0; *s; s++, n++) {
kernel_putchar(*s);
}
return n;
}
static unsigned long
xdiv(unsigned long x, unsigned int denom)
{
switch (denom) {
case 16:
return x / 16;
case 10:
return x / 10;
default:
return 0;
}
}
static unsigned long
xmod(unsigned long x, unsigned int denom)
{
switch (denom) {
case 16:
return x % 16;
case 10:
return x % 10;
default:
return 0;
}
}
word_t
print_unsigned_long(unsigned long x, word_t ui_base)
{
char out[sizeof(unsigned long) * 2 + 3];
word_t i, j;
unsigned int d;
if (ui_base != 10 && ui_base != 16) {
return 0;
}
if (x == 0) {
kernel_putchar('0');
return 1;
}
for (i = 0; x; x = xdiv(x, ui_base), i++) {
d = xmod(x, ui_base);
if (d >= 10) {
out[i] = 'a' + d - 10;
} else {
out[i] = '0' + d;
}
}
for (j = i; j > 0; j--) {
kernel_putchar(out[j - 1]);
}
return i;
}
compile_assert(print_unsigned_long_long_sizes, sizeof(unsigned int) * 2 == sizeof(unsigned long long))
static unsigned int
print_unsigned_long_long(unsigned long long x, unsigned int ui_base)
{
unsigned int upper, lower;
unsigned int n = 0;
unsigned int mask = 0xF0000000u;
unsigned int shifts = 0;
if (ui_base != 16) {
return 0;
}
upper = (unsigned int) (x >> 32llu);
lower = (unsigned int) x & 0xffffffff;
if (upper > 0) {
n += print_unsigned_long(upper, ui_base);
while (!(mask & lower)) {
kernel_putchar('0');
n++;
mask = mask >> 4;
shifts++;
if (shifts == 8) {
break;
}
}
}
n += print_unsigned_long(lower, ui_base);
return n;
}
static int
vprintf(const char *format, va_list ap)
{
unsigned int n;
unsigned int formatting;
if (!format) {
return 0;
}
n = 0;
formatting = 0;
while (*format) {
if (formatting) {
switch (*format) {
case '%':
kernel_putchar('%');
n++;
format++;
break;
case 'd': {
int x = va_arg(ap, int);
if (x < 0) {
kernel_putchar('-');
n++;
x = -x;
}
n += print_unsigned_long(x, 10);
format++;
break;
}
case 'u':
n += print_unsigned_long(va_arg(ap, unsigned int), 10);
format++;
break;
case 'x':
n += print_unsigned_long(va_arg(ap, unsigned int), 16);
format++;
break;
case 'p': {
unsigned long p = va_arg(ap, unsigned long);
if (p == 0) {
n += print_string("(nil)");
} else {
n += print_string("0x");
n += print_unsigned_long(p, 16);
}
format++;
break;
}
case 's':
n += print_string(va_arg(ap, char *));
format++;
break;
case 'l':
format++;
switch (*format) {
case 'd': {
long x = va_arg(ap, long);
if (x < 0) {
kernel_putchar('-');
n++;
x = -x;
}
n += print_unsigned_long((unsigned long)x, 10);
format++;
}
break;
case 'l':
if (*(format + 1) == 'x') {
n += print_unsigned_long_long(va_arg(ap, unsigned long long), 16);
}
format += 2;
break;
case 'u':
n += print_unsigned_long(va_arg(ap, unsigned long), 10);
format++;
break;
case 'x':
n += print_unsigned_long(va_arg(ap, unsigned long), 16);
format++;
break;
default:
return -1;
}
break;
default:
return -1;
}
formatting = 0;
} else {
switch (*format) {
case '%':
formatting = 1;
format++;
break;
default:
kernel_putchar(*format);
n++;
format++;
break;
}
}
}
return n;
}
word_t puts(const char *s)
{
for (; *s; s++) {
kernel_putchar(*s);
}
kernel_putchar('\n');
return 0;
}
word_t
kprintf(const char *format, ...)
{
va_list args;
word_t i;
va_start(args, format);
i = vprintf(format, args);
va_end(args);
return i;
}
#endif