summaryrefslogtreecommitdiff
path: root/com32/elflink/ldlinux/cli.c
diff options
context:
space:
mode:
Diffstat (limited to 'com32/elflink/ldlinux/cli.c')
-rw-r--r--com32/elflink/ldlinux/cli.c486
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 */
+}