#include "alloc.h" #include "commands.h" #include "kprintf.h" #include "shell.h" #include "string.h" #include "terminal.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 commands[] = { {"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}, }; #define NB_CMDS (sizeof(commands) / sizeof(commands[0])) extern struct screen *screen; 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", commands[i].name); for (size_t j = 0; j < (padding - strlen(commands[i].name)); j++) kprintf(" "); kprintf(": %s\n", commands[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, commands[i].name, len)) { nb_matches++; last_match = commands[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 void read_line(void) { size_t i = 0; struct key_event ev; uint8_t prev_scan_code = 0; while (1) { ev = terminal_getkey(); if (ev.c == '\n') break; char *buf = screen->line; i = strlen(screen->line); const size_t size = sizeof(screen->line); if (prev_scan_code != ev.scan_code && ev.scan_code) { if (ev.scan_code == KEY_BACKSPACE && i) { buf[--i] = '\0'; move_cursor(LEFT); terminal_putchar(' '); move_cursor(LEFT); } 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; } prev_scan_code = ev.scan_code; } kprintf("\n"); screen->line[i] = '\0'; } void shell_init() { while (1) { kprintf(PROMPT); read_line(); bool invalid = true; for (unsigned i = 0; i < NB_CMDS; i++) { if (!strcmp(commands[i].name, screen->line)) { commands[i].fn(screen->line + strlen(commands[i].name) + 1); invalid = false; break; } } if (invalid && screen->line[0]) kprintf(KERN_WARNING "invalid command: %s\n", screen->line); memset(screen->line, '\0', sizeof(screen->line)); } }