diff options
Diffstat (limited to 'com32/elflink/ldlinux/cli.c')
-rw-r--r-- | com32/elflink/ldlinux/cli.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c new file mode 100644 index 00000000..6ff30c64 --- /dev/null +++ b/com32/elflink/ldlinux/cli.c @@ -0,0 +1,486 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <console.h> +#include <com32.h> +#include <syslinux/adv.h> +#include <syslinux/config.h> +#include <setjmp.h> +#include <netinet/in.h> +#include <limits.h> +#include <minmax.h> +#include <linux/list.h> +#include <sys/exec.h> +#include <sys/module.h> +#include <dprintf.h> +#include <core.h> + +#include "getkey.h" +#include "menu.h" +#include "cli.h" +#include "config.h" + +static struct list_head cli_history_head; + +void clear_screen(void) +{ + //dprintf("enter"); + fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout); +} + +static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto) +{ + clock_t t0, t1; + int key; + + t0 = times(NULL); + key = get_key(stdin, *kbd_to ? *kbd_to : *tto); + + /* kbdtimeout only applies to the first character */ + if (*kbd_to) + *kbd_to = 0; + + t1 = times(NULL) - t0; + if (*tto) { + /* Timed out. */ + if (*tto <= (long long)t1) + key = KEY_NONE; + else { + /* Did it wrap? */ + if (*tto > totaltimeout) + key = KEY_NONE; + + *tto -= t1; + } + } + + return key; +} + +static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to, + clock_t *tto) +{ + int key; + int i = 0; + char buf[MAX_CMDLINE_LEN]; + const char *p = NULL; + struct cli_command *last_found; + struct cli_command *last_good = NULL; + + last_found = list_entry(cli_history_head.next, typeof(*last_found), list); + + memset(buf, 0, MAX_CMDLINE_LEN); + + printf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m"); + while (1) { + key = mygetkey_timeout(kbd_to, tto); + + if (key == KEY_CTRL('C')) { + return NULL; + } else if (key == KEY_CTRL('R')) { + if (i == 0) + continue; /* User typed nothing yet */ + /* User typed 'CTRL-R' again, so try the next */ + last_found = list_entry(last_found->list.next, typeof(*last_found), list); + } else if (key >= ' ' && key <= 'z') { + buf[i++] = key; + } else { + /* Treat other input chars as terminal */ + break; + } + + while (last_found) { + p = strstr(last_found->command, buf); + if (p) + break; + + if (list_is_last(&last_found->list, &cli_history_head)) + break; + + last_found = list_entry(last_found->list.next, typeof(*last_found), list); + } + + if (!p && !last_good) { + return NULL; + } else if (!p) { + continue; + } else { + last_good = last_found; + *cursor = p - last_good->command; + } + + printf("\033[?7l\033[?25l"); + /* Didn't handle the line wrap case here */ + printf("\033[1G\033[1;36m(reverse-i-search)\033[0m`%s': %s", + buf, last_good->command ? : ""); + printf("\033[K\r"); + } + + return last_good ? last_good->command : NULL; +} + + + +const char *edit_cmdline(const char *input, int top /*, int width */ , + int (*pDraw_Menu) (int, int, int), + void (*show_fkey) (int), bool *timedout) +{ + char cmdline[MAX_CMDLINE_LEN] = { }; + int key, len, prev_len, cursor; + int redraw = 0; + int x, y; + bool done = false; + const char *ret; + int width = 0; + struct cli_command *comm_counter = NULL; + clock_t kbd_to = kbdtimeout; + clock_t tto = totaltimeout; + + if (!width) { + int height; + if (getscreensize(1, &height, &width)) + width = 80; + } + + len = cursor = 0; + prev_len = 0; + x = y = 0; + + /* + * Before we start messing with the x,y coordinates print 'input' + * so that it follows whatever text has been written to the screen + * previously. + */ + printf("%s ", input); + + while (!done) { + if (redraw > 1) { + /* Clear and redraw whole screen */ + /* Enable ASCII on G0 and DEC VT on G1; do it in this order + to avoid confusing the Linux console */ + clear_screen(); + if (pDraw_Menu) + (*pDraw_Menu) (-1, top, 1); + prev_len = 0; + printf("\033[2J\033[H"); + // printf("\033[0m\033[2J\033[H"); + } + + if (redraw > 0) { + int dy, at; + + prev_len = max(len, prev_len); + + /* Redraw the command line */ + printf("\033[?25l"); + printf("\033[1G%s ", input); + + x = strlen(input); + y = 0; + at = 0; + while (at < prev_len) { + putchar(at >= len ? ' ' : cmdline[at]); + at++; + x++; + if (x >= width) { + printf("\r\n"); + x = 0; + y++; + } + } + printf("\033[K\r"); + + dy = y - (cursor + strlen(input) + 1) / width; + x = (cursor + strlen(input) + 1) % width; + + if (dy) { + printf("\033[%dA", dy); + y -= dy; + } + if (x) + printf("\033[%dC", x); + printf("\033[?25h"); + prev_len = len; + redraw = 0; + } + + key = mygetkey_timeout(&kbd_to, &tto); + + switch (key) { + case KEY_NONE: + /* We timed out. */ + *timedout = true; + return NULL; + + case KEY_CTRL('L'): + redraw = 2; + break; + + case KEY_ENTER: + case KEY_CTRL('J'): + ret = cmdline; + done = true; + break; + + case KEY_BACKSPACE: + case KEY_DEL: + if (cursor) { + memmove(cmdline + cursor - 1, cmdline + cursor, + len - cursor + 1); + len--; + cursor--; + redraw = 1; + } + break; + + case KEY_CTRL('D'): + case KEY_DELETE: + if (cursor < len) { + memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor); + len--; + redraw = 1; + } + break; + + case KEY_CTRL('U'): + if (len) { + len = cursor = 0; + cmdline[len] = '\0'; + redraw = 1; + } + break; + + case KEY_CTRL('W'): + if (cursor) { + int prevcursor = cursor; + + while (cursor && my_isspace(cmdline[cursor - 1])) + cursor--; + + while (cursor && !my_isspace(cmdline[cursor - 1])) + cursor--; + +#if 0 + memmove(cmdline + cursor, cmdline + prevcursor, + len - prevcursor + 1); +#else + { + int i; + char *q = cmdline + cursor; + char *p = cmdline + prevcursor; + for (i = 0; i < len - prevcursor + 1; i++) + *q++ = *p++; + } +#endif + len -= (prevcursor - cursor); + redraw = 1; + } + break; + + case KEY_LEFT: + case KEY_CTRL('B'): + if (cursor) { + cursor--; + redraw = 1; + } + break; + + case KEY_RIGHT: + case KEY_CTRL('F'): + if (cursor < len) { + putchar(cmdline[cursor]); + cursor++; + x++; + if (x >= width) { + printf("\r\n"); + y++; + x = 0; + } + } + break; + + case KEY_CTRL('K'): + if (cursor < len) { + cmdline[len = cursor] = '\0'; + redraw = 1; + } + break; + + case KEY_HOME: + case KEY_CTRL('A'): + if (cursor) { + cursor = 0; + redraw = 1; + } + break; + + case KEY_END: + case KEY_CTRL('E'): + if (cursor != len) { + cursor = len; + redraw = 1; + } + break; + + case KEY_F1: + case KEY_F2: + case KEY_F3: + case KEY_F4: + case KEY_F5: + case KEY_F6: + case KEY_F7: + case KEY_F8: + case KEY_F9: + case KEY_F10: + case KEY_F11: + case KEY_F12: + if (show_fkey != NULL) { + (*show_fkey) (key); + redraw = 1; + } + break; + case KEY_CTRL('P'): + case KEY_UP: + { + if (!list_empty(&cli_history_head)) { + struct list_head *next; + + if (!comm_counter) + next = cli_history_head.next; + else + next = comm_counter->list.next; + + comm_counter = + list_entry(next, typeof(*comm_counter), list); + + if (&comm_counter->list != &cli_history_head) + strcpy(cmdline, comm_counter->command); + + cursor = len = strlen(cmdline); + redraw = 1; + } + } + break; + case KEY_CTRL('N'): + case KEY_DOWN: + { + if (!list_empty(&cli_history_head)) { + struct list_head *prev; + + if (!comm_counter) + prev = cli_history_head.prev; + else + prev = comm_counter->list.prev; + + comm_counter = + list_entry(prev, typeof(*comm_counter), list); + + if (&comm_counter->list != &cli_history_head) + strcpy(cmdline, comm_counter->command); + + cursor = len = strlen(cmdline); + redraw = 1; + } + } + break; + case KEY_CTRL('R'): + { + /* + * Handle this case in another function, since it's + * a kind of special. + */ + const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto); + if (p) { + strcpy(cmdline, p); + len = strlen(cmdline); + } else { + cmdline[0] = '\0'; + cursor = len = 0; + } + redraw = 1; + } + break; + case KEY_TAB: + { + const char *p; + size_t len; + + /* Label completion enabled? */ + if (nocomplete) + break; + + p = cmdline; + len = 0; + while(*p && !my_isspace(*p)) { + p++; + len++; + } + + print_labels(cmdline, len); + redraw = 1; + break; + } + case KEY_CTRL('V'): + if (BIOSName) + printf("%s%s%s", syslinux_banner, + (char *)MK_PTR(0, BIOSName), copyright_str); + else + printf("%s%s", syslinux_banner, copyright_str); + + redraw = 1; + break; + + default: + if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) { + if (cursor == len) { + cmdline[len++] = key; + cmdline[len] = '\0'; + putchar(key); + cursor++; + x++; + if (x >= width) { + printf("\r\n\033[K"); + y++; + x = 0; + } + prev_len++; + } else { + if (cursor > len) + return NULL; + + memmove(cmdline + cursor + 1, cmdline + cursor, + len - cursor + 1); + cmdline[cursor++] = key; + len++; + redraw = 1; + } + } + break; + } + } + + printf("\033[?7h"); + + /* Add the command to the history if its length is larger than 0 */ + len = strlen(ret); + if (len > 0) { + comm_counter = malloc(sizeof(struct cli_command)); + comm_counter->command = malloc(sizeof(char) * (len + 1)); + strcpy(comm_counter->command, ret); + list_add(&(comm_counter->list), &cli_history_head); + } + + return len ? ret : NULL; +} + +static int __constructor cli_init(void) +{ + INIT_LIST_HEAD(&cli_history_head); + + return 0; +} + +static void __destructor cli_exit(void) +{ + /* Nothing to do */ +} |