197 lines
5.6 KiB
C
197 lines
5.6 KiB
C
#include "console.h"
|
|
#include <string.h>
|
|
|
|
#define ROWS 25
|
|
#define COLUMNS 80
|
|
|
|
typedef struct {
|
|
u8 character;
|
|
u8 color;
|
|
} vga_char_t;
|
|
|
|
static vga_char_t *vga_buffer = (vga_char_t *)0xb8000;
|
|
static u8 cursor_row = 0;
|
|
static u8 cursor_col = 0;
|
|
|
|
void console_putchar(char c, u8 color) {
|
|
switch (c) {
|
|
case '\n': {
|
|
cursor_row += 1;
|
|
cursor_col = 0;
|
|
break;
|
|
}
|
|
case '\r': {
|
|
cursor_col = 0;
|
|
break;
|
|
}
|
|
case '\t': {
|
|
u8 remainder = 4 - (cursor_col % 4);
|
|
cursor_col += remainder;
|
|
break;
|
|
}
|
|
case '\b': {
|
|
if (cursor_col > 0) {
|
|
cursor_col -= 1;
|
|
} else if (cursor_row > 0) {
|
|
cursor_row -= 1;
|
|
|
|
cursor_col = 0;
|
|
for (int col = COLUMNS - 1; col >= 0; col--) {
|
|
vga_char_t cell = vga_buffer[cursor_row * COLUMNS + col];
|
|
if (cell.character != ' ') {
|
|
cursor_col = col;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
vga_buffer[cursor_row * COLUMNS + cursor_col] = (vga_char_t){
|
|
.character = ' ',
|
|
.color = VGA_DEFAULT_COLOR,
|
|
};
|
|
break;
|
|
}
|
|
default: {
|
|
vga_buffer[COLUMNS * cursor_row + cursor_col] = (vga_char_t){
|
|
.character = c,
|
|
.color = color,
|
|
};
|
|
cursor_col += 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cursor_col >= COLUMNS) {
|
|
cursor_col = 0;
|
|
cursor_row += 1;
|
|
}
|
|
|
|
if (cursor_row >= ROWS) {
|
|
for (size_t row = 1; row < ROWS; row++) {
|
|
for (size_t col = 0; col < COLUMNS; col++) {
|
|
vga_buffer[COLUMNS * (row - 1) + col] = vga_buffer[COLUMNS * row + col];
|
|
}
|
|
}
|
|
|
|
for (size_t col = 0; col < COLUMNS; col++) {
|
|
vga_buffer[COLUMNS * (ROWS - 1) + col] = (vga_char_t){
|
|
.character = ' ',
|
|
.color = VGA_DEFAULT_COLOR,
|
|
};
|
|
};
|
|
|
|
cursor_row = ROWS - 1;
|
|
}
|
|
}
|
|
|
|
void console_clear() {
|
|
for (size_t row = 0; row < ROWS; row++) {
|
|
for (size_t col = 0; col < COLUMNS; col++) {
|
|
vga_buffer[COLUMNS * row + col] = (vga_char_t){
|
|
.character = ' ',
|
|
.color = VGA_DEFAULT_COLOR,
|
|
};
|
|
}
|
|
}
|
|
|
|
cursor_row = 0;
|
|
cursor_col = 0;
|
|
}
|
|
|
|
// Supported formats:
|
|
// - `d`: i32 (decimal)
|
|
// - `u`: u32 (decimal)
|
|
// - `x`: u32 (hex)
|
|
// - `c`: char (ascii)
|
|
// - `s`: char* (ascii string)
|
|
void kvprintf(const char *fmt, va_list args) {
|
|
bool should_format = false;
|
|
|
|
for (size_t i = 0; fmt[i] != '\0'; i++) {
|
|
if (should_format) {
|
|
should_format = false;
|
|
|
|
if (fmt[i] == '%') {
|
|
console_putchar('%', VGA_DEFAULT_COLOR);
|
|
} else if (fmt[i] == 's') {
|
|
const char *str = va_arg(args, const char *);
|
|
for (size_t j = 0; str[j] != '\0'; j++) {
|
|
console_putchar(str[j], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == 'c') {
|
|
char character = (char)va_arg(args, u32);
|
|
console_putchar(character, VGA_DEFAULT_COLOR);
|
|
} else if (fmt[i] == 'd') {
|
|
u32 val = va_arg(args, u32);
|
|
char buf[ITOA32_BUFSIZE];
|
|
itoa32(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == 'u') {
|
|
u32 val = va_arg(args, u32);
|
|
char buf[UITOA32_BUFSIZE];
|
|
uitoa32(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == 'x') {
|
|
u32 val = va_arg(args, u32);
|
|
char buf[UITOA32_HEX_BUFSIZE];
|
|
uitoa32_hex(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == 'D') {
|
|
i64 val = va_arg(args, i64);
|
|
char buf[ITOA64_BUFSIZE];
|
|
itoa64(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == 'U') {
|
|
u64 val = va_arg(args, u64);
|
|
char buf[UITOA64_BUFSIZE];
|
|
uitoa64(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++)
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
|
|
} else if (fmt[i] == 'X') {
|
|
u64 val = va_arg(args, u64);
|
|
char buf[UITOA64_HEX_BUFSIZE];
|
|
uitoa64_hex(val, buf);
|
|
for (size_t j = 0; buf[j] != '\0'; j++)
|
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
|
|
|
} else {
|
|
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
|
|
}
|
|
} else if (fmt[i] == '%') {
|
|
should_format = true;
|
|
} else {
|
|
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Supported formats:
|
|
// - `d`: i32 (decimal)
|
|
// - `u`: u32 (decimal)
|
|
// - `x`: u32 (hex)
|
|
// - `c`: char (ascii)
|
|
// - `s`: char* (ascii string)
|
|
//
|
|
// ```c
|
|
// printf(
|
|
// "The answer is %d is located at offset %x in file %s",
|
|
// 42,
|
|
// 0x2000
|
|
// "hitchhiker.txt"
|
|
// );
|
|
// ```
|
|
void kprintf(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
kvprintf(fmt, args);
|
|
va_end(args);
|
|
} |