src/kernel --> src/

This commit is contained in:
boreddevnl
2026-03-16 00:30:47 +01:00
parent 3da1496e4f
commit fc83d7941b
630 changed files with 2 additions and 2 deletions

32
src/userland/cli/cat.c Normal file
View File

@@ -0,0 +1,32 @@
// 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) {
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) {
printf("Usage: cat <filename>\n");
return 1;
}
int fd = sys_open(argv[1], "r");
if (fd < 0) {
sys_set_text_color(error_color);
printf("Error: Cannot open %s\n", argv[1]);
sys_set_text_color(default_color);
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
sys_write(1, buffer, bytes);
}
sys_close(fd);
return 0;
}

562
src/userland/cli/cc.c Normal file
View File

@@ -0,0 +1,562 @@
// 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>
#include "../../mem/vm.h"
// --- Compiler Limits ---
#define MAX_SOURCE 65536
#define MAX_TOKENS 16384
#define MAX_VARS 512
#define CODE_SIZE 32768
#define STR_POOL_SIZE 16384
static int compile_error = 0;
static uint32_t color_error = 0xFFFF4444;
static uint32_t color_success = 0xFF6A9955;
static uint32_t color_default = 0xFFCCCCCC;
// --- Lexer ---
typedef enum {
TOK_EOF,
TOK_INT, // 123, 0xFF
TOK_STRING, // "hello"
TOK_ID, // abc
TOK_PLUS, // +
TOK_MINUS, // -
TOK_MUL, // *
TOK_DIV, // /
TOK_ASSIGN, // =
TOK_LPAREN, // (
TOK_RPAREN, // )
TOK_LBRACKET, // [
TOK_RBRACKET, // ]
TOK_LBRACE, // {
TOK_RBRACE, // }
TOK_SEMI, // ;
TOK_COMMA, // ,
TOK_EQ, // ==
TOK_NEQ, // !=
TOK_LT, // <
TOK_GT, // >
TOK_LE, // <=
TOK_GE, // >=
TOK_IF, // if
TOK_ELSE, // else
TOK_WHILE, // while
TOK_INT_TYPE, // int
TOK_CHAR_TYPE,// char
TOK_VOID_TYPE,// void
TOK_MAIN // main
} TokenType;
typedef struct {
TokenType type;
int int_val;
char str_val[64]; // Identifier or String Content
} Token;
static char *source_ptr;
static Token tokens[MAX_TOKENS];
static int token_count = 0;
static void lex_error(const char *msg) {
sys_set_text_color(color_error);
printf("Compiler Error: %s\n", msg);
sys_set_text_color(color_default);
compile_error = 1;
}
static void lexer(const char *source) {
source_ptr = (char*)source;
token_count = 0;
compile_error = 0;
while (*source_ptr) {
while (*source_ptr == ' ' || *source_ptr == '\n' || *source_ptr == '\t' || *source_ptr == '\r') source_ptr++;
if (!*source_ptr) break;
if (*source_ptr == '/' && *(source_ptr+1) == '/') {
while (*source_ptr && *source_ptr != '\n') source_ptr++;
continue;
}
Token *t = &tokens[token_count++];
if (*source_ptr == '0' && (*(source_ptr+1) == 'x' || *(source_ptr+1) == 'X')) {
source_ptr += 2;
t->type = TOK_INT;
t->int_val = 0;
int has_digits = 0;
while ((*source_ptr >= '0' && *source_ptr <= '9') ||
(*source_ptr >= 'a' && *source_ptr <= 'f') ||
(*source_ptr >= 'A' && *source_ptr <= 'F')) {
int digit = 0;
if (*source_ptr >= '0' && *source_ptr <= '9') digit = *source_ptr - '0';
else if (*source_ptr >= 'a' && *source_ptr <= 'f') digit = *source_ptr - 'a' + 10;
else if (*source_ptr >= 'A' && *source_ptr <= 'F') digit = *source_ptr - 'A' + 10;
t->int_val = (t->int_val << 4) | digit;
source_ptr++;
has_digits = 1;
}
if (!has_digits) { lex_error("Invalid hex literal"); return; }
} else if (*source_ptr >= '0' && *source_ptr <= '9') {
t->type = TOK_INT;
t->int_val = 0;
while (*source_ptr >= '0' && *source_ptr <= '9') {
t->int_val = t->int_val * 10 + (*source_ptr - '0');
source_ptr++;
}
} else if (*source_ptr == '"') {
t->type = TOK_STRING;
source_ptr++;
int len = 0;
while (*source_ptr && *source_ptr != '"') {
if (*source_ptr == '\\' && *(source_ptr+1) == 'n') {
if (len < 63) t->str_val[len++] = '\n';
source_ptr += 2;
} else {
if (len < 63) t->str_val[len++] = *source_ptr;
source_ptr++;
}
}
t->str_val[len] = 0;
if (*source_ptr == '"') source_ptr++;
} else if (*source_ptr == '\'') {
t->type = TOK_INT;
source_ptr++;
char c = 0;
if (*source_ptr == '\\') {
source_ptr++;
if (*source_ptr == 'n') c = '\n';
else if (*source_ptr == 't') c = '\t';
else if (*source_ptr == '0') c = '\0';
else if (*source_ptr == '\\') c = '\\';
else if (*source_ptr == '\'') c = '\'';
else c = *source_ptr;
source_ptr++;
} else {
c = *source_ptr;
source_ptr++;
}
if (*source_ptr == '\'') source_ptr++;
else { lex_error("Expected closing '"); return; }
t->int_val = (int)c;
} else if ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || *source_ptr == '_') {
int len = 0;
while ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || (*source_ptr >= '0' && *source_ptr <= '9') || *source_ptr == '_') {
if (len < 63) t->str_val[len++] = *source_ptr;
source_ptr++;
}
t->str_val[len] = 0;
if (strcmp(t->str_val, "if") == 0) t->type = TOK_IF;
else if (strcmp(t->str_val, "else") == 0) t->type = TOK_ELSE;
else if (strcmp(t->str_val, "while") == 0) t->type = TOK_WHILE;
else if (strcmp(t->str_val, "int") == 0) t->type = TOK_INT_TYPE;
else if (strcmp(t->str_val, "char") == 0) t->type = TOK_CHAR_TYPE;
else if (strcmp(t->str_val, "void") == 0) t->type = TOK_VOID_TYPE;
else if (strcmp(t->str_val, "main") == 0) t->type = TOK_MAIN;
else t->type = TOK_ID;
} else {
switch (*source_ptr) {
case '+': t->type = TOK_PLUS; break;
case '-': t->type = TOK_MINUS; break;
case '*': t->type = TOK_MUL; break;
case '/': t->type = TOK_DIV; break;
case '(': t->type = TOK_LPAREN; break;
case ')': t->type = TOK_RPAREN; break;
case '[': t->type = TOK_LBRACKET; break;
case ']': t->type = TOK_RBRACKET; break;
case '{': t->type = TOK_LBRACE; break;
case '}': t->type = TOK_RBRACE; break;
case ';': t->type = TOK_SEMI; break;
case ',': t->type = TOK_COMMA; break;
case '=':
if (*(source_ptr+1) == '=') { t->type = TOK_EQ; source_ptr++; }
else t->type = TOK_ASSIGN;
break;
case '!':
if (*(source_ptr+1) == '=') { t->type = TOK_NEQ; source_ptr++; }
else { lex_error("Unexpected !"); return; }
break;
case '<':
if (*(source_ptr+1) == '=') { t->type = TOK_LE; source_ptr++; }
else t->type = TOK_LT;
break;
case '>':
if (*(source_ptr+1) == '=') { t->type = TOK_GE; source_ptr++; }
else t->type = TOK_GT;
break;
default: lex_error("Unknown char"); return;
}
source_ptr++;
}
}
tokens[token_count].type = TOK_EOF;
}
typedef struct {
const char *name;
int syscall_id;
} Builtin;
static const Builtin builtins[] = {
{"exit", VM_SYS_EXIT},
{"print_int", VM_SYS_PRINT_INT},
{"print_char", VM_SYS_PRINT_CHAR},
{"print_str", VM_SYS_PRINT_STR},
{"print", VM_SYS_PRINT_INT},
{"pritc", VM_SYS_PRINT_CHAR},
{"puts", VM_SYS_PRINT_STR},
{"nl", VM_SYS_NL},
{"cls", VM_SYS_CLS},
{"getchar", VM_SYS_GETCHAR},
{"strlen", VM_SYS_STRLEN},
{"strcmp", VM_SYS_STRCMP},
{"strcpy", VM_SYS_STRCPY},
{"strcat", VM_SYS_STRCAT},
{"memset", VM_SYS_MEMSET},
{"memcpy", VM_SYS_MEMCPY},
{"malloc", VM_SYS_MALLOC},
{"free", VM_SYS_FREE},
{"rand", VM_SYS_RAND},
{"srand", VM_SYS_SRAND},
{"abs", VM_SYS_ABS},
{"min", VM_SYS_MIN},
{"max", VM_SYS_MAX},
{"pow", VM_SYS_POW},
{"sqrt", VM_SYS_SQRT},
{"sleep", VM_SYS_SLEEP},
{"fopen", VM_SYS_FOPEN},
{"fclose", VM_SYS_FCLOSE},
{"fread", VM_SYS_FREAD},
{"fwrite", VM_SYS_FWRITE},
{"fseek", VM_SYS_FSEEK},
{"remove", VM_SYS_REMOVE},
{"draw_pixel", VM_SYS_DRAW_PIXEL},
{"draw_rect", VM_SYS_DRAW_RECT},
{"draw_line", VM_SYS_DRAW_LINE},
{"draw_text", VM_SYS_DRAW_TEXT},
{"get_width", VM_SYS_GET_WIDTH},
{"get_height", VM_SYS_GET_HEIGHT},
{"get_time", VM_SYS_GET_TIME},
{"kb_hit", VM_SYS_KB_HIT},
{"mouse_x", VM_SYS_MOUSE_X},
{"mouse_y", VM_SYS_MOUSE_Y},
{"mouse_state", VM_SYS_MOUSE_STATE},
{"play_sound", VM_SYS_PLAY_SOUND},
{"atoi", VM_SYS_ATOI},
{"itoa", VM_SYS_ITOA},
{"peek", VM_SYS_PEEK},
{"poke", VM_SYS_POKE},
{"exec", VM_SYS_EXEC},
{"system", VM_SYS_SYSTEM},
{"strchr", VM_SYS_STRCHR},
{"memcmp", VM_SYS_MEMCMP},
{"isalnum", VM_SYS_ISALNUM},
{"isalpha", VM_SYS_ISALPHA},
{"isdigit", VM_SYS_ISDIGIT},
{"tolower", VM_SYS_TOLOWER},
{"toupper", VM_SYS_TOUPPER},
{"strncpy", VM_SYS_STRNCPY},
{"strncat", VM_SYS_STRNCAT},
{"strncmp", VM_SYS_STRNCMP},
{"strstr", VM_SYS_STRSTR},
{"strrchr", VM_SYS_STRRCHR},
{"memmove", VM_SYS_MEMMOVE},
{NULL, 0}
};
static int find_builtin(const char *name) {
for (int i = 0; builtins[i].name != NULL; i++) {
if (strcmp(builtins[i].name, name) == 0) return builtins[i].syscall_id;
}
return -1;
}
static uint8_t code[CODE_SIZE];
static int code_pos = 0;
static int cur_token = 0;
static uint8_t str_pool[STR_POOL_SIZE];
static int str_pool_pos = 0;
typedef struct {
char name[32];
int addr;
} Symbol;
static Symbol symbols[MAX_VARS];
static int symbol_count = 0;
static int next_var_addr = 32768;
static int find_symbol(const char *name) {
for (int i = 0; i < symbol_count; i++) {
if (strcmp(symbols[i].name, name) == 0) return symbols[i].addr;
}
return -1;
}
static int add_symbol(const char *name) {
int existing = find_symbol(name);
if (existing != -1) return existing;
if (symbol_count >= MAX_VARS) return -1;
strcpy(symbols[symbol_count].name, name);
symbols[symbol_count].addr = next_var_addr;
next_var_addr += 4;
return symbol_count++;
}
static void emit(uint8_t b) {
if (code_pos < CODE_SIZE) code[code_pos++] = b;
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) {
emit(v & 0xFF); emit((v >> 8) & 0xFF); emit((v >> 16) & 0xFF); emit((v >> 24) & 0xFF);
}
static int add_string(const char *str) {
int start = str_pool_pos;
int len = strlen(str);
if (str_pool_pos + len + 1 >= STR_POOL_SIZE) { printf("Error: String pool overflow\n"); compile_error = 1; return 0; }
for(int i=0; i<len; i++) str_pool[str_pool_pos++] = str[i];
str_pool[str_pool_pos++] = 0;
return start;
}
static void match(TokenType t) {
if (compile_error) return;
if (tokens[cur_token].type == t) cur_token++;
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 statement();
static void block();
static void function_call(int syscall_id) {
if (compile_error) return;
cur_token++;
match(TOK_LPAREN);
if (tokens[cur_token].type != TOK_RPAREN) {
expression();
while (tokens[cur_token].type == TOK_COMMA) { cur_token++; expression(); }
}
match(TOK_RPAREN);
emit(OP_SYSCALL);
emit32(syscall_id);
}
static void factor() {
if (compile_error) return;
if (tokens[cur_token].type == TOK_INT) { emit(OP_IMM); emit32(tokens[cur_token].int_val); cur_token++; }
else if (tokens[cur_token].type == TOK_STRING) { int offset = add_string(tokens[cur_token].str_val); emit(OP_PUSH_PTR); emit32(offset); cur_token++; }
else if (tokens[cur_token].type == TOK_ID) {
int syscall = find_builtin(tokens[cur_token].str_val);
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) function_call(syscall);
else {
int addr = find_symbol(tokens[cur_token].str_val);
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++;
}
} else if (tokens[cur_token].type == TOK_LPAREN) { cur_token++; expression(); match(TOK_RPAREN); }
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() {
if (compile_error) return;
factor();
while (tokens[cur_token].type == TOK_MUL || tokens[cur_token].type == TOK_DIV) {
TokenType op = tokens[cur_token].type; cur_token++; factor();
if (op == TOK_MUL) emit(OP_MUL); else emit(OP_DIV);
}
}
static void additive() {
if (compile_error) return;
term();
while (tokens[cur_token].type == TOK_PLUS || tokens[cur_token].type == TOK_MINUS) {
TokenType op = tokens[cur_token].type; cur_token++; term();
if (op == TOK_PLUS) emit(OP_ADD); else emit(OP_SUB);
}
}
static void relation() {
if (compile_error) return;
additive();
if (tokens[cur_token].type >= TOK_EQ && tokens[cur_token].type <= TOK_GE) {
TokenType op = tokens[cur_token].type; cur_token++; additive();
switch (op) {
case TOK_EQ: emit(OP_EQ); break;
case TOK_NEQ: emit(OP_NEQ); break;
case TOK_LT: emit(OP_LT); break;
case TOK_GT: emit(OP_GT); break;
case TOK_LE: emit(OP_LE); break;
case TOK_GE: emit(OP_GE); break;
default: break;
}
}
}
static void expression() { if (compile_error) return; relation(); }
static void statement() {
if (compile_error) return;
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_CHAR_TYPE) {
cur_token++;
while (tokens[cur_token].type == TOK_MUL) cur_token++;
if (tokens[cur_token].type == TOK_ID) {
add_symbol(tokens[cur_token].str_val);
cur_token++;
if (tokens[cur_token].type == TOK_LBRACKET) {
cur_token++; if (tokens[cur_token].type == TOK_INT) cur_token++;
if (tokens[cur_token].type == TOK_RBRACKET) cur_token++;
else printf("Error: Expected ]\n");
}
if (tokens[cur_token].type == TOK_ASSIGN) {
int addr = find_symbol(tokens[cur_token-1].str_val);
cur_token++; expression(); emit(OP_STORE); emit32(addr);
}
match(TOK_SEMI);
} else { printf("Syntax Error: Expected identifier\n"); compile_error = 1; }
} else if (tokens[cur_token].type == TOK_ID) {
int syscall = find_builtin(tokens[cur_token].str_val);
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) {
function_call(syscall); match(TOK_SEMI); emit(OP_POP);
} else {
int addr = find_symbol(tokens[cur_token].str_val);
if (addr == -1) { printf("Error: Undefined variable assignment: %s\n", tokens[cur_token].str_val); compile_error = 1; return; }
cur_token++; match(TOK_ASSIGN); expression(); match(TOK_SEMI); emit(OP_STORE); emit32(addr);
}
} else if (tokens[cur_token].type == TOK_IF) {
cur_token++; match(TOK_LPAREN); expression(); match(TOK_RPAREN);
emit(OP_JZ); int jz_addr_pos = code_pos; emit32(0); block();
if (tokens[cur_token].type == TOK_ELSE) {
emit(OP_JMP); int jmp_addr_pos = code_pos; emit32(0);
int else_start = code_pos;
code[jz_addr_pos] = else_start & 0xFF; code[jz_addr_pos+1] = (else_start >> 8) & 0xFF; code[jz_addr_pos+2] = (else_start >> 16) & 0xFF; code[jz_addr_pos+3] = (else_start >> 24) & 0xFF;
cur_token++; block();
int end_addr = code_pos;
code[jmp_addr_pos] = end_addr & 0xFF; code[jmp_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jmp_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jmp_addr_pos+3] = (end_addr >> 24) & 0xFF;
} else {
int end_addr = code_pos;
code[jz_addr_pos] = end_addr & 0xFF; code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
}
} else if (tokens[cur_token].type == TOK_WHILE) {
int start_addr = code_pos; cur_token++; match(TOK_LPAREN); expression(); match(TOK_RPAREN);
emit(OP_JZ); int jz_addr_pos = code_pos; emit32(0); block();
emit(OP_JMP); emit32(start_addr);
int end_addr = code_pos;
code[jz_addr_pos] = end_addr & 0xFF; code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
} else cur_token++;
}
static void block() {
if (compile_error) return;
match(TOK_LBRACE);
while (tokens[cur_token].type != TOK_RBRACE && tokens[cur_token].type != TOK_EOF && !compile_error) statement();
match(TOK_RBRACE);
}
static void program() {
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_VOID_TYPE) cur_token++;
if (tokens[cur_token].type == TOK_MAIN) cur_token++;
match(TOK_LPAREN); match(TOK_RPAREN); block(); emit(OP_HALT);
}
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; }
int fh = sys_open(argv[1], "r");
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);
if (!source) { printf("Error: Out of memory for source buffer.\n"); sys_close(fh); return 1; }
int len = sys_read(fh, source, MAX_SOURCE - 1);
source[len] = 0;
sys_close(fh);
lexer(source);
free(source);
if (compile_error) return 1;
code_pos = 0; symbol_count = 0; cur_token = 0; str_pool_pos = 0; next_var_addr = 32768;
const char* magic = VM_MAGIC;
for(int i=0; i<7; i++) emit(magic[i]);
emit(1);
program();
if (compile_error) { printf("Compilation Failed.\n"); return 1; }
int pool_start_addr = code_pos;
for(int i=0; i<str_pool_pos; i++) emit(str_pool[i]);
int pc = 8;
while (pc < pool_start_addr) {
uint8_t op = code[pc++];
switch (op) {
case OP_HALT: break; case OP_IMM: case OP_LOAD: case OP_STORE: case OP_LOAD8: case OP_STORE8: case OP_JMP: case OP_JZ: case OP_SYSCALL: pc += 4; break;
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_PRINT: case OP_PRITC: case OP_EQ: case OP_NEQ: case OP_LT: case OP_GT: case OP_LE: case OP_GE: case OP_POP: break;
case OP_PUSH_PTR: {
int offset = 0;
offset |= code[pc]; offset |= code[pc+1] << 8; offset |= code[pc+2] << 16; offset |= code[pc+3] << 24;
int abs_addr = pool_start_addr + offset;
code[pc] = abs_addr & 0xFF; code[pc+1] = (abs_addr >> 8) & 0xFF; code[pc+2] = (abs_addr >> 16) & 0xFF; code[pc+3] = (abs_addr >> 24) & 0xFF;
pc += 4; code[pc-5] = OP_IMM; break;
}
default: break;
}
}
char out_name[64]; int i = 0;
while(argv[1][i] && argv[1][i] != '.') { out_name[i] = argv[1][i]; i++; }
out_name[i] = 0;
int out_fh = sys_open(out_name, "w");
if (out_fh >= 0) {
sys_write_fs(out_fh, code, code_pos);
sys_close(out_fh);
sys_set_text_color(color_success);
printf("Compilation successful. Output: %s\n", out_name);
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;
}

11
src/userland/cli/clear.c Normal file
View File

@@ -0,0 +1,11 @@
// 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) {
(void)argc; (void)argv;
sys_system(10, 0, 0, 0, 0);
return 0;
}

27
src/userland/cli/cowsay.c Normal file
View File

@@ -0,0 +1,27 @@
// 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) {
char *msg = (char*)"Bored!";
if (argc > 1) {
msg = argv[1];
}
size_t len = strlen(msg);
printf(" ");
for(size_t i=0; i<len+2; i++) printf("_");
printf("\n< %s >\n ", msg);
for(size_t i=0; i<len+2; i++) printf("-");
printf("\n");
printf(" \\ ^__^\n");
printf(" \\ (oo)\\_______\n");
printf(" (__)\\ )\\/\\\n");
printf(" ||----w |\n");
printf(" || ||\n\n");
return 0;
}

166
src/userland/cli/cp.c Normal file
View File

@@ -0,0 +1,166 @@
// 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>
typedef int bool;
#define true 1
#define false 0
void combine_path(char *dest, const char *path1, const char *path2) {
int i = 0;
while (path1[i]) {
dest[i] = path1[i];
i++;
}
if (i > 0 && dest[i-1] != '/') {
dest[i++] = '/';
}
int j = 0;
while (path2[j]) {
dest[i++] = path2[j++];
}
dest[i] = 0;
}
const char* get_basename(const char *path) {
const char *last_slash = NULL;
int len = 0;
while (path[len]) {
if (path[len] == '/') last_slash = path + len;
len++;
}
if (!last_slash) return path;
// If it ends with a slash, skip it and find the previous one
if (last_slash[1] == '\0') {
if (len <= 1) return path; // root "/"
int i = len - 2;
while (i >= 0 && path[i] != '/') i--;
if (i < 0) return path;
return path + i + 1;
}
return last_slash + 1;
}
void copy_recursive(const char *src, const char *dst) {
FAT32_FileInfo info;
if (sys_get_file_info(src, &info) < 0) {
printf("Error: Cannot get info for %s\n", src);
return;
}
if (info.is_directory) {
if (sys_mkdir(dst) < 0) {
// Might already exist
}
FAT32_FileInfo entries[64];
int count = sys_list(src, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_src[512], sub_dst[512];
combine_path(sub_src, src, entries[i].name);
combine_path(sub_dst, dst, entries[i].name);
copy_recursive(sub_src, sub_dst);
}
} else {
int fd_in = sys_open(src, "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", src);
return;
}
int fd_out = sys_open(dst, "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", dst);
sys_close(fd_in);
return;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
}
int main(int argc, char **argv) {
bool recursive = false;
char *src_path = NULL;
char *dst_path = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-r") == 0) {
recursive = true;
} else if (!src_path) {
src_path = argv[i];
} else if (!dst_path) {
dst_path = argv[i];
}
}
if (!src_path || !dst_path) {
printf("Usage: cp [-r] <source> <dest>\n");
return 1;
}
FAT32_FileInfo info_src;
if (sys_get_file_info(src_path, &info_src) < 0) {
printf("Error: Source %s does not exist\n", src_path);
return 1;
}
if (info_src.is_directory && !recursive) {
printf("Error: %s is a directory (use -r to copy recursively)\n", src_path);
return 1;
}
char actual_dst[512];
FAT32_FileInfo info_dst;
if (sys_get_file_info(dst_path, &info_dst) == 0 && info_dst.is_directory) {
// If destination is a directory, copy INTO it
const char *base = get_basename(src_path);
// Clean up trailing slash from basename if any (get_basename handles it mostly)
char clean_base[256];
int k = 0;
while (base[k] && base[k] != '/') {
clean_base[k] = base[k];
k++;
}
clean_base[k] = 0;
combine_path(actual_dst, dst_path, clean_base);
} else {
strcpy(actual_dst, dst_path);
}
if (recursive) {
copy_recursive(src_path, actual_dst);
} else {
int fd_in = sys_open(src_path, "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", src_path);
return 1;
}
int fd_out = sys_open(actual_dst, "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", actual_dst);
sys_close(fd_in);
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
return 0;
}

16
src/userland/cli/date.c Normal file
View File

@@ -0,0 +1,16 @@
// 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) {
(void)argc; (void)argv;
int dt[6];
if (sys_system(11, (uint64_t)dt, 0, 0, 0) == 0) {
printf("Current Date: %d-%d-%d %d:%d:%d\n", dt[0], dt[1], dt[2], dt[3], dt[4], dt[5]);
} else {
printf("Error: Could not retrieve date.\n");
}
return 0;
}

13
src/userland/cli/echo.c Normal file
View File

@@ -0,0 +1,13 @@
// 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) {
for (int i = 1; i < argc; i++) {
printf("%s%s", argv[i], (i == argc - 1) ? "" : " ");
}
printf("\n");
return 0;
}

17
src/userland/cli/hello.c Normal file
View File

@@ -0,0 +1,17 @@
// 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;
}

39
src/userland/cli/help.c Normal file
View File

@@ -0,0 +1,39 @@
// 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) {
(void)argc; (void)argv;
uint64_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("---------------------------\n");
printf("ls [path] - List directory contents\n");
printf("cd <path> - Change current directory (built-in)\n");
printf("pwd - Print current directory\n");
printf("mkdir <dir> - Create directory\n");
printf("rm <path> - Remove file or directory\n");
printf("cat <file> - Print file contents\n");
printf("echo [text] - Print text\n");
printf("touch <file> - Create empty file\n");
printf("cp <src> <dst> - Copy file\n");
printf("mv <src> <dst> - Move file\n");
printf("date - Print current date and time\n");
printf("uptime - Print system uptime\n");
printf("meminfo - Print memory information\n");
printf("cowsay [msg] - Fun cow says something\n");
printf("beep - Make a beep sound\n");
printf("reboot - Reboot the system\n");
printf("shutdown - Shutdown the system\n");
printf("sysfetch - Show system information\n");
printf("cc <file.c> - C Compiler\n");
printf("man <cmd> - Show manual page\n");
printf("clear - Clear the screen\n");
printf("exit - Exit the terminal\n");
printf("net - Network tools\n");
printf("\nHint: Use Ctrl+C to force quit any running application.\n");
return 0;
}

66
src/userland/cli/ls.c Normal file
View File

@@ -0,0 +1,66 @@
// 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) {
uint64_t dir_color = sys_get_shell_config("dir_color");
uint64_t file_color = sys_get_shell_config("file_color");
uint64_t size_color = sys_get_shell_config("size_color");
uint64_t error_color = sys_get_shell_config("error_color");
uint64_t default_color = sys_get_shell_config("default_text_color");
char path[256];
if (argc > 1) {
strcpy(path, argv[1]);
} else {
if (!sys_getcwd(path, sizeof(path))) {
strcpy(path, "/");
}
}
FAT32_FileInfo info;
if (sys_get_file_info(path, &info) < 0) {
sys_set_text_color(error_color);
printf("Error: Path '%s' does not exist\n", path);
sys_set_text_color(default_color);
return 1;
}
if (!info.is_directory) {
sys_set_text_color(file_color);
printf("[FILE] %s", info.name);
sys_set_text_color(size_color);
printf(" (%d bytes)\n", info.size);
sys_set_text_color(default_color);
printf("\nTotal: 1 items\n");
return 0;
}
FAT32_FileInfo entries[128];
int count = sys_list(path, entries, 128);
if (count < 0) {
sys_set_text_color(error_color);
printf("Error: Cannot list directory %s\n", path);
sys_set_text_color(default_color);
return 1;
}
for (int i = 0; i < count; i++) {
if (entries[i].is_directory) {
sys_set_text_color(dir_color);
printf("[DIR] %s\n", entries[i].name);
} else {
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);
return 0;
}

36
src/userland/cli/man.c Normal file
View File

@@ -0,0 +1,36 @@
// 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) {
if (argc < 2) {
printf("What manual page do you want?\nExample: man ls\n");
return 0;
}
char path[128];
printf("Manual for: %s\n", argv[1]);
printf("---------------------------\n");
strcpy(path, "A:/Library/man/");
strcat(path, argv[1]);
strcat(path, ".txt");
int fd = sys_open(path, "r");
if (fd < 0) {
printf("No manual entry for %s\n", argv[1]);
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
sys_write(1, buffer, bytes);
}
sys_close(fd);
printf("\n");
return 0;
}

28
src/userland/cli/mkdir.c Normal file
View File

@@ -0,0 +1,28 @@
// 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) {
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) {
printf("Usage: mkdir <dirname>\n");
return 1;
}
if (sys_mkdir(argv[1]) == 0) {
sys_set_text_color(success_color);
printf("Created directory: %s\n", argv[1]);
} else {
sys_set_text_color(error_color);
printf("Error: Cannot create directory %s\n", argv[1]);
sys_set_text_color(default_color);
return 1;
}
sys_set_text_color(default_color);
return 0;
}

128
src/userland/cli/mv.c Normal file
View File

@@ -0,0 +1,128 @@
// 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>
void combine_path(char *dest, const char *path1, const char *path2) {
int i = 0;
while (path1[i]) {
dest[i] = path1[i];
i++;
}
if (i > 0 && dest[i-1] != '/') {
dest[i++] = '/';
}
int j = 0;
while (path2[j]) {
dest[i++] = path2[j++];
}
dest[i] = 0;
}
const char* get_basename(const char *path) {
const char *last_slash = NULL;
int len = 0;
while (path[len]) {
if (path[len] == '/') last_slash = path + len;
len++;
}
if (!last_slash) return path;
if (last_slash[1] == '\0') {
if (len <= 1) return path;
int i = len - 2;
while (i >= 0 && path[i] != '/') i--;
if (i < 0) return path;
return path + i + 1;
}
return last_slash + 1;
}
void copy_recursive(const char *src, const char *dst) {
FAT32_FileInfo info;
if (sys_get_file_info(src, &info) < 0) return;
if (info.is_directory) {
sys_mkdir(dst);
FAT32_FileInfo entries[64];
int count = sys_list(src, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_src[512], sub_dst[512];
combine_path(sub_src, src, entries[i].name);
combine_path(sub_dst, dst, entries[i].name);
copy_recursive(sub_src, sub_dst);
}
} else {
int fd_in = sys_open(src, "r");
if (fd_in < 0) return;
int fd_out = sys_open(dst, "w");
if (fd_out < 0) { sys_close(fd_in); return; }
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
}
void delete_recursive(const char *path) {
FAT32_FileInfo info;
if (sys_get_file_info(path, &info) < 0) return;
if (info.is_directory) {
FAT32_FileInfo entries[64];
int count = sys_list(path, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_path[512];
combine_path(sub_path, path, entries[i].name);
delete_recursive(sub_path);
}
sys_delete(path);
} else {
sys_delete(path);
}
}
int main(int argc, char **argv) {
if (argc < 3) {
printf("Usage: mv <source> <dest>\n");
return 1;
}
char *src_path = argv[1];
char *dst_path = argv[2];
FAT32_FileInfo info_src;
if (sys_get_file_info(src_path, &info_src) < 0) {
printf("Error: Cannot open source %s\n", src_path);
return 1;
}
char actual_dst[512];
FAT32_FileInfo info_dst;
if (sys_get_file_info(dst_path, &info_dst) == 0 && info_dst.is_directory) {
const char *base = get_basename(src_path);
char clean_base[256];
int k = 0;
while (base[k] && base[k] != '/') {
clean_base[k] = base[k];
k++;
}
clean_base[k] = 0;
combine_path(actual_dst, dst_path, clean_base);
} else {
strcpy(actual_dst, dst_path);
}
copy_recursive(src_path, actual_dst);
delete_recursive(src_path);
return 0;
}

17
src/userland/cli/pwd.c Normal file
View File

@@ -0,0 +1,17 @@
// 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) {
(void)argc; (void)argv;
char path[256];
if (getcwd(path, sizeof(path))) {
printf("%s\n", path);
} else {
printf("Error: Could not get current directory\n");
return 1;
}
return 0;
}

29
src/userland/cli/rm.c Normal file
View File

@@ -0,0 +1,29 @@
// 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) {
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) {
printf("Usage: rm <path>\n");
return 1;
}
// Simple rm (no recursive support yet for simplicity, but can be added)
if (sys_delete(argv[1]) == 0) {
sys_set_text_color(success_color);
printf("Deleted: %s\n", argv[1]);
} else {
sys_set_text_color(error_color);
printf("Error: Cannot delete %s\n", argv[1]);
sys_set_text_color(default_color);
return 1;
}
sys_set_text_color(default_color);
return 0;
}

185
src/userland/cli/sort.c Normal file
View File

@@ -0,0 +1,185 @@
// 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 "stdlib.h"
#define WIN_W 400
#define WIN_H 210
#define NUM_ELEM (WIN_W / 2)
#define BAR_W 2
static uint32_t *fb = NULL;
static int heights[NUM_ELEM];
static int moves = 0;
static unsigned long int next_rand = 1;
static int my_rand(void) {
next_rand = next_rand * 1103515245 + 12345;
return (unsigned int)(next_rand / 65536) % 32768;
}
static void my_srand(unsigned int seed) {
next_rand = seed;
}
static void render_state(ui_window_t win) {
// Clear fb
for (int i = 0; i < WIN_W * WIN_H; i++) {
fb[i] = 0xFF1E1E1E;
}
// Draw bars
for (int i = 0; i < NUM_ELEM; i++) {
int h = heights[i];
if (h > WIN_H - 10) h = WIN_H - 10;
int x = i * BAR_W;
int y = WIN_H - h;
// draw rect
for (int yy = y; yy < WIN_H; yy++) {
for (int xx = x; xx < x + BAR_W; xx++) {
if (xx >= 0 && xx < WIN_W && yy >= 0 && yy < WIN_H) {
fb[yy * WIN_W + xx] = 0xFF4A90E2; // Blue
}
}
}
}
// Draw Border for Box - bottom left
int box_x = 10;
int box_y = WIN_H - 40; // moved up by 10 pixels
int box_w = 120;
int box_h = 24;
for (int yy = box_y; yy < box_y + box_h; yy++) {
for (int xx = box_x; xx < box_x + box_w; xx++) {
if (xx == box_x || xx == box_x + box_w - 1 || yy == box_y || yy == box_y + box_h - 1) {
fb[yy * WIN_W + xx] = 0xFFFFFFFF;
} else {
fb[yy * WIN_W + xx] = 0xFF1E1E1E;
}
}
}
// Draw framebuffer to window
ui_draw_image(win, 0, 0, WIN_W, WIN_H, fb);
// Draw text inside the box
char buf[32];
strcpy(buf, "Moves: ");
char num_buf[16];
itoa(moves, num_buf);
strcat(buf, num_buf);
ui_draw_string(win, box_x + 8, box_y + 4, buf, 0xFFFFFFFF);
ui_mark_dirty(win, 0, 0, WIN_W, WIN_H);
}
int main(void) {
ui_window_t win = ui_window_create("sort", 100, 100, WIN_W, WIN_H);
fb = (uint32_t*)malloc(WIN_W * WIN_H * sizeof(uint32_t));
if (!fb) return 1;
// Seed PRNG with system time (ticks)
my_srand((unsigned int)sys_system(16, 0, 0, 0, 0));
// Initialize perfect slope
int max_h = WIN_H - 40; // max height
int min_h = 10;
for (int i = 0; i < NUM_ELEM; i++) {
heights[i] = min_h + (max_h - min_h) * i / (NUM_ELEM - 1);
}
// Shuffle
for (int i = NUM_ELEM - 1; i > 0; i--) {
int j = my_rand() % (i + 1);
int t = heights[i];
heights[i] = heights[j];
heights[j] = t;
}
gui_event_t ev;
// Cocktail shaker sort variables
bool swapped = true;
int start = 0;
int end = NUM_ELEM - 1;
bool done = false;
// We render after each swap so the steps are extremely visual
while (1) {
if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_CLOSE) {
break;
}
}
if (!done) {
swapped = false;
// Forward pass
for (int i = start; i < end; ++i) {
if (heights[i] > heights[i + 1]) {
int t = heights[i];
heights[i] = heights[i+1];
heights[i+1] = t;
swapped = true;
moves++;
render_state(win);
// Allow UI events while sorting
if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_CLOSE) {
goto exit_app;
}
}
sleep(2);
}
}
if (!swapped) {
done = true;
continue;
}
swapped = false;
end = end - 1;
// Backward pass
for (int i = end - 1; i >= start; --i) {
if (heights[i] > heights[i + 1]) {
int t = heights[i];
heights[i] = heights[i+1];
heights[i+1] = t;
swapped = true;
moves++;
render_state(win);
// Allow UI events
if (ui_get_event(win, &ev)) {
if (ev.type == GUI_EVENT_CLOSE) {
goto exit_app;
}
}
sleep(2);
}
}
start = start + 1;
} else {
// Sort is done, just render and idle
render_state(win);
sleep(200);
}
}
exit_app:
free(fb);
exit(0);
return 0;
}

27
src/userland/cli/touch.c Normal file
View File

@@ -0,0 +1,27 @@
// 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) {
if (argc < 2) {
printf("Usage: touch <filename>\n");
return 1;
}
// Check if file already exists
if (sys_exists(argv[1])) {
// Just return success if it exists (simplification)
return 0;
}
int fd = sys_open(argv[1], "w");
if (fd < 0) {
printf("Error: Cannot create %s\n", argv[1]);
return 1;
}
sys_close(fd);
return 0;
}