00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <limits.h>
00018
00019 #include "libgraph.h"
00020
00021 #ifdef DMALLOC
00022 #include "dmalloc.h"
00023 #endif
00024
00025 Dtdisc_t agNamedisc = {
00026 offsetof(Agnode_t, name),
00027 -1,
00028 -1,
00029 NIL(Dtmake_f),
00030 NIL(Dtfree_f),
00031 NIL(Dtcompar_f),
00032 NIL(Dthash_f),
00033 NIL(Dtmemory_f),
00034 NIL(Dtevent_f)
00035 };
00036
00037 Dtdisc_t agNodedisc = {
00038 offsetof(Agnode_t, id),
00039 sizeof(int),
00040 -1,
00041 NIL(Dtmake_f),
00042 NIL(Dtfree_f),
00043 (Dtcompar_f) agcmpid,
00044 NIL(Dthash_f),
00045 NIL(Dtmemory_f),
00046 NIL(Dtevent_f)
00047 };
00048
00049 Dtdisc_t agIndisc = {
00050 0,
00051 0,
00052 -1,
00053 NIL(Dtmake_f),
00054 NIL(Dtfree_f),
00055 (Dtcompar_f) agcmpin,
00056 NIL(Dthash_f),
00057 NIL(Dtmemory_f),
00058 NIL(Dtevent_f)
00059 };
00060
00061 Dtdisc_t agOutdisc = {
00062 0,
00063 0,
00064 -1,
00065 (Dtmake_f) 0,
00066 (Dtfree_f) 0,
00067 (Dtcompar_f) agcmpout,
00068 (Dthash_f) 0,
00069 (Dtmemory_f) 0,
00070 (Dtevent_f) 0
00071 };
00072
00073 int agcmpid(Dt_t * dict, int *id0, int *id1, Dtdisc_t * disc)
00074 {
00075 return (*id0) - *(id1);
00076 }
00077
00078 #ifdef DEBUG
00079 static int myinedgecmp(e0, e1)
00080 Agedge_t *e0, *e1;
00081 {
00082 int rv = myinedgecmp(e0, e1);
00083 printf("compare (%s,%s:%s),(%s,%s:%s) = %d\n",
00084 e0->head ? e0->head->name : "nil",
00085 e0->tail ? e0->tail->name : "nil",
00086 e0->attr && e0->attr[KEYX]? e0->attr[KEYX] : "nil",
00087 e1->head ? e1->head->name : "nil",
00088 e1->tail ? e1->tail->name : "nil",
00089 e1->attr && e1->attr[KEYX]? e1->attr[KEYX] : "nil",
00090 rv);
00091 return rv;
00092 }
00093 #endif
00094
00095 static int keycmp(Agedge_t * e0, Agedge_t * e1)
00096 {
00097 char *key0, *key1;
00098 key0 = e0->attr ? e0->attr[KEYX] : NULL;
00099 key1 = e1->attr ? e1->attr[KEYX] : NULL;
00100 if (key0 == NULL)
00101 return (key1 ? -1 : 0);
00102 if (key1 == NULL)
00103 return 1;
00104 return strcmp(key0, key1);
00105 }
00106
00107 int agcmpin(Dict_t * d, Agedge_t * e0, Agedge_t * e1, Dtdisc_t * disc)
00108 {
00109 int e0tailid, e0headid, e1tailid, e1headid;
00110
00111 e0tailid = e0->tail ? e0->tail->id : -1;
00112 e0headid = e0->head ? e0->head->id : -1;
00113 e1tailid = e1->tail ? e1->tail->id : -1;
00114 e1headid = e1->head ? e1->head->id : -1;
00115
00116 if (e0headid != e1headid)
00117 return e0headid - e1headid;
00118 if (e0tailid != e1tailid)
00119 return e0tailid - e1tailid;
00120 return keycmp(e0, e1);
00121 }
00122
00123 int agcmpout(Dict_t * d, Agedge_t * e0, Agedge_t * e1, Dtdisc_t * disc)
00124 {
00125 int e0tailid, e0headid, e1tailid, e1headid;
00126
00127 e0tailid = e0->tail ? e0->tail->id : -1;
00128 e0headid = e0->head ? e0->head->id : -1;
00129 e1tailid = e1->tail ? e1->tail->id : -1;
00130 e1headid = e1->head ? e1->head->id : -1;
00131
00132 if (e0tailid != e1tailid)
00133 return e0tailid - e1tailid;
00134 if (e0headid != e1headid)
00135 return e0headid - e1headid;
00136 return keycmp(e0, e1);
00137 }
00138
00139 static Agdata_t *agnewdata(void)
00140 {
00141 Agdata_t *rv;
00142
00143 rv = NEW(Agdata_t);
00144 rv->node_dict = dtopen(&agNamedisc, Dttree);
00145 rv->globattr = agNEWdict("graph");
00146 rv->nodeattr = agNEWdict("node");
00147 rv->edgeattr = agNEWdict("edge");
00148 if (AG.proto_g) {
00149 agcopydict(rv->globattr, AG.proto_g->univ->globattr);
00150 agcopydict(rv->nodeattr, AG.proto_g->univ->nodeattr);
00151 agcopydict(rv->edgeattr, AG.proto_g->univ->edgeattr);
00152 }
00153 return rv;
00154 }
00155
00156 static void agfreedata(Agraph_t * g)
00157 {
00158 agFREEdict(g, g->univ->globattr);
00159 agFREEdict(g, g->univ->nodeattr);
00160 agFREEdict(g, g->univ->edgeattr);
00161 dtclose(g->univ->node_dict);
00162 free(g->univ);
00163 }
00164
00165 static void dup_proto(Agraph_t * g, Agproto_t * proto)
00166 {
00167 Agnode_t *n = NULL;
00168 Agedge_t *e = NULL;
00169 Agproto_t *s = NEW(Agproto_t);
00170
00171 s->prev = g->proto;
00172 if (proto) {
00173 n = proto->n;
00174 e = proto->e;
00175 }
00176 s->n = agNEWnode(g, "\001proto", n);
00177 s->e = agNEWedge(g, s->n, s->n, e);
00178 g->proto = s;
00179 }
00180
00181 void agpushproto(Agraph_t * g)
00182 {
00183 dup_proto(g, g->proto);
00184 }
00185
00186 void agpopproto(Agraph_t * g)
00187 {
00188 Agproto_t *s = g->proto;
00189 if (s != NULL) {
00190 g->proto = s->prev;
00191 s->e->tail = s->e->head = s->n;
00192 agFREEedge(s->e);
00193 agFREEnode(s->n);
00194 free(s);
00195 }
00196 }
00197
00198 static Agraph_t *agNEWgraph(char *name, Agraph_t * parent, int kind)
00199 {
00200 int i, nobj;
00201 Agraph_t *g;
00202
00203 if (AG.init_called == FALSE) {
00204 agerr(AGERR, "libag error -- aginit() was not called\n");
00205 return 0;
00206 }
00207 g = (Agraph_t *) calloc(1, AG.graph_nbytes);
00208 g->tag = TAG_GRAPH;
00209 g->kind = kind;
00210 g->nodes = dtopen(&agNodedisc, Dttree);
00211 g->inedges = dtopen(&agIndisc, Dttree);
00212 g->outedges = dtopen(&agOutdisc, Dttree);
00213
00214 if (parent == NULL) {
00215 g->univ = agnewdata();
00216 g->root = g;
00217 nobj = dtsize(g->univ->globattr->dict);
00218 if (nobj) {
00219 g->attr = N_NEW(nobj, char *);
00220 g->didset = N_NEW((nobj + CHAR_BIT - 1) / CHAR_BIT, char);
00221 }
00222 else {
00223 g->attr = NULL;
00224 g->didset = NULL;
00225 }
00226 for (i = 0; i < nobj; i++)
00227 g->attr[i] = agstrdup(AG.proto_g->attr[i]);
00228 } else {
00229 g->univ = parent->univ;
00230 g->root = parent->root;
00231 nobj = dtsize(parent->univ->globattr->dict);
00232 if (nobj) {
00233 g->attr = N_NEW(nobj, char *);
00234 g->didset = N_NEW((nobj + CHAR_BIT - 1) / CHAR_BIT, char);
00235 }
00236 else {
00237 g->attr = NULL;
00238 g->didset = NULL;
00239 }
00240 for (i = 0; i < nobj; i++)
00241 g->attr[i] = agstrdup(parent->attr[i]);
00242
00243 }
00244
00245 g->meta_node = NULL;
00246 g->name = agstrdup(name);
00247 g->proto = NULL;
00248
00249 if (parent)
00250 dup_proto(g, parent->proto);
00251 else
00252 agpushproto(g);
00253 return g;
00254 }
00255
00256 static int reach0(Dict_t * m, Agnode_t * from, Agnode_t * to)
00257 {
00258 Agedge_t *e;
00259
00260 if (from == to)
00261 return TRUE;
00262 if (agfindedge(from->graph->root, from, to))
00263 return TRUE;
00264 dtinsert(m, from);
00265 for (e = agfstout(from->graph, from); e; e = agnxtout(from->graph, e))
00266 if ((dtsearch(m, e->head) == NULL) && reach0(m, e->head, to))
00267 return TRUE;
00268 return FALSE;
00269 }
00270
00271 static int reach(Agnode_t * from, Agnode_t * to)
00272 {
00273 Dict_t *m;
00274 int rv;
00275
00276 m = dtopen(&agNodedisc, Dttree);
00277 rv = reach0(m, from, to);
00278 dtclose(m);
00279 return rv;
00280 }
00281
00282 Agraph_t *agusergraph(Agnode_t * n)
00283 {
00284 return (n->graph->meta_node ? NULL : (Agraph_t *) (n->attr[0]));
00285 }
00286
00287 Agraph_t *agopen(char *name, int kind)
00288 {
00289 Agraph_t *g, *meta;
00290
00291 g = agNEWgraph(name, NULL, kind);
00292 meta = agNEWgraph(name, NULL, AGMETAGRAPH);
00293 if (!g || !meta)
00294 return 0;
00295 agnodeattr(meta, "agusergraph", NULL);
00296 g->meta_node = agnode(meta, name);
00297 g->meta_node->attr[0] = (char *) g;
00298 return g;
00299 }
00300
00301 Agraph_t *agsubg(Agraph_t * g, char *name)
00302 {
00303 Agraph_t *subg, *meta;
00304 Agnode_t *n;
00305
00306 meta = g->meta_node->graph;
00307 n = agfindnode(meta, name);
00308 if (n)
00309 subg = agusergraph(n);
00310 else {
00311 subg = agNEWgraph(name, g, g->kind);
00312 if (!subg)
00313 return 0;
00314 n = agnode(meta, name);
00315 subg->meta_node = n;
00316 n->attr[0] = (char *) subg;
00317 }
00318 agINSgraph(g, subg);
00319 return subg;
00320 }
00321
00322 Agraph_t *agfindsubg(Agraph_t * g, char *name)
00323 {
00324 Agnode_t *n;
00325
00326 if (g->meta_node) {
00327 n = agfindnode(g->meta_node->graph, name);
00328 if (n)
00329 return agusergraph(n);
00330 }
00331 return NULL;
00332 }
00333
00334 void agINSgraph(Agraph_t * g, Agraph_t * subg)
00335 {
00336 Agnode_t *h, *t;
00337 t = g->meta_node;
00338 h = subg->meta_node;
00339 if (t && h && (reach(h, t) == FALSE))
00340 agedge(t->graph, t, h);
00341 }
00342
00343 void agclose(Agraph_t * g)
00344 {
00345 Agedge_t *e, *f;
00346 Agnode_t *n, *nn;
00347 Agraph_t *meta = NULL;
00348 int i, nobj, flag, is_meta;
00349
00350 if ((g == NULL) || (TAG_OF(g) != TAG_GRAPH))
00351 return;
00352 is_meta = AG_IS_METAGRAPH(g);
00353 if (is_meta == FALSE) {
00354 meta = g->meta_node->graph;
00355
00356 do {
00357 flag = FALSE;
00358 for (e = agfstout(meta, g->meta_node); e; e = f) {
00359 f = agnxtout(meta, e);
00360 if (agnxtin(meta, agfstin(meta, e->head)) == NULL) {
00361 agclose(agusergraph(e->head));
00362 flag = TRUE;
00363 }
00364 }
00365 } while (flag);
00366 }
00367 while (g->proto)
00368 agpopproto(g);
00369 if (is_meta == FALSE) {
00370 nobj = dtsize(g->univ->globattr->dict);
00371 for (i = 0; i < nobj; i++)
00372 agstrfree(g->attr[i]);
00373 }
00374 if (g->attr)
00375 free(g->attr);
00376 if (g->didset)
00377 free(g->didset);
00378 if (g == g->root) {
00379 for (n = agfstnode(g); n; n = nn) {
00380 nn = agnxtnode(g, n);
00381 agDELnode(g, n);
00382 }
00383 if (is_meta == FALSE)
00384 agclose(g->meta_node->graph);
00385 agfreedata(g);
00386 } else {
00387 if (is_meta == FALSE)
00388 agdelete(meta, g->meta_node);
00389 }
00390 dtclose(g->nodes);
00391 dtclose(g->inedges);
00392 dtclose(g->outedges);
00393 agstrfree(g->name);
00394 TAG_OF(g) = -1;
00395 free(g);
00396 }
00397
00398 int agcontains(Agraph_t * g, void *obj)
00399 {
00400 switch (TAG_OF(obj)) {
00401 case TAG_NODE:
00402 return (agidnode(g, ((Agnode_t *) obj)->id) != NULL);
00403 case TAG_EDGE:
00404 return (dtsearch(g->inedges, (Agedge_t *) obj) != NULL);
00405 case TAG_GRAPH:
00406 return (reach(g->meta_node, ((Agraph_t *) obj)->meta_node));
00407 }
00408 return FALSE;
00409 }
00410
00411 void aginsert(Agraph_t * g, void *obj)
00412 {
00413 switch (TAG_OF(obj)) {
00414 case TAG_NODE:
00415 agINSnode(g, obj);
00416 break;
00417 case TAG_EDGE:
00418 agINSedge(g, obj);
00419 break;
00420 case TAG_GRAPH:
00421 agINSgraph(g, obj);
00422 break;
00423 }
00424 }
00425
00426 void agdelete(Agraph_t * g, void *obj)
00427 {
00428 switch (TAG_OF(obj)) {
00429 case TAG_NODE:
00430 agDELnode(g, obj);
00431 break;
00432 case TAG_EDGE:
00433 agDELedge(g, obj);
00434 break;
00435 case TAG_GRAPH:
00436 agclose(obj);
00437 break;
00438 }
00439 }
00440
00441 int agnnodes(Agraph_t * g)
00442 {
00443 return dtsize(g->nodes);
00444 }
00445
00446 int agnedges(Agraph_t * g)
00447 {
00448 return dtsize(g->outedges);
00449 }