#pragma prototyped
#define EXTERN
#include <aghdr.h>
#ifdef DMALLOC
#include "dmalloc.h"
#endif
const char AgraphVersion[] = VERSION;
static Agclos_t *agclos(Agdisc_t *proto)
{
Agmemdisc_t *memdisc;
void *memclosure;
Agclos_t *rv;
memdisc = ((proto && proto->mem)? proto->mem : &AgMemDisc);
memclosure = memdisc->open();
rv = memdisc->alloc(memclosure, sizeof(Agclos_t));
rv->disc.mem = memdisc;
rv->state.mem = memclosure;
rv->disc.id = ((proto && proto->id)? proto->id : &AgIdDisc);
rv->disc.io = ((proto && proto->io)? proto->io : &AgIoDisc);
rv->callbacks_enabled = TRUE;
return rv;
}
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *arg_disc)
{
Agraph_t *g;
Agclos_t *clos;
unsigned long gid;
clos = agclos(arg_disc);
g = clos->disc.mem->alloc(clos->state.mem, sizeof(Agraph_t));
AGTYPE(g) = AGRAPH;
g->clos = clos;
g->desc = desc;
g->desc.maingraph = TRUE;
g->root = g;
g->clos->state.id = g->clos->disc.id->open(g);
if (agmapnametoid(g, AGRAPH, name, &gid, TRUE))
AGID(g) = gid;
return agopen1(g);
}
Agraph_t *agopen1(Agraph_t *g)
{
Agraph_t *par;
g->n_seq = agdtopen(g,&Ag_obj_seq_disc,Dttree);
g->n_id = agdtopen(g,&Ag_obj_id_disc,Dttree);
g->e_seq = agdtopen(g,&Ag_obj_seq_disc,Dttree);
g->e_id = agdtopen(g,&Ag_edge_disc,Dttree);
g->g_dict = agdtopen(g,&Ag_obj_id_disc,Dttree);
par = agparent(g);
if (par) {
AGSEQ(g) = agnextseq(par, AGRAPH);
dtinsert(par->g_dict,g);
}
if (g->desc.has_attrs) agraphattr_init(g,FALSE);
agmethod_init(g,g);
return g;
}
int agclose(Agraph_t *g)
{
Agraph_t *subg,*next_subg,*par;
Agnode_t *n,*next_n;
agflatten(g,FALSE);
par = agparent(g);
if ((par == NILgraph) && (AGDISC(g,mem)->close)) {
agmethod_delete(g,g);
agfreeid(g, AGRAPH, AGID(g));
AGDISC(g,mem)->close(AGCLOS(g,mem));
return SUCCESS;
}
for (subg = agfstsubg(g); subg; subg = next_subg) {
next_subg = agnxtsubg(subg);
agclose(subg);
}
for (n = agfstnode(g); n; n = next_n) {
next_n = agnxtnode(n);
agdelnode(n);
}
aginternalmapclose(g);
agmethod_delete(g,g);
assert(dtsize(g->n_id) == 0);
agdtclose(g,g->n_id);
assert(dtsize(g->n_seq) == 0);
agdtclose(g,g->n_seq);
assert(dtsize(g->e_id) == 0);
agdtclose(g,g->e_id);
assert(dtsize(g->e_seq) == 0);
agdtclose(g,g->e_seq);
assert(dtsize(g->g_dict) == 0);
agdtclose(g,g->g_dict);
if (g->desc.has_attrs) agraphattr_delete(g);
agrecclose((Agobj_t*)g);
agfreeid(g, AGRAPH, AGID(g));
if (par) {agdelsubg(par,g); agfree(par,g);}
else {
Agmemdisc_t *memdisc;
void *memclos, *clos;
while (g->clos->cb)
agpopdisc(g,g->clos->cb->f);
AGDISC(g,id)->close(AGCLOS(g,id));
agstrclose(g);
memdisc = AGDISC(g,mem);
memclos = AGCLOS(g,mem);
clos = g->clos;
(memdisc->free)(memclos,g);
(memdisc->free)(memclos,clos);
}
return SUCCESS;
}
unsigned long agnextseq(Agraph_t *g, int objtype) { return ++(g->clos->seq[objtype]);}
int agnnodes(Agraph_t *g)
{
return dtsize(g->n_id);
}
int agnedges(Agraph_t *g)
{
Agnode_t *n;
int rv = 0;
for (n = agfstnode(g); n; n = agnxtnode(n))
rv += agdegree(n,FALSE,TRUE);
return rv;
}
int agisflattened(Agraph_t *g)
{
return g->desc.flatlock;
}
int agisdirected(Agraph_t *g)
{
return g->desc.directed;
}
int agisundirected(Agraph_t *g)
{
return NOT(agisdirected(g));
}
int agisstrict(Agraph_t *g)
{
return g->desc.strict;
}
int agdegree(Agnode_t *n, int want_in, int want_out)
{
Agedge_t *e;
int rv = 0;
if (want_in) for (e = agfstin(n); e; e = agnxtin(e)) rv++;
if (want_out) for (e = agfstout(n); e; e = agnxtout(e)) rv++;
return rv;
}
Agdesc_t Agdirected = {1, 0, 0, 1};
Agdesc_t Agstrictdirected = {1, 1, 0, 1};
Agdesc_t Agundirected = {0, 0, 0, 1};
Agdesc_t Agstrictundirected = {0, 1, 0, 1};
Agdisc_t AgDefaultDisc = {&AgMemDisc, &AgIdDisc, &AgIoDisc};