Files
Espresso/lib/printf.c

424 lines
7.1 KiB
C
Raw Normal View History

2025-05-28 14:41:02 -05:00
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
2025-10-20 21:57:30 -05:00
#include <drivers/serio.h>
2025-05-28 14:41:02 -05:00
#include <printf.h>
2025-10-20 21:57:30 -05:00
static uint8_t color = 0xFF;
2025-05-28 14:41:02 -05:00
void printwc(const char* str, uint8_t color)
{
uint8_t c = terminal_getcolor();
2025-10-20 21:57:30 -05:00
2025-05-28 14:41:02 -05:00
terminal_setcolor(color);
2025-10-20 21:57:30 -05:00
2025-05-28 14:41:02 -05:00
printf(str);
2025-10-20 21:57:30 -05:00
2025-05-28 14:41:02 -05:00
terminal_setcolor(c);
}
void printd(const char* str)
{
terminal_debug_writestring(str);
2025-10-20 21:57:30 -05:00
serial_puts("[ DEBUG ] ");
serial_puts(str);
2025-05-28 14:41:02 -05:00
}
void printdc(const char* str, uint8_t color)
{
uint8_t c = terminal_getcolor();
terminal_setcolor(color);
2025-10-20 21:57:30 -05:00
2025-05-28 14:41:02 -05:00
printd(str);
2025-10-20 21:57:30 -05:00
2025-05-28 14:41:02 -05:00
terminal_setcolor(c);
}
2025-10-20 21:57:30 -05:00
void printf_set_color(uint8_t _color)
{
if (_color == 0xFF)
{
return;
}
color = _color;
}
2025-07-04 14:23:29 -05:00
void printf(const char* format, ...)
{
2025-10-20 21:57:30 -05:00
va_list args;
va_start(args, format);
if (color != 0xFF)
{
terminal_setcolor(color);
}
for (size_t i = 0; format[i] != '\0'; ++i)
{
if (format[i] == '%' && format[i + 1] != '\0')
{
++i;
int width = 0;
if (format[i] == '0')
{
++i;
while (format[i] >= '0' && format[i] <= '9')
{
width = width * 10 + (format[i] - '0');
++i;
}
}
bool is_ll = false;
if (format[i] == 'l' && format[i + 1] == 'l')
{
is_ll = true;
i += 2;
}
switch (format[i])
{
case 's': {
const char* str = va_arg(args, const char*);
terminal_writestring(str ? str : "(null)");
if (use_serial())
{
serial_puts(str ? str : "(null)");
}
break;
2025-05-28 14:41:02 -05:00
}
2025-10-20 21:57:30 -05:00
case 'c': {
char c = (char) va_arg(args, int);
terminal_putchar(c);
if (use_serial())
{
serial_write(c);
}
break;
}
case 'd':
case 'i': {
if (is_ll)
{
int64_t val = va_arg(args, int64_t);
print_lint(val);
}
else
{
int32_t val = va_arg(args, int32_t);
print_int(val);
}
break;
}
case 'u': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_luint(val);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_uint(val);
}
break;
}
case 'x': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, false);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, false);
}
break;
}
case 'X': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, true);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, true);
}
break;
}
case 'p': {
void* ptr = va_arg(args, void*);
terminal_writestring("0x");
if (use_serial())
{
serial_write('0');
serial_write('x');
}
print_hex((uint32_t)(uintptr_t)ptr, 8, true);
break;
}
case 'f':
case 'F': {
double val = va_arg(args, double);
print_double(val, 2);
break;
}
case '%': {
terminal_putchar('%');
if (use_serial())
{
serial_write('%');
}
break;
}
default: {
terminal_putchar('%');
terminal_putchar(format[i]);
if (use_serial())
{
serial_write('%');
serial_write(format[i]);
}
break;
}
}
}
else
{
terminal_putchar(format[i]);
if (use_serial())
{
serial_write(format[i]);
}
2025-05-28 14:41:02 -05:00
}
2025-10-20 21:57:30 -05:00
}
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
va_end(args);
2025-05-28 14:41:02 -05:00
}
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
void print_int(int32_t value)
{
char buffer[12];
int i = 0;
uint32_t u;
if (value < 0)
{
terminal_putchar('-');
if (use_serial())
{
serial_write('-');
}
u = (uint32_t)(-value);
}
else
{
u = (uint32_t)value;
}
do
{
buffer[i++] = '0' + (u % 10);
u /= 10;
} while (u > 0);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
void print_lint(int64_t value)
{
char buffer[21];
int i = 0;
uint64_t u;
if (value < 0)
{
terminal_putchar('-');
if (use_serial())
{
serial_write('-');
2025-06-13 18:03:39 -05:00
}
2025-10-20 21:57:30 -05:00
u = (uint64_t) (-value);
}
else
{
u = (uint64_t) value;
}
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
do
{
buffer[i++] = '0' + (u % 10);
u /= 10;
} while (u > 0);
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
2025-06-13 18:03:39 -05:00
}
2025-10-20 21:57:30 -05:00
}
2025-06-13 18:03:39 -05:00
}
void print_hex(uint32_t value, int width, bool uppercase)
{
2025-10-20 21:57:30 -05:00
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
char buffer[9]; // 8 hex digits max for 32-bit
int i = 0;
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
do
{
buffer[i++] = hex_chars[value & 0xF];
value >>= 4;
} while (value || i < width); // ensure at least 'width' digits
2025-06-13 18:03:39 -05:00
2025-10-20 21:57:30 -05:00
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
2025-06-13 18:03:39 -05:00
}
2025-10-20 21:57:30 -05:00
}
2025-06-13 18:03:39 -05:00
}
2025-05-28 14:41:02 -05:00
void print_double(double value, int precision)
{
2025-10-20 21:57:30 -05:00
// Handle the integer part
int32_t integer_part = (int32_t)value;
double fractional_part = value - integer_part;
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
// Print the integer part
print_int(integer_part);
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
// Print the decimal point
terminal_putchar('.');
if (use_serial())
{
serial_write('.');
}
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
// Print the fractional part (scaled up)
fractional_part *= 1;
for (int i = 0; i < precision; i++)
{
fractional_part *= 10;
}
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
int32_t frac_int = (int32_t)fractional_part;
print_int(frac_int);
2025-05-28 14:41:02 -05:00
}
2025-10-20 21:57:30 -05:00
void print_uint(uint32_t value)
{
char buffer[11];
int i = 0;
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
do
{
buffer[i++] = '0' + (value % 10);
value /= 10;
} while (value > 0);
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
2025-05-28 14:41:02 -05:00
}
2025-10-20 21:57:30 -05:00
}
2025-05-28 14:41:02 -05:00
}
2025-10-20 21:57:30 -05:00
void print_luint(uint64_t value)
{
char buffer[21];
int i = 0;
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
do
{
buffer[i++] = '0' + (value % 10);
value /= 10;
} while (value > 0);
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
2025-05-28 14:41:02 -05:00
2025-10-20 21:57:30 -05:00
void print_hex64(uint64_t value, int width, bool uppercase)
{
char buffer[17] = {0};
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
int i = 0;
do
{
buffer[i++] = digits[value % 16];
value /= 16;
} while (value > 0);
while (i < width)
{
buffer[i++] = '0';
}
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
2025-05-28 14:41:02 -05:00
}
2025-06-13 18:03:39 -05:00