Hi, I picked up the following patches from Liu Aleaxander that he sent to the mailing list last year. They add some new features to the command line interface code and fix a couple of bugs. The following changes since commit 9ded45991b4fc83b40af963feb773ddca2589d74: ldlinux: Parse and store the "onerror" command line (2011-03-09 14:32:36 +0000) are available in the git repository at: git://git.zytor.com/users/mfleming/syslinux.git for-hpa/elflink/cmdline Liu Aleaxander (6): elflink: Fix the wrong malloc size in enter_cmdline elflink: Do clear screen even if we have no pDraw_Menu method elflink: Add Ctrl-p + Ctrl-n key binds elflink: use 'input' as the prompt of the CLI elflink: Add ctrl-R key bind support elflink: handle the NULL return of edit_cmdline com32/elflink/ldlinux/cli.c | 102 ++++++++++++++++++++++++++++++++++----- com32/elflink/ldlinux/ldlinux.c | 4 +- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c index 77d32cd..defc6d0 100644 --- a/com32/elflink/ldlinux/cli.c +++ b/com32/elflink/ldlinux/cli.c @@ -68,6 +68,65 @@ int mygetkey(clock_t timeout) } } +static const char * cmd_reverse_search(int *cursor) +{ + 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(0); + + 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 != &cli_history_head) { + p = strstr(last_found->command, buf); + if (p) + 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)) @@ -90,22 +149,20 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , width = 80; } - strncpy(cmdline, input, MAX_CMDLINE_LEN); cmdline[MAX_CMDLINE_LEN - 1] = '\0'; - len = cursor = strlen(cmdline); + len = cursor = 0; prev_len = 0; x = y = 0; while (!done) { - if (redraw > 1 && pDraw_Menu != NULL) { + 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(); - draw_menu(-1, top, 1); */ clear_screen(); - (*pDraw_Menu) (-1, top, 1); + if (pDraw_Menu) + (*pDraw_Menu) (-1, top, 1); prev_len = 0; // printf("\033[0m\033[2J\033[H"); } @@ -119,9 +176,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , printf("\033[?7l\033[?25l"); if (y) printf("\033[%dA", y); - printf("\033[1G\033[1;36m> \033[0m"); + printf("\033[1G\033[1;36m%s \033[0m", input); - x = 2; + x = strlen(input); y = 0; at = 0; while (at < prev_len) { @@ -136,8 +193,8 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , } printf("\033[K\r"); - dy = y - (cursor + 2) / width; - x = (cursor + 2) % width; + dy = y - (cursor + strlen(input) + 1) / width; + x = (cursor + strlen(input) + 1) % width; if (dy) { printf("\033[%dA", dy); @@ -286,6 +343,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , redraw = 1; } break; + case KEY_CTRL('P'): case KEY_UP: { if (!list_empty(&cli_history_head)) { @@ -302,6 +360,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , } } break; + case KEY_CTRL('N'): case KEY_DOWN: { if (!list_empty(&cli_history_head)) { @@ -318,6 +377,24 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , } } 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); + if (p) { + strcpy(cmdline, p); + len = strlen(cmdline); + } else { + cmdline[0] = '\0'; + len = 0; + } + redraw = 1; + } + break; + default: if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) { if (cursor == len) { @@ -369,9 +446,8 @@ void process_command(const char *cmd, bool history) if (history) { struct cli_command *comm; - comm = (struct cli_command *)malloc(sizeof(struct cli_command *)); - comm->command - (char *)malloc(sizeof(char) * (strlen(cmd) + 1)); + comm = malloc(sizeof(struct cli_command)); + comm->command = malloc(sizeof(char) * (strlen(cmd) + 1)); strcpy(comm->command, cmd); list_add(&(comm->list), &cli_history_head); } diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index b5a4409..5ebbd7f 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -17,7 +17,9 @@ static void enter_cmdline(void) /* Enter endless command line prompt, should support "exit" */ while (1) { - cmdline = edit_cmdline("", 1, NULL, NULL); + cmdline = edit_cmdline("syslinux$", 1, NULL, NULL); + if (!cmdline) + continue; /* feng: give up the aux check here */ //aux = list_entry(cli_history_head.next, typeof(*aux), list); //if (strcmp(aux->command, cmdline)) {