diff --git a/Makefile b/Makefile index 2ad7c66..508d1f4 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ $(BUILD_DIR)/%.asm.o: $(SRC_DIR)/%.asm $(BUILD_DIR)/%.c.o: $(SRC_DIR)/%.c @mkdir -p "$(@D)" - $(CC) -c $< -o $@ -I$(INCLUDE_DIR) -std=gnu99 -ffreestanding -O2 -Wall -Wextra + $(CC) -c $< -o $@ -I$(INCLUDE_DIR) -std=gnu99 -ffreestanding -O2 -Wall -Wextra -Wformat clean: rm -rf $(BUILD_DIR)/* diff --git a/src/kernel/include/internal/text_screen.h b/src/kernel/include/internal/text_screen.h index feed931..2a0d209 100644 --- a/src/kernel/include/internal/text_screen.h +++ b/src/kernel/include/internal/text_screen.h @@ -36,4 +36,7 @@ void tsinit(void); void tsputch(char ch, uint8_t color); void tsputs(const char* str, uint8_t color); +void tsprintf(const char* format, ...) + __attribute__((format (printf, 1, 2))); + #endif // _CLIPPER_TEXT_SCREEN_H_ diff --git a/src/kernel/kmain.c b/src/kernel/kmain.c index 58dd5d6..9ca34e1 100644 --- a/src/kernel/kmain.c +++ b/src/kernel/kmain.c @@ -16,8 +16,10 @@ void kmain(void) { tsinit(); - const char* msg = "Clipper set sail!\n~~~~~~~~~~~~~~~~~"; + const char* msg = "Clipper set sail!\n~~~~~~~~~~~~~~~~~\n"; tsputs(msg, TEXT_SCREEN_BG_BLACK | TEXT_SCREEN_FG_LIGHT_CYAN); + tsprintf("Test | Integers: %d, Unsigned: %u, Hexadecimal: %x\n", -48, 28493, 28493); + return; } diff --git a/src/kernel/lib/text_screen.c b/src/kernel/lib/text_screen.c index 1150263..6481ae9 100644 --- a/src/kernel/lib/text_screen.c +++ b/src/kernel/lib/text_screen.c @@ -1,5 +1,8 @@ #include "internal/text_screen.h" + +#include #include "internal/io.h" +#include "stdlib.h" struct text_screen_char { char character; @@ -13,6 +16,13 @@ static uint8_t cursor_y = 0; #define SCREEN_WIDTH 80 #define SCREEN_HEIGHT 25 +enum printf_format_specifier { + FORMAT_SPECIFIER_INT, + FORMAT_SPECIFIER_UNSIGNED, + FORMAT_SPECIFIER_HEXADECIMAL, + FORMAT_SPEFICIER_UNKNOWN +}; + void tsinit(void) { outb(0x3D4, 0x0A); outb(0x3D5, 0x20); @@ -23,7 +33,8 @@ void tsputch(char ch, uint8_t color) { tsputs(tmp, color); } -static void handle_special_char(char c) { +static +void handle_special_char(char c) { switch (c) { case '\n': { cursor_x = 0; @@ -66,3 +77,93 @@ void tsputs(const char* ch, uint8_t color) { } } } + +static +const char* decode_format_spefifier(const char* str, enum printf_format_specifier* data) { + switch (*str) { + case 'd': + case 'i': + *data = FORMAT_SPECIFIER_INT; + return str+1; + + case 'o': + case 'u': + *data = FORMAT_SPECIFIER_UNSIGNED; + return str+1; + + case 'x': + case 'X': + *data = FORMAT_SPECIFIER_HEXADECIMAL; + return str+1; + } + + *data = FORMAT_SPEFICIER_UNKNOWN; + return str; +} + +static +const char* handle_format_specifier(const char* str, va_list* args) { + str++; + char tmp[16]; + + enum printf_format_specifier specifier; + str = decode_format_spefifier(str, &specifier); + switch (specifier) { + case FORMAT_SPECIFIER_INT: { + int value = va_arg(*args, int); + tsputs(itoa(value, tmp, 10), TEXT_SCREEN_BG_BLACK | TEXT_SCREEN_FG_WHITE); + } break; + + case FORMAT_SPECIFIER_UNSIGNED: { + unsigned int value = va_arg(*args, unsigned int); + tsputs(utoa(value, tmp, 10), TEXT_SCREEN_BG_BLACK | TEXT_SCREEN_FG_WHITE); + } break; + + + case FORMAT_SPECIFIER_HEXADECIMAL: { + unsigned int value = va_arg(*args, unsigned int); + tsputs(utoa(value, tmp, 16), TEXT_SCREEN_BG_BLACK | TEXT_SCREEN_FG_WHITE); + } break; + default: return str; + } + + return str-1; +} + +void tsprintf(const char* format, ...) { + struct text_screen_char tsch = { + .character = '\0', + .attribute = TEXT_SCREEN_BG_BLACK | TEXT_SCREEN_FG_GRAY + }; + + va_list args; + va_start(args, format); + + for (const char* c = format; *c != '\0'; c++) { + if (*c == '%') { + c = handle_format_specifier(c, &args); + continue; + } + + if ((uint8_t)(*c) < 0x20) { + handle_special_char(*c); + continue; + } + + tsch.character = *c; + + videomem[cursor_y * SCREEN_WIDTH + cursor_x] = tsch; + + cursor_x++; + if (cursor_x >= SCREEN_WIDTH) { + cursor_y++; + cursor_x = 0; + + if (cursor_y >= SCREEN_HEIGHT) { + cursor_y = 0; + } + } + } + + va_end(args); +}