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