Newer
Older
tree-os / src / kernel / lib / textMode / stdio.c
#include <stdarg.h>
#include <stdint.h>
#include <lib/textMode/stdio.h>
#include <lib/ports.h>
#include <lib/textMode/cursor.h>
#include <lib/task/message.h>
#include <lib/task/task.h>
#include <lib/task/osTasks.h>
#include <lib/memory/alloc.h>

uint16_t* framebuffer = (uint16_t*) FRAMEBUFFER_LOCATION;
char format = 0x0F;

void putCharWithFormatAtOffset(uint16_t c, uint16_t position) {
    *(framebuffer + position) = c;
}

void putCharWithFormatAtPosition(uint8_t x, uint8_t y, uint32_t c) {
    putCharWithFormatAtOffset(c, (x + y * VIDEO_WIDTH));
}

void putCharAtOffset(char c, uint16_t offset) {
    putCharWithFormatAtOffset(c | format << 8, offset);
}

void putCharAt(char c, uint8_t x, uint8_t y) {
    putCharAtOffset(c, (x + y * VIDEO_WIDTH));
}

uint16_t getCharWithFormatAt(uint8_t x, uint8_t y) {
    return *(framebuffer + x + y * VIDEO_WIDTH);
}

void putCharsAt(char* string, uint8_t x, uint8_t y) {
    uint16_t position = 0;
    char c = *string;
    while (c != 0x00) {
        putCharAt(c, x + position, y);
        position++;
        c = *(string + position);
    }
}

void shiftUp() {
    for (int y = 1; y < VIDEO_HEIGHT; y++) {
        for (int x = 0; x < VIDEO_WIDTH; x++) {
            putCharWithFormatAtPosition(x, y-1, getCharWithFormatAt(x, y));
        }
    }
    for (int x = 0; x < VIDEO_WIDTH; x++) {
        putCharWithFormatAtPosition(x, VIDEO_HEIGHT-1, 0x00);
    }
}

void newLine() {
    uint16_t offset = getCursorOffset();
    uint8_t x = offset % VIDEO_WIDTH;
    uint8_t y = offset / VIDEO_WIDTH;
    x = 0;
    y++;
    if (y >= VIDEO_HEIGHT) {
        shiftUp();
        y--;
    }
    setCursorPosition(x, y);
}

void putChar(char c) {
    if (c == '\n') {
        newLine();
        return;
    }
    uint16_t offset = getCursorOffset();
    putCharAtOffset(c, offset);
    setCursorOffset(offset + 1);
}

void puts(char* string) {
    while (*string != 0x00) {
        putChar(*string);
        string++;
    }
}

char HEX_PREFIX[] = "0x";
char HEX_CHARS[] = "0123456789ABCDEF";

void putHex(char** write, uint32_t x) {
    uint8_t alreadyWriting = 0;
    for (uint8_t position = 3; position >= 0; position--) {
        uint8_t byte = (x >> (position * 8)) & 0xFF;
        if (byte != 0x00) {
            alreadyWriting = 0x01;
        }
        if (alreadyWriting) {
            **write = HEX_CHARS[byte % 256];
            *write++;
            **write = HEX_CHARS[byte / 256];
            *write++;
        }
    }
}

uint32_t getInsertLength(char insertType, uint32_t x) {
    switch (insertType)
    {
    case 's':
        return strlen((char*) x);
    case 'x':
        for (uint8_t position = 3; position >= 0; position--) {
            uint8_t byte = (x >> (position * 8)) & 0xFF;
            if (byte != 0x00) {
                return 2*position;
            }
        }
        return 0;
    }
    return 0;
}

void handleInsert(char** write, char insertType, uint32_t x) {
    if (insertType == 's') {
        char* string = (char*) x;
        uint32_t length = strlen(string);
        for (uint32_t position = 0; position < length; position++) {
            **write = string[position];
            *write++;
        }
        return;
    }
    if (insertType == 'x') {
        putHex(write, x);
    }
}

void printf(const char* format, ...) {
    uint32_t size = 0;
    va_list valist;
    va_start(valist, format);
    for (int i = 0; format[i] != 0; i++) {
        if (format[i] == '%') {
            size += getInsertLength(format[++i], va_arg(valist, uint32_t));
            continue;
        }
        size++;
    }
    va_start(valist, format);

    char* data = malloc(size);
    char* write = data;    
    for (int i = 0; format[i] != 0; i++) {
        if (format[i] == '%') {
            handleInsert(&write, format[++i], va_arg(valist, uint32_t));
            continue;
        }
        *write = format[i];
        write++;
    }
    va_end(valist);
    
    Message message = {
        message.data = data,
        message.size = size,
        message.next = 0x00
    };
    sendMessage(getPrinterTask(), &message);
    schedule(getPrinterTask());
    yields();
}

void clearScreen() {
    setCursorOffset(0);
    for (int y = 0; y < VIDEO_HEIGHT; y++) {
        for (int x = 0; x < VIDEO_WIDTH; x++) {
            putCharAt(' ', x, y);
        }
    }
}

void setTextStyle(uint8_t style) {
    format = style;
}

void putChars(char* string, uint32_t length) {
    for (uint32_t i = 0; i < length; i++) {
        if (string[i] == '\n') {
            newLine();
            continue;
        }
        putChar(string[i]);
    }
}

uint32_t strlen(char* string) {
    uint32_t length = 0;
    while (string[length] != 0) {
        length++;
    }
    return length;
}