| 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 | |
| 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 */ |
| 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) */ |
| 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 | */ |
| 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(?) */ |
| 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 */ |
| 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 | |
| 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 | |
| 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 |
| 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 | |
| 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 | |
| 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 | |
| 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 | |