140 lines
3.3 KiB
C
140 lines
3.3 KiB
C
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include "stdio.h"
|
|
#include "debug.h"
|
|
#include "video/render.h"
|
|
#include "arch/x86_64/e9.h"
|
|
#include "mp/spinlock.h"
|
|
|
|
static const uint32_t g_LogSeverityColors[] =
|
|
{
|
|
[LVL_DEBUG] = 0xAAAAAA, // light gray
|
|
[LVL_INFO] = 0xFFFFFF, // white
|
|
[LVL_WARN] = 0xFFFF00, // yellow
|
|
[LVL_ERROR] = 0xFF0000, // red
|
|
[LVL_CRITICAL] = 0xFFFFFF, // white (can do red background separately if you want)
|
|
};
|
|
|
|
static spinlock_t s_printf_lock = SPINLOCK_INIT;
|
|
|
|
|
|
|
|
void fputc(char c)
|
|
{
|
|
putchar(c);
|
|
e9_putc(c);
|
|
}
|
|
|
|
void fputs(const char* str)
|
|
{
|
|
const char* s = str;
|
|
while (*s) fputc(*s++);
|
|
}
|
|
|
|
void fputs_colored(const char* str, uint32_t color) {
|
|
while (*str) putchar_colored(*str++, color);
|
|
while (*str) fputc(*str++);
|
|
}
|
|
|
|
const char g_HexChars[] = "0123456789abcdef";
|
|
|
|
void fprintf_unsigned(uint64_t number, int radix)
|
|
{
|
|
char buffer[32];
|
|
int pos = 0;
|
|
|
|
do {
|
|
buffer[pos++] = g_HexChars[number % radix];
|
|
number /= radix;
|
|
} while (number > 0);
|
|
|
|
while (--pos >= 0) fputc(buffer[pos]);
|
|
}
|
|
|
|
void fprintf_signed(int64_t number, int radix)
|
|
{
|
|
if (number < 0) {
|
|
fputc('-');
|
|
fprintf_unsigned(-number, radix);
|
|
} else {
|
|
fprintf_unsigned(number, radix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void vfprintf(const char* fmt, va_list args)
|
|
{
|
|
int state = 0; // normal
|
|
int length = 0; // default
|
|
int radix = 10;
|
|
bool sign = false;
|
|
bool number = false;
|
|
|
|
while (*fmt) {
|
|
switch (state) {
|
|
case 0: // normal
|
|
if (*fmt == '%') state = 1;
|
|
else fputc(*fmt);
|
|
break;
|
|
|
|
case 1: // length
|
|
if (*fmt == 'l') { length = 3; state = 4; }
|
|
else if (*fmt == 'h') { length = 2; state = 4; }
|
|
else goto spec;
|
|
break;
|
|
|
|
case 4: // spec
|
|
spec:
|
|
switch (*fmt) {
|
|
case 'c': fputc((char)va_arg(args,int)); break;
|
|
case 's': fputs(va_arg(args,const char*)); break;
|
|
case 'd':
|
|
case 'i': sign = true; number = true; radix = 10; break;
|
|
case 'u': sign = false; number = true; radix = 10; break;
|
|
case 'x':
|
|
case 'X': sign = false; number = true; radix = 16; break;
|
|
case 'p': number = true; sign = false; radix = 16; break;
|
|
case 'o': sign = false; number = true; radix = 8; break;
|
|
case '%': fputc('%'); break;
|
|
}
|
|
|
|
if (number) {
|
|
if (sign) fprintf_signed(va_arg(args,long), radix);
|
|
else fprintf_unsigned(va_arg(args,unsigned long), radix);
|
|
}
|
|
|
|
state = 0;
|
|
length = 0;
|
|
number = false;
|
|
sign = false;
|
|
break;
|
|
}
|
|
|
|
fmt++;
|
|
}
|
|
}
|
|
|
|
void printf(const char* fmt, ...)
|
|
{
|
|
uint64_t flags;
|
|
spinlock_acquire_irqsave(&s_printf_lock, &flags);
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
vfprintf(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
spinlock_release_irqrestore(&s_printf_lock, flags);
|
|
}
|
|
|
|
void fprintf(const char* fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(fmt, args);
|
|
va_end(args);
|
|
}
|