From def3415b17165efeeb155b981aef524ef40f998d Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 15 Jan 2024 00:52:00 +0000 Subject: [PATCH] read -s: initialise history file in time for reading When emacs or vi mode is activated in a script, 'read -s' should allow the user to arrow up to the current shell history file ($HISTFILE, default ~/.sh_history). But it looks like the history file is not properly initialised for 'read -s' as it does not work on the first invocation: $ ksh -c 'set -o emacs; read -s foo' (type up arrow; beep -- before f840ce81, infinite loop) $ ksh -c 'set -o emacs; read -s foo; read -s foo' (type return, then up arrow; shell history appears) src/cmd/ksh93/bltins/read.c: sh_readline(): - Move the code block that initialises the shell history file to immediately before where the first read operation is performed. Discussion: https://github.com/ksh93/ksh/pull/701#issuecomment-1891059973 --- NEWS | 4 ++++ src/cmd/ksh93/bltins/read.c | 16 ++++++++-------- src/cmd/ksh93/tests/pty.sh | 11 +++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 2f5b6e8fa9d4..95482828d0df 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. an infinite loop after using the up arrow in emacs mode with an empty history file. +- Fixed a bug in 'read -s': in a script, the first invocation of that + command, with the emacs or vi shell option on, did not allow the user to + navigate through the shell history file. + 2024-01-11: - Fixed ancient incorrect behaviour in the 'kill' built-in: it sent SIGCONT diff --git a/src/cmd/ksh93/bltins/read.c b/src/cmd/ksh93/bltins/read.c index 193f6756f9aa..64debaadc6b7 100644 --- a/src/cmd/ksh93/bltins/read.c +++ b/src/cmd/ksh93/bltins/read.c @@ -361,6 +361,14 @@ int sh_readline(char **names, volatile int fd, int flags, ssize_t size, long tim if(timeout) timeslot = sh_timeradd(timeout,0,timedout,iop); } +#if !SHOPT_SCRIPTONLY + if((flags&S_FLAG) && !sh.hist_ptr) + { + sh_histinit(); + if(!sh.hist_ptr) + flags &= ~S_FLAG; + } +#endif if(flags&(N_FLAG|NN_FLAG)) { char buf[256],*var=buf,*cur,*end,*up,*v; @@ -516,14 +524,6 @@ int sh_readline(char **names, volatile int fd, int flags, ssize_t size, long tim } if(timeslot) sh_timerdel(timeslot); -#if !SHOPT_SCRIPTONLY - if((flags&S_FLAG) && !sh.hist_ptr) - { - sh_histinit(); - if(!sh.hist_ptr) - flags &= ~S_FLAG; - } -#endif if(cp) { cpmax = cp + c; diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index d98c25dffc8f..39bdc12c6b6b 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -1303,5 +1303,16 @@ r ^:child-1: kill -s HUP \$\$\r\n$ r ^Hangup\r\n$ ! +((SHOPT_VSH)) && HISTFILE=$tmp/tmp_histfile tst $LINENO <<"!" +L 'read -s' reads from history file on first go + +d 40 +p :test-1: +w "$SHELL" -o vi -c 'read -s "foo?:prompt: "' +p :prompt: +c \Ek +r ^:prompt: "\$SHELL" -o vi -c 'read -s "foo\?:prompt: "'$ +! + # ====== exit $((Errors<125?Errors:125))