system/readline: add caller-selectable control handling

Let CPython handle Ctrl-D and signals without changing existing NSH behavior.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
This commit is contained in:
raiden00pl 2026-08-22 07:42:22 +02:00 committed by Xiang Xiao
parent 0923948d80
commit 9545e12054
4 changed files with 60 additions and 8 deletions

View file

@ -42,6 +42,11 @@
# undef CONFIG_READLINE_TABCOMPLETION
#endif
/* readline_fd_ex() options */
#define READLINE_CTRL_D_EOF (1 << 0)
#define READLINE_RETURN_ON_EINTR (1 << 1)
/* Make sure that the are valid values for all tab-completion settings */
#ifdef CONFIG_READLINE_TABCOMPLETION
@ -176,6 +181,19 @@ FAR const struct extmatch_vtable_s *
ssize_t readline_fd(FAR char *buf, int buflen, int infd, int outfd);
/****************************************************************************
* Name: readline_fd_ex
*
* readline_fd_ex() extends readline_fd() with caller-selected options.
* READLINE_CTRL_D_EOF makes Ctrl-D return EOF when the line is empty.
* READLINE_RETURN_ON_EINTR makes an interrupted input read return -EINTR
* instead of being retried.
*
****************************************************************************/
ssize_t readline_fd_ex(FAR char *buf, int buflen, int infd, int outfd,
unsigned int options);
/****************************************************************************
* Name: readline_stream
*

View file

@ -84,6 +84,6 @@ struct rl_common_s
****************************************************************************/
ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf, int buflen);
FAR char *buf, int buflen, unsigned int options);
#endif /* __APPS_SYSTEM_READLINE_READLINE_H */

View file

@ -49,12 +49,13 @@
# define RL_CMDHIST_LINELEN CONFIG_READLINE_CMD_HISTORY_LINELEN
#endif
#define CTRL_D 4 /* ^D - EOF or delete at cursor */
#ifdef CONFIG_READLINE_EDIT_EMACS
/* Emacs-style control key codes */
/* Additional Emacs-style control key codes */
# define CTRL_A 1 /* ^A - Home */
# define CTRL_B 2 /* ^B - Left */
# define CTRL_D 4 /* ^D - Delete at cursor */
# define CTRL_E 5 /* ^E - End */
# define CTRL_F 6 /* ^F - Right */
# define CTRL_K 11 /* ^K - Kill to end of line */
@ -849,7 +850,7 @@ FAR const struct extmatch_vtable_s *
****************************************************************************/
ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf,
int buflen)
int buflen, unsigned int options)
{
int escape;
int nch;
@ -1440,6 +1441,14 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf,
return submit_line(buf, nch);
}
/* Some callers use the conventional empty-line Ctrl-D as EOF. */
else if (ch == CTRL_D && (options & READLINE_CTRL_D_EOF) != 0 &&
nch == 0)
{
return EOF;
}
/* Emacs-style control keys */
#ifdef CONFIG_READLINE_EDIT_EMACS

View file

@ -43,9 +43,11 @@
struct readline_s
{
struct rl_common_s vtbl;
int infd;
unsigned int options;
int infd;
int errcode;
#ifdef CONFIG_READLINE_ECHO
int outfd;
int outfd;
#endif
};
@ -93,7 +95,13 @@ static int readline_getc(FAR struct rl_common_s *vtbl)
*/
int errcode = errno;
if (errcode != EINTR)
if (errcode == EINTR &&
(priv->options & READLINE_RETURN_ON_EINTR) != 0)
{
priv->errcode = errcode;
return EOF;
}
else if (errcode != EINTR)
{
/* Return EOF on any errors that we cannot handle */
@ -219,6 +227,16 @@ static void readline_write(FAR struct rl_common_s *vtbl,
****************************************************************************/
ssize_t readline_fd(FAR char *buf, int buflen, int infd, int outfd)
{
return readline_fd_ex(buf, buflen, infd, outfd, 0);
}
/****************************************************************************
* Name: readline_fd_ex
****************************************************************************/
ssize_t readline_fd_ex(FAR char *buf, int buflen, int infd, int outfd,
unsigned int options)
{
UNUSED(outfd);
@ -244,6 +262,8 @@ ssize_t readline_fd(FAR char *buf, int buflen, int infd, int outfd)
vtbl.vtbl.rl_getc = readline_getc;
vtbl.infd = infd;
vtbl.options = options;
vtbl.errcode = 0;
#ifdef CONFIG_READLINE_ECHO
vtbl.vtbl.rl_putc = readline_putc;
@ -253,12 +273,17 @@ ssize_t readline_fd(FAR char *buf, int buflen, int infd, int outfd)
/* The let the common readline logic do the work */
ret = readline_common(&vtbl.vtbl, buf, buflen);
ret = readline_common(&vtbl.vtbl, buf, buflen, options);
if (restore_termios)
{
tcsetattr(infd, TCSANOW, &cfg);
}
if (vtbl.errcode != 0)
{
ret = -vtbl.errcode;
}
return ret;
}