--- /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 *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AGXBUF_H
+#define AGXBUF_H
+
+/* Extensible buffer:
+ * Malloc'ed memory is never released until agxbfree is called.
+ */
+ typedef struct {
+ unsigned char *buf; /* start of buffer */
+ unsigned char *ptr; /* next place to write */
+ unsigned char *eptr; /* end of buffer */
+ int dyna; /* true if buffer is malloc'ed */
+ } agxbuf;
+
+/* agxbinit:
+ * Initializes new agxbuf; caller provides memory.
+ * Assume if init is non-null, hint = sizeof(init[])
+ */
+ extern void agxbinit(agxbuf * xb, unsigned int hint,
+ unsigned char *init);
+
+/* agxbput_n:
+ * Append string s of length n into xb
+ */
+ extern int agxbput_n(agxbuf * xb, char *s, unsigned int n);
+
+/* agxbput:
+ * Append string s into xb
+ */
+ extern int agxbput(agxbuf * xb, char *s);
+
+/* agxbfree:
+ * Free any malloced resources.
+ */
+ extern void agxbfree(agxbuf * xb);
+
+/* agxbpop:
+ * Removes last character added, if any.
+ */
+ extern int agxbpop(agxbuf * xb);
+
+/* agxbmore:
+ * Expand buffer to hold at least ssz more bytes.
+ */
+ extern int agxbmore(agxbuf * xb, int unsigned ssz);
+
+/* agxbputc:
+ * Add character to buffer.
+ * int agxbputc(agxbuf*, char)
+ */
+#define agxbputc(X,C) ((((X)->ptr >= (X)->eptr) ? agxbmore(X,1) : 0), \
+ (int)(*(X)->ptr++ = ((unsigned char)C)))
+
+/* agxbuse:
+ * Null-terminates buffer; resets and returns pointer to data;
+ * char* agxbuse(agxbuf* xb)
+ */
+#define agxbuse(X) (agxbputc(X,'\0'),(char*)((X)->ptr = (X)->buf))
+
+/* agxbstart:
+ * Return pointer to beginning of buffer.
+ * char* agxbstart(agxbuf* xb)
+ */
+#define agxbstart(X) ((char*)((X)->buf))
+
+/* agxblen:
+ * Return number of characters currently stored.
+ * int agxblen(agxbuf* xb)
+ */
+#define agxblen(X) (((X)->ptr)-((X)->buf))
+
+/* agxbclear:
+ * Resets pointer to data;
+ * void agxbclear(agxbuf* xb)
+ */
+#define agxbclear(X) ((void)((X)->ptr = (X)->buf))
+
+/* agxbnext:
+ * Next position for writing.
+ * char* agxbnext(agxbuf* xb)
+ */
+#define agxbnext(X) ((char*)((X)->ptr))
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
--- /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>
+
+/* The following functions take a graph and a template (node/edge/graph)
+ * and return the object representing the template within the local graph.
+ */
+static Agobj_t *subnode_search(Agraph_t * sub, Agobj_t * n)
+{
+ if (agraphof(n) == sub)
+ return n;
+ return (Agobj_t *) agsubnode(sub, (Agnode_t *) n, FALSE);
+}
+
+static Agobj_t *subedge_search(Agraph_t * sub, Agobj_t * e)
+{
+ if (agraphof(e) == sub)
+ return e;
+ return (Agobj_t *) agsubedge(sub, (Agedge_t *) e, FALSE);
+}
+
+static Agobj_t *subgraph_search(Agraph_t * sub, Agobj_t * g)
+{
+ NOTUSED(g);
+ return (Agobj_t *) sub;
+}
+
+/* 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);
+}
+
+/* external entry point (this seems to be one of those ineffective
+ * comments censured in books on programming style) */
+int agapply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
+ int preorder)
+{
+ Agobj_t *subobj;
+
+ agobjsearchfn_t objsearch;
+ switch (AGTYPE(obj)) {
+ case AGRAPH:
+ objsearch = subgraph_search;
+ break;
+ case AGNODE:
+ objsearch = subnode_search;
+ break;
+ case AGOUTEDGE:
+ case AGINEDGE:
+ objsearch = subedge_search;
+ break;
+ default:
+ abort();
+ }
+ if ((subobj = objsearch(g, obj))) {
+ rec_apply(g, subobj, fn, arg, objsearch, preorder);
+ return SUCCESS;
+ } else
+ return FAILURE;
+}