diff options
Diffstat (limited to 'src/user/highway')
-rw-r--r-- | src/user/highway/cmds.c | 46 | ||||
-rw-r--r-- | src/user/highway/cmds.h | 7 | ||||
-rw-r--r-- | src/user/highway/highway.c | 24 | ||||
-rw-r--r-- | src/user/highway/line.c | 100 | ||||
-rw-r--r-- | src/user/highway/line.h | 6 | ||||
-rw-r--r-- | src/user/highway/main.c | 16 | ||||
-rw-r--r-- | src/user/highway/vars.c | 98 | ||||
-rw-r--r-- | src/user/highway/vars.h | 17 |
8 files changed, 290 insertions, 24 deletions
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 <knob/file.h> +#include <knob/user.h> +#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 <knob/user.h> -#include <knob/task.h> -#include <knob/block.h> - -//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 <knob/block.h> +#include <knob/quit.h> +#include <knob/task.h> +#include <knob/user.h> +#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 <knob/user.h> +#include <knob/task.h> +#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 <knob/block.h> +#include <knob/heap.h> +#include <knob/user.h> + +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 <stdint.h> + +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 |