diff --git a/src/frontend/com_help.c b/src/frontend/com_help.c index 1039ec386..d8ffebe6a 100644 --- a/src/frontend/com_help.c +++ b/src/frontend/com_help.c @@ -81,7 +81,7 @@ void com_help(wordlist *wl) else { while (wl != NULL) { struct comm *c; - for (c = &cp_coms[0]; c->co_func != NULL; c++) + for (c = &cp_coms[0]; c->co_comname != NULL; c++) { if (eq(wl->wl_word, c->co_comname)) { out_printf("%s ", c->co_comname); out_printf(c->co_help, cp_program); @@ -90,7 +90,8 @@ void com_help(wordlist *wl) out_send("\n"); break; } - if (c->co_func == NULL) { + } + if (c->co_comname == NULL) { /* See if this is aliased. */ struct alias *al; diff --git a/src/frontend/com_wr_ic.c b/src/frontend/com_wr_ic.c index cad8454fa..db9ebf1b5 100644 --- a/src/frontend/com_wr_ic.c +++ b/src/frontend/com_wr_ic.c @@ -18,6 +18,8 @@ void com_wric(wordlist* wl); /* Print the current node status to a file with format .ic V(node) = value + during a transient simulation which has been stopped, + by command 'stop' and which may continue by 'resume'. */ void com_wric(wordlist* wl) { @@ -32,11 +34,6 @@ com_wric(wordlist* wl) { else file = "dot_ic_out.txt"; - if ((fp = fopen(file, "w")) == NULL) { - perror(file); - return; - } - if (!ft_curckt) { fprintf(cp_err, "Error: there aren't any circuits loaded.\n"); return; @@ -48,6 +45,17 @@ com_wric(wordlist* wl) { ckt = ft_curckt->ci_ckt; + if (!ckt->CKTrhsOld) { + fprintf(stderr, "\nWarning: Command wrnodev is ignored!\n"); + fprintf(stderr, " You need to execute stop ... tran ... resume\n\n"); + return; + } + + if ((fp = fopen(file, "w")) == NULL) { + perror(file); + return; + } + fprintf(fp, "* Intermediate Transient Solution\n"); fprintf(fp, "* Circuit: %s\n", ft_curckt->ci_name); fprintf(fp, "* Recorded at simulation time: %g\n", ckt->CKTtime); 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/cpitf.c b/src/frontend/cpitf.c index 484b2ff49..ec92c981c 100644 --- a/src/frontend/cpitf.c +++ b/src/frontend/cpitf.c @@ -180,7 +180,6 @@ ft_cpinit(void) } cp_vset("prompt", CP_STRING, buf); - cp_vset("noglob", CP_BOOL, &t); cp_vset("brief", CP_BOOL, &t); /* Make vectors from values in predefs[] for the current plot. diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 9c5f0f405..a48e89724 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -179,8 +179,11 @@ com_listing(wordlist *wl) } else { if (type != LS_DECK && type != LS_RUNNABLE) fprintf(cp_out, "\t%s\n\n", ft_curckt->ci_name); - else if (type == LS_RUNNABLE) + else if (type == LS_RUNNABLE) { fprintf(cp_out, "* expanded deck of %s\n", ft_curckt->ci_name); + fprintf(cp_out, "* %s\n", ft_curckt->ci_deck->line); /* title line with extra '*' */ + ft_curckt->ci_deck = ft_curckt->ci_deck->nextcard; /* skip title */ + } inp_list(cp_out, expand ? ft_curckt->ci_deck : ft_curckt->ci_origdeck, ft_curckt->ci_options, type); diff --git a/src/frontend/inpc_probe.c b/src/frontend/inpc_probe.c index 825eef914..730ce30f0 100644 --- a/src/frontend/inpc_probe.c +++ b/src/frontend/inpc_probe.c @@ -1052,8 +1052,8 @@ static char *get_terminal_name(char* element, char *numberstr, NGHASHPTR instanc if (!allsubs) { char* instline = xcard->line; char* inst = gettok(&instline); - fprintf(stderr, "Warning: No .subckt line found during evaluating command .probe (...)!\n"); - fprintf(stderr, " failing instance: %s\n", inst); + fprintf(stderr, "Instance '%s' does not have an corresponding subcircuit '%s'!\n", inst, subcktname); + fprintf(stderr, " Is the model missing? .probe cannot determine subcircuit pin names.\n"); tfree(subcktname); tfree(inst); return tprintf("n%s", numberstr); diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index f5f1c1e73..97c822937 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -1009,6 +1009,10 @@ struct card *inp_readall(FILE *fp, const char *dir_name, rv = inp_read(fp, 0, dir_name, comfile, intfile); cc = rv.cc; + /* skip all pre-processing for expanded input files created by 'listing r' */ + if (ciprefix("* expanded deck of", cc->line)) + return cc; + /* files starting with *ng_script are user supplied command files */ if (cc && ciprefix("*ng_script", cc->line)) comfile = TRUE; diff --git a/src/frontend/parser/glob.c b/src/frontend/parser/glob.c index 9353a7235..2a1566cc3 100644 --- a/src/frontend/parser/glob.c +++ b/src/frontend/parser/glob.c @@ -79,13 +79,16 @@ static inline void strip_1st_char(wordlist *wl_node); static void tilde_expand_word(wordlist *wl_node); -/* For each word, go through two steps: expand the {}'s, and then do ?*[] - * globbing in them. Sort after the second phase but not the first... +/* For each word, go through two steps: expand the {}'s, and then do + * tilde-expansion in them (not available of Windows). * * Globbing of arbitrary levels of brace nesting and tilde expansion to the - * name of a "HOME" directory are supported. ?*[] are not */ + * name of a "HOME" directory are supported. File globbing (?*[]) is not */ wordlist *cp_doglob(wordlist *wlist) { + if (cp_noglob) + return wlist; + /* Expand {a,b,c} */ { wordlist *wl = wlist; diff --git a/src/frontend/plotting/gnuplot.c b/src/frontend/plotting/gnuplot.c index 00f94a220..27f727947 100644 --- a/src/frontend/plotting/gnuplot.c +++ b/src/frontend/plotting/gnuplot.c @@ -751,12 +751,12 @@ void ft_writesimple(double *xlims, double *ylims, struct dvec* scale = v->v_scale; /* If wr_singlescale is set, print scale name only in first column */ if (prscale) - fprintf(file_data, " %s", scale->v_name); + fprintf(file_data, "%s ", scale->v_name); if (isreal(v)) - fprintf(file_data, " %s", v->v_name); + fprintf(file_data, "%s ", v->v_name); else - fprintf(file_data, " %s %s", v->v_name, v->v_name); + fprintf(file_data, "%s %s ", v->v_name, v->v_name); if (singlescale) /* the following names are printed without scale vector names */ prscale = FALSE; 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/frontend/variable.c b/src/frontend/variable.c index ef28cffed..f4302e52c 100644 --- a/src/frontend/variable.c +++ b/src/frontend/variable.c @@ -19,7 +19,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "variable.h" -bool cp_noglob = TRUE; +bool cp_noglob = FALSE; bool cp_nonomatch = FALSE; bool cp_noclobber = FALSE; bool cp_ignoreeof = FALSE; 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 } diff --git a/src/xspice/cmpp/mod_lex.l b/src/xspice/cmpp/mod_lex.l index 444a7d2ba..fbb86eb5b 100644 --- a/src/xspice/cmpp/mod_lex.l +++ b/src/xspice/cmpp/mod_lex.l @@ -89,6 +89,8 @@ Z [0-9A-Za-z_] } while (ch != '\n'); } +\"(\\.|[^"\\])*\" {return TOK_IDENTIFIER;} /* Literal string. */ + ARGS {return TOK_ARGS;} INIT {return TOK_INIT;} CALLBACK {return TOK_CALLBACK;} diff --git a/src/xspice/cmpp/mod_yacc.y b/src/xspice/cmpp/mod_yacc.y index 4d3e00aa3..92433aca4 100644 --- a/src/xspice/cmpp/mod_yacc.y +++ b/src/xspice/cmpp/mod_yacc.y @@ -31,20 +31,13 @@ SUMMARY INTERFACES mod_yyparse() - Function 'yyparse()' is generated automatically - by UNIX 'yacc' utility and then converted to - 'mod_yyparse()' by UNIX 'sed' utility under - direction of Makefile. + by UNIX 'yacc' utility. All yy* global names + are converted to mod_yy* by #define. REFERENCED FILES mod_lex.l -NON-STANDARD FEATURES - - Names of functions generated by 'yacc' are translated by 'sed' - under direction of the Makefile to prevent collisions with - functions generated from ifs_yacc.y. - ============================================================================*/ @@ -388,8 +381,8 @@ mod_file : /* empty */ c_code : /* empty */ | c_code c_char | c_code macro - /*| TOK_RPAREN {yyerror ("Unmatched )"); YYERROR;} - | TOK_RBRACKET {yyerror ("Unmatched ]"); YYERROR;}*/ + | TOK_RPAREN {yyerror ("Unmatched )"); YYERROR;} + | TOK_RBRACKET {yyerror ("Unmatched ]"); YYERROR;} ; buffered_c_code : {init_buffer();} buffered_c_code2 @@ -416,10 +409,12 @@ buffered_c_char : TOK_IDENTIFIER {append (mod_yytext);} c_char : TOK_IDENTIFIER {fputs (mod_yytext, mod_yyout);} | TOK_MISC_C {fputs (mod_yytext, mod_yyout);} | TOK_COMMA {fputs (mod_yytext, mod_yyout);} + | TOK_LBRACKET TOK_RBRACKET {fputs ("[]", mod_yyout);} | TOK_LBRACKET {putc ('[', mod_yyout);} c_code TOK_RBRACKET {putc (']', mod_yyout);} + | TOK_LPAREN TOK_RPAREN {fputs ("()", mod_yyout);} | TOK_LPAREN {putc ('(', mod_yyout);} c_code TOK_RPAREN diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 662c4103f..78e578e99 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -95,10 +95,14 @@ cm-descr := \ .SECONDARY : $(cm-gens) +# When recursively making clean, cm-objs and cm-gens do not contain +# the files generated for individual code models, as cmpp has already gone +# and modlist and udnlist are empty. Those files are explicitly removed. cm-clean : -rm -f $(cm)/$(cm).cm -rm -f $(cm-descr) $(cm-objs) $(cm-gens) + -rm -f $(cm)/*/*.o $(cm)/*/*.c $(cm)/*/.deps/* -rm -f $(cm-deps) cm-distclean : diff --git a/src/xspice/icm/analog/delay/cfunc.mod b/src/xspice/icm/analog/delay/cfunc.mod index a1bd95d83..0830bcc12 100644 --- a/src/xspice/icm/analog/delay/cfunc.mod +++ b/src/xspice/icm/analog/delay/cfunc.mod @@ -298,13 +298,17 @@ void cm_delay(ARGS) delmin = loc->tdelmin; delmax = loc->tdelmax; - lcntrl = INPUT(cntrl); - if (lcntrl < 0) - lcntrl = 0.; - else if (lcntrl > 1.) - lcntrl = 1.; - if (PARAM(has_delay_cnt) == MIF_TRUE) { + if (!PORT_NULL(cntrl)) { + lcntrl = INPUT(cntrl); + if (lcntrl < 0) + lcntrl = 0.; + else if (lcntrl > 1.) + lcntrl = 1.; + } + else { + lcntrl = 0; + } delay = (delmax - delmin) * lcntrl + delmin; } diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index a1ccfb3ad..bdc35148e 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -227,6 +227,7 @@ false + KLU\x64\Debug;%(AdditionalLibraryDirectories)