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: 1987 UCB
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Manage graph data structure.
10  */
11 
12 #include "spice.h"
13 #include "ftegraph.h"
14 #include "ftedebug.h"
15 
16 #ifndef NULL
17 #define NULL ((char*)0)
18 #endif
19 
20 /* invariant:  currentgraph contains the current graph */
21 GRAPH *currentgraph;
22 
23 /* count the number of context switches */
24 int numgraphcxsw;
25 
26 /*
27  *  We use a linked list rather than a circular one because we
28  *    expect few links per list and we don't need to add at the
29  *    end of a list (we can add at the beginning).
30  */
31 
32 /* linked list of graphs */
33 typedef struct listgraph {
34       /* we use GRAPH here instead of a pointer to save a calloc */
35     GRAPH graph;
36     struct listgraph *next;
37 } LISTGRAPH;
38 #define NEWLISTGRAPH (LISTGRAPH *) calloc(1, sizeof(LISTGRAPH))
39 
40 #define NUMGBUCKETS 16
41 
42 typedef struct gbucket {
43     LISTGRAPH *list;
44 } GBUCKET;
45 /* #define NEWGBUCKET (GBUCKET *) calloc(1, sizeof(GBUCKET)) */
46 
47 static GBUCKET GBucket[NUMGBUCKETS];
48 
49 /* note: Zero is not a valid id.  This is used in plot() in graf.c. */
50 static RunningId = 1;
51 
52 /* initialize graph structure */
53 #define SETGRAPH(pgraph, id) (pgraph)->graphid = (id); \
54                                 (pgraph)->degree = 1; \
55                                 (pgraph)->linestyle = -1
56 
57 
58 GRAPH *
NewGraph()59 NewGraph()
60 
61 /* returns NULL on error */
62 {
63 
64     GRAPH *pgraph;
65     LISTGRAPH *list;
66     int BucketId = RunningId % NUMGBUCKETS;
67 
68     if (!(list = NEWLISTGRAPH)) {
69           internalerror("can't allocate a listgraph");
70         return  ((GRAPH *) NULL);
71     }
72 
73     pgraph = &list->graph;
74     SETGRAPH(pgraph, RunningId);
75 
76     if (!GBucket[BucketId].list) {
77         GBucket[BucketId].list = list;
78     }
79     else {
80         /* insert at front of current list */
81         list->next = GBucket[BucketId].list;
82         GBucket[BucketId].list = list;
83     }
84 
85     RunningId++ ;
86 
87     return (pgraph);
88 
89 }
90 
91 
92 GRAPH *
FindGraph(id)93 FindGraph(id)
94 
95 /* Given graph id, return graph */
96 int id;
97 {
98     LISTGRAPH *list;
99 
100     for (list = GBucket[id % NUMGBUCKETS].list;
101             list && list->graph.graphid != id;
102             list = list->next)
103         ;
104 
105     if (list)
106         return (&list->graph);
107     else
108         return (NULL);
109 }
110 
111 
112 GRAPH *
CopyGraph(graph)113 CopyGraph(graph)
114 
115 GRAPH *graph;
116 {
117     GRAPH *ret;
118     struct _keyed *k;
119 
120     ret = NewGraph();
121     bcopy(graph, ret, sizeof(struct graph));
122 
123     ret->graphid = RunningId - 1;   /* restore id */
124 
125     /* copy keyed */
126     for (ret->keyed = NULL, k = graph->keyed; k; k = k->next) {
127         SaveText(ret, k->text, k->x, k->y);
128     }
129     ret->plotdata = (GRDATA)NULL;
130     if (graph->copydata)
131         ret->plotdata = (*graph->copydata)((GRDATA)graph->plotdata);
132 
133     ret->commandline = copy(graph->commandline);
134     ret->plotname = copy(graph->plotname);
135 
136     return (ret);
137 }
138 
139 
140 int
DestroyGraph(id)141 DestroyGraph(id)
142 
143 int id;
144 {
145 
146     LISTGRAPH *list, *lastlist;
147     struct _keyed *k, *nextk;
148     extern struct dbcomm *dbiplot;
149     struct dbcomm *db;
150 
151     list = GBucket[id % NUMGBUCKETS].list;
152     lastlist = NULL;
153 
154     while (list) {
155         if (list->graph.graphid == id) {  /* found it */
156 
157             /* Fix the iplot/trace dbiplot list */
158             for (db = dbiplot;
159                 db && db->db_graphid != id; db = db->db_next) ;
160 
161             if (db && db->db_type == DB_IPLOT) {
162                 db->db_type = DB_DEADIPLOT;
163                 /* Delete this later */
164                 return (0);
165             }
166 
167             /* adjust bucket pointers */
168             if (lastlist) {
169                 lastlist->next = list->next;
170             }
171             else {
172                 GBucket[id % NUMGBUCKETS].list = list->next;
173             }
174 
175             /* run through and de-allocate dynamically allocated keyed list */
176             k = list->graph.keyed;
177             while (k) {
178                 nextk = k->next;
179                 txfree(k->text);
180                 txfree((char*)k);
181                 k = nextk;
182             }
183 
184             if (list->graph.destroy)
185                 (*list->graph.destroy)((GRDATA)list->graph.plotdata);
186             list->graph.plotdata = (GRDATA)NULL;
187 
188             tfree(list->graph.commandline);
189             tfree(list->graph.plotname);
190 
191             /* If device dependent space allocated, free it. */
192             if (list->graph.devdep)
193                 txfree(list->graph.devdep);
194             txfree((char*)list);
195 
196             return (1);
197         }
198         lastlist = list;
199         list = list->next;
200     }
201 
202     internalerror("tried to destroy non-existent graph");
203     return (0);
204 }
205 
206 
207 void
FreeGraphs()208 FreeGraphs()
209 
210 /* free up all dynamically allocated data structures */
211 {
212     GBUCKET *gbucket;
213     LISTGRAPH *list, *deadl;
214 
215     for (gbucket = GBucket; gbucket < &GBucket[NUMGBUCKETS]; gbucket++) {
216         list = gbucket->list;
217         while (list) {
218             deadl = list;
219             list = list->next;
220             txfree((char*)deadl);
221         }
222     }
223 }
224 
225 
226 void
SetGraphContext(graphid)227 SetGraphContext(graphid)
228 
229 int graphid;
230 {
231     currentgraph = FindGraph(graphid);
232 }
233 
234 
235 typedef struct gcstack {
236     GRAPH *pgraph;
237     struct gcstack *next;
238 } GCSTACK;
239 GCSTACK *gcstacktop;
240 #define NEWGCSTACK (GCSTACK *) calloc(1, sizeof(GCSTACK))
241 
242 
243 /* note: This Push and Pop has tricky semantics.
244  *   Push(graph) will push the currentgraph onto the stack
245  *       and set currentgraph to graph.
246  *   Pop() simply sets currentgraph to the top of the stack and pops stack.
247  */
248 
249 void
PushGraphContext(graph)250 PushGraphContext(graph)
251 
252 GRAPH *graph;
253 {
254     GCSTACK *gcstack = NEWGCSTACK;
255 
256     if (!gcstacktop) {
257         gcstacktop = gcstack;
258     }
259     else {
260         gcstack->next = gcstacktop;
261         gcstacktop = gcstack;
262     }
263     gcstacktop->pgraph = currentgraph;
264     currentgraph = graph;
265     numgraphcxsw++;
266 }
267 
268 
269 void
PopGraphContext()270 PopGraphContext()
271 
272 {
273     GCSTACK *dead;
274 
275     currentgraph = gcstacktop->pgraph;
276     dead = gcstacktop;
277     gcstacktop = gcstacktop->next;
278     txfree((char*)dead);
279     numgraphcxsw++;
280 }
281