1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 #include <cghdr.h>
15
16 /*
17 * run time records
18 */
19
set_data(Agobj_t * obj,Agrec_t * data,int mtflock)20 static void set_data(Agobj_t * obj, Agrec_t * data, int mtflock)
21 {
22 Agedge_t *e;
23
24 obj->data = data;
25 obj->tag.mtflock = mtflock;
26 if ((AGTYPE(obj) == AGINEDGE) || (AGTYPE(obj) == AGOUTEDGE)) {
27 e = agopp((Agedge_t *) obj);
28 AGDATA(e) = data;
29 e->base.tag.mtflock = mtflock;
30 }
31 }
32
33 /* find record in circular list and do optional move-to-front */
aggetrec(void * obj,char * name,int mtf)34 Agrec_t *aggetrec(void *obj, char *name, int mtf)
35 {
36 Agobj_t *hdr;
37 Agrec_t *d, *first;
38
39 hdr = (Agobj_t *) obj;
40 first = d = hdr->data;
41 while (d) {
42 if ((d->name == name) || streq(name, d->name))
43 break;
44 d = d->next;
45 if (d == first) {
46 d = NIL(Agrec_t *);
47 break;
48 }
49 }
50 if (d) {
51 if (hdr->tag.mtflock) {
52 if (mtf && (hdr->data != d))
53 agerr(AGERR, "move to front lock inconsistency");
54 } else {
55 if ((d != first) || (mtf != hdr->tag.mtflock))
56 set_data(hdr, d, mtf); /* Always optimize */
57 }
58 }
59 return d;
60 }
61
62 /* insert the record in data list of this object (only) */
objputrec(Agraph_t * g,Agobj_t * obj,void * arg)63 static void objputrec(Agraph_t * g, Agobj_t * obj, void *arg)
64 {
65 Agrec_t *firstrec, *newrec;
66
67 newrec = arg;
68 firstrec = obj->data;
69 if (firstrec == NIL(Agrec_t *))
70 newrec->next = newrec; /* 0 elts */
71 else {
72 if (firstrec->next == firstrec) {
73 firstrec->next = newrec; /* 1 elt */
74 newrec->next = firstrec;
75 } else {
76 newrec->next = firstrec->next;
77 firstrec->next = newrec;
78 }
79 }
80 if (NOT(obj->tag.mtflock))
81 set_data(obj, newrec, FALSE);
82 }
83
84 /* attach a new record of the given size to the object.
85 */
agbindrec(void * arg_obj,char * recname,unsigned int recsize,int mtf)86 void *agbindrec(void *arg_obj, char *recname, unsigned int recsize,
87 int mtf)
88 {
89 Agraph_t *g;
90 Agobj_t *obj;
91 Agrec_t *rec;
92
93 obj = (Agobj_t *) arg_obj;
94 g = agraphof(obj);
95 rec = aggetrec(obj, recname, FALSE);
96 if ((rec == NIL(Agrec_t *)) && (recsize > 0)) {
97 rec = (Agrec_t *) agalloc(g, recsize);
98 rec->name = agstrdup(g, recname);
99 switch (obj->tag.objtype) {
100 case AGRAPH:
101 objputrec(g, obj, rec);
102 break;
103 case AGNODE:
104 objputrec(g, obj, rec);
105 break;
106 case AGINEDGE:
107 case AGOUTEDGE:
108 objputrec(g, obj, rec);
109 break;
110 }
111 }
112 if (mtf)
113 aggetrec(arg_obj, recname, TRUE);
114 return (void *) rec;
115 }
116
117
118 /* if obj points to rec, move its data pointer. break any mtf lock(?) */
objdelrec(Agraph_t * g,Agobj_t * obj,void * arg_rec)119 static void objdelrec(Agraph_t * g, Agobj_t * obj, void *arg_rec)
120 {
121 Agrec_t *rec = (Agrec_t *) arg_rec, *newrec;
122 if (obj->data == rec) {
123 if (rec->next == rec)
124 newrec = NIL(Agrec_t *);
125 else
126 newrec = rec->next;
127 set_data(obj, newrec, FALSE);
128 }
129 }
130
131 /* delete a record from a circular data list */
listdelrec(Agobj_t * obj,Agrec_t * rec)132 static void listdelrec(Agobj_t * obj, Agrec_t * rec)
133 {
134 Agrec_t *prev;
135
136 prev = obj->data;
137 while (prev->next != rec) {
138 prev = prev->next;
139 assert(prev != obj->data);
140 }
141 /* following is a harmless no-op if the list is trivial */
142 prev->next = rec->next;
143 }
144
agdelrec(void * arg_obj,char * name)145 int agdelrec(void *arg_obj, char *name)
146 {
147 Agobj_t *obj;
148 Agrec_t *rec;
149 Agraph_t *g;
150
151 obj = (Agobj_t *) arg_obj;
152 g = agraphof(obj);
153 rec = aggetrec(obj, name, FALSE);
154 if (rec) {
155 listdelrec(obj, rec); /* zap it from the circular list */
156 switch (obj->tag.objtype) { /* refresh any stale pointers */
157 case AGRAPH:
158 objdelrec(g, obj, rec);
159 break;
160 case AGNODE:
161 case AGINEDGE:
162 case AGOUTEDGE:
163 agapply(agroot(g), obj, objdelrec, rec, FALSE);
164 break;
165 }
166 agstrfree(g, rec->name);
167 agfree(g, rec);
168 return SUCCESS;
169 } else
170 return FAILURE;
171 }
172
simple_delrec(Agraph_t * g,Agobj_t * obj,void * rec_name)173 static void simple_delrec(Agraph_t * g, Agobj_t * obj, void *rec_name)
174 {
175 agdelrec(obj, rec_name);
176 }
177
178 #ifdef OLD
agclean(Agraph_t * g,char * graphdata,char * nodedata,char * edgedata)179 void agclean(Agraph_t * g, char *graphdata, char *nodedata, char *edgedata)
180 {
181 Agnode_t *n;
182 Agedge_t *e;
183
184 if (nodedata || edgedata) {
185 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
186 if (edgedata)
187 for (e = agfstout(n); e; e = agnxtout(g, e)) {
188 agdelrec(e, edgedata);
189 }
190 if (nodedata)
191 agdelrec(n, nodedata);
192 }
193 }
194 agdelrec(g, graphdata);
195 }
196 #endif
197
aginit(Agraph_t * g,int kind,char * rec_name,int arg_rec_size,int mtf)198 void aginit(Agraph_t * g, int kind, char *rec_name, int arg_rec_size, int mtf)
199 {
200 Agnode_t *n;
201 Agedge_t *e;
202 Agraph_t *s;
203 unsigned int rec_size;
204 int recur; /* if recursive on subgraphs */
205
206 if (arg_rec_size < 0)
207 {
208 recur = 1;
209 }
210 else
211 {
212 recur = 0;
213 }
214 rec_size = (unsigned int) abs(arg_rec_size);
215 switch (kind) {
216 case AGRAPH:
217 agbindrec(g, rec_name, rec_size, mtf);
218 if (recur)
219 for (s = agfstsubg(g); s; s = agnxtsubg(s))
220 aginit(s,kind,rec_name,arg_rec_size,mtf);
221 break;
222 case AGNODE:
223 case AGOUTEDGE:
224 case AGINEDGE:
225 for (n = agfstnode(g); n; n = agnxtnode(g, n))
226 if (kind == AGNODE)
227 agbindrec(n, rec_name, rec_size, mtf);
228 else {
229 for (e = agfstout(g, n); e; e = agnxtout(g, e))
230 agbindrec(e, rec_name, rec_size, mtf);
231 }
232 break;
233 default:
234 break;
235 }
236 }
237
agclean(Agraph_t * g,int kind,char * rec_name)238 void agclean(Agraph_t * g, int kind, char *rec_name)
239 {
240 Agnode_t *n;
241 Agedge_t *e;
242
243 switch (kind) {
244 case AGRAPH:
245 agapply(g, (Agobj_t *) g, simple_delrec, rec_name, TRUE);
246 break;
247 case AGNODE:
248 case AGOUTEDGE:
249 case AGINEDGE:
250 for (n = agfstnode(g); n; n = agnxtnode(g, n))
251 if (kind == AGNODE)
252 agdelrec(n, rec_name);
253 else {
254 for (e = agfstout(g, n); e; e = agnxtout(g, e))
255 agdelrec(e, rec_name);
256 }
257 break;
258 default:
259 break;
260 }
261 }
262
agrecclose(Agobj_t * obj)263 void agrecclose(Agobj_t * obj)
264 {
265 Agraph_t *g;
266 Agrec_t *rec, *nrec;
267
268 g = agraphof(obj);
269 if ((rec = obj->data)) {
270 do {
271 nrec = rec->next;
272 agstrfree(g, rec->name);
273 agfree(g, rec);
274 rec = nrec;
275 } while (rec != obj->data);
276 }
277 obj->data = NIL(Agrec_t *);
278 }
279