Espresso 0.0.2a
This commit is contained in:
505
lib/printf.c
505
lib/printf.c
@ -2,219 +2,422 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <drivers/serio.h>
|
||||
|
||||
#include <printf.h>
|
||||
|
||||
static uint8_t color = 0xFF;
|
||||
|
||||
void printwc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
|
||||
terminal_setcolor(color);
|
||||
|
||||
printf(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printd(const char* str)
|
||||
{
|
||||
terminal_debug_writestring(str);
|
||||
|
||||
serial_puts("[ DEBUG ] ");
|
||||
serial_puts(str);
|
||||
}
|
||||
|
||||
void printdc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
terminal_setcolor(color);
|
||||
|
||||
printd(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printf_set_color(uint8_t _color)
|
||||
{
|
||||
if (_color == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
color = _color;
|
||||
}
|
||||
|
||||
void printf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
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;
|
||||
for (size_t i = 0; format[i] != '\0'; ++i)
|
||||
{
|
||||
if (format[i] == '%' && format[i + 1] != '\0')
|
||||
{
|
||||
++i;
|
||||
|
||||
// Check for width (like %016llx)
|
||||
int width = 0;
|
||||
if (format[i] == '0') {
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9') {
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for 'll' prefix
|
||||
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)");
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char) va_arg(args, int);
|
||||
terminal_putchar(c);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int32_t val = va_arg(args, int32_t);
|
||||
print_int(val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
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");
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true); // assumes 32-bit pointer
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double val = va_arg(args, double);
|
||||
print_double(val, 2);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
terminal_putchar('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
terminal_putchar('%');
|
||||
terminal_putchar(format[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
terminal_putchar(format[i]);
|
||||
int width = 0;
|
||||
if (format[i] == '0')
|
||||
{
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9')
|
||||
{
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void print_int(int32_t value) {
|
||||
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
void print_int(int32_t value)
|
||||
{
|
||||
char buffer[12];
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
|
||||
if (value < 0) {
|
||||
terminal_putchar('-');
|
||||
u = (uint32_t)(-value);
|
||||
} else {
|
||||
u = (uint32_t)value;
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint32_t)(-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint32_t)value;
|
||||
}
|
||||
|
||||
// Convert to string in reverse
|
||||
do {
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
// Print in correct order
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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('-');
|
||||
}
|
||||
|
||||
u = (uint64_t) (-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint64_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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex(uint32_t value, int width, bool uppercase)
|
||||
{
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
do
|
||||
{
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_double(double value, int precision)
|
||||
{
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('.');
|
||||
}
|
||||
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++) {
|
||||
fractional_part *= 10;
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++)
|
||||
{
|
||||
fractional_part *= 10;
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value)
|
||||
{
|
||||
char buffer[11];
|
||||
int i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value) {
|
||||
char buffer[11]; // Enough for 32-bit unsigned int
|
||||
int i = 0;
|
||||
void print_luint(uint64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex64(uint64_t value, int width, bool uppercase) {
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
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);
|
||||
do
|
||||
{
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
|
||||
while (i < width)
|
||||
buffer[i++] = '0';
|
||||
while (i < width)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
}
|
||||
|
||||
while (i--)
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user