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
com_listing(wl)49 com_listing(wl)
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 :
84 ft_curckt->ci_origdeck, ft_curckt->ci_options,
85 type);
86 }
87 else
88 fprintf(cp_err, "Error: no circuit loaded.\n");
89 return;
90 }
91
92
93 static char *
upper(string)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
inp_list(file,deck,extras,type)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
inp_spsource(fp,comfile,filename)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
spsource(fp,nospice,nocmds,filename)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
inp_decksource(deck,comfile,filename)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
decksource(deck,nospice,nocmds,filename)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
is_ckt(deck)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
inp_spdeck(deck,filename)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 *
get_speccmds(deck)523 get_speccmds(deck)
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 *
get_controls(deck,allcmds)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
varsub(str)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 *
wl_separate(str)680 wl_separate(str)
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 *
flatten(wl)771 flatten(wl)
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
inp_dodeck(deck,tt,end,reuse,options,filename)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) {
845 ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES,
846 (char *) NULL);
847 ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES,
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 */
877 ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES,
878 (char *) NULL);
879 (void) cp_kwswitch(CT_DEVNAMES, ft_curckt->ci_devices);
880 ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, (char *) NULL);
881 (void) cp_kwswitch(CT_NODENAMES, ft_curckt->ci_nodes);
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
928 cp_addkword(CT_CKTNAMES, tt);
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
com_edit(wl)940 com_edit(wl)
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 }
999 inp_list(fp, ft_curckt->ci_origdeck ? ft_curckt->ci_origdeck :
1000 ft_curckt->ci_deck, ft_curckt->ci_options, LS_DECK);
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
inp_srcedit(filename,permfile,reuse)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
com_sced(wl)1099 com_sced(wl)
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
com_source(wl)1237 com_source(wl)
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
inp_source(file)1341 inp_source(file)
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 }
1352