#include #include #include "stdio.h" #include "debug.h" #include "video/render.h" #include "arch/x86_64/e9.h" #include "mp/spinlock.h" #include #include 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; typedef struct { char* buf; size_t size; size_t pos; } snprintf_ctx_t; static void buf_putc(snprintf_ctx_t* ctx, char c) { if (ctx->pos + 1 < ctx->size) { ctx->buf[ctx->pos] = c; } ctx->pos++; } static void buf_puts(snprintf_ctx_t* ctx, const char* str) { while (*str) { buf_putc(ctx, *str++); } } 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"; static void buf_print_unsigned(snprintf_ctx_t* ctx, uint64_t number, int radix, int width, int zero_pad) { char buffer[32]; int pos = 0; do { buffer[pos++] = g_HexChars[number % radix]; number /= radix; } while (number > 0); // Apply zero-padding / width if (zero_pad) { while (pos < width) buffer[pos++] = '0'; } while (--pos >= 0) buf_putc(ctx, buffer[pos]); } static void buf_print_signed(snprintf_ctx_t* ctx, int64_t number, int radix, int width, int zero_pad) { if (number < 0) { buf_putc(ctx, '-'); buf_print_unsigned(ctx, (uint64_t)(-number), radix, width, zero_pad); } else { buf_print_unsigned(ctx, (uint64_t)number, radix, width, zero_pad); } } int snprintf(char* buf, size_t size, const char* fmt, ...) { va_list args; va_start(args, fmt); int ret = vsnprintf(buf, size, fmt, args); va_end(args); return ret; } static void fprintf_unsigned(uint64_t number, int radix, int width, int zero_pad) { char buffer[32]; int pos = 0; do { buffer[pos++] = g_HexChars[number % radix]; number /= radix; } while (number > 0); if (zero_pad) { while (pos < width) buffer[pos++] = '0'; } while (--pos >= 0) fputc(buffer[pos]); } static void fprintf_signed(int64_t number, int radix, int width, int zero_pad) { if (number < 0) { fputc('-'); fprintf_unsigned((uint64_t)(-number), radix, width, zero_pad); } else { fprintf_unsigned((uint64_t)number, radix, width, zero_pad); } } void vfprintf(const char* fmt, va_list args) { while (*fmt) { if (*fmt != '%') { fputc(*fmt++); continue; } fmt++; // skip % /* flags */ int zero_pad = 0; if (*fmt == '0') { zero_pad = 1; fmt++; } /* width */ int width = 0; while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + (*fmt++ - '0'); } /* precision */ int precision = -1; if (*fmt == '.') { fmt++; precision = 0; while (*fmt >= '0' && *fmt <= '9') { precision = precision * 10 + (*fmt++ - '0'); } } /* length modifier */ int is_long_long = 0; if (*fmt == 'l') { fmt++; if (*fmt == 'l') { is_long_long = 1; fmt++; } } else if (*fmt == 'z') { // %zu, %zx is_long_long = 1; fmt++; } else if (*fmt == 'h') { fmt++; // ignore h/hh } /* specifier */ switch (*fmt++) { case 'c': fputc((char)va_arg(args, int)); break; case 's': { const char* s = va_arg(args, const char*); if (!s) s = "(null)"; if (precision >= 0) { while (*s && precision--) fputc(*s++); } else { fputs(s); } break; } case 'd': case 'i': if (is_long_long) fprintf_signed(va_arg(args, long long), 10, width, zero_pad); else fprintf_signed(va_arg(args, long), 10, width, zero_pad); break; case 'u': if (is_long_long) fprintf_unsigned(va_arg(args, unsigned long long), 10, width, zero_pad); else fprintf_unsigned(va_arg(args, unsigned long), 10, width, zero_pad); break; case 'x': case 'X': if (is_long_long) fprintf_unsigned(va_arg(args, unsigned long long), 16, width, zero_pad); else fprintf_unsigned(va_arg(args, unsigned long), 16, width, zero_pad); break; case 'p': fputs("0x"); fprintf_unsigned(va_arg(args, uint64_t), 16, 16, 1); // always full 64-bit break; case 'o': if (is_long_long) fprintf_unsigned(va_arg(args, unsigned long long), 8, width, zero_pad); else fprintf_unsigned(va_arg(args, unsigned long), 8, width, zero_pad); break; case '%': fputc('%'); break; default: fputc('%'); fputc(*(fmt - 1)); break; } } } int vsnprintf(char* buf, size_t size, const char* fmt, va_list args) { snprintf_ctx_t ctx = { .buf = buf, .size = size, .pos = 0 }; while (*fmt) { if (*fmt != '%') { buf_putc(&ctx, *fmt++); continue; } fmt++; int zero_pad = 0; if (*fmt == '0') { zero_pad = 1; fmt++; } int width = 0; while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + (*fmt++ - '0'); } int precision = -1; if (*fmt == '.') { fmt++; precision = 0; while (*fmt >= '0' && *fmt <= '9') { precision = precision * 10 + (*fmt++ - '0'); } } int is_long_long = 0; if (*fmt == 'l') { fmt++; if (*fmt == 'l') { is_long_long = 1; fmt++; } } else if (*fmt == 'z') { is_long_long = 1; fmt++; } else if (*fmt == 'h') { fmt++; } switch (*fmt++) { case 'c': buf_putc(&ctx, (char)va_arg(args, int)); break; case 's': { const char* s = va_arg(args, const char*); if (!s) s = "(null)"; int max = (precision >= 0) ? precision : INT_MAX; while (*s && max--) buf_putc(&ctx, *s++); break; } case 'd': case 'i': if (is_long_long) buf_print_signed(&ctx, va_arg(args, long long), 10, width, zero_pad); else buf_print_signed(&ctx, va_arg(args, long), 10, width, zero_pad); break; case 'u': if (is_long_long) buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 10, width, zero_pad); else buf_print_unsigned(&ctx, va_arg(args, unsigned long), 10, width, zero_pad); break; case 'x': case 'X': if (is_long_long) buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 16, width, zero_pad); else buf_print_unsigned(&ctx, va_arg(args, unsigned long), 16, width, zero_pad); break; case 'p': buf_puts(&ctx, "0x"); buf_print_unsigned(&ctx, va_arg(args, uint64_t), 16, 16, 1); break; case 'o': if (is_long_long) buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 8, width, zero_pad); else buf_print_unsigned(&ctx, va_arg(args, unsigned long), 8, width, zero_pad); break; case '%': buf_putc(&ctx, '%'); break; default: buf_putc(&ctx, '%'); buf_putc(&ctx, *(fmt - 1)); break; } } if (ctx.size > 0) { if (ctx.pos < ctx.size) ctx.buf[ctx.pos] = '\0'; else ctx.buf[ctx.size - 1] = '\0'; } return (int)ctx.pos; } 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); }