summaryrefslogtreecommitdiff
path: root/src/user/knob/user.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/knob/user.c')
-rw-r--r--src/user/knob/user.c125
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