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: 1988 Wayne A. Christopher
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * This module replaces the old "writedata" routines in nutmeg.
10  * Unlike the writedata routines, the OUT routines are only called by
11  * the simulator routines, and only call routines in nutmeg.  The rest
12  * of nutmeg doesn't deal with OUT at all.
13  */
14 
15 #include "spice.h"
16 #include "ftedefs.h"
17 #include "inpdefs.h"
18 #include "ftegraph.h"
19 #include "spfteext.h"
20 #include "plotext.h"
21 #include "iferrmsg.h"
22 #include "outdata.h"
23 
24 #define DOUBLE_PRECISION    15
25 
26 typedef struct dataDesc {
27     char *name;         /* The name of the vector. */
28     int type;           /* The type. */
29     bool regular;       /* Is this given to us? */
30     int outIndex;       /* If regular then the index. */
31     char *specName;     /* The device name if special. */
32     char *specParamName;/* The parameter name if special. */
33     int specIndex;      /* For sensitivity, if special. */
34     int specType;
35     GENERIC *specFast;
36     int refIndex;       /* The index of our ref vector. */
37     struct dvec *vec;
38 } dataDesc;
39 
40 typedef struct runDesc {
41     GENERIC *analysis;
42     GENERIC *circuit;
43     char *name;
44     char *type;
45     int numData;
46     int refIndex;
47     dataDesc *data;
48     bool writeOut;
49     bool binary;
50     struct plot *runPlot;
51     FILE *fp;
52     long pointPos;      /* where to write pointCount */
53     int pointCount;     /* running count of output points */
54     int numPoints;      /* num points expected, -1 if not known */
55     int isComplex;
56     int windowCount;
57 } runDesc;
58 
59 /* signal the simulator to end analysis as if finished */
60 bool OUTendit;
61 
62 static struct sOUTcontrol OUTcntrl;
63 
64 #ifdef __STDC__
65 static void out_destroy(void);
66 static int  addDataDesc(runDesc*,char*,int,int);
67 static int  addSpecialDesc(runDesc*,char*,char*,char*,int);
68 static void addPointToFile(runDesc*,IFvalue*,IFvalue*);
69 static void addPointToPlot(runDesc*,IFvalue*,IFvalue*,bool);
70 static void fileInit(runDesc*);
71 static void fileStartPoint(FILE*,bool,int);
72 static void fileAddRealValue(FILE*,bool,double);
73 static void fileAddComplexValue(FILE*,bool,IFcomplex);
74 static void fileEndPoint(FILE*,bool);
75 static void fileEnd(runDesc*);
76 static void plotInit(runDesc*,double,double,double,struct plot*);
77 static void plotAddRealValue(dataDesc*,double,bool);
78 static void plotAddComplexValue(dataDesc*,IFcomplex,bool);
79 static void plotEnd(runDesc*);
80 static bool parseSpecial(char*,char*,char*,char*);
81 static bool name_eq(char*,char*);
82 static bool getSpecial(dataDesc*,runDesc*,IFvalue*);
83 static void freeRun(runDesc*);
84 #else
85 static void out_destroy();
86 static int  addDataDesc();
87 static int  addSpecialDesc();
88 static void addPointToFile();
89 static void addPointToPlot();
90 static void fileInit();
91 static void fileStartPoint();
92 static void fileAddRealValue();
93 static void fileAddComplexValue();
94 static void fileEndPoint();
95 static void fileEnd();
96 static void plotInit();
97 static void plotAddRealValue();
98 static void plotAddComplexValue();
99 static void plotEnd();
100 static bool parseSpecial();
101 static bool name_eq();
102 static bool getSpecial();
103 static void freeRun();
104 #endif
105 
106 static bool shouldstop = false; /* Tell simulator to stop next time it asks. */
107 static bool printinfo = false;    /* Print informational "error messages". */
108 
109 
110 char *
OUTcntrlInit()111 OUTcntrlInit()
112 {
113     /* return the OUTcntrl structure */
114     OUTcntrl.out_destroy    = out_destroy;
115     OUTcntrl.out_rundesc    = NULL;
116     OUTcntrl.out_check      = false;
117     OUTcntrl.out_usecurplot = false;
118     OUTcntrl.out_keepplot   = false;
119     OUTcntrl.out_points     = NULL;
120     OUTcntrl.out_index      = 0;
121     OUTcntrl.out_max        = 0;
122     OUTcntrl.out_fail       = 0;
123     OUTcntrl.out_evaluate   = NULL;
124     OUTcntrl.out_end        = NULL;
125     return (char *)&OUTcntrl;
126 }
127 
128 
129 static void
out_destroy()130 out_destroy()
131 {
132     if (OUTcntrl.out_rundesc) {
133         freeRun((runDesc*)OUTcntrl.out_rundesc);
134         OUTcntrl.out_rundesc = NULL;
135     }
136     OUTcntrl.out_check      = false;
137     OUTcntrl.out_usecurplot = false;
138     OUTcntrl.out_keepplot   = false;
139     OUTcntrl.out_points     = NULL;
140     OUTcntrl.out_index      = 0;
141     OUTcntrl.out_max        = 0;
142     OUTcntrl.out_fail       = 0;
143     OUTcntrl.out_evaluate   = NULL;
144     OUTcntrl.out_end        = NULL;
145 }
146 
147 
148 int
OUTbeginPlot(outdp)149 OUTbeginPlot(outdp)
150 
151 GENERIC *outdp;
152 {
153     struct sOUTdata *outd = (struct sOUTdata*)outdp;
154     struct plot *plot = NULL;
155     runDesc *run;
156     char **saves;
157     char *cktName;
158     bool *savesused;
159     int numsaves;
160     int i, j, depind;
161     char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP];
162     bool saveall = true;
163     extern char *kw_printinfo;
164 
165     shouldstop = false;
166 
167     if (OUTcntrl.out_check) {
168         OUTcntrl.out_index = 0;
169     }
170     if (OUTcntrl.out_usecurplot) {
171         plot = plot_cur;
172     }
173     if (OUTcntrl.out_keepplot && OUTcntrl.out_rundesc) {
174         *outd->plotPtr = (GENERIC*)OUTcntrl.out_rundesc;
175         return (OK);
176     }
177 
178     if (ft_curckt && ft_curckt->ci_ckt == outd->circuitPtr)
179         cktName = ft_curckt->ci_name;
180     else {
181         /* hack for test system interface */
182         if (outd->circuitPtr == NULL)
183             cktName = (char*)outd->refName + (strlen(outd->refName) + 1);
184         else
185             cktName = "circuit name";
186     }
187 
188     /* Check to see if we want to print informational data. */
189     if (cp_getvar(kw_printinfo, VT_BOOL, (char *) &printinfo))
190     fprintf(cp_err, "(debug printing enabled)\n");
191 
192     run = alloc(struct runDesc);
193     *outd->plotPtr = (GENERIC*)run;
194 
195     /* First fill in some general stuff. */
196     run->analysis = outd->analysisPtr;
197     run->circuit = outd->circuitPtr;
198     run->name = copy(cktName);
199     run->type = copy(outd->analName);
200     if (outd->numPts <= 0)
201         run->numPoints = 1;
202     else
203         run->numPoints = outd->numPts;
204 
205     if (OUTcntrl.out_check) {
206         run->numPoints = 1;
207     }
208     if (OUTcntrl.out_keepplot) {
209         OUTcntrl.out_rundesc = (char*)run;
210     }
211 
212     /* Now let's see which of these things we need.  First toss in the
213      * reference vector.  Then toss in anything that getSaves() tells
214      * us to save that we can find in the name list.  Finally unpack
215      * the remaining saves into parameters.
216      */
217     numsaves = ft_getSaves(&saves);
218     if (numsaves) {
219         savesused = (bool *) tmalloc(sizeof (bool) * numsaves);
220         saveall = false;
221         for (i = 0; i < numsaves; i++)
222             if (cieq(saves[i], "all")) {
223                 saveall = true;
224                 savesused[i] = true;
225                 break;
226             }
227     }
228 
229     /* Pass 0. */
230     if (outd->refName) {
231         addDataDesc(run, outd->refName, outd->refType, -1);
232         for (i = 0; i < numsaves; i++)
233             if (name_eq(saves[i], outd->refName)) {
234                 savesused[i] = true;
235             }
236     }
237     else {
238         run->refIndex = -1;
239     }
240 
241     /* Pass 1. */
242     if (numsaves && !saveall) {
243         for (i = 0; i < numsaves; i++) {
244             for (j = 0; j < outd->numNames; j++)
245                 if (name_eq(saves[i], outd->dataNames[j])) {
246                     addDataDesc(run, outd->dataNames[j],
247                             outd->dataType, j);
248                     savesused[i] = true;
249                     break;
250                 }
251         }
252     }
253     else {
254         for (i = 0; i < outd->numNames; i++)
255             if (!outd->refName ||
256                     !name_eq(outd->dataNames[i], outd->refName)) {
257                 addDataDesc(run, outd->dataNames[i], outd->dataType, i);
258             }
259     }
260 
261     /* Pass 2. */
262     for (i = 0; i < numsaves; i++) {
263         if (savesused[i])
264             continue;
265         if (!parseSpecial(saves[i], namebuf, parambuf, depbuf)) {
266             if (numsaves == 1 && !saves[0])
267                 fprintf(cp_err, "Warning: no variables saved\n");
268             else
269                 fprintf(cp_err, "Warning: can't parse '%s': ignored\n",
270                     saves[i]);
271             continue;
272         }
273         /* Now, if there's a dep variable, do we already have it? */
274         if (*depbuf) {
275             for (j = 0; j < run->numData; j++)
276                 if (name_eq(depbuf, run->data[j].name))
277                     break;
278             if (j == run->numData) {
279                 /* Better add it. */
280                 for (j = 0; j < outd->numNames; j++)
281                     if (name_eq(depbuf, outd->dataNames[j]))
282                         break;
283                 if (j == outd->numNames) {
284                     fprintf(cp_err,
285             "Warning: can't find '%s': value '%s' ignored\n",
286                         depbuf, saves[i]);
287                     continue;
288                 }
289                 addDataDesc(run, outd->dataNames[j], outd->dataType, j);
290                 savesused[i] = true;
291                 depind = j;
292             }
293             else
294                 depind = run->data[j].outIndex;
295         }
296         addSpecialDesc(run, saves[i], namebuf, parambuf, depind);
297     }
298 
299     if (numsaves)
300         txfree((char*)savesused);
301 
302     /* Now that we have our own data structures built up, let's see what
303      * nutmeg wants us to do.
304      */
305     run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
306             run->type, run->name);
307 
308     if (run->writeOut)
309         fileInit(run);
310     else
311         plotInit(run,outd->initValue,outd->finalValue,outd->step,plot);
312 
313     if (outd->refName && run->runPlot)
314         run->runPlot->pl_ndims = 1;
315 
316     return (OK);
317 }
318 
319 
320 static int
addDataDesc(run,name,type,ind)321 addDataDesc(run, name, type, ind)
322 
323 runDesc *run;
324 char *name;
325 int type;
326 int ind;
327 {
328     dataDesc *data;
329 
330     if (!run->numData)
331         run->data = (dataDesc *) tmalloc(sizeof (dataDesc));
332     else
333         run->data = (dataDesc *) trealloc((char *) run->data,
334                 sizeof (dataDesc) * (run->numData + 1));
335     data = &run->data[run->numData];
336     /* so freeRun will get nice NULL pointers for the fields we don't set */
337     bzero(data, sizeof(dataDesc));
338 
339     data->name = copy(name);
340     data->type = type;
341     data->regular = true;
342     data->outIndex = ind;
343 
344     if (ind == -1) {
345         /* It's the reference vector. */
346         run->refIndex = run->numData;
347     }
348 
349     run->numData++;
350 
351     return (OK);
352 }
353 
354 
355 static int
addSpecialDesc(run,name,devname,param,depind)356 addSpecialDesc(run, name, devname, param, depind)
357 
358 runDesc *run;
359 char *name;
360 char *devname;
361 char *param;
362 int depind;
363 {
364     dataDesc *data;
365     char *unique;       /* unique char * from back-end */
366 
367     if (!run->numData)
368         run->data = (dataDesc *) tmalloc(sizeof (dataDesc));
369     else
370         run->data = (dataDesc *) trealloc((char *) run->data,
371                 sizeof (dataDesc) * (run->numData + 1));
372     data = &run->data[run->numData];
373     /* so freeRun will get nice NULL pointers for the fields we don't set */
374     bzero(data, sizeof(dataDesc));
375 
376     data->name = copy(name);
377 
378     unique = devname;
379     INPinsert(&unique, (INPtables *) ft_curckt->ci_symtab);
380     data->specName = unique;
381 
382     data->specParamName = copy(param);
383 
384     data->specIndex = depind;
385     data->specType = -1;
386     data->specFast = NULL;
387     data->regular = false;
388 
389     run->numData++;
390 
391     return (OK);
392 }
393 
394 
395 int
OUTdata(plotPtr,refValue,valuePtr)396 OUTdata(plotPtr, refValue, valuePtr)
397 
398 GENERIC *plotPtr;
399 IFvalue *refValue;
400 IFvalue *valuePtr;
401 {
402     runDesc *run = (runDesc *) plotPtr;
403 
404     if (OUTcntrl.out_check) {
405 
406         if (refValue->rValue < OUTcntrl.out_points[OUTcntrl.out_index])
407             return (OK);
408 
409         addPointToPlot(run,refValue,valuePtr,false);
410         if (OUTcntrl.out_evaluate)
411             OUTcntrl.out_fail = (*OUTcntrl.out_evaluate)();
412         else
413             OUTcntrl.out_fail = false;
414 
415         OUTcntrl.out_index++;
416         if (OUTcntrl.out_fail || OUTcntrl.out_index == OUTcntrl.out_max) {
417             OUTendit = true;
418         }
419         return (OK);
420     }
421 
422     run->pointCount++;
423 
424     if (run->writeOut) {
425         addPointToFile(run,refValue,valuePtr);
426     }
427     else {
428         addPointToPlot(run,refValue,valuePtr,true);
429         gr_iplot(run->runPlot);
430     }
431 
432     if (ft_bpcheck(run->runPlot, run->pointCount) == false)
433         shouldstop = true;
434 
435     vec_gc();
436     return (OK);
437 }
438 
439 
440 int
OUTsetDims(plotPtr,dims,numDims)441 OUTsetDims(plotPtr,dims,numDims)
442 
443 GENERIC *plotPtr;
444 int *dims, numDims;
445 {
446     runDesc *run = (runDesc *) plotPtr;
447     struct dvec *v;
448     int i, j;
449 
450     if (OUTcntrl.out_check) {
451         OUTcntrl.out_index = 0;
452         if (OUTcntrl.out_fail)
453             OUTendit = true;
454         return (OK);
455     }
456 
457     if (run->writeOut)
458         return (OK);
459 
460     for (i = 0; i < run->numData; i++) {
461         v = run->data[i].vec;
462         for (j = 0; j < numDims; j++)
463             v->v_dims[j] = dims[j];
464         v->v_numdims = numDims;
465     }
466     return (OK);
467 }
468 
469 
470 static void
addPointToFile(run,refValue,valuePtr)471 addPointToFile(run,refValue,valuePtr)
472 
473 runDesc *run;
474 IFvalue *refValue;
475 IFvalue *valuePtr;
476 {
477     int i;
478     IFvalue val;
479 
480     fileStartPoint(run->fp, run->binary, run->pointCount);
481 
482     if (run->refIndex != -1) {
483         if (run->isComplex)
484             fileAddComplexValue(run->fp, run->binary, refValue->cValue);
485         else
486             fileAddRealValue(run->fp, run->binary, refValue->rValue);
487     }
488 
489     for (i = 0; i < run->numData; i++) {
490         /* we've already printed reference vec first */
491         if (run->data[i].outIndex == -1) continue;
492 
493         if (run->data[i].regular) {
494             if(run->data[i].type == IF_REAL)
495                 fileAddRealValue(run->fp, run->binary,
496                     valuePtr->v.vec.rVec
497                     [run->data[i].outIndex]);
498             else if (run->data[i].type == IF_COMPLEX)
499                 fileAddComplexValue(run->fp, run->binary,
500                     valuePtr->v.vec.cVec
501                     [run->data[i].outIndex]);
502             else
503                 fprintf(stderr, "OUTdata: unsupported data type\n");
504         }
505         else {
506             /* should pre-check instance */
507             if (!getSpecial(&run->data[i], run, &val))
508                 continue;
509             if (run->data[i].type == IF_REAL)
510                 fileAddRealValue(run->fp, run->binary,
511                     val.rValue);
512             else if (run->data[i].type == IF_COMPLEX)
513                 fileAddComplexValue(run->fp, run->binary,
514                     val.cValue);
515             else
516                 fprintf(stderr, "OUTdata: unsupported data type\n");
517         }
518     }
519     fileEndPoint(run->fp, run->binary);
520 }
521 
522 
523 static void
addPointToPlot(run,refValue,valuePtr,inc)524 addPointToPlot(run,refValue,valuePtr,inc)
525 
526 runDesc *run;
527 IFvalue *refValue;
528 IFvalue *valuePtr;
529 bool inc; /* increment dvec length if true */
530 {
531     int i;
532     IFvalue val;
533 
534     for (i = 0; i < run->numData; i++) {
535         if (run->data[i].outIndex == -1) {
536             if (run->data[i].type == IF_REAL)
537                 plotAddRealValue(&run->data[i],
538                         refValue->rValue,inc);
539             else if (run->data[i].type == IF_COMPLEX)
540                 plotAddComplexValue(&run->data[i],
541                         refValue->cValue,inc);
542         }
543         else if (run->data[i].regular) {
544             if (run->data[i].type == IF_REAL)
545                 plotAddRealValue(&run->data[i],
546                     valuePtr->v.vec.rVec
547                     [run->data[i].outIndex],inc);
548             else if (run->data[i].type == IF_COMPLEX)
549                 plotAddComplexValue(&run->data[i],
550                     valuePtr->v.vec.cVec
551                     [run->data[i].outIndex],inc);
552         }
553         else {
554             /* should pre-check instance */
555             if (!getSpecial(&run->data[i], run, &val))
556                 continue;
557             if (run->data[i].type == IF_REAL)
558                 plotAddRealValue(&run->data[i],
559                         val.rValue,inc);
560             else if (run->data[i].type == IF_COMPLEX)
561                 plotAddComplexValue(&run->data[i],
562                         val.cValue,inc);
563             else
564                 fprintf(stderr, "OUTdata: unsupported data type\n");
565         }
566     }
567 }
568 
569 
570 int
OUTendPlot(plotPtr)571 OUTendPlot(plotPtr)
572 
573 GENERIC *plotPtr;
574 {
575     runDesc *run = (runDesc *) plotPtr;
576 
577     if (OUTcntrl.out_check) {
578         if (OUTcntrl.out_end)
579             (*OUTcntrl.out_end)();
580         OUTendit = false;
581         return (OK);
582     }
583     else if (OUTcntrl.out_keepplot) {
584         return (OK);
585     }
586 
587     if (run->writeOut)
588         fileEnd(run);
589     else {
590         gr_end_iplot();
591         plotEnd(run);
592     }
593 
594     freeRun(run);
595 
596     return (OK);
597 }
598 
599 
600 /* The file writing routines. */
601 
602 static void
fileInit(run)603 fileInit(run)
604 
605 runDesc *run;
606 {
607     int i;
608     char *name, buf[BSIZE_SP];
609     int type;
610 
611     /* This is a hack. */
612     run->isComplex = false;
613     for (i = 0; i < run->numData; i++)
614         if (run->data[i].type == IF_COMPLEX)
615             run->isComplex = true;
616 
617     fprintf(run->fp, "Title: %s\n", run->name);
618     fprintf(run->fp, "Date: %s\n", datestring());
619     fprintf(run->fp, "Plotname: %s\n", run->type);
620     fprintf(run->fp, "Flags: %s\n", run->isComplex ? "complex" : "real");
621     fprintf(run->fp, "No. Variables: %d\n", run->numData);
622     fprintf(run->fp, "No. Points: ");
623 
624     fflush(run->fp);        /* Gotta do this for LATTICE. */
625     run->pointPos = ftell(run->fp);
626     fprintf(run->fp, "0       \n"); /* Save 8 spaces here. */
627 
628     fprintf(run->fp, "Command: version %s\n", ft_sim->version);
629     fprintf(run->fp, "Variables:\n");
630 
631     for (i = 0; i < run->numData; i++) {
632         if (isdigit(*run->data[i].name)) {
633       (void) sprintf(buf, "v(%s)", run->data[i].name);
634           name = buf;
635         }
636         else {
637           name = run->data[i].name;
638         }
639         if (substring("#branch", name))
640             type = SV_CURRENT;
641         else if (cieq(name, "time"))
642             type = SV_TIME;
643         else if (cieq(name, "frequency"))
644             type = SV_FREQUENCY;
645         else
646             type = SV_VOLTAGE;
647         fprintf(run->fp, "\t%d\t%s\t%s\n", i, name,
648                 ft_typenames(type));
649     }
650 
651     fprintf(run->fp, "%s:\n", run->binary ? "Binary" : "Values");
652 
653     return;
654 }
655 
656 
657 static void
fileStartPoint(fp,bin,num)658 fileStartPoint(fp, bin, num)
659 
660 FILE *fp;
661 bool bin;
662 int num;
663 {
664     if (!bin)
665         fprintf(fp, "%d", num - 1);
666 
667     return;
668 }
669 
670 
671 static void
fileAddRealValue(fp,bin,value)672 fileAddRealValue(fp, bin, value)
673 
674 FILE *fp;
675 bool bin;
676 double value;
677 {
678     if (bin)
679         fwrite((char *) &value, sizeof (double), 1, fp);
680     else
681         fprintf(fp, "\t%.*e\n", DOUBLE_PRECISION, value);
682 
683     return;
684 }
685 
686 
687 static void
fileAddComplexValue(fp,bin,value)688 fileAddComplexValue(fp, bin, value)
689 
690 FILE *fp;
691 bool bin;
692 IFcomplex value;
693 {
694 
695     if (bin) {
696         fwrite((char *) &value.real, sizeof (double), 1, fp);
697         fwrite((char *) &value.imag, sizeof (double), 1, fp);
698     }
699     else {
700         fprintf(fp, "\t%.*e,%.*e\n", DOUBLE_PRECISION, value.real,
701             DOUBLE_PRECISION, value.imag);
702     }
703 
704 }
705 
706 
707 /* ARGSUSED */ /* until some code gets written */
708 static void
fileEndPoint(fp,bin)709 fileEndPoint(fp, bin)
710 
711 FILE *fp;
712 bool bin;
713 {
714     return;
715 }
716 
717 
718 /* Here's the hack...  Run back and fill in the number of points. */
719 
720 static void
fileEnd(run)721 fileEnd(run)
722 
723 runDesc *run;
724 {
725     long place;
726 
727     if (run->fp == stdout)
728         return;
729     fflush(run->fp);    /* For LATTICE... */
730     place = ftell(run->fp);
731     fseek(run->fp, run->pointPos, 0);
732     fprintf(run->fp, "%d", run->pointCount);
733     fseek(run->fp, place, 0);
734     fflush(run->fp);
735 
736     return;
737 }
738 
739 
740 /* The plot maintenance routines. */
741 
742 static void
plotInit(run,tstart,tstop,tstep,plot)743 plotInit(run,tstart,tstop,tstep,plot)
744 
745 runDesc *run;
746 double tstart, tstop, tstep;
747 struct plot *plot;
748 {
749     struct plot *pl;
750     char buf[100];
751     struct dvec *v;
752     dataDesc *dd;
753     int i;
754 
755     if (plot == NULL) {
756         pl = plot_alloc(run->type);
757         plot_new(pl);
758         plot_setcur(pl->pl_typename);
759     }
760     else
761         pl = plot;
762     pl->pl_title = copy(run->name);
763     pl->pl_name = copy(run->type);
764     pl->pl_date = copy(datestring( ));
765     pl->pl_ndims = 0;
766     pl->pl_start = tstart;
767     pl->pl_stop = tstop;
768     pl->pl_step = tstep;
769     run->runPlot = pl;
770 
771     /* This is a hack. */
772     /* if any of them are complex, make them all complex */
773     run->isComplex = false;
774     for (i = 0; i < run->numData; i++) {
775       if (run->data[i].type == IF_COMPLEX) run->isComplex = true;
776     }
777 
778     for (i = 0; i < run->numData; i++) {
779         dd = &run->data[i];
780         v = alloc(struct dvec);
781         if (isdigit(*dd->name)) {
782             (void) sprintf(buf, "v(%s)", dd->name);
783             v->v_name = copy(buf);
784         }
785         else
786             v->v_name = copy(dd->name);
787         if (substring("#branch", v->v_name) || eq(v->v_name,"isweep"))
788             v->v_type = SV_CURRENT;
789         else if (cieq(v->v_name, "time"))
790             v->v_type = SV_TIME;
791         else if (cieq(v->v_name, "frequency"))
792             v->v_type = SV_FREQUENCY;
793         else
794             v->v_type = SV_VOLTAGE;
795         v->v_length = 0;
796         v->v_rlength = run->numPoints;
797         v->v_scale = NULL;
798 
799         if (!run->isComplex) {
800             v->v_flags = VF_REAL;
801             v->v_realdata = (double *)
802                 tmalloc(v->v_rlength * sizeof(double));
803         }
804         else {
805             v->v_flags = VF_COMPLEX;
806             v->v_compdata = (complex *)
807                 tmalloc(v->v_rlength * sizeof(complex));
808         }
809         vec_newperm(v);
810         dd->vec = v;
811     }
812 }
813 
814 
815 static void
plotAddRealValue(desc,value,inc)816 plotAddRealValue(desc, value, inc)
817 
818 dataDesc *desc;
819 double value;
820 bool inc;
821 {
822     struct dvec *v = desc->vec;
823 
824     if (isreal(v)) {
825         if (!inc) {
826             v->v_realdata[0] = value;
827             v->v_length = 1;
828             return;
829         }
830         if (v->v_length >= v->v_rlength) {
831             v->v_realdata = (double *) trealloc((char *) v->v_realdata,
832                 sizeof (double) * (v->v_length + 1));
833             v->v_rlength = v->v_length + 1;
834         }
835         v->v_realdata[v->v_length] = value;
836     }
837     else {
838         /* a real parading as a VF_COMPLEX */
839         if (!inc) {
840             v->v_compdata[0].cx_real = value;
841             v->v_compdata[0].cx_imag = (double) 0;
842             v->v_length = 1;
843             return;
844         }
845         if (v->v_length >= v->v_rlength) {
846             v->v_compdata = (complex *) trealloc((char *) v->v_compdata,
847                 sizeof (complex) * (v->v_length + 1));
848             v->v_rlength = v->v_length + 1;
849         }
850         v->v_compdata[v->v_length].cx_real = value;
851         v->v_compdata[v->v_length].cx_imag = (double) 0;
852     }
853     v->v_length++;
854 
855     return;
856 }
857 
858 
859 static void
plotAddComplexValue(desc,value,inc)860 plotAddComplexValue(desc, value, inc)
861 
862 dataDesc *desc;
863 IFcomplex value;
864 bool inc;
865 {
866     struct dvec *v = desc->vec;
867 
868     if (!inc) {
869         v->v_compdata[0].cx_real = value.real;
870         v->v_compdata[0].cx_imag = value.imag;
871         v->v_length = 1;
872         return;
873     }
874     if (v->v_length >= v->v_rlength) {
875         v->v_compdata = (complex *) trealloc((char *) v->v_compdata,
876             sizeof (complex) * (v->v_length + 1));
877         v->v_rlength = v->v_length + 1;
878     }
879     v->v_compdata[v->v_length].cx_real = value.real;
880     v->v_compdata[v->v_length].cx_imag = value.imag;
881     v->v_length++;
882 
883     return;
884 }
885 
886 
887 /* ARGSUSED */ /* until some code gets written */
888 static void
plotEnd(run)889 plotEnd(run)
890 
891 runDesc *run;
892 {
893     return;
894 }
895 
896 
897 /* ParseSpecial takes something of the form "@name[param,index]" and rips
898  * out name, param, and index.
899  */
900 
901 static bool
parseSpecial(name,dev,param,ind)902 parseSpecial(name, dev, param, ind)
903 
904 char *name;
905 char *dev;
906 char *param;
907 char *ind;
908 {
909     char *s;
910 
911     *dev = *param = *ind = '\0';
912 
913     if (*name != '@')
914         return (false);
915     name++;
916 
917     s = dev;
918     while (*name && (*name != '['))
919         *s++ = *name++;
920     *s = '\0';
921     if (!*name)
922         return (true);
923     name++;
924 
925     s = param;
926     while (*name && (*name != ',') && (*name != ']'))
927         *s++ = *name++;
928     *s = '\0';
929     if (*name == ']')
930         return (!name[1] ? true : false);
931     else if (!*name)
932         return (false);
933     name++;
934 
935     s = ind;
936     while (*name && (*name != ']'))
937         *s++ = *name++;
938     *s = '\0';
939     if (*name && !name[1])
940         return (true);
941     else
942         return (false);
943 }
944 
945 
946 /* This routine must match two names with or without a V() around them. */
947 
948 static bool
name_eq(n1,n2)949 name_eq(n1, n2)
950 
951 char *n1, *n2;
952 {
953     char *s;
954 
955     if (!n1 || !n2)
956         return (false);
957     s = strchr(n1,'(');
958     if (s)
959         n1 = s+1;
960     s = strchr(n2,'(');
961     if (s)
962         n2 = s+1;
963 
964     for ( ; ; n1++,n2++) {
965         if ((*n1 == 0 || *n1 == ')') && (*n2 == 0 || *n2 == ')'))
966             return (true);
967         if (*n1 != *n2)
968             break;
969     }
970     return (false);
971 }
972 
973 
974 static bool
getSpecial(desc,run,val)975 getSpecial(desc, run, val)
976 
977 dataDesc *desc;
978 runDesc *run;
979 IFvalue *val;
980 {
981     IFvalue selector;
982     struct variable *vv;
983 
984     selector.iValue = desc->specIndex;
985     if (INPaName(desc->specParamName, val, run->circuit, &desc->specType,
986             desc->specName, &desc->specFast, ft_sim, &desc->type,
987             &selector) == OK) {
988         desc->type &= (IF_REAL | IF_COMPLEX);   /* mask out other bits */
989         return (true);
990     }
991     if (vv = if_getstat(run->circuit, &desc->name[1],
992         (wordlist **)NULL)) {
993             /* skip @ sign */
994         desc->type = IF_REAL;
995         if (vv->va_type == VT_REAL)
996             val->rValue = vv->va_real;
997         else if (vv->va_type == VT_NUM)
998             val->rValue = vv->va_num;
999         else if (vv->va_type == VT_BOOL)
1000             val->rValue = (vv->va_bool ? 1.0 : 0.0);
1001         else {
1002             return (false); /* not a real */
1003         }
1004         tfree(vv);
1005         return (true);
1006     }
1007     return (false);
1008 }
1009 
1010 
1011 static void
freeRun(run)1012 freeRun(run)
1013 
1014 runDesc *run;
1015 {
1016 
1017     int i;
1018 
1019     for (i = 0; i < run->numData; i++) {
1020       txfree(run->data[i].name);
1021       txfree(run->data[i].specParamName);
1022     }
1023     txfree((char*)run->data);
1024     txfree(run->type);
1025     txfree(run->name);
1026     txfree((char*)run);
1027 
1028 }
1029 
1030 
1031 int
OUTstopnow()1032 OUTstopnow()
1033 {
1034     static REQUEST reqst = { checkup_option, 0 };
1035 
1036     if (!ft_batchmode)
1037         DevInput(&reqst, 0);
1038     if (ft_intrpt || shouldstop) {
1039         ft_intrpt = shouldstop = false;
1040         return (1);
1041     }
1042     else
1043         return (0);
1044 }
1045 
1046 
1047 /* Print out error messages. */
1048 
1049 static struct mesg {
1050         char *string;
1051         long flag;
1052 } msgs[] = {
1053         { "Warning", ERR_WARNING } ,
1054         { "Fatal error", ERR_FATAL } ,
1055         { "Panic", ERR_PANIC } ,
1056         { "Note", ERR_INFO } ,
1057         { NULL, 0 }
1058 } ;
1059 
1060 
1061 int
OUTerror(flags,format,names)1062 OUTerror(flags,format,names)
1063 
1064 int flags;
1065 char *format;
1066 IFuid *names;
1067 {
1068 
1069     struct mesg *m;
1070     char buf[BSIZE_SP], *s, *bptr;
1071     int nindex = 0;
1072 
1073     if ((flags == ERR_INFO) && !printinfo)
1074         return (OK);
1075 
1076     for (m = msgs; m->flag; m++)
1077         if (flags & m->flag)
1078             fprintf(cp_err, "%s: ", m->string);
1079 
1080     for (s = format, bptr = buf; *s; s++) {
1081         if (*s == '%' && (s == format || *(s-1) != '%') && *(s+1) == 's') {
1082             strcpy(bptr, names[nindex]);
1083             bptr += strlen(names[nindex]);
1084             s++;
1085             nindex++;
1086         }
1087         else {
1088             *bptr++ = *s;
1089         }
1090     }
1091     *bptr = '\0';
1092     fprintf(cp_err, "%s\n", buf);
1093     fflush(cp_err);
1094     return (OK);
1095 }
1096