diff --git a/ChangeLog b/ChangeLog index 66872e1e3..003d78f53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,23 @@ 2004-01-10 Paolo Nenzi + * configure.in: changed version to rework-15pre2. + + * src/frontend/{com_history.c, cpitf.c, display.h, evaluate.c, + inpcom.c, misccoms.c, parser/glob.c, plotting/x11.c, resource.c, + runcoms.c, signal_handler.c, subckt.c, variable.c} + src/include/{ftedev.h, ngspice.h} + src/misc{ivars.c, Makefile.am, string.c, tilde.c, tilde.h, util.c, + util.h} + src/{main.c, nghelp.c, ngmultidec.c} + configure.in: + + Applied Stuart's patch tclspice-0.2.14_12-03-2003.diff.gz but + with libreadline disabled by default. (Stuart Brorson + ). + * Fixed makefiles in src/xspice/icm and src/xspice/cmpp to make distclean without barfing. (Stuart Brorson ). - * configure.in src/xspice/cmpp/Makefile src/xspice/cmpp/Makefile.in: Make configure automatically set paths for lex yacc and diff --git a/configure.in b/configure.in index 05be16cc0..3507f6f7b 100644 --- a/configure.in +++ b/configure.in @@ -9,7 +9,7 @@ dnl Create a configuration header AM_CONFIG_HEADER(config.h) dnl Initialize automake stuff -AM_INIT_AUTOMAKE(ng-spice-rework,15pre1) +AM_INIT_AUTOMAKE(ng-spice-rework,15pre2) dnl --enable-ansi : try to force --ansi option to the compiler @@ -116,6 +116,12 @@ dnl --enable-numparams: define NUMPARAMS in the code. This is for .param support AC_ARG_ENABLE(numparam, [ --enable-numparam Enable numparams library support, experimental *not in standard distribution*]) +dnl --with-readline: Includes GNU readline support into CLI. Default is "no". +dnl Including readline into ngspice is a violation of GPL license. It's use +dnl is discouraged. +AC_ARG_WITH(readline, + [ --with-readline[=yes/no] Enable GNU readline support for CLI. Default=no.]) + dnl Enable maintainer commands only if requested AM_MAINTAINER_MODE @@ -495,13 +501,19 @@ fi AC_SUBST(NUMPARAMDIR) AC_SUBST(NUMPARAMLIB) -dnl --with-readline : the user wants to use readline library -AC_ARG_WITH(readline, - [ --with-readline Use the readline library. WARNING: breaks GPL license], - AC_MSG_RESULT(Checking for readline library:) - AC_CHECK_LIB(readline, readline, AC_DEFINE(HAVE_GNUREADLINE) LIBS="$LIBS -lreadline") -) - +dnl ---- Option to include GNU readline support in ngspice CLI ---- +if test "$with_readline" != "yes"; then + AC_MSG_RESULT(GNU readline disabled.) + +else + AC_MSG_RESULT(Checking for readline:) + AC_CHECK_HEADERS([readline/readline.h readline/history.h], + [AC_DEFINE(HAVE_GNUREADLINE)], + [AC_MSG_ERROR(Couldn't find GNU readline headers.)]) + AC_CHECK_LIB(readline, readline, + [LIBS="$LIBS -lreadline"], + [AC_MSG_ERROR(Couldn't find readline libraries.)]) +fi AC_OUTPUT( \ Makefile \ diff --git a/src/frontend/com_history.c b/src/frontend/com_history.c index 0fa5cb2ed..35d94ab24 100644 --- a/src/frontend/com_history.c +++ b/src/frontend/com_history.c @@ -353,10 +353,10 @@ cp_addhistent(int event, wordlist *wlist) cp_lastone->hi_next = NULL; cp_lastone->hi_event = event; cp_lastone->hi_wlist = wl_copy(wlist); -#ifndef HAVE_GNUREADLINE +#ifndef HAVE_GNUREADLINE freehist(histlength - cp_maxhistlength); histlength++; -#endif +#endif return; } @@ -493,36 +493,38 @@ com_history(wordlist *wl) wl = wl->wl_next; rev = TRUE; } + #ifdef HAVE_GNUREADLINE /* Added GNU Readline Support -- Andrew Veliath */ { - HIST_ENTRY *he; - int i, N; + HIST_ENTRY *he; + int i, N; - N = (wl == NULL) ? history_length : atoi(wl->wl_word); + N = (wl == NULL) ? history_length : atoi(wl->wl_word); - if (N < 0) N = 0; - if (N > history_length) N = history_length; + if (N < 0) N = 0; + if (N > history_length) N = history_length; - if (rev) - for (i = history_length; i > 0 && N; --i, --N) { - he = history_get(i); - if (!he) return; - fprintf(cp_out, "%d\t%s\n", i, he->line); - } - else - for (i = history_length - N + 1; i <= history_length; ++i) { - he = history_get(i); - if (!he) return; - fprintf(cp_out, "%d\t%s\n", i, he->line); - } + if (rev) + for (i = history_length; i > 0 && N; --i, --N) { + he = history_get(i); + if (!he) return; + fprintf(cp_out, "%d\t%s\n", i, he->line); + } + else + for (i = history_length - N + 1; i <= history_length; ++i) { + he = history_get(i); + if (!he) return; + fprintf(cp_out, "%d\t%s\n", i, he->line); + } } -#else +#else if (wl == NULL) cp_hprint(cp_event - 1, cp_event - histlength, rev); else cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev); -#endif /* ifelse HAVE_GNUREADLINE */ +#endif /* ifelse HAVE_GNUREADLINE */ + return; } diff --git a/src/frontend/cpitf.c b/src/frontend/cpitf.c index 50b880220..018c95cc0 100644 --- a/src/frontend/cpitf.c +++ b/src/frontend/cpitf.c @@ -293,7 +293,8 @@ cp_istrue(wordlist *wl) void cp_periodic(void) { - ft_setflag = ft_intrpt = FALSE; + ft_setflag = FALSE; + ft_intrpt = FALSE; ft_ckspace(); ft_checkkids(); vec_gc(); diff --git a/src/frontend/display.h b/src/frontend/display.h index a0a9e2d3d..a1ab5e5a1 100644 --- a/src/frontend/display.h +++ b/src/frontend/display.h @@ -3,9 +3,15 @@ * 1999 E. Rouat ************/ +/* See if we have been already included */ #ifndef DISPLAY_H_INCLUDED #define DISPLAY_H_INCLUDED +/* Include a bunch of other stuff to make display.h work */ +#include +#include +#include + DISPDEVICE *FindDev(char *name); void DevInit(void); int NewViewport(GRAPH *pgraph); @@ -25,6 +31,5 @@ void SaveText(GRAPH *graph, char *text, int x, int y); int DevSwitch(char *devname); +#endif /* DISPLAY_H_INCLUDED */ - -#endif diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c index cf9cf0d10..5c05c3177 100644 --- a/src/frontend/evaluate.c +++ b/src/frontend/evaluate.c @@ -28,13 +28,13 @@ static char * mkcname(char what, char *v1, char *v2); * be lost, but that's no great loss. */ -static jmp_buf matherrbuf; +static sigjmp_buf matherrbuf; static RETSIGTYPE sig_matherr(void) { fprintf(cp_err, "Error: argument out of range for math function\n"); - longjmp(matherrbuf, 1); + siglongjmp(matherrbuf, 1); } @@ -221,7 +221,7 @@ doop(char what, /* Some of the math routines generate SIGILL if the argument is * out of range. Catch this here. */ - if (setjmp(matherrbuf)) { + if (sigsetjmp(matherrbuf, 1)) { return (NULL); } (void) signal(SIGILL, (SIGNAL_FUNCTION) sig_matherr); @@ -296,7 +296,7 @@ doop(char what, tfree(c2); } } - + /* va: garbage collection */ if (arg1->pn_value==NULL && v1!=NULL) vec_free(v1); if (arg2->pn_value==NULL && v2!=NULL) vec_free(v2); @@ -701,7 +701,7 @@ apply_func(struct func *func, struct pnode *arg) /* Some of the math routines generate SIGILL if the argument is * out of range. Catch this here. */ - if (setjmp(matherrbuf)) { + if (sigsetjmp(matherrbuf, 1)) { (void) signal(SIGILL, SIG_DFL); return (NULL); } diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 93736ebd2..aa1159bfa 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -131,11 +131,14 @@ inp_readall(FILE *fp, struct line **data) struct line *end = NULL, *cc = NULL, *prev = NULL, *working, *newcard; char *buffer, *s, *t, c; /* segfault fix */ - char *copys = NULL; + char *copys=NULL; int line = 1; FILE *newfp; -/* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc enabled */ + /* Must set this to NULL or non-tilde includes segfault. -- Tim Molteno */ + /* copys = NULL; */ /* This caused a parse error with gcc 2.96. Why??? */ + +/* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc enabled */ #ifdef XSPICE Ipc_Status_t ipc_status; char ipc_buffer[1025]; /* Had better be big enough */ @@ -172,7 +175,7 @@ inp_readall(FILE *fp, struct line **data) /* gtri - end - 12/12/90 */ #else while ((buffer = readline(fp))) { - #endif +#endif #ifdef TRACE /* SDB debug statement */ @@ -185,12 +188,15 @@ inp_readall(FILE *fp, struct line **data) || (strcmp(buffer,"\r\n") == 0) ) { continue; } - + + if (*buffer == '@') { tfree(buffer); /* was allocated by readline() */ break; } - /* loop through 'buffer' until end is reached. Then test for + + + /* loop through 'buffer' until end is reached. Then test for premature end. If premature end is reached, spew error and zap the line. */ for (s = buffer; *s && (*s != '\n'); s++); @@ -201,21 +207,21 @@ inp_readall(FILE *fp, struct line **data) if(*(s-1) == '\r') /* Zop the carriage return under windows */ *(s-1) = '\0'; - + /* now handle .include statements */ if (ciprefix(".include", buffer)) { - for (s = buffer; *s && !isspace(*s); s++)/* advance past non-space chars */ + for (s = buffer; *s && !isspace(*s); s++) /* advance past non-space chars */ ; - while (isspace(*s)) /* now advance past space chars */ + while (isspace(*s)) /* now advance past space chars */ s++; - if (!*s) { /* if at end of line, error */ + if (!*s) { /* if at end of line, error */ fprintf(cp_err, "Error: .include filename missing\n"); tfree(buffer); /* was allocated by readline() */ continue; } /* Now s points to first char after .include */ - for (t = s; *t && !isspace(*t); t++) /* now advance past non-space chars */ + for (t = s; *t && !isspace(*t); t++) /* now advance past non-space chars */ ; - *t = '\0'; /* place \0 and end of file name in buffer */ + *t = '\0'; /* place \0 and end of file name in buffer */ if (*s == '~') { copys = cp_tildexpand(s); /* allocates memory, but can also return NULL */ @@ -224,8 +230,8 @@ inp_readall(FILE *fp, struct line **data) } } - /* open file specified by .include statement */ - if (!(newfp = inp_pathopen(s, "r"))) { + /* open file specified by .include statement */ + if (!(newfp = inp_pathopen(s, "r"))) { perror(s); if(copys) { tfree(copys); /* allocated by the cp_tildexpand() above */ @@ -243,16 +249,17 @@ inp_readall(FILE *fp, struct line **data) /* Make the .include a comment */ *buffer = '*'; + /* now check if this is the first pass (i.e. end points to null) */ - if (end) { /* end already exists */ - end->li_next = alloc(struct line); /* create next card */ - end = end->li_next; /* make end point to next card */ + if (end) { /* end already exists */ + end->li_next = alloc(struct line); /* create next card */ + end = end->li_next; /* make end point to next card */ } else { - end = cc = alloc(struct line); /* create the deck & end. cc will - point to beginning of deck, end to - the end */ + end = cc = alloc(struct line); /* create the deck & end. cc will + point to beginning of deck, end to + the end */ } - + /* now fill out rest of struct end. */ end->li_next = NULL; end->li_error = NULL; @@ -267,28 +274,29 @@ inp_readall(FILE *fp, struct line **data) /* Fix the buffer up a bit. */ (void) strncpy(buffer + 1, "end of:", 7); - } /* end of .include handling */ + } /* end of .include handling */ - /* now check if this is the first pass (i.e. end points to null) */ - if (end) { /* end already exists */ - end->li_next = alloc(struct line); /* create next card */ - end = end->li_next; /* point to next card */ - } else { /* End doesn't exist. Create it. */ - end = cc = alloc(struct line); /* note that cc points to beginning - of deck, end to the end */ + /* now check if this is the first pass (i.e. end points to null) */ + if (end) { /* end already exists */ + end->li_next = alloc(struct line); /* create next card */ + end = end->li_next; /* point to next card */ + } else { /* End doesn't exist. Create it. */ + end = cc = alloc(struct line); /* note that cc points to beginning + of deck, end to the end */ } - - /* now put buffer into li */ + + /* now put buffer into li */ end->li_next = NULL; end->li_error = NULL; end->li_actual = NULL; end->li_line = buffer; end->li_linenum = line++; } + if (!end) { /* No stuff here */ *data = NULL; return; - } /* end while ((buffer = readline(fp))) */ + } /* end while ((buffer = readline(fp))) */ /* This should be freed because we are done with it. */ /* tfree(buffer); */ @@ -296,8 +304,7 @@ inp_readall(FILE *fp, struct line **data) /* Now clean up li: remove comments & stitch together continuation lines. */ working = cc->li_next; /* cc points to head of deck. Start with the - next card (skip title). */ - + next card. */ while (working) { for (s = working->li_line; (c = *s) && c <= ' '; s++) @@ -306,28 +313,30 @@ inp_readall(FILE *fp, struct line **data) #ifdef TRACE /* SDB debug statement */ printf("In inp_readall, processing linked list element s = %s . . . \n", s); -#endif - +#endif + switch (c) { - case '#': + case '#': case '$': case '*': case '\0': - /* this used to be commented out. Why? */ - /* prev = NULL; */ - working = working->li_next; /* for these chars, go to next card */ + /* this used to be commented out. Why? */ + /* prev = NULL; */ + working = working->li_next; /* for these chars, go to next card */ break; - case '+': /* handle continuation */ + + case '+': /* handle continuation */ if (!prev) { working->li_error = copy( "Illegal continuation line: ignored."); working = working->li_next; break; } - + /* create buffer and write last and current line into it. */ buffer = tmalloc(strlen(prev->li_line) + strlen(s) + 2); - (void) sprintf(buffer, "%s %s", prev->li_line, s + 1); + (void) sprintf(buffer, "%s %s", prev->li_line, s + 1); + s = prev->li_line; prev->li_line = buffer; prev->li_next = working->li_next; @@ -349,7 +358,8 @@ inp_readall(FILE *fp, struct line **data) } working = prev->li_next; break; - default: /* regular one-line card */ + + default: /* regular one-line card */ prev = working; working = working->li_next; break; @@ -360,7 +370,6 @@ inp_readall(FILE *fp, struct line **data) return; } - /*-------------------------------------------------------------------------* * * *-------------------------------------------------------------------------*/ diff --git a/src/frontend/misccoms.c b/src/frontend/misccoms.c index de3e16d9c..039e737e5 100644 --- a/src/frontend/misccoms.c +++ b/src/frontend/misccoms.c @@ -15,12 +15,10 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "hcomp.h" #include "variable.h" + #ifdef HAVE_GNUREADLINE #include #include - -extern int gnu_history_lines; -extern char gnu_history_file[]; #endif static void byemesg(void); @@ -77,8 +75,9 @@ com_quit(wordlist *wl) clearerr(stdin); *buf = 'y'; } - if ((*buf == 'y') || (*buf == 'Y') || (*buf == '\n')) + if ((*buf == 'y') || (*buf == 'Y') || (*buf == '\n')) { byemesg(); + } else { return; } @@ -86,14 +85,9 @@ com_quit(wordlist *wl) byemesg(); } else byemesg(); -#ifdef HAVE_GNUREADLINE - /* Added GNU Readline Support -- Andrew Veliath */ - if (cp_interactive && (cp_maxhistlength > 0)) { - stifle_history(cp_maxhistlength); - write_history(gnu_history_file); - } -#endif /* HAVE_GNUREADLINE */ + exit(EXIT_NORMAL); + } @@ -235,6 +229,18 @@ com_version(wordlist *wl) static void byemesg(void) { + +#ifdef HAVE_GNUREADLINE + extern char gnu_history_file[]; + + /* write out command history only when saying goodbye. */ + if (cp_interactive && (cp_maxhistlength > 0)) { + stifle_history(cp_maxhistlength); + write_history(gnu_history_file); + } +#endif /* HAVE_GNUREADLINE */ + printf("%s-%s done\n", ft_sim->simulator, ft_sim->version); return; } + diff --git a/src/frontend/parser/glob.c b/src/frontend/parser/glob.c index 7a46c3bda..9c366bf47 100644 --- a/src/frontend/parser/glob.c +++ b/src/frontend/parser/glob.c @@ -72,11 +72,8 @@ cp_tildexpand(char *string) { char *result; -#ifdef HAVE_READLINE result = tildexpand(string); -#else - result = tilde_expand(string); -#endif + if (!result) { if (cp_nonomatch) { return copy(string); diff --git a/src/frontend/plotting/x11.c b/src/frontend/plotting/x11.c index 8f337fcad..af277922e 100644 --- a/src/frontend/plotting/x11.c +++ b/src/frontend/plotting/x11.c @@ -796,6 +796,7 @@ zoomin(GRAPH *graph) wl = cp_parse(buf); (void) cp_addhistent(cp_event++, wl); } + #endif /* HAVE_GNUREADLINE */ (void) cp_evloop(buf); diff --git a/src/frontend/resource.c b/src/frontend/resource.c index a18e75fe1..3a2a949a6 100644 --- a/src/frontend/resource.c +++ b/src/frontend/resource.c @@ -386,13 +386,13 @@ printres(char *name) #define LOG2_PAGESIZE 8 -static jmp_buf env; +static sigjmp_buf env; static RETSIGTYPE fault(void) { signal(SIGSEGV, (SIGNAL_FUNCTION) fault); /* SysV style */ - longjmp(env, 1); + siglongjmp(env, 1); } static void * @@ -425,13 +425,13 @@ baseaddr(void) break; } - if (setjmp(env)) { + if (sigsetjmp(env, 1)) { low = at; continue; } else x = *at; - if (setjmp(env)) { + if (sigsetjmp(env, 1)) { low = at; continue; } else diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 97f801949..7b9d4dfcf 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -203,11 +203,11 @@ dosim(char *what, wordlist *wl) ct->ci_inprogress = FALSE; } if (ft_curckt->ci_inprogress && eq(what, "resume")) { - ft_setflag = TRUE; + ft_setflag = TRUE; /* don't allow abort upon interrupt during run */ ft_intrpt = FALSE; fprintf(cp_err, "Warning: resuming run in progress.\n"); com_resume((wordlist *) NULL); - ft_setflag = FALSE; + ft_setflag = FALSE; /* Now allow aborts again */ return 0; } @@ -215,7 +215,7 @@ dosim(char *what, wordlist *wl) * set a flag and let spice finish up, then control will be * passed back to the user. */ - ft_setflag = TRUE; + ft_setflag = TRUE; /* Don't allow abort upon interrupt during run. */ ft_intrpt = FALSE; if (dofile) { #ifdef PARALLEL_ARCH @@ -245,9 +245,9 @@ dosim(char *what, wordlist *wl) #else else if (!(rawfileFp = fopen(wl->wl_word, "w"))) { setvbuf(rawfileFp, rawfileBuf, _IOFBF, RAWBUF_SIZE); - perror(wl->wl_word); - ft_setflag = FALSE; - return 1; + perror(wl->wl_word); + ft_setflag = FALSE; + return 1; } #endif /* __MINGW32__ */ rawfileBinary = !ascii; @@ -261,14 +261,14 @@ dosim(char *what, wordlist *wl) } /*save rawfile name saj*/ if(last_used_rawfile) - tfree(last_used_rawfile); /* va: we should allways use tfree */ + tfree(last_used_rawfile); if(rawfileFp){ last_used_rawfile = copy(wl->wl_word); }else { last_used_rawfile = NULL; } /*end saj*/ - + /* Spice calls wrd_init and wrd_end itself */ ft_curckt->ci_inprogress = TRUE; if (eq(what,"sens2")) { @@ -282,7 +282,7 @@ dosim(char *what, wordlist *wl) if(g_ipc.enabled) ipc_send_errchk(); /* gtri - end - 12/12/90 */ -#endif +#endif } else ft_curckt->ci_inprogress = FALSE; } else { @@ -296,7 +296,7 @@ dosim(char *what, wordlist *wl) if(g_ipc.enabled) ipc_send_errchk(); /* gtri - end - 12/12/90 */ -#endif +#endif err = 0; } else if (err == 2) { fprintf(cp_err, "%s simulation(s) aborted\n", what); @@ -322,7 +322,7 @@ dosim(char *what, wordlist *wl) if (wl) wl->wl_prev = NULL; tfree(ww); - } + } return err; } diff --git a/src/frontend/signal_handler.c b/src/frontend/signal_handler.c index 37a2a7a56..adaac68ce 100644 --- a/src/frontend/signal_handler.c +++ b/src/frontend/signal_handler.c @@ -18,10 +18,15 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include #include "signal_handler.h" +#ifdef HAVE_GNUREADLINE +/* Added GNU Readline Support 11/3/97 -- Andrew Veliath */ +/* from spice3f4 patch to ng-spice. jmr */ +#include +#include +#include "fteinput.h" +#endif - - -extern jmp_buf jbuf; +extern sigjmp_buf jbuf; /* The (void) signal handlers... SIGINT is the only one that gets reset (by * cshpar) so it is global. They are ifdef BSD because of the sigmask @@ -32,32 +37,45 @@ extern jmp_buf jbuf; extern pid_t getpid (void); -/* not using SIGINT with GNU Readline - AV */ -#ifndef HAVE_GNUREADLINE +/* invoke this function upon keyboard interrupt */ RETSIGTYPE ft_sigintr(void) { + /* fprintf (cp_err, "Received interrupt. Handling it . . . . .\n"); */ - gr_clean(); + /* Reinstall ft_signintr as the signal handler. */ + (void) signal( SIGINT, (SIGNAL_FUNCTION) ft_sigintr ); - (void) signal( SIGINT, (SIGNAL_FUNCTION) ft_sigintr ); + gr_clean(); /* Clean up plot window */ - if (ft_intrpt) - fprintf(cp_err, "Interrupt (ouch)\n"); + if (ft_intrpt) /* check to see if we're being interrupted repeatedly */ + fprintf(cp_err, "Interrupted again (ouch)\n"); else { - fprintf(cp_err, "Interrupt\n"); + fprintf(cp_err, "Interrupted once . . .\n"); ft_intrpt = TRUE; } - if (ft_setflag) - return; -/* To restore screen after an interrupt to a plot for instance - */ + if (ft_setflag) { + return; /* just return without aborting simulation if ft_setflag = TRUE */ + } + +#ifdef HAVE_GNUREADLINE + /* Clean up readline after catching signals */ + /* One or all of these might be supurfluous */ + (void) rl_free_line_state(); + (void) rl_cleanup_after_signal(); + (void) rl_reset_after_signal(); +#endif + + /* To restore screen after an interrupt to a plot for instance */ cp_interactive = TRUE; - cp_resetcontrol(); - longjmp(jbuf, 1); + cp_resetcontrol(); + + /* here we jump to the start of command processing in main() after resetting everything. */ + siglongjmp(jbuf, 1); + } -#endif /* !HAVE_GNUREADLINE */ + RETSIGTYPE sigfloat(int sig, int code) @@ -66,7 +84,7 @@ sigfloat(int sig, int code) fperror("Error", code); rewind(cp_out); (void) signal( SIGFPE, (SIGNAL_FUNCTION) sigfloat ); - longjmp(jbuf, 1); + siglongjmp(jbuf, 1); } /* This should give a new prompt if cshpar is waiting for input. */ @@ -88,7 +106,7 @@ sigcont(void) { (void) signal(SIGTSTP, (SIGNAL_FUNCTION) sigstop); if (cp_cwait) - longjmp(jbuf, 1); + siglongjmp(jbuf, 1); } # endif diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c index 69ed615a5..04c74cc66 100644 --- a/src/frontend/subckt.c +++ b/src/frontend/subckt.c @@ -168,6 +168,10 @@ inp_subcktexpand(struct line *deck) */ for (c = deck; c; c = c->li_next) { /* iterate on lines in deck */ if (prefix(start, c->li_line)) { /* if we find .subckt . . . */ +#ifdef TRACE + /* SDB debug statement */ + printf("In inp_subcktexpand, found a .subckt: %s\n", c->li_line); +#endif for (s = c->li_line; *s && (*s != '('); s++) /* Iterate charwise along line until ( is found */ ; if (*s) { @@ -200,6 +204,10 @@ inp_subcktexpand(struct line *deck) /* doit does the actual splicing in of the .subckt . . . */ +#ifdef TRACE + /* SDB debug statement */ + printf("In inp_subcktexpand, about to call doit.\n"); +#endif ll = doit(deck); /* Now check to see if there are still subckt instances undefined... */ @@ -259,6 +267,11 @@ doit(struct line *deck) subs = NULL; submod = NULL; +#ifdef TRACE + /* SDB debug statement */ + printf("In doit, about to start first pass through deck.\n"); +#endif + /* First pass: xtract all the .subckts and stick pointers to them into sss. */ for (last = deck, lc = NULL; last; ) { if (prefix(sbend, last->li_line)) { /* if line == .ends */ @@ -383,6 +396,11 @@ doit(struct line *deck) wl->wl_word = gettok(&s); /* wl->wl_word now holds name of model */ } +#ifdef TRACE + /* SDB debug statement */ + printf("In doit, about to start second pass through deck.\n"); +#endif + error = 0; /* Second pass: do the replacements. */ do { /* while (!error && numpasses-- && gotone) */ @@ -444,8 +462,8 @@ doit(struct line *deck) lcc = inp_deckcopy(sss->su_def); /* Change the names of .models found in .subckts . . . */ - if (modtranslate(lcc, scname)) - devmodtranslate(lcc, scname); + if (modtranslate(lcc, scname)) /* this translates the model name in the .model line */ + devmodtranslate(lcc, scname); /* This translates the model name on all components in the deck */ s = sss->su_args; txfree(gettok(&t)); /* Throw out the subcircuit refdes */ @@ -735,7 +753,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub nnodes = numnodes(c->li_line); while (nnodes-- > 0) { - name = gettok(&s); + name = gettok_node(&s); if (name == NULL) { fprintf(cp_err, "Error: too few nodes: %s\n", c->li_line); @@ -770,12 +788,12 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub printf("In translate, looking at e, f, g, h found poly\n"); #endif - /* move pointer ahead of paren */ + /* move pointer ahead of ( */ if( get_l_paren(&s) == 1 ) { - fprintf(cp_err, "Error: no left paren after POLY %s\n", - c->li_line); - tfree(next_name); - goto quit; + fprintf(cp_err, "Error: no left paren after POLY %s\n", + c->li_line); + tfree(next_name); + goto quit; } nametofree = gettok_noparens(&s); @@ -784,10 +802,10 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub /* move pointer ahead of ) */ if( get_r_paren(&s) == 1 ) { - fprintf(cp_err, "Error: no right paren after POLY %s\n", - c->li_line); - tfree(next_name); - goto quit; + fprintf(cp_err, "Error: no right paren after POLY %s\n", + c->li_line); + tfree(next_name); + goto quit; } /* Write POLY(dim) into buffer */ @@ -803,7 +821,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub /* Now translate the controlling source/nodes */ nnodes = dim * numdevs(c->li_line); while (nnodes-- > 0) { - nametofree = name = gettok(&s); /* name points to the returned token */ + nametofree = name = gettok_node(&s); /* name points to the returned token */ if (name == NULL) { fprintf(cp_err, "Error: too few devs: %s\n", c->li_line); @@ -863,7 +881,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub /*================= Default case ===================*/ default: /* this section handles ordinary components */ s = c->li_line; - nametofree = name = gettok(&s); + nametofree = name = gettok_node(&s); /* changed to gettok_node to handle netlists with ( , ) */ if (!name) continue; if (!*name) { @@ -892,7 +910,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub nnodes = numnodes(c->li_line); while (nnodes-- > 0) { - name = gettok(&s); + name = gettok_node(&s); if (name == NULL) { fprintf(cp_err, "Error: too few nodes: %s\n", c->li_line); @@ -920,7 +938,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub */ nnodes = numdevs(c->li_line); while (nnodes-- > 0) { - t = name = gettok(&s); + t = name = gettok_node(&s); if (name == NULL) { fprintf(cp_err, "Error: too few devs: %s\n", c->li_line); @@ -1192,9 +1210,9 @@ numnodes(char *name) i = 0; s = buf; gotit = 0; - txfree(gettok(&s)); /* Skip component name */ + txfree(gettok(&s)); /* Skip component name */ while ((i < n) && (*s) && !gotit) { - t = gettok(&s); + t = gettok_node(&s); /* get nodenames . . . */ for (wl = modnames; wl; wl = wl->wl_next) if (eq(t, wl->wl_word)) gotit = 1; @@ -1332,8 +1350,11 @@ modtranslate(struct line *deck, char *subname) /*-------------------------------------------------------------------* - * Devmodtranslate translates ?????? - * + * Devmodtranslate scans through the deck, and translates the + * name of the model in a line held in a .subckt. For example: + * before: .subckt U1 . . . . + * Q1 c b e 2N3904 + * after: Q1 c b e U1:2N3904 *-------------------------------------------------------------------*/ static void devmodtranslate(struct line *deck, char *subname) @@ -1345,9 +1366,14 @@ devmodtranslate(struct line *deck, char *subname) for (s = deck; s; s = s->li_next) { t = s->li_line; +#ifdef TRACE + /* SDB debug stuff */ + printf("In devmodtranslate, examining line %s.\n", t); +#endif + while (*t && isspace(*t)) t++; - c = isupper(*t) ? tolower(*t) : *t; + c = isupper(*t) ? tolower(*t) : *t; /* set c to first char in line. . . . */ found = FALSE; buffer = tmalloc(strlen(t) + strlen(subname) + 4); @@ -1355,17 +1381,17 @@ devmodtranslate(struct line *deck, char *subname) case 'r': case 'c': - name = gettok(&t); + name = gettok(&t); /* get refdes */ (void) sprintf(buffer,"%s ",name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get first netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get second netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - if (*t) { + if (*t) { /* if there is a model, process it. . . . */ name = gettok(&t); /* Now, is this a subcircuit model? */ for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { @@ -1404,13 +1430,13 @@ devmodtranslate(struct line *deck, char *subname) break; case 'd': - name = gettok(&t); + name = gettok(&t); /* get refdes */ (void) sprintf(buffer,"%s ",name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get first attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get second attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); name = gettok(&t); @@ -1437,6 +1463,10 @@ devmodtranslate(struct line *deck, char *subname) case 'u': case 'j': case 'z': + /* What are these devices anyway? J = JFET, W = trans line (?), + and u = IC, but what is Z?. + Also, why is 'U' here? A 'U' element can have an arbitrary + number of nodes attached. . . . -- SDB. */ name = gettok(&t); (void) sprintf(buffer,"%s ",name); name = gettok(&t); @@ -1464,22 +1494,26 @@ devmodtranslate(struct line *deck, char *subname) s->li_line = buffer; break; - case 'o': + /* Changed gettok() to gettok_node() on 12.2.2003 by SDB + to enable parsing lines like "S1 10 11 (80,51) SLATCH1" + which occurr in real Analog Devices SPICE models. + */ + case 'o': /* what is this element? -- SDB */ case 's': case 'm': - name = gettok(&t); + name = gettok(&t); /* get refdes */ (void) sprintf(buffer,"%s ",name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get first attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get second attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get third attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get fourth attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); name = gettok(&t); @@ -1503,19 +1537,19 @@ devmodtranslate(struct line *deck, char *subname) break; case 'q': - name = gettok(&t); + name = gettok(&t); /* get refdes */ (void) sprintf(buffer,"%s ",name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get first attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get second attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* get third attached netname */ (void) sprintf(buffer + strlen(buffer), "%s ", name); tfree(name); - name = gettok(&t); + name = gettok_node(&t); /* this can be either a model name or a node name. */ /* Now, is this a subcircuit model? */ for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { diff --git a/src/frontend/variable.c b/src/frontend/variable.c index 706bd504a..ea7a813e8 100644 --- a/src/frontend/variable.c +++ b/src/frontend/variable.c @@ -157,7 +157,7 @@ cp_vset(char *varname, char type, char *value) cp_maxhistlength = v->va_real; else if (eq(copyvarname, "noclobber")) cp_noclobber = TRUE; - else if (eq(varname, "echo")) /*CDHW*/ + else if (eq(varname, "echo")) /*CDHW*/ cp_echo = TRUE; /*CDHW*/ else if (eq(copyvarname, "prompt") && (type == VT_STRING)) cp_promptstring = copy(v->va_string); @@ -208,10 +208,12 @@ cp_vset(char *varname, char type, char *value) alreadythere = FALSE; if (ft_curckt) { for (u = ft_curckt->ci_vars; u; u = u->va_next) + { if (eq(copyvarname, u->va_name)) { alreadythere = TRUE; break; } + } if (!alreadythere) { v->va_next = ft_curckt->ci_vars; ft_curckt->ci_vars = v; @@ -225,7 +227,7 @@ cp_vset(char *varname, char type, char *value) /* va_next left unchanged */ tfree(v->va_name); tfree(v); -/* va: old version with memory leaks +/* va: old version with memory leaks w = u->va_next; bcopy(v, u, sizeof(*u)); u->va_next = w; @@ -291,9 +293,7 @@ cp_setparse(wordlist *wl) *s = '\0'; if (*val == '\0') { if (!wl) { - fprintf(cp_err, - "Error: %s equals what?.\n", - name); + fprintf(cp_err, "Error: %s equals what?.\n", name); tfree(name);/*DG: cp_unquote Memory leak: free name before exiting*/ return (NULL); } else { @@ -343,7 +343,7 @@ cp_setparse(wordlist *wl) } if (balance && !wl) { fprintf(cp_err, "Error: bad set form.\n"); - tfree(name); /* va: cp_unquote memory leak: free name before exiting */ + tfree(name); /* va: cp_unquote memory leak: free name before exiting */ return (NULL); } @@ -373,7 +373,7 @@ cp_setparse(wordlist *wl) vv->va_string = copy(val); } tfree(copyval);/*DG: must free ss any way to avoid cp_unquote memory leak */ - tfree(name); /* va: cp_unquote memory leak: free name for every loop */ + tfree(name); /* va: cp_unquote memory leak: free name for every loop */ } if(name) tfree(name); @@ -485,6 +485,11 @@ cp_getvar(char *name, int type, void *retval) { struct variable *v; +#ifdef TRACE + /* SDB debug statement */ + printf("in cp_getvar, trying to get value of variable %s.\n", name); +#endif + for (v = variables; v; v = v->va_next) if (eq(name, v->va_name)) break; diff --git a/src/include/ftedev.h b/src/include/ftedev.h index 1d4d9bd00..12385b225 100644 --- a/src/include/ftedev.h +++ b/src/include/ftedev.h @@ -9,6 +9,10 @@ Author: 1987 Jeffrey M. Hsu The display device structure. */ +#ifndef FTEDEV_H_INCLUDED +#define FTEDEV_H_INCLUDED + + typedef struct { char *name; int minx, miny; @@ -35,3 +39,6 @@ typedef struct { } DISPDEVICE; extern DISPDEVICE *dispdev; + + +#endif diff --git a/src/include/ngspice.h b/src/include/ngspice.h index e5f1aa11c..b83e5894a 100644 --- a/src/include/ngspice.h +++ b/src/include/ngspice.h @@ -127,6 +127,7 @@ struct timeb timebegin; extern char *gettok(char **s); extern char *gettok_noparens(char **s); +extern char *gettok_node(char **s); extern int get_l_paren(char **s); extern int get_r_paren(char **s); extern void appendc(char *s, char c); @@ -134,11 +135,11 @@ extern int scannum(char *str); extern int ciprefix(register char *p, register char *s); extern int cieq(register char *p, register char *s); extern void strtolower(char *str); -#ifdef HAVE_GNUREADLINE extern char *tildexpand(char *string); -#else -extern char *tilde_expand(char *string); -#endif + +extern char *canonicalize_pathname(char *path); +extern char *absolute_pathname(char *string, char *dot_path); + extern char *smktemp(char *id); extern char *copy(char *str); diff --git a/src/main.c b/src/main.c index 5a640034d..5c7190fec 100644 --- a/src/main.c +++ b/src/main.c @@ -5,7 +5,7 @@ Author: 1985 Wayne A. Christopher The main routine for ngspice */ - + #include #include @@ -30,7 +30,7 @@ #include #include #include -//#include "frontend/display.h" /* va */ +#include /* added by SDB to pick up Input() fcn */ /* saj xspice headers */ #ifdef XSPICE @@ -49,7 +49,10 @@ #include #include #include "fteinput.h" -#endif + +char gnu_history_file[512]; +static char *application_name; +#endif /* HAVE_GNUREADLINE */ #ifndef HAVE_GETRUSAGE #ifdef HAVE_FTIME @@ -68,8 +71,8 @@ static bool ft_servermode = FALSE; static bool ft_batchmode = FALSE; /* Frontend options */ -bool ft_intrpt = FALSE; /* Set by the (void) signal handlers. */ -bool ft_setflag = FALSE; /* Don't abort after an interrupt. */ +bool ft_intrpt = FALSE; /* Set by the (void) signal handlers. TRUE = we've been interrupted. */ +bool ft_setflag = FALSE; /* TRUE = Don't abort simulation after an interrupt. */ char *ft_rawfile = "rawspice.raw"; #ifdef HAVE_GNUREADLINE @@ -144,7 +147,7 @@ struct variable *(*if_getparam)( ); -jmp_buf jbuf; +sigjmp_buf jbuf; static int started = FALSE; @@ -171,56 +174,67 @@ extern struct comm nutcp_coms[ ]; struct comm *cp_coms = nutcp_coms; static IFfrontEnd nutmeginfo; +/* -------------------------------------------------------------------------- */ int if_run(char *t, char *w, wordlist *s, char *b) { return (0); } +/* -------------------------------------------------------------------------- */ int if_sens_run(char *t, char *w, wordlist *s, char *b) { return (0); } +/* -------------------------------------------------------------------------- */ void if_dump(char *ckt, FILE *fp) {} +/* -------------------------------------------------------------------------- */ char * if_inpdeck(struct line *deck, char **tab) { return ((char *) 0); } +/* -------------------------------------------------------------------------- */ int if_option(char *ckt, char *name, int type, char *value) { return 0; } +/* -------------------------------------------------------------------------- */ void if_cktfree(char *ckt, char *tab) {} +/* -------------------------------------------------------------------------- */ void if_setndnames(char *line) {} +/* -------------------------------------------------------------------------- */ char * if_errstring(int code) { return ("spice error"); } +/* -------------------------------------------------------------------------- */ void if_setparam(char *ckt, char *name, char *param, struct variable *val) {} +/* -------------------------------------------------------------------------- */ bool if_tranparams(struct circ *ckt, double *start, double *stop, double *step) { return (FALSE); } +/* -------------------------------------------------------------------------- */ struct variable * if_getstat(char *n, char *c) { @@ -237,7 +251,7 @@ void com_savesnap(wordlist *wl) { return; } #ifndef SIMULATOR #ifdef XSPICE -/* saj,dw to get nutmeg to compile, not nice but necessary */ +/* saj to get nutmeg to compile, not nice but necessary */ Ipc_Tiein_t g_ipc; Ipc_Status_t ipc_send_errchk(void ) { Ipc_Status_t x=0; @@ -278,7 +292,7 @@ double CONSTe; IFfrontEnd *SPfrontEnd = NULL; int DEVmaxnum = 0; - +/* -------------------------------------------------------------------------- */ int SIMinit(IFfrontEnd *frontEnd, IFsimulator **simulator) { #ifdef SIMULATOR @@ -307,6 +321,7 @@ int SIMinit(IFfrontEnd *frontEnd, IFsimulator **simulator) } +/* -------------------------------------------------------------------------- */ /* Shutdown gracefully. */ int shutdown(int exitval) @@ -322,6 +337,8 @@ shutdown(int exitval) exit (exitval); } +/* -------------------------------------------------------------------------- */ + #ifdef HAVE_GNUREADLINE /* Adapted ../lib/cp/lexical.c:prompt() for GNU Readline -- Andrew Veliath */ static char * @@ -340,15 +357,15 @@ prompt() s = cp_altprompt; while (*s) { switch (strip(*s)) { - case '!': - p += sprintf(p, "%d", where_history() + 1); - break; - case '\\': - if (*(s + 1)) - p += sprintf(p, "%c", strip(*++s)); - default: - *p = strip(*s); ++p; - break; + case '!': + p += sprintf(p, "%d", where_history() + 1); + break; + case '\\': + if (*(s + 1)) + p += sprintf(p, "%c", strip(*++s)); + default: + *p = strip(*s); ++p; + break; } s++; } @@ -356,55 +373,51 @@ prompt() return pbuf; } +/* -------------------------------------------------------------------------- */ /* Process device events in Readline's hook since there is no where else to do it now - AV */ -int rl_event_func() +int rl_event_func() +/* called by GNU readline periodically to know what to do about keypresses */ { static REQUEST reqst = { checkup_option, 0 }; Input(&reqst, NULL); return 0; } +/* -------------------------------------------------------------------------- */ /* Added GNU Readline Support -- Andrew Veliath */ void app_rl_readlines() { char *line, *expanded_line; - strcpy(gnu_history_file, getenv("HOME")); - strcat(gnu_history_file, "/."); - strcat(gnu_history_file, application_name); - strcat(gnu_history_file, "_history"); - - using_history(); - read_history(gnu_history_file); - - rl_readline_name = application_name; - rl_instream = cp_in; - rl_outstream = cp_out; - rl_event_hook = rl_event_func; - + /* note that we want some mechanism to detect ctrl-D and expand it to exit */ while (1) { - history_set_pos(history_length); - line = readline(prompt()); - if (line && *line) { - int s = history_expand(line, &expanded_line); - - if (s == 2) { - fprintf(stderr, "-> %s\n", expanded_line); - } else if (s == -1) { - fprintf(stderr, "readline: %s\n", expanded_line); - } else { - cp_evloop(expanded_line); - add_history(expanded_line); - } - free(expanded_line); - } - if (line) free(line); + history_set_pos(history_length); + + sigsetjmp(jbuf, 1); /* Set location to jump to after handling SIGINT (ctrl-C) */ + + line = readline(prompt()); + if (line && *line) { + int s = history_expand(line, &expanded_line); + + if (s == 2) { + fprintf(stderr, "-> %s\n", expanded_line); + } else if (s == -1) { + fprintf(stderr, "readline: %s\n", expanded_line); + } else { + cp_evloop(expanded_line); + add_history(expanded_line); + } + free(expanded_line); + } + if (line) free(line); } /* History gets written in ../fte/misccoms.c com_quit */ } #endif /* HAVE_GNUREADLINE */ + +/* -------------------------------------------------------------------------- */ void show_help(void) { @@ -426,6 +439,7 @@ show_help(void) "Report bugs to %s.\n", cp_program, Bug_Addr); } +/* -------------------------------------------------------------------------- */ void show_version(void) { @@ -438,6 +452,7 @@ show_version(void) " The NGSpice Project\n", cp_program, PACKAGE, VERSION); } +/* -------------------------------------------------------------------------- */ void append_to_stream(FILE *dest, FILE *source) { @@ -500,6 +515,8 @@ main(int argc, char **argv) FILE *fp; FILE *circuit_file; + + #ifdef TRACE /* this is used to detect memory leaks during debugging */ /* added by SDB during debug . . . . */ @@ -524,8 +541,8 @@ main(int argc, char **argv) application_name = argv[0]; else ++application_name; -#endif - +#endif /* HAVE_GNUREADLINE */ + #ifdef PARALLEL_ARCH PBEGIN_(argc, argv); ARCHme = NODEID_(); @@ -553,8 +570,7 @@ main(int argc, char **argv) #ifdef MALLOCTRACE mallocTraceInit("malloc.out"); #endif - -#if defined (HAVE_ISATTY) && !defined(HAS_WINDOWS) +#if defined(HAVE_ISATTY) && !defined(HAS_WINDOWS) istty = (bool) isatty(fileno(stdin)); #endif @@ -571,7 +587,7 @@ main(int argc, char **argv) srandom(getpid()); - + /* --- Process command line options --- */ while (1) { int option_index = 0; static struct option long_options[] = { @@ -681,7 +697,7 @@ main(int argc, char **argv) default: printf ("?? getopt returned character code 0%o ??\n", c); } - } + } /* --- End of command line option processing --- */ #ifdef SIMULATOR @@ -712,7 +728,7 @@ main(int argc, char **argv) ft_cpinit(); /* To catch interrupts during .spiceinit... */ - if (setjmp(jbuf) == 1) { + if (sigsetjmp(jbuf, 1) == 1) { fprintf(cp_err, "Warning: error executing .spiceinit.\n"); if (!ft_batchmode) goto bot; @@ -720,13 +736,13 @@ main(int argc, char **argv) /* Set up signal handling */ if (!ft_batchmode) { + /* Set up interrupt handler */ + (void) signal(SIGINT, ft_sigintr); -#ifndef HAVE_GNUREADLINE - signal(SIGINT, ft_sigintr); -#endif + /* floating point exception */ + (void) signal(SIGFPE, sigfloat); - signal(SIGFPE, sigfloat); -#if defined(SIGTSTP) // && !defined(__MINGW32__) +#ifdef SIGTSTP signal(SIGTSTP, sigstop); #endif } @@ -761,9 +777,9 @@ main(int argc, char **argv) #define INITSTR "/.spiceinit" #ifdef HAVE_ASPRINTF asprintf(&s, "%s%s", pw->pw_dir,INITSTR); -#else /* ~ HAVE_ASPRINTF */ /* va: we use tmalloc */ - s=(char *) tmalloc(1 + strlen(pw->pw_dir)+strlen(INITSTR)); - sprintf(s,"%s%s",pw->pw_dir,INITSTR); +#else /* ~ HAVE_ASPRINTF */ + s=(char *) tmalloc(1 + strlen(pw->pw_dir)+strlen(INITSTR)); + sprintf(s,"%s%s",pw->pw_dir,INITSTR); #endif /* HAVE_ASPRINTF */ if (access(s, 0) == 0) @@ -800,7 +816,7 @@ bot: * build a circuit for this file. If this is in server mode, don't * process any of these args. */ - if (setjmp(jbuf) == 1) + if (sigsetjmp(jbuf, 1) == 1) goto evl; @@ -846,7 +862,7 @@ bot: } if (ft_batchmode && err) shutdown(EXIT_BAD); - } + } /* --- if (!ft_servermode && !ft_nutmeg) --- */ if (!gotone && ft_batchmode && !ft_nutmeg) inp_spsource(circuit_file, FALSE, (char *) NULL); @@ -857,7 +873,8 @@ evl: * so exit. */ bool st = FALSE; - (void) setjmp(jbuf); + (void) sigsetjmp(jbuf, 1); + if (st == TRUE) { shutdown(EXIT_BAD); @@ -878,7 +895,7 @@ evl: * save too much. */ cp_interactive = FALSE; if (rflag) { - /* saj done already in inp_spsource ft_dotsaves();*/ + /* saj done already in inp_spsource ft_dotsaves();*/ error2 = ft_dorun(ft_rawfile); if (ft_cktcoms(TRUE) || error2) shutdown(EXIT_BAD); @@ -892,15 +909,34 @@ evl: "no simulations run\n"); shutdown(EXIT_BAD); } - } else { - (void) setjmp(jbuf); + } /* --- if (ft_batchmode) --- */ + else { cp_interactive = TRUE; + #ifdef HAVE_GNUREADLINE - app_rl_readlines(); -#else + /* --- set up readline params --- */ + strcpy(gnu_history_file, getenv("HOME")); + strcat(gnu_history_file, "/."); + strcat(gnu_history_file, application_name); + strcat(gnu_history_file, "_history"); + + using_history(); + read_history(gnu_history_file); + + rl_readline_name = application_name; + rl_instream = cp_in; + rl_outstream = cp_out; + rl_event_hook = rl_event_func; + rl_catch_signals = 0; /* disable readline signal handling */ + rl_catch_sigwinch = 1; /* allow readline to respond to resized windows */ + + /* Here's where we enter the command processing loop */ + app_rl_readlines(); +#else while (cp_evloop((char *) NULL) == 1) ; -#endif /* ifelse HAVE_GNUREADLINE */ - } +#endif /* ifelse HAVE_GNUREADLINE */ + + } /* --- else (if (ft_batchmode)) --- */ #else /* ~ SIMULATOR */ @@ -915,16 +951,16 @@ evl: evl: /* Nutmeg "main" */ - (void) setjmp(jbuf); + (void) sigsetjmp(jbuf, 1); cp_interactive = TRUE; -#ifdef HAVE_GNUREADLINE - app_rl_readlines(); -#else while (cp_evloop((char *) NULL) == 1) ; -#endif /* ifelse HAVE_GNUREADLINE */ #endif /* ~ SIMULATOR */ shutdown(EXIT_NORMAL); return EXIT_NORMAL; } + + + + diff --git a/src/misc/Makefile.am b/src/misc/Makefile.am index 2477d316d..6d355cd45 100644 --- a/src/misc/Makefile.am +++ b/src/misc/Makefile.am @@ -27,7 +27,9 @@ libmisc_a_SOURCES = \ tilde.h \ misc_time.c \ misc_time.h \ - wlist.c + wlist.c \ + util.c \ + util.h ## Note that the getopt files get compiled unconditionnaly but some ## magic #define away the body of their own code if the compilation environment diff --git a/src/misc/ivars.c b/src/misc/ivars.c index e6fc50d6a..caa20de82 100644 --- a/src/misc/ivars.c +++ b/src/misc/ivars.c @@ -40,7 +40,7 @@ mkvar(char **p, char *path_prefix, char *var_dir, char *env_var) asprintf(p, "%s", buffer); else asprintf(p, "%s%s%s", path_prefix, DIR_PATHSEP, var_dir); -#else /* ~ HAVE_ASPRINTF */ /* va: we use tmalloc */ +#else /* ~ HAVE_ASPRINTF */ if (buffer){ *p = (char *) tmalloc(strlen(buffer)+1); sprintf(*p,"%s",buffer); @@ -48,7 +48,7 @@ mkvar(char **p, char *path_prefix, char *var_dir, char *env_var) } else{ *p = (char *) tmalloc(strlen(path_prefix) + - strlen(DIR_PATHSEP) + strlen(var_dir) + 1); + strlen(DIR_PATHSEP) + strlen(var_dir) + 1); sprintf(*p, "%s%s%s", path_prefix, DIR_PATHSEP, var_dir); /* asprintf(p, "%s%s%s", path_prefix, DIR_PATHSEP, var_dir); */ } @@ -64,6 +64,7 @@ ivars(void) env_overr(&Spice_Exec_Dir, "SPICE_EXEC_DIR"); env_overr(&Spice_Lib_Dir, "SPICE_LIB_DIR"); + mkvar(&News_File, Spice_Lib_Dir, "news", "SPICE_NEWS"); mkvar(&Default_MFB_Cap, Spice_Lib_Dir, "mfbcap", "SPICE_MFBCAP"); mkvar(&Help_Path, Spice_Lib_Dir, "helpdir", "SPICE_HELP_DIR"); diff --git a/src/misc/string.c b/src/misc/string.c index ebbbabd3e..53aff57f1 100644 --- a/src/misc/string.c +++ b/src/misc/string.c @@ -192,8 +192,13 @@ register char *p, *s; #endif /* CIDER */ - - +/*-------------------------------------------------------------------------* + * gettok skips over whitespace and returns the next token found. This is + * the original version. It does not "do the right thing" when you have + * parens or commas anywhere in the nodelist. Note that I left this unmodified + * since I didn't want to break any fcns which called it from elsewhere than + * subckt.c. -- SDB 12.3.2003. + *-------------------------------------------------------------------------*/ char * gettok(char **s) { @@ -224,9 +229,10 @@ gettok(char **s) /*-------------------------------------------------------------------------* * gettok_noparens was added by SDB on 4.21.2003. - * It acts like gettok, except that it stops parsing when it hits a paren - * (i.e. it treats parens like whitespace). It is used in translate (subckt.c) - * while looking for the POLY token. + * It acts like gettok, except that it treats parens and commas like + * whitespace while looking for the POLY token. That is, it stops + * parsing and returns when it finds one of those chars. It is called from + * 'translate' (subckt.c). *-------------------------------------------------------------------------*/ char * gettok_noparens(char **s) @@ -235,24 +241,78 @@ gettok_noparens(char **s) int i = 0; char c; - while (isspace(**s)) - (*s)++; + while ( isspace(**s) ) + (*s)++; /* iterate over whitespace */ + if (!**s) - return (NULL); - while ((c = **s) && !isspace(c) && - ( **s != '(' ) && ( **s != ')' ) ) { + return (NULL); /* return NULL if we come to end of line */ + + while ((c = **s) && + !isspace(c) && + ( **s != '(' ) && + ( **s != ')' ) && + ( **s != ',') + ) { buf[i++] = *(*s)++; } buf[i] = '\0'; - while (isspace(**s)) - (*s)++; + + /* Now iterate up to next non-whitespace char */ + while ( isspace(**s) ) + (*s)++; + + return (copy(buf)); +} + +/*-------------------------------------------------------------------------* + * gettok_node was added by SDB on 12.3.2003 + * It acts like gettok, except that it treats parens and commas like + * whitespace (i.e. it ignores them). Use it when parsing through netnames + * (node names) since they may be grouped using ( , ). + *-------------------------------------------------------------------------*/ +char * +gettok_node(char **s) +{ + char buf[BSIZE_SP]; + int i = 0; + char c; + + while (isspace(**s) || + ( **s == '(' ) || + ( **s == ')' ) || + ( **s == ',') + ) + (*s)++; /* iterate over whitespace and ( , ) */ + + if (!**s) + return (NULL); /* return NULL if we come to end of line */ + + while ((c = **s) && + !isspace(c) && + ( **s != '(' ) && + ( **s != ')' ) && + ( **s != ',') + ) { /* collect chars until whitespace or ( , ) */ + buf[i++] = *(*s)++; + } + buf[i] = '\0'; + + /* Now iterate up to next non-whitespace char */ + while (isspace(**s) || + ( **s == '(' ) || + ( **s == ')' ) || + ( **s == ',') + ) + (*s)++; /* iterate over whitespace and ( , ) */ + return (copy(buf)); } /*-------------------------------------------------------------------------* * get_l_paren iterates the pointer forward in a string until it hits * the position after the next left paren "(". It returns 0 if it found a left - * paren, and 1 if no left paren is found. + * paren, and 1 if no left paren is found. It is called from 'translate' + * (subckt.c). *-------------------------------------------------------------------------*/ int get_l_paren(char **s) @@ -274,7 +334,8 @@ get_l_paren(char **s) /*-------------------------------------------------------------------------* * get_r_paren iterates the pointer forward in a string until it hits * the position after the next right paren ")". It returns 0 if it found a right - * paren, and 1 if no right paren is found. + * paren, and 1 if no right paren is found. It is called from 'translate' + * (subckt.c). *-------------------------------------------------------------------------*/ int get_r_paren(char **s) diff --git a/src/misc/tilde.c b/src/misc/tilde.c index 1e72b4e27..d657b41e8 100644 --- a/src/misc/tilde.c +++ b/src/misc/tilde.c @@ -15,6 +15,7 @@ Modified: 2002 R. Oktas, #include #endif + /* XXX To prevent a name collision with `readline's `tilde_expand', the original name: `tilde_expand' has changed to `tildexpand'. This situation naturally brings to mind that `tilde_expand' could be used @@ -25,70 +26,13 @@ Modified: 2002 R. Oktas, not behave this way, IMHO. Anyway... Don't care for the moment, may be in the future. -- ro */ -/* PN: Since readline patch is not compiled in by default the behaviour - described above is not acceptable. I will make two different version - of tilde expansion routine, the one choosen depends on HAVE_GNUREADLINE - Note: since a readline replacement called libedit is under - development at libedit.sourceforge.net, I will switch to it - ASAP, since libedit is covered by BSD licnse. - - */ - -#ifndef HAVE_GNUREADLINE -char * -tilde_expand(char *string) -{ - -#ifdef HAVE_PWD_H - struct passwd *pw; - /*extern struct passwd *getpwuid( );*/ - char buf[BSIZE_SP]; - char *k, c; - - if (!string) - return NULL; - - while (*string && isspace(*string)) - string++; - - if (*string != '~') - return copy(string); - - string += 1; - - if (!*string || *string == '/') { - pw = getpwuid(getuid()); - *buf = 0; - } else { - k = buf; - while ((c = *string) && c != '/') - *k++ = c, string++; - *k = 0; - pw = getpwnam(buf); - } - - if (pw) { - strcpy(buf, pw->pw_dir); - if (*string) - strcat(buf, string); - } else - return NULL; - - return copy(buf); - -#else - return copy(string); -#endif -} - -#else /* HAVE_GNUREADLINE */ char * tildexpand(char *string) { - char buf[BSIZE_SP]; char *result, *k, c; + if (!string) return NULL; @@ -101,42 +45,44 @@ tildexpand(char *string) string += 1; if (!*string || *string == '/') { - /* First try the environment setting. May also make life easier - for non-unix platforms, eg. MS-DOS. -- ro */ - result = getenv("HOME"); + /* First try the environment setting. May also make life easier + for non-unix platforms, eg. MS-DOS. -- ro */ + result = getenv("HOME"); #ifdef HAVE_PWD_H - /* Can't find a result from the environment, let's try - the other stuff. -- ro */ - if (!result) { - struct passwd *pw; - pw = getpwuid(getuid()); - if (pw) - result = pw->pw_dir; - *buf = 0; - } + /* Can't find a result from the environment, let's try + the other stuff. -- ro */ + if (!result) { + struct passwd *pw; + pw = getpwuid(getuid()); + if (pw) + result = pw->pw_dir; + *buf = 0; + } + } else { - struct passwd *pw; + struct passwd *pw; k = buf; while ((c = *string) && c != '/') *k++ = c, string++; *k = 0; pw = getpwnam(buf); - if (pw) - result = pw->pw_dir; -#endif + if (pw) + result = pw->pw_dir; +#endif } if (result) { #ifdef HAVE_PWD_H - strcpy(buf, result); + strcpy(buf, result); if (*string) strcat(buf, string); - return copy(buf); + return copy(buf); + } else return NULL; -#else - /* Emulate the old behavior to prevent side effects. -- ro */ - return copy(string); +#else + /* Emulate the old behavior to prevent side effects. -- ro */ + return copy(string); #endif } -#endif /* HAVE_GNUREADLINE */ + diff --git a/src/misc/tilde.h b/src/misc/tilde.h index 54b605aee..83cd8f72c 100644 --- a/src/misc/tilde.h +++ b/src/misc/tilde.h @@ -6,10 +6,7 @@ #ifndef TILDE_H_INCLUDED #define TILDE_H_INCLUDED -#ifdef HAVE_GNUREADLINE char * tildexpand(char *string); -#else -char * tilde_expand(char *string); -#endif + #endif diff --git a/src/misc/util.c b/src/misc/util.c new file mode 100644 index 000000000..369641dec --- /dev/null +++ b/src/misc/util.c @@ -0,0 +1,151 @@ +/************* + * Various utility functions. + * 2002 R. Oktas, + ************/ + +#ifdef HAVE_STRING_H +#include +#endif + +#include "ngspice.h" +#include "util.h" + + +/* **************************************************************** */ +/* */ +/* Stuff for Filename Handling */ +/* */ +/* **************************************************************** */ + +/* Canonicalize PATH, and return a new path. The new path differs from PATH + in that: + Multple `/'s are collapsed to a single `/'. + Leading `./'s and trailing `/.'s are removed. + Trailing `/'s are removed. + Non-leading `../'s and trailing `..'s are handled by removing + portions of the path. + + Stolen from Bash source (slightly modified). + Credit goes to Chet Ramey, et al. -- ro */ + +char * +canonicalize_pathname(char *path) +{ + int i, start; + char stub_char; + char *result; + + /* The result cannot be larger than the input PATH. */ + result = copy(path); + + stub_char = (*path == '/') ? '/' : '.'; + + /* Walk along RESULT looking for things to compact. */ + i = 0; + while (1) { + if (!result[i]) + break; + + while (result[i] && result[i] != '/') + i++; + + start = i++; + + /* If we didn't find any slashes, then there is nothing left to do. */ + if (!result[start]) + break; + + /* Handle multiple `/'s in a row. */ + while (result[i] == '/') + i++; + +#if !defined (apollo) + if ((start + 1) != i) +#else + if ((start + 1) != i && (start != 0 || i != 2)) +#endif /* apollo */ + { + strcpy (result + start + 1, result + i); + i = start + 1; + } + +#if 0 + /* Handle backslash-quoted `/'. */ + if (start > 0 && result[start - 1] == '\\') + continue; +#endif + + /* Check for trailing `/'. */ + if (start && !result[i]) { + zero_last: + result[--i] = '\0'; + break; + } + + /* Check for `../', `./' or trailing `.' by itself. */ + if (result[i] == '.') { + /* Handle trailing `.' by itself. */ + if (!result[i + 1]) + goto zero_last; + + /* Handle `./'. */ + if (result[i + 1] == '/') { + strcpy(result + i, result + i + 1); + i = (start < 0) ? 0 : start; + continue; + } + + /* Handle `../' or trailing `..' by itself. */ + if (result[i + 1] == '.' && + (result[i + 2] == '/' || !result[i + 2])) { + while (--start > -1 && result[start] != '/'); + strcpy(result + start + 1, result + i + 2); + i = (start < 0) ? 0 : start; + continue; + } + } + } + + if (!*result) { + *result = stub_char; + result[1] = '\0'; + } + return (result); +} + + +/* Turn STRING (a pathname) into an absolute pathname, assuming that + DOT_PATH contains the symbolic location of `.'. This always + returns a new string, even if STRING was an absolute pathname to + begin with. + + Stolen from Bash source (slightly modified). + Credit goes to Chet Ramey, et al. -- ro */ + +char * absolute_pathname(char *string, char *dot_path) +{ + char *result; + int result_len; + + if (!dot_path || *string == '/') + result = copy(string); + else { + if (dot_path && dot_path[0]) { + result = tmalloc(2 + strlen(dot_path) + strlen(string)); + strcpy(result, dot_path); + result_len = strlen(result); + if (result[result_len - 1] != '/') { + result[result_len++] = '/'; + result[result_len] = '\0'; + } + } else { + result = tmalloc(3 + strlen (string)); + result[0] = '.'; result[1] = '/'; result[2] = '\0'; + result_len = 2; + } + + strcpy(result + result_len, string); + } + + return (result); +} diff --git a/src/misc/util.h b/src/misc/util.h new file mode 100644 index 000000000..af071e72f --- /dev/null +++ b/src/misc/util.h @@ -0,0 +1,12 @@ +/************* + * Header file for util.c + * 2002 R. Oktas, + ************/ + +#ifndef UTIL_H_INCLUDED +#define UTIL_H_INCLUDED + +char *canonicalize_pathname(char *path); +char *absolute_pathname(char *string, char *dot_path); + +#endif diff --git a/src/nghelp.c b/src/nghelp.c index 1fdc3b195..9bac2307d 100644 --- a/src/nghelp.c +++ b/src/nghelp.c @@ -28,6 +28,7 @@ char *Bug_Addr = ""; char *Spice_Host = ""; char *Spiced_Log = ""; + /* dummy declaration so CP.a doesn't pull in lexical.o and other objects */ bool cp_interactive = FALSE; @@ -110,5 +111,5 @@ cp_getvar(char *n, int t, void *r) char * cp_tildexpand(char *s) { - return tilde_expand(s); + return tildexpand(s); } diff --git a/src/ngmultidec.c b/src/ngmultidec.c index b8e8e0744..8ab3aa62e 100644 --- a/src/ngmultidec.c +++ b/src/ngmultidec.c @@ -14,6 +14,7 @@ Author: 1990 Jaijeet Roychowdury #undef DEBUG_LEVEL1 +/* `-u' option showing the usage help is changed to `-h'. -- ro */ extern void usage(); extern void comments(); @@ -102,7 +103,7 @@ int use_opt = 1; gotnum=1; break; - case 'u': + case 'h': usage(pname); exit(1); break; @@ -350,7 +351,7 @@ fprintf(stderr,"Usage: %s -l -c\n",argv[0]); fprintf(stderr," -r -g \n"); fprintf(stderr," -k \n"); fprintf(stderr," -x -o \n"); -fprintf(stderr," -n -L -u\n"); +fprintf(stderr," -n -L -h\n"); fprintf(stderr,"Example: %s -n4 -l9e-9 -c20e-12 -r5.3 -x5e-12 -k0.7 -otest -L5.4\n\n",argv[0]); fprintf(stderr,"See \"Efficient Transient Simulation of Lossy Interconnect\",\n");