hippOS/std/kstd.c

127 lines
3.3 KiB
C

#include <stdarg.h>
#include <limits.h>
#include "std/kstd.h"
#include "std/std.h"
#include "gfx/terminal.h"
int putchar(int ic) {
char c = (char) ic;
terminal_write(&c, sizeof(c));
return ic;
}
static bool print(const char* data, size_t length) {
const unsigned char* bytes = (const unsigned char*) data;
for (size_t i = 0; i < length; i++) {
if (putchar(bytes[i]) == (-1)) { // EOF??
return false;
}
}
return true;
}
// https://wiki.osdev.org/Meaty_Skeleton
int kprintf(const char* restrict format, ...) {
va_list parameters;
va_start(parameters, format);
int written = 0;
while (*format != '\0') {
size_t maxrem = INT_MAX - written;
if (format[0] != '%' || format[1] == '%') {
if (format[0] == '%')
format++;
size_t amount = 1;
while (format[amount] && format[amount] != '%')
amount++;
if (maxrem < amount) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, amount))
return -1;
format += amount;
written += amount;
continue;
}
const char* format_begun_at = format++;
if (*format == 'c') {
format++;
char c = (char) va_arg(parameters, int /* char promotes to int */);
if (!maxrem) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(&c, sizeof(c)))
return -1;
written++;
} else if (*format == 's') {
format++;
const char* str = va_arg(parameters, const char*);
size_t len = strlen(str);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(str, len))
return -1;
written += len;
} else if (*format == 'd') {
format++;
int val = va_arg(parameters, int);
int base = 10;
char *str;
// note: flawed implementation
// based on: https://www.strudel.org.uk/itoa/
if (val == 0) {
str = "0\0";
} else {
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base) {
buf[i] = "0123456789abcdef"[val % base];
}
str = &buf[i+1];
}
size_t len = strlen(str);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
print(str, len);
written += len;
} else {
format = format_begun_at;
size_t len = strlen(format);
if (maxrem < len) {
// TODO: Set errno to EOVERFLOW.
return -1;
}
if (!print(format, len))
return -1;
written += len;
format += len;
}
}
va_end(parameters);
return written;
}
void kputs(const char* data) {
kprintf("%s\n", data);
}
void kabort() {
kprintf("kabort(): halting kernel...\n");
asm volatile("cli");
asm volatile("hlt");
while (1) {}
__builtin_unreachable();
}