42_KFS/src/shell/exec.c

123 lines
2.8 KiB
C
Raw Normal View History

#include "kprintf.h"
#include "shell.h"
#include "string.h"
#include "terminal.h"
#define NB_CMDS 8
#define BORDER "==========================================================="
#define HEADER "Welcome to bozOShell - Available Commands"
extern struct screen *screen;
struct shell_command {
char name[16];
char description[256];
void (*fn)(void);
};
static void help(void);
static const struct shell_command commands[NB_CMDS] = {
{"help", "Print this help menu", help},
{"reboot", "Reboot the system", reboot},
{"poweroff", "Shut down the system", halt},
{"halt", "Stop all CPU functions", halt},
{"stack", "Print the stack trace", print_stack},
{"clear", "Clear the current terminal", terminal_clear},
{"date", "Display the current time and date (UTC+0)", date},
{"merdella", "Surprise", merdella},
};
static void help(void)
{
const size_t padding = 15;
kprintf("%s\n", BORDER);
kprintf(" %s\n", HEADER);
kprintf("%s\n", BORDER);
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); 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(void)
{
while (1) {
kprintf(PROMPT);
read_line();
bool invalid = true;
for (int i = 0; i < NB_CMDS; i++) {
if (!strcmp(commands[i].name, screen->line)) {
commands[i].fn();
invalid = false;
break;
}
}
if (invalid && screen->line[0])
kprintf(KERN_WARNING "invalid command: %s\n",
screen->line);
memset(screen->line, '\0', sizeof(screen->line));
}
}