From fadd46012c9974931add6c36e69636d3cbc6906f Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sun, 20 Sep 2020 14:50:12 -0400 Subject: history when getting line from user in knob --- src/user/highway/line.c | 17 +++--- src/user/highway/main.c | 3 +- src/user/include/knob/block.h | 3 + src/user/include/knob/user.h | 7 +++ src/user/include/pland/syscall.h | 2 +- src/user/knob/block.c | 12 +++- src/user/knob/user.c | 125 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 10 deletions(-) (limited to 'src/user') diff --git a/src/user/highway/line.c b/src/user/highway/line.c index 40dccfa..b5a54c5 100644 --- a/src/user/highway/line.c +++ b/src/user/highway/line.c @@ -57,25 +57,28 @@ void run_line(const char *original_line) { const char *space; for (space = line; *space && (*space != ' '); ++space) ; - if (blockequ(line, "source", space - line)) + if (blockequ(line, "source ", 7)) source(space + 1); - else if (blockequ(line, "set", space - line)) + else if (blockequ(line, "set ", 4)) set(space + 1); - else if (blockequ(line, "echo", space - line)) { + else if (blockequ(line, "echo ", 5)) { tell_user_sz(space + 1); tell_user_sz("\n"); } - else if (blockequ(line, "vars", space - line)) + else if (blockequ(line, "vars", 5)) dump_vars(); - else if (blockequ(line, "quit", space - line)) + else if (blockequ(line, "quit", 5)) __pcrt_quit(); - else if (blockequ(line, "help", space - line)) + else if (blockequ(line, "clear", 6)) + _clear_screen(); + else if (blockequ(line, "help", 5)) 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" + " clear clear the screen\n" " echo STRING print STRING\n" + " set VAR VALUE set $VAR$ to VALUE\n" " vars dump variables\n" " quit exit highway\n" " help show this\n"); diff --git a/src/user/highway/main.c b/src/user/highway/main.c index 61f736e..4599315 100644 --- a/src/user/highway/main.c +++ b/src/user/highway/main.c @@ -7,10 +7,11 @@ void main(const char *arg) { source(*arg ? arg : "user/default.rc"); char cmd_buf[128]; yield_task(); + struct history *cmd_hs = new_history(128); tell_user_sz("Portland Highway\nType \"help\" for help.\n"); while (1) { tell_user_sz("\n> "); - ask_user_line_sz(cmd_buf, 127); + ask_user_line_sz_with_history(cmd_buf, 127, cmd_hs); run_line(cmd_buf); } } \ No newline at end of file diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h index 43137e1..56d3740 100644 --- a/src/user/include/knob/block.h +++ b/src/user/include/knob/block.h @@ -10,4 +10,7 @@ bool blockequ(const void *a, const void *b, uint32_t size) __attribute__ ((__pur //returns length without null-terminator uint32_t strcpy(char *to, const char *from); +//allocates new memory +char *strdup(const char *from); + #endif \ No newline at end of file diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h index cd7676c..fb11c9b 100644 --- a/src/user/include/knob/user.h +++ b/src/user/include/knob/user.h @@ -4,6 +4,8 @@ #include #include +struct history; + char key_to_char(_key_code_t key) __attribute__ ((const)); void tell_user_sz(const char *sz); @@ -12,4 +14,9 @@ void tell_user_sz(const char *sz); //returns the real length of the string uint32_t ask_user_line_sz(char *sz, uint32_t max_length); +struct history *new_history(uint32_t max_entries); +void del_history(struct history *hs); + +uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs); + #endif \ No newline at end of file diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h index 331002e..14164aa 100644 --- a/src/user/include/pland/syscall.h +++ b/src/user/include/pland/syscall.h @@ -73,7 +73,7 @@ typedef enum { _KEY_NDOT, _KEY_NSLASH, /* 0xc0 unassigned */ - _KEY_DELETE, + _KEY_DELETE = 0xc1, _KEY_HOME, _KEY_END, _KEY_PUP, diff --git a/src/user/knob/block.c b/src/user/knob/block.c index 4ec0564..94bd073 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -1,5 +1,6 @@ -#include #include +#include +#include //unsophisticated, should copy by dwords where available void blockcpy(void *to, const void *from, uint32_t size) { @@ -23,4 +24,13 @@ uint32_t strcpy(char *to, const char *from) { to[i] = from[i]; while (from[i++]); return i - 1; +} + +char *strdup(const char *from) { + const char *end = from; + while (*(end++)) + ; + char *buf = get_block(end - from); + blockcpy(buf, from, end - from); + return buf; } \ No newline at end of file diff --git a/src/user/knob/user.c b/src/user/knob/user.c index dfcb791..1e273bb 100644 --- a/src/user/knob/user.c +++ b/src/user/knob/user.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -170,5 +172,128 @@ uint32_t ask_user_line_sz(char *sz, uint32_t max_length) { } sz[i] = '\0'; + return i; +} + +struct history_entry { + struct history_entry *prev; + struct history_entry *next; + const char *contents; +}; + +struct history { + struct history_entry *earliest_history_item; + struct history_entry *latest_history_item; + uint32_t max_entries; + uint32_t cur_entries; +}; + +struct history *new_history(uint32_t max_entries) { + struct history *new = get_block(sizeof(struct history)); + new->latest_history_item = 0; + new->earliest_history_item = 0; + new->max_entries = max_entries; + new->cur_entries = 0; + return new; +} + +void del_history(struct history *hs) { + free_block(hs); + for (struct history_entry *he = hs->latest_history_item; he; he = he->prev) { + free_block(he); + free_block(he->contents); + } +} + +//return value and max_length don't include null terminator +uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs) { + char log_buf[2]; + log_buf[1] = '\0'; + struct history_entry *cur_he = 0; + + uint32_t i; + for (i = 0; i != max_length; ++i) { + char key; + replace: + key = get_key_char(); + if (!key) + goto replace; + if (key == (char)_KEY_UP) { + struct history_entry *new_cur_he = cur_he ? cur_he->prev : hs->latest_history_item; + if (new_cur_he) { + cur_he = new_cur_he; + for (uint32_t j = 0; j < i; ++j) + _log_string("\b"); + i = strcpy(sz, cur_he->contents); + _log_string(sz); + } + goto replace; + } + if (key == (char)_KEY_DOWN) { + cur_he = cur_he ? cur_he->next : 0; + for (uint32_t j = 0; j < i; ++j) + _log_string("\b"); + if (cur_he) { + i = strcpy(sz, cur_he->contents); + _log_string(sz); + } + else + i = 0; + goto replace; + } + if (key & 0x80) + goto replace;//TODO + if (key == '\b') { + if (i) { + --i; + _log_string("\b"); + } + goto replace; + } + + log_buf[0] = key; + _log_string(log_buf); + + if (key == '\n') + break; + sz[i] = key; + } + + sz[i] = '\0'; + + struct history_entry *new_he = get_block(sizeof(struct history_entry)); + new_he->contents = strdup(sz); + + new_he->next = 0; + if (hs->latest_history_item) { + new_he->prev = hs->latest_history_item; + hs->latest_history_item->next = new_he; + } + else + new_he->prev = 0; + hs->latest_history_item = new_he; + if (!hs->earliest_history_item) + hs->earliest_history_item = new_he; + if (hs->max_entries == hs->cur_entries) { + free_block(hs->earliest_history_item); + free_block(hs->earliest_history_item->contents); + hs->earliest_history_item->next->prev = 0; + hs->earliest_history_item = hs->earliest_history_item->next; + } + else + ++(hs->cur_entries); + + for (struct history_entry *check_he = hs->latest_history_item->prev; check_he; check_he = check_he->prev) { + if (blockequ(check_he->contents, sz, i + 1)) { + check_he->next->prev = check_he->prev; + if (check_he->prev) + check_he->prev->next = check_he->next; + else + hs->earliest_history_item = check_he->next; + free_block(check_he); + free_block(check_he->contents); + } + } + return i; } \ No newline at end of file -- cgit v1.2.3