summaryrefslogtreecommitdiff
path: root/src/user/lib/libc/std/readline.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib/libc/std/readline.c')
-rw-r--r--src/user/lib/libc/std/readline.c139
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;
+ }
+ }
+}