/* This software may only be used by you under license from AT&T Corp. ("AT&T"). A copy of AT&T's Source Code Agreement is available at AT&T's Internet website having the URL: If you received this software without first entering into a license with AT&T, you have an infringing copy of this software and cannot use it without violating AT&T's intellectual property rights. */ #pragma prototyped #include #include #define MARKED(n) ((n)->u.mark) #define MARK(n) ((n)->u.mark = 1) #define UNMARK(n) ((n)->u.mark = 0) typedef void (*dfsfn)(Agnode_t*, void*); static void dfs(Agraph_t* g, Agnode_t* n, dfsfn action, void* state) { Agedge_t *e; Agnode_t *other; MARK(n); action(n, state); for (e = agfstedge(g,n); e ; e = agnxtedge(g,e,n)) { if ((other = e->tail) == n) other = e->head; if (!MARKED(other)) dfs(g,other,action,state); } } static int isLegal (char* p) { char c; while ((c = *p++)) { if ((c != '_') && !isalnum(c)) return 0; } return 1; } /* insertFn: */ static void insertFn (Agnode_t* n, void* state) { aginsert((Agraph_t*)state,n); } /* pccomps: * Return an array of subgraphs consisting of the connected * components of graph g. The number of components is returned in ncc. * All pinned nodes are in one component. * If pfx is non-null and a legal graph name, we use it as the prefix * for the name of the subgraphs created. If not, a simple default is used. * If pinned is non-null, *pinned set to 1 if pinned nodes found * and the first component is the one containing the pinned nodes. * Note that the component subgraphs do not contain any edges. These must * be obtained from the root graph. */ Agraph_t** pccomps (Agraph_t* g, int* ncc, char* pfx, boolean* pinned) { int c_cnt = 0; char buffer[SMALLBUF]; char* name; Agraph_t* out = 0; Agnode_t* n; Agraph_t** ccs; int len; int bnd = 10; boolean pin = FALSE; if (!pfx || !isLegal(pfx)) { pfx = "_cc_"; } len = strlen (pfx); if (len + 25 <= SMALLBUF) name = buffer; else name = (char*)gmalloc(len+25); strcpy (name, pfx); for (n = agfstnode(g); n; n = agnxtnode(g,n)) UNMARK(n); ccs = N_GNEW(bnd,Agraph_t*); /* Component with pinned nodes */ for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (MARKED(n) || !ND_pinned(n)) continue; if (!out) { sprintf(name+len,"%d",c_cnt); out = agsubg(g,name); ccs[c_cnt] = out; c_cnt++; pin = TRUE; } dfs(g,n,insertFn,out); } /* Remaining nodes */ for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (MARKED(n)) continue; sprintf(name+len,"%d",c_cnt); out = agsubg(g,name); dfs(g,n,insertFn,out); if (c_cnt == bnd) { bnd *= 2; ccs = RALLOC(bnd,ccs,Agraph_t*); } ccs[c_cnt] = out; c_cnt++; } ccs = RALLOC(c_cnt,ccs,Agraph_t*); if (name != buffer) free (name); *ncc = c_cnt; *pinned = pin; return ccs; } /* ccomps: * Return an array of subgraphs consisting of the connected * components of graph g. The number of components is returned in ncc. * If pfx is non-null and a legal graph name, we use it as the prefix * for the name of the subgraphs created. If not, a simple default is used. * Note that the component subgraphs do not contain any edges. These must * be obtained from the root graph. */ Agraph_t** ccomps (Agraph_t* g, int* ncc, char* pfx) { int c_cnt = 0; char buffer[SMALLBUF]; char* name; Agraph_t* out; Agnode_t* n; Agraph_t** ccs; int len; int bnd = 10; if (!pfx || !isLegal(pfx)) { pfx = "_cc_"; } len = strlen (pfx); if (len + 25 <= SMALLBUF) name = buffer; else name = (char*)gmalloc(len+25); strcpy (name, pfx); for (n = agfstnode(g); n; n = agnxtnode(g,n)) UNMARK(n); ccs = N_GNEW(bnd,Agraph_t*); for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (MARKED(n)) continue; sprintf(name+len,"%d",c_cnt); out = agsubg(g,name); dfs(g,n,insertFn,out); if (c_cnt == bnd) { bnd *= 2; ccs = RALLOC(bnd,ccs,Agraph_t*); } ccs[c_cnt] = out; c_cnt++; } ccs = RALLOC(c_cnt,ccs,Agraph_t*); if (name != buffer) free (name); *ncc = c_cnt; return ccs; } /* cntFn: */ static void cntFn (Agnode_t* n, void* s) { *(int*)s += 1; } /* isConnected: * Returns true if the graph is connected. */ int isConnected (Agraph_t* g) { Agnode_t* n; int ret = 1; int cnt = 0; for (n = agfstnode(g); n; n = agnxtnode(g,n)) UNMARK(n); n = agfstnode(g); if (n) { dfs (g,n,cntFn,&cnt); if (cnt != agnnodes(g)) ret = 0; } return ret; } /* nodeInduce: * Given a subgraph, adds all edges in the root graph both of whose * endpoints are in the subgraph. * If g is a connected component, this will be all edges attached to * any node in g. * Returns the number of edges added. */ int nodeInduce (Agraph_t* g) { Agnode_t* n; Agraph_t* root = g->root; Agedge_t* e; int e_cnt = 0; for (n = agfstnode(g); n; n = agnxtnode(g,n)) { for (e = agfstout(root,n); e; e = agnxtout(root,e)) { if (agcontains(g,e->head)) { /* test will always be true */ aginsert(g,e); /* for connected component */ e_cnt++; } } } return e_cnt; }