Vhex-kernel/src/kernel/devices/earlyterm/write.c

170 lines
4.2 KiB
C

#include <kernel/devices/earlyterm.h>
#include <kernel/drivers/screen.h>
#include <kernel/util/atomic.h>
#include <stdarg.h>
/* earlyterm_vertical_update() - Check / update device vertical cursor */
static void earlyterm_vertical_update(struct earlyterm *earlyterm)
{
// Check if we can move the cursor
if (earlyterm->cursor.y + 1 < earlyterm->cursor.max.y) {
earlyterm->cursor.y = earlyterm->cursor.y + 1;
return;
}
// Other wise scroll the vram
dscroll(&earlyterm->display, earlyterm->display.font->font.height + 1);
}
/* earlyterm_horizontal_update() - Check / update earlyterm horizotal cursor */
static int earlyterm_horizontal_update(struct earlyterm *earlyterm)
{
earlyterm->cursor.x = earlyterm->cursor.x + 1;
if (earlyterm->cursor.x >= earlyterm->cursor.max.x)
{
earlyterm_vertical_update(earlyterm);
earlyterm->cursor.x = 0;
return (1);
}
return (0);
}
/* print_base() - display number in base (0~16)*/
static void print_base(struct earlyterm *earlyterm, uint32_t nb,
int base, int digits_min)
{
char hex[] = "0123456789abcdef";
char buffer[16];
int digits;
// Generate string (reverse)
digits = 0;
while (digits < digits_min || nb != 0)
{
buffer[digits++] = hex[nb % base];
nb = nb / base;
}
// Display string.
while (--digits >= 0)
{
dascii(&earlyterm->display, earlyterm->cursor.x,
earlyterm->cursor.y, buffer[digits], 0);
earlyterm_horizontal_update(earlyterm);
}
}
/* line_discipline() - Check all "special" char */
static int line_discipline(struct earlyterm *earlyterm, char n)
{
// New line
if (n == '\n')
{
earlyterm->cursor.x = 0;
earlyterm_vertical_update(earlyterm);
return (1);
}
return (0);
}
// earlyterm_write() - printf wrapper for early terminal device
// TODO: update me... x_x
void earlyterm_write(const char *format, ...)
{
extern struct earlyterm earlyterm;
int32_t nb;
va_list ap;
int i;
// Atomic start
atomic_start();
// Get starting variable args
va_start(ap, format);
// Walk into string and display character by character
i = -1;
while (format[++i] != '\0')
{
// Check line discipline
if (line_discipline(&earlyterm, format[i]) != 0)
continue;
// String format "simple"
if (format[i] == '%')
{
if (format[i + 1] == 'c') {
nb = (char)va_arg(ap, int);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, nb, 0);
earlyterm_horizontal_update(&earlyterm);
i = i + 1;
continue;
}
if (format[i + 1] == 'd' || format[i + 1] == 'x')
{
// Check negative value
// FIXME: negative error (max)
nb = va_arg(ap, int32_t);
if (nb < 0 && format[i + 1] == 'd')
{
nb = 0 - nb;
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '-', 0);
earlyterm_horizontal_update(&earlyterm);
}
print_base(&earlyterm, nb, (format[i + 1] == 'd') ? 10 : 16, 1);
i = i + 1;
continue;
}
if ((format[i + 1] == '#' && format[i + 2] == 'x') || format[i + 1] == 'p')
{
// add @ if 'p' (pointer)
if (format[i + 1] == 'p')
{
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '@', 0);
earlyterm_horizontal_update(&earlyterm);
}
// Add "0x"
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, '0', 0);
earlyterm_horizontal_update(&earlyterm);
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, 'x', 0);
earlyterm_horizontal_update(&earlyterm);
// Get value
nb = va_arg(ap, uint32_t);
print_base(&earlyterm, nb, 16, 8);
// Update cursor
i = (format[i + 1] == '#') ? i + 2 : i + 1;
continue;
}
if (format[i + 1] == 's')
{
nb = va_arg(ap, uint32_t) - 1;
while (*(char*)(++nb) != '\0')
{
if (line_discipline(&earlyterm, *(char*)nb) != 0)
continue;
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, *(char*)nb, 0);
earlyterm_horizontal_update(&earlyterm);
}
i = i + 1;
continue;
}
}
// Default, display character
dascii(&earlyterm.display, earlyterm.cursor.x, earlyterm.cursor.y, format[i], 0);
earlyterm_horizontal_update(&earlyterm);
}
// Display vram
screen_update(earlyterm.display.vram);
// End of variodic args.
va_end(ap);
// Atomic stop
atomic_stop();
}