From 44d29a33df81ac07163d5146a9e43a0c4fb80af0 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sun, 13 Sep 2020 22:06:40 -0400 Subject: new shell --- src/user/highway/cmds.c | 46 +++++++++++++++++++ src/user/highway/cmds.h | 7 +++ src/user/highway/highway.c | 24 ---------- src/user/highway/line.c | 100 ++++++++++++++++++++++++++++++++++++++++++ src/user/highway/line.h | 6 +++ src/user/highway/main.c | 16 +++++++ src/user/highway/vars.c | 98 +++++++++++++++++++++++++++++++++++++++++ src/user/highway/vars.h | 17 +++++++ src/user/include/knob/block.h | 5 ++- src/user/include/knob/file.h | 3 ++ src/user/include/knob/user.h | 1 - src/user/init/init.c | 36 ++++----------- src/user/knob/block.c | 2 +- src/user/knob/file.c | 44 +++++++++++++++++++ src/user/knob/quit.c | 2 + src/user/knob/user.c | 17 ------- 16 files changed, 353 insertions(+), 71 deletions(-) create mode 100644 src/user/highway/cmds.c create mode 100644 src/user/highway/cmds.h delete mode 100644 src/user/highway/highway.c create mode 100644 src/user/highway/line.c create mode 100644 src/user/highway/line.h create mode 100644 src/user/highway/main.c create mode 100644 src/user/highway/vars.c create mode 100644 src/user/highway/vars.h (limited to 'src/user') diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c new file mode 100644 index 0000000..d7a89d1 --- /dev/null +++ b/src/user/highway/cmds.c @@ -0,0 +1,46 @@ +#include +#include +#include "line.h" +#include "vars.h" + +void source(const char *path) { + struct file *f = open_file(path); + if (!f) + tell_user_sz("couldn't open file.\n"); + char buf[128]; + while (read_line_from_file(f, buf, 127)) + run_line(buf); + close_file(f); +} + +void set(const char *arg) { + const char *space = arg; + while (*space != ' ') + if (*space) + ++space; + else { + struct no_null_sn vname = { + .data = arg, + .length = space - arg + }; + del_var(vname); + return; + } + + struct no_null_sn vname = { + .data = arg, + .length = space - arg + }; + + const char *vstart = space + 1, + *vend = vstart; + while (*vend) + ++vend; + + struct no_null_sn vval = { + .data = vstart, + .length = vend - vstart + }; + + set_var(vname, vval); +} \ No newline at end of file diff --git a/src/user/highway/cmds.h b/src/user/highway/cmds.h new file mode 100644 index 0000000..c404d40 --- /dev/null +++ b/src/user/highway/cmds.h @@ -0,0 +1,7 @@ +#ifndef CMDS_H +#define CMDS_H + +void source(const char *path); +void set(const char *arg); + +#endif \ No newline at end of file diff --git a/src/user/highway/highway.c b/src/user/highway/highway.c deleted file mode 100644 index 7e78472..0000000 --- a/src/user/highway/highway.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include - -//TODO: load a user environment file containing a PATH-like setting. -//TODO: have an active disk and/or directory - -void main() { - char path_buf[1024 + 4] = "bin/"; - char *const line_buf = path_buf + 4; - - tell_user_sz("Highway, Portland Command Shell, started.\n" - "Type \"exit\" to quit.\n"); - yield_task(); - - while (1) { - tell_user_sz("> "); - ask_user_line_sz(line_buf, 1023); - if (blockequ(line_buf, "exit", 5)) - return; - if (!try_run_command_blocking(path_buf)) - tell_user_sz("An error occured trying to run that command.\n"); - } -} \ No newline at end of file diff --git a/src/user/highway/line.c b/src/user/highway/line.c new file mode 100644 index 0000000..ca38c9b --- /dev/null +++ b/src/user/highway/line.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include "cmds.h" +#include "vars.h" + +#define LINE_SIZE 4096 +static char line[LINE_SIZE]; + +static void line_replace(const char *from) { + const char *fi = from; + char *ti = line; + while (*fi) { + if (ti == line + LINE_SIZE) { + tell_user_sz("Line too long.\n"); + line[0] = '\0'; + return; + } + if (*fi != '$') { + *ti = *fi; + ++ti; + ++fi; + continue; + } + const char *var_start = ++fi; + const char *var_end = var_start; + while (*var_end != '$') + if (!*var_end++) { + tell_user_sz("Unterminated variable name.\n"); + line[0] = '\0'; + return; + } + if (ti + (var_end - var_start) >= line + LINE_SIZE) { + tell_user_sz("Line too long.\n"); + line[0] = '\0'; + return; + } + struct no_null_sn vname = { + .data = var_start, + .length = var_end - var_start + }; + const struct no_null_sn *vval = get_var(vname); + if (!vval) + vval = &vname; + blockcpy(ti, vval->data, vval->length); + ti += vval->length; + fi = var_end + 1; + } + *ti = '\0'; +} + +void run_line(const char *original_line) { + line_replace(original_line); + if (!*line) + return; + const char *space; + for (space = line; *space && (*space != ' '); ++space) + ; + if (blockequ(line, "source", space - line)) + source(space + 1); + else if (blockequ(line, "set", space - line)) + set(space + 1); + else if (blockequ(line, "echo", space - line)) { + tell_user_sz(space + 1); + tell_user_sz("\n"); + } + else if (blockequ(line, "vars", space - line)) + dump_vars(); + else if (blockequ(line, "quit", space - line)) + quit(space + 1); + else if (blockequ(line, "help", space - line)) + tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n" + "of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n" + "following list shows each of the pseudo-commands.\n\n" + " source FILE run each command in FILE\n" + " set VAR VALUE set $VAR$ to VALUE\n" + " echo STRING print STRING\n" + " vars dump variables\n" + " quit exit highway\n" + " help show this\n\n"); + else if (!try_run_command_blocking(line)) { + struct no_null_sn arg = { + .data = "_path", + .length = 5 + }; + const struct no_null_sn *path = get_var(arg); + if (!path->length) { + tell_user_sz("Could not run command.\n"); + return; + } + for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i) + line[to_i] = line[to_i - path->length]; + blockcpy(line, path->data, path->length); + if (!try_run_command_blocking(line)) { + tell_user_sz("Could not run command.\n"); + return; + } + } +} \ No newline at end of file diff --git a/src/user/highway/line.h b/src/user/highway/line.h new file mode 100644 index 0000000..4785034 --- /dev/null +++ b/src/user/highway/line.h @@ -0,0 +1,6 @@ +#ifndef LINE_H +#define LINE_H + +void run_line(const char *line); + +#endif \ No newline at end of file diff --git a/src/user/highway/main.c b/src/user/highway/main.c new file mode 100644 index 0000000..1934920 --- /dev/null +++ b/src/user/highway/main.c @@ -0,0 +1,16 @@ +#include +#include +#include "cmds.h" +#include "line.h" + +void main(const char *arg) { + source(*arg ? arg : "user/default.rc"); + char cmd_buf[128]; + yield_task(); + tell_user_sz("Portland Highway\nType \"help\" for help.\n"); + while (1) { + tell_user_sz("> "); + ask_user_line_sz(cmd_buf, 127); + run_line(cmd_buf); + } +} \ No newline at end of file diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c new file mode 100644 index 0000000..6090b76 --- /dev/null +++ b/src/user/highway/vars.c @@ -0,0 +1,98 @@ +#include +#include +#include + +struct no_null_sn { + char *data; + uint32_t length; +}; + +struct var_dict_node { + struct var_dict_node *next; + struct var_dict_node *prev; + struct no_null_sn name; + struct no_null_sn value; +}; + +static struct var_dict_node *var_dict_start = 0; + +__attribute__ ((pure)) +static struct var_dict_node *get_node(struct no_null_sn name) { + for (struct var_dict_node *i = var_dict_start; i; i = i->next) + if ((i->name.length == name.length) && + blockequ(i->name.data, name.data, name.length)) + return i; + return 0; +} + +static struct var_dict_node *new_node() { + struct var_dict_node *node = get_block(sizeof(struct var_dict_node)); + node->prev = 0; + node->next = var_dict_start; + if (var_dict_start) + var_dict_start->prev = node; + var_dict_start = node; + return node; +} + +void set_var(struct no_null_sn name, struct no_null_sn value) { + struct var_dict_node *node = get_node(name); + if (node) + free_block(node->value.data); + else { + node = new_node(); + node->name.length = name.length; + node->name.data = get_block(name.length); + blockcpy(node->name.data, name.data, name.length); + } + node->value.length = value.length; + node->value.data = get_block(value.length); + blockcpy(node->value.data, value.data, value.length); +} + +__attribute__ ((pure)) +const struct no_null_sn *get_var(struct no_null_sn name) { + struct var_dict_node *node = get_node(name); + return node ? &node->value : 0; +} + +void del_var(struct no_null_sn name) { + struct var_dict_node *node = get_node(name); + if (!node) + return; + free_block(node->name.data); + free_block(node->value.data); + if (node->prev) + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + if (node == var_dict_start) + var_dict_start = node->next; + free_block(node); +} + +void dump_vars() { + for (struct var_dict_node *node = var_dict_start; node; node = node->next) { + tell_user_sz("$"); + + char *buf = get_block(node->name.length + 1); + blockcpy(buf, node->name.data, node->name.length); + buf[node->name.length] = '\0'; + + tell_user_sz(buf); + + free_block(buf); + + tell_user_sz("$ = "); + + buf = get_block(node->value.length + 1); + blockcpy(buf, node->value.data, node->value.length); + buf[node->value.length] = '\0'; + + tell_user_sz(buf); + + free_block(buf); + + tell_user_sz("\n"); + } +} \ No newline at end of file diff --git a/src/user/highway/vars.h b/src/user/highway/vars.h new file mode 100644 index 0000000..fc4d197 --- /dev/null +++ b/src/user/highway/vars.h @@ -0,0 +1,17 @@ +#ifndef VARS_H +#define VARS_H + +#include + +struct no_null_sn { + const char *data; + uint32_t length; +}; + +void set_var(struct no_null_sn name, struct no_null_sn value); +const struct no_null_sn *get_var(struct no_null_sn name) __attribute__ ((pure)); +void del_var(struct no_null_sn name); + +void dump_vars(); + +#endif \ No newline at end of file diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h index 2aa2b36..4625577 100644 --- a/src/user/include/knob/block.h +++ b/src/user/include/knob/block.h @@ -1,7 +1,10 @@ #ifndef KNOB_BLOCK_H #define KNOB_BLOCK_H +#include +#include + void blockcpy(void *to, const void *from, uint32_t size); -bool blockequ(void *a, void *b, uint32_t size) __attribute__ ((__pure__)); +bool blockequ(const void *a, const void *b, uint32_t size) __attribute__ ((__pure__)); #endif \ No newline at end of file diff --git a/src/user/include/knob/file.h b/src/user/include/knob/file.h index 4d0da87..a0d084f 100644 --- a/src/user/include/knob/file.h +++ b/src/user/include/knob/file.h @@ -9,8 +9,11 @@ const char *remove_prefix(const char *path, uint8_t *dn_out); struct file *open_file(const char *path); void close_file(struct file *f); +void _close_all_files(); uint32_t read_from_file(struct file *f, uint32_t max, void *buf); +//return value and max_length don't include null terminator +uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length); uint32_t seek_file_to(struct file *f, uint32_t to); int32_t seek_file_by(struct file *f, int32_t by); diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h index 45caab4..479a731 100644 --- a/src/user/include/knob/user.h +++ b/src/user/include/knob/user.h @@ -4,7 +4,6 @@ #include void tell_user_sz(const char *sz); -void tell_user_n(uint32_t n); //return value and max_length don't include null terminator //returns the real length of the string diff --git a/src/user/init/init.c b/src/user/init/init.c index e878603..fb231e0 100644 --- a/src/user/init/init.c +++ b/src/user/init/init.c @@ -2,19 +2,6 @@ #include #include -void start(const char *cmd) { - tell_user_sz("[init] Starting "); - tell_user_sz(cmd); - tell_user_sz(": "); - tell_user_sz( - run_command(cmd) - ? "Succeded.\n" - : "Failed.\n" - ); - tell_user_sz("[init] Yielding.\n"); - yield_task(); -} - #define STARTUP_FILE_PATH "sys/startup.rc" void main() { @@ -26,22 +13,17 @@ void main() { tell_user_sz("[init] Reading from " STARTUP_FILE_PATH ".\n"); - char buf[1024]; - char *bufp = buf; - while (read_from_file(f, 1, bufp)) { - if (*bufp == '\n') { - if (bufp == buf) - continue; - *bufp = '\0'; - start(buf); - bufp = buf; + char cmdbuf[128]; + while (read_line_from_file(f, cmdbuf, 127)) { + tell_user_sz("[init] Starting "); + tell_user_sz(cmdbuf); + tell_user_sz(": "); + if (run_command(cmdbuf)) { + tell_user_sz("Succeded.\n"); + yield_task(); } else - ++bufp; - } - if (bufp != buf) { - *bufp = '\0'; - start(buf); + tell_user_sz("Failed.\n"); } close_file(f); diff --git a/src/user/knob/block.c b/src/user/knob/block.c index e890fa1..7524ad3 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -9,7 +9,7 @@ void blockcpy(void *to, const void *from, uint32_t size) { //unsophisticated, should check by dwords wheere available __attribute__ ((__pure__)) -bool blockequ(void *a, void *b, uint32_t size) { +bool blockequ(const void *a, const void *b, uint32_t size) { for (uint32_t i = 0; i < size; ++i) if (*(uint8_t *)(a++) != *(uint8_t *)(b++)) return false; diff --git a/src/user/knob/file.c b/src/user/knob/file.c index 0032cf2..23b7564 100644 --- a/src/user/knob/file.c +++ b/src/user/knob/file.c @@ -3,7 +3,21 @@ #include #include +struct ofl_node { + struct ofl_node *next; + struct ofl_node *prev; + _file_handle_t handle; +}; + +static struct ofl_node *head_ofl_node = 0; + +void _close_all_files() { + for (struct ofl_node *i = head_ofl_node; i; i = i->next) + _close_file(i->handle); +} + struct file { + struct ofl_node *node; _file_handle_t handle; uint32_t position; uint32_t length; @@ -38,7 +52,16 @@ struct file *open_file(const char *path) { if (!h) return 0; + struct ofl_node *new_node = get_block(sizeof(struct ofl_node)); + new_node->next = head_ofl_node; + new_node->prev = 0; + new_node->handle = h; + if (head_ofl_node) + head_ofl_node->prev = new_node; + head_ofl_node = new_node; + struct file *f = get_block(sizeof(struct file)); + f->node = new_node; f->handle = h; f->position = 0; f->length = _file_size(h); @@ -48,6 +71,14 @@ struct file *open_file(const char *path) { void close_file(struct file *f) { _close_file(f->handle); + struct ofl_node *n = f->node; + if (n->next) + n->next->prev = n->prev; + if (n->prev) + n->prev->next = n->next; + if (n == head_ofl_node) + head_ofl_node = n->next; + free_block(n); free_block(f); } @@ -61,6 +92,19 @@ uint32_t read_from_file(struct file *f, uint32_t max, void *buf) { return read; } +//return value and max_length don't include null terminator +uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length) { + uint8_t i; + for (i = 0; i < max_length; ++i) { + char byte; + if (!read_from_file(f, 1, &byte) || (byte == '\n')) + break; + sz[i] = byte; + } + sz[i] = '\0'; + return i; +} + uint32_t seek_file_to(struct file *f, uint32_t to) { if (to > f->length) to = f->length; diff --git a/src/user/knob/quit.c b/src/user/knob/quit.c index 7c20bdd..98881b7 100644 --- a/src/user/knob/quit.c +++ b/src/user/knob/quit.c @@ -1,6 +1,8 @@ #include +#include __attribute__ ((noreturn)) void quit() { + _close_all_files(); _exit_task(); } \ No newline at end of file diff --git a/src/user/knob/user.c b/src/user/knob/user.c index c84977c..b642f79 100644 --- a/src/user/knob/user.c +++ b/src/user/knob/user.c @@ -134,23 +134,6 @@ void tell_user_sz(const char *sz) { _log_string(sz); } -void tell_user_n(uint32_t n) { - char buf[11]; - char *buf_ptr = buf; - bool zero_yet = false; - for (uint32_t d = 1000000000U; d; d /= 10) { - uint8_t v = (n / d ) % 10; - if (v || zero_yet) { - zero_yet = true; - *buf_ptr++ = v | '0'; - } - } - if (buf_ptr == buf) - *buf_ptr++ = '0'; - *buf_ptr = '\0'; - tell_user_sz(buf); -} - //return value and max_length don't include null terminator uint32_t ask_user_line_sz(char *sz, uint32_t max_length) { char log_buf[2]; -- cgit v1.2.3