summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
Diffstat (limited to 'src/user')
-rw-r--r--src/user/highway/cmds.c46
-rw-r--r--src/user/highway/cmds.h7
-rw-r--r--src/user/highway/highway.c24
-rw-r--r--src/user/highway/line.c100
-rw-r--r--src/user/highway/line.h6
-rw-r--r--src/user/highway/main.c16
-rw-r--r--src/user/highway/vars.c98
-rw-r--r--src/user/highway/vars.h17
-rw-r--r--src/user/include/knob/block.h5
-rw-r--r--src/user/include/knob/file.h3
-rw-r--r--src/user/include/knob/user.h1
-rw-r--r--src/user/init/init.c36
-rw-r--r--src/user/knob/block.c2
-rw-r--r--src/user/knob/file.c44
-rw-r--r--src/user/knob/quit.c2
-rw-r--r--src/user/knob/user.c17
16 files changed, 353 insertions, 71 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
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 <stdbool.h>
+#include <stdint.h>
+
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 <stdint.h>
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 <knob/file.h>
#include <knob/task.h>
-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 <knob/heap.h>
#include <knob/env.h>
+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 <pland/syscall.h>
+#include <knob/file.h>
__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];