summaryrefslogtreecommitdiff
path: root/src/user/highway/line.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/highway/line.c')
-rw-r--r--src/user/highway/line.c100
1 files changed, 100 insertions, 0 deletions
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