mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Merge branch 'BoredDevNL:main' into terminal-fix
This commit is contained in:
commit
e1864b2a66
10 changed files with 337 additions and 140 deletions
|
|
@ -67,9 +67,9 @@ If you find this project interesting or helpful, consider fueling the developmen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚠️ Project Disclaimer & Heritage
|
## Project Disclaimer & Heritage
|
||||||
|
|
||||||
**BoredOS** is the successor to **BrewKernel**, a project initiated in 2023.
|
**BoredOS** is the successor to **[BrewKernel](https://github.com/boreddevnl/brewkernel)**, a project initiated in 2023.
|
||||||
|
|
||||||
While BrewKernel served as the foundational learning ground for this OS, it has been officially **deprecated and archived**. It no longer receives updates, bug fixes, or pull request reviews. BoredOS represents a complete architectural reboot, applying years of lessons learned to create a cleaner, more modular, and more capable system.
|
While BrewKernel served as the foundational learning ground for this OS, it has been officially **deprecated and archived**. It no longer receives updates, bug fixes, or pull request reviews. BoredOS represents a complete architectural reboot, applying years of lessons learned to create a cleaner, more modular, and more capable system.
|
||||||
|
|
||||||
|
|
@ -80,12 +80,12 @@ While BrewKernel served as the foundational learning ground for this OS, it has
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
- **boreddevnl** — Project creator and lead maintainer.
|
- **BoredDevNL** — Project creator and lead maintainer.
|
||||||
- **Lluciocc** — Contributor.
|
- **Lluciocc** — Contributor.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
**Copyright (C) 2024-2026 boreddevnl**
|
**Copyright (C) 2023-2026 boreddevnl**
|
||||||
|
|
||||||
Distributed under the **GNU General Public License v3**. See the `LICENSE` file for details.
|
Distributed under the **GNU General Public License v3**. See the `LICENSE` file for details.
|
||||||
|
|
||||||
|
|
|
||||||
BIN
disk.img
BIN
disk.img
Binary file not shown.
|
|
@ -1,19 +0,0 @@
|
||||||
; Copyright (c) 2023-2026 Chris (boreddevnl)
|
|
||||||
; This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
|
||||||
; This header needs to maintain in any file it is present in, as per the GPL license terms.
|
|
||||||
global test_syscall
|
|
||||||
section .text
|
|
||||||
|
|
||||||
test_syscall:
|
|
||||||
; syscall number in RDI
|
|
||||||
mov rdi, 1
|
|
||||||
; string pointer in RSI
|
|
||||||
lea rsi, [rel test_msg]
|
|
||||||
|
|
||||||
; The SYSCALL instruction
|
|
||||||
syscall
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
section .rodata
|
|
||||||
test_msg: db "Hello from Syscall!", 10, 0
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
; Copyright (c) 2023-2026 Chris (boreddevnl)
|
|
||||||
; This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
|
||||||
; This header needs to maintain in any file it is present in, as per the GPL license terms.
|
|
||||||
global user_test_function
|
|
||||||
|
|
||||||
section .text
|
|
||||||
user_test_function:
|
|
||||||
; Syscall convention
|
|
||||||
.loop:
|
|
||||||
; Invoke SYS_WRITE (Syscall #1)
|
|
||||||
mov rdi, 1 ; arg1: fd = 1 (stdout)
|
|
||||||
lea rsi, [rel msg] ; arg2: buffer (RIP-relative)
|
|
||||||
mov rdx, 15 ; arg3: length
|
|
||||||
mov eax, 1 ; syscall_num = 1 (SYS_WRITE)
|
|
||||||
syscall
|
|
||||||
|
|
||||||
; Some delay loop
|
|
||||||
mov rcx, 100000000
|
|
||||||
.delay:
|
|
||||||
dec rcx
|
|
||||||
jnz .delay
|
|
||||||
|
|
||||||
jmp .loop
|
|
||||||
|
|
||||||
msg: db "Hello syscall!", 10
|
|
||||||
|
|
@ -13,7 +13,7 @@ void get_os_info(os_info_t *info) {
|
||||||
for (size_t i = 0; i < sizeof(os_info_t); i++) p[i] = 0;
|
for (size_t i = 0; i < sizeof(os_info_t); i++) p[i] = 0;
|
||||||
|
|
||||||
const char *os_name = "BoredOS";
|
const char *os_name = "BoredOS";
|
||||||
const char *os_version = "26.4.2";
|
const char *os_version = "26.4.2.1";
|
||||||
const char *os_codename = "Voyager";
|
const char *os_codename = "Voyager";
|
||||||
const char *kernel_name = "Boredkernel";
|
const char *kernel_name = "Boredkernel";
|
||||||
const char *kernel_version = "4.1.0-stable";
|
const char *kernel_version = "4.1.0-stable";
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
# Lines starting with # are comments.
|
# Lines starting with # are comments.
|
||||||
#
|
#
|
||||||
# PATH controls command lookup order (colon-separated).
|
# PATH controls command lookup order (colon-separated).
|
||||||
PATH=/bin:/root/Apps
|
export PATH="/bin"
|
||||||
|
|
||||||
# Scripts to run automatically.
|
# Scripts to run automatically.
|
||||||
# STARTUP runs for interactive shells.
|
# STARTUP runs for interactive shells.
|
||||||
|
|
@ -19,9 +19,21 @@ BOOT_SCRIPT=/Library/bsh/boot.bsh
|
||||||
# %h = hostname
|
# %h = hostname
|
||||||
# %~ = cwd ("~" for /root)
|
# %~ = cwd ("~" for /root)
|
||||||
# %T = time (HH:MM)
|
# %T = time (HH:MM)
|
||||||
PROMPT_LEFT=%n@%h:%~$
|
# Colors:
|
||||||
|
# %{color} switches text color; use names or hex.
|
||||||
|
# Names: default, red, green, yellow, blue, magenta, cyan, white, gray
|
||||||
|
# Hex: #RRGGBB, 0xRRGGBB, or 0xAARRGGBB
|
||||||
|
PROMPT_LEFT=%{green}%n@%h%{default}:%~%{blue}$%{default}
|
||||||
PROMPT_RIGHT=%T
|
PROMPT_RIGHT=%T
|
||||||
|
|
||||||
|
# Minimal history mode
|
||||||
|
# When enabled, the entered line is rewritten as PROMPT_MINIMAL_PREFIX + command.
|
||||||
|
# Example:
|
||||||
|
# root@boredos:~$ echo hi
|
||||||
|
# > echo hi
|
||||||
|
PROMPT_MINIMAL_HISTORY=true
|
||||||
|
PROMPT_MINIMAL_PREFIX="> "
|
||||||
|
|
||||||
# History settings.
|
# History settings.
|
||||||
HISTORY_FILE=/Library/bsh/history
|
HISTORY_FILE=/Library/bsh/history
|
||||||
HISTORY_SIZE=200
|
HISTORY_SIZE=200
|
||||||
|
|
@ -31,5 +43,3 @@ GLOB=true
|
||||||
COMPLETE=true
|
COMPLETE=true
|
||||||
SUGGEST=true
|
SUGGEST=true
|
||||||
|
|
||||||
# Example aliases (future support).
|
|
||||||
# alias ll=ls -la
|
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ BIN_DIR = bin
|
||||||
LIBC_SOURCES = $(wildcard libc/*.c)
|
LIBC_SOURCES = $(wildcard libc/*.c)
|
||||||
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o
|
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o
|
||||||
|
|
||||||
VPATH = cli gui sys games libc net
|
VPATH = cli gui sys games libc net cli/third_party
|
||||||
vpath %.c cli gui sys games libc net
|
vpath %.c cli gui sys games libc net cli/third_party
|
||||||
|
|
||||||
APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c net/*.c)
|
APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c net/*.c cli/third_party/*.c)
|
||||||
APP_SOURCES = $(filter-out stb_image.c, $(APP_SOURCES_FULL))
|
APP_SOURCES = $(filter-out stb_image.c, $(APP_SOURCES_FULL))
|
||||||
APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(notdir $(APP_SOURCES)))
|
APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(notdir $(APP_SOURCES)))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ typedef struct {
|
||||||
char boot_script[256];
|
char boot_script[256];
|
||||||
char prompt_left[128];
|
char prompt_left[128];
|
||||||
char prompt_right[128];
|
char prompt_right[128];
|
||||||
|
char prompt_minimal_prefix[64];
|
||||||
char history_file[128];
|
char history_file[128];
|
||||||
int history_size;
|
int history_size;
|
||||||
|
bool prompt_minimal_history;
|
||||||
bool glob_enabled;
|
bool glob_enabled;
|
||||||
bool complete_enabled;
|
bool complete_enabled;
|
||||||
bool suggest_enabled;
|
bool suggest_enabled;
|
||||||
|
|
@ -47,6 +49,7 @@ static alias_t g_aliases[MAX_ALIASES];
|
||||||
static int g_alias_count = 0;
|
static int g_alias_count = 0;
|
||||||
|
|
||||||
static int g_tty_id = -1;
|
static int g_tty_id = -1;
|
||||||
|
static bool g_need_prompt_newline = false;
|
||||||
static uint32_t g_color_dir = 0;
|
static uint32_t g_color_dir = 0;
|
||||||
static uint32_t g_color_file = 0;
|
static uint32_t g_color_file = 0;
|
||||||
static uint32_t g_color_size = 0;
|
static uint32_t g_color_size = 0;
|
||||||
|
|
@ -54,6 +57,69 @@ static uint32_t g_color_error = 0;
|
||||||
static uint32_t g_color_success = 0;
|
static uint32_t g_color_success = 0;
|
||||||
static uint32_t g_color_default = 0;
|
static uint32_t g_color_default = 0;
|
||||||
|
|
||||||
|
static bool str_eq(const char *a, const char *b);
|
||||||
|
static void get_time_string(char *out, int max_len);
|
||||||
|
|
||||||
|
static int hex_digit(char c) {
|
||||||
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
|
||||||
|
if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_hex_color(const char *s, int len, uint32_t *out) {
|
||||||
|
if (!s || len <= 0 || !out) return false;
|
||||||
|
if (len == 7 && s[0] == '#') {
|
||||||
|
uint32_t rgb = 0;
|
||||||
|
for (int i = 1; i < 7; i++) {
|
||||||
|
int d = hex_digit(s[i]);
|
||||||
|
if (d < 0) return false;
|
||||||
|
rgb = (rgb << 4) | (uint32_t)d;
|
||||||
|
}
|
||||||
|
*out = 0xFF000000 | rgb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (len == 8 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||||
|
uint32_t rgb = 0;
|
||||||
|
for (int i = 2; i < 8; i++) {
|
||||||
|
int d = hex_digit(s[i]);
|
||||||
|
if (d < 0) return false;
|
||||||
|
rgb = (rgb << 4) | (uint32_t)d;
|
||||||
|
}
|
||||||
|
*out = 0xFF000000 | rgb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (len == 10 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||||
|
uint32_t argb = 0;
|
||||||
|
for (int i = 2; i < 10; i++) {
|
||||||
|
int d = hex_digit(s[i]);
|
||||||
|
if (d < 0) return false;
|
||||||
|
argb = (argb << 4) | (uint32_t)d;
|
||||||
|
}
|
||||||
|
*out = argb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_named_color(const char *s, uint32_t *out) {
|
||||||
|
if (!s || !out) return false;
|
||||||
|
if (str_eq(s, "default")) {
|
||||||
|
*out = g_color_default;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (str_eq(s, "black")) { *out = 0xFF000000; return true; }
|
||||||
|
if (str_eq(s, "red")) { *out = 0xFFFF4444; return true; }
|
||||||
|
if (str_eq(s, "green")) { *out = 0xFF6A9955; return true; }
|
||||||
|
if (str_eq(s, "yellow")) { *out = 0xFFFFCC00; return true; }
|
||||||
|
if (str_eq(s, "blue")) { *out = 0xFF569CD6; return true; }
|
||||||
|
if (str_eq(s, "magenta")) { *out = 0xFFC586C0; return true; }
|
||||||
|
if (str_eq(s, "cyan")) { *out = 0xFF4EC9B0; return true; }
|
||||||
|
if (str_eq(s, "white")) { *out = 0xFFFFFFFF; return true; }
|
||||||
|
if (str_eq(s, "gray")) { *out = 0xFFCCCCCC; return true; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void str_copy(char *dst, const char *src, int max_len) {
|
static void str_copy(char *dst, const char *src, int max_len) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (max_len <= 0) return;
|
if (max_len <= 0) return;
|
||||||
|
|
@ -118,6 +184,42 @@ static void trim(char *s) {
|
||||||
s[out] = 0;
|
s[out] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void strip_quotes(char *s) {
|
||||||
|
if (!s) return;
|
||||||
|
int len = (int)strlen(s);
|
||||||
|
if (len >= 2 && ((s[0] == '"' && s[len - 1] == '"') || (s[0] == '\'' && s[len - 1] == '\''))) {
|
||||||
|
for (int i = 1; i < len - 1; i++) {
|
||||||
|
s[i - 1] = s[i];
|
||||||
|
}
|
||||||
|
s[len - 2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expand_path_value(const char *val, char *out, int max_len) {
|
||||||
|
if (!out || max_len <= 0) return;
|
||||||
|
out[0] = 0;
|
||||||
|
if (!val) return;
|
||||||
|
|
||||||
|
const char *needle1 = "$PATH";
|
||||||
|
const char *needle2 = "${PATH}";
|
||||||
|
int i = 0;
|
||||||
|
while (val[i] && (int)strlen(out) < max_len - 1) {
|
||||||
|
if (starts_with(&val[i], needle1)) {
|
||||||
|
str_append(out, g_cfg.path, max_len);
|
||||||
|
i += (int)strlen(needle1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (starts_with(&val[i], needle2)) {
|
||||||
|
str_append(out, g_cfg.path, max_len);
|
||||||
|
i += (int)strlen(needle2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char ch[2] = { val[i], 0 };
|
||||||
|
str_append(out, ch, max_len);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void alias_add(const char *name, const char *value) {
|
static void alias_add(const char *name, const char *value) {
|
||||||
if (!name || !name[0] || !value) return;
|
if (!name || !name[0] || !value) return;
|
||||||
for (int i = 0; i < g_alias_count; i++) {
|
for (int i = 0; i < g_alias_count; i++) {
|
||||||
|
|
@ -159,8 +261,10 @@ static void config_defaults(void) {
|
||||||
str_copy(g_cfg.boot_script, "", sizeof(g_cfg.boot_script));
|
str_copy(g_cfg.boot_script, "", sizeof(g_cfg.boot_script));
|
||||||
str_copy(g_cfg.prompt_left, DEFAULT_PROMPT, sizeof(g_cfg.prompt_left));
|
str_copy(g_cfg.prompt_left, DEFAULT_PROMPT, sizeof(g_cfg.prompt_left));
|
||||||
str_copy(g_cfg.prompt_right, "", sizeof(g_cfg.prompt_right));
|
str_copy(g_cfg.prompt_right, "", sizeof(g_cfg.prompt_right));
|
||||||
|
str_copy(g_cfg.prompt_minimal_prefix, "> ", sizeof(g_cfg.prompt_minimal_prefix));
|
||||||
str_copy(g_cfg.history_file, "/Library/bsh/history", sizeof(g_cfg.history_file));
|
str_copy(g_cfg.history_file, "/Library/bsh/history", sizeof(g_cfg.history_file));
|
||||||
g_cfg.history_size = 200;
|
g_cfg.history_size = 200;
|
||||||
|
g_cfg.prompt_minimal_history = false;
|
||||||
g_cfg.glob_enabled = true;
|
g_cfg.glob_enabled = true;
|
||||||
g_cfg.complete_enabled = true;
|
g_cfg.complete_enabled = true;
|
||||||
g_cfg.suggest_enabled = true;
|
g_cfg.suggest_enabled = true;
|
||||||
|
|
@ -220,6 +324,88 @@ static void reset_color(void) {
|
||||||
sys_set_text_color(g_color_default);
|
sys_set_text_color(g_color_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prompt_emit(const char *text, int len, char *out, int *out_idx, int max_len, bool do_write) {
|
||||||
|
if (!text || len <= 0) return;
|
||||||
|
if (do_write) sys_write(1, text, len);
|
||||||
|
if (!out || max_len <= 0 || !out_idx) return;
|
||||||
|
for (int i = 0; i < len && *out_idx < max_len - 1; i++) {
|
||||||
|
out[(*out_idx)++] = text[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void render_prompt(const char *tmpl, char *out, int max_len, bool do_write) {
|
||||||
|
char cwd[256];
|
||||||
|
if (!getcwd(cwd, sizeof(cwd))) str_copy(cwd, "/", sizeof(cwd));
|
||||||
|
|
||||||
|
int out_idx = 0;
|
||||||
|
for (int i = 0; tmpl[i] && (!out || out_idx < max_len - 1); i++) {
|
||||||
|
if (tmpl[i] == '%' && tmpl[i + 1]) {
|
||||||
|
if (tmpl[i + 1] == '{') {
|
||||||
|
int j = i + 2;
|
||||||
|
while (tmpl[j] && tmpl[j] != '}') j++;
|
||||||
|
if (tmpl[j] == '}') {
|
||||||
|
char color_buf[32];
|
||||||
|
int len = j - (i + 2);
|
||||||
|
if (len > (int)sizeof(color_buf) - 1) len = (int)sizeof(color_buf) - 1;
|
||||||
|
for (int k = 0; k < len; k++) color_buf[k] = tmpl[i + 2 + k];
|
||||||
|
color_buf[len] = 0;
|
||||||
|
trim(color_buf);
|
||||||
|
|
||||||
|
uint32_t color = 0;
|
||||||
|
if (parse_hex_color(color_buf, (int)strlen(color_buf), &color) ||
|
||||||
|
parse_named_color(color_buf, &color)) {
|
||||||
|
if (do_write) set_color(color);
|
||||||
|
i = j;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char token = tmpl[i + 1];
|
||||||
|
if (token == '~') {
|
||||||
|
if (starts_with(cwd, "/root") && (cwd[5] == 0 || cwd[5] == '/')) {
|
||||||
|
prompt_emit("~", 1, out, &out_idx, max_len, do_write);
|
||||||
|
int j = 5;
|
||||||
|
while (cwd[j]) {
|
||||||
|
prompt_emit(&cwd[j], 1, out, &out_idx, max_len, do_write);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int j = 0;
|
||||||
|
while (cwd[j]) {
|
||||||
|
prompt_emit(&cwd[j], 1, out, &out_idx, max_len, do_write);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token == 'n') {
|
||||||
|
const char *user = "root";
|
||||||
|
prompt_emit(user, (int)strlen(user), out, &out_idx, max_len, do_write);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token == 'h') {
|
||||||
|
const char *host = "boredos";
|
||||||
|
prompt_emit(host, (int)strlen(host), out, &out_idx, max_len, do_write);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token == 'T') {
|
||||||
|
char time_buf[16];
|
||||||
|
get_time_string(time_buf, sizeof(time_buf));
|
||||||
|
prompt_emit(time_buf, (int)strlen(time_buf), out, &out_idx, max_len, do_write);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prompt_emit(&tmpl[i], 1, out, &out_idx, max_len, do_write);
|
||||||
|
}
|
||||||
|
if (out && max_len > 0) out[out_idx] = 0;
|
||||||
|
if (do_write) reset_color();
|
||||||
|
}
|
||||||
|
|
||||||
static void config_load(void) {
|
static void config_load(void) {
|
||||||
config_defaults();
|
config_defaults();
|
||||||
|
|
||||||
|
|
@ -270,20 +456,33 @@ static void config_load(void) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sep = line;
|
char *assign = line;
|
||||||
|
if (starts_with(assign, "export ") || starts_with(assign, "export\t")) {
|
||||||
|
assign += 6;
|
||||||
|
while (*assign == ' ' || *assign == '\t') assign++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sep = assign;
|
||||||
while (*sep && *sep != '=') sep++;
|
while (*sep && *sep != '=') sep++;
|
||||||
if (*sep == '=') {
|
if (*sep == '=') {
|
||||||
*sep = 0;
|
*sep = 0;
|
||||||
char *key = line;
|
char *key = assign;
|
||||||
char *val = sep + 1;
|
char *val = sep + 1;
|
||||||
trim(key);
|
trim(key);
|
||||||
trim(val);
|
trim(val);
|
||||||
|
strip_quotes(val);
|
||||||
|
|
||||||
if (str_eq(key, "PATH")) str_copy(g_cfg.path, val, sizeof(g_cfg.path));
|
if (str_eq(key, "PATH")) {
|
||||||
|
char expanded[256];
|
||||||
|
expand_path_value(val, expanded, sizeof(expanded));
|
||||||
|
str_copy(g_cfg.path, expanded[0] ? expanded : val, sizeof(g_cfg.path));
|
||||||
|
}
|
||||||
else if (str_eq(key, "STARTUP")) str_copy(g_cfg.startup, val, sizeof(g_cfg.startup));
|
else if (str_eq(key, "STARTUP")) str_copy(g_cfg.startup, val, sizeof(g_cfg.startup));
|
||||||
else if (str_eq(key, "BOOT_SCRIPT")) str_copy(g_cfg.boot_script, val, sizeof(g_cfg.boot_script));
|
else if (str_eq(key, "BOOT_SCRIPT")) str_copy(g_cfg.boot_script, val, sizeof(g_cfg.boot_script));
|
||||||
else if (str_eq(key, "PROMPT_LEFT")) str_copy(g_cfg.prompt_left, val, sizeof(g_cfg.prompt_left));
|
else if (str_eq(key, "PROMPT_LEFT")) str_copy(g_cfg.prompt_left, val, sizeof(g_cfg.prompt_left));
|
||||||
else if (str_eq(key, "PROMPT_RIGHT")) str_copy(g_cfg.prompt_right, val, sizeof(g_cfg.prompt_right));
|
else if (str_eq(key, "PROMPT_RIGHT")) str_copy(g_cfg.prompt_right, val, sizeof(g_cfg.prompt_right));
|
||||||
|
else if (str_eq(key, "PROMPT_MINIMAL_HISTORY")) parse_bool(val, &g_cfg.prompt_minimal_history);
|
||||||
|
else if (str_eq(key, "PROMPT_MINIMAL_PREFIX")) str_copy(g_cfg.prompt_minimal_prefix, val, sizeof(g_cfg.prompt_minimal_prefix));
|
||||||
else if (str_eq(key, "HISTORY_FILE")) str_copy(g_cfg.history_file, val, sizeof(g_cfg.history_file));
|
else if (str_eq(key, "HISTORY_FILE")) str_copy(g_cfg.history_file, val, sizeof(g_cfg.history_file));
|
||||||
else if (str_eq(key, "HISTORY_SIZE")) g_cfg.history_size = atoi(val);
|
else if (str_eq(key, "HISTORY_SIZE")) g_cfg.history_size = atoi(val);
|
||||||
else if (str_eq(key, "GLOB")) parse_bool(val, &g_cfg.glob_enabled);
|
else if (str_eq(key, "GLOB")) parse_bool(val, &g_cfg.glob_enabled);
|
||||||
|
|
@ -379,55 +578,7 @@ static void get_time_string(char *out, int max_len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void format_prompt(const char *tmpl, char *out, int max_len) {
|
static void format_prompt(const char *tmpl, char *out, int max_len) {
|
||||||
char cwd[256];
|
render_prompt(tmpl, out, max_len, false);
|
||||||
if (!getcwd(cwd, sizeof(cwd))) str_copy(cwd, "/", sizeof(cwd));
|
|
||||||
|
|
||||||
int out_idx = 0;
|
|
||||||
for (int i = 0; tmpl[i] && out_idx < max_len - 1; i++) {
|
|
||||||
if (tmpl[i] == '%' && tmpl[i + 1]) {
|
|
||||||
char token = tmpl[i + 1];
|
|
||||||
if (token == '~') {
|
|
||||||
if (starts_with(cwd, "/root") && (cwd[5] == 0 || cwd[5] == '/')) {
|
|
||||||
out[out_idx++] = '~';
|
|
||||||
int j = 5;
|
|
||||||
while (cwd[j] && out_idx < max_len - 1) {
|
|
||||||
out[out_idx++] = cwd[j++];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int j = 0;
|
|
||||||
while (cwd[j] && out_idx < max_len - 1) {
|
|
||||||
out[out_idx++] = cwd[j++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (token == 'n') {
|
|
||||||
const char *user = "root";
|
|
||||||
int j = 0;
|
|
||||||
while (user[j] && out_idx < max_len - 1) out[out_idx++] = user[j++];
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (token == 'h') {
|
|
||||||
const char *host = "boredos";
|
|
||||||
int j = 0;
|
|
||||||
while (host[j] && out_idx < max_len - 1) out[out_idx++] = host[j++];
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (token == 'T') {
|
|
||||||
char time_buf[16];
|
|
||||||
get_time_string(time_buf, sizeof(time_buf));
|
|
||||||
int j = 0;
|
|
||||||
while (time_buf[j] && out_idx < max_len - 1) out[out_idx++] = time_buf[j++];
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out[out_idx++] = tmpl[i];
|
|
||||||
}
|
|
||||||
out[out_idx] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int split_args(char *line, char *argv[], int max_args) {
|
static int split_args(char *line, char *argv[], int max_args) {
|
||||||
|
|
@ -677,21 +828,62 @@ static int collect_path_matches(const char *dir_part, const char *prefix, char m
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void redraw_input(const char *prompt, const char *line, int len) {
|
static void prompt_write(const char *tmpl) {
|
||||||
|
render_prompt(tmpl, NULL, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prompt_write_with_right(const char *left_tmpl, const char *right_tmpl) {
|
||||||
|
char left_buf[128];
|
||||||
|
render_prompt(left_tmpl, left_buf, sizeof(left_buf), false);
|
||||||
|
int left_len = (int)strlen(left_buf);
|
||||||
|
|
||||||
|
prompt_write(left_tmpl);
|
||||||
|
if (!right_tmpl || !right_tmpl[0]) return;
|
||||||
|
|
||||||
|
char right_buf[128];
|
||||||
|
render_prompt(right_tmpl, right_buf, sizeof(right_buf), false);
|
||||||
|
int right_len = (int)strlen(right_buf);
|
||||||
|
if (right_len <= 0) return;
|
||||||
|
|
||||||
sys_write(1, "\r", 1);
|
sys_write(1, "\r", 1);
|
||||||
sys_write(1, prompt, (int)strlen(prompt));
|
sys_write(1, "\x1b[999C", 6);
|
||||||
|
if (right_len > 0) {
|
||||||
|
char num[8];
|
||||||
|
char seq[16];
|
||||||
|
itoa(right_len, num);
|
||||||
|
str_copy(seq, "\x1b[", sizeof(seq));
|
||||||
|
str_append(seq, num, sizeof(seq));
|
||||||
|
str_append(seq, "D", sizeof(seq));
|
||||||
|
sys_write(1, seq, (int)strlen(seq));
|
||||||
|
}
|
||||||
|
prompt_write(right_tmpl);
|
||||||
|
sys_write(1, "\r", 1);
|
||||||
|
if (left_len > 0) {
|
||||||
|
char num[8];
|
||||||
|
char seq[16];
|
||||||
|
itoa(left_len, num);
|
||||||
|
str_copy(seq, "\x1b[", sizeof(seq));
|
||||||
|
str_append(seq, num, sizeof(seq));
|
||||||
|
str_append(seq, "C", sizeof(seq));
|
||||||
|
sys_write(1, seq, (int)strlen(seq));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void redraw_input(const char *prompt_tmpl, const char *line, int len) {
|
||||||
|
sys_write(1, "\r", 1);
|
||||||
|
prompt_write_with_right(prompt_tmpl, g_cfg.prompt_right);
|
||||||
sys_write(1, line, len);
|
sys_write(1, line, len);
|
||||||
sys_write(1, "\x1b[K", 3);
|
sys_write(1, "\x1b[K", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_matches(const char *prompt, const char *line, int len, char matches[][MAX_MATCH_LEN], int count) {
|
static void show_matches(const char *prompt_tmpl, const char *line, int len, char matches[][MAX_MATCH_LEN], int count) {
|
||||||
sys_write(1, "\n", 1);
|
sys_write(1, "\n", 1);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
sys_write(1, matches[i], (int)strlen(matches[i]));
|
sys_write(1, matches[i], (int)strlen(matches[i]));
|
||||||
sys_write(1, " ", 2);
|
sys_write(1, " ", 2);
|
||||||
}
|
}
|
||||||
sys_write(1, "\n", 1);
|
sys_write(1, "\n", 1);
|
||||||
redraw_input(prompt, line, len);
|
redraw_input(prompt_tmpl, line, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pid_exists(int pid) {
|
static int pid_exists(int pid) {
|
||||||
|
|
@ -1196,6 +1388,7 @@ static int execute_line_inner(const char *line, int depth) {
|
||||||
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, pid);
|
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, pid);
|
||||||
wait_for_pid(pid);
|
wait_for_pid(pid);
|
||||||
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
||||||
|
g_need_prompt_newline = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1234,7 +1427,7 @@ static bool run_script(const char *path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_line(char *out, int max_len, const char *prompt) {
|
static int read_line(char *out, int max_len, const char *prompt_tmpl) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int hist_index = g_history_count;
|
int hist_index = g_history_count;
|
||||||
bool search_mode = false;
|
bool search_mode = false;
|
||||||
|
|
@ -1260,7 +1453,16 @@ static int read_line(char *out, int max_len, const char *prompt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '\r' || ch == '\n') {
|
if (ch == '\r' || ch == '\n') {
|
||||||
sys_write(1, "\n", 1);
|
if (g_cfg.prompt_minimal_history) {
|
||||||
|
const char *minimal_tmpl = g_cfg.prompt_minimal_prefix[0] ? g_cfg.prompt_minimal_prefix : "> ";
|
||||||
|
sys_write(1, "\r", 1);
|
||||||
|
sys_write(1, "\x1b[K", 3);
|
||||||
|
prompt_write(minimal_tmpl);
|
||||||
|
sys_write(1, out, len);
|
||||||
|
sys_write(1, "\n", 1);
|
||||||
|
} else {
|
||||||
|
sys_write(1, "\n", 1);
|
||||||
|
}
|
||||||
out[len] = 0;
|
out[len] = 0;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
@ -1322,7 +1524,7 @@ static int read_line(char *out, int max_len, const char *prompt) {
|
||||||
out[token_start] = 0;
|
out[token_start] = 0;
|
||||||
str_append(out, matches[0], max_len);
|
str_append(out, matches[0], max_len);
|
||||||
len = (int)strlen(out);
|
len = (int)strlen(out);
|
||||||
redraw_input(prompt, out, len);
|
redraw_input(prompt_tmpl, out, len);
|
||||||
} else {
|
} else {
|
||||||
int common_len = common_prefix_len(matches, match_count);
|
int common_len = common_prefix_len(matches, match_count);
|
||||||
if (common_len > token_len) {
|
if (common_len > token_len) {
|
||||||
|
|
@ -1333,9 +1535,9 @@ static int read_line(char *out, int max_len, const char *prompt) {
|
||||||
out[token_start] = 0;
|
out[token_start] = 0;
|
||||||
str_append(out, prefix_buf, max_len);
|
str_append(out, prefix_buf, max_len);
|
||||||
len = (int)strlen(out);
|
len = (int)strlen(out);
|
||||||
redraw_input(prompt, out, len);
|
redraw_input(prompt_tmpl, out, len);
|
||||||
} else {
|
} else {
|
||||||
show_matches(prompt, out, len, matches, match_count);
|
show_matches(prompt_tmpl, out, len, matches, match_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
search_mode = false;
|
search_mode = false;
|
||||||
|
|
@ -1363,7 +1565,7 @@ static int read_line(char *out, int max_len, const char *prompt) {
|
||||||
hist_index = found;
|
hist_index = found;
|
||||||
str_copy(out, g_history[hist_index], max_len);
|
str_copy(out, g_history[hist_index], max_len);
|
||||||
len = (int)strlen(out);
|
len = (int)strlen(out);
|
||||||
redraw_input(prompt, out, len);
|
redraw_input(prompt_tmpl, out, len);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1387,7 +1589,7 @@ static int read_line(char *out, int max_len, const char *prompt) {
|
||||||
str_copy(out, saved_line, max_len);
|
str_copy(out, saved_line, max_len);
|
||||||
len = (int)strlen(out);
|
len = (int)strlen(out);
|
||||||
}
|
}
|
||||||
redraw_input(prompt, out, len);
|
redraw_input(prompt_tmpl, out, len);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1438,16 +1640,22 @@ int main(int argc, char **argv) {
|
||||||
while (1) {
|
while (1) {
|
||||||
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
||||||
|
|
||||||
char prompt[128];
|
const char *prompt_tmpl = g_cfg.prompt_left[0] ? g_cfg.prompt_left : DEFAULT_PROMPT;
|
||||||
format_prompt(g_cfg.prompt_left[0] ? g_cfg.prompt_left : DEFAULT_PROMPT, prompt, sizeof(prompt));
|
if (g_need_prompt_newline) {
|
||||||
sys_write(1, prompt, (int)strlen(prompt));
|
sys_write(1, "\n", 1);
|
||||||
|
g_need_prompt_newline = false;
|
||||||
|
}
|
||||||
|
sys_write(1, "\r", 1);
|
||||||
|
sys_write(1, "\x1b[K", 3);
|
||||||
|
prompt_write_with_right(prompt_tmpl, g_cfg.prompt_right);
|
||||||
|
|
||||||
char line[MAX_LINE];
|
char line[MAX_LINE];
|
||||||
int len = read_line(line, sizeof(line), prompt);
|
int len = read_line(line, sizeof(line), prompt_tmpl);
|
||||||
if (len <= 0) continue;
|
if (len <= 0) continue;
|
||||||
|
|
||||||
history_add(line);
|
history_add(line);
|
||||||
int res = execute_line(line);
|
int res = execute_line(line);
|
||||||
|
if (g_cfg.prompt_minimal_history) g_need_prompt_newline = true;
|
||||||
if (res == 2) break;
|
if (res == 2) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
|
||||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
printf("Hello from Userland ELF!\n");
|
|
||||||
|
|
||||||
printf("argc: %d\n", argc);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
printf("argv[%d]: %s\n", i, argv[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
40
src/userland/cli/third_party/donut.c
vendored
Normal file
40
src/userland/cli/third_party/donut.c
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* donut.c - A rotating ASCII donut in C, but the code is a donut aswell.
|
||||||
|
* Created by Andy Sloane (@a1k0n) in 2006.
|
||||||
|
* * Source: https://www.a1k0n.net/2006/09/15/obfuscated-c-donut.html
|
||||||
|
*
|
||||||
|
* LICENSE NOTE:
|
||||||
|
* This file is included in BoredOS as a demonstration.
|
||||||
|
* This specific file is NOT covered by the project's GPLv3 license
|
||||||
|
* and remains the intellectual property of Andy Sloane.
|
||||||
|
* Use of this file is subject to the author's original terms.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
int putchar(int c) {
|
||||||
|
char ch = (char)c;
|
||||||
|
return sys_write(1, &ch, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int k;double sin()
|
||||||
|
,cos();int main(){float A=
|
||||||
|
0,B=0,i,j,z[1760];char b[
|
||||||
|
1760];printf("\x1b[2J");for(;;
|
||||||
|
){memset(b,32,1760);memset(z,0,7040)
|
||||||
|
;for(j=0;6.28>j;j+=0.07)for(i=0;6.28
|
||||||
|
>i;i+=0.02){float c=sin(i),d=cos(j),e=
|
||||||
|
sin(A),f=sin(j),g=cos(A),h=d+2,D=1/(c*
|
||||||
|
h*e+f*g+5),l=cos (i),m=cos(B),n=s\
|
||||||
|
in(B),t=c*h*g-f* e;int x=40+30*D*
|
||||||
|
(l*h*m-t*n),y= 12+15*D*(l*h*n
|
||||||
|
+t*m),o=x+80*y, N=8*((f*e-c*d*g
|
||||||
|
)*m-c*d*e-f*g-l *d*n);if(22>y&&
|
||||||
|
y>0&&x>0&&80>x&&D>z[o]){z[o]=D;;;b[o]=
|
||||||
|
".,-~:;=!*#$@"[N>0?N:0];}}/*#****!!-*/
|
||||||
|
printf("\x1b[H");for(k=0;1761>k;k++)
|
||||||
|
putchar(k%80?b[k]:10);A+=0.04;B+=
|
||||||
|
0.02;}}/*****####*******!!=;:~
|
||||||
|
~::==!!!**********!!!==::-
|
||||||
|
.,~~;;;========;;;:~-.
|
||||||
|
..,--------,*/
|
||||||
Loading…
Reference in a new issue