diff --git a/ANNOUNCE b/ANNOUNCE index 7520963d0..6f9be1a11 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -199,6 +199,11 @@ New command line editor features: mode, 7 will now move the cursor seven positions to the left. In vi control mode, this would be entered as: 7 . +- When the -b/--notify shell option is on and the vi or emacs/gmacs shell + line editor is in use, 'Done' and similar notifications from completed + background jobs are now inserted directly above the line you're typing, + without affecting your command line display. + New shell language features: - The &>file redirection shorthand (for >file 2>&1) is now available for diff --git a/NEWS b/NEWS index 7cc1f0622..ad0b6ec15 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,17 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0 Any uppercase BUG_* names are modernish shell bug IDs. +2022-07-24: + +- New feature to make 'set -b'/'set -o notify' more usable. When that option + is on (and either the vi or emacs/gmacs line editor is in use), 'Done' and + similar notifications from completed background jobs no longer mess up the + command line you're typing. Instead, the notification is inserted directly + above the line you're typing, without affecting your command line display. + +- Fixed a bug that caused the -b/--notify option to only notify on one job if + more than one background job completed at the same time. + 2022-07-21: - Fixed a bug where a reproducible $RANDOM sequence (after assigning a diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index e40c95002..0bc8f72ef 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -48,9 +48,17 @@ #include "edit.h" #include "shlex.h" -static char CURSOR_UP[20] = { ESC, '[', 'A', 0 }; -static char KILL_LINE[20] = { ESC, '[', 'J', 0 }; - +static char *CURSOR_UP = Empty; /* move cursor up one line */ +static char *ERASE_EOS = Empty; /* erase to end of screen */ +#if _tput_terminfo +#define TPUT_CURSOR_UP "cuu1" +#define TPUT_ERASE_EOS "ed" +#elif _tput_termcap +#define TPUT_CURSOR_UP "up" +#define TPUT_ERASE_EOS "cd" +#else +#undef _pth_tput +#endif /* _tput_terminfo */ #if SHOPT_MULTIBYTE # define is_cntrl(c) ((c<=STRIP) && iscntrl(c)) @@ -499,17 +507,11 @@ int tty_alt(register int fd) */ int ed_window(void) { - int rows,cols; - register char *cp = nv_getval(COLUMNS); - if(cp) - cols = (int)strtol(cp, (char**)0, 10)-1; - else - { - astwinsize(2,&rows,&cols); - if(--cols <0) - cols = DFLTWINDOW-1; - } - if(cols < MINWINDOW) + int cols; + sh_winsize(NIL(int*),&cols); + if(--cols < 0) + cols = DFLTWINDOW - 1; + else if(cols < MINWINDOW) cols = MINWINDOW; else if(cols > MAXWINDOW) cols = MAXWINDOW; @@ -546,23 +548,32 @@ void ed_ringbell(void) * send a carriage return line feed to the terminal */ -void ed_crlf(register Edit_t *ep) +#ifdef _pth_tput +/* + * Get or update a tput (terminfo or termcap) capability string. + */ +static void get_tput(char *tp, char **cpp) { -#ifdef cray - ed_putchar(ep,'\r'); -#endif /* cray */ -#ifdef u370 - ed_putchar(ep,'\r'); -#endif /* u370 */ -#ifdef VENIX - ed_putchar(ep,'\r'); -#endif /* VENIX */ - ed_putchar(ep,'\n'); - ed_flush(ep); + Shopt_t o = sh.options; + char *cp; + sigblock(SIGINT); + sh_offoption(SH_RESTRICTED); + sh_offoption(SH_VERBOSE); + sh_offoption(SH_XTRACE); + sfprintf(sh.strbuf,".sh.value=$(" _pth_tput " %s 2>/dev/null)",tp); + sh_trap(sfstruse(sh.strbuf),0); + if((cp = nv_getval(SH_VALNOD)) && (!*cpp || strcmp(cp,*cpp)!=0)) + { + if(*cpp && *cpp!=Empty) + free(*cpp); + *cpp = *cp ? sh_strdup(cp) : Empty; + } + nv_unset(SH_VALNOD); + sh.options = o; + sigrelease(SIGINT); } -#endif /* SHOPT_ESH || SHOPT_VSH */ +#endif /* _pth_tput */ -#if SHOPT_ESH || SHOPT_VSH /* ED_SETUP( max_prompt_size ) * * This routine sets up the prompt string @@ -584,17 +595,8 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) register int qlen = 1, qwid; char inquote = 0; ep->e_fd = fd; -#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 - sh_update_columns_lines(); -#ifdef SIGWINCH + ep->e_multiline = sh_editor_active() && sh_isoption(SH_MULTILINE); sh.winch = 0; -#endif #if SHOPT_EDPREDICT ep->hlist = 0; ep->nhlist = 0; @@ -616,18 +618,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) ep->e_hismax = ep->e_hismin = ep->e_hloff = 0; } ep->e_hline = ep->e_hismax; -#if SHOPT_ESH && SHOPT_VSH - if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) -#elif SHOPT_ESH - if(!sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) -#elif SHOPT_VSH - if(!sh_isoption(SH_VI)) -#else - if(1) -#endif /* SHOPT_ESH && SHOPT_VSH */ - ep->e_wsize = MAXLINE; - else - ep->e_wsize = ed_window()-2; + ep->e_wsize = sh_editor_active() ? ed_window()-2 : MAXLINE; ep->e_winsz = ep->e_wsize+2; ep->e_crlf = 1; ep->e_plen = 0; @@ -789,35 +780,17 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) #if SHOPT_ESH || SHOPT_VSH if(ep->e_multiline) { -#if defined(_pth_tput) && (_tput_terminfo || _tput_termcap) +#ifdef _pth_tput char *term; if(!ep->e_term) ep->e_term = nv_search("TERM",sh.var_tree,0); if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)e_termname) && strcmp(term,ep->e_termname)) { - Shopt_t o = sh.options; - sigblock(SIGINT); - sh_offoption(SH_RESTRICTED); - sh_offoption(SH_VERBOSE); - sh_offoption(SH_XTRACE); - /* get the cursor up sequence from tput */ -#if _tput_terminfo - sh_trap(".sh.subscript=$(" _pth_tput " cuu1 2>/dev/null)",0); -#elif _tput_termcap - sh_trap(".sh.subscript=$(" _pth_tput " up 2>/dev/null)",0); -#else -#error no tput method -#endif - if((pp = nv_getval(SH_SUBSCRNOD)) && strlen(pp) < sizeof(CURSOR_UP)) - strcopy(CURSOR_UP,pp); - else - CURSOR_UP[0] = '\0'; /* no escape sequence is better than a faulty one */ - nv_unset(SH_SUBSCRNOD); + get_tput(TPUT_CURSOR_UP,&CURSOR_UP); + get_tput(TPUT_ERASE_EOS,&ERASE_EOS); strcopy(ep->e_termname,term); - sh.options = o; - sigrelease(SIGINT); } -#endif +#endif /* _pth_tput */ ep->e_wsize = MAXLINE - (ep->e_plen+1); } #endif /* SHOPT_ESH || SHOPT_VSH */ @@ -880,47 +853,40 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) { if(sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; -#ifdef SIGWINCH -#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))) -#else - if(sh.winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI)) -#endif + /* + * If sh.winch is set, the number of window columns changed and/or there is a buffered + * job notification. When using a line editor, erase and redraw the command line. + */ + if(sh.winch && sh_editor_active() && sh_isstate(SH_INTERACTIVE)) { - /* redraw the prompt after receiving SIGWINCH */ - Edpos_t lastpos; - int n, rows, newsize; - /* move cursor to start of first line */ - ed_putchar(ep,'\r'); - ed_flush(ep); - astwinsize(2,&rows,&newsize); - n = (ep->e_plen+ep->e_cur)/++ep->e_winsz; - while(n--) - ed_putstring(ep,CURSOR_UP); - if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz)) + int n, newsize; + char *cp; + sh_winsize(NIL(int*),&newsize); + /* + * Try to move cursor to start of first line and pray it works... it's very + * failure-prone if the window size changed, especially on modern terminals + * that break the whole terminal abstraction by rewrapping lines themselves :( + */ + if(ep->e_multiline) { - /* clear the current command line */ - n = lastpos.line; - while(lastpos.line--) - { - ed_nputchar(ep,ep->e_winsz,' '); - ed_putchar(ep,'\n'); - } - ed_nputchar(ep,ep->e_winsz,' '); + n = (ep->e_plen + ep->e_cur) / newsize; while(n--) ed_putstring(ep,CURSOR_UP); } + ed_putchar(ep,'\r'); + /* clear the current command line */ + ed_putstring(ep,ERASE_EOS); ed_flush(ep); - sh_delay(.05,0); - astwinsize(2,&rows,&newsize); + /* show any buffered 'set -b' job notification(s) */ + if(sh.notifybuf && (cp = sfstruse(sh.notifybuf)) && *cp) + sfputr(sfstderr, cp, -1); + /* update window size */ ep->e_winsz = newsize-1; if(ep->e_winsz < MINWINDOW) ep->e_winsz = MINWINDOW; if(!ep->e_multiline && ep->e_wsize < MAXLINE) ep->e_wsize = ep->e_winsz-2; + /* redraw command line */ #if SHOPT_ESH && SHOPT_VSH if(sh_isoption(SH_VI)) vi_redraw(ep->e_vi); @@ -930,11 +896,9 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) vi_redraw(ep->e_vi); #elif SHOPT_ESH emacs_redraw(ep->e_emacs); -#endif +#endif /* SHOPT_ESH && SHOPT_VSH */ } -#endif /* SHOPT_ESH || SHOPT_VSH */ sh.winch = 0; -#endif /* SIGWINCH */ /* an interrupt that should be ignored */ errno = 0; if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0) @@ -1842,7 +1806,7 @@ void ed_histlist(Edit_t *ep,int n) ep->hlist = 0; ep->nhlist = 0; } - ed_putstring(ep,KILL_LINE); + ed_putstring(ep,ERASE_EOS); if(n) { for(i=1; (mp= *mpp) && i <= 16 ; i++,mpp++) diff --git a/src/cmd/ksh93/edit/emacs.c b/src/cmd/ksh93/edit/emacs.c index f82a0f602..0e372ce59 100644 --- a/src/cmd/ksh93/edit/emacs.c +++ b/src/cmd/ksh93/edit/emacs.c @@ -613,7 +613,7 @@ update: } continue; case cntl('L'): - ed_crlf(ep->ed); + putchar(ep->ed,'\n'); draw(ep,REFRESH); continue; case ESC : @@ -733,7 +733,8 @@ process: { out[eol++] = '\n'; out[eol] = '\0'; - ed_crlf(ep->ed); + putchar(ep->ed,'\n'); + ed_flush(ep->ed); } #if SHOPT_MULTIBYTE ed_external(out,buff); diff --git a/src/cmd/ksh93/edit/vi.c b/src/cmd/ksh93/edit/vi.c index f0c3a7cd2..d2335b2e9 100644 --- a/src/cmd/ksh93/edit/vi.c +++ b/src/cmd/ksh93/edit/vi.c @@ -474,7 +474,10 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit pr_string(vp,Prompt); putstring(vp,0, last_phys+1); if(echoctl) - ed_crlf(vp->ed); + { + putchar('\n'); + ed_flush(vp->ed); + } else while(kill_erase-- > 0) putchar(' '); @@ -483,7 +486,10 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit if( term_char=='\n' ) { if(!echoctl) - ed_crlf(vp->ed); + { + putchar('\n'); + ed_flush(vp->ed); + } virtual[++last_virt] = '\n'; } vp->last_cmd = 'i'; @@ -596,7 +602,8 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit if( vp->addnl ) { virtual[++last_virt] = '\n'; - ed_crlf(vp->ed); + putchar('\n'); + ed_flush(vp->ed); } if( ++last_virt >= 0 ) { diff --git a/src/cmd/ksh93/features/cmds b/src/cmd/ksh93/features/cmds index 87d211c0d..e4853e301 100644 --- a/src/cmd/ksh93/features/cmds +++ b/src/cmd/ksh93/features/cmds @@ -13,6 +13,7 @@ tput_terminfo note{ does tput support terminfo codes }end run{ \"/*/tput\") tput=`echo "${_pth_tput}" | sed 's/^"//; s/"$//'` if "$tput" sgr0 >/dev/null 2>&1 && + "$tput" ed >/dev/null 2>&1 && "$tput" cuu1 >/dev/null 2>&1 then echo '#define _tput_terminfo 1 /* tput supports terminfo codes */' else echo '#define _tput_terminfo 0 /* tput does not support terminfo codes */' @@ -29,6 +30,7 @@ tput_termcap note{ does tput support termcap codes }end run{ \"/*/tput\") tput=`echo "${_pth_tput}" | sed 's/^"//; s/"$//'` if "$tput" me >/dev/null 2>&1 && + "$tput" cd >/dev/null 2>&1 && "$tput" up >/dev/null 2>&1 then echo '#define _tput_termcap 1 /* tput supports termcap codes */' else echo '#define _tput_termcap 0 /* tput does not support termcap codes */' diff --git a/src/cmd/ksh93/include/edit.h b/src/cmd/ksh93/include/edit.h index c8bed0af5..0e425ec9c 100644 --- a/src/cmd/ksh93/include/edit.h +++ b/src/cmd/ksh93/include/edit.h @@ -174,7 +174,6 @@ typedef struct edit (c<'J'?c+1-'A':(c+10-'J')))))))))))))))) #endif -extern void ed_crlf(Edit_t*); extern void ed_putchar(Edit_t*, int); extern void ed_ringbell(void); extern void ed_setup(Edit_t*,int, int); diff --git a/src/cmd/ksh93/include/fault.h b/src/cmd/ksh93/include/fault.h index f8682323a..fc8019728 100644 --- a/src/cmd/ksh93/include/fault.h +++ b/src/cmd/ksh93/include/fault.h @@ -117,7 +117,7 @@ struct checkpt extern noreturn void sh_done(int); extern void sh_fault(int); -extern void sh_update_columns_lines(void); +extern void sh_winsize(int*,int*); extern void sh_sigclear(int); extern void sh_sigdone(void); extern void sh_siginit(void); diff --git a/src/cmd/ksh93/include/io.h b/src/cmd/ksh93/include/io.h index 9a4bb80b7..73a2890a9 100644 --- a/src/cmd/ksh93/include/io.h +++ b/src/cmd/ksh93/include/io.h @@ -52,6 +52,21 @@ struct ionod; #endif /* !ARG_RAW */ +/* + * Check if there is an editor active while avoiding repetitive #if flaggery. + * The 0 definition is used to optimize out code if no editor is compiled in. + * (This is here and not in edit.h because io.h is far more widely included.) + */ +#if SHOPT_ESH && SHOPT_VSH +#define sh_editor_active() (sh_isoption(SH_VI) || sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)) +#elif SHOPT_ESH +#define sh_editor_active() (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)) +#elif SHOPT_VSH +#define sh_editor_active() (sh_isoption(SH_VI)!=0) +#else +#define sh_editor_active() 0 +#endif + extern int sh_iocheckfd(int); extern void sh_ioinit(void); extern int sh_iomovefd(int); diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h index 5a6336f93..17aab6f8a 100644 --- a/src/cmd/ksh93/include/shell.h +++ b/src/cmd/ksh93/include/shell.h @@ -312,9 +312,7 @@ struct Shell_s char funload; char used_pos; /* used positional parameter */ char universe; -#ifdef SIGWINCH - char winch; -#endif + char winch; /* set upon window size change or 'set -b' notification */ short arithrecursion; /* current arithmetic recursion level */ char indebug; /* set when in debug trap */ unsigned char ignsig; /* ignored signal in subshell */ @@ -366,6 +364,7 @@ struct Shell_s void *mktype; Sfio_t *strbuf; Sfio_t *strbuf2; + Sfio_t *notifybuf; /* for 'set -o notify' job notices */ Dt_t *first_root; Dt_t *prefix_root; Dt_t *last_root; diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index abb3dbdcc..8268165fd 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -23,7 +23,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2022-07-21" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2022-07-24" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index d35c515b6..3c6ded32e 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -7513,6 +7513,10 @@ above) are only exported while their name space is active. .B \-b Prints job completion messages as soon as a background job changes state rather than waiting for the next prompt. +If one of the shell line editors is in use (see +.I In-line Editing Options +above), the completion message is inserted directly above the +command line being typed. .TP 8 .B \-e Unless contained in a diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 16021210e..28dfd39de 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -74,10 +74,7 @@ void sh_fault(register int sig) sig &= ~SH_TRAP; #ifdef SIGWINCH if(sig==SIGWINCH) - { - sh_update_columns_lines(); - sh.winch = 1; - } + sh_winsize(NIL(int*),NIL(int*)); #endif /* SIGWINCH */ trap = sh.st.trapcom[sig]; if(sh.savesig) @@ -227,17 +224,35 @@ done: } /* - * update $COLUMNS and $LINES + * Get window size and update LINES and COLUMNS. + * Returns the sizes in the pointed-to ints if non-null. + * If the number of columns changed, flags a window size change in sh.winch. */ -void sh_update_columns_lines(void) +void sh_winsize(int *linesp, int *columnsp) { - int rows=0, cols=0; - int32_t v; - astwinsize(2,&rows,&cols); - if(v = cols) - nv_putval(COLUMNS, (char*)&v, NV_INT32|NV_RDONLY); - if(v = rows) - nv_putval(LINES, (char*)&v, NV_INT32|NV_RDONLY); + static int oldlines, oldcolumns; + int lines = oldlines, columns = oldcolumns; + int32_t i; + astwinsize(2,&lines,&columns); + if(linesp) + *linesp = lines; + if(columnsp) + *columnsp = columns; + /* + * Update LINES and COLUMNS only when the values changed; this makes + * LINES.set and COLUMNS.set shell discipline functions more useful. + */ + if((lines != oldlines || nv_isnull(LINES)) && (i = (int32_t)lines)) + { + nv_putval(LINES, (char*)&i, NV_INT32|NV_RDONLY); + oldlines = lines; + } + if((columns != oldcolumns || nv_isnull(COLUMNS)) && (i = (int32_t)columns)) + { + nv_putval(COLUMNS, (char*)&i, NV_INT32|NV_RDONLY); + oldcolumns = columns; + sh.winch = 1; + } } /* @@ -662,18 +677,8 @@ noreturn void sh_done(register int sig) #if SHOPT_ACCT sh_accend(); #endif /* SHOPT_ACCT */ -#if SHOPT_VSH || SHOPT_ESH - if(mbwide() -#if SHOPT_ESH - || sh_isoption(SH_EMACS) - || sh_isoption(SH_GMACS) -#endif -#if SHOPT_VSH - || sh_isoption(SH_VI) -#endif - ) + if(mbwide() && sh_editor_active()) tty_cooked(-1); -#endif /* SHOPT_VSH || SHOPT_ESH */ #ifdef JOBS if((sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_LOGIN_SHELL)) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP))) job_walk(sfstderr, job_hup, SIGHUP, NIL(char**)); diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c index 0668026b9..10001806d 100644 --- a/src/cmd/ksh93/sh/io.c +++ b/src/cmd/ksh93/sh/io.c @@ -2445,8 +2445,8 @@ void sh_menu(Sfio_t *outfile,int argn,char *argv[]) register char **arg; int nrow, ncol=1, ndigits=1; int fldsize, wsize = ed_window(); - char *cp = nv_getval(sh_scoped(LINES)); - nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW); + sh_winsize(&nrow,NIL(int*)); + nrow = nrow ? (2 * (nrow / 3) + 1) : NROW; for(i=argn;i >= 10;i /= 10) ndigits++; if(argn < nrow) diff --git a/src/cmd/ksh93/sh/jobs.c b/src/cmd/ksh93/sh/jobs.c index c60014040..02473fc64 100644 --- a/src/cmd/ksh93/sh/jobs.c +++ b/src/cmd/ksh93/sh/jobs.c @@ -292,7 +292,6 @@ int job_reap(register int sig) int nochild = 0, oerrno = errno, wstat; Waitevent_f waitevent = sh.waitevent; static int wcontinued = WCONTINUED; - int was_ttywait_on; if (vmbusy()) { errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen"); @@ -310,18 +309,14 @@ int job_reap(register int sig) else flags = WUNTRACED|wcontinued; sh.waitevent = 0; - was_ttywait_on = sh_isstate(SH_TTYWAIT); /* save tty wait state */ while(1) { if(!(flags&WNOHANG) && !sh.intrap && job.pwlist) { - sh_onstate(SH_TTYWAIT); if(waitevent && (*waitevent)(-1,-1L,0)) flags |= WNOHANG; } pid = waitpid((pid_t)-1,&wstat,flags); - if(!was_ttywait_on) - sh_offstate(SH_TTYWAIT); /* * some systems (Linux 2.6) may return EINVAL @@ -331,10 +326,20 @@ int job_reap(register int sig) if (pid<0 && errno==EINVAL && (flags&WCONTINUED)) pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED); sh_sigcheck(); - if(pid<0 && errno==EINTR && (sig||job.savesig)) + if(pid<0) { - errno = 0; - continue; + if(errno==EINTR && (sig||job.savesig)) + { + errno = 0; + continue; + } + if(errno==ECHILD) + { +#if SHOPT_BGX + job.numbjob = 0; +#endif /* SHOPT_BGX */ + nochild = 1; + } } if(pid<=0) break; @@ -474,23 +479,29 @@ int job_reap(register int sig) sh.sigflag[SIGCHLD] |= SH_SIGTRAP; sh.trapnote |= SH_SIGTRAP; } -#endif - } - if(errno==ECHILD) - { -#if SHOPT_BGX - job.numbjob = 0; -#endif /* SHOPT_BGX */ - nochild = 1; +#endif /* !SHOPT_BGX */ + /* Handle -b/--notify while waiting for command line input */ + if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT)) + { + if(sh_editor_active()) + { + /* Buffer the notification for ed_read() to show */ + if(!sh.notifybuf) + sh.notifybuf = sfstropen(); + outfile = sh.notifybuf; + job_list(pw,JOB_NFLAG); + sh.winch = 1; + } + else + { + outfile = sfstderr; + job_list(pw,JOB_NFLAG|JOB_NLFLAG); + sfsync(sfstderr); + } + job_unpost(pw,1); + } } sh.waitevent = waitevent; - if(pw && sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT)) - { - outfile = sfstderr; - job_list(pw,JOB_NFLAG|JOB_NLFLAG); - job_unpost(pw,1); - sfsync(sfstderr); - } if(sig) signal(sig, job_waitsafe); /* @@ -897,7 +908,8 @@ int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[ /* * list the given job * flag JOB_LFLAG for long listing - * flag JOB_NFLAG for list only jobs marked for notification + * flag JOB_NFLAG to list only jobs marked for notification + * flag JOB_NLFLAG to print an initial newline * flag JOB_PFLAG for process ID(s) only */ int job_list(struct process *pw,register int flag) diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c index 9b0cfbca6..8ad8897cb 100644 --- a/src/cmd/ksh93/sh/main.c +++ b/src/cmd/ksh93/sh/main.c @@ -341,22 +341,18 @@ int sh_main(int ac, char *av[], Shinit_f userinit) sh_onstate(SH_INTERACTIVE); #if SHOPT_ESH /* do not leave users without a line editor */ - if(!sh_isoption(SH_GMACS) -#if SHOPT_VSH - && !sh_isoption(SH_VI) -#endif /* SHOPT_VSH */ - && !is_option(&sh.offoptions,SH_EMACS)) + if(!sh_editor_active() && !is_option(&sh.offoptions,SH_EMACS)) sh_onoption(SH_EMACS); #endif /* SHOPT_ESH */ } -#ifdef SIGWINCH else { /* keep $COLUMNS and $LINES up to date even for scripts that don't trap SIGWINCH */ - sh_update_columns_lines(); + sh_winsize(NIL(int*),NIL(int*)); +#ifdef SIGWINCH signal(SIGWINCH,sh_fault); +#endif /* SIGWINCH */ } -#endif /* (Re)set PS4 and IFS, but don't export these now even if allexport is on. */ i = (sh_isoption(SH_ALLEXPORT) != 0); sh_offoption(SH_ALLEXPORT); diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index 0a8d2dbed..a1e9a3d14 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -1014,5 +1014,15 @@ r echo r ^ok\r\n$ ! +tst $LINENO <<"!" +L --notify does not report all simultaneously terminated jobs + +d 15 +p :test-1: +w set -b; sleep .1 & sleep .1 & sleep .1 & +u Done +u Done +u Done +! # ====== exit $((Errors<125?Errors:125))