diff --git a/src/frontend/control.c b/src/frontend/control.c index fb697f8e0..5c724ec12 100644 --- a/src/frontend/control.c +++ b/src/frontend/control.c @@ -615,9 +615,10 @@ getcommand(char *string) #if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) /* set cp_altprompt for use by the lexer - see parser/lexical.c */ cp_altprompt = get_alt_prompt(); +#else + cp_cwait = TRUE; #endif /* !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) */ - cp_cwait = TRUE; wlist = cp_parse(string); cp_cwait = FALSE; if (cp_debug) { diff --git a/src/frontend/signal_handler.c b/src/frontend/signal_handler.c index 058c3c352..4e72bfcf7 100644 --- a/src/frontend/signal_handler.c +++ b/src/frontend/signal_handler.c @@ -91,6 +91,7 @@ ft_sigintr(void) if (interrupt_counter >= 3) { fprintf(cp_err, "\nKilling, since %d interrupts have been requested\n\n", interrupt_counter); + cp_ccon(FALSE); controlled_exit(1); } @@ -99,6 +100,7 @@ ft_sigintr(void) } /* here we jump to the start of command processing in main() after resetting everything. */ + cp_background = FALSE; LONGJMP(jbuf, 1); } @@ -112,6 +114,32 @@ sigfloat(int code) LONGJMP(jbuf, 1); } +/* Shared handler for SIGTTIN and SIGTTOU. Restart event handling if caught + * attempting terminal IO as a background process. + */ + +bool cp_background = FALSE; + +#ifdef SIGTTIN +void +sigttio(void) +{ + if (cp_cwait) { + /* Attempted command input/output on the terminal while in background. + * Set background flag and restart event loop. + */ + cp_background = TRUE; + LONGJMP(jbuf, 1); + } else { + /* Non-command terminal IO in background. That should never happen. + * Stop. + */ + + (void) signal(SIGTSTP, SIG_DFL); + (void) kill(getpid(), SIGTSTP); /* This should stop us */ + } +} +#endif /* This should give a new prompt if cshpar is waiting for input. */ @@ -122,8 +150,10 @@ sigstop(void) { gr_clean(); cp_ccon(FALSE); - (void) signal(SIGTSTP, SIG_DFL); - (void) kill(getpid(), SIGTSTP); /* This should stop us */ + if (!cp_background) { + (void) signal(SIGTSTP, SIG_DFL); + (void) kill(getpid(), SIGTSTP); /* This should stop us */ + } } diff --git a/src/frontend/signal_handler.h b/src/frontend/signal_handler.h index 7ef02c6da..66168d818 100644 --- a/src/frontend/signal_handler.h +++ b/src/frontend/signal_handler.h @@ -8,6 +8,7 @@ void ft_sigintr(void); void sigfloat(int code); +void sigttio(void); void sigstop(void); void sigcont(void); void sigill(void); diff --git a/src/include/ngspice/cpextern.h b/src/include/ngspice/cpextern.h index fedf26307..b051e0bcd 100644 --- a/src/include/ngspice/cpextern.h +++ b/src/include/ngspice/cpextern.h @@ -67,7 +67,8 @@ extern wordlist *cp_parse(char *string); /* control.c */ -extern bool cp_cwait; +extern bool cp_cwait; // Interactive and awaiting command input. +extern bool cp_background; // Running in background. extern bool cp_dounixcom; extern char *cp_csep; extern char * get_alt_prompt(void); diff --git a/src/main.c b/src/main.c index 653d3ddcb..e3999a865 100644 --- a/src/main.c +++ b/src/main.c @@ -681,10 +681,32 @@ app_rl_readlines(void) history_set_pos(history_length); if (SETJMP(jbuf, 1)) { /* Set location to jump to after handling SIGINT (ctrl-C) */ - ft_sigintr_cleanup(); + if (!cp_background) + ft_sigintr_cleanup(); } - line = readline(prompt()); +#if defined(SIGTTIN) && !defined(X_DISPLAY_MISSING) + if (cp_background) { + /* This process is running in the background, so reading from + * the terminal will fail. Instead, call the X11 input loop + * directly. It will process X11 events until terminal input + * is available, then return. If the process is still in background + * readline() will then cause another SIGTTIN and this loop + * will restart at SETJMP(). Such polling sees to be the only way + * to detect a return to the foreground. + * + * Global cp_cwait is set early so that SIGTTOU from output + * caused by clicking in a plot window will not stop the program. + */ + + cp_cwait = TRUE; + app_event_func(); // Direct call to process X11 input. + } +#endif + cp_cwait = TRUE; + line = readline(cp_background ? NULL : prompt()); + cp_cwait = FALSE; + cp_background = FALSE; if (!line) { cp_evloop("quit"); @@ -706,7 +728,6 @@ app_rl_readlines(void) } tfree(expanded_line); } - tfree(line); } /* History gets written in ../fte/misccoms.c com_quit */ @@ -1189,6 +1210,10 @@ int main(int argc, char **argv) #ifdef SIGTSTP signal(SIGTSTP, (SIGNAL_FUNCTION) sigstop); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, (SIGNAL_FUNCTION) sigttio); + signal(SIGTTOU, (SIGNAL_FUNCTION) sigttio); #endif }