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/knob/block.c | 12 ++++- src/user/knob/user.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) (limited to 'src/user/knob') 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