CMD config

This commit is contained in:
boreddevnl 2026-02-28 22:09:33 +01:00
parent fbd0bf880e
commit 74bdb89ad3
21 changed files with 691 additions and 138 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,48 +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 "about.h"
#include "graphics.h"
#include "wm.h"
#include <stddef.h>
Window win_about;
static void about_paint(Window *win) {
int offset_x = win->x + 15;
int offset_y = win->y + 35;
draw_boredos_logo(win->x + 60, offset_y, 4);
// Version info
draw_string(offset_x, offset_y + 105, "BoredOS 'Panda'", COLOR_WHITE);
draw_string(offset_x, offset_y + 120, "BoredOS Version 1.64", COLOR_WHITE);
draw_string(offset_x, offset_y + 135, "Kernel Version 3.0.0", COLOR_WHITE);
// Copyright
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_WHITE);
draw_string(offset_x, offset_y + 165, "All rights reserved.", COLOR_WHITE);
}
static void about_click(Window *win, int x, int y) {
(void)win;
(void)x;
(void)y;
// No interactive elements needed for About dialog
}
void about_init(void) {
win_about.title = "About BoredOS";
win_about.x = 250;
win_about.y = 180;
win_about.w = 185;
win_about.h = 240;
win_about.visible = false;
win_about.focused = false;
win_about.z_index = 0;
win_about.paint = about_paint;
win_about.handle_click = about_click;
win_about.handle_right_click = NULL;
win_about.handle_key = NULL;
}

View file

@ -1,13 +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.
#ifndef ABOUT_H
#define ABOUT_H
#include "wm.h"
extern Window win_about;
void about_init(void);
#endif

View file

@ -43,6 +43,35 @@ typedef enum {
MODE_PAGER MODE_PAGER
} CmdMode; } CmdMode;
// Shell Configuration
typedef struct {
uint32_t prompt_drive_color;
uint32_t prompt_colon_color;
uint32_t prompt_dir_color;
uint32_t prompt_op_color;
char prompt_op_char;
uint32_t default_text_color;
uint32_t bg_color;
uint32_t cursor_color;
bool show_drive;
bool show_dir;
uint32_t dir_color;
uint32_t file_color;
uint32_t size_color;
uint32_t error_color;
uint32_t success_color;
uint32_t help_color;
uint32_t command_color;
char title_text[64];
char custom_welcome_message[128];
char startup_cmd[128];
char prompt_suffix[32];
bool welcome_msg;
bool history_save_prompt;
} ShellConfig;
static ShellConfig shell_config;
// CMD Window State (per-window context) // CMD Window State (per-window context)
typedef struct { typedef struct {
char current_drive; char current_drive;
@ -58,6 +87,7 @@ static int cursor_row = 0;
static int cursor_col = 0; static int cursor_col = 0;
static uint32_t current_color = COLOR_DARK_TEXT; static uint32_t current_color = COLOR_DARK_TEXT;
static CmdState *cmd_state = NULL; // Will be set in cmd_init static CmdState *cmd_state = NULL; // Will be set in cmd_init
static int current_prompt_len = 0;
// Pager State // Pager State
static CmdMode current_mode = MODE_SHELL; static CmdMode current_mode = MODE_SHELL;
@ -129,6 +159,290 @@ static void itoa(int n, char *buf) {
buf[j] = buf[i - 1 - j]; buf[j] = buf[i - 1 - j];
buf[i - 1 - j] = t; buf[i - 1 - j] = t;
} }
buf[i] = 0;
}
// --- Configuration Parsing ---
static bool parse_bool(const char *s) {
if (!s) return false;
while (*s == ' ' || *s == '\t') s++;
if (cmd_strcmp(s, "true") == 0 || cmd_strcmp(s, "1") == 0 || cmd_strcmp(s, "yes") == 0) return true;
return false;
}
static int parse_int(const char *s) {
if (!s) return 0;
while (*s == ' ' || *s == '\t') s++;
int res = 0;
int sign = 1;
if (*s == '-') { sign = -1; s++; }
while (*s >= '0' && *s <= '9') {
res = res * 10 + (*s - '0');
s++;
}
return res * sign;
}
static uint32_t parse_color(const char *s) {
if (!s) return 0;
while (*s == ' ' || *s == '\t') s++;
if (!*s) return 0;
// 1. HEX Format: #RRGGBB or 0xRRGGBB
if (s[0] == '#' || (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))) {
const char *hex = (s[0] == '#') ? s + 1 : s + 2;
uint32_t res = 0;
int count = 0;
while (*hex && count < 8) {
char c = *hex++;
if (c >= '0' && c <= '9') res = (res << 4) | (c - '0');
else if (c >= 'a' && c <= 'f') res = (res << 4) | (c - 'a' + 10);
else if (c >= 'A' && c <= 'F') res = (res << 4) | (c - 'A' + 10);
else break;
count++;
}
if (count == 6) res |= 0xFF000000;
return res;
}
// 2. RGB Format: rgb(r, g, b)
if (s[0] == 'r' && s[1] == 'g' && s[2] == 'b') {
const char *p = s + 3;
while (*p && *p != '(') p++;
if (*p == '(') {
p++;
while (*p == ' ' || *p == '\t') p++;
int r = parse_int(p);
while (*p && *p != ',' && *p != ')') p++;
if (*p == ',') {
p++;
while (*p == ' ' || *p == '\t') p++;
int g = parse_int(p);
while (*p && *p != ',' && *p != ')') p++;
if (*p == ',') {
p++;
while (*p == ' ' || *p == '\t') p++;
int b = parse_int(p);
return 0xFF000000 | ((uint32_t)(r & 0xFF) << 16) | ((uint32_t)(g & 0xFF) << 8) | (uint32_t)(b & 0xFF);
}
}
}
}
// 3. Named Colors (assuming s is trimmed and lowercased)
if (cmd_strcmp(s, "black") == 0) return 0xFF000000;
if (cmd_strcmp(s, "white") == 0) return 0xFFFFFFFF;
if (cmd_strcmp(s, "gray") == 0 || cmd_strcmp(s, "grey") == 0) return 0xFF808080;
if (cmd_strcmp(s, "lightgray") == 0 || cmd_strcmp(s, "light gray") == 0 || cmd_strcmp(s, "lightgrey") == 0 || cmd_strcmp(s, "light grey") == 0) return 0xFFD3D3D3;
if (cmd_strcmp(s, "darkgray") == 0 || cmd_strcmp(s, "dark gray") == 0 || cmd_strcmp(s, "darkgrey") == 0 || cmd_strcmp(s, "dark grey") == 0) return 0xFFA9A9A9;
if (cmd_strcmp(s, "red") == 0) return 0xFFFF0000;
if (cmd_strcmp(s, "lightred") == 0 || cmd_strcmp(s, "light red") == 0) return 0xFFFF7F7F;
if (cmd_strcmp(s, "darkred") == 0 || cmd_strcmp(s, "dark red") == 0) return 0xFF8B0000;
if (cmd_strcmp(s, "green") == 0) return 0xFF00FF00;
if (cmd_strcmp(s, "lightgreen") == 0 || cmd_strcmp(s, "light green") == 0) return 0xFF90EE90;
if (cmd_strcmp(s, "darkgreen") == 0 || cmd_strcmp(s, "dark green") == 0) return 0xFF006400;
if (cmd_strcmp(s, "yellow") == 0) return 0xFFFFFF00;
if (cmd_strcmp(s, "lightyellow") == 0 || cmd_strcmp(s, "light yellow") == 0) return 0xFFFFFFE0;
if (cmd_strcmp(s, "blue") == 0) return 0xFF0000FF;
if (cmd_strcmp(s, "lightblue") == 0 || cmd_strcmp(s, "light blue") == 0) return 0xFFADD8E6;
if (cmd_strcmp(s, "darkblue") == 0 || cmd_strcmp(s, "dark blue") == 0) return 0xFF00008B;
if (cmd_strcmp(s, "magenta") == 0) return 0xFFFF00FF;
if (cmd_strcmp(s, "lightmagenta") == 0 || cmd_strcmp(s, "light magenta") == 0) return 0xFFFF77FF;
if (cmd_strcmp(s, "cyan") == 0 || cmd_strcmp(s, "aqua") == 0) return 0xFF00FFFF;
if (cmd_strcmp(s, "lightcyan") == 0 || cmd_strcmp(s, "light cyan") == 0) return 0xFFE0FFFF;
if (cmd_strcmp(s, "orange") == 0) return 0xFFFFA500;
if (cmd_strcmp(s, "brown") == 0) return 0xFFA52A2A;
if (cmd_strcmp(s, "pink") == 0) return 0xFFFFC0CB;
if (cmd_strcmp(s, "purple") == 0) return 0xFF800080;
if (cmd_strcmp(s, "teal") == 0) return 0xFF008080;
if (cmd_strcmp(s, "lime") == 0) return 0xFF00FF00;
if (cmd_strcmp(s, "maroon") == 0) return 0xFF800000;
if (cmd_strcmp(s, "navy") == 0) return 0xFF000080;
if (cmd_strcmp(s, "indigo") == 0) return 0xFF4B0082;
if (cmd_strcmp(s, "violet") == 0) return 0xFFEE82EE;
// 4. Fallback: Loose Hex (e.g. "FF00FF")
const char *hex = s;
uint32_t res = 0;
int count = 0;
while (*hex && count < 8) {
char c = *hex++;
if (c >= '0' && c <= '9') res = (res << 4) | (c - '0');
else if (c >= 'a' && c <= 'f') res = (res << 4) | (c - 'a' + 10);
else if (c >= 'A' && c <= 'F') res = (res << 4) | (c - 'A' + 10);
else break;
count++;
}
if (count == 6) res |= 0xFF000000;
return res;
}
static void cmd_init_config_defaults(void) {
shell_config.prompt_drive_color = 0xFFCCCCCC; // Default light gray
shell_config.prompt_colon_color = 0xFFCCCCCC;
shell_config.prompt_dir_color = 0xFF569CD6; // Blue
shell_config.prompt_op_color = 0xFFCCCCCC;
shell_config.prompt_op_char = '>';
shell_config.default_text_color = 0xFFCCCCCC;
shell_config.bg_color = 0xFF1E1E1E; // Dark background
shell_config.cursor_color = 0xFFFFFFFF;
shell_config.show_drive = true;
shell_config.show_dir = true;
shell_config.dir_color = 0xFF569CD6;
shell_config.file_color = 0xFFCCCCCC;
shell_config.size_color = 0xFF6A9955; // Green
shell_config.error_color = 0xFFFF4444; // Red
shell_config.success_color = 0xFF6A9955;
shell_config.help_color = 0xFFCCCCCC;
shell_config.command_color = 0xFFFFFFFF; // White typed text
cmd_strcpy(shell_config.title_text, "Command Prompt");
cmd_strcpy(shell_config.custom_welcome_message, "");
cmd_strcpy(shell_config.startup_cmd, "");
cmd_strcpy(shell_config.prompt_suffix, " ");
shell_config.welcome_msg = true;
shell_config.history_save_prompt = true;
}
void cmd_load_config(void) {
cmd_init_config_defaults();
FAT32_FileHandle *fh = fat32_open("Library/conf/shell.cfg", "r");
if (!fh) return;
char buffer[4096];
int bytes = fat32_read(fh, buffer, sizeof(buffer) - 1);
fat32_close(fh);
if (bytes <= 0) return;
buffer[bytes] = 0;
char *line = buffer;
while (*line) {
char *end = line;
while (*end && *end != '\n' && *end != '\r') end++;
char saved = *end;
*end = 0;
// Skip comments and empty lines
if (line[0] == '/' && line[1] == '/') {
line = end + (saved ? 1 : 0);
if (saved == '\r' && *line == '\n') line++;
continue;
}
char *sep = line;
while (*sep && *sep != '=') sep++;
if (*sep == '=') {
*sep = 0;
char *key = line;
char *val = sep + 1;
// Trim whitespace from key
char *k_end = sep - 1;
while (k_end > key && (*k_end == ' ' || *k_end == '\t')) {
*k_end-- = 0;
}
// Trim whitespace from value
while (*val == ' ' || *val == '\t') val++;
char *v_end = val;
while (*v_end) v_end++;
if (v_end > val) {
v_end--;
while (v_end > val && (*v_end == ' ' || *v_end == '\t' || *v_end == '\n' || *v_end == '\r')) {
*v_end-- = 0;
}
}
// Lowercase value for easier parsing of named colors, EXCEPT for string fields
if (cmd_strcmp(key, "title_text") != 0 &&
cmd_strcmp(key, "custom_welcome_message") != 0 &&
cmd_strcmp(key, "startup_cmd") != 0 &&
cmd_strcmp(key, "prompt_suffix") != 0) {
char *p_low = val;
while (*p_low) {
if (*p_low >= 'A' && *p_low <= 'Z') *p_low += 32;
p_low++;
}
}
if (cmd_strcmp(key, "prompt_drive_color") == 0) shell_config.prompt_drive_color = parse_color(val);
else if (cmd_strcmp(key, "prompt_colon_color") == 0) shell_config.prompt_colon_color = parse_color(val);
else if (cmd_strcmp(key, "prompt_dir_color") == 0) shell_config.prompt_dir_color = parse_color(val);
else if (cmd_strcmp(key, "prompt_op_color") == 0) shell_config.prompt_op_color = parse_color(val);
else if (cmd_strcmp(key, "prompt_op_char") == 0) {
if (*val) shell_config.prompt_op_char = *val;
}
else if (cmd_strcmp(key, "default_text_color") == 0) shell_config.default_text_color = parse_color(val);
else if (cmd_strcmp(key, "bg_color") == 0) shell_config.bg_color = parse_color(val);
else if (cmd_strcmp(key, "cursor_color") == 0) shell_config.cursor_color = parse_color(val);
else if (cmd_strcmp(key, "show_drive") == 0) shell_config.show_drive = parse_bool(val);
else if (cmd_strcmp(key, "show_dir") == 0) shell_config.show_dir = parse_bool(val);
else if (cmd_strcmp(key, "dir_color") == 0) shell_config.dir_color = parse_color(val);
else if (cmd_strcmp(key, "file_color") == 0) shell_config.file_color = parse_color(val);
else if (cmd_strcmp(key, "size_color") == 0) shell_config.size_color = parse_color(val);
else if (cmd_strcmp(key, "error_color") == 0) shell_config.error_color = parse_color(val);
else if (cmd_strcmp(key, "success_color") == 0) shell_config.success_color = parse_color(val);
else if (cmd_strcmp(key, "help_color") == 0) shell_config.help_color = parse_color(val);
else if (cmd_strcmp(key, "command_color") == 0) shell_config.command_color = parse_color(val);
else if (cmd_strcmp(key, "title_text") == 0) {
cmd_strcpy(shell_config.title_text, val);
}
else if (cmd_strcmp(key, "custom_welcome_message") == 0) {
cmd_strcpy(shell_config.custom_welcome_message, val);
}
else if (cmd_strcmp(key, "startup_cmd") == 0) {
cmd_strcpy(shell_config.startup_cmd, val);
}
else if (cmd_strcmp(key, "prompt_suffix") == 0) {
cmd_strcpy(shell_config.prompt_suffix, val);
}
else if (cmd_strcmp(key, "welcome_msg") == 0) shell_config.welcome_msg = parse_bool(val);
else if (cmd_strcmp(key, "history_save_prompt") == 0) shell_config.history_save_prompt = parse_bool(val);
}
line = end + (saved ? 1 : 0);
if (saved == '\r' && *line == '\n') line++;
}
}
// System Call Helper
uint64_t cmd_get_config_value(const char *key) {
if (cmd_strcmp(key, "prompt_drive_color") == 0) return shell_config.prompt_drive_color;
if (cmd_strcmp(key, "prompt_colon_color") == 0) return shell_config.prompt_colon_color;
if (cmd_strcmp(key, "prompt_drive_color") == 0) return shell_config.prompt_drive_color;
if (cmd_strcmp(key, "prompt_colon_color") == 0) return shell_config.prompt_colon_color;
if (cmd_strcmp(key, "prompt_dir_color") == 0) return shell_config.prompt_dir_color;
if (cmd_strcmp(key, "prompt_op_color") == 0) return shell_config.prompt_op_color;
if (cmd_strcmp(key, "default_text_color") == 0) return shell_config.default_text_color;
if (cmd_strcmp(key, "bg_color") == 0) return shell_config.bg_color;
if (cmd_strcmp(key, "cursor_color") == 0) return shell_config.cursor_color;
if (cmd_strcmp(key, "show_drive") == 0) return shell_config.show_drive;
if (cmd_strcmp(key, "show_dir") == 0) return shell_config.show_dir;
if (cmd_strcmp(key, "dir_color") == 0) return shell_config.dir_color;
if (cmd_strcmp(key, "file_color") == 0) return shell_config.file_color;
if (cmd_strcmp(key, "size_color") == 0) return shell_config.size_color;
if (cmd_strcmp(key, "error_color") == 0) return shell_config.error_color;
if (cmd_strcmp(key, "success_color") == 0) return shell_config.success_color;
if (cmd_strcmp(key, "help_color") == 0) return shell_config.help_color;
if (cmd_strcmp(key, "command_color") == 0) return shell_config.command_color;
if (cmd_strcmp(key, "welcome_msg") == 0) return shell_config.welcome_msg;
if (cmd_strcmp(key, "history_save_prompt") == 0) return shell_config.history_save_prompt;
return 0;
}
void cmd_set_current_color(uint32_t color) {
current_color = color;
} }
// --- History --- // --- History ---
@ -153,25 +467,37 @@ static void cmd_history_add(const char *cmd) {
if (history_len < HISTORY_MAX) history_len++; if (history_len < HISTORY_MAX) history_len++;
} }
static void cmd_print_prompt(void) { void cmd_print_prompt(void) {
// Clear the current line to prevent old output from corrupting the new command buffer if (cmd_state) {
for (int i = 0; i < CMD_COLS; i++) { current_prompt_len = 0;
screen_buffer[cursor_row][i].c = 0; cursor_col = 0;
screen_buffer[cursor_row][i].color = current_color;
if (shell_config.show_drive) {
current_color = shell_config.prompt_drive_color;
cmd_putchar(cmd_state->current_drive);
current_color = shell_config.prompt_colon_color;
cmd_putchar(':');
}
if (shell_config.show_dir) {
current_color = shell_config.prompt_dir_color;
cmd_write(cmd_state->current_dir);
}
current_color = shell_config.prompt_op_color;
cmd_putchar(shell_config.prompt_op_char);
if (shell_config.prompt_suffix[0]) {
cmd_write(shell_config.prompt_suffix);
}
current_prompt_len = cursor_col;
current_color = shell_config.command_color;
} }
cursor_col = 0;
char buf[5];
buf[0] = cmd_state ? cmd_state->current_drive : 'A';
buf[1] = ':';
buf[2] = '>';
buf[3] = ' ';
buf[4] = 0;
cmd_write(buf);
} }
static void cmd_clear_line_content(void) { void cmd_clear_line_content(void) {
int prompt_len = 4; // "A:> " int prompt_len = current_prompt_len;
for (int i = prompt_len; i < CMD_COLS; i++) { for (int i = prompt_len; i < CMD_COLS; i++) {
screen_buffer[cursor_row][i].c = ' '; screen_buffer[cursor_row][i].c = ' ';
screen_buffer[cursor_row][i].color = current_color; screen_buffer[cursor_row][i].color = current_color;
@ -200,7 +526,7 @@ static void cmd_scroll_up() {
// Clear bottom row // Clear bottom row
for (int c = 0; c < CMD_COLS; c++) { for (int c = 0; c < CMD_COLS; c++) {
screen_buffer[CMD_ROWS - 1][c].c = ' '; screen_buffer[CMD_ROWS - 1][c].c = ' ';
screen_buffer[CMD_ROWS - 1][c].color = current_color; screen_buffer[CMD_ROWS - 1][c].color = shell_config.default_text_color;
} }
} }
@ -224,10 +550,15 @@ void cmd_putchar(char c) {
if (c == '\n') { if (c == '\n') {
cursor_col = 0; cursor_col = 0;
cursor_row++; cursor_row++;
} else if (c == '\t') {
int spaces = 4 - (cursor_col % 4);
for (int i = 0; i < spaces; i++) cmd_putchar(' ');
return;
} else if (c == '\b') { } else if (c == '\b') {
if (cursor_col > 0) { if (cursor_col > 0) {
cursor_col--; cursor_col--;
screen_buffer[cursor_row][cursor_col].c = ' '; screen_buffer[cursor_row][cursor_col].c = ' ';
screen_buffer[cursor_row][cursor_col].color = shell_config.default_text_color;
} }
} else { } else {
if (cursor_col >= CMD_COLS) { if (cursor_col >= CMD_COLS) {
@ -252,7 +583,6 @@ void cmd_putchar(char c) {
// Trigger repaint so output from syscalls is immediately visible // Trigger repaint so output from syscalls is immediately visible
wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h); wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h);
wm_refresh();
} }
// Public for CLI apps to use // Public for CLI apps to use
@ -594,6 +924,22 @@ static void internal_cmd_exit(char *args) {
cmd_window_exit(); cmd_window_exit();
} }
static void internal_cmd_reload(char *args) {
(void)args;
cmd_load_config();
win_cmd.title = shell_config.title_text;
cmd_write("Configuration reloaded.\n");
cmd_print_prompt();
}
static void internal_cmd_cls(char *args) {
(void)args;
cmd_screen_clear();
cursor_row = 0;
cursor_col = 0;
cmd_print_prompt();
}
// Command dispatch table // Command dispatch table
typedef struct { typedef struct {
const char *name; const char *name;
@ -609,6 +955,12 @@ static const CommandEntry commands[] = {
{"exit", internal_cmd_exit}, {"exit", internal_cmd_exit},
{"CD", internal_cmd_cd}, {"CD", internal_cmd_cd},
{"cd", internal_cmd_cd}, {"cd", internal_cmd_cd},
{"RELOAD", internal_cmd_reload},
{"reload", internal_cmd_reload},
{"CLS", internal_cmd_cls},
{"cls", internal_cmd_cls},
{"CLEAR", internal_cmd_cls},
{"clear", internal_cmd_cls},
{NULL, NULL} {NULL, NULL}
}; };
@ -793,10 +1145,15 @@ static void cmd_exec_single(char *cmd) {
i += 2; i += 2;
while (args[i] == ' ') { temp_args[j++] = ' '; i++; } while (args[i] == ' ') { temp_args[j++] = ' '; i++; }
// Prepend drive to filename // Prepend drive and directory to filename if relative
if (args[i] && args[i+1] != ':') { if (args[i] && args[i+1] != ':') {
temp_args[j++] = cmd_state->current_drive; temp_args[j++] = cmd_state->current_drive;
temp_args[j++] = ':'; temp_args[j++] = ':';
if (args[i] != '/') {
const char *d = cmd_state->current_dir;
while (*d && j < 509) temp_args[j++] = *d++;
if (j > 2 && temp_args[j-1] != '/') temp_args[j++] = '/';
}
} }
in_redirect = true; in_redirect = true;
} else if (args[i] == '>' && args[i+1] != '>') { } else if (args[i] == '>' && args[i+1] != '>') {
@ -805,10 +1162,15 @@ static void cmd_exec_single(char *cmd) {
i++; i++;
while (args[i] == ' ') { temp_args[j++] = ' '; i++; } while (args[i] == ' ') { temp_args[j++] = ' '; i++; }
// Prepend drive to filename // Prepend drive and directory to filename if relative
if (args[i] && args[i+1] != ':') { if (args[i] && args[i+1] != ':') {
temp_args[j++] = cmd_state->current_drive; temp_args[j++] = cmd_state->current_drive;
temp_args[j++] = ':'; temp_args[j++] = ':';
if (args[i] != '/') {
const char *d = cmd_state->current_dir;
while (*d && j < 509) temp_args[j++] = *d++;
if (j > 2 && temp_args[j-1] != '/') temp_args[j++] = '/';
}
} }
in_redirect = true; in_redirect = true;
} else { } else {
@ -823,11 +1185,14 @@ static void cmd_exec_single(char *cmd) {
cmd_strcmp(cmd, "cc") == 0 || cmd_strcmp(cmd, "CC") == 0 || cmd_strcmp(cmd, "cc") == 0 || cmd_strcmp(cmd, "CC") == 0 ||
cmd_strcmp(cmd, "compc") == 0 || cmd_strcmp(cmd, "COMPC") == 0 || cmd_strcmp(cmd, "compc") == 0 || cmd_strcmp(cmd, "COMPC") == 0 ||
cmd_strcmp(cmd, "touch") == 0 || cmd_strcmp(cmd, "TOUCH") == 0 || cmd_strcmp(cmd, "touch") == 0 || cmd_strcmp(cmd, "TOUCH") == 0 ||
cmd_strcmp(cmd, "mkdir") == 0 || cmd_strcmp(cmd, "MKDIR") == 0 ||
cmd_strcmp(cmd, "rm") == 0 || cmd_strcmp(cmd, "RM") == 0 ||
cmd_strcmp(cmd, "ls") == 0 || cmd_strcmp(cmd, "LS") == 0 ||
cmd_strcmp(cmd, "cp") == 0 || cmd_strcmp(cmd, "CP") == 0 || cmd_strcmp(cmd, "cp") == 0 || cmd_strcmp(cmd, "CP") == 0 ||
cmd_strcmp(cmd, "mv") == 0 || cmd_strcmp(cmd, "MV") == 0 || cmd_strcmp(cmd, "mv") == 0 || cmd_strcmp(cmd, "MV") == 0 ||
cmd_strcmp(cmd, "txtedit") == 0 || cmd_strcmp(cmd, "TXTEDIT") == 0 || cmd_strcmp(cmd, "txtedit") == 0 || cmd_strcmp(cmd, "TXTEDIT") == 0 ||
cmd_strcmp(cmd, "tx") == 0 || cmd_strcmp(cmd, "TX") == 0) { cmd_strcmp(cmd, "tx") == 0 || cmd_strcmp(cmd, "TX") == 0) {
// For cat, cc, compc, touch, cp, mv, txtedit: prepend drive to file arguments if not already present // For filesystem commands: prepend drive and current directory if relative
if (args[1] == ':') { if (args[1] == ':') {
// Already has drive letter // Already has drive letter
cmd_strcpy(full_path_arg, args); cmd_strcpy(full_path_arg, args);
@ -1247,40 +1612,43 @@ static void cmd_exec(char *cmd) {
// --- Window Functions --- // --- Window Functions ---
static void cmd_paint(Window *win) { static void cmd_paint(Window *win) {
// Draw Window Content Background // Fill background
draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, shell_config.bg_color);
int offset_x = win->x + 4; int offset_x = win->x + 4;
int offset_y = win->y + 24; int offset_y = win->y + 24;
// Fill background - dark mode terminal
draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, COLOR_DARK_BG);
int start_y = offset_y + 4; int start_y = offset_y + 4;
int start_x = offset_x + 4; int start_x = offset_x + 4;
if (current_mode == MODE_PAGER) { if (current_mode == MODE_PAGER) {
// Draw Pager Content (Wrapped) // Draw Pager Content (Wrapped)
for (int i = 0; i < CMD_ROWS && (pager_top_line + i) < pager_total_lines; i++) { for (int i = 0; i < CMD_ROWS && (pager_top_line + i) < pager_total_lines; i++) {
draw_string(start_x, start_y + (i * LINE_HEIGHT), pager_wrapped_lines[pager_top_line + i], COLOR_DARK_TEXT); draw_string(start_x, start_y + (i * LINE_HEIGHT), pager_wrapped_lines[pager_top_line + i], shell_config.default_text_color);
} }
// Status Bar // Status Bar
draw_string(start_x, start_y + (CMD_ROWS * LINE_HEIGHT), "-- Press Q to quit --", COLOR_DARK_TEXT); draw_string(start_x, start_y + (CMD_ROWS * LINE_HEIGHT), "-- Press Q to quit --", shell_config.default_text_color);
} else { } else {
// Draw Cursor
if (win->focused) {
draw_rect(start_x + (cursor_col * CHAR_WIDTH), start_y + (cursor_row * LINE_HEIGHT),
CHAR_WIDTH, LINE_HEIGHT, shell_config.cursor_color);
}
// Draw Shell Buffer // Draw Shell Buffer
for (int r = 0; r < CMD_ROWS; r++) { for (int r = 0; r < CMD_ROWS; r++) {
for (int c = 0; c < CMD_COLS; c++) { for (int c = 0; c < CMD_COLS; c++) {
char ch = screen_buffer[r][c].c; char ch = screen_buffer[r][c].c;
if (ch != 0 && ch != ' ') { if (ch != 0 && ch != ' ') {
draw_char(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, screen_buffer[r][c].color); uint32_t color = screen_buffer[r][c].color;
// If cursor is on this character, and cursor color is bright, use background color for char
if (r == cursor_row && c == cursor_col && win->focused) {
color = shell_config.bg_color;
}
draw_char(start_x + (c * CHAR_WIDTH), start_y + (r * LINE_HEIGHT), ch, color);
} }
} }
} }
// Draw Cursor
if (win->focused) {
draw_rect(start_x + (cursor_col * CHAR_WIDTH), start_y + (cursor_row * LINE_HEIGHT) + 8, CHAR_WIDTH, 2, COLOR_WHITE);
}
} }
} }
@ -1301,17 +1669,18 @@ static void cmd_key(Window *target, char c) {
if (c == '\n') { // Enter if (c == '\n') { // Enter
char cmd_buf[CMD_COLS + 1]; char cmd_buf[CMD_COLS + 1];
int len = 0; int len = 0;
int prompt_len = 4; int prompt_len = current_prompt_len;
for (int i = prompt_len; i < CMD_COLS; i++) { for (int i = prompt_len; i < CMD_COLS; i++) {
char ch = screen_buffer[cursor_row][i].c; char ch = screen_buffer[cursor_row][i].c;
if (ch == 0) break; if (ch == 0 || (ch == ' ' && i > prompt_len && screen_buffer[cursor_row][i+1].c == 0)) break;
cmd_buf[len++] = ch; cmd_buf[len++] = ch;
} }
while (len > 0 && cmd_buf[len-1] == ' ') len--; while (len > 0 && cmd_buf[len-1] == ' ') len--;
cmd_buf[len] = 0; cmd_buf[len] = 0;
cmd_putchar('\n'); cmd_putchar('\n');
current_color = shell_config.default_text_color;
if (len > 0) cmd_history_add(cmd_buf); if (len > 0) cmd_history_add(cmd_buf);
history_pos = -1; history_pos = -1;
@ -1326,10 +1695,10 @@ static void cmd_key(Window *target, char c) {
if (history_pos == -1) { if (history_pos == -1) {
// Save current line // Save current line
int len = 0; int len = 0;
int prompt_len = 4; int prompt_len = current_prompt_len;
for (int i = prompt_len; i < CMD_COLS; i++) { for (int i = prompt_len; i < CMD_COLS; i++) {
char ch = screen_buffer[cursor_row][i].c; char ch = screen_buffer[cursor_row][i].c;
if (ch == 0) break; if (ch == 0 || (ch == ' ' && i > prompt_len && screen_buffer[cursor_row][i+1].c == 0)) break;
history_save_buf[len++] = ch; history_save_buf[len++] = ch;
} }
while (len > 0 && history_save_buf[len-1] == ' ') len--; while (len > 0 && history_save_buf[len-1] == ' ') len--;
@ -1356,7 +1725,7 @@ static void cmd_key(Window *target, char c) {
} }
} }
} else if (c == 19) { // LEFT } else if (c == 19) { // LEFT
if (cursor_col > 4) { if (cursor_col > current_prompt_len) {
cursor_col--; cursor_col--;
} }
} else if (c == 20) { // RIGHT } else if (c == 20) { // RIGHT
@ -1364,37 +1733,100 @@ static void cmd_key(Window *target, char c) {
cursor_col++; cursor_col++;
} }
} else if (c == '\b') { // Backspace } else if (c == '\b') { // Backspace
if (cursor_col > 4) { if (cursor_col > current_prompt_len) {
// Shift characters to the left
for (int i = cursor_col; i < CMD_COLS; i++) {
screen_buffer[cursor_row][i - 1] = screen_buffer[cursor_row][i];
}
screen_buffer[cursor_row][CMD_COLS - 1].c = ' ';
cursor_col--; cursor_col--;
screen_buffer[cursor_row][cursor_col].c = ' '; wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h);
} }
} else { } else {
if (c >= 32 && c <= 126) { if (c >= 32 && c <= 126) {
cmd_putchar(c); // Shift characters to the right
for (int i = CMD_COLS - 1; i > cursor_col; i--) {
screen_buffer[cursor_row][i] = screen_buffer[cursor_row][i - 1];
}
screen_buffer[cursor_row][cursor_col].c = c;
screen_buffer[cursor_row][cursor_col].color = current_color;
cursor_col++;
wm_mark_dirty(win_cmd.x, win_cmd.y, win_cmd.w, win_cmd.h);
} }
} }
} }
void cmd_reset(void) { void cmd_reset(void) {
// Reset terminal to fresh state // Reset terminal to fresh state
cmd_screen_clear(); cmd_load_config();
cmd_write("BoredOS Command Prompt\n");
if (msg_count > 0) { cursor_row = 0;
cmd_write("You have "); cursor_col = 0;
cmd_write_int(msg_count); current_color = shell_config.default_text_color;
cmd_write(" new message(s) run \"msgrc\" to see your new message(s).\n"); win_cmd.title = shell_config.title_text;
if (shell_config.welcome_msg) {
if (shell_config.custom_welcome_message[0]) {
cmd_write(shell_config.custom_welcome_message);
cmd_putchar('\n');
} else {
cmd_write("BoredOS Command Prompt\n");
}
} }
if (shell_config.startup_cmd[0]) {
// Run startup command without prompt prefix
cmd_exec(shell_config.startup_cmd);
}
cmd_print_prompt(); cmd_print_prompt();
} }
static void create_test_files(void) { static void create_ramfs_files(void) {
if (!fat32_exists("Documents")) fat32_mkdir("Documents"); if (!fat32_exists("Documents")) fat32_mkdir("Documents");
if (!fat32_exists("Projects")) fat32_mkdir("Projects"); if (!fat32_exists("Projects")) fat32_mkdir("Projects");
if (!fat32_exists("Documents/Important")) fat32_mkdir("Documents/Important"); if (!fat32_exists("Documents/Important")) fat32_mkdir("Documents/Important");
if (!fat32_exists("Apps")) fat32_mkdir("Apps"); if (!fat32_exists("Apps")) fat32_mkdir("Apps");
if (!fat32_exists("Desktop")) fat32_mkdir("Desktop"); if (!fat32_exists("Desktop")) fat32_mkdir("Desktop");
if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin"); if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin");
if (!fat32_exists("bin")) fat32_mkdir("bin"); if (!fat32_exists("Library/conf")) fat32_mkdir("Library/conf");
// Create default shell configuration file (commented out)
if (!fat32_exists("Library/conf/shell.cfg")) {
FAT32_FileHandle *cfg = fat32_open("Library/conf/shell.cfg", "w");
if (cfg) {
const char *config_content =
"// BoredOS Shell Configuration\n"
"// Colors: HEX (#RRGGBB), RGB (rgb(r,g,b)), or Names (red, blue, light blue, etc.)\n"
"// ---------------------------------------------------------------------------\n"
"// prompt_drive_color=white\n"
"// prompt_colon_color=gray\n"
"// prompt_dir_color=light blue\n"
"// prompt_op_color=white\n"
"// prompt_op_char=>\n"
"// prompt_suffix= \n"
"// default_text_color=light gray\n"
"// command_color=white\n"
"// bg_color=#1E1E1E\n"
"// cursor_color=white\n"
"// title_text=Command Prompt\n"
"// custom_welcome_message=\n"
"// startup_cmd=\n"
"// welcome_msg=true\n"
"// show_drive=true\n"
"// show_dir=true\n"
"// dir_color=light blue\n"
"// file_color=white\n"
"// size_color=light green\n"
"// error_color=light red\n"
"// success_color=light green\n"
"// help_color=light gray\n"
"// history_save_prompt=true\n";
fat32_write(cfg, (void *)config_content, cmd_strlen(config_content));
fat32_close(cfg);
}
}
@ -1596,14 +2028,18 @@ static void create_test_files(void) {
void cmd_init(void) { void cmd_init(void) {
create_test_files(); cmd_init_config_defaults();
create_ramfs_files();
create_man_entries(); create_man_entries();
// Load config after files are created
cmd_load_config();
win_cmd.title = "Command Prompt"; win_cmd.title = shell_config.title_text;
win_cmd.x = 50; win_cmd.x = 50;
win_cmd.y = 50; win_cmd.y = 50;
win_cmd.w = (CMD_COLS * CHAR_WIDTH) + 20; win_cmd.w = (CMD_COLS * CHAR_WIDTH) + 20;
win_cmd.h = (CMD_ROWS * LINE_HEIGHT) + 40; win_cmd.h = (CMD_ROWS * LINE_HEIGHT) + 50;
win_cmd.visible = false; win_cmd.visible = false;
win_cmd.focused = false; win_cmd.focused = false;

View file

@ -22,4 +22,7 @@ void cmd_screen_clear(void);
void cmd_increment_msg_count(void); void cmd_increment_msg_count(void);
void cmd_reset_msg_count(void); void cmd_reset_msg_count(void);
uint64_t cmd_get_config_value(const char *key);
void cmd_set_current_color(uint32_t color);
#endif #endif

View file

@ -9,7 +9,6 @@
#include "memory_manager.h" #include "memory_manager.h"
#include "cmd.h" #include "cmd.h"
#include "process.h" #include "process.h"
#include "about.h"
#define EXPLORER_ITEM_HEIGHT 80 #define EXPLORER_ITEM_HEIGHT 80
#define EXPLORER_ITEM_WIDTH 120 #define EXPLORER_ITEM_WIDTH 120
#define EXPLORER_COLS 4 #define EXPLORER_COLS 4
@ -853,7 +852,7 @@ static void explorer_open_item(Window *win, int index) {
} else if (explorer_strcmp(state->items[index].name, "Control Panel.shortcut") == 0 || explorer_strcmp(state->items[index].name, "Settings.shortcut") == 0) { } else if (explorer_strcmp(state->items[index].name, "Control Panel.shortcut") == 0 || explorer_strcmp(state->items[index].name, "Settings.shortcut") == 0) {
process_create_elf("/bin/settings.elf", NULL); return; process_create_elf("/bin/settings.elf", NULL); return;
} else if (explorer_strcmp(state->items[index].name, "About.shortcut") == 0) { } else if (explorer_strcmp(state->items[index].name, "About.shortcut") == 0) {
target = &win_about; process_create_elf("/bin/about.elf", NULL); return;
} else if (explorer_strcmp(state->items[index].name, "Explorer.shortcut") == 0) { } else if (explorer_strcmp(state->items[index].name, "Explorer.shortcut") == 0) {
explorer_open_directory("/"); return; explorer_open_directory("/"); return;
} else if (explorer_strcmp(state->items[index].name, "Recycle Bin.shortcut") == 0) { } else if (explorer_strcmp(state->items[index].name, "Recycle Bin.shortcut") == 0) {

View file

@ -294,7 +294,8 @@ uint64_t process_terminate_current(void) {
if (!current_process) return 0; if (!current_process) return 0;
// 1. Cleanup side effects // 1. Cleanup side effects
if (current_process->ui_window && !current_process->is_terminal_proc) { extern Window win_cmd;
if (current_process->ui_window && (current_process->ui_window != &win_cmd)) {
extern void serial_write(const char *str); extern void serial_write(const char *str);
serial_write("PROC: Terminating proc with window\n"); serial_write("PROC: Terminating proc with window\n");
wm_remove_window((Window *)current_process->ui_window); wm_remove_window((Window *)current_process->ui_window);

View file

@ -15,6 +15,7 @@
#include "kutils.h" #include "kutils.h"
#include "network.h" #include "network.h"
#include "icmp.h" #include "icmp.h"
#include "cmd.h"
// Read MSR // Read MSR
static inline uint64_t rdmsr(uint32_t msr) { static inline uint64_t rdmsr(uint32_t msr) {
@ -136,10 +137,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
extern void cmd_process_finished(void); extern void cmd_process_finished(void);
if (syscall_num == 1) { // SYS_WRITE if (syscall_num == 1) { // SYS_WRITE
// arg2 is the buffer based on our user_test logic
cmd_write((const char*)arg2); cmd_write((const char*)arg2);
} else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT } else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT
serial_write("Kernel: SYS_EXIT called\n");
uint64_t next_rsp = process_terminate_current(); uint64_t next_rsp = process_terminate_current();
extern void context_switch_to(uint64_t rsp); extern void context_switch_to(uint64_t rsp);
context_switch_to(next_rsp); context_switch_to(next_rsp);
@ -724,6 +723,14 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
return cli_cmd_ping_syscall(dest_ip); return cli_cmd_ping_syscall(dest_ip);
} else if (cmd == 27) { // SYSTEM_CMD_NETWORK_IS_INIT } else if (cmd == 27) { // SYSTEM_CMD_NETWORK_IS_INIT
return network_is_initialized() ? 1 : 0; return network_is_initialized() ? 1 : 0;
} else if (cmd == 28) { // SYSTEM_CMD_GET_SHELL_CONFIG
const char *key = (const char *)arg2;
if (!key) return -1;
return cmd_get_config_value(key);
} else if (cmd == 29) { // SYSTEM_CMD_SET_TEXT_COLOR
uint32_t color = (uint32_t)arg2;
cmd_set_current_color(color);
return 0;
} }
return -1; return -1;
} }

View file

@ -0,0 +1,83 @@
// 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 "syscall.h"
#include "libui.h"
#include <stddef.h>
static void draw_boredos_logo(ui_window_t win, int x, int y, int scale) {
static const uint8_t brewos_bmp[] = {
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0,
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0
};
for (int r = 0; r < 16; r++) {
for (int c = 0; c < 16; c++) {
uint8_t p = brewos_bmp[r * 16 + c];
if (p == 1) {
ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFF1A1A1A);
} else if (p == 2) {
ui_draw_rect(win, x + c * scale, y + r * scale, scale, scale, 0xFFFEFEFE);
}
}
}
}
static void about_paint(ui_window_t win) {
int w = 185;
int h = 240;
//ui_draw_rect(win, 0, 0, w, h, 0xFF1E1E1E);
int offset_x = 15;
int offset_y = 35;
draw_boredos_logo(win, 60, offset_y, 4);
// Version info
ui_draw_string(win, offset_x, offset_y + 105, "BoredOS 'Panda'", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 120, "BoredOS Version 1.64", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 135, "Kernel Version 3.0.0", 0xFFFFFFFF);
// Copyright
ui_draw_string(win, offset_x, offset_y + 150, "(C) 2026 boreddevnl.", 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 165, "All rights reserved.", 0xFFFFFFFF);
ui_mark_dirty(win, 0, 0, w, h);
}
int main(void) {
ui_window_t win_about = ui_window_create("About BoredOS", 250, 180, 185, 240);
about_paint(win_about);
gui_event_t ev;
while (1) {
if (ui_get_event(win_about, &ev)) {
if (ev.type == GUI_EVENT_PAINT) {
about_paint(win_about);
} else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0);
}
} else {
// Avoid high CPU usage
for(volatile int i=0; i<10000; i++);
}
}
return 0;
}

View file

@ -5,6 +5,9 @@
#include <syscall.h> #include <syscall.h>
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t error_color = (uint32_t)sys_get_shell_config("error_color");
uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color");
if (argc < 2) { if (argc < 2) {
printf("Usage: cat <filename>\n"); printf("Usage: cat <filename>\n");
return 1; return 1;
@ -12,7 +15,9 @@ int main(int argc, char **argv) {
int fd = sys_open(argv[1], "r"); int fd = sys_open(argv[1], "r");
if (fd < 0) { if (fd < 0) {
sys_set_text_color(error_color);
printf("Error: Cannot open %s\n", argv[1]); printf("Error: Cannot open %s\n", argv[1]);
sys_set_text_color(default_color);
return 1; return 1;
} }

View file

@ -13,6 +13,9 @@
#define STR_POOL_SIZE 16384 #define STR_POOL_SIZE 16384
static int compile_error = 0; static int compile_error = 0;
static uint32_t color_error = 0xFFFF4444;
static uint32_t color_success = 0xFF6A9955;
static uint32_t color_default = 0xFFCCCCCC;
// --- Lexer --- // --- Lexer ---
typedef enum { typedef enum {
@ -59,7 +62,9 @@ static Token tokens[MAX_TOKENS];
static int token_count = 0; static int token_count = 0;
static void lex_error(const char *msg) { static void lex_error(const char *msg) {
sys_set_text_color(color_error);
printf("Compiler Error: %s\n", msg); printf("Compiler Error: %s\n", msg);
sys_set_text_color(color_default);
compile_error = 1; compile_error = 1;
} }
@ -304,7 +309,12 @@ static int add_symbol(const char *name) {
static void emit(uint8_t b) { static void emit(uint8_t b) {
if (code_pos < CODE_SIZE) code[code_pos++] = b; if (code_pos < CODE_SIZE) code[code_pos++] = b;
else { printf("Error: Code buffer overflow\n"); compile_error = 1; } else {
sys_set_text_color(color_error);
printf("Error: Code buffer overflow\n");
sys_set_text_color(color_default);
compile_error = 1;
}
} }
static void emit32(int v) { static void emit32(int v) {
@ -323,7 +333,12 @@ static int add_string(const char *str) {
static void match(TokenType t) { static void match(TokenType t) {
if (compile_error) return; if (compile_error) return;
if (tokens[cur_token].type == t) cur_token++; if (tokens[cur_token].type == t) cur_token++;
else { printf("Syntax Error: Expected token %d got %d\n", t, tokens[cur_token].type); compile_error = 1; } else {
sys_set_text_color(color_error);
printf("Syntax Error: Expected token %d got %d\n", t, tokens[cur_token].type);
sys_set_text_color(color_default);
compile_error = 1;
}
} }
static void expression(); static void expression();
@ -352,11 +367,21 @@ static void factor() {
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) function_call(syscall); if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) function_call(syscall);
else { else {
int addr = find_symbol(tokens[cur_token].str_val); int addr = find_symbol(tokens[cur_token].str_val);
if (addr == -1) { printf("Error: Undefined variable: %s\n", tokens[cur_token].str_val); compile_error = 1; } if (addr == -1) {
sys_set_text_color(color_error);
printf("Error: Undefined variable: %s\n", tokens[cur_token].str_val);
sys_set_text_color(color_default);
compile_error = 1;
}
emit(OP_LOAD); emit32(addr); cur_token++; emit(OP_LOAD); emit32(addr); cur_token++;
} }
} else if (tokens[cur_token].type == TOK_LPAREN) { cur_token++; expression(); match(TOK_RPAREN); } } else if (tokens[cur_token].type == TOK_LPAREN) { cur_token++; expression(); match(TOK_RPAREN); }
else { printf("Syntax Error: Unexpected token in factor\n"); compile_error = 1; } else {
sys_set_text_color(color_error);
printf("Syntax Error: Unexpected token in factor\n");
sys_set_text_color(color_default);
compile_error = 1;
}
} }
static void term() { static void term() {
@ -461,10 +486,19 @@ static void program() {
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
color_error = (uint32_t)sys_get_shell_config("error_color");
color_success = (uint32_t)sys_get_shell_config("success_color");
color_default = (uint32_t)sys_get_shell_config("default_text_color");
if (argc < 2) { printf("Usage: cc <filename.c>\n"); return 1; } if (argc < 2) { printf("Usage: cc <filename.c>\n"); return 1; }
int fh = sys_open(argv[1], "r"); int fh = sys_open(argv[1], "r");
if (fh < 0) { printf("Error: Cannot open source file.\n"); return 1; } if (fh < 0) {
sys_set_text_color(color_error);
printf("Error: Cannot open source file.\n");
sys_set_text_color(color_default);
return 1;
}
char *source = (char*)malloc(MAX_SOURCE); char *source = (char*)malloc(MAX_SOURCE);
if (!source) { printf("Error: Out of memory for source buffer.\n"); sys_close(fh); return 1; } if (!source) { printf("Error: Out of memory for source buffer.\n"); sys_close(fh); return 1; }
@ -515,8 +549,14 @@ int main(int argc, char **argv) {
if (out_fh >= 0) { if (out_fh >= 0) {
sys_write_fs(out_fh, code, code_pos); sys_write_fs(out_fh, code, code_pos);
sys_close(out_fh); sys_close(out_fh);
sys_set_text_color(color_success);
printf("Compilation successful. Output: %s\n", out_name); printf("Compilation successful. Output: %s\n", out_name);
} else { printf("Error: Cannot write output file.\n"); } sys_set_text_color(color_default);
} else {
sys_set_text_color(color_error);
printf("Error: Cannot write output file.\n");
sys_set_text_color(color_default);
}
return 0; return 0;
} }

View file

@ -6,6 +6,9 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
(void)argc; (void)argv; (void)argc; (void)argv;
uint32_t help_color = sys_get_shell_config("help_color");
if (help_color != 0) sys_set_text_color(help_color);
printf("BoredOS CLI Help\n"); printf("BoredOS CLI Help\n");
printf("---------------------------\n"); printf("---------------------------\n");
printf("ls [path] - List directory contents\n"); printf("ls [path] - List directory contents\n");

View file

@ -179,3 +179,11 @@ int sys_network_is_initialized(void) {
return (int)syscall2(SYS_SYSTEM, SYSTEM_CMD_NETWORK_IS_INIT, 0); return (int)syscall2(SYS_SYSTEM, SYSTEM_CMD_NETWORK_IS_INIT, 0);
} }
uint64_t sys_get_shell_config(const char *key) {
return (uint64_t)sys_system(SYSTEM_CMD_GET_SHELL_CONFIG, (uint64_t)key, 0, 0, 0);
}
void sys_set_text_color(uint32_t color) {
sys_system(SYSTEM_CMD_SET_TEXT_COLOR, (uint64_t)color, 0, 0, 0);
}

View file

@ -56,6 +56,8 @@
#define SYSTEM_CMD_NETWORK_GET_DNS 25 #define SYSTEM_CMD_NETWORK_GET_DNS 25
#define SYSTEM_CMD_ICMP_PING 26 #define SYSTEM_CMD_ICMP_PING 26
#define SYSTEM_CMD_NETWORK_IS_INIT 27 #define SYSTEM_CMD_NETWORK_IS_INIT 27
#define SYSTEM_CMD_GET_SHELL_CONFIG 28
#define SYSTEM_CMD_SET_TEXT_COLOR 29
// Internal assembly entry into Ring 0 // Internal assembly entry into Ring 0
extern uint64_t syscall0(uint64_t sys_num); extern uint64_t syscall0(uint64_t sys_num);
@ -113,4 +115,7 @@ int sys_udp_send(const net_ipv4_address_t *dest_ip, uint16_t dest_port, uint16_t
int sys_icmp_ping(const net_ipv4_address_t *dest_ip); int sys_icmp_ping(const net_ipv4_address_t *dest_ip);
int sys_network_is_initialized(void); int sys_network_is_initialized(void);
uint64_t sys_get_shell_config(const char *key);
void sys_set_text_color(uint32_t color);
#endif #endif

View file

@ -5,12 +5,18 @@
#include <syscall.h> #include <syscall.h>
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t dir_color = (uint32_t)sys_get_shell_config("dir_color");
uint32_t file_color = (uint32_t)sys_get_shell_config("file_color");
uint32_t size_color = (uint32_t)sys_get_shell_config("size_color");
uint32_t error_color = (uint32_t)sys_get_shell_config("error_color");
uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color");
char path[256]; char path[256];
if (argc > 1) { if (argc > 1) {
strcpy(path, argv[1]); strcpy(path, argv[1]);
} else { } else {
if (!getcwd(path, sizeof(path))) { if (!sys_getcwd(path, sizeof(path))) {
strcpy(path, "."); strcpy(path, "/");
} }
} }
@ -18,18 +24,25 @@ int main(int argc, char **argv) {
int count = sys_list(path, entries, 128); int count = sys_list(path, entries, 128);
if (count < 0) { if (count < 0) {
sys_set_text_color(error_color);
printf("Error: Cannot list directory %s\n", path); printf("Error: Cannot list directory %s\n", path);
sys_set_text_color(default_color);
return 1; return 1;
} }
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (entries[i].is_directory) { if (entries[i].is_directory) {
sys_set_text_color(dir_color);
printf("[DIR] %s\n", entries[i].name); printf("[DIR] %s\n", entries[i].name);
} else { } else {
printf("[FILE] %s (%d bytes)\n", entries[i].name, entries[i].size); sys_set_text_color(file_color);
printf("[FILE] %s", entries[i].name);
sys_set_text_color(size_color);
printf(" (%d bytes)\n", entries[i].size);
} }
} }
sys_set_text_color(default_color);
printf("\nTotal: %d items\n", count); printf("\nTotal: %d items\n", count);
return 0; return 0;
} }

View file

@ -5,16 +5,24 @@
#include <syscall.h> #include <syscall.h>
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t error_color = (uint32_t)sys_get_shell_config("error_color");
uint32_t success_color = (uint32_t)sys_get_shell_config("success_color");
uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color");
if (argc < 2) { if (argc < 2) {
printf("Usage: mkdir <dirname>\n"); printf("Usage: mkdir <dirname>\n");
return 1; return 1;
} }
if (sys_mkdir(argv[1]) == 0) { if (sys_mkdir(argv[1]) == 0) {
sys_set_text_color(success_color);
printf("Created directory: %s\n", argv[1]); printf("Created directory: %s\n", argv[1]);
} else { } else {
sys_set_text_color(error_color);
printf("Error: Cannot create directory %s\n", argv[1]); printf("Error: Cannot create directory %s\n", argv[1]);
sys_set_text_color(default_color);
return 1; return 1;
} }
sys_set_text_color(default_color);
return 0; return 0;
} }

View file

@ -5,6 +5,10 @@
#include <syscall.h> #include <syscall.h>
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t error_color = (uint32_t)sys_get_shell_config("error_color");
uint32_t success_color = (uint32_t)sys_get_shell_config("success_color");
uint32_t default_color = (uint32_t)sys_get_shell_config("default_text_color");
if (argc < 2) { if (argc < 2) {
printf("Usage: rm <path>\n"); printf("Usage: rm <path>\n");
return 1; return 1;
@ -12,10 +16,14 @@ int main(int argc, char **argv) {
// Simple rm (no recursive support yet for simplicity, but can be added) // Simple rm (no recursive support yet for simplicity, but can be added)
if (sys_delete(argv[1]) == 0) { if (sys_delete(argv[1]) == 0) {
sys_set_text_color(success_color);
printf("Deleted: %s\n", argv[1]); printf("Deleted: %s\n", argv[1]);
} else { } else {
sys_set_text_color(error_color);
printf("Error: Cannot delete %s\n", argv[1]); printf("Error: Cannot delete %s\n", argv[1]);
sys_set_text_color(default_color);
return 1; return 1;
} }
sys_set_text_color(default_color);
return 0; return 0;
} }

View file

@ -12,7 +12,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include "wallpaper.h" #include "wallpaper.h"
#include "about.h"
#include "fat32.h" #include "fat32.h"
#include "nanojpeg.h" #include "nanojpeg.h"
#include "memory_manager.h" #include "memory_manager.h"
@ -1583,7 +1582,7 @@ void wm_handle_click(int x, int y) {
int item = rel_y / 20; int item = rel_y / 20;
if (item == 0) { // About if (item == 0) { // About
wm_bring_to_front(&win_about); process_create_elf("/bin/about.elf", NULL);
} else if (item == 1) { // Settings } else if (item == 1) { // Settings
Window *existing = wm_find_window_by_title("Settings"); Window *existing = wm_find_window_by_title("Settings");
if (existing) wm_bring_to_front(existing); if (existing) wm_bring_to_front(existing);
@ -1882,7 +1881,7 @@ void wm_handle_right_click(int x, int y) {
if (existing) wm_bring_to_front(existing); if (existing) wm_bring_to_front(existing);
else process_create_elf("/bin/paint.elf", NULL); else process_create_elf("/bin/paint.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "About")) { } else if (str_starts_with(start_menu_pending_app, "About")) {
wm_bring_to_front(&win_about); process_create_elf("/bin/about.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "Shutdown")) { } else if (str_starts_with(start_menu_pending_app, "Shutdown")) {
k_shutdown(); k_shutdown();
} else if (str_starts_with(start_menu_pending_app, "Restart")) { } else if (str_starts_with(start_menu_pending_app, "Restart")) {
@ -1912,7 +1911,7 @@ void wm_handle_right_click(int x, int y) {
} else if (str_ends_with(icon->name, "Terminal.shortcut")) { } else if (str_ends_with(icon->name, "Terminal.shortcut")) {
wm_bring_to_front(&win_cmd); handled = true; wm_bring_to_front(&win_cmd); handled = true;
} else if (str_ends_with(icon->name, "About.shortcut")) { } else if (str_ends_with(icon->name, "About.shortcut")) {
wm_bring_to_front(&win_about); handled = true; process_create_elf("/bin/about.elf", NULL); handled = true;
} else if (str_ends_with(icon->name, "Files.shortcut")) { } else if (str_ends_with(icon->name, "Files.shortcut")) {
explorer_open_directory("/"); handled = true; explorer_open_directory("/"); handled = true;
} else if (str_ends_with(icon->name, "Recycle Bin.shortcut")) { } else if (str_ends_with(icon->name, "Recycle Bin.shortcut")) {
@ -2379,7 +2378,6 @@ void wm_init(void) {
cmd_init(); cmd_init();
explorer_init(); explorer_init();
about_init();
wallpaper_init(); wallpaper_init();
refresh_desktop_icons(); refresh_desktop_icons();
@ -2387,19 +2385,16 @@ void wm_init(void) {
// Initialize z-indices // Initialize z-indices
win_cmd.z_index = 0; win_cmd.z_index = 0;
win_explorer.z_index = 1; win_explorer.z_index = 1;
win_about.z_index = 2;
all_windows[0] = &win_cmd; all_windows[0] = &win_cmd;
all_windows[1] = &win_explorer; all_windows[1] = &win_explorer;
all_windows[2] = &win_about; window_count = 2;
window_count = 3;
win_explorer.visible = false; win_explorer.visible = false;
win_explorer.focused = false; win_explorer.focused = false;
win_explorer.z_index = 10; win_explorer.z_index = 10;
win_cmd.visible = false; win_cmd.visible = false;
win_about.visible = false;
force_redraw = true; force_redraw = true;
} }