From 0f97e944b2bb08b7e13210fc6bea75817aee3237 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:05 -0600 Subject: cli: Move simple readline into a function Move this code into its own function since it is a separate implementation from the full version. Signed-off-by: Simon Glass --- common/cli_readline.c | 79 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 33 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index e83743e90c9..9a7c268719d 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -440,41 +440,22 @@ int cli_readline(const char *const prompt) return cli_readline_into_buffer(prompt, console_buffer, 0); } - -int cli_readline_into_buffer(const char *const prompt, char *buffer, - int timeout) +/** + * cread_line_simple() - Simple (small) command-line reader + * + * This supports only basic editing, with no cursor movement + * + * @prompt: Prompt to display + * @p: Text buffer to edit + * Return: length of text buffer, or -1 if input was cannncelled (Ctrl-C) + */ +static int cread_line_simple(const char *const prompt, char *p) { - char *p = buffer; -#ifdef CONFIG_CMDLINE_EDITING - unsigned int len = CONFIG_SYS_CBSIZE; - int rc; - static int initted; - - /* - * History uses a global array which is not - * writable until after relocation to RAM. - * Revert to non-history version if still - * running from flash. - */ - if (gd->flags & GD_FLG_RELOC) { - if (!initted) { - hist_init(); - initted = 1; - } - - if (prompt) - puts(prompt); - - rc = cread_line(prompt, p, &len, timeout); - return rc < 0 ? rc : len; - - } else { -#endif /* CONFIG_CMDLINE_EDITING */ char *p_buf = p; - int n = 0; /* buffer index */ - int plen = 0; /* prompt length */ - int col; /* output column cnt */ - char c; + int n = 0; /* buffer index */ + int plen = 0; /* prompt length */ + int col; /* output column cnt */ + char c; /* print prompt */ if (prompt) { @@ -567,6 +548,38 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, } } } +} + +int cli_readline_into_buffer(const char *const prompt, char *buffer, + int timeout) +{ + char *p = buffer; +#ifdef CONFIG_CMDLINE_EDITING + unsigned int len = CONFIG_SYS_CBSIZE; + int rc; + static int initted; + + /* + * History uses a global array which is not + * writable until after relocation to RAM. + * Revert to non-history version if still + * running from flash. + */ + if (gd->flags & GD_FLG_RELOC) { + if (!initted) { + hist_init(); + initted = 1; + } + + if (prompt) + puts(prompt); + + rc = cread_line(prompt, p, &len, timeout); + return rc < 0 ? rc : len; + + } else { +#endif /* CONFIG_CMDLINE_EDITING */ + return cread_line_simple(prompt, p); #ifdef CONFIG_CMDLINE_EDITING } #endif -- cgit v1.2.3 From 33eb0b9eef3360396aa0f650f8e1e01baf6dc181 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:06 -0600 Subject: cli: Add a command to show cmdline history There is a function for this but it is never used. Showing the history is a useful feature, so add a new 'history' command. Signed-off-by: Simon Glass --- common/cli_readline.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 9a7c268719d..f3ba76a62ec 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -160,8 +160,7 @@ static char *hist_next(void) return ret; } -#ifndef CONFIG_CMDLINE_EDITING -static void cread_print_hist_list(void) +void cread_print_hist_list(void) { int i; unsigned long n; @@ -179,7 +178,6 @@ static void cread_print_hist_list(void) i++; } } -#endif /* CONFIG_CMDLINE_EDITING */ #define BEGINNING_OF_LINE() { \ while (num) { \ -- cgit v1.2.3 From 039f8cc375fb9ad28def3403f2e3483c1ded571e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:07 -0600 Subject: cli: Drop some #ifdefs in cli_readline Add a few static inlines to avoid the need for #ifdefs in cli_readline_into_buffer() Signed-off-by: Simon Glass --- common/cli_readline.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index f3ba76a62ec..61f9ba99068 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -423,6 +423,18 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, return 0; } +#else /* !CONFIG_CMDLINE_EDITING */ + +static inline void hist_init(void) +{ +} + +static int cread_line(const char *const prompt, char *buf, unsigned int *len, + int timeout) +{ + return 0; +} + #endif /* CONFIG_CMDLINE_EDITING */ /****************************************************************************/ @@ -552,8 +564,7 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, int timeout) { char *p = buffer; -#ifdef CONFIG_CMDLINE_EDITING - unsigned int len = CONFIG_SYS_CBSIZE; + uint len = CONFIG_SYS_CBSIZE; int rc; static int initted; @@ -563,7 +574,7 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, * Revert to non-history version if still * running from flash. */ - if (gd->flags & GD_FLG_RELOC) { + if (IS_ENABLED(CONFIG_CMDLINE_EDITING) && (gd->flags & GD_FLG_RELOC)) { if (!initted) { hist_init(); initted = 1; @@ -576,9 +587,6 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, return rc < 0 ? rc : len; } else { -#endif /* CONFIG_CMDLINE_EDITING */ return cread_line_simple(prompt, p); -#ifdef CONFIG_CMDLINE_EDITING } -#endif } -- cgit v1.2.3 From 6321391ac3e310081768b6170554d4f49416b5c2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:08 -0600 Subject: cli: Drop #ifdefs for CONFIG_AUTO_COMPLETE in cli_readline Use a static inline and adjust the logic to avoid the need for #ifdefs in cli_readline_into_buffer() Signed-off-by: Simon Glass --- common/cli_readline.c | 85 +++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 61f9ba99068..458e927e492 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -386,27 +386,27 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, REFRESH_TO_EOL(); continue; } -#ifdef CONFIG_AUTO_COMPLETE - case '\t': { - int num2, col; + case '\t': + if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { + int num2, col; + + /* do not autocomplete when in the middle */ + if (num < eol_num) { + getcmd_cbeep(); + break; + } - /* do not autocomplete when in the middle */ - if (num < eol_num) { - getcmd_cbeep(); + buf[num] = '\0'; + col = strlen(prompt) + eol_num; + num2 = num; + if (cmd_auto_complete(prompt, buf, &num2, &col)) { + col = num2 - num; + num += col; + eol_num += col; + } break; } - - buf[num] = '\0'; - col = strlen(prompt) + eol_num; - num2 = num; - if (cmd_auto_complete(prompt, buf, &num2, &col)) { - col = num2 - num; - num += col; - eol_num += col; - } - break; - } -#endif + fallthrough; default: cread_add_char(ichar, insert, &num, &eol_num, buf, *len); @@ -519,14 +519,15 @@ static int cread_line_simple(const char *const prompt, char *p) continue; default: - /* - * Must be a normal character then - */ - if (n < CONFIG_SYS_CBSIZE-2) { - if (c == '\t') { /* expand TABs */ -#ifdef CONFIG_AUTO_COMPLETE + /* Must be a normal character then */ + if (n >= CONFIG_SYS_CBSIZE - 2) { /* Buffer full */ + putc('\a'); + break; + } + if (c == '\t') { /* expand TABs */ + if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { /* - * if auto completion triggered just + * if auto-completion triggered just * continue */ *p = '\0'; @@ -536,26 +537,24 @@ static int cread_line_simple(const char *const prompt, char *p) p = p_buf + n; /* reset */ continue; } -#endif - puts(tab_seq + (col & 07)); - col += 8 - (col & 07); - } else { - char __maybe_unused buf[2]; - - /* - * Echo input using puts() to force an - * LCD flush if we are using an LCD - */ - ++col; - buf[0] = c; - buf[1] = '\0'; - puts(buf); } - *p++ = c; - ++n; - } else { /* Buffer full */ - putc('\a'); + puts(tab_seq + (col & 07)); + col += 8 - (col & 07); + } else { + char __maybe_unused buf[2]; + + /* + * Echo input using puts() to force an LCD + * flush if we are using an LCD + */ + ++col; + buf[0] = c; + buf[1] = '\0'; + puts(buf); } + *p++ = c; + ++n; + break; } } } -- cgit v1.2.3 From dcc18ce0dbaf93d82ef7f0c6fe625c42313eca32 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:09 -0600 Subject: cli: Implement delete-word in cread_line() The Ctrl-W option is implemented in the cread_line_simple() but not in the full version. This seems odd, so add an implementation. Signed-off-by: Simon Glass --- common/cli_readline.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 458e927e492..687e239bfa7 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -89,6 +89,14 @@ static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */ #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) +static void getcmd_putchars(int count, int ch) +{ + int i; + + for (i = 0; i < count; i++) + getcmd_putch(ch); +} + static void hist_init(void) { int i; @@ -337,6 +345,29 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, case CTL_CH('o'): insert = !insert; break; + case CTL_CH('w'): + if (num) { + uint base; + + for (base = num - 1; + base >= 0 && buf[base] == ' ';) + base--; + for (; base > 0 && buf[base - 1] != ' ';) + base--; + + /* now delete chars from base to num */ + wlen = num - base; + eol_num -= wlen; + memmove(&buf[base], &buf[num], + eol_num - base + 1); + num = base; + getcmd_putchars(wlen, CTL_BACKSPACE); + puts(buf + base); + getcmd_putchars(wlen, ' '); + getcmd_putchars(wlen + eol_num - num, + CTL_BACKSPACE); + } + break; case CTL_CH('x'): case CTL_CH('u'): BEGINNING_OF_LINE(); -- cgit v1.2.3 From fedd372976f499afb71f854f401cf3a4432ab8ec Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:10 -0600 Subject: cli: Use unsigned int instead of unsigned long The index values are not very large so it makes no sense to use a long integer. Change these to uint instead. Signed-off-by: Simon Glass --- common/cli_readline.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 687e239bfa7..f863404110c 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -171,7 +171,7 @@ static char *hist_next(void) void cread_print_hist_list(void) { int i; - unsigned long n; + uint n; n = hist_num - hist_max; @@ -211,10 +211,10 @@ void cread_print_hist_list(void) } \ } -static void cread_add_char(char ichar, int insert, unsigned long *num, - unsigned long *eol_num, char *buf, unsigned long len) +static void cread_add_char(char ichar, int insert, uint *num, + uint *eol_num, char *buf, uint len) { - unsigned long wlen; + uint wlen; /* room ??? */ if (insert || *num == *eol_num) { @@ -245,8 +245,7 @@ static void cread_add_char(char ichar, int insert, unsigned long *num, } static void cread_add_str(char *str, int strsize, int insert, - unsigned long *num, unsigned long *eol_num, - char *buf, unsigned long len) + uint *num, uint *eol_num, char *buf, uint len) { while (strsize--) { cread_add_char(*str, insert, num, eol_num, buf, len); @@ -258,9 +257,9 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, int timeout) { struct cli_ch_state s_cch, *cch = &s_cch; - unsigned long num = 0; - unsigned long eol_num = 0; - unsigned long wlen; + uint num = 0; + uint eol_num = 0; + uint wlen; char ichar; int insert = 1; int init_len = strlen(buf); -- cgit v1.2.3 From be5c2edd10cc0c5c1b938fc03bc7e7c35801a0bd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:11 -0600 Subject: cli: Convert cread_line() to use a struct for the main vars We want to reuse the editing code elsewhere. As a first step, move the common variables into a struct. This will allow us to eventually put the contents of the inner loop in a function, so it can be called from elsewhere. Signed-off-by: Simon Glass --- common/cli_readline.c | 116 ++++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 55 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index f863404110c..03624ca18af 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -188,27 +188,27 @@ void cread_print_hist_list(void) } #define BEGINNING_OF_LINE() { \ - while (num) { \ + while (cls->num) { \ getcmd_putch(CTL_BACKSPACE); \ - num--; \ + cls->num--; \ } \ } #define ERASE_TO_EOL() { \ - if (num < eol_num) { \ - printf("%*s", (int)(eol_num - num), ""); \ + if (cls->num < cls->eol_num) { \ + printf("%*s", (int)(cls->eol_num - cls->num), ""); \ do { \ getcmd_putch(CTL_BACKSPACE); \ - } while (--eol_num > num); \ + } while (--cls->eol_num > cls->num); \ } \ } -#define REFRESH_TO_EOL() { \ - if (num < eol_num) { \ - wlen = eol_num - num; \ - putnstr(buf + num, wlen); \ - num = eol_num; \ - } \ +#define REFRESH_TO_EOL() { \ + if (cls->num < cls->eol_num) { \ + uint wlen = cls->eol_num - cls->num; \ + putnstr(buf + cls->num, wlen); \ + cls->num = cls->eol_num; \ + } \ } static void cread_add_char(char ichar, int insert, uint *num, @@ -257,18 +257,18 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, int timeout) { struct cli_ch_state s_cch, *cch = &s_cch; - uint num = 0; - uint eol_num = 0; - uint wlen; + struct cli_line_state s_cls, *cls = &s_cls; char ichar; - int insert = 1; int init_len = strlen(buf); int first = 1; cli_ch_init(cch); + memset(cls, '\0', sizeof(struct cli_line_state)); + cls->insert = true; if (init_len) - cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len); + cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, + *len); while (1) { /* Check for saved characters */ @@ -309,30 +309,33 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, *buf = '\0'; /* discard input */ return -1; case CTL_CH('f'): - if (num < eol_num) { - getcmd_putch(buf[num]); - num++; + if (cls->num < cls->eol_num) { + getcmd_putch(buf[cls->num]); + cls->num++; } break; case CTL_CH('b'): - if (num) { + if (cls->num) { getcmd_putch(CTL_BACKSPACE); - num--; + cls->num--; } break; case CTL_CH('d'): - if (num < eol_num) { - wlen = eol_num - num - 1; + if (cls->num < cls->eol_num) { + uint wlen; + + wlen = cls->eol_num - cls->num - 1; if (wlen) { - memmove(&buf[num], &buf[num+1], wlen); - putnstr(buf + num, wlen); + memmove(&buf[cls->num], + &buf[cls->num + 1], wlen); + putnstr(buf + cls->num, wlen); } getcmd_putch(' '); do { getcmd_putch(CTL_BACKSPACE); } while (wlen--); - eol_num--; + cls->eol_num--; } break; case CTL_CH('k'): @@ -342,28 +345,28 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, REFRESH_TO_EOL(); break; case CTL_CH('o'): - insert = !insert; + cls->insert = !cls->insert; break; case CTL_CH('w'): - if (num) { - uint base; + if (cls->num) { + uint base, wlen; - for (base = num - 1; + for (base = cls->num - 1; base >= 0 && buf[base] == ' ';) base--; for (; base > 0 && buf[base - 1] != ' ';) base--; - /* now delete chars from base to num */ - wlen = num - base; - eol_num -= wlen; - memmove(&buf[base], &buf[num], - eol_num - base + 1); - num = base; + /* now delete chars from base to cls->num */ + wlen = cls->num - base; + cls->eol_num -= wlen; + memmove(&buf[base], &buf[cls->num], + cls->eol_num - base + 1); + cls->num = base; getcmd_putchars(wlen, CTL_BACKSPACE); puts(buf + base); getcmd_putchars(wlen, ' '); - getcmd_putchars(wlen + eol_num - num, + getcmd_putchars(wlen + cls->eol_num - cls->num, CTL_BACKSPACE); } break; @@ -375,17 +378,20 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, case DEL: case DEL7: case 8: - if (num) { - wlen = eol_num - num; - num--; - memmove(&buf[num], &buf[num+1], wlen); + if (cls->num) { + uint wlen; + + wlen = cls->eol_num - cls->num; + cls->num--; + memmove(&buf[cls->num], &buf[cls->num + 1], + wlen); getcmd_putch(CTL_BACKSPACE); - putnstr(buf + num, wlen); + putnstr(buf + cls->num, wlen); getcmd_putch(' '); do { getcmd_putch(CTL_BACKSPACE); } while (wlen--); - eol_num--; + cls->eol_num--; } break; case CTL_CH('p'): @@ -412,7 +418,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, /* copy new line into place and display */ strcpy(buf, hline); - eol_num = strlen(buf); + cls->eol_num = strlen(buf); REFRESH_TO_EOL(); continue; } @@ -421,30 +427,30 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, int num2, col; /* do not autocomplete when in the middle */ - if (num < eol_num) { + if (cls->num < cls->eol_num) { getcmd_cbeep(); break; } - buf[num] = '\0'; - col = strlen(prompt) + eol_num; - num2 = num; + buf[cls->num] = '\0'; + col = strlen(prompt) + cls->eol_num; + num2 = cls->num; if (cmd_auto_complete(prompt, buf, &num2, &col)) { - col = num2 - num; - num += col; - eol_num += col; + col = num2 - cls->num; + cls->num += col; + cls->eol_num += col; } break; } fallthrough; default: - cread_add_char(ichar, insert, &num, &eol_num, buf, - *len); + cread_add_char(ichar, cls->insert, &cls->num, + &cls->eol_num, buf, *len); break; } } - *len = eol_num; - buf[eol_num] = '\0'; /* lose the newline */ + *len = cls->eol_num; + buf[cls->eol_num] = '\0'; /* lose the newline */ if (buf[0] && buf[0] != CREAD_HIST_CHAR) cread_add_to_hist(buf); -- cgit v1.2.3 From 8d997aab6e231aa3b442ffe504b24709ff9c7c19 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:12 -0600 Subject: cli: Unindent some code in cread_line() Reduce the indentation level of this code so it is easier to review the next patch, which moves it into a function. Signed-off-by: Simon Glass --- common/cli_readline.c | 279 +++++++++++++++++++++++++------------------------- 1 file changed, 139 insertions(+), 140 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 03624ca18af..f5d1cb03433 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -292,162 +292,161 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, ichar = cli_ch_process(cch, ichar); } - /* ichar=0x0 when error occurs in U-Boot getc */ - if (!ichar) - continue; - - if (ichar == '\n') { - putc('\n'); - break; - } + /* ichar=0x0 when error occurs in U-Boot getc */ + if (!ichar) + continue; - switch (ichar) { - case CTL_CH('a'): - BEGINNING_OF_LINE(); - break; - case CTL_CH('c'): /* ^C - break */ - *buf = '\0'; /* discard input */ - return -1; - case CTL_CH('f'): - if (cls->num < cls->eol_num) { - getcmd_putch(buf[cls->num]); - cls->num++; - } - break; - case CTL_CH('b'): - if (cls->num) { - getcmd_putch(CTL_BACKSPACE); - cls->num--; - } - break; - case CTL_CH('d'): - if (cls->num < cls->eol_num) { - uint wlen; + if (ichar == '\n') { + putc('\n'); + break; + } - wlen = cls->eol_num - cls->num - 1; - if (wlen) { - memmove(&buf[cls->num], - &buf[cls->num + 1], wlen); - putnstr(buf + cls->num, wlen); - } + switch (ichar) { + case CTL_CH('a'): + BEGINNING_OF_LINE(); + break; + case CTL_CH('c'): /* ^C - break */ + *buf = '\0'; /* discard input */ + return -1; + case CTL_CH('f'): + if (cls->num < cls->eol_num) { + getcmd_putch(buf[cls->num]); + cls->num++; + } + break; + case CTL_CH('b'): + if (cls->num) { + getcmd_putch(CTL_BACKSPACE); + cls->num--; + } + break; + case CTL_CH('d'): + if (cls->num < cls->eol_num) { + uint wlen; - getcmd_putch(' '); - do { - getcmd_putch(CTL_BACKSPACE); - } while (wlen--); - cls->eol_num--; - } - break; - case CTL_CH('k'): - ERASE_TO_EOL(); - break; - case CTL_CH('e'): - REFRESH_TO_EOL(); - break; - case CTL_CH('o'): - cls->insert = !cls->insert; - break; - case CTL_CH('w'): - if (cls->num) { - uint base, wlen; - - for (base = cls->num - 1; - base >= 0 && buf[base] == ' ';) - base--; - for (; base > 0 && buf[base - 1] != ' ';) - base--; - - /* now delete chars from base to cls->num */ - wlen = cls->num - base; - cls->eol_num -= wlen; - memmove(&buf[base], &buf[cls->num], - cls->eol_num - base + 1); - cls->num = base; - getcmd_putchars(wlen, CTL_BACKSPACE); - puts(buf + base); - getcmd_putchars(wlen, ' '); - getcmd_putchars(wlen + cls->eol_num - cls->num, - CTL_BACKSPACE); - } - break; - case CTL_CH('x'): - case CTL_CH('u'): - BEGINNING_OF_LINE(); - ERASE_TO_EOL(); - break; - case DEL: - case DEL7: - case 8: - if (cls->num) { - uint wlen; - - wlen = cls->eol_num - cls->num; - cls->num--; + wlen = cls->eol_num - cls->num - 1; + if (wlen) { memmove(&buf[cls->num], &buf[cls->num + 1], wlen); - getcmd_putch(CTL_BACKSPACE); putnstr(buf + cls->num, wlen); - getcmd_putch(' '); - do { - getcmd_putch(CTL_BACKSPACE); - } while (wlen--); - cls->eol_num--; } - break; - case CTL_CH('p'): - case CTL_CH('n'): - { - char *hline; - if (ichar == CTL_CH('p')) - hline = hist_prev(); - else - hline = hist_next(); - - if (!hline) { - getcmd_cbeep(); - continue; - } + getcmd_putch(' '); + do { + getcmd_putch(CTL_BACKSPACE); + } while (wlen--); + cls->eol_num--; + } + break; + case CTL_CH('k'): + ERASE_TO_EOL(); + break; + case CTL_CH('e'): + REFRESH_TO_EOL(); + break; + case CTL_CH('o'): + cls->insert = !cls->insert; + break; + case CTL_CH('w'): + if (cls->num) { + uint base, wlen; + + for (base = cls->num - 1; + base >= 0 && buf[base] == ' ';) + base--; + for (; base > 0 && buf[base - 1] != ' ';) + base--; + + /* now delete chars from base to cls->num */ + wlen = cls->num - base; + cls->eol_num -= wlen; + memmove(&buf[base], &buf[cls->num], + cls->eol_num - base + 1); + cls->num = base; + getcmd_putchars(wlen, CTL_BACKSPACE); + puts(buf + base); + getcmd_putchars(wlen, ' '); + getcmd_putchars(wlen + cls->eol_num - cls->num, + CTL_BACKSPACE); + } + break; + case CTL_CH('x'): + case CTL_CH('u'): + BEGINNING_OF_LINE(); + ERASE_TO_EOL(); + break; + case DEL: + case DEL7: + case 8: + if (cls->num) { + uint wlen; + + wlen = cls->eol_num - cls->num; + cls->num--; + memmove(&buf[cls->num], &buf[cls->num + 1], wlen); + getcmd_putch(CTL_BACKSPACE); + putnstr(buf + cls->num, wlen); + getcmd_putch(' '); + do { + getcmd_putch(CTL_BACKSPACE); + } while (wlen--); + cls->eol_num--; + } + break; + case CTL_CH('p'): + case CTL_CH('n'): + { + char *hline; + + if (ichar == CTL_CH('p')) + hline = hist_prev(); + else + hline = hist_next(); + + if (!hline) { + getcmd_cbeep(); + continue; + } - /* nuke the current line */ - /* first, go home */ - BEGINNING_OF_LINE(); + /* nuke the current line */ + /* first, go home */ + BEGINNING_OF_LINE(); - /* erase to end of line */ - ERASE_TO_EOL(); + /* erase to end of line */ + ERASE_TO_EOL(); - /* copy new line into place and display */ - strcpy(buf, hline); - cls->eol_num = strlen(buf); - REFRESH_TO_EOL(); - continue; - } - case '\t': - if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { - int num2, col; - - /* do not autocomplete when in the middle */ - if (cls->num < cls->eol_num) { - getcmd_cbeep(); - break; - } + /* copy new line into place and display */ + strcpy(buf, hline); + cls->eol_num = strlen(buf); + REFRESH_TO_EOL(); + continue; + } + case '\t': + if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { + int num2, col; - buf[cls->num] = '\0'; - col = strlen(prompt) + cls->eol_num; - num2 = cls->num; - if (cmd_auto_complete(prompt, buf, &num2, &col)) { - col = num2 - cls->num; - cls->num += col; - cls->eol_num += col; - } + /* do not autocomplete when in the middle */ + if (cls->num < cls->eol_num) { + getcmd_cbeep(); break; } - fallthrough; - default: - cread_add_char(ichar, cls->insert, &cls->num, - &cls->eol_num, buf, *len); + + buf[cls->num] = '\0'; + col = strlen(prompt) + cls->eol_num; + num2 = cls->num; + if (cmd_auto_complete(prompt, buf, &num2, &col)) { + col = num2 - cls->num; + cls->num += col; + cls->eol_num += col; + } break; } + fallthrough; + default: + cread_add_char(ichar, cls->insert, &cls->num, &cls->eol_num, + buf, *len); + break; + } } *len = cls->eol_num; buf[cls->eol_num] = '\0'; /* lose the newline */ -- cgit v1.2.3 From e5509ce87b29f773b045200735bec2903b72eed4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:13 -0600 Subject: cli: Create a function to process characters Move most of the inner loop from cread_line() into a new function. This will allow using it from other code. This involves adding a few more members to the state struct. Signed-off-by: Simon Glass --- common/cli_readline.c | 108 +++++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 45 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index f5d1cb03433..62d419bb36a 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -253,52 +253,17 @@ static void cread_add_str(char *str, int strsize, int insert, } } -static int cread_line(const char *const prompt, char *buf, unsigned int *len, - int timeout) +int cread_line_process_ch(struct cli_line_state *cls, char ichar) { - struct cli_ch_state s_cch, *cch = &s_cch; - struct cli_line_state s_cls, *cls = &s_cls; - char ichar; - int init_len = strlen(buf); - int first = 1; - - cli_ch_init(cch); - memset(cls, '\0', sizeof(struct cli_line_state)); - cls->insert = true; - - if (init_len) - cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, - *len); - - while (1) { - /* Check for saved characters */ - ichar = cli_ch_process(cch, 0); - - if (!ichar) { - if (bootretry_tstc_timeout()) - return -2; /* timed out */ - if (first && timeout) { - u64 etime = endtick(timeout); - - while (!tstc()) { /* while no incoming data */ - if (get_ticks() >= etime) - return -2; /* timed out */ - schedule(); - } - first = 0; - } - - ichar = getcmd_getch(); - ichar = cli_ch_process(cch, ichar); - } + char *buf = cls->buf; /* ichar=0x0 when error occurs in U-Boot getc */ if (!ichar) - continue; + return -EAGAIN; if (ichar == '\n') { putc('\n'); - break; + return 0; } switch (ichar) { @@ -307,7 +272,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, break; case CTL_CH('c'): /* ^C - break */ *buf = '\0'; /* discard input */ - return -1; + return -EINTR; case CTL_CH('f'): if (cls->num < cls->eol_num) { getcmd_putch(buf[cls->num]); @@ -405,7 +370,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, if (!hline) { getcmd_cbeep(); - continue; + break; } /* nuke the current line */ @@ -419,7 +384,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, strcpy(buf, hline); cls->eol_num = strlen(buf); REFRESH_TO_EOL(); - continue; + break; } case '\t': if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { @@ -432,9 +397,9 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, } buf[cls->num] = '\0'; - col = strlen(prompt) + cls->eol_num; + col = strlen(cls->prompt) + cls->eol_num; num2 = cls->num; - if (cmd_auto_complete(prompt, buf, &num2, &col)) { + if (cmd_auto_complete(cls->prompt, buf, &num2, &col)) { col = num2 - cls->num; cls->num += col; cls->eol_num += col; @@ -444,9 +409,62 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, fallthrough; default: cread_add_char(ichar, cls->insert, &cls->num, &cls->eol_num, - buf, *len); + buf, cls->len); break; } + + return -EAGAIN; +} + +static int cread_line(const char *const prompt, char *buf, unsigned int *len, + int timeout) +{ + struct cli_ch_state s_cch, *cch = &s_cch; + struct cli_line_state s_cls, *cls = &s_cls; + char ichar; + int init_len = strlen(buf); + int first = 1; + + cli_ch_init(cch); + memset(cls, '\0', sizeof(struct cli_line_state)); + cls->insert = true; + cls->len = *len; + cls->prompt = prompt; + cls->buf = buf; + + if (init_len) + cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, + *len); + + while (1) { + int ret; + + /* Check for saved characters */ + ichar = cli_ch_process(cch, 0); + + if (!ichar) { + if (bootretry_tstc_timeout()) + return -2; /* timed out */ + if (first && timeout) { + u64 etime = endtick(timeout); + + while (!tstc()) { /* while no incoming data */ + if (get_ticks() >= etime) + return -2; /* timed out */ + schedule(); + } + first = 0; + } + + ichar = getcmd_getch(); + ichar = cli_ch_process(cch, ichar); + } + + ret = cread_line_process_ch(cls, ichar); + if (ret == -EINTR) + return -1; + else if (!ret) + break; } *len = cls->eol_num; buf[cls->eol_num] = '\0'; /* lose the newline */ -- cgit v1.2.3 From 657e14da835298a948eb313feffba6732fe9232e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:14 -0600 Subject: cli: Terminate the string in cread_line_process_ch() Rather than relying on the caller, terminate the string inside this function. Do this each time we return, whether input is finished or not. It is not needed when the input is aborted, since the string will be discarded in that case. Signed-off-by: Simon Glass --- common/cli_readline.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 62d419bb36a..fdb84d9204f 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -263,6 +263,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) if (ichar == '\n') { putc('\n'); + buf[cls->eol_num] = '\0'; /* terminate the string */ return 0; } @@ -413,6 +414,12 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) break; } + /* + * keep the string terminated...if we added a char at the end then we + * want a \0 after it + */ + buf[cls->eol_num] = '\0'; + return -EAGAIN; } @@ -467,7 +474,6 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, break; } *len = cls->eol_num; - buf[cls->eol_num] = '\0'; /* lose the newline */ if (buf[0] && buf[0] != CREAD_HIST_CHAR) cread_add_to_hist(buf); -- cgit v1.2.3 From 8fc041fe4c34bb6108444ee9970151f43add0ce9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:15 -0600 Subject: cli: Allow history to be disabled When inputting text outside the command line we don't want history to be accessible. Add an option to control this. Signed-off-by: Simon Glass --- common/cli_readline.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index fdb84d9204f..fa8f525d3a4 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -361,32 +361,33 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) break; case CTL_CH('p'): case CTL_CH('n'): - { - char *hline; + if (cls->history) { + char *hline; - if (ichar == CTL_CH('p')) - hline = hist_prev(); - else - hline = hist_next(); + if (ichar == CTL_CH('p')) + hline = hist_prev(); + else + hline = hist_next(); - if (!hline) { - getcmd_cbeep(); - break; - } + if (!hline) { + getcmd_cbeep(); + break; + } - /* nuke the current line */ - /* first, go home */ - BEGINNING_OF_LINE(); + /* nuke the current line */ + /* first, go home */ + BEGINNING_OF_LINE(); - /* erase to end of line */ - ERASE_TO_EOL(); + /* erase to end of line */ + ERASE_TO_EOL(); - /* copy new line into place and display */ - strcpy(buf, hline); - cls->eol_num = strlen(buf); - REFRESH_TO_EOL(); + /* copy new line into place and display */ + strcpy(buf, hline); + cls->eol_num = strlen(buf); + REFRESH_TO_EOL(); + break; + } break; - } case '\t': if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { int num2, col; @@ -438,6 +439,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, cls->len = *len; cls->prompt = prompt; cls->buf = buf; + cls->history = true; if (init_len) cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, -- cgit v1.2.3 From 3b487bf51115bfb9a0f85667a5608fc57788107c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:16 -0600 Subject: cli: Allow command completion to be disabled When inputting text outside the command line we don't want to use tab for command completion. Add an option to control this. Signed-off-by: Simon Glass --- common/cli_readline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index fa8f525d3a4..23913a857a9 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -389,7 +389,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) } break; case '\t': - if (IS_ENABLED(CONFIG_AUTO_COMPLETE)) { + if (IS_ENABLED(CONFIG_AUTO_COMPLETE) && cls->cmd_complete) { int num2, col; /* do not autocomplete when in the middle */ @@ -440,6 +440,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len, cls->prompt = prompt; cls->buf = buf; cls->history = true; + cls->cmd_complete = true; if (init_len) cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, -- cgit v1.2.3 From 39ee32166f607d4e30a74d46f82adb39e4134ec4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 Oct 2023 19:13:17 -0600 Subject: cli: Add a function to set up a new cread Create a init function so that it is easy to use command-line reading. Signed-off-by: Simon Glass --- common/cli_readline.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'common/cli_readline.c') diff --git a/common/cli_readline.c b/common/cli_readline.c index 23913a857a9..06b8d465044 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -424,28 +424,34 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) return -EAGAIN; } +void cli_cread_init(struct cli_line_state *cls, char *buf, uint buf_size) +{ + int init_len = strlen(buf); + + memset(cls, '\0', sizeof(struct cli_line_state)); + cls->insert = true; + cls->buf = buf; + cls->len = buf_size; + + if (init_len) + cread_add_str(buf, init_len, 0, &cls->num, &cls->eol_num, buf, + buf_size); +} + static int cread_line(const char *const prompt, char *buf, unsigned int *len, int timeout) { struct cli_ch_state s_cch, *cch = &s_cch; struct cli_line_state s_cls, *cls = &s_cls; char ichar; - int init_len = strlen(buf); int first = 1; cli_ch_init(cch); - memset(cls, '\0', sizeof(struct cli_line_state)); - cls->insert = true; - cls->len = *len; + cli_cread_init(cls, buf, *len); cls->prompt = prompt; - cls->buf = buf; cls->history = true; cls->cmd_complete = true; - if (init_len) - cread_add_str(buf, init_len, 1, &cls->num, &cls->eol_num, buf, - *len); - while (1) { int ret; -- cgit v1.2.3