From b509e92241d3899ec078a167912dd007ea977f3d Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Wed, 12 Jan 2022 19:19:42 +0000 Subject: [PATCH] edit: do not enable multiline mode with no editor active If neither gmacs/emacs nor vi are active, the multiline mode should not be enabled even if the multiline option is on. Doing so can cause inconsistent behaviour, particularly in multibyte locales where, if the shell is compiled with SHOPT_RAWONLY (as is default), the no-editor mode is actually handled by vi.c. Also, the new --histreedit and --histverify options only work in the emacs or vi editors, or in no-editor mode when handled by vi. Which means they cannot ever work if neither emacs or vi were compiled in (i.e. SHOPT_ESH and SHOPT_VSH were both disabled). In that case, there's no point in compiling in those options. Come to think of it, the same applies to the multiline option. All changed files: - Update SHOPT_ESH/SHOPT_VSH preprocessor directives as per above. src/cmd/ksh93/include/defs.h, src/cmd/ksh93/include/shell.h: - Move definitions of history expansion-related options to shell.h, which is where all the other shell options are defined. --- src/cmd/ksh93/data/builtins.c | 4 ++++ src/cmd/ksh93/data/options.c | 4 ++++ src/cmd/ksh93/edit/edit.c | 18 ++++++++++++++---- src/cmd/ksh93/include/defs.h | 6 ------ src/cmd/ksh93/include/edit.h | 2 ++ src/cmd/ksh93/include/shell.h | 9 +++++++++ src/cmd/ksh93/sh/init.c | 2 ++ src/cmd/ksh93/sh/io.c | 25 +++++++++++++++---------- src/cmd/ksh93/sh/shcomp.c | 2 ++ 9 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index dcef8229c..3cc4eff60 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -228,6 +228,7 @@ const char sh_set[] = #endif #if SHOPT_HISTEXPAND "[+histexpand?Equivalent to \b-H\b.]" +#if SHOPT_ESH || SHOPT_VSH "[+histreedit?If a history expansion (see \bhistexpand\b) " "fails, the command line is reloaded into the next " "prompt's edit buffer, allowing corrections.]" @@ -235,6 +236,7 @@ const char sh_set[] = "\bhistexpand\b) are not immediately executed. " "Instead, the expanded line is loaded into the next " "prompt's edit buffer, allowing further changes.]" +#endif #endif "[+ignoreeof?Prevents an interactive shell from exiting on " "reading an end-of-file.]" @@ -244,8 +246,10 @@ const char sh_set[] = "[+markdirs?A trailing \b/\b is appended to directories " "resulting from pathname expansion.]" "[+monitor?Equivalent to \b-m\b.]" +#if SHOPT_ESH || SHOPT_VSH "[+multiline?Use multiple lines when editing lines that are " "longer than the window width.]" +#endif "[+noclobber?Equivalent to \b-C\b.]" "[+noexec?Equivalent to \b-n\b.]" "[+noglob?Equivalent to \b-f\b.]" diff --git a/src/cmd/ksh93/data/options.c b/src/cmd/ksh93/data/options.c index fb2576341..2ad1c1cae 100644 --- a/src/cmd/ksh93/data/options.c +++ b/src/cmd/ksh93/data/options.c @@ -52,8 +52,10 @@ const Shtable_t shtab_options[] = #endif #if SHOPT_HISTEXPAND "histexpand", SH_HISTEXPAND, +#if SHOPT_ESH || SHOPT_VSH "histreedit", SH_HISTREEDIT, "histverify", SH_HISTVERIFY, +#endif #endif "ignoreeof", SH_IGNOREEOF, "interactive", SH_INTERACTIVE|SH_COMMANDLINE, @@ -63,7 +65,9 @@ const Shtable_t shtab_options[] = "login_shell", SH_LOGIN_SHELL|SH_COMMANDLINE, "markdirs", SH_MARKDIRS, "monitor", SH_MONITOR, +#if SHOPT_ESH || SHOPT_VSH "multiline", SH_MULTILINE, +#endif "notify", SH_NOTIFY, "pipefail", SH_PIPEFAIL, "posix", SH_POSIX, diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index 8cabe73b7..45684dad8 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -587,7 +587,13 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) register int qlen = 1, qwid; char inquote = 0; ep->e_fd = fd; - ep->e_multiline = sh_isoption(SH_MULTILINE)!=0; +#if SHOPT_ESH && SHOPT_VSH + ep->e_multiline = sh_isoption(SH_MULTILINE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS) || sh_isoption(SH_VI)); +#elif SHOPT_ESH + ep->e_multiline = sh_isoption(SH_MULTILINE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)); +#else + ep->e_multiline = sh_isoption(SH_MULTILINE) && sh_isoption(SH_VI); +#endif #ifdef SIGWINCH if(!(sh.sigflag[SIGWINCH]&SH_SIGFAULT)) { @@ -761,6 +767,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) if(pp-ep->e_prompt > qlen) ep->e_plen = pp - ep->e_prompt - qlen; *pp = 0; +#if SHOPT_ESH || SHOPT_VSH if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7) { register int shift = 7-ep->e_wsize; @@ -770,6 +777,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) ep->e_plen -= shift; last[-ep->e_plen-2] = '\r'; } +#endif /* SHOPT_ESH || SHOPT_VSH */ sfsync(sfstderr); if(fd == sffileno(sfstderr)) { @@ -789,6 +797,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) sfset(sfstderr,SF_READ,1); sfwrite(sfstderr,ep->e_outptr,0); ep->e_eol = reedit; +#if SHOPT_ESH || SHOPT_VSH if(ep->e_multiline) { #if defined(_pth_tput) && (_tput_terminfo || _tput_termcap) @@ -822,6 +831,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) #endif ep->e_wsize = MAXLINE - (ep->e_plen+1); } +#endif /* SHOPT_ESH || SHOPT_VSH */ if(ep->e_default && (pp = nv_getval(ep->e_default))) { n = strlen(pp); @@ -887,14 +897,13 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) { if(sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; +#if SHOPT_ESH || SHOPT_VSH #if SHOPT_ESH && SHOPT_VSH if(sh.winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))) #elif SHOPT_ESH if(sh.winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))) -#elif SHOPT_VSH - if(sh.winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI)) #else - if(0) + if(sh.winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI)) #endif { /* redraw the prompt after receiving SIGWINCH */ @@ -939,6 +948,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) emacs_redraw(ep->e_emacs); #endif } +#endif /* SHOPT_ESH || SHOPT_VSH */ sh.winch = 0; /* an interrupt that should be ignored */ errno = 0; diff --git a/src/cmd/ksh93/include/defs.h b/src/cmd/ksh93/include/defs.h index 96c26af56..5d707640d 100644 --- a/src/cmd/ksh93/include/defs.h +++ b/src/cmd/ksh93/include/defs.h @@ -103,12 +103,6 @@ extern char* sh_setenviron(const char*); #define SH_TYPE_PROFILE 020 #define SH_TYPE_RESTRICTED 040 -#if SHOPT_HISTEXPAND -# define SH_HISTEXPAND 43 -# define SH_HISTREEDIT 61 -# define SH_HISTVERIFY 62 -#endif - #ifndef PIPE_BUF # define PIPE_BUF 512 #endif diff --git a/src/cmd/ksh93/include/edit.h b/src/cmd/ksh93/include/edit.h index a1ace4c64..3a8a7c78e 100644 --- a/src/cmd/ksh93/include/edit.h +++ b/src/cmd/ksh93/include/edit.h @@ -135,7 +135,9 @@ typedef struct edit int e_stkoff; /* saved stack offset */ char **e_clist; /* completion list after = */ int e_nlist; /* number of elements on completion list */ +#if SHOPT_ESH || SHOPT_VSH int e_multiline; /* allow multiple lines for editing */ +#endif int e_winsz; /* columns in window */ Edpos_t e_curpos; /* cursor line and column */ Namval_t *e_default; /* variable containing default value */ diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h index 63b618bf5..6ad3ac04f 100644 --- a/src/cmd/ksh93/include/shell.h +++ b/src/cmd/ksh93/include/shell.h @@ -133,8 +133,17 @@ typedef union Shnode_u Shnode_t; #if SHOPT_BRACEPAT #define SH_BRACEEXPAND 42 #endif +#if SHOPT_HISTEXPAND +#define SH_HISTEXPAND 43 +#if SHOPT_ESH || SHOPT_VSH +#define SH_HISTREEDIT 44 +#define SH_HISTVERIFY 45 +#endif +#endif #define SH_POSIX 46 +#if SHOPT_ESH || SHOPT_VSH #define SH_MULTILINE 47 +#endif #define SH_NOBACKSLCTRL 48 #define SH_LOGIN_SHELL 67 #define SH_NOUSRPROFILE 79 /* internal use only */ diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index 2e5ca7153..4ae2d8a44 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -1334,7 +1334,9 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) #endif /* SHOPT_TIMEOUT */ /* initialize jobs table */ job_clear(); +#if SHOPT_ESH || SHOPT_VSH sh_onoption(SH_MULTILINE); +#endif if(argc>0) { int dolv_index; diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c index 1e76e00d8..f0a56550b 100644 --- a/src/cmd/ksh93/sh/io.c +++ b/src/cmd/ksh93/sh/io.c @@ -1947,21 +1947,22 @@ static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *ha int reedit=0, rsize; #if SHOPT_HISTEXPAND char *xp=0; -#endif -# if SHOPT_ESH +#endif /* SHOPT_HISTEXPAND */ +#if SHOPT_ESH if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)) readf = ed_emacsread; else -# endif /* SHOPT_ESH */ -# if SHOPT_VSH -# if SHOPT_RAWONLY - if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide())) -# else +#endif /* SHOPT_ESH */ +#if SHOPT_VSH +# if SHOPT_RAWONLY + /* In multibyte locales, vi handles the no-editor mode as well. TODO: is this actually still needed? */ + if(sh_isoption(SH_VI) || mbwide()) +# else if(sh_isoption(SH_VI)) -# endif +# endif readf = ed_viread; else -# endif /* SHOPT_VSH */ +#endif /* SHOPT_VSH */ readf = ed_read; if(sh.trapnote) { @@ -1993,7 +1994,9 @@ static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *ha { strlcpy(buff, xp, size); rsize = strlen(buff); +#if SHOPT_ESH || SHOPT_VSH if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read) +#endif /* SHOPT_ESH || SHOPT_VSH */ { sfputr(sfstderr, xp, -1); break; @@ -2001,18 +2004,20 @@ static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *ha reedit = rsize - 1; continue; } +#if SHOPT_ESH || SHOPT_VSH if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT)) { reedit = rsize - 1; continue; } +#endif /* SHOPT_ESH || SHOPT_VSH */ if(r & (HIST_ERROR|HIST_PRINT)) { *(char*)buff = '\n'; rsize = 1; } } -#endif +#endif /* SHOPT_HISTEXPAND */ break; } return(rsize); diff --git a/src/cmd/ksh93/sh/shcomp.c b/src/cmd/ksh93/sh/shcomp.c index c4836374c..d3701aa45 100644 --- a/src/cmd/ksh93/sh/shcomp.c +++ b/src/cmd/ksh93/sh/shcomp.c @@ -160,7 +160,9 @@ int main(int argc, char *argv[]) sh_onoption(SH_VERBOSE); if(!dflag) sfwrite(out,header,sizeof(header)); /* write binary shcomp header */ +#if SHOPT_ESH || SHOPT_VSH sh_offoption(SH_MULTILINE); +#endif sh.inlineno = 1; #if SHOPT_BRACEPAT sh_onoption(SH_BRACEEXPAND);