From b8a2b120be948cfec50d0cd7eb65d254f4bec94a Mon Sep 17 00:00:00 2001 From: Emden Gansner Date: Fri, 11 Nov 2011 14:34:26 -0500 Subject: [PATCH] Similar fix that we did for dot: cgraph does not have a flat namespace for subgraphs, so we need to construct an explicit map from name to cluster. Pulled out the code we used in dot and moved it to utils.c. --- lib/common/utils.c | 89 ++++++++++++++++++++++++++++++++++++++++++- lib/common/utils.h | 2 + lib/dotgen/compound.c | 80 +++++--------------------------------- 3 files changed, 99 insertions(+), 72 deletions(-) diff --git a/lib/common/utils.c b/lib/common/utils.c index 4ff6bdc2c..966d97a12 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -1137,11 +1137,17 @@ static item *mapEdge(Dt_t * map, edge_t * e) #ifndef WITH_CGRAPH #define MAPC(n) (strncmp((n)->name,"cluster",7)?NULL:agfindsubg((n)->graph, (n)->name)) #else /* WITH_CGRAPH */ -#define MAPC(n) (strncmp(agnameof(n),"cluster",7)?NULL:agsubg(agraphof(n), agnameof(n),0)) +#define MAPC(n) (strncmp(agnameof(n),"cluster",7)?NULL:findCluster(cmap,agnameof(n))) #endif /* WITH_CGRAPH */ + +#ifdef WITH_CGRAPH +static void +checkCompound(edge_t * e, graph_t * clg, agxbuf * xb, Dt_t * map, Dt_t* cmap) +#else static void checkCompound(edge_t * e, graph_t * clg, agxbuf * xb, Dt_t * map) +#endif { graph_t *tg; graph_t *hg; @@ -1221,6 +1227,9 @@ int processClusterEdges(graph_t * g) graph_t *clg; agxbuf xb; Dt_t *map; +#ifdef WITH_CGRAPH + Dt_t *cmap = mkClustMap (g); +#endif unsigned char buf[SMALLBUF]; map = dtopen(&mapDisc, Dtoset); @@ -1234,7 +1243,11 @@ int processClusterEdges(graph_t * g) for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (IS_CLUST_NODE(n)) continue; for (e = agfstout(g, n); e; e = agnxtout(g, e)) { +#ifndef WITH_CGRAPH checkCompound(e, clg, &xb, map); +#else + checkCompound(e, clg, &xb, map, cmap); +#endif } } agxbfree(&xb); @@ -1247,6 +1260,9 @@ int processClusterEdges(graph_t * g) agclose(clg); if (rv) SET_CLUST_EDGE(g); +#ifdef WITH_CGRAPH + dtclose(cmap); +#endif return rv; } @@ -1947,3 +1963,74 @@ double drand48(void) return d; } #endif +#ifdef WITH_CGRAPH +typedef struct { + Dtlink_t link; + char* name; + Agraph_t* clp; +} clust_t; + +static void free_clust (Dt_t* dt, clust_t* clp, Dtdisc_t* disc) +{ + free (clp); +} + +static Dtdisc_t strDisc = { + offsetof(clust_t,name), + -1, + offsetof(clust_t,link), + NIL(Dtmake_f), + (Dtfree_f)free_clust, + NIL(Dtcompar_f), + NIL(Dthash_f), + NIL(Dtmemory_f), + NIL(Dtevent_f) +}; + +static void fillMap (Agraph_t* g, Dt_t* map) +{ + Agraph_t* cl; + int c; + char* s; + clust_t* ip; + + for (c = 1; c <= GD_n_cluster(g); c++) { + cl = GD_clust(g)[c]; + s = agnameof(cl); + if (dtmatch (map, &s)) { + agerr(AGWARN, "Two clusters named %s - the second will be ignored\n", s); + } + else { + ip = NEW(clust_t); + ip->name = s; + ip->clp = cl; + dtinsert (map, ip); + } + fillMap (cl, map); + } +} + +/* mkClustMap: + * Generates a dictionary mapping cluster names to corresponding cluster. + * Used with cgraph as the latter does not support a flat namespace of clusters. + * Assumes G has already built a cluster tree using GD_n_cluster and GD_clust. + */ +Dt_t* mkClustMap (Agraph_t* g) +{ + Dt_t* map = dtopen (&strDisc, Dtoset); + + fillMap (g, map); + + return map; +} + +Agraph_t* +findCluster (Dt_t* map, char* name) +{ + clust_t* clp = dtmatch (map, name); + if (clp) + return clp->clp; + else + return NULL; +} +#endif diff --git a/lib/common/utils.h b/lib/common/utils.h index 28368a987..b922b4a56 100644 --- a/lib/common/utils.h +++ b/lib/common/utils.h @@ -60,6 +60,8 @@ extern "C" { extern attrsym_t* safe_dcl(graph_t*, void*, char*, char*, attrsym_t * (*fun) (Agraph_t *, char *, char *)); #else + extern Dt_t* mkClustMap (Agraph_t* g); + extern Agraph_t* findCluster (Dt_t* map, char* name); extern attrsym_t* safe_dcl(graph_t * g, int obj_kind, char *name, char *def); #endif diff --git a/lib/dotgen/compound.c b/lib/dotgen/compound.c index d42656675..25d659aac 100644 --- a/lib/dotgen/compound.c +++ b/lib/dotgen/compound.c @@ -88,93 +88,31 @@ static int inBoxf(pointf p, boxf * bb) return INSIDE(p, *bb); } -#ifdef WITH_CGRAPH -typedef struct { - Dtlink_t link; - char* name; - Agraph_t* clp; -} clust_t; - -static void free_clust (Dt_t* dt, clust_t* clp, Dtdisc_t* disc) -{ - free (clp); -} - -static Dtdisc_t strDisc = { - offsetof(clust_t,name), - -1, - offsetof(clust_t,link), - NIL(Dtmake_f), - (Dtfree_f)free_clust, - NIL(Dtcompar_f), - NIL(Dthash_f), - NIL(Dtmemory_f), - NIL(Dtevent_f) -}; - -static void fillMap (Agraph_t* g, Dt_t* map) -{ - Agraph_t* cl; - int c; - char* s; - clust_t* ip; - - for (c = 1; c <= GD_n_cluster(g); c++) { - cl = GD_clust(g)[c]; - s = agnameof(cl); - if (dtmatch (map, &s)) { - agerr(AGWARN, "Two clusters named %s - the second will be ignored\n", s); - } - else { - ip = NEW(clust_t); - ip->name = s; - ip->clp = cl; - dtinsert (map, ip); - } - fillMap (cl, map); - } -} - -static Dt_t* mkClustMap (Agraph_t* g) -{ - Dt_t* map = dtopen (&strDisc, Dtoset); - - fillMap (g, map); - - return map; -} - /* getCluster: * Returns subgraph of g with given name. * Returns NULL if no name is given, or subgraph of * that name does not exist. */ +#ifdef WITH_CGRAPH static graph_t *getCluster(graph_t * g, char *cluster_name, Dt_t* map) -{ - clust_t* clp; - - if (!cluster_name || (*cluster_name == '\0')) - return NULL; - clp = dtmatch (map, cluster_name); - if (clp == NULL) { - agerr(AGWARN, "cluster named %s not found\n", cluster_name); - return NULL; - } - else return clp->clp; -} #else static graph_t *getCluster(graph_t * g, char *cluster_name) +#endif { - graph_t *sg; + Agraph_t* sg; if (!cluster_name || (*cluster_name == '\0')) return NULL; +#ifdef WITH_CGRAPH + sg = findCluster (map, cluster_name); +#else sg = agfindsubg(g, cluster_name); - if (sg == NULL) +#endif + if (sg == NULL) { agerr(AGWARN, "cluster named %s not found\n", cluster_name); + } return sg; } -#endif /* The following functions are derived from pp. 411-415 (pp. 791-795) * of Graphics Gems. In the code there, they use a SGN function to -- 2.40.0