diff options
Diffstat (limited to 'src/user/knob/user.c')
-rw-r--r-- | src/user/knob/user.c | 125 |
1 files changed, 125 insertions, 0 deletions
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 <pland/syscall.h> +#include <knob/block.h> +#include <knob/heap.h> #include <stdint.h> #include <stdbool.h> @@ -171,4 +173,127 @@ 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 |