/*
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:
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
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 <render.h>
#include <pack.h>
#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;
}
|