diff options
Diffstat (limited to 'src/user/lib/libc/std/readline.c')
-rw-r--r-- | src/user/lib/libc/std/readline.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/user/lib/libc/std/readline.c b/src/user/lib/libc/std/readline.c new file mode 100644 index 0000000..c2237b6 --- /dev/null +++ b/src/user/lib/libc/std/readline.c @@ -0,0 +1,139 @@ +#include <readline.h> +#include <stdlib.h> + +char* freadln(FILE f) { + fprint(f, "\x1b[e"); // enable keyboard echo + int i; + + char *p = (char*)malloc(256); + char *b = p; + + while (1) { + int l = read(f, 0, 255, b); + if (l < 0) { + free(b); + return 0; + } + + for (i = 0; i < l; i++) { + if (b[i] == '\n') { + b[i+1] = 0; + return p; + } else if (b[i] == 27) { // ignore escape sequences + b[i] = 0; + l = i; + } + } + + int d = b - p + l; + + char* newp = (char*)malloc(d + 256); + memcpy(newp, p, d); + free(p); + p = newp; + b = p + d; + } +} + + +// ** READLINE + +char *freadline(FILE f, readline_history *h) { + int i; + fprint(f, "\x1b[h"); // disable keyboard echo + + if (h->str == 0) { + h->str = (char**)malloc(h->max * sizeof(char*)); + for (i = 0; i < h->max; i++) h->str[i] = 0; + h->n = 0; + } + + int lid; + if (h->n < h->max) { + lid = h->n++; + } else { + free(h->str[0]); + int i; + for (i = 0; i < h->max - 1; i++) { + h->str[i] = h->str[i+1]; + } + lid = h->max - 1; + h->str[lid] = 0; + } + + if (h->str[lid] == 0) h->str[lid] = (char*)malloc(256); + + char *str = h->str[lid]; + str[0] = 0; + char *cur = str; // position in string + int len = 0; // string length + + while (1) { + int finished = 0; + + int te = cur - str; + + char buf[16]; + int l = read(f, 0, 16, buf); + if (l < 0) return 0; + + if (buf[0] == 27) { + if (buf[1] == '[') { + if (buf[2] == 'A') { // up + if (lid > 0) { + lid--; + str = h->str[lid]; + len = strlen(str); + cur = str + len; + } + } else if (buf[2] == 'B') { // down + if (lid < h->n - 1) { + lid++; + str = h->str[lid]; + len = strlen(str); + cur = str + len; + } + } else if (buf[2] == 'C') { // forward (right) + if (cur < str + len) cur++; + } else if (buf[2] == 'D') { // back (left) + if (cur > str) cur--; + } + } else { + // ALT sequence - ignore + } + } else if (buf[0] == '\n') { + finished = 1; + cur = str + len; + } else if (buf[0] == '\b') { + if (cur > str) { + cur--; + len--; + char* c; + for (c = cur; *c != 0; c++) c[0] = c[1]; + } + } else if (buf[0] == '\t') { + // ignore tabs -- todo: tab completion???? haha + } else if (buf[0] >= ' ') { + if (l < 255) { + char* c; + for (c = cur + len; c >= cur; c--) c[1] = c[0]; + cur[0] = buf[0]; + cur++; + len++; + } + } + + // ASSUMPTION : everything will fit on one line... + if (te > 0) fprintf(f, "\x1b[%iD", te); + fprintf(f, "\x1b[K%s", str); + te = len - (cur - str); + if (te > 0) fprintf(f, "\x1b[%iD", te); + + + if (finished) { + fprintf(f, "\n"); + if (h->str[h->n-1][0] == 0) h->n--; + return str; + } + } +} |