#include #include "alloc.h" #include "commands.h" #include "font.h" #include "kprintf.h" #include "shell.h" #include "string.h" #include "terminal.h" #include "utils.h" #include "vbe.h" #define BORDER "===========================================================" #define HEADER "Welcome to bozOShell - Available Commands" struct shell_command { char name[16]; char description[256]; void (*fn)(char *arg); }; const struct shell_command cmds[] = { {"help", "Print this help menu", help_cmd}, {"reboot", "Reboot the system", reboot_cmd}, {"poweroff", "Shut down the system", poweroff_cmd}, {"halt", "Stop all CPU functions", halt_cmd}, {"stack", "Print the stack trace", stack_cmd}, {"heap", "Print the heaps", heap_cmd}, {"clear", "Clear the current terminal", clear_cmd}, {"date", "Display the current time and date", date_cmd}, {"merdella", "Surprise", merdella_cmd}, {"color", "Change the screen color", color_cmd}, }; #define NB_CMDS ARRAY_SIZE(cmds) extern struct screen *screen; extern struct icon *terminal_bg; extern int line_status; void help_cmd(char *arg) { const size_t padding = 15; (void)arg; kprintf("%s\n", BORDER); kprintf(" %s\n", HEADER); kprintf("%s\n", BORDER); for (size_t i = 0; i < NB_CMDS; i++) { kprintf(" %s", cmds[i].name); for (size_t j = 0; j < (padding - strlen(cmds[i].name)); j++) kprintf(" "); kprintf(": %s\n", cmds[i].description); } kprintf("%s\n", BORDER); } static void auto_complete(void) { const size_t len = strlen(screen->line); int nb_matches = 0; const char *last_match; for (size_t i = 0; i < NB_CMDS; i++) { if (!strncmp(screen->line, cmds[i].name, len)) { nb_matches++; last_match = cmds[i].name; } } if (nb_matches != 1) return; for (size_t i = len; last_match[i]; i++) { screen->line[i] = last_match[i]; kprintf("%c", screen->line[i]); } } static char *get_line(void) { size_t i = 0; struct key_event ev; while (1) { ev = get_key(); if (ev.c == '\n') break; char *buf = screen->line; i = strlen(screen->line); const size_t size = sizeof(screen->line); if (ev.scan_code) { if (ev.scan_code == KEY_BACKSPACE) { if (!i) continue; buf[--i] = '\0'; terminal_remove_last_char(); } else if (ev.scan_code == KEY_TAB && i) { auto_complete(); } else if (ev.c && i < size - 1) { kprintf("%c", ev.c); buf[i++] = ev.c; } if (i >= size) break; } } kprintf("\n"); screen->line[i] = '\0'; return screen->line; } void shell_init(void) { while (1) { kprintf(PROMPT); get_line(); bool invalid = true; for (unsigned i = 0; i < NB_CMDS; i++) { if (!strncmp(cmds[i].name, screen->line, strlen(cmds[i].name))) { char *args = strchr(screen->line, ' '); if (args) args++; // skip the space cmds[i].fn(args); invalid = false; break; } } if (invalid && screen->line[0]) kprintf(KERN_WARNING "invalid command: %s\n", screen->line); memset(screen->line, '\0', sizeof(screen->line)); } }