#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;
}
static void
insertFn (Agnode_t* n, void* state)
{
aginsert((Agraph_t*)state,n);
}
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 (agnnodes(g) == 0) {
*ncc = 0;
return 0;
}
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) || !isPinned(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);
}
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;
}
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 (agnnodes(g) == 0) {
*ncc = 0;
return 0;
}
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;
}
static void
cntFn (Agnode_t* n, void* s)
{
*(int*)s += 1;
}
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;
}
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)) {
aginsert(g,e);
e_cnt++;
}
}
}
return e_cnt;
}