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
20static 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 */
34Agrec_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) */
63static 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 */
86void *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(?) */
119static 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 */
132static 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
145int 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
173static void simple_delrec(Agraph_t * g, Agobj_t * obj, void *rec_name)
174{
175 agdelrec(obj, rec_name);
176}
177
178#ifdef OLD
179void 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
198void 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
238void 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
263void 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