--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#include <cghdr.h>
+
+/*
+ * dynamic attributes
+ */
+
+/* to create a graph's data dictionary */
+
+#define MINATTR 4 /* minimum allocation */
+
+static void freesym(Dict_t * d, Void_t * obj, Dtdisc_t * disc);
+
+Dtdisc_t AgDataDictDisc = {
+ (int) offsetof(Agsym_t, name), /* use symbol name as key */
+ -1,
+ (int) offsetof(Agsym_t, link),
+ NIL(Dtmake_f),
+ freesym,
+ NIL(Dtcompar_f),
+ NIL(Dthash_f)
+};
+
+static char DataDictName[] = "_AG_datadict";
+static void init_all_attrs(Agraph_t * g);
+static Agdesc_t ProtoDesc = {1,0,1,0,1,1};
+static Agraph_t *ProtoGraph;
+
+Agdatadict_t *agdatadict(Agraph_t * g)
+{
+ Agdatadict_t *rv;
+ while ((rv = (Agdatadict_t *) aggetrec(g, DataDictName, FALSE))
+ == NIL(Agdatadict_t *))
+ init_all_attrs(g);
+ return rv;
+}
+
+Dict_t *agdictof(Agraph_t * g, int kind)
+{
+ Agdatadict_t *dd;
+ Dict_t *dict;
+
+ dd = agdatadict(g);
+ switch (kind) {
+ case AGRAPH:
+ dict = dd->dict.g;
+ break;
+ case AGNODE:
+ dict = dd->dict.n;
+ break;
+ case AGINEDGE:
+ case AGOUTEDGE:
+ dict = dd->dict.e;
+ break;
+ default:
+ abort();
+ }
+ return dict;
+}
+
+static Agdatadict_t *agmakedatadict(Agraph_t * g)
+{
+ Agraph_t *par;
+ Agdatadict_t *parent_dd, *dd;
+
+ dd = (Agdatadict_t *) agbindrec(g, DataDictName, sizeof(Agdatadict_t),
+ FALSE);
+ dd->dict.n = agdtopen(g, &AgDataDictDisc, Dttree);
+ dd->dict.e = agdtopen(g, &AgDataDictDisc, Dttree);
+ dd->dict.g = agdtopen(g, &AgDataDictDisc, Dttree);
+ if ((par = agparent(g))) {
+ parent_dd = agdatadict(par);
+ assert(dd != parent_dd);
+ dtview(dd->dict.n, parent_dd->dict.n);
+ dtview(dd->dict.e, parent_dd->dict.e);
+ dtview(dd->dict.g, parent_dd->dict.g);
+ }
+ return dd;
+}
+
+Agsym_t *agnewsym(Agraph_t * g, char *name, char *value, int id, int kind)
+{
+ Agsym_t *sym;
+ sym = agalloc(g, sizeof(Agsym_t));
+ sym->kind = kind;
+ sym->name = agstrdup(g, name);
+ sym->defval = agstrdup(g, value);
+ sym->id = id;
+ return sym;
+}
+
+ /* look up or update a value associated with an object. */
+Agsym_t *agdictsym(Dict_t * dict, char *name)
+{
+ Agsym_t key;
+ key.name = (char *) name;
+ return (Agsym_t *) dtsearch(dict, &key);
+}
+
+/* look up attribute in local dictionary with no view pathing */
+Agsym_t *aglocaldictsym(Dict_t * dict, char *name)
+{
+ Agsym_t *rv;
+ Dict_t *view;
+
+ view = dtview(dict, NIL(Dict_t *));
+ rv = agdictsym(dict, name);
+ dtview(dict, view);
+ return rv;
+}
+
+Agsym_t *agattrsym(void *obj, char *name)
+{
+ Agattr_t *data;
+
+ data = agattrrec((Agobj_t *) obj);
+ return (data ? agdictsym(data->dict, name) : NILsym);
+}
+
+/* to create a graph's, node's edge's string attributes */
+
+char *AgDataRecName = "_AG_strdata";
+
+static int topdictsize(Agobj_t * obj)
+{
+ return dtsize(agdictof(agroot(agraphof(obj)), AGTYPE(obj)));
+}
+
+static Agrec_t *agmakeattrs(void *obj)
+{
+ int sz;
+ Agattr_t *rec;
+ Agsym_t *sym;
+ Agraph_t *g;
+ Dict_t *datadict;
+
+ g = agraphof(obj);
+ rec = agbindrec(obj, AgDataRecName, sizeof(Agattr_t), FALSE);
+ datadict = agdictof(g, AGTYPE(obj));
+ if (rec->dict == NIL(Dict_t *)) {
+ rec->dict = datadict;
+ /* don't malloc(0) */
+ sz = topdictsize(obj);
+ if (sz < MINATTR)
+ sz = MINATTR;
+ rec->str = agalloc(g, sz * sizeof(char *));
+ /* doesn't call agxset() so no obj-modified callbacks occur */
+ for (sym = (Agsym_t *) dtfirst(datadict); sym;
+ sym = (Agsym_t *) dtnext(datadict, sym))
+ rec->str[sym->id] = agstrdup(g, sym->defval);
+ } else {
+ assert(rec->dict == datadict);
+ }
+ return (Agrec_t *) rec;
+}
+
+
+static void freeattr(Agobj_t * obj, Agattr_t * attr)
+{
+ int i, sz;
+ Agraph_t *g;
+
+ g = agraphof(obj);
+ sz = topdictsize(obj);
+ for (i = 0; i < sz; i++)
+ agstrfree(g, attr->str[i]);
+ agfree(g, attr->str);
+}
+
+static void freesym(Dict_t * d, Void_t * obj, Dtdisc_t * disc)
+{
+ Agsym_t *sym;
+
+ NOTUSED(d);
+ sym = (Agsym_t *) obj;
+ NOTUSED(disc);
+ agstrfree(Ag_G_global, sym->name);
+ agstrfree(Ag_G_global, sym->defval);
+ agfree(Ag_G_global, sym);
+}
+
+Agattr_t *agattrrec(void *obj)
+{
+ return (Agattr_t *) aggetrec(obj, AgDataRecName, FALSE);
+}
+
+
+static void addattr(Agraph_t * g, Agobj_t * obj, Agsym_t * sym)
+{
+ Agattr_t *attr;
+
+ attr = (Agattr_t *) agattrrec(obj);
+ assert(attr != NIL(Agattr_t *));
+ if (sym->id >= MINATTR)
+ attr->str = (char **) AGDISC(g, mem)->resize(AGCLOS(g, mem),
+ attr->str,
+ sym->id *
+ sizeof(char *),
+ (sym->id +
+ 1) * sizeof(char *));
+ attr->str[sym->id] = agstrdup(g, sym->defval);
+ /* agmethod_upd(g,obj,sym); JCE and GN didn't like this. */
+}
+
+
+/*
+ * create or update an existing attribute and return its descriptor.
+ * if the new value is NIL(char*), this is only a search, no update.
+ * when a new attribute is created, existing graphs/nodes/edges
+ * receive its default value.
+ */
+Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value)
+{
+ Agraph_t *root;
+ Agsym_t *lsym, *rsym;
+ Dict_t *ldict, *rdict;
+ Agnode_t *n;
+ Agedge_t *e;
+
+ if (g == 0) {if (ProtoGraph == 0) ProtoGraph = agopen(0,ProtoDesc,0); g = ProtoGraph;}
+ ldict = agdictof(g, kind);
+ lsym = aglocaldictsym(ldict, name);
+ root = agroot(g);
+ if (lsym) {
+ /* this attr was previously defined in this graph */
+ if (value) {
+ agstrfree(g, lsym->defval);
+ lsym->defval = agstrdup(g, value);
+ }
+ } else { /* not previously defined here */
+ rsym = agdictsym(ldict, name); /* viewpath up to root */
+ if (value) { /* need to define */
+ if (rsym) {
+ lsym = agnewsym(g, name, value, rsym->id, kind);
+ dtinsert(ldict, lsym);
+ } else { /* just define globally */
+ rdict = agdictof(root, kind);
+ lsym = rsym =
+ agnewsym(g, name, value, dtsize(rdict), kind);
+ dtinsert(rdict, rsym);
+
+ switch (kind) {
+ case AGRAPH:
+ agapply(root, (Agobj_t *) root, (agobjfn_t) addattr,
+ lsym, TRUE);
+ break;
+ case AGNODE:
+ for (n = agfstnode(root); n; n = agnxtnode(root, n))
+ addattr(g, (Agobj_t *) n, lsym);
+ break;
+ case AGINEDGE:
+ case AGOUTEDGE:
+ for (n = agfstnode(root); n; n = agnxtnode(root, n))
+ for (e = agfstout(root, n); e;
+ e = agnxtout(root, e))
+ addattr(g, (Agobj_t *) e, lsym);
+ break;
+ }
+ }
+ agmethod_upd(g, g, lsym); /* JCE and GN wanted this instead */
+ } else
+ return rsym;
+ }
+ /* in graphs, defaults and actual values are always the same.
+ * see also agxset() where graph attrs are handled. therefore
+ * agxset() must not call agattr() in its implementation
+ */
+ if (lsym && (kind == AGRAPH))
+ agxset(g, lsym, value);
+ return lsym;
+}
+
+Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr)
+{
+ Dict_t *d;
+ Agsym_t *rv;
+
+ d = agdictof(g, kind);
+ if (attr)
+ rv = (Agsym_t *) dtnext(d, attr);
+ else
+ rv = (Agsym_t *) dtfirst(d);
+ return rv;
+}
+
+/* Create or delete attributes associated with an object */
+
+void agraphattr_init(Agraph_t * g)
+{
+ /* Agdatadict_t *dd; */
+ /* Agrec_t *attr; */
+
+ g->desc.has_attrs = 1;
+ /* dd = */ agmakedatadict(g);
+ /* attr = */ agmakeattrs(g);
+}
+
+void agraphattr_delete(Agraph_t * g)
+{
+ Agdatadict_t *dd;
+ Agattr_t *attr;
+
+ Ag_G_global = g;
+ if ((attr = agattrrec(g))) {
+ freeattr((Agobj_t *) g, attr);
+ agdelrec(g, attr->h.name);
+ }
+
+ if ((dd = agdatadict(g))) {
+ agdtclose(g, dd->dict.n);
+ agdtclose(g, dd->dict.e);
+ agdtclose(g, dd->dict.g);
+ agdelrec(g, dd->h.name);
+ }
+}
+
+void agnodeattr_init(Agnode_t * n)
+{
+ Agattr_t *data;
+
+ data = agattrrec(n);
+ if ((!data) || (!data->dict))
+ (void) agmakeattrs(n);
+}
+
+void agnodeattr_delete(Agnode_t * n)
+{
+ Agattr_t *rec;
+
+ if ((rec = agattrrec(n))) {
+ freeattr((Agobj_t *) n, rec);
+ agdelrec(n, AgDataRecName);
+ }
+}
+
+void agedgeattr_init(Agedge_t * e)
+{
+ Agattr_t *data;
+
+ data = agattrrec(e);
+ if ((!data) || (!data->dict))
+ (void) agmakeattrs(e);
+}
+
+void agedgeattr_delete(Agedge_t * e)
+{
+ Agattr_t *rec;
+
+ if ((rec = agattrrec(e))) {
+ freeattr((Agobj_t *) e, rec);
+ agdelrec(e, AgDataRecName);
+ }
+}
+
+char *agget(void *obj, char *name)
+{
+ Agsym_t *sym;
+ Agattr_t *data;
+ char *rv;
+
+ sym = agattrsym(obj, name);
+ if (sym == NILsym)
+ rv = 0; /* note was "", but this provides more info */
+ else {
+ data = agattrrec((Agobj_t *) obj);
+ rv = (char *) (data->str[sym->id]);
+ }
+ return rv;
+}
+
+char *agxget(void *obj, Agsym_t * sym)
+{
+ Agattr_t *data;
+ char *rv;
+
+ data = agattrrec((Agobj_t *) obj);
+ assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
+ rv = (char *) (data->str[sym->id]);
+ return rv;
+}
+
+int agset(void *obj, char *name, char *value)
+{
+ Agsym_t *sym;
+ int rv;
+
+ sym = agattrsym(obj, name);
+ if (sym == NILsym)
+ rv = FAILURE;
+ else
+ rv = agxset(obj, sym, value);
+ return rv;
+}
+
+int agxset(void *obj, Agsym_t * sym, char *value)
+{
+ Agraph_t *g;
+ Agobj_t *hdr;
+ Agattr_t *data;
+ Agsym_t *lsym;
+
+ g = agraphof(obj);
+ hdr = (Agobj_t *) obj;
+ data = agattrrec(hdr);
+ assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
+ agstrfree(g, data->str[sym->id]);
+ data->str[sym->id] = agstrdup(g, value);
+ if (hdr->tag.objtype == AGRAPH) {
+ /* also update dict default */
+ Dict_t *dict;
+ dict = agdatadict(g)->dict.g;
+ if ((lsym = aglocaldictsym(dict, sym->name))) {
+ agstrfree(g, lsym->defval);
+ lsym->defval = agstrdup(g, value);
+ } else {
+ lsym = agnewsym(g, sym->name, value, sym->id, AGTYPE(hdr));
+ dtinsert(dict, lsym);
+ }
+ }
+ agmethod_upd(g, obj, sym);
+ return SUCCESS;
+}
+
+int agsafeset(void* obj, char* name, char* value, char* def)
+{
+ Agsym_t* a;
+
+ a = agattr(agraphof(obj),AGTYPE(obj),value,0);
+ if (!a) a = agattr(agraphof(obj),AGTYPE(obj),value,def);
+ return agxset(obj, a, value);
+}
+
+
+/*
+ * here we are attaching attributes to the already created graph objs.
+ * presumably they were already initialized, so we don't invoke any
+ * of the old methods.
+ */
+static void init_all_attrs(Agraph_t * g)
+{
+ Agraph_t *root;
+ Agnode_t *n;
+ Agedge_t *e;
+
+ root = agroot(g);
+ agapply(root, (Agobj_t *) root, (agobjfn_t) agraphattr_init,
+ NIL(Agdisc_t *), TRUE);
+ for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
+ agnodeattr_init(n);
+ for (e = agfstout(root, n); e; e = agnxtout(root, e)) {
+ agedgeattr_init(e);
+ }
+ }
+}
+
+/* agcopyattr:
+ * Assumes attributes have already been declared.
+ * Do not copy key attribute for edges, as this must be distinct.
+ * Returns non-zero on failure or if objects have different type.
+ */
+int agcopyattr(void *oldobj, void *newobj)
+{
+ Agraph_t *g;
+ Agsym_t *sym;
+ Agsym_t *newsym;
+ int r = 1;
+
+ g = agraphof(oldobj);
+ if (AGTYPE(oldobj) != AGTYPE(newobj)) return 1;
+ sym = 0;
+ while ((sym = agnxtattr(g, AGTYPE(oldobj), sym))) {
+ newsym = agattrsym(newobj,sym->name);
+ if (!newsym) return 1;
+ r = agxset(newobj, newsym, agxget(oldobj, sym));
+ }
+ return r;
+}
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifndef ATT_GRAPHPVT_H
+#define ATT_GRAPHPVT_H 1
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#include <cgraph.h>
+
+#include <ctype.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_AST
+#include <ast.h>
+#include <vmalloc.h>
+#else
+#ifdef HAVE_VMALLOC
+#include <vmalloc.h>
+#endif /* HAVE_VMALLOC */
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#endif /* HAVE_AST */
+#ifdef DEBUG
+#include <assert.h>
+#else
+#define assert(x)
+#endif
+
+#ifndef streq
+#define streq(s,t) ((*s == *t) && !strcmp((s),(t)))
+#endif
+#ifdef offsetof
+#undef offsetof
+#endif
+#define offsetof(typ,fld) ((int)(&(((typ*)0)->fld)))
+#define NOTUSED(var) (void) var
+
+#define NILgraph NIL(Agraph_t*)
+#define NILnode NIL(Agnode_t*)
+#define NILedge NIL(Agedge_t*)
+#define NILsym NIL(Agsym_t*)
+#define NILstr NIL(char*)
+
+#define MAX_OUTPUTLINE 80
+#define SUCCESS 0
+#define FAILURE -1
+#define LOCALNAMEPREFIX '%'
+
+#define AGDISC(g,d) ((g)->clos->disc.d)
+#define AGCLOS(g,d) ((g)->clos->state.d)
+#define AGNEW(g,t) ((t*)(agalloc(g,sizeof(t))))
+
+#define ISALNUM(c) ((isalnum(c)) || ((c) == '_') || (!isascii(c)))
+
+ /* functional definitions */
+typedef Agobj_t *(*agobjsearchfn_t) (Agraph_t * g, Agobj_t * obj);
+int agapply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
+ int preorder);
+
+ /* global variables */
+EXTERN Agraph_t *Ag_G_global;
+extern char *AgDataRecName;
+
+ /* set ordering disciplines */
+extern Dtdisc_t Ag_subnode_id_disc;
+extern Dtdisc_t Ag_subnode_seq_disc;
+extern Dtdisc_t Ag_mainedge_id_disc;
+extern Dtdisc_t Ag_subedge_id_disc;
+extern Dtdisc_t Ag_mainedge_seq_disc;
+extern Dtdisc_t Ag_subedge_seq_disc;
+extern Dtdisc_t Ag_subgraph_id_disc;
+extern Agcbdisc_t AgAttrdisc;
+
+ /* internal constructor of graphs and subgraphs */
+Agraph_t *agopen1(Agraph_t * g);
+void agstrclose(Agraph_t * g);
+
+ /* object set management */
+Agnode_t *agfindnode_by_id(Agraph_t * g, unsigned long id);
+Dtcompar_f agdictorder(Agraph_t *, Dict_t *, Dtcompar_f);
+int agedgecmpf(Dict_t * d, void *arg_e0, void *arg_e1, Dtdisc_t * disc);
+int agnamecmpf(Dict_t * d, void *, void *, Dtdisc_t * disc);
+void agset_node_disc(Agraph_t * g, Dtdisc_t * disc);
+unsigned long agnextseq(Agraph_t * g, int objtype);
+
+/* dict helper functions */
+Dict_t *agdtopen(Agraph_t * g, Dtdisc_t * disc, Dtmethod_t * method);
+void agdtdisc(Agraph_t * g, Dict_t * dict, Dtdisc_t * disc);
+long agdtdelete(Agraph_t * g, Dict_t * dict, void *obj);
+void agdtclose(Agraph_t * g, Dict_t * dict);
+void *agdictobjmem(Dict_t * dict, Void_t * p, size_t size,
+ Dtdisc_t * disc);
+void agdictobjfree(Dict_t * dict, Void_t * p, Dtdisc_t * disc);
+
+ /* name-value pair operations */
+Agdatadict_t *agdatadict(Agraph_t * g);
+Agattr_t *agattrrec(void *obj);
+
+void agraphattr_init(Agraph_t * g);
+void agraphattr_delete(Agraph_t * g);
+void agnodeattr_init(Agnode_t * n);
+void agnodeattr_delete(Agnode_t * n);
+void agedgeattr_init(Agedge_t * e);
+void agedgeattr_delete(Agedge_t * e);
+
+ /* parsing and lexing graph files */
+int aagparse(void);
+void aglexinit(Agdisc_t * disc, void *ifile);
+int aaglex(void);
+void aglexeof(void);
+
+ /* ID management */
+int agmapnametoid(Agraph_t * g, int objtype, char *str,
+ unsigned long *result, int allocflag);
+int agallocid(Agraph_t * g, int objtype, unsigned long request);
+void agfreeid(Agraph_t * g, int objtype, unsigned long id);
+char *agprintid(Agobj_t * obj);
+int aginternalmaplookup(Agraph_t * g, int objtype, char *str,
+ unsigned long *result);
+void aginternalmapinsert(Agraph_t * g, int objtype, char *str,
+ unsigned long result);
+char *aginternalmapprint(Agraph_t * g, int objtype, unsigned long id);
+int aginternalmapdelete(Agraph_t * g, int objtype, unsigned long id);
+void aginternalmapclose(Agraph_t * g);
+
+ /* internal set operations */
+void agedgesetop(Agraph_t * g, Agedge_t * e, int insertion);
+void agdelnodeimage(Agraph_t * g, Agnode_t * node, void *ignored);
+void agdeledgeimage(Agraph_t * g, Agedge_t * edge, void *ignored);
+void *agrebind0(Agraph_t * g, void *obj); /* unsafe */
+int agrename(Agobj_t * obj, char *newname);
+void agrecclose(Agobj_t * obj);
+
+void agmethod_init(Agraph_t * g, void *obj);
+void agmethod_upd(Agraph_t * g, void *obj, Agsym_t * sym);
+void agmethod_delete(Agraph_t * g, void *obj);
+
+#define CB_INITIALIZE 100
+#define CB_UPDATE 101
+#define CB_DELETION 102
+void agsyspushdisc(Agraph_t * g, Agcbdisc_t * cb, void *state, int stack);
+int agsyspopdisc(Agraph_t * g, Agcbdisc_t * cb, int stack);
+void agrecord_callback(Agraph_t * g, Agobj_t * obj, int kind,
+ Agsym_t * optsym);
+void aginitcb(Agraph_t * g, void *obj, Agcbstack_t * disc);
+void agupdcb(Agraph_t * g, void *obj, Agsym_t * sym, Agcbstack_t * disc);
+void agdelcb(Agraph_t * g, void *obj, Agcbstack_t * disc);
+
+#endif /* ATT_GRAPHPVT_H */
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifndef ATT_GRAPH_H
+#define ATT_GRAPH_H
+
+#include <cdt.h>
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+#ifndef NOT
+#define NOT(x) (!(x))
+#endif
+#ifndef NIL
+#define NIL(type) ((type)0)
+#endif
+#define NILgraph NIL(Agraph_t*)
+#define NILnode NIL(Agnode_t*)
+#define NILedge NIL(Agedge_t*)
+#define NILsym NIL(Agsym_t*)
+
+/* forward struct type declarations */
+typedef struct Agtag_s Agtag_t;
+typedef struct Agobj_s Agobj_t; /* generic object header */
+typedef struct Agraph_s Agraph_t; /* graph, subgraph (or hyperedge) */
+typedef struct Agnode_s Agnode_t; /* node (atom) */
+typedef struct Agedge_s Agedge_t; /* node pair */
+typedef struct Agdesc_s Agdesc_t; /* graph descriptor */
+typedef struct Agmemdisc_s Agmemdisc_t; /* memory allocator */
+typedef struct Agiddisc_s Agiddisc_t; /* object ID allocator */
+typedef struct Agiodisc_s Agiodisc_t; /* IO services */
+typedef struct Agdisc_s Agdisc_t; /* union of client discipline methods */
+typedef struct Agdstate_s Agdstate_t; /* client state (closures) */
+typedef struct Agsym_s Agsym_t; /* string attribute descriptors */
+typedef struct Agattr_s Agattr_t; /* string attribute container */
+typedef struct Agcbdisc_s Agcbdisc_t; /* client event callbacks */
+typedef struct Agcbstack_s Agcbstack_t; /* enclosing state for cbdisc */
+typedef struct Agclos_s Agclos_t; /* common fields for graph/subgs */
+typedef struct Agrec_s Agrec_t; /* generic runtime record */
+typedef struct Agdatadict_s Agdatadict_t; /* set of dictionaries per graph */
+typedef struct Agedgepair_s Agedgepair_t; /* the edge object */
+typedef struct Agsubnode_s Agsubnode_t;
+
+/* Header of a user record. These records are attached by client programs
+dynamically at runtime. A unique string ID must be given to each record
+attached to the same object. Cgraph has functions to create, search for,
+and delete these records. The records are maintained in a circular list,
+with obj->data pointing somewhere in the list. The search function has
+an option to lock this pointer on a given record. The application must
+be written so only one such lock is outstanding at a time. */
+
+struct Agrec_s {
+ char *name;
+ Agrec_t *next;
+ /* following this would be any programmer-defined data */
+};
+
+/* Object tag for graphs, nodes, and edges. While there may be several structs
+for a given node or edges, there is only one unique ID (per main graph). */
+struct Agtag_s {
+ unsigned objtype:2; /* see literal tags below */
+ unsigned mtflock:1; /* move-to-front lock, see above */
+ unsigned attrwf:1; /* attrs written (parity, write.c) */
+ unsigned seq:(sizeof(unsigned) * 8 - 4); /* sequence no. */
+ unsigned long id; /* client ID */
+};
+
+ /* object tags */
+#define AGRAPH 0 /* can't exceed 2 bits. see Agtag_t. */
+#define AGNODE 1
+#define AGOUTEDGE 2
+#define AGINEDGE 3 /* (1 << 1) indicates an edge tag. */
+#define AGEDGE AGOUTEDGE /* synonym in object kind args */
+
+ /* a generic graph/node/edge header */
+struct Agobj_s {
+ Agtag_t tag;
+ Agrec_t *data;
+};
+
+#define AGTAG(obj) (((Agobj_t*)(obj))->tag)
+#define AGTYPE(obj) (AGTAG(obj).objtype)
+#define AGID(obj) (AGTAG(obj).id)
+#define AGSEQ(obj) (AGTAG(obj).seq)
+#define AGATTRWF(obj) (AGTAG(obj).attrwf)
+#define AGDATA(obj) (((Agobj_t*)(obj))->data)
+
+/* This is the node struct allocated per graph (or subgraph). It resides
+in the n_dict of the graph. The node set is maintained by libdict, but
+transparently to libgraph callers. Every node may be given an optional
+string name at its time of creation, or it is permissible to pass NIL(char*)
+for the name. */
+
+struct Agsubnode_s { /* the node-per-graph-or-subgraph record */
+ Dtlink_t id_link;
+ Dtlink_t seq_link;
+ Agnode_t *node; /* the object */
+ Dtlink_t *in_id, *out_id; /* by node/ID for random access */
+ Dtlink_t *in_seq, *out_seq; /* by node/sequence for serial access */
+};
+
+struct Agnode_s {
+ Agobj_t base;
+ Agraph_t *root;
+ Agsubnode_t mainsub; /* embedded for main graph */
+};
+
+struct Agedge_s {
+ Agobj_t base;
+ Dtlink_t id_link; /* main graph only */
+ Dtlink_t seq_link;
+ Agnode_t *node; /* the endpoint node */
+};
+
+struct Agedgepair_s {
+ Agedge_t out, in;
+};
+
+struct Agdesc_s { /* graph descriptor */
+ unsigned directed:1; /* if edges are asymmetric */
+ unsigned strict:1; /* if and self, multi-edges forbidden */
+ unsigned maingraph:1; /* if this is the top level graph */
+ unsigned flatlock:1; /* if sets are flattened into lists in cdt */
+ unsigned no_write:1; /* if a temporary subgraph */
+ unsigned has_attrs:1; /* if string attr tables should be initialized */
+ unsigned has_cmpnd:1; /* if may contain collapsed nodes */
+};
+
+/* disciplines for external resources needed by libgraph */
+
+struct Agmemdisc_s { /* memory allocator */
+ void *(*open) (void); /* independent of other resources */
+ void *(*alloc) (void *state, size_t req);
+ void *(*resize) (void *state, void *ptr, size_t old, size_t req);
+ void (*free) (void *state, void *ptr);
+ void (*close) (void *state);
+};
+
+struct Agiddisc_s { /* object ID allocator */
+ void *(*open) (Agraph_t * g); /* associated with a graph */
+ long (*map) (void *state, int objtype, char *str, unsigned long *id,
+ int createflag);
+ long (*alloc) (void *state, int objtype, unsigned long id);
+ void (*free) (void *state, int objtype, unsigned long id);
+ char *(*print) (void *state, int objtype, unsigned long id);
+ void (*close) (void *state);
+};
+
+struct Agiodisc_s {
+ int (*afread) (void *chan, char *buf, int bufsize);
+ int (*putstr) (void *chan, char *str);
+ int (*flush) (void *chan); /* sync */
+ /* error messages? */
+};
+
+struct Agdisc_s { /* user's discipline */
+ Agmemdisc_t *mem;
+ Agiddisc_t *id;
+ Agiodisc_t *io;
+};
+
+ /* default resource disciplines */
+extern Agmemdisc_t AgMemDisc;
+extern Agiddisc_t AgIdDisc;
+extern Agiodisc_t AgIoDisc;
+
+extern Agdisc_t AgDefaultDisc;
+
+struct Agdstate_s {
+ void *mem;
+ void *id;
+ /* IO must be initialized and finalized outside Cgraph,
+ * and channels (FILES) are passed as void* arguments. */
+};
+
+typedef void (*agobjfn_t) (Agraph_t * g, Agobj_t * obj, void *arg);
+typedef void (*agobjupdfn_t) (Agraph_t * g, Agobj_t * obj, void *arg,
+ Agsym_t * sym);
+
+struct Agcbdisc_s {
+ struct {
+ agobjfn_t ins;
+ agobjupdfn_t mod;
+ agobjfn_t del;
+ } graph, node, edge;
+};
+
+struct Agcbstack_s { /* object event callbacks */
+ Agcbdisc_t *f; /* methods */
+ void *state; /* closure */
+ Agcbstack_t *prev; /* kept in a stack, unlike other disciplines */
+};
+
+struct Agclos_s {
+ Agdisc_t disc; /* resource discipline functions */
+ Agdstate_t state; /* resource closures */
+ Dict_t *strdict; /* shared string dict */
+ unsigned long seq[3]; /* local object sequence number counter */
+ Agcbstack_t *cb; /* user and system callback function stacks */
+ unsigned char callbacks_enabled; /* issue user callbacks or hold them? */
+ Dict_t *lookup_by_name[3];
+ Dict_t *lookup_by_id[3];
+};
+
+struct Agraph_s {
+ Agobj_t base;
+ Agdesc_t desc;
+ Dtlink_t link;
+ Dict_t *n_seq; /* the node set in sequence */
+ Dict_t *n_id; /* the node set indexed by ID */
+ Dict_t *e_seq, *e_id; /* holders for edge sets */
+ Dict_t *g_dict; /* subgraphs - descendants */
+ Agraph_t *parent, *root; /* subgraphs - ancestors */
+ Agclos_t *clos; /* shared resources */
+};
+
+
+#if _PACKAGE_ast
+/* fine control of object callbacks */
+# if defined(_BLD_agraph) && defined(__EXPORT__)
+# define extern __EXPORT__
+# endif
+# if !defined(_BLD_agraph) && defined(__IMPORT__)
+# define extern __IMPORT__
+# endif
+#endif
+
+extern void agpushdisc(Agraph_t * g, Agcbdisc_t * disc, void *state);
+extern int agpopdisc(Agraph_t * g, Agcbdisc_t * disc);
+extern int agcallbacks(Agraph_t * g, int flag); /* return prev value */
+
+/* graphs */
+extern Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * disc);
+extern int agclose(Agraph_t * g);
+extern Agraph_t *agread(void *chan, Agdisc_t * disc);
+extern void agreadline(int);
+extern void agsetfile(char *);
+extern Agraph_t *agconcat(Agraph_t * g, void *chan, Agdisc_t * disc);
+extern int agwrite(Agraph_t * g, void *chan);
+extern int agisdirected(Agraph_t * g);
+extern int agisundirected(Agraph_t * g);
+extern int agisstrict(Agraph_t * g);
+
+/* nodes */
+extern Agnode_t *agnode(Agraph_t * g, char *name, int createflag);
+extern Agnode_t *agidnode(Agraph_t * g, unsigned long id, int createflag);
+extern Agnode_t *agsubnode(Agraph_t * g, Agnode_t * n, int createflag);
+extern Agnode_t *agfstnode(Agraph_t * g);
+extern Agnode_t *agnxtnode(Agraph_t * g, Agnode_t * n);
+extern Agnode_t *aglstnode(Agraph_t * g);
+extern Agnode_t *agprvnode(Agraph_t * g, Agnode_t * n);
+
+extern Agsubnode_t *agsubrep(Agraph_t * g, Agnode_t * n);
+
+/* edges */
+extern Agedge_t *agedge(Agraph_t * g, Agnode_t * t, Agnode_t * h,
+ char *name, int createflag);
+extern Agedge_t *agidedge(Agraph_t * g, Agnode_t * t, Agnode_t * h,
+ unsigned long id, int createflag);
+extern Agedge_t *agsubedge(Agraph_t * g, Agedge_t * e, int createflag);
+extern Agedge_t *agfstin(Agraph_t * g, Agnode_t * n);
+extern Agedge_t *agnxtin(Agraph_t * g, Agedge_t * e);
+extern Agedge_t *agfstout(Agraph_t * g, Agnode_t * n);
+extern Agedge_t *agnxtout(Agraph_t * g, Agedge_t * e);
+extern Agedge_t *agfstedge(Agraph_t * g, Agnode_t * n);
+extern Agedge_t *agnxtedge(Agraph_t * g, Agedge_t * e, Agnode_t * n);
+
+/* generic */
+extern Agraph_t *agraphof(void *);
+extern char *agnameof(void *);
+extern int agrelabel(void *obj, char *name); /* scary */
+extern int agrelabel_node(Agnode_t * n, char *newname);
+extern int agdelete(Agraph_t * g, void *obj);
+extern long agdelsubg(Agraph_t * g, Agraph_t * sub); /* could be agclose */
+extern int agdelnode(Agraph_t * g, Agnode_t * arg_n);
+extern int agdeledge(Agraph_t * g, Agedge_t * arg_e);
+extern Agobj_t *agrebind(Agraph_t * g, Agobj_t * obj);
+extern int agobjkind(void *);
+
+/* strings */
+extern char *agstrdup(Agraph_t *, char *);
+extern char *agstrdup_html(Agraph_t *, char *);
+extern int aghtmlstr(char *);
+extern char *agstrbind(Agraph_t * g, char *);
+extern int agstrfree(Agraph_t *, char *);
+extern char *agstrcanon(char *, char *);
+char *agcanonStr(char *str); /* manages its own buf */
+
+/* definitions for dynamic string attributes */
+struct Agattr_s { /* dynamic string attributes */
+ Agrec_t h; /* common data header */
+ Dict_t *dict; /* shared dict to interpret attr field */
+ char **str; /* the attribute string values */
+};
+
+struct Agsym_s { /* symbol in one of the above dictionaries */
+ Dtlink_t link;
+ char *name; /* attribute's name */
+ char *defval; /* its default value for initialization */
+ int id; /* its index in attr[] */
+ unsigned char kind; /* referent object type */
+ unsigned char fixed; /* immutable value */
+};
+
+struct Agdatadict_s { /* set of dictionaries per graph */
+ Agrec_t h; /* installed in list of graph recs */
+ struct {
+ Dict_t *n, *e, *g;
+ } dict;
+};
+
+extern Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value);
+extern Agsym_t *agattrsym(void *obj, char *name);
+extern Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr);
+extern int agcopyattr(void *, void *);
+
+extern void *agbindrec(void *obj, char *name, unsigned int size,
+ int move_to_front);
+extern Agrec_t *aggetrec(void *obj, char *name, int move_to_front);
+extern int agdelrec(void *obj, char *name);
+extern void aginit(Agraph_t * g, int kind, char *rec_name, int rec_size,
+ int move_to_front);
+extern void agclean(Agraph_t * g, int kind, char *rec_name);
+
+extern char *agget(void *obj, char *name);
+extern char *agxget(void *obj, Agsym_t * sym);
+extern int agset(void *obj, char *name, char *value);
+extern int agxset(void *obj, Agsym_t * sym, char *value);
+extern int agsafeset(void* obj, char* name, char* value, char* def);
+
+/* defintions for subgraphs */
+extern Agraph_t *agsubg(Agraph_t * g, char *name, int cflag); /* constructor */
+extern Agraph_t *agidsubg(Agraph_t * g, unsigned long id, int cflag); /* constructor */
+extern Agraph_t *agfstsubg(Agraph_t * g), *agnxtsubg(Agraph_t * subg);
+extern Agraph_t *agparent(Agraph_t * g), *agroot(Agraph_t * g);
+
+/* set cardinality */
+extern int agnnodes(Agraph_t * g), agnedges(Agraph_t * g);
+extern int agdegree(Agraph_t * g, Agnode_t * n, int in, int out);
+
+/* memory */
+extern void *agalloc(Agraph_t * g, size_t size);
+extern void *agrealloc(Agraph_t * g, void *ptr, size_t oldsize,
+ size_t size);
+extern void agfree(Agraph_t * g, void *ptr);
+extern struct _vmalloc_s *agheap(Agraph_t * g);
+
+/* an engineering compromise is a joy forever */
+extern void aginternalmapclearlocalnames(Agraph_t * g);
+
+#define agnew(g,t) ((t*)agalloc(g,sizeof(t)))
+#define agnnew(g,n,t) ((t*)agalloc(g,(n)*sizeof(t)))
+
+/* error handling */
+typedef enum { AGWARN, AGERR, AGMAX, AGPREV } agerrlevel_t;
+extern agerrlevel_t agerrno;
+extern void agseterr(agerrlevel_t);
+extern char *aglasterr(void);
+extern int agerr(agerrlevel_t level, char *fmt, ...);
+extern void agerrorf(char *fmt, ...);
+extern void agwarningf(char *fmt, ...);
+extern int agerrors(void);
+
+/* data access macros */
+/* this assumes that e[0] is out and e[1] is inedge, see edgepair in edge.c */
+#define AGIN2OUT(e) ((e)-1)
+#define AGOUT2IN(e) ((e)+1)
+#define AGOPP(e) ((AGTYPE(e)==AGINEDGE)?AGIN2OUT(e):AGOUT2IN(e))
+#define AGMKOUT(e) (AGTYPE(e) == AGOUTEDGE? (e): AGIN2OUT(e))
+#define AGMKIN(e) (AGTYPE(e) == AGINEDGE? (e): AGOUT2IN(e))
+#define AGTAIL(e) (AGMKIN(e)->node)
+#define AGHEAD(e) (AGMKOUT(e)->node)
+#define agtail(e) AGTAIL(e)
+#define aghead(e) AGHEAD(e)
+#define agopp(e) AGOPP(e)
+
+#define TAILPORT_ID "tailport"
+#define HEADPORT_ID "headport"
+
+#if _PACKAGE_ast
+# if !defined(_BLD_agraph) && defined(__IMPORT__)
+# define extern __IMPORT__
+# endif
+#endif
+
+extern Agdesc_t Agdirected, Agstrictdirected, Agundirected,
+ Agstrictundirected;
+
+#undef extern
+#if _PACKAGE_ast
+_END_EXTERNS_
+#endif
+#endif