From patchwork Sun Jan 18 20:42:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1593 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768769008; bh=8brEVj9grnTKeaxUQljUbh7It/+axzPKma1l8RWsT5Q=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=UOwRY++9lPcf5SAHW9LwcKmO00HsxBk/+SdpbZ/TJu3HmvrcSMnU2vWRxP+G4vB0w UOVKHSTTouEhBlhIGwqmgwFt72wh46KySnJcdkE9LyoAmDsY1BROuQR3mcM5XXST/r ZhHYVI/Kwoz+h0ULDrcCYoGnr2BeET3tA7J1hE5x5S79rV5CIMRlxLGtD3uscyOmSV /Z4jPM8qV9CtQI/mMrRt4DPgGUerFzcRDQiHxT8FM/EpEJ5LGva+BqsezXyH4gd9GE V5WV/2U5ID6zSuolr96r+j3K6AFTJt0JAGtXLPctY5OoCiymvQDw5ZUG2A5EvFEOeK fDJVN0L2b/yEQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 41E3369494 for ; Sun, 18 Jan 2026 13:43:28 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ebUofX6hfEN3 for ; Sun, 18 Jan 2026 13:43:28 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768769008; bh=8brEVj9grnTKeaxUQljUbh7It/+axzPKma1l8RWsT5Q=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=UOwRY++9lPcf5SAHW9LwcKmO00HsxBk/+SdpbZ/TJu3HmvrcSMnU2vWRxP+G4vB0w UOVKHSTTouEhBlhIGwqmgwFt72wh46KySnJcdkE9LyoAmDsY1BROuQR3mcM5XXST/r ZhHYVI/Kwoz+h0ULDrcCYoGnr2BeET3tA7J1hE5x5S79rV5CIMRlxLGtD3uscyOmSV /Z4jPM8qV9CtQI/mMrRt4DPgGUerFzcRDQiHxT8FM/EpEJ5LGva+BqsezXyH4gd9GE V5WV/2U5ID6zSuolr96r+j3K6AFTJt0JAGtXLPctY5OoCiymvQDw5ZUG2A5EvFEOeK fDJVN0L2b/yEQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 2DABC6948C for ; Sun, 18 Jan 2026 13:43:28 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768769005; bh=8R3uUhNyon4WsqNwrjw0X6E/QVL/JpaoYz66x1u0Sp8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZNpgPiPkbxHpDZalTnNudyEd/VHZPYiM6S2Dvsvcyw2qN+0XUyfxj/QfAEERElky2 6qUiTz/JnwiH1Tb1s/VtRG3zg9kWdOfsmTEee2q4NUkK54kXhhXsXdZ//kWP+5RrOL BarUwsKSQr4VxT6yx+7soZtaoixyf8Aj5SgkamZ55bldgy1d8DwrcQWFBbb32QbRwi km3STmpaNu73hsUTEVvmcp0wMcmd1qi1Jhe+bqqJRpjwoeS4upYD/Zkg09Sj2eaFuN T8K/66K4RjcL8nnVwDSTfFQt3xPXsg8kU3IVN2Jo9TrsknJroedepb1YEOiZ16NPgq hL5FlZOYuKRzw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6F1986946A; Sun, 18 Jan 2026 13:43:25 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id pHtUbJpOKoDx; Sun, 18 Jan 2026 13:43:25 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768769001; bh=tNaGiZ0QkvFO2VsBjt/n2Fu6H29VgzyOFsDnQnfugcg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HhGqdfvaoNEHVf3w+qTbD7ZQPJoTT+2iHetULYUXoa7VNgyISjQS6E0xBmOIT2nDU vTJBFIZRuK+kSUtb58uW7S1Y3BztibzP7/ai9dxpqx+3N086ci0riP6ietCANDCDK6 6MGyBZWBsK8Kzx2TMUHNmpHrA+fPka4tjTST9e+wM6fNM/1ox/yZP8V9cYDmT1LWe3 A8iwfOqUAujtURipYBIYXxJmMCEDWru6f0HbsPanC0VKyKZS6aA5DOcAB+R42mvXIS AM1/2B2+zC3/B6scvUjvl7EMG4BNxvbWAJl/mYQ5gWhTk2l+5Op5dqppe87cOPBUb2 laZ/Cr3bAGcbA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 14E1969394; Sun, 18 Jan 2026 13:43:21 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Sun, 18 Jan 2026 13:42:41 -0700 Message-ID: <20260118204303.1982533-3-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260118204303.1982533-1-sjg@u-boot.org> References: <20260118204303.1982533-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: OSX7HWUEEGECKNH725FPHR4SLAOZOSYT X-Message-ID-Hash: OSX7HWUEEGECKNH725FPHR4SLAOZOSYT X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 02/16] cli: Add putch callback to struct cli_line_state List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a callback function pointer to struct cli_line_state that allows redirection of character output during line editing. This enables expo textlines to direct output to the correct vidconsole context. Add a new Kconfig option CLI_READLINE_CALLBACK which is selected by EXPO When enabled, the callback is checked before outputting characters. When disabled, the compiler optimises away the check. Update all character-output functions in cli_readline.c to use the new cls_putch() helper, which calls the callback if set or falls back to putc() Add a few comments while we are here. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- boot/Kconfig | 1 + cmd/Kconfig | 8 +++++ common/cli_readline.c | 82 +++++++++++++++++++++++++++---------------- include/cli.h | 2 ++ 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index cde4472ca57..7ff0dedb748 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -973,6 +973,7 @@ config EXPO bool "Support for expos - groups of scenes displaying a UI" depends on VIDEO default y if BOOTMETH_VBE + select CLI_READLINE_CALLBACK if CMDLINE_EDITING help An expo is a way of presenting and collecting information from the user. It consists of a collection of 'scenes' of which only one is diff --git a/cmd/Kconfig b/cmd/Kconfig index 072ff879cd8..8a873b1d927 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -54,6 +54,14 @@ config CMDLINE_EDITING Enable editing and History functions for interactive command line input operations +config CLI_READLINE_CALLBACK + bool "Support a callback for character output" + depends on CMDLINE_EDITING + help + Enable a callback for character output during line editing. This + allows redirection of output to a different destination, such as + a vidconsole. This is used by expo to support textline editing. + config CMDLINE_PS_SUPPORT bool "Enable support for changing the command prompt string at run-time" depends on HUSH_PARSER diff --git a/common/cli_readline.c b/common/cli_readline.c index 244a287b435..81b0688da38 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -71,9 +71,23 @@ static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen) #define DEL7 ((char)127) #define CREAD_HIST_CHAR ('!') -#define getcmd_putch(ch) putc(ch) #define getcmd_getch() getchar() -#define getcmd_cbeep() getcmd_putch('\a') + +/** + * cls_putch() - Output a character, using callback if available + * + * @cls: CLI line state + * @ch: Character to output + */ +static void cls_putch(struct cli_line_state *cls, int ch) +{ + if (CONFIG_IS_ENABLED(CLI_READLINE_CALLBACK) && cls->putch) + cls->putch(cls, ch); + else + putc(ch); +} + +#define getcmd_cbeep(cls) cls_putch(cls, '\a') #ifdef CONFIG_XPL_BUILD #define HIST_MAX 3 @@ -95,12 +109,19 @@ static char *hist_list[HIST_MAX]; #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) -static void getcmd_putchars(int count, int ch) +/** + * cls_putchars() - Output a character multiple times + * + * @cls: CLI line state + * @count: Number of times to output the character + * @ch: Character to output + */ +static void cls_putchars(struct cli_line_state *cls, int count, int ch) { int i; for (i = 0; i < count; i++) - getcmd_putch(ch); + cls_putch(cls, ch); } static int hist_init(void) @@ -206,7 +227,7 @@ void cread_print_hist_list(void) #define BEGINNING_OF_LINE() { \ while (cls->num) { \ - getcmd_putch(CTL_BACKSPACE); \ + cls_putch(cls, CTL_BACKSPACE); \ cls->num--; \ } \ } @@ -215,7 +236,7 @@ void cread_print_hist_list(void) if (cls->num < cls->eol_num) { \ printf("%*s", (int)(cls->eol_num - cls->num), ""); \ do { \ - getcmd_putch(CTL_BACKSPACE); \ + cls_putch(cls, CTL_BACKSPACE); \ } while (--cls->eol_num > cls->num); \ } \ } @@ -228,15 +249,15 @@ void cread_print_hist_list(void) } \ } -static void cread_add_char(char ichar, int insert, uint *num, - uint *eol_num, char *buf, uint len) +static void cread_add_char(struct cli_line_state *cls, char ichar, int insert, + uint *num, uint *eol_num, char *buf, uint len) { uint wlen; /* room ??? */ if (insert || *num == *eol_num) { if (*eol_num > len - 1) { - getcmd_cbeep(); + getcmd_cbeep(cls); return; } (*eol_num)++; @@ -251,7 +272,7 @@ static void cread_add_char(char ichar, int insert, uint *num, putnstr(buf + *num, wlen); (*num)++; while (--wlen) - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } else { /* echo the character */ wlen = 1; @@ -261,11 +282,12 @@ static void cread_add_char(char ichar, int insert, uint *num, } } -static void cread_add_str(char *str, int strsize, int insert, - uint *num, uint *eol_num, char *buf, uint len) +static void cread_add_str(struct cli_line_state *cls, char *str, int strsize, + int insert, uint *num, uint *eol_num, char *buf, + uint len) { while (strsize--) { - cread_add_char(*str, insert, num, eol_num, buf, len); + cread_add_char(cls, *str, insert, num, eol_num, buf, len); str++; } } @@ -293,13 +315,13 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) return -EINTR; case CTL_CH('f'): if (cls->num < cls->eol_num) { - getcmd_putch(buf[cls->num]); + cls_putch(cls, buf[cls->num]); cls->num++; } break; case CTL_CH('b'): if (cls->num) { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); cls->num--; } break; @@ -314,9 +336,9 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) putnstr(buf + cls->num, wlen); } - getcmd_putch(' '); + cls_putch(cls, ' '); do { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } while (wlen--); cls->eol_num--; } @@ -346,11 +368,11 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) memmove(&buf[base], &buf[cls->num], cls->eol_num - base + 1); cls->num = base; - getcmd_putchars(wlen, CTL_BACKSPACE); + cls_putchars(cls, wlen, CTL_BACKSPACE); puts(buf + base); - getcmd_putchars(wlen, ' '); - getcmd_putchars(wlen + cls->eol_num - cls->num, - CTL_BACKSPACE); + cls_putchars(cls, wlen, ' '); + cls_putchars(cls, wlen + cls->eol_num - cls->num, + CTL_BACKSPACE); } break; case CTL_CH('x'): @@ -367,11 +389,11 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) wlen = cls->eol_num - cls->num; cls->num--; memmove(&buf[cls->num], &buf[cls->num + 1], wlen); - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); putnstr(buf + cls->num, wlen); - getcmd_putch(' '); + cls_putch(cls, ' '); do { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } while (wlen--); cls->eol_num--; } @@ -387,7 +409,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) hline = hist_next(); if (!hline) { - getcmd_cbeep(); + getcmd_cbeep(cls); break; } @@ -411,7 +433,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) /* do not autocomplete when in the middle */ if (cls->num < cls->eol_num) { - getcmd_cbeep(); + getcmd_cbeep(cls); break; } @@ -427,8 +449,8 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) } fallthrough; default: - cread_add_char(ichar, cls->insert, &cls->num, &cls->eol_num, - buf, cls->len); + cread_add_char(cls, ichar, cls->insert, &cls->num, + &cls->eol_num, buf, cls->len); break; } @@ -451,8 +473,8 @@ void cli_cread_init(struct cli_line_state *cls, char *buf, uint buf_size) cls->len = buf_size; if (init_len) - cread_add_str(buf, init_len, 0, &cls->num, &cls->eol_num, buf, - buf_size); + cread_add_str(cls, 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, diff --git a/include/cli.h b/include/cli.h index e183d561369..88f96c03cb3 100644 --- a/include/cli.h +++ b/include/cli.h @@ -36,6 +36,7 @@ struct cli_ch_state { * be set) * @buf: Buffer containing line * @prompt: Prompt for the line + * @putch: Function to call to output a character (NULL to use putc()) */ struct cli_line_state { uint num; @@ -46,6 +47,7 @@ struct cli_line_state { bool cmd_complete; char *buf; const char *prompt; + void (*putch)(struct cli_line_state *cls, int ch); }; /**