Additional printf formats

This commit is contained in:
FyloZ 2026-02-22 22:50:35 -05:00
parent 8ccf823c67
commit d3991147c7
2 changed files with 83 additions and 1 deletions

View File

@ -7,7 +7,7 @@
void kmain(void) {
uart_init();
print("Hello world, %s!\n", ARCH);
print("Hello world, %x!\n", 0xff);
power_off();
}

View File

@ -1,6 +1,8 @@
#include <stdint.h>
#include "../../uart.h"
#include <limits.h>
// QEMU emulates the NS16550A UART
// The UART is memory mapped at 0x1000000
#define UART_ADDR 0x10000000
@ -36,9 +38,16 @@ void uart_puts(const char *line) {
uart_putchar('\n');
}
#define DIGIT_TO_STR(digit) ('0' + (digit))
#define DIGIT_TO_HEX(digit) ('0' + (digit) + ((digit < 10 ? 0 : 'a' - '0' - 10)))
// Basic implementation of printf supporting the following formats:
// - c: Character
// - s: String of characters
// - d, i: Signed integer
// - u: Unsigned integer
// - x: Unsigned hexadecimal
// - p: Pointer address
// - %: Literal '%'
void uart_vprintf(const char *restrict format, va_list args) {
while (*format) {
@ -57,6 +66,79 @@ void uart_vprintf(const char *restrict format, va_list args) {
case 's': // String
uart_print(va_arg(args, char*));
break;
case 'd':
case 'i': {
// TODO: This implementation breaks when the number starts with '0'. Check when debugging is possible?
int num = va_arg(args, int);
if (num == INT_MIN) {
uart_print("-2147483648");
break;
}
if (num < 0) {
uart_putchar('-');
num = -num;
}
const char lsh = DIGIT_TO_STR(num % 10);
num /= 10;
// Convert the number into a buffer of characters
// The buffer will be reversed (the last digit will be first)
char buf[9]; // There can't be more than 10 digits in an integer, -1 because of lsh
char *buf_ptr = buf;
while (num > 0) {
*buf_ptr++ = DIGIT_TO_STR(num % 10);
num /= 10;
}
// Print the characters in correct order
while (buf_ptr != buf) {
uart_putchar(*--buf_ptr);
}
uart_putchar(lsh);
}
break;
case 'u': {
// Similar as the signed variant, without support for negatives
unsigned int num = va_arg(args, unsigned int);
const char lsh = DIGIT_TO_STR(num % 10);
num /= 10;
char buf[9];
char *buf_ptr = buf;
while (num > 0) {
*buf_ptr++ = DIGIT_TO_STR(num % 10);
num /= 10;
}
while (buf_ptr != buf) {
uart_putchar(*--buf_ptr);
}
uart_putchar(lsh);
}
break;
case 'p':
uart_print("0x");
case 'x': {
unsigned int num = va_arg(args, unsigned int);
const char lsh = DIGIT_TO_HEX(num % 16);
num /= 16;
char buf[7];
char *buf_ptr = buf;
while (num > 0) {
*buf_ptr++ = DIGIT_TO_HEX(num % 16);
num /= 16;
}
while (buf_ptr != buf) {
uart_putchar(*--buf_ptr);
}
uart_putchar(lsh);
}
break;
case '%': // Literal '%'
uart_putchar('%');
break;