chore(libterm/stdio): printf reworked, vsnprintf() and snprintf()

This commit is contained in:
Karina
2026-01-30 20:22:45 +04:00
parent 52d0bfeaae
commit e323e91dac
5 changed files with 115 additions and 57 deletions
+8 -4
View File
@@ -23,12 +23,11 @@
### v0.5.4 (The Shell Update)
*Focus: Interactive Userspace*
- [ ] **Userspace Shell (`termosh`)**
- [x] **Userspace Shell (`termosh`)**
- Porting `ksh` logic into a standalone `.hot` binary.
- Standard I/O abstraction (stdin/stdout) to pass keyboard input to active process.
- [ ] **Basic Utils**
- `ls`, `cat`, `echo`, `ver` as standalone programs.
- Remove built-in commands from the kernel.
- [ ] ~~**Basic Utils** (`ls`, `cat`, `echo`)~~ *(Moved to v0.6.1 — awaiting Apple-style API)*
---
@@ -36,6 +35,11 @@
*Goal: Total independence from external libraries and architectural hygiene.*
### v0.6.0 (Architecture Overhaul)
- [ ] **System-wide Naming & API Refactoring (Apple-style)**
- Replace generic types with PascalCase branding (`u64` -> `UInt64`, `i32` -> `Int32`).
- Standardize system prefixes: `VM` for Virtual Memory, `OS` for Core, `CPU` for HAL.
- Transition from `snake_case` to `PascalCase` for all kernel functions and structures.
- Implement `OSReturn` status codes for unified error handling.
- [ ] **Bootloader Independence**
- Remove `posix-uefi` library.
- Write custom UEFI entry point (pure PE).
+6 -4
View File
@@ -2,11 +2,13 @@
// Copyright (c) 2026 0xKarinyash
#include <process.h>
#include <stdio.h>
#include <malloc.h>
// TODO: read .cfg and spawn what stated there
int main() {
wait(spawn("/bin/termosh")); // TODO: read .cfg and spawn what stated there
printf("\nbaiii");
return 0;
while (1) {
i32 pid = spawn("/bin/termosh");
if (pid < 0) return pid;
wait(pid);
}
}
+2 -1
View File
@@ -4,7 +4,8 @@
#pragma once
#include <types.h>
void printf(const char *fmt, ...);
int printf(const char *fmt, ...);
int snprintf(char* str, u64 size, const char* fmt, ...);
int getchar();
char* gets(char* str);
char* gets_s(char* str, u64 size);
+94 -47
View File
@@ -7,6 +7,7 @@
#include <string.h>
#define EOF (-1)
#define PRINTF_BUFFER_SIZE 1024
extern u64 sys_read(u64 fd, void* buf, u64 len);
extern u64 sys_write(u64 fd, const void* buf, u64 len);
@@ -15,65 +16,111 @@ static void putchar(char c) {
sys_write(1, &c, 1);
}
static void print_str(const char* str) {
if (!str) str = "(null)";
sys_write(1, str, strlen(str));
}
static void print_dec(long long n) {
if (n < 0) {
putchar('-');
n = -n;
static inline void buf_add(char* str, u64 size, u64* written, char c) {
if (*written < size - 1 && size > 0) {
str[*written] = c;
}
unsigned long long u = (unsigned long long)n;
char buffer[32];
int i = 0;
do {
buffer[i++] = (u % 10) + '0';
u /= 10;
} while (u > 0);
while (--i >= 0) putchar(buffer[i]);
(*written)++;
}
static void print_hex(unsigned long long u, int padding) {
char buffer[16];
int i = 0;
const char* hex_chars = "0123456789ABCDEF";
int vsnprintf(char* str, u64 size, const char* fmt, va_list args) {
u64 written = 0;
for (u32 i = 0; fmt[i] != '\0'; i++) {
if (fmt[i] == '%') {
i++;
if (fmt[i] == '\0') break;
switch (fmt[i]) {
case 's': {
const char* s = va_arg(args, const char*);
if (!s) s = "(null)";
while (*s) buf_add(str, size, &written, *s++);
break;
}
case 'c': {
char c = (char)va_arg(args, int);
buf_add(str, size, &written, c);
break;
}
case 'd': {
i64 n = va_arg(args, int);
if (n < 0) {
buf_add(str, size, &written, '-');
n = -n;
}
u64 u = (u64)n;
char tmp[32];
i32 pos = 0;
if (u == 0) tmp[pos++] = '0';
while (u > 0) {
tmp[pos++] = (u % 10) + '0';
u /= 10;
}
do {
buffer[i++] = hex_chars[u % 16];
u /= 16;
} while (u > 0);
while (pos > 0) buf_add(str, size, &written, tmp[--pos]);
break;
}
case 'x':
case 'X': {
u64 u = va_arg(args, unsigned long long);
u8 padding = (fmt[i] == 'X') ? 16 : 0;
while (i < padding) buffer[i++] = '0';
char tmp[32];
int pos = 0;
const char* hex = "0123456789ABCDEF";
if (u == 0 && padding == 0) tmp[pos++] = '0';
while (u > 0) {
tmp[pos++] = hex[u % 16];
u /= 16;
}
print_str("0x");
while (--i >= 0) putchar(buffer[i]);
while (pos < padding) tmp[pos++] = '0';
while (pos > 0) buf_add(str, size, &written, tmp[--pos]);
break;
}
case '%': {
buf_add(str, size, &written, '%');
break;
}
default: {
buf_add(str, size, &written, '%');
buf_add(str, size, &written, fmt[i]);
break;
}
}
} else {
buf_add(str, size, &written, fmt[i]);
}
}
if (size > 0) {
if (written < size) str[written] = '\0';
else str[size - 1] = '\0';
}
return (int)written;
}
void printf(const char *fmt, ...) {
int snprintf(char* str, usize size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int ret = vsnprintf(str, size, fmt, args);
va_end(args);
return ret;
}
int printf(const char *fmt, ...) {
char buf[PRINTF_BUFFER_SIZE];
va_list args;
va_start(args, fmt);
for (int i = 0; fmt[i] != '\0'; i++) {
if (fmt[i] == '%') {
i++;
switch (fmt[i]) {
case 's': print_str(va_arg(args, const char*)); break;
case 'c': putchar((char)va_arg(args, int)); break;
case 'd': print_dec(va_arg(args, int)); break;
case 'x': print_hex(va_arg(args, unsigned long long), 0); break;
case 'X': print_hex(va_arg(args, unsigned long long), 16); break;
case '%': putchar('%'); break;
default: putchar(fmt[i]); break;
}
}
else {
putchar(fmt[i]);
}
}
int len = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
u64 write_len = ((u64)len < sizeof(buf)) ? len : (sizeof(buf) - 1);
sys_write(1, buf, write_len);
return (int)write_len;
}
int getchar() {
+5 -1
View File
@@ -23,7 +23,11 @@ int main() {
case TOKEN_CLEAR: not_implemented_yet(); break;
case TOKEN_HELP: not_implemented_yet(); break;
case TOKEN_SPAWN: if (tokens_count >= 2) cmd_spawn(tokens[1]); break;
default: printf("Unknown command\n"); break;
default: {
char buff[256];
snprintf(buff, sizeof(buff), "/bin/%s", tokens[0]);
cmd_spawn(buff);
}
}
}
}