Jspice3
inp.c
Go to the documentation of this file.
1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5  1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Stuff for dealing with spice input decks and command scripts, and
10  * the listing routines.
11  */
12 
13 #include "spice.h"
14 #ifdef HAVE_STAT
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #endif
18 #include "ftedefs.h"
19 #include "inpdefs.h"
20 #include "fteinp.h"
21 #include "spfteext.h"
22 
23 #ifdef __STDC__
24 static char *upper(char*);
25 static void spsource(FILE*,bool,bool,char*);
26 static void decksource(struct line*,bool,bool,char*);
27 static bool is_ckt(struct line*);
28 static wordlist *get_speccmds(struct line*);
29 static wordlist *get_controls(struct line*,bool);
30 static void varsub(char**);
31 static wordlist *wl_separate(char*);
32 static char *flatten(wordlist*);
33 #else
34 static char *upper();
35 static void spsource();
36 static void decksource();
37 static bool is_ckt();
38 static wordlist *get_speccmds();
39 static wordlist *get_controls();
40 static void varsub();
41 static wordlist *wl_separate();
42 static char *flatten();
43 #endif
44 
45 
46 /* Do a listing. Use is listing [expanded] [logical] [physical] [deck] */
47 
48 void
50 
51 wordlist *wl;
52 {
53  int type = LS_LOGICAL;
54  bool expand = false;
55  char *s;
56 
57  if (ft_curckt) {
58  while (wl) {
59  s = wl->wl_word;
60  switch (*s) {
61  case 'l':
62  case 'L':
63  type = LS_LOGICAL;
64  break;
65  case 'p':
66  case 'P':
67  type = LS_PHYSICAL;
68  break;
69  case 'd':
70  case 'D':
71  type = LS_DECK;
72  break;
73  case 'e':
74  case 'E':
75  expand = true;
76  break;
77  default:
78  fprintf(cp_err,
79  "Error: bad listing type %s\n", s);
80  }
81  wl = wl->wl_next;
82  }
83  inp_list(cp_out, expand ? ft_curckt->ci_deck :
85  type);
86  }
87  else
88  fprintf(cp_err, "Error: no circuit loaded.\n");
89  return;
90 }
91 
92 
93 static char *
94 upper(string)
95 
96 register char *string;
97 {
98 
99  static char buf[BSIZE_SP];
100  register char *s;
101 
102  if (string) {
103  strncpy(buf, string, BSIZE_SP - 1);
104  buf[BSIZE_SP - 1] = 0;
105  inp_casefix(buf);
106  }
107  else {
108  strcpy(buf, "<null>");
109  }
110 
111  return buf;
112 
113 }
114 
115 
116 /* Provide an input listing on the specified file of the given
117  * card deck. The listing should be of either LS_PHYSICAL or LS_LOGICAL
118  * or LS_DECK lines as specified by the type parameter.
119  */
120 
121 void
122 inp_list(file, deck, extras, type)
123 
124 FILE *file;
125 struct line *deck, *extras;
126 int type;
127 {
128  struct line *here;
129  struct line *there;
130  struct line *tmp, *next;
131  bool renumber;
132  bool useout = (file == cp_out);
133  int i = 1;
134  extern char *kw_renumber;
135 
136  if (useout)
137  out_init();
138 
139  if (type != LS_DECK)
140  if (useout) {
141  out_printf("\t%s\n", ft_curckt->ci_name);
142  if (ft_curckt->ci_contblk)
143  out_printf("\tBound codeblock: %s\n\n",ft_curckt->ci_contblk);
144  else
145  out_send("\n");
146  }
147  else {
148  fprintf(cp_out, "\t%s\n", ft_curckt->ci_name);
149  if (ft_curckt->ci_contblk)
150  fprintf(cp_out,
151  "\tBound codeblock: %s\n\n",ft_curckt->ci_contblk);
152  else
153  fputc('\n',cp_out);
154  }
155 
156 
157  (void) cp_getvar(kw_renumber, VT_BOOL, (char *) &renumber);
158  if (type == LS_LOGICAL) {
159 top1:
160  for (here = deck; here; here = here->li_next) {
161  if (renumber)
162  here->li_linenum = i;
163  i++;
164  if (ciprefix(".end", here->li_line) &&
165  !isalpha(here->li_line[4]))
166  continue;
167  if (*here->li_line != '*') {
168  if (useout) {
169  out_printf("%6d : %s\n",
170  here->li_linenum,
171  upper(here->li_line));
172  }
173  else
174  fprintf(file, "%6d : %s\n",
175  here->li_linenum,
176  upper(here->li_line));
177  if (here->li_error) {
178  if (useout) {
179  out_printf("%s\n",
180  here->li_error);
181  }
182  else
183  fprintf(file, "%s\n",
184  here->li_error, file);
185  }
186  }
187  }
188  if (extras) {
189  deck = extras;
190  extras = NULL;
191  goto top1;
192  }
193  if (useout) {
194  out_printf("%6d : .end\n", i);
195  }
196  else
197  fprintf(file, "%6d : .end\n", i);
198  }
199  else if ((type == LS_PHYSICAL) || (type == LS_DECK)) {
200 top2:
201  for (here = deck; here; here = here->li_next) {
202  if ((here->li_actual == NULL) || (here == deck)) {
203  if (renumber)
204  here->li_linenum = i;
205  i++;
206  if (ciprefix(".end", here->li_line) &&
207  !isalpha(here->li_line[4]))
208  continue;
209  if (type == LS_PHYSICAL) {
210  if (useout) {
211  out_printf("%6d : %s\n",
212  here->li_linenum,
213  upper(here->li_line));
214  }
215  else
216  fprintf(file, "%6d : %s\n",
217  here->li_linenum,
218  upper(here->li_line));
219  }
220  else {
221  if (useout)
222  out_printf("%s\n",
223  upper(here->li_line));
224  else
225  fprintf(file, "%s\n",
226  upper(here->li_line));
227  }
228  if (here->li_error && (type == LS_PHYSICAL)) {
229  if (useout)
230  out_printf("%s\n",
231  here->li_error);
232  else
233  fprintf(file, "%s\n",
234  here->li_error);
235  }
236  }
237  else {
238  for (there = here->li_actual; there;
239  there = there->li_next) {
240  there->li_linenum = i++;
241  if (ciprefix(".end", here->li_line) &&
242  isalpha(here->li_line[4]))
243  continue;
244  if (type == LS_PHYSICAL) {
245  if (useout) {
246  out_printf("%6d : %s\n",
247  there->li_linenum,
248  upper(there->li_line));
249  }
250  else
251  fprintf(file, "%6d : %s\n",
252  there->li_linenum,
253  upper(there->li_line));
254  }
255  else {
256  if (useout)
257  out_printf("%s\n",
258  upper(there->li_line));
259  else
260  fprintf(file, "%s\n",
261  upper(there->li_line));
262  }
263  if (there->li_error &&
264  (type == LS_PHYSICAL)) {
265  if (useout)
266  out_printf("%s\n",
267  there->li_error);
268  else
269  fprintf(file, "%s\n",
270  there->li_error);
271  }
272  }
273  here->li_linenum = i;
274  }
275  }
276  if (extras) {
277  deck = extras;
278  extras = NULL;
279  goto top2;
280  }
281  if (type == LS_PHYSICAL) {
282  if (useout) {
283  out_printf("%6d : .end\n", i);
284  }
285  else
286  fprintf(file, "%6d : .end\n", i);
287  }
288  else {
289  if (useout)
290  out_printf(".end\n");
291  else
292  fprintf(file, ".end\n");
293  }
294  }
295  else
296  fprintf(cp_err, "inp_list: Internal Error: bad type %d\n",type);
297  return;
298 }
299 
300 
301 /* The routine to source a spice input deck. We read the deck in, take out
302  * the front-end commands, and create a CKT structure. Also we filter out
303  * the following cards: .save, .width, .four, .print, and .plot, to perform
304  * after the run is over.
305  */
306 
307 void
308 inp_spsource(fp, comfile, filename)
309 
310 FILE *fp;
311 bool comfile;
312 char *filename;
313 {
314  spsource(fp, comfile, comfile, filename);
315 }
316 
317 
318 static void
319 spsource(fp, nospice, nocmds, filename)
320 
321 FILE *fp;
322 bool nospice, nocmds;
323 char *filename;
324 {
325  struct line *deck;
326  wordlist wl;
327  char *buf;
328 
329  if ((buf = readline(fp)) == NULL)
330  return;
331  if (prefix("(Symbo",buf)) {
332  /* file contains symbolic layout information */
333  txfree(buf);
334  while ((buf = readline(fp)) != NULL) {
335  if (eq(buf,"E\n")) {
336  txfree(buf);
337  break;
338  }
339  txfree(buf);
340  }
341  if ((buf = readline(fp)) == NULL)
342  return;
343  }
344  if (prefix(".check",buf)) {
345  /* operating range analysis file */
346  wl.wl_word = filename;
347  wl.wl_next = wl.wl_prev = NULL;
348  txfree(buf);
349  ft_check(&wl,fp);
350  return;
351  }
352 #ifdef HAVE_STIM
353  if (prefix(".stim",buf)) {
354  /* stimulus description file */
355  txfree(buf);
356  MB_run(fp,1,filename);
357  return;
358  }
359 #endif
360 
361  inp_readall(fp,&deck,buf);
362  if (deck)
363  decksource(deck, nospice, nocmds, filename);
364 }
365 
366 void
367 inp_decksource(deck, comfile, filename)
368 
369 struct line *deck;
370 bool comfile;
371 char *filename;
372 {
373  decksource(deck,comfile,comfile,filename);
374 }
375 
376 
377 static void
378 decksource(deck, nospice, nocmds, filename)
379 
380 /* Source a deck. If nospice is true, execute the commands in the deck
381  * without saving the spice text, if any. If nocmds is true, save the
382  * spice text but discard the commands. If both flags are true, then
383  * execute all commands up until a .endc line, the deck is assumed to
384  * come from an init file. If neither flag is true, source the spice
385  * text and execute the commands.
386  */
387 struct line *deck;
388 bool nospice, nocmds;
389 char *filename;
390 {
391  wordlist *wl, *controls;
392  FILE *lastin, *lastout, *lasterr;
393 
394  if (!deck)
395  return;
396 
397  controls = get_controls(deck,nospice && nocmds);
398  if (!nospice && is_ckt(deck)) {
399  out_init();
400  if (!ft_servermode && deck->li_line && *deck->li_line)
401  out_printf("\nCircuit: %s\n\n", deck->li_line);
402  if (inp_spdeck(deck,filename)) {
403  wl_free(controls);
404  return;
405  }
406  }
407  else
408  inp_deckfree(deck);
409 
410  /* Now do the commands */
411  if (controls) {
412  if (!nocmds || nospice) {
413 
414  lastin = cp_curin;
415  lastout = cp_curout;
416  lasterr = cp_curerr;
417  cp_curin = cp_in;
418  cp_curout = cp_out;
419  cp_curerr = cp_err;
420  cp_pushcontrol();
421 
422  for (wl = controls; wl; wl = wl->wl_next)
423  (void) cp_evloop(wl->wl_word);
424 
425  cp_popcontrol();
426  cp_curin = lastin;
427  cp_curout = lastout;
428  cp_curerr = lasterr;
429  }
430  wl_free(controls);
431  }
432  return;
433 }
434 
435 
436 static bool
437 is_ckt(deck)
438 
439 /* return true if there is a circuit */
440 struct line *deck;
441 {
442  struct line *l;
443  char *s;
444 
445  for (l = deck->li_next; l; l = l->li_next) {
446  s = l->li_line;
447  if (!s) {
448  continue;
449  }
450  while (isspace(*s))
451  s++;
452  if (!*s || *s == '*' || *s == '#') {
453  continue;
454  }
455  /* found something real */
456  return (true);
457  }
458  return (false);
459 }
460 
461 
462 bool
463 inp_spdeck(deck,filename)
464 
465 struct line *deck;
466 char *filename;
467 {
468  struct line *dd, *realdeck, *options;
469  wordlist *end;
470  char *tt;
471  bool nosubckts = false;
472  extern char *kw_nosubckt;
473 
474  realdeck = inp_deckcopy(deck);
475  tt = copy(deck->li_line);
476 
477  /* substitute for shell variables in spice text */
478  for (dd = deck->li_next; dd; dd = dd->li_next) {
479  if (*dd->li_line == '*') continue;
480  if (strchr(dd->li_line,'$'))
481  varsub(&dd->li_line);
482  }
483  end = get_speccmds(deck);
484  options = inp_getopts(deck);
485 
486  if (deck->li_next) {
487 
488  /* Now expand subcircuit macros. Note that we have to
489  * fix the case before we do this but after we
490  * deal with the commands.
491  */
492  if (!cp_getvar(kw_nosubckt, VT_BOOL, (char *)&nosubckts)) {
493  dd = inp_subcktexpand(deck->li_next);
494  if (dd == (struct line *)NULL) {
495  inp_deckfree(deck);
496  inp_deckfree(realdeck);
497  inp_deckfree(options);
498  wl_free(end);
499  tfree(tt);
500  fprintf(cp_err,
501  "Error during subcircuit expansion, circuit not loaded.\n");
502  return (true);;
503  }
504  deck->li_next = dd;
505  }
506  deck->li_actual = realdeck;
507  inp_dodeck(deck, tt, end, false, options, copy(filename));
508  }
509  else {
510  fprintf(cp_err, "Error: no lines in input\n");
511  tfree(tt);
512  wl_free(end);
513  inp_deckfree(options);
514  inp_deckfree(realdeck);
515  inp_deckfree(deck);
516  return (true);
517  }
518  return (false);
519 }
520 
521 
522 static wordlist *
524 
525 struct line *deck;
526 {
527  struct line *dd, *ld;
528  wordlist *wl, *end = NULL;
529  char *s;
530 
531  ld = deck;
532  for (dd = deck->li_next; dd; dd = ld->li_next) {
533  if (dd->li_line[0] == '*') {
534  ld = dd;
535  continue;
536  }
537  s = dd->li_line;
538  while (isspace(*s)) s++;
539  inp_casefix(dd->li_line);
540 
541  if (prefix(".width",s) || prefix(".four",s) ||
542  prefix(".plot",s) || prefix(".print",s) ||
543  prefix(".save",s)) {
544  if (end) {
545  end->wl_next = alloc(struct wordlist);
546  end->wl_next->wl_prev = end;
547  end = end->wl_next;
548  }
549  else
550  wl = end = alloc(struct wordlist);
551  end->wl_word = copy(dd->li_line);
552  ld->li_next = dd->li_next;
553  txfree(dd->li_line);
554  txfree((char*)dd);
555  }
556  else
557  ld = dd;
558  }
559  return (end);
560 }
561 
562 
563 static wordlist *
564 get_controls(deck,allcmds)
565 
566 /* strip the control lines out of the deck and return as a wordlist */
567 struct line *deck;
568 bool allcmds;
569 {
570  bool commands = allcmds;
571  struct line *dd, *ld;
572  char *s;
573  wordlist *wl, *controls = NULL;
574 
575  ld = deck;
576  for (dd = deck->li_next; dd; dd = ld->li_next) {
577  if (ciprefix(".control", dd->li_line)) {
578  ld->li_next = dd->li_next;
579  txfree(dd->li_line);
580  txfree((char*)dd);
581  if (commands && !allcmds)
582  fprintf(cp_err,
583  "Warning: redundant .control card\n");
584  commands = true;
585  }
586  else if (ciprefix(".endc", dd->li_line)) {
587  ld->li_next = dd->li_next;
588  txfree(dd->li_line);
589  txfree((char*)dd);
590  if (commands)
591  commands = false;
592  else
593  fprintf(cp_err,
594  "Warning: misplaced .endc card\n");
595  }
596  else if (!*dd->li_line ||
597  (commands && (*dd->li_line == '#' || *dd->li_line == '*'))) {
598  /* So blank lines in com files don't get
599  * considered as circuits.
600  * Also kill comments in commands.
601  */
602  ld->li_next = dd->li_next;
603  txfree(dd->li_line);
604  txfree((char*)dd);
605  }
606  else if (commands || prefix("*#", dd->li_line)) {
607  wl = alloc(struct wordlist);
608  if (controls) {
609  wl->wl_next = controls;
610  controls->wl_prev = wl;
611  controls = wl;
612  }
613  else
614  controls = wl;
615  if (prefix("*#", dd->li_line))
616  wl->wl_word = copy(dd->li_line + 2);
617  else
618  wl->wl_word = copy(dd->li_line);
619  if (commands) {
620  for (;;) {
621  /* look for lines concatenated with \ */
622  s = wl->wl_word + strlen(wl->wl_word) - 1;
623  while (isspace(*s)) s--;
624  if (*s == '\\') {
625  *s = '\0';
626  ld->li_next = dd->li_next;
627  txfree(dd->li_line);
628  txfree((char*)dd);
629  dd = ld->li_next;
630  s = tmalloc(
631  strlen(wl->wl_word) + strlen(dd->li_line) + 1);
632  strcpy(s,wl->wl_word);
633  strcat(s,dd->li_line);
634  txfree(wl->wl_word);
635  wl->wl_word = s;
636  continue;
637  }
638  break;
639  }
640  }
641  ld->li_next = dd->li_next;
642  txfree(dd->li_line);
643  txfree((char*)dd);
644  }
645  else
646  ld = dd;
647  }
648  if (!controls)
649  return (NULL);
650  return (wl_reverse(controls));
651 }
652 
653 
654 /* New Feature: substitute for $variables in the spice deck as it is
655  * read. The variables must have been defined previously, and (presently)
656  * not in the same deck, i.e., not in control statements of the same file.
657  */
658 
659 
660 static void
661 varsub(str)
662 
663 /* replace the $variables */
664 char **str;
665 {
666  wordlist *wl;
667 
668  wl = wl_separate(*str);
669  cp_variablesubst(&wl);
670  txfree(*str);
671  *str = flatten(wl);
672  wl_free(wl);
673 }
674 
675 
676 #define VALIDCHARS "_<#?@.()[]&"
677 
678 
679 static wordlist *
681 
682 /* separate out the $variables into a linked wordlist */
683 char *str;
684 {
685  char *c, *d;
686  wordlist *wl, *wl0 = NULL;
687  int lev1, lev2;
688 
689  c = str;
690  while (isspace(*c)) c++;
691 
692  while ((d = strchr(c,'$')) != NULL) {
693  if (d != c) {
694  if (wl0 == NULL) {
695  wl = wl0 = alloc(wordlist);
696  }
697  else {
698  wl->wl_next = alloc(wordlist);
699  wl->wl_next->wl_prev = wl;
700  wl = wl->wl_next;
701  }
702  wl->wl_word = tmalloc((d-c+1)*sizeof(char));
703  strncpy(wl->wl_word,c,d-c);
704  wl->wl_word[d-c] = '\0';
705  c = wl->wl_word + (d-c-1);
706  while(isspace(*c)) *c-- = '\0';
707  }
708  c = d;
709  if (*++d == '\0') break;
710  if (*++d == '\0') break;
711  if (wl0 == NULL) {
712  wl = wl0 = alloc(wordlist);
713  }
714  else {
715  wl->wl_next = alloc(wordlist);
716  wl->wl_next->wl_prev = wl;
717  wl = wl->wl_next;
718  }
719  if (*d &&
720  (isalphanum(*d) || strchr(VALIDCHARS, *d) || *d == cp_dol)) {
721  d++;
722  }
723  lev1 = lev2 = 0;
724  for ( ; *d; d++) {
725  if (isalphanum(*d))
726  continue;
727  if (*d == '[') {
728  lev1++;
729  continue;
730  }
731  if (*d == '(') {
732  lev2++;
733  continue;
734  }
735  if (*d == ']') {
736  if (lev1) lev1--;
737  continue;
738  }
739  if (*d == ')') {
740  if (lev2) lev2--;
741  continue;
742  }
743  if (strchr(VALIDCHARS, *d))
744  continue;
745  if (lev1 || lev2)
746  continue;
747  break;
748  }
749  wl->wl_word = tmalloc((d-c+1)*sizeof(char));
750  strncpy(wl->wl_word,c,d-c);
751  wl->wl_word[d-c] = '\0';
752  while (*d && isspace(*d)) d++;
753  c = d;
754  }
755  if (*c) {
756  if (wl0 == NULL) {
757  wl = wl0 = alloc(wordlist);
758  }
759  else {
760  wl->wl_next = alloc(wordlist);
761  wl->wl_next->wl_prev = wl;
762  wl = wl->wl_next;
763  }
764  wl->wl_word = copy(c);
765  }
766  return (wl0);
767 }
768 
769 
770 static char *
772 
773 /* like wl_flatten(), but join tokens with leading '%' */
774 wordlist *wl;
775 {
776  wordlist *ww;
777  int len;
778  char *str, *s;
779 
780  len = 1;
781  for (ww = wl; ww; ww = ww->wl_next)
782  len += strlen(ww->wl_word) + 1;
783  str = tmalloc(len);
784  *str = '\0';
785  for (ww = wl; ww; ww = ww->wl_next) {
786  s = ww->wl_word;
787  if (*s == '%') {
788  while (*s == '%') s++;
789  strcat(str,s);
790  continue;
791  }
792  if (ww != wl)
793  strcat(str," ");
794  strcat(str,s);
795  }
796  return (str);
797 }
798 
799 
800 /* This routine is cut in half here because com_rset has to do what follows
801  * also. End is the list of commands we execute when the job is finished:
802  * we only bother with this if we might be running in batch mode, since
803  * it isn't much use otherwise.
804  */
805 
806 void
807 inp_dodeck(deck, tt, end, reuse, options, filename)
808 
809 struct line *deck;
810 char *tt;
811 wordlist *end;
812 bool reuse;
813 struct line *options;
814 char *filename;
815 {
816  struct circ *ct;
817  struct line *dd;
818  char *ckt, *s;
819  INPtables *tab;
820  struct variable *eev = NULL;
821  wordlist *wl;
822  bool noparse, ii;
823  extern char *kw_noparse;
824 
825  /* First throw away any old error messages there might be and fix
826  * the case of the lines.
827  */
828  for (dd = deck; dd; dd = dd->li_next) {
829  if (dd->li_error) {
830  tfree(dd->li_error);
831  dd->li_error = NULL;
832  }
833  }
834  for (dd = options; dd; dd = dd->li_next) {
835  if (dd->li_error) {
836  tfree(dd->li_error);
837  dd->li_error = NULL;
838  }
839  }
840  if (reuse) {
841  ct = ft_curckt;
842  }
843  else {
844  if (ft_curckt) {
846  (char *) NULL);
848  (char *) NULL);
849  }
850  ft_curckt = ct = alloc(struct circ);
851  }
852  (void) cp_getvar(kw_noparse, VT_BOOL, (char *) &noparse);
853  if (!noparse)
854  ckt = if_inpdeck(deck, (char**)&tab);
855  else
856  ckt = NULL;
857 
858  for (dd = deck; dd; dd = dd->li_next)
859  if (dd->li_error) {
860  if (cp_out != stdout)
861  fprintf(cp_err, "Warning, line %d : %s\n%s\n",
862  dd->li_linenum, dd->li_line, dd->li_error);
863  else
864  out_printf("Warning, line %d : %s\n%s\n",
865  dd->li_linenum, dd->li_line, dd->li_error);
866  }
867 
868  /* Add this circuit to the circuit list. If reuse is true then
869  * use the ft_curckt structure.
870  */
871 
872  if (!reuse) {
873  for (dd = deck->li_next; dd; dd = dd->li_next)
874  if_setndnames(dd->li_line);
875 
876  /* Be sure that ci_devices and ci_nodes are valid */
878  (char *) NULL);
882  ft_newcirc(ct);
883  /* ft_setccirc(); */ ft_curckt = ct;
884  }
885  ct->ci_name = tt;
886  ct->ci_deck = deck;
887  ct->ci_options = options;
888  if (deck->li_actual)
889  ct->ci_origdeck = deck->li_actual;
890  else
891  ct->ci_origdeck = ct->ci_deck;
892  ct->ci_ckt = ckt;
893  ct->ci_symtab = (char*)tab;
894  ct->ci_inprogress = false;
895  ct->ci_runonce = false;
896  ct->ci_commands = end;
897  if (filename)
898  ct->ci_filename = filename;
899  else
900  tfree(ct->ci_filename);
901 
902  if (!noparse) {
903  for (; options; options = options->li_next) {
904  INP2dot(ct->ci_ckt,(INPtables*)ct->ci_symtab,
905  (card*)options,NULL,NULL);
906  for (s = options->li_line; *s && !isspace(*s); s++)
907  ;
908  ii = cp_interactive;
909  cp_interactive = false;
910  wl = cp_lexer(s);
911  cp_interactive = ii;
912  if (!wl || !wl->wl_word || !*wl->wl_word)
913  continue;
914  if (eev)
915  eev->va_next = cp_setparse(wl);
916  else
917  ct->ci_vars = eev = cp_setparse(wl);
918  wl_free(wl);
919  while (eev->va_next)
920  eev = eev->va_next;
921 
922  if (options->li_error)
923  out_printf("Warning, line %d : %s\n%s\n",
924  options->li_linenum, options->li_line, options->li_error);
925  }
926  }
927 
929  return;
930 }
931 
932 
933 /* Edit and re-load the current input deck. In this version, the previous
934  * circuit (before editing) is kept, but is no longer associated with the
935  * original file name, unless "-r" option is given. "-n" supresses source
936  * after edit;
937  */
938 
939 void
941 
942 wordlist *wl;
943 {
944 
945  char *filename;
946  FILE *fp;
947  bool permfile, nosource = false, reuse = false;
948  struct circ *old;
949  extern char *kw_editor;
950  char ed[BSIZE_SP];
951  int rval;
952 
953  if (SCEDactive()) {
954  ShowPrompt("Exit sced to edit.");
955  return;
956  }
957 
958 top:
959  if (wl) {
960 
961  /* supress sourcing if "-n" given */
962  /* reuse ckt structure if "-r" given */
963  if (eq(wl->wl_word,"-n")) {
964  nosource = true;
965  wl = wl->wl_next;
966  goto top;
967  }
968  if (eq(wl->wl_word,"-r")) {
969  reuse = true;
970  wl = wl->wl_next;
971  goto top;
972  }
973  if (wl->wl_next && eq(wl->wl_next->wl_word,"-n"))
974  nosource = true;
975  if (wl->wl_next && eq(wl->wl_next->wl_word,"-r"))
976  reuse = true;
977  filename = wl->wl_word;
978  permfile = true;
979  }
980  else {
981  if (ft_curckt && ft_curckt->ci_filename) {
982  /* know the circuit and file */
983  filename = ft_curckt->ci_filename;
984  permfile = true;
985  }
986  else {
987  /* work with temp file */
988  filename = smktemp("sp");
989  permfile = false;
990  }
991  if (ft_curckt && !ft_curckt->ci_filename) {
992  /* Circuit came from file which was subsequently modified.
993  * Dump circuit listing into temp file.
994  */
995  if (!(fp = fopen(filename, "w"))) {
996  perror(filename);
997  return;
998  }
1001  fprintf(cp_err,
1002  "Warning: editing a temporary file -- circuit not saved\n");
1003  (void) fclose(fp);
1004  }
1005  else if (!ft_curckt) {
1006  /* No current circuit, user must create (using temp file) */
1007  if (!(fp = fopen(filename, "w"))) {
1008  perror(filename);
1009  return;
1010  }
1011  fprintf(fp, "SPICE 3 test deck\n");
1012  (void) fclose(fp);
1013  }
1014  }
1015 
1016  rval = cp_getvar(kw_editor, VT_STRING, ed);
1017  if ((!rval || cieq(ed, "xeditor")) && !xeditor(filename)) {
1018  if (!permfile) {
1019  (void) unlink(filename);
1020  txfree(filename);
1021  }
1022  return;
1023  }
1024  else {
1025 
1026 #ifdef HAVE_STAT
1027  /* supress source if file is not written */
1028  int i, j;
1029  struct stat st1, st2;
1030 
1031  if (permfile) {
1032  i = stat(filename,&st1);
1033  if (inp_edit(filename))
1034  return;
1035  j = stat(filename,&st2);
1036  if (j == -1)
1037  return;
1038  if (!i && st1.st_mtime == st2.st_mtime) {
1039  /* file was not modified */
1040  for (old = ft_circuits; old; old = old->ci_next) {
1041  if (old->ci_filename && eq(old->ci_filename,filename))
1042  /* already sourced */
1043  return;
1044  }
1045  }
1046  }
1047  else
1048 #endif
1049  if (inp_edit(filename)) return;
1050  }
1051  if (!nosource)
1052  inp_srcedit(filename, permfile, reuse);
1053 }
1054 
1055 
1056 void
1057 inp_srcedit(filename, permfile, reuse)
1058 
1059 char *filename;
1060 bool permfile, reuse;
1061 {
1062  FILE *fp;
1063  struct circ *old;
1064  bool inter;
1065 
1066  inter = cp_interactive;
1067  cp_interactive = false;
1068  if (!(fp = inp_pathopen(filename, "r"))) {
1069  perror(filename);
1070  goto ret;
1071  }
1072  if (reuse) if_cktclear();
1073  inp_spsource(fp, false, permfile ? filename : (char *) NULL);
1074  (void) fclose(fp);
1075 
1076  if (!permfile) {
1077  (void) unlink(filename);
1078  txfree(filename);
1079  }
1080 
1081  /* Check for other loaded circuits from the same file. If found,
1082  * free and null the filename entry, as the file has been edited
1083  * and therefore does not correspond to the saved circuit struct.
1084  */
1085  if (permfile)
1086  for (old = ft_circuits; old; old = old->ci_next) {
1087  if (old != ft_curckt && old->ci_filename &&
1088  eq(old->ci_filename,filename))
1089  tfree(old->ci_filename);
1090  }
1091 ret:
1092  cp_interactive = inter;
1093  return;
1094 }
1095 
1096 
1097 /* SCED interface */
1098 void
1100 
1101 wordlist *wl;
1102 {
1103  FILE *fp,*errfp,*outfp,*errtmp,*outtmp;
1104  struct circ *old;
1105  bool inter, nosource = false, reuse = false;
1106  char *errmsg = "Error: no symbolic representation found.\n";
1107  char *filename,*errfile,*outfile;
1108  int i;
1109 
1110  inter = cp_interactive;
1111  cp_interactive = false;
1112 top:
1113  if (wl) {
1114 
1115  /* supress sourcing if "-n" given */
1116  /* reuse ckt structure if "-r" given */
1117  if (eq(wl->wl_word,"-n")) {
1118  nosource = true;
1119  wl = wl->wl_next;
1120  goto top;
1121  }
1122  if (eq(wl->wl_word,"-r")) {
1123  reuse = true;
1124  wl = wl->wl_next;
1125  goto top;
1126  }
1127  if (wl->wl_next && eq(wl->wl_next->wl_word,"-n"))
1128  nosource = true;
1129  if (wl->wl_next && eq(wl->wl_next->wl_word,"-r"))
1130  reuse = true;
1131  filename = wl->wl_word;
1132  }
1133  else {
1134  if (ft_curckt && ft_curckt->ci_filename) {
1135  /* know the circuit and symbolic file */
1136  filename = ft_curckt->ci_filename;
1137  }
1138  else {
1139  if (ft_curckt) {
1140  fprintf(cp_err,errmsg);
1141  goto ret;
1142  }
1143  else {
1144  filename = "noname";
1145  }
1146  }
1147  }
1148  errfile = smktemp("er");
1149  outfile = smktemp("ot");
1150 
1151  errfp = fopen(errfile,"w+");
1152  outfp = fopen(outfile,"w");
1153  if (errfp == NULL || outfp == NULL) {
1154  fprintf(cp_err,"Error: redirection failed.\n");
1155  return;
1156  }
1157  errtmp = cp_err;
1158  outtmp = cp_out;
1159  cp_err = cp_curerr = errfp;
1160  cp_out = cp_curout = outfp;
1161 
1162 
1163 #ifdef HAVE_STAT
1164 /* supress source if file is not written */
1165 {
1166  int k, j;
1167  struct stat st1, st2;
1168  char *f1;
1169 
1170  f1 = filename;
1171  k = stat(filename,&st1);
1172  i = sced(&filename);
1173  if (i == 1) {
1174  j = stat(filename,&st2);
1175  if (j == -1)
1176  i = 2;
1177  if (!k && eq(f1,filename) && st1.st_mtime == st2.st_mtime) {
1178  /* file was not modified */
1179  for (old = ft_circuits; old; old = old->ci_next) {
1180  if (old->ci_filename && eq(old->ci_filename,filename)) {
1181  /* already sourced */
1182  i = 2;
1183  break;
1184  }
1185  }
1186  }
1187  }
1188 }
1189 #else
1190  i = sced(&filename);
1191 #endif
1192  cp_curout = outtmp;
1193  cp_curerr = errtmp;
1194  cp_ioreset();
1195  unlink(errfile);
1196  unlink(outfile);
1197  tfree(errfile);
1198  tfree(outfile);
1199 
1200  if (i == 3) {
1201  fprintf(cp_err,errmsg);
1202  goto ret;
1203  }
1204  if (i == 2 || nosource)
1205  goto ret;
1206 
1207  if (i == 1) {
1208  if (!(fp = inp_pathopen(filename, "r"))) {
1209  perror(filename);
1210  goto ret;
1211  }
1212  if (reuse) if_cktclear();
1213  fprintf(cp_err,"Sourcing the spice text from %s\n",filename);
1214  fprintf(cp_err,
1215 "Warning: this text may not accurately reflect subcircuit changes\n\
1216 made after %s was saved in sced\n",filename);
1217  inp_spsource(fp,false,filename);
1218  (void) fclose(fp);
1219  }
1220 
1221  /* Check for other loaded circuits from the same file. If found,
1222  * free and null the filename entry, as the file has been edited
1223  * and therefore does not correspond to the saved circuit struct.
1224  */
1225  for (old = ft_circuits; old; old = old->ci_next) {
1226  if (old != ft_curckt)
1227  if (old->ci_filename && eq(old->ci_filename,filename))
1228  tfree(old->ci_filename);
1229  }
1230 ret:
1231  cp_interactive = inter;
1232  return;
1233 }
1234 
1235 
1236 void
1238 
1239 wordlist *wl;
1240 {
1241  FILE *fp, *tp;
1242  char buf[BSIZE_SP];
1243  bool inter;
1244  char *tempfile = NULL, *fname;
1245  wordlist *owl, *ww, *wn;
1246  int i;
1247  bool nospice = false, nocmds = false, reuse = false;
1248 
1249  owl = wl;
1250  wl = wl_copy(wl);
1251  ww = wl;
1252  for (; wl; wl = wn) {
1253  wn = wl->wl_next;
1254  if (*wl->wl_word != '-')
1255  continue;
1256  if (strchr(wl->wl_word,'n'))
1257  nospice = true;
1258  else if (strchr(wl->wl_word,'c'))
1259  nocmds = true;
1260  else if (strchr(wl->wl_word,'r'))
1261  reuse = true;
1262  else
1263  continue;
1264  if (wl->wl_prev)
1265  wl->wl_prev->wl_next = wl->wl_next;
1266  if (wl->wl_next)
1267  wl->wl_next->wl_prev = wl->wl_prev;
1268  txfree(wl->wl_word);
1269  if (ww == wl)
1270  ww = wl->wl_next;
1271  txfree((char*)wl);
1272  }
1273  wl = ww;
1274 
1275  inter = cp_interactive;
1276  cp_interactive = false;
1277  if (wl && wl->wl_next) {
1278  /* There are several files -- put them into a temp file */
1279  tempfile = smktemp("sp");
1280  if (!(fp = inp_pathopen(tempfile, "w+"))) {
1281  perror(tempfile);
1282  goto done;
1283  }
1284  while (wl) {
1285  if (!(tp = inp_pathopen(wl->wl_word, "r"))) {
1286  perror(wl->wl_word);
1287  (void) fclose(fp);
1288  goto done;
1289  }
1290  while ((i = fread(buf, 1, BSIZE_SP, tp)) > 0)
1291  (void) fwrite(buf, 1, i, fp);
1292  (void) fclose(tp);
1293  wl = wl->wl_next;
1294  }
1295  (void) fseek(fp, (long) 0, 0);
1296  }
1297  else {
1298  if (wl) {
1299  if (!(fp = inp_pathopen(wl->wl_word, "r"))) {
1300  perror(wl->wl_word);
1301  goto done;
1302  }
1303  }
1304  else
1305  fp = stdin;
1306  }
1307  if (reuse && !nospice)
1308  if_cktclear();
1309 
1310  if (tempfile)
1311  fname = NULL;
1312  else {
1313  if (wl)
1314  fname = wl->wl_word;
1315  else
1316  fname = NULL;
1317  }
1318 
1319  /* Don't print the title if this is a .spiceinit file. */
1320  if (substring(".spiceinit", owl->wl_word) ||
1321  substring("spice.rc", owl->wl_word))
1322  spsource(fp, true, true, fname);
1323  else
1324  spsource(fp,nospice,nocmds,fname);
1325  if (fp != stdin)
1326  (void) fclose(fp);
1327 
1328 done:
1329  cp_interactive = inter;
1330 
1331  if (tempfile) {
1332  (void) unlink(tempfile);
1333  txfree(tempfile);
1334  }
1335  wl_free(ww);
1336  return;
1337 }
1338 
1339 
1340 void
1342 
1343 char *file;
1344 {
1345  wordlist *wl;
1346 
1347  wl = cp_lexer(file);
1348  com_source(wl);
1349  wl_free(wl);
1350  return;
1351 }
static bool is_ckt()
void ft_check()
int li_linenum
Definition: fteinp.h:15
void cp_ioreset()
Definition: cshpar.c:349
void com_edit(wordlist *wl)
Definition: inp.c:940
struct line * li_actual
Definition: fteinp.h:19
static char buf[MAXPROMPT]
Definition: arg.c:18
#define BSIZE_SP
Definition: misc.h:19
#define eq(a, b)
Definition: misc.h:29
void inp_casefix()
int ciprefix()
struct circ * ci_next
Definition: ftedefs.h:37
void inp_readall()
void inp_decksource(struct line *deck, bool comfile, char *filename)
Definition: inp.c:367
bool cp_getvar(char *n, int t, char *r)
Definition: help.c:184
static wordlist * get_speccmds()
int cieq()
#define LS_PHYSICAL
Definition: fteinp.h:25
#define prefix(x, y)
Definition: readhelp.c:39
void out_printf()
char * strcpy()
struct line * inp_deckcopy()
Definition: ftedefs.h:25
wordlist * wl_reverse()
Definition: cddefs.h:119
static complex ii
Definition: vectors.c:19
struct line * ci_origdeck
Definition: ftedefs.h:31
Definition: xforms.c:16
char * kw_nosubckt
Definition: options.c:395
struct line * ci_deck
Definition: ftedefs.h:30
char * ci_devices
Definition: ftedefs.h:39
bool inp_spdeck(struct line *deck, char *filename)
Definition: inp.c:463
static void decksource()
Definition: inpdefs.h:62
struct line * ci_options
Definition: ftedefs.h:32
bool ci_inprogress
Definition: ftedefs.h:34
FILE * cp_curerr
Definition: cshpar.c:77
char * ci_ckt
Definition: ftedefs.h:27
static char * upper()
void inp_srcedit(char *filename, bool permfile, bool reuse)
Definition: inp.c:1057
char * ci_filename
Definition: ftedefs.h:40
#define tab(num)
Definition: front.c:1365
#define LS_DECK
Definition: fteinp.h:26
void inp_source(char *file)
Definition: inp.c:1341
void inp_spsource(FILE *fp, bool comfile, char *filename)
Definition: inp.c:308
Definition: library.c:18
Definition: cddefs.h:312
struct line * inp_getopts()
char * ci_contblk
Definition: ftedefs.h:29
static wordlist * get_controls()
char * kw_noparse
Definition: options.c:392
#define alloc(type)
Definition: cdmacs.h:21
struct variable * cp_setparse()
char * ci_nodes
Definition: ftedefs.h:38
char * copy()
static char * flatten()
FILE * cp_curin
Definition: cshpar.c:75
void wl_free()
FILE * cp_err
Definition: help.c:101
char * tmalloc()
#define CT_DEVNAMES
Definition: fteconst.h:87
Definition: fteinp.h:14
void com_source(wordlist *wl)
Definition: inp.c:1237
static void varsub()
struct circ * ft_circuits
Definition: main.c:185
void if_cktclear()
Definition: spiceif.c:476
int substring()
struct wordlist * wl_prev
Definition: cpstd.h:24
void inp_list(FILE *file, struct line *deck, struct line *extras, int type)
Definition: inp.c:122
Definition: cddefs.h:237
bool cp_interactive
Definition: help.c:100
#define tfree(x)
Definition: cdmacs.h:22
static wordlist * wl_separate()
#define LS_LOGICAL
Definition: fteinp.h:24
void txfree()
#define NULL
Definition: spdefs.h:121
Definition: types.c:18
char * li_error
Definition: fteinp.h:17
struct circ * ft_curckt
Definition: main.c:184
FILE * inp_pathopen()
FILE * cp_out
Definition: help.c:101
int unlink(char *fn)
Definition: libfuncs.c:96
char * li_line
Definition: fteinp.h:16
char * kw_renumber
Definition: options.c:412
void inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse, struct line *options, char *filename)
Definition: inp.c:807
bool ft_servermode
Definition: main.c:46
void com_listing(wordlist *wl)
Definition: inp.c:49
int INP2dot()
void ft_newcirc()
struct variable * ci_vars
Definition: ftedefs.h:33
char * smktemp()
static double c
Definition: vectors.c:16
#define VT_STRING
Definition: cpstd.h:63
void perror()
void if_setndnames()
struct line * li_next
Definition: fteinp.h:18
char cp_dol
Definition: variable.c:51
wordlist * cp_lexer()
bool ci_runonce
Definition: ftedefs.h:35
#define VT_BOOL
Definition: cpstd.h:60
void inp_deckfree()
Definition: cpstd.h:21
static void spsource()
int sced()
struct line * inp_subcktexpand()
void cp_variablesubst()
int xeditor()
static struct ccom * commands
Definition: complete.c:94
Definition: netlist.c:477
void com_sced(wordlist *wl)
Definition: inp.c:1099
void out_send()
struct wordlist * wl_next
Definition: cpstd.h:23
#define CT_NODENAMES
Definition: fteconst.h:89
char * if_inpdeck()
char * ci_symtab
Definition: ftedefs.h:28
char * ci_name
Definition: ftedefs.h:26
char * wl_word
Definition: cpstd.h:22
wordlist * ci_commands
Definition: ftedefs.h:36
void cp_pushcontrol()
Definition: front.c:1066
bool inp_edit()
void cp_popcontrol()
Definition: front.c:1051
char * kw_editor
Definition: options.c:354
#define CT_CKTNAMES
Definition: fteconst.h:84
#define isalphanum(c)
Definition: misc.h:30
#define VALIDCHARS
Definition: inp.c:676
int cp_evloop()
enum Active SCEDactive()
Definition: scedstub.c:63
FILE * cp_curout
Definition: cshpar.c:76
FILE * cp_in
Definition: help.c:101
void cp_addkword()
struct variable * va_next
Definition: cpstd.h:51
void ShowPrompt(char *str)
Definition: scedstub.c:71
Definition: cpstd.h:41
char * readline()
void out_init()
Definition: output.c:128
char * cp_kwswitch()
wordlist * wl_copy()