From e323e91dac77a12eceff33876ce87768944c96c4 Mon Sep 17 00:00:00 2001 From: Karina Date: Fri, 30 Jan 2026 20:22:45 +0400 Subject: [PATCH] chore(libterm/stdio): printf reworked, vsnprintf() and snprintf() --- ROADMAP.md | 12 ++- userspace/init/src/main.c | 10 ++- userspace/libterm/inc/stdio.h | 3 +- userspace/libterm/src/stdio.c | 141 ++++++++++++++++++++++------------ userspace/termosh/src/main.c | 6 +- 5 files changed, 115 insertions(+), 57 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index f2a24ed..31e1480 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -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). diff --git a/userspace/init/src/main.c b/userspace/init/src/main.c index 33e9095..725f0b5 100644 --- a/userspace/init/src/main.c +++ b/userspace/init/src/main.c @@ -2,11 +2,13 @@ // Copyright (c) 2026 0xKarinyash #include -#include #include +// 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); + } } \ No newline at end of file diff --git a/userspace/libterm/inc/stdio.h b/userspace/libterm/inc/stdio.h index e682313..b446dbf 100644 --- a/userspace/libterm/inc/stdio.h +++ b/userspace/libterm/inc/stdio.h @@ -4,7 +4,8 @@ #pragma once #include -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); \ No newline at end of file diff --git a/userspace/libterm/src/stdio.c b/userspace/libterm/src/stdio.c index 288318d..2e215e2 100644 --- a/userspace/libterm/src/stdio.c +++ b/userspace/libterm/src/stdio.c @@ -7,6 +7,7 @@ #include #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() { diff --git a/userspace/termosh/src/main.c b/userspace/termosh/src/main.c index 77d291c..09c8107 100644 --- a/userspace/termosh/src/main.c +++ b/userspace/termosh/src/main.c @@ -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); + } } } } \ No newline at end of file