Beispiel #1
0
static void
cloneSubg (Agraph_t* parent, Agraph_t* sg, Dt_t* emap)
{
    Agraph_t* subg;
    Agnode_t* t;
    Agedge_t* e;
    Agnode_t* newt;
    Agedge_t* newe;
    Agraph_t* newg;

    if (is_a_cluster(sg)) {
	newg = agsubg (parent, agnameof(sg), 1);
	parent = newg; 

	for (t = agfstnode(sg); t; t = agnxtnode(sg, t)) {
	    newt = agnode(newg, agnameof(t), 0);
            agsubnode(newg, newt, 1);
	    /* if e is in sg, both end points are, so we can use out edges */
	    for (e = agfstout(sg, t); e; e = agnxtout(sg, e)) {
		newe = mapEdge (emap, e);
		agsubedge(newg, newe, 1);
	    }
	}
    }

    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) {
	cloneSubg(parent, subg, emap);
    }
}
Beispiel #2
0
/* Execute union commands for "same rank" subgraphs and clusters. */
static void 
collapse_sets(graph_t *rg, graph_t *g)
{
    int c;
    graph_t  *subg;
#ifdef OBSOLETE
    node_t *n;
#endif

    for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
	c = rank_set_class(subg);
	if (c) {
	    if ((c == CLUSTER) && CL_type == LOCAL)
		collapse_cluster(rg, subg);
	    else
		collapse_rankset(rg, subg, c);
	}
	else collapse_sets(rg, subg);

#ifdef OBSOLETE
 Collapsing leaves is currently obsolete

	/* mark nodes with ordered edges so their leaves are not collapsed */
	if (agget(subg, "ordering"))
	    for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
		ND_order(n) = 1;
#endif
    }
}
Agraph_t *nextsubg(Agraph_t *g, Agraph_t *sg)
{

    if (!g || !sg)
        return NULL;
    return agnxtsubg(sg);
}
Beispiel #4
0
/* cloneGraph:
 * Clone node, edge and subgraph structure from src to tgt.
 */
static void cloneGraph(Agraph_t * tgt, Agraph_t * src)
{
    Agedge_t *e;
    Agnode_t *t;
    Agraph_t *sg;

    for (t = agfstnode(src); t; t = agnxtnode(t)) {
	if (!copy(tgt, OBJ(t))) {
	    error(ERROR_FATAL, "error cloning node %s from graph %s",
		  agnameof(t), agnameof(src));
	}
    }
    for (t = agfstnode(src); t; t = agnxtnode(t)) {
	for (e = agfstout(t); e; e = agnxtout(e)) {
	    if (!copy(tgt, OBJ(e))) {
		error(ERROR_FATAL,
		      "error cloning edge (%s,%s)[%s] from graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      agnameof(e), agnameof(src));
	    }
	}
    }
    for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) {
	if (!cloneSubg(tgt, sg)) {
	    error(ERROR_FATAL, "error cloning subgraph %s from graph %s",
		  agnameof(sg), agnameof(src));
	}
    }
}
Beispiel #5
0
/* createGroups:
 * run after temp nodes are created
*/
void createGroups(Agraph_t* sg)
{
    mcGroup* gr;
    Agraph_t* subg;
    Agnode_t* v;
    mcNode* leader;
    mcNode* mcn;
    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) 
    {
	if(is_a_cluster(subg)) {
	    int isLeader=1;
	    gr=initMcGroup(mcGrStrict);
	    for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) {
		mcn = MND_mcn(v);
		dtappend(gr->nodes,mcn);
		mcn->group=gr;
		mcn->groupOrder=0;/*this will be removed eventually */
		mcn->isLeader=isLeader;

		if(isLeader==1) {
		    leader = mcn;
		    isLeader = 0;
		}
		mcn->leader = leader;
	    }
	}
	else
	    createGroups (subg);
    }
}
Beispiel #6
0
static int write_subgs(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
{
    Agraph_t* sg;
    int not_first = 0;

    sg = agfstsubg(g);
    if (!sg) return 0;
   
    gvputs(job, ",\n");
    indent(job, sp->Level++);
    if (top)
	gvputs(job, "\"objects\": [\n");
    else {
	gvputs(job, "\"subgraphs\": [\n");
	indent(job, sp->Level);
    }
    for (; sg; sg = agnxtsubg(sg)) {
	if (not_first) 
	    gvputs(job, ",\n");
	else
	    not_first = 1;
        if (top)
	    write_subg (sg, job, sp);
	else
	    gvprintf(job, "%d", GD_gid(sg));
    }
    if (!top) {
	sp->Level--;
	gvputs(job, "\n");
	indent(job, sp->Level);
	gvputs(job, "]");
    }

    return 1;
}
Beispiel #7
0
	void GraphvizPlotter::parseSubgraphs(Agraph_t *g, GraphComponent *g_component, processedProperties *props) {
		// nacteni zpracovanych komponent pro jejich mozne budouci preskoceni v aktualni iteraci
		string_map node_attrs_bak = props->node_attrs;
		string_map edge_attrs_bak = props->edge_attrs;
		string_map graph_attrs_bak = props->graph_attrs;

		// prochazeni vsech podgrafu daneho grafu/podgrafu
		for (Agraph_t *subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
			// vytvoreni podgrafu v datovem modelu
			Subgraph *subgraph = g_component->addSubgraph(agnameof(subg));
			// zpracovani atributu grafu/podgrafu a ulozeni do datoveho modelu k danemu podgrafu
			parseGraphAttrs(subg, subgraph, props);
			// zpracovani podgrafu a ulozeni do datoveho modelu k danemu pdgrafu
			parseSubgraphs(subg, subgraph, props);
			// stejne zpracovani v pripade
			parseNodes(subg, subgraph, props);
			parseEdges(subg, subgraph, props);

			// pro dalsi podgraf nactu zpet zpracovane komponenty
			props->graph_attrs.clear();
			props->node_attrs.clear();
			props->edge_attrs.clear();

			props->graph_attrs = graph_attrs_bak;
			props->node_attrs = node_attrs_bak;
			props->edge_attrs = edge_attrs_bak;
		}
	}
Beispiel #8
0
static void rec_cluster_init(Agraph_t *ug)
{
	Agraph_t	*subg;

	if (is_a_cluster(ug)) cluster_init(ug);
	for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg))
		rec_cluster_init(subg);
}
Beispiel #9
0
/* this is a first cut at a top-level planner.  it's lame. */
static void rec_cluster_run(Agraph_t *ug)
{
	Agraph_t	*subg;

	if (is_a_cluster(ug)) mincross_clust(ug);
	for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg))
		rec_cluster_run(subg);
	if (is_a_cluster(ug)) mincross_clust(ug);
}
Beispiel #10
0
static void 
find_clusters(graph_t * g)
{
    graph_t *subg;
    for (subg = agfstsubg(dot_root(g)); subg; subg = agnxtsubg(subg)) {
	if (GD_set_type(subg) == CLUSTER)
	    collapse_cluster(g, subg);
    }
}
Beispiel #11
0
static void rec_model_subclusts(Agraph_t *model, Agraph_t *user)
{
	Agraph_t	*subg;

	if (is_a_cluster(user))
		(void) model_clust(model,user);
	/* note there can be non-cluster subgraphs that contain lower clusters */
	for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg))
		rec_model_subclusts(model,subg);
}
Beispiel #12
0
static void write_subg(Agraph_t * g, GVJ_t * job, state_t* sp)
{
    Agraph_t* sg;

    write_graph (g, job, FALSE, sp);
    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
	gvputs(job, ",\n");
	write_subg(sg, job, sp);
    }
}
Beispiel #13
0
/* cloneSubg:
 * Clone subgraph sg in tgt.
 */
static Agraph_t *cloneSubg(Agraph_t * tgt, Agraph_t * g, Dt_t* emap)
{
    Agraph_t *ng;
    Agraph_t *sg;
    Agnode_t *t;
    Agnode_t *newt;
    Agedge_t *e;
    Agedge_t *newe;
    char* name;

    ng = (Agraph_t *) (copy(tgt, OBJ(g)));
    if (!ng)
	return 0;
    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
	newt = agnode(tgt, agnameof(t), 0);
	if (!newt) {
	    exerror("node %s not found in cloned graph %s",
		  agnameof(t), agnameof(tgt));
	    return 0;
	}
	else
	    agsubnode(ng, newt, 1);
    }
    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
	for (e = agfstout(g, t); e; e = agnxtout(g, e)) {
	    newe = mapEdge (emap, e);
	    if (!newe) {
		name = agnameof(AGMKOUT(e));
		if (name)
		    exerror("edge (%s,%s)[%s] not found in cloned graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      name, agnameof(tgt));
		else
		    exerror("edge (%s,%s) not found in cloned graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      agnameof(tgt));
		return 0;
	    }
	    else
		agsubedge(ng, newe, 1);
	}
    }
    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
	if (!cloneSubg(ng, sg, emap)) {
	    exerror("error cloning subgraph %s from graph %s",
		  agnameof(sg), agnameof(g));
	    return 0;
	}
    }
    return ng;
}
Beispiel #14
0
static int label_subgs(Agraph_t* g, int lbl, Dt_t* map)
{
    Agraph_t* sg;

    if (g != agroot(g)) {
	GD_gid(g) = lbl++;
	if (IS_CLUSTER(g))
	    insert (map, agnameof(g), GD_gid(g)); 
    }
    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
	lbl = label_subgs(sg, lbl, map);
    }
    return lbl;
}
Beispiel #15
0
void graphGroups(Agraph_t* sg)
{
    Agraph_t* subg;
    Agnode_t* v;
    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) 
    {
	if(is_a_cluster(subg))
	    for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) 
	    	MND_highCluster(v)=subg;
	else
	    graphGroups (subg);

    }
}
Beispiel #16
0
static void
dot_init_subg(graph_t * g, graph_t* droot)
{
    graph_t* subg;

    if ((g != agroot(g)))
	agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
    if (g == droot)
	GD_dotroot(agroot(g)) = droot;
	
    for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
	dot_init_subg(subg, droot);
    }
}
bool rm(Agraph_t *g)
{
    Agedge_t *e;

    if (!g)
        return false;
    Agraph_t* sg;
    for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg))
	rm(sg);
    if (g == agroot(g))
	agclose(g);
    else
        agdelete(agroot(g), g);
    return true;
}
Beispiel #18
0
/* recursively apply objfn within the hierarchy of a graph.
 * if obj is a node or edge, it and its images in every subg are visited.
 * if obj is a graph, then it and its subgs are visited.
 */
static void rec_apply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
		      agobjsearchfn_t objsearch, int preorder)
{
    Agraph_t *sub;
    Agobj_t *subobj;

    if (preorder)
	fn(g, obj, arg);
    for (sub = agfstsubg(g); sub; sub = agnxtsubg(sub)) {
	if ((subobj = objsearch(sub, obj)))
	    rec_apply(sub, subobj, fn, arg, objsearch, preorder);
    }
    if (NOT(preorder))
	fn(g, obj, arg);
}
Beispiel #19
0
/* cloneGraph:
 * Clone node, edge and subgraph structure from src to tgt.
 */
static void cloneGraph(Agraph_t * tgt, Agraph_t * src)
{
    Agedge_t *e;
    Agedge_t *ne;
    Agnode_t *t;
    Agraph_t *sg;
    char* name;
    Dt_t* emap = dtopen (&edgepair, Dtoset);
    edgepair_t* data = (edgepair_t*)malloc(sizeof(edgepair_t)*agnedges(src));
    edgepair_t* ep = data;

    for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
	if (!copy(tgt, OBJ(t))) {
	    exerror("error cloning node %s from graph %s",
		  agnameof(t), agnameof(src));
	}
    }
    for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
	for (e = agfstout(src, t); e; e = agnxtout(src, e)) {
	    if (!(ne = (Agedge_t*)copy(tgt, OBJ(e)))) {
		name = agnameof(AGMKOUT(e));
		if (name)
		    exerror("error cloning edge (%s,%s)[%s] from graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      name, agnameof(src));
		else
		    exerror("error cloning edge (%s,%s) from graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      agnameof(src));
		return;
	    }
	    ep->key = e;
	    ep->val = ne;
	    dtinsert (emap, ep++);
	}
    }
    for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) {
	if (!cloneSubg(tgt, sg, emap)) {
	    exerror("error cloning subgraph %s from graph %s",
		  agnameof(sg), agnameof(src));
	}
    }

    dtclose (emap);
    free (data);
}
Beispiel #20
0
/* mkMCGraph:
 * Clone original graph. We only need the nodes, edges and clusters.
 * Copy
 */
Agraph_t* 
mkMCGraph (Agraph_t* g)
{
    Agnode_t* t;
    Agnode_t* newt;
    Agnode_t* newh;
    Agedge_t* e;
    Agedge_t* newe;
    Agraph_t* sg;
    edgepair_t* data;
    edgepair_t* ep;
    Agraph_t* newg = agopen (agnameof(g), g->desc, 0);
    Dt_t* emap = dtopen (&edgepair, Dtoset);;
    data = N_NEW(agnedges(g), edgepair_t);
    ep = data;

    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
	newt = mkMCNode (newg, STDNODE, agnameof(t));
	assert(newt);
        MND_orig(newt) = t;
        MND_rank(newt) = ND_rank(t);
    }

    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
        newt = agnode (newg, agnameof(t), 0);
	for (e = agfstout(g, t); e; e = agnxtout(g, e)) {
	    newh = agnode (newg, agnameof(aghead(e)), 0);
	    assert(newh);
            newe = mkMCEdge (newg, newt, newh, agnameof (e), NORMAL, e); 
	    assert(newe);
	    ep->key = e;
	    ep->val = newe;
	    dtinsert (emap, ep++);
	}
    }

    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
	cloneSubg(newg, sg, emap);
    }

    dtclose (emap);
    free (data);

    return newg;
}
Beispiel #21
0
void drawGraph(Agraph_t * g)
{
    Agnode_t *v;
    Agedge_t *e;
    Agraph_t *s;
    int param = 0;
	for (s = agfstsubg(g); s; s = agnxtsubg(s))
	{
		OD_SelFlag(s) = 0;
		if (OD_Selected(s) == 1)
			param = 1;
		else
		    param = 0;
		drawXdotwithattrs(s, param);
    }

    for (v = agfstnode(g); v; v = agnxtnode(g, v)) 
	{
		if (OD_Selected(v) == 1)
			param = 1;
		else
			param = 0;
		OD_SelFlag(v) = 0;
		drawXdotwithattr(v, "_draw_", param); //draw primitives
		drawXdotwithattr(v, "_ldraw_", param);//label drawing
		for (e = agfstout(g, v); e; e = agnxtout(g, e)) 
		{
			OD_SelFlag(e) = 0;
			if (OD_Selected(e) == 1)
				param = 1;
			else
				param = 0;
		    drawXdotwithattrs(e, param);
		}
    }
    if ((view->Selection.Active > 0) && (!view->SignalBlock)) 
	{
		view->Selection.Active = 0;
		drawGraph(g);
		view->SignalBlock = 1;
		glexpose();
		view->SignalBlock = 0;
    }

}
Beispiel #22
0
static void set_attrwf(Agraph_t * g, int toplevel, int value)
{
    Agraph_t *subg;
    Agnode_t *n;
    Agedge_t *e;

    AGATTRWF(g) = value;
    for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
	set_attrwf(subg, FALSE, value);
    }
    if (toplevel) {
	for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	    AGATTRWF(n) = value;
	    for (e = agfstout(g, n); e; e = agnxtout(g, e))
		AGATTRWF(e) = value;
	}
    }
}
Beispiel #23
0
void deleteGraph(gctx_t * gctx, Agraph_t *g)
{
    Agraph_t *sg;
    char *hndl;

    for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg)) {
	deleteGraph(gctx, sg);
    }
    deleteGraphNodes(gctx, g);

    hndl = obj2cmd(g);
    if (g == agroot(g)) {
	agclose(g);
    } else {
	agdelsubg(agroot(g), g);
    }
    Tcl_DeleteCommand(gctx->ictx->interp, hndl);
}
Beispiel #24
0
/* cloneSubg:
 * Clone subgraph sg in tgt.
 */
static Agraph_t *cloneSubg(Agraph_t * tgt, Agraph_t * g)
{
    Agraph_t *ng;
    Agraph_t *sg;
    Agnode_t *t;
    Agnode_t *newt;
    Agnode_t *newh;
    Agedge_t *e;
    Agedge_t *newe;

    ng = (Agraph_t *) (copy(tgt, OBJ(g)));
    if (!ng)
	return 0;
    for (t = agfstnode(g); t; t = agnxtnode(t)) {
	newt = agnode(tgt, agnameof(t), 0);
	if (!newt)
	    error(ERROR_PANIC, "node %s not found in cloned graph %s",
		  agnameof(t), agnameof(tgt));
	agsubnode(ng, newt, 1);
    }
    for (t = agfstnode(g); t; t = agnxtnode(t)) {
	newt = agnode(tgt, agnameof(t), 0);
	for (e = agfstout(t); e; e = agnxtout(e)) {
	    newh = agnode(tgt, agnameof(aghead(e)), 0);
	    newe = agedge(newt, newh, agnameof(e), 0);
	    if (!newe)
		error(ERROR_PANIC,
		      "edge (%s,%s)[%s] not found in cloned graph %s",
		      agnameof(agtail(e)), agnameof(aghead(e)),
		      agnameof(e), agnameof(tgt));
	    agsubedge(ng, newe, 1);
	}
    }
    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
	if (!cloneSubg(ng, sg)) {
	    error(ERROR_FATAL, "error cloning subgraph %s from graph %s",
		  agnameof(sg), agnameof(g));
	}
    }
    return ng;
}
Beispiel #25
0
static void 
dot_cleanup_graph(graph_t * g)
{
    int i;
    graph_t *subg;
    for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
	dot_cleanup_graph(subg);
    }
    if (GD_clust(g)) free (GD_clust(g));
    if (GD_rankleader(g)) free (GD_rankleader(g));

    free_list(GD_comp(g));
    if (GD_rank(g)) {
	for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
	    free(GD_rank(g)[i].av);
	if (GD_minrank(g) == -1)
	    free(GD_rank(g)-1);
	else
	    free(GD_rank(g));
    }
    if (g != agroot(g)) 
	agdelrec(g,"Agraphinfo_t");
}
Beispiel #26
0
/* Execute union commands for "same rank" subgraphs and clusters. */
static void 
collapse_sets(graph_t *rg, graph_t *g)
{
    int c;
    graph_t  *subg;
#ifdef OBSOLETE
    node_t *n;
#endif

#ifndef WITH_CGRAPH
    graph_t *mg;
    node_t *mn;
    edge_t *me;
    mg = g->meta_node->graph;
    for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
	mn = aghead(me);
	subg = agusergraph(mn);
#else /* WITH_CGRAPH */
    for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
#endif /* WITH_CGRAPH */
	c = rank_set_class(subg);
	if (c) {
	    if ((c == CLUSTER) && CL_type == LOCAL)
		collapse_cluster(rg, subg);
	    else
		collapse_rankset(rg, subg, c);
	}
	else collapse_sets(rg, subg);

#ifdef OBSOLETE
 Collapsing leaves is currently obsolete

	/* mark nodes with ordered edges so their leaves are not collapsed */
	if (agget(subg, "ordering"))
	    for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
		ND_order(n) = 1;
#endif
    }
}

static void 
find_clusters(graph_t * g)
{
    graph_t *subg;
#ifndef WITH_CGRAPH
    graph_t *mg;
    node_t *mn;
    edge_t *me;

    mg = g->meta_node->graph;
    for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
	mn = me->head;
	subg = agusergraph(mn);
#else /* WITH_CGRAPH */
    for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) {
#endif /* WITH_CGRAPH */
	if (GD_set_type(subg) == CLUSTER)
	    collapse_cluster(g, subg);
    }
}

static void 
set_minmax(graph_t * g)
{
    int c;

    GD_minrank(g) += ND_rank(GD_leader(g));
    GD_maxrank(g) += ND_rank(GD_leader(g));
    for (c = 1; c <= GD_n_cluster(g); c++)
	set_minmax(GD_clust(g)[c]);
}
Beispiel #27
0
/*
 * Close a graph or subgraph, freeing its storage.
 */
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)) {
	/* free entire heap */
	agmethod_delete(g, g);	/* invoke user callbacks */
	agfreeid(g, AGRAPH, AGID(g));
	AGDISC(g, mem)->close(AGCLOS(g, mem));	/* whoosh */
	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;
}