]> granicus.if.org Git - graphviz/commitdiff
Update the libgraph document to use Cgraph
authorEmden Gansner <erg@research.att.com>
Thu, 7 Mar 2013 22:17:16 +0000 (17:17 -0500)
committerEmden Gansner <erg@research.att.com>
Thu, 7 Mar 2013 22:17:16 +0000 (17:17 -0500)
doc/libgraph/Agraph.tex
doc/libgraph/Makefile
doc/libgraph/agmemread.c [new file with mode: 0644]
doc/libgraph/lgrind.sty
doc/libgraph/sccmap.tex

index c11a08bec7d81da742b3f890dcc09f46e9b407f1..c4dfc420a1d7e6fb02c26be6c674ed2a59981b8f 100644 (file)
@@ -3,17 +3,20 @@
 \usepackage{graphicx}
 \usepackage{times}
 \usepackage{lgrind}
-\author{Stephen C. North\\
+\author{Stephen C. North\thanks{Updated by Emden R. Gansner} \\
 {\small AT\&T Shannon Laboratory, Florham Park, NJ, USA}\\
 {\small north@research.att.com}
 }
-\title{Agraph Tutorial}
-\date{July 15, 2002}
+\title{Cgraph Tutorial}
+\date{1 March 2013}
 
 \begin{document}
 
 %\begin{titlepage}
 \maketitle  
+\newpage
+\tableofcontents
+\newpage
 %\thispagestyle{empty}
 %\end{titlepage}
 %\pagenumbering{arabic}
 
 \section{Introduction}
 \label{sec:introduction}
-Agraph is a C library for graph programming.
+Cgraph is a C library for graph programming.
 It defines data types and operations for graphs comprised
 of attributed nodes, edges and subgraphs.
 Attributes may be string name-value pairs for convenient
 file I/O, or internal C data structures for efficient algorithm
 implementation.
 
-Agraph is aimed at graph representation; it is not an library of
+Cgraph is aimed at graph representation; it is not an library of
 higher-level algorithms such as shortest path or network flow.
 We envision these as higher-level libraries written on top of
-Agraph.  Efforts were made in Agraph's design to strive
+Cgraph.  Efforts were made in Cgraph's design to strive
 for time and space efficiency.  The basic (unattributed) graph representation
-takes 48 bytes per node and 64 bytes per edge, so storage of graphs with
-millions of objects is reasonable.  For attributed graphs, Agraph also
+takes 104 bytes per node and 64 bytes per edge, so storage of graphs with
+millions of objects is reasonable.  For attributed graphs, Cgraph also
 maintains an internal shared string pool, so if all the nodes of a graph
-have \verb'"color"="red"', only one copy of \verb"color" and \verb"red"
+have \verb'color=red', only one copy of \verb'"color"' and \verb'"red"'
 are made.  There are other tricks that experts can exploit for
 flat-out coding efficiency.  For example, there are ways to inline the
 instructions for edge list traversal and internal data structure access.
 
-Agraph uses Phong Vo's dictionary library, libcdt, to store node
+Cgraph uses Phong Vo's dictionary library, libcdt, to store node
 and edge sets.  This library provides a uniform interface to hash
 tables and splay trees, and its API is usable for general programming
-(such as storing  multisets, hash tables, lists and queues) in Agraph
+(such as storing  multisets, hash tables, lists and queues) in Cgraph
 programs.
 
+{\bf Notation} In the following, we use \verb"TRUE" to denote a non-zero
+value, and \verb"FALSE" to denote zero.
 \section{Graph Objects}
 \label{sec:graphobjects}
-Almost all Agraph programming can be done with pointers to
+Almost all Cgraph programming can be done with pointers to
 these data types:
 
 \begin{itemize}
@@ -60,18 +65,21 @@ these data types:
 \item \verb"Agrec_t": an internal C data record attribute of a graph object
 \end{itemize}
 
-Agraph is responsible for its own memory management; allocation
-and deallocation of Agraph data structures is always done through
-Agraph calls.
+Cgraph is responsible for its own memory management; allocation
+and deallocation of Cgraph data structures is always done through
+Cgraph calls.
 
 \section{Graphs}
 \label{sec:graphs}
 A top-level graph (also called a root graph) defines a universe
 of nodes, edges, subgraphs, data dictionaries and other information.
 A graph has a name and two properties: whether it is directed or
-undirected, and whether it is strict (self-arcs and multi-edges 
-forbidden).  \footnote{It would be nice to also have a graph type allowing
-self-arcs but not multi-edges; mixed graphs could also be useful.}
+undirected, and whether it is strict (multi-edges are
+forbidden).  \footnote{It is possible to specify that a graph is simple
+(neither multi-edges nor loops), or can have multi-edges but not loops.}
+
+Note that nodes, edges and subgraphs exists in exactly one root graph. They
+cannot be used independently of that graph, or attached to another root graph.
 
 The following examples use the convention that \verb"G" and
 \verb"g" are \verb"Agraph_t*" (graph pointers), \verb"n", \verb"u",
@@ -81,20 +89,20 @@ The following examples use the convention that \verb"G" and
 To make a new, empty top-level directed graph:
 
 \begin{verbatim}
-    Agraph_t    *g;
-    g = agopen("G", Agdirected, 0);
+  Agraph_t    *g;
+  g = agopen("G", Agdirected, NULL);
 \end{verbatim}
 
 The first argument to \verb"agopen" is any string, and is not
-interpreted by Agraph, except it is recorded and preserved when
+interpreted by Cgraph, except it is recorded and preserved when
 the graph is written as a file.\footnote{An application
-could, of course, maintain its own graph catalog using graph names.} 
-The second argument is a graph type, and should be one of
+could, of course, maintain its own graph catalogue using graph names.} 
+The second argument indicates the type of graph, and should be one of
 {\tt Agdirected}, {\tt Agstrictdirected}, {\tt Agundirected},
 or {\tt Agstrictundirected}.
 The third argument is an optional pointer to a collection of
-methods for overriding certain default behaviors of Agraph,
-and in most situations can just be {\tt 0}.
+methods for overriding certain default behaviors of Cgraph,
+and in most situations can just be {\tt NULL}.
 
 You can get the name of a graph by \verb"agnameof(g)", and
 you can get its properties by the predicate functions
@@ -102,150 +110,201 @@ you can get its properties by the predicate functions
 
 You can also construct a new graph by reading a file:
 \begin{verbatim}
-    g = agread(stdin,0);
+  g = agread(stdin,NULL);
 \end{verbatim}
 
 Here, the graph's name, type and contents including attributes depend
 on the file contents.  (The second argument is the same optional method
 pointer mentioned above for \verb"agopen").
 
+Sometimes it is convenient to have the graph represented concretely as a 
+character string \verb"str".
+In this case, the graph can be created using:
+\begin{verbatim}
+  g = agmemread (str);
+\end{verbatim}
+
 You can write a representation of a graph to a file:
 
 \begin{verbatim}
-    g = agwrite(g,stdout);
+  g = agwrite(g,stdout);
 \end{verbatim}
 
 \verb"agwrite" creates an external representation of a graph's
 contents and attributes (except for internal attributes),
-that it can later be reconstructed by calling \verb"agread"
+that can later be reconstructed by calling \verb"agread"
 on the same file.\footnote{It is the application programmer's job to
 convert between internal attributes to external strings
 when graphs are read and written, if desired.
 This seemed better than inventing a complicated way
 to automate this conversion.}
 
-\verb"agnnodes(g)" and \verb"agnedges(g)" return the count of nodes
-and edges in a graph (or subgraph).
+\verb"agnnodes(g)", \verb"agnedges(g)" and \verb"agnsubg(g)" return the count of nodes,
+edges and (immediate) subgraphs in a graph (or subgraph).
 
 To delete a graph and its associated data structures,
-(freeing their memory):
+freeing their memory, one uses:
 \begin{verbatim}
-    agclose(g);
+  agclose(g);
 \end{verbatim}
 
 Finally, there is an interesting if obscure function to concatenate
 the contents of a graph file onto an existing graph, as shown here.
 \begin{verbatim}
-    g = agconcat(g,stdin,0);
+  g = agconcat(g,stdin,NULL);
 \end{verbatim}
 
 \section{Nodes}
 \label{sec:nodes}
-In Agraph, a node is usually identified by a unique string name
-and a unique 32-bit internal ID assigned by Agraph.
+In Cgraph, a node is usually identified by a unique string name
+and a unique internal integer ID assigned by Cgraph.
 (For convenience, you can also create "anonymous" nodes by
-giving \verb"NULL" as the node name.) A node also has in- and out-edge sets.
+giving \verb"NULL" as the node name.) A node also has in- and out-edge sets,
+even in undirected graphs.
 
 Once you have a graph, you can create or search for nodes this way:
 \begin{verbatim}
-    Agnode_t    *n;
-    n = agnode(g,"node28",TRUE);
+  Agnode_t    *n;
+  n = agnode(g,"node28",TRUE);
 \end{verbatim}
 
 The first argument is a graph or subgraph in which the node
 is to be created.  The second is the name (or NULL for anonymous nodes.)
-When the third argument is TRUE, the node is created if it doesn't
-already exist.  When it's FALSE, as shown below, then Agraph 
-searches to locate an existing node with the given name.
+When the third argument is \verb"TRUE", the node is created if it doesn't
+already exist.  When it's \verb"FALSE", as shown below, then Cgraph 
+searches to locate an existing node with the given name, returning NULL if
+none is found.
 
 \begin{verbatim}
-    n = agnode(g,"node28",FALSE);
+  n = agnode(g,"node28",FALSE);
 \end{verbatim}
 
-The function \verb"agdegree(n, in, out)" gives the degree
-of a node, where \verb"in" and \verb"out" select the edge sets.
-\verb"agdegree(n,TRUE,FALSE)" returns in-degree,
-\verb"agdegree(n,FALSE,TRUE)" returns out-degree,
-and \verb"agdegree(n,TRUE,TRUE)" returns their sum.
+The function \verb"agdegree(g, n, in, out)" gives the degree
+of a node in (sub)graph \verb"g", where \verb"in" and \verb"out" select the edge sets.
+\begin{itemize}
+\item \verb"agdegree(g,n,TRUE,FALSE)" returns the in-degree.
+\item \verb"agdegree(g,n,FALSE,TRUE)" returns the out-degree.
+\item \verb"agdegree(g,n,TRUE,TRUE)" returns their sum.
+\end{itemize}
+The function \verb"agcountuniqedges" is identical to {\tt agdegree}
+except when the last two arguments are both \verb"TRUE". In this case, a loop is only
+counted once.
 
 \verb"agnameof(n)" returns the printable string name of a node.
 Note that for various reasons this string may be a temporary
-buffer that is overwritten by subsequent calls.
-Thus, \verb'printf("%s %s\n",agnameof(agtail(e)),agnameof(aghead(e)))'
+buffer that can be overwritten by subsequent calls.
+Thus, the usage
+\begin{verbatim}
+printf("%s %s\n",agnameof(agtail(e)),agnameof(aghead(e)));
+\end{verbatim}
 is unsafe because the buffer may be overwritten when the
 arguments to printf are being computed.
 
-A node can be deleted from a graph or subgraph by \verb"agdelnode(n)".
-
-
+A node can be deleted from a graph or subgraph by \verb"agdelnode(g,n)".
 
 \section{Edges}
 \label{sec:edges}
 An edge is a node pair: an ordered pair in a directed graph,
 unordered in an undirected graph.  For convenience there is
 a common edge data structure for both kinds and the endpoints
-are the fields "tail" and "head" (but there is no special
-interpretation of these fields in an undirected graph).
-An edge is made by the 
+are the fields \verb"tail" and \verb"head". \footnote{When an edge is created,
+the first node will be used as the tail node, and the second node as the head.}
+
+Because an edge is implemented as an edge pair, there are two valid pointers
+to the same edge, so simple pointer comparison does not work for edge equality.
+The function \verb"Ageqedge(Agedge_t *e0, Agedge_t *e1)" evaluates to true if
+the two pointers represent the same abstract edge.
+
+An edge is made using
 
 \begin{verbatim}
-    Agnode_t    *u, *v;
-    Agedge_t    *e;
+  Agnode_t    *u, *v;
+  Agedge_t    *e;
     
-    /* assume u and v are already defined */
-    e = agedge(u,v,"e28",TRUE);
-
+  /* assume u and v are already defined */
+  e = agedge(g,u,v,"e28",TRUE);
 \end{verbatim}
 
 \verb"u" and \verb"v" must belong to the same graph or subgraph
 for the operation to succeed.  The ``name'' of an edge
-(more correctly, label) is treated as a unique identifier for edges
+(more correctly, identifier) is treated as a unique identifier for edges
 between a particular node pair.  That is, there can only be at most
-one edge labeled \verb"e28" between any given \verb"u" and \verb"v",
+one edge with name \verb"e28" between any given \verb"u" and \verb"v",
 but there can be many other edges \verb"e28" between other nodes.
 
-\verb"agtail(e)" and \verb"aghead(e)" return the endpoints of e.
-Alternatively, \verb"e->node" is the ``other'' endpoint
+\verb"agtail(e)" and \verb"aghead(e)" return the endpoints of \verb"e".
+If \verb"e" is created as in the call to \verb"agedge" above, \verb"u"
+will be the tail node and \verb"v" will be the head node. This holds true
+even for undirected graphs.
+
+The value \verb"e->node" is the ``other'' endpoint
 with respect to the node from which e was obtained.
-A common idiom is: {\tt for (e = agfstout(n); e; e = agnxtout(e)) f(e->node);}
+That is, if \verb"e" is an out-edge of node \verb"n" (equivalently, \verb"n"
+is the tail of \verb"e"), then \verb"e->node" is the head of \verb"e".
+A common idiom is: 
+\begin{verbatim}
+  for (e = agfstout(g,n); e; e = agnxtout(g,e)) 
+    /* do something with e->node */
+\end{verbatim}
 
 \verb"agedge" can also search for edges:
 
 \begin{verbatim}
-    e = agedge(u,v,NULL,FALSE); /* finds any u,v edge */
-    e = agedge(u,v,"e8",FALSE); /* finds a u,v edge with name "e8" */
+  /* finds any u,v edge */
+  e = agedge(g,u,v,NULL,FALSE); 
+  /* finds a u,v edge with name "e8" */
+  e = agedge(g,u,v,"e8",FALSE); 
 \end{verbatim}
 
-An edge can be deleted from a graph or subgraph by \verb"agdeledge(e)".  
+In an undirected graph, an edge search will consider the given vertices
+as both tail and head nodes.
+
+An edge can be deleted from a graph or subgraph by \verb"agdeledge(g,e)".  
+The \verb"agnameof" function can be used to get the ``name'' of an edge.
+Note that this will be the identifier string provided at edge creation. 
+The names
+of the head and tail nodes will not be part of the string. In addition, it
+returns NULL for anonymous edges.
 
 \section{Traversals}
 \label{sec:traversals}
 
-Agraph has functions for walking graph objects.
+Cgraph has functions for iterating over graph objects.
 For example, we can scan all the edges of a graph (directed
 or undirected) by the following:
 
 \begin{verbatim}
-    for (n = agfstnode(g); n; n = agnxtnode(n)) {
-        for (e = agfstout(n); e; n = agnxtout(e)) {
-            /* do something with e */
-        }
+  for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
+    for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
+      /* do something with e */
     }
+  }
 \end{verbatim}
+\label{traversal}
 
-The functions \verb"agfstin(n)" and \verb"afnxtin(e)" are
+The functions \verb"agfstin(g,n)" and \verb"afnxtin(g,e)" are
 provided for walking in-edge lists.
 
-In the case of a directed edge, the meaning of ``out'' is somewhat
-obvious.  For undirected graphs, Agraph assigns an arbitrary internal
-orientation to all edges for its internal bookkeeping. (It's from
-lower to higher internal ID.)
+In the case of a directed edge, the meanings of ``in'' and ``out'' are 
+obvious.  For undirected graphs, Cgraph assigns an 
+orientation based on the analogous order of the two nodes when the edge
+is created.
 
 To visit all the edges of a node in an undirected graph:
 
 \begin{verbatim}
-    for (e = agfstedge(n); e; n = agnxtedge(e,n))
-        /* do something with e */
+  for (e = agfstedge(g,n); e; e = agnxtedge(g,e,n))
+    /* do something with e */
+\end{verbatim}
+
+Be careful if your code deletes an edge or node during the traversal, as
+then the object will no longer be valid to get the next object. 
+This is typically handled by code like:
+\begin{verbatim}
+  for (e = agfstedge(g,n); e; e = f) { 
+    f = agnxtedge(g,e,n))
+    /* delete e */
+  }
 \end{verbatim}
 
 Traversals are guaranteed to visit the nodes of a graph, or edges of a node,
@@ -256,27 +315,25 @@ to override object ordering, as mentioned in section~\ref{sec:openissues}).
 \label{sec:externalattributes}
 
 Graph objects may have associated string name-value pairs.  
-When a graph file is read, Agraph's parser takes care of 
-the details of this, so attributed can just be added
+When a graph file is read, Cgraph's parser takes care of 
+the details of this, so attributes can just be added
 anywhere in the file.  In C programs, values must be
 declared before use.
 
-Agraph assumes that all objects of a given kind (graphs/subgraphs,
+Cgraph assumes that all objects of a given kind (graphs/subgraphs,
 nodes, or edges) have the same attributes - there's no notion of
 subtyping within attributes.   Information about attributes is 
 stored in data dictionaries.  Each graph has three (for
 graphs/subgraphs, nodes, and edges) for which you'll need the
-helpful predefined constants AGRAPH, AGNODE and AGEDGE in
+predefined constants AGRAPH, AGNODE and AGEDGE in
 calls to create, search and walk these dictionaries.
 
-To create an attribute:
-
+Thus, to create an attribute for nodes, one uses:
 \begin{verbatim}
-    Agsym_t *sym;
-    sym = agattr(g,AGNODE,"shape","box");
+  Agsym_t *sym;
+  sym = agattr(g,AGNODE,"shape","box");
 \end{verbatim}
-
-If this succeeeds, \verb"sym" points to a descriptor for the 
+If this succeeds, \verb"sym" points to a descriptor for the 
 newly created (or updated) attribute.  (Thus, even if \verb"shape"
 was previously declared and had some other default value,
 it would be set to \verb"box" by the above.)
@@ -284,90 +341,139 @@ it would be set to \verb"box" by the above.)
 By using a NULL pointer as the value,
 you can use the same function to search the attribute definitions of a graph.
 \begin{verbatim}
-    sym = agattr(g,AGNODE,"shape",0);
-    if (sym) printf("The default shape is %s.\n",sym->defval);
+  sym = agattr(g,AGNODE,"shape",0);
+  if (sym) 
+    printf("The default shape is %s.\n",sym->defval);
+\end{verbatim}
+If you have the pointer to some graph object, you can also use the function
+\verb"agattrsym".  
+\begin{verbatim}
+  Agnode_t* n;
+  Agsym_t* sym = agattrsym (n,"shape");
+  if (sym) 
+    printf("The default shape is %s.\n",sym->defval);
 \end{verbatim}
+Both functions return NULL if the attribute is not defined.
 
 Instead of looking for a particular attribute, it is possible to
 iterate over all of them:
 
 \begin{verbatim}
-    sym = 0;    /* to get the first one */
-    while (sym = agnxtattr(g,AGNODE,sym)
-       printf("%s = %s\n",sym->name,sym->defval);
+  sym = 0;    /* to get the first one */
+  while (sym = agnxtattr(g,AGNODE,sym)
+    printf("%s = %s\n",sym->name,sym->defval);
 \end{verbatim}
 
 Assuming an attribute already exists for some object, its value can be
-obtained, either using the string name or an \verb"Agsym_t*" as an index.
-To use the string name:
+obtained or set using its string name or its \verb"Agsym_t" descriptor.
+To use the string name, we have:
 
 \begin{verbatim}
-    str = agget(n,"shape");
-    agset(n,"shape","hexagon");
+  str = agget(n,"shape");
+  agset(n,"shape","hexagon");
 \end{verbatim}
 
 If an attribute will be referenced often, it is faster to
 use its descriptor as an index, as shown here:
 
 \begin{verbatim}
-    Agsym_t *sym;
-    sym = agattr(g,AGNODE,"shape","box");
-    str = agxget(n,sym);
-    agxset(n,sym,"hexagon");
+  Agsym_t *sym = agattr(g,AGNODE,"shape","box");
+  str = agxget(n,sym);
+  agxset(n,sym,"hexagon");
 \end{verbatim}
 
+Cgraph provides two helper functions for dealing with attributes. The function
+\verb"agsafeset(void *obj, char *name, char *value, char *def)" first checks
+that the attribute has been defined, defining it with the default value \verb"def"
+if not. It then uses \verb"value" as the specific value assigned to \verb"obj".
+
+It is sometimes useful to copy all of the values from one object to another. This can
+be easily done using \verb"agcopyattr(void *src, void* tgt)". This assumes that the
+source and target are the same type of graph objects, and that the attributes of
+\verb"src" have already been defined for \verb"tgt". If \verb"src" and \verb"tgt"
+belong to the same root graph, this will automatically be true.
+
 \section{Internal Attributes}
 \label{sec:internalattributes}
 
-Each graph object (graph, node or edge) may have a list of
+It would be possible to do everything using just string-valued
+attributes. In general, though, this will be too inefficient.
+To deal with this,
+each graph object (graph, node or edge) may have a list of
 associated internal data records.  The layout of each such
 record is programmer-defined, except each must have an
 \verb"Agrec_t" header.  The records are allocated through
-Agraph.  For example:
+Cgraph.  For example:
 
 \begin{verbatim}
-typedef struct mynode_s {
+  typedef struct mynode_s {
     Agrec_t     h;
     int         count;
-} mynode_t;
-
-    mynode_t    *data;
-    Agnode_t        *n;
-    n = agnode(g,"mynodename",TRUE);
-    data = (mynode_t*)agbindrec(n,"mynode_t",sizeof(mynode_t),FALSE);
-    data->count = 1;
+  } mynode_t;
+
+  mynode_t    *data;
+  Agnode_t    *n;
+  n = agnode(g,"mynodename",TRUE);
+  data = (mynode_t*)agbindrec(n,"mynode_t",
+    sizeof(mynode_t),FALSE);
+  data->count = 1;
 \end{verbatim}
 
-In a similar way, \verb"aggetrec" searches for a record that must already
-exist; \verb"agdelrec" removes a record from an object. 
+In a similar way, \verb"aggetrec" searches for a record, returning a pointer
+to the record if it exists and NULL otherwise;
+\verb"agdelrec" removes a record from an object. 
 
-Two other points:
+Although each graph object may have its own unique, individual collection
+of records, for convenience, there are functions that update an entire graph
+by allocating or removing the same record from all nodes,
+edges or subgraphs at the same time.  These functions are:
 
-1. For convenience, there is a way to ``lock'' the data pointer of
-a graph object to point to a given record.  In the above example,
+\begin{verbatim}
+  void aginit(Agraph_t *g, int kind, char *rec_name,
+              int rec_size, int move_to_front);
+  void agclean(Agraph_t *g, int kind, char *rec_name);
+\end{verbatim}
+
+Note that in addition to \verb"agdelrec" and \verb"agclean", records are removed
+and their storage freed when their associated graph object is deleted. Only the
+record data structure is freed. If the application has attached any additional heap
+memory to a record, it is the responsibility of the application to handle this before
+the actual record is deleted.
+
+For further efficiency, there is a way to ``lock'' the data pointer of
+a graph object to point to a given record.  This can be done by using \verb"TRUE"
+as the last argument in \verb"agbindrec", \verb"aginit" or \verb"aggetrec".
+If this is done, in the above example
 we could then simply cast this pointer to the appropriate type
 for direct (un-typesafe) access to the data.
 
 \begin{verbatim}
-    (mydata_t*) (n->base.data)->count = 1;
+  (mydata_t*) (n->base.data)->count = 1;
 \end{verbatim}
 
-Although each graph object may have its own unique, individual collection
-of records, for convenience, there are functions that update an entire graph
-by allocating or removing the same record from all nodes,
-edges or subgraphs at the same time.  These functions are:
+Typically, it is convenient to encapsulate this access using macros. For example,
+we may have:
+\begin{verbatim}
+  #define ND_count(n) (((mydata_t*)(AGDATA(n)))->count)
+  ND_count(n) = 1;
+\end{verbatim}
 
+As this is unsafe if the record was not allocated for some object, it is good form
+to two versions of the macro:
 \begin{verbatim}
-void aginit(Agraph_t *g, int kind, char *rec_name,
-   int rec_size, int move_to_front);
-void agclean(Agraph_t *g, int kind, char *rec_name);
+  #ifdef DEBUG
+  #define ND_count(n) \
+    (assert(aggetrec(n,"mynode_t",1)),((mynode_t*)(AGDATA(n)))->count)
+  #else
+  #define ND_count(n) (((mydata_t*)(AGDATA(n)))->count)
+  #endif
 \end{verbatim}
 
 \section{Subgraphs}
 \label{sec:subgraphs}
-Subgraphs are an important construct in Agraph.  They are intended for
-organizing subsets of graph objects and can be used interchangably with
-top-level graphs in almost all Agraph functions.
+Subgraphs are an important construct in Cgraph.  They are intended for
+organizing subsets of graph objects and can be used interchangeably with
+top-level graphs in almost all Cgraph functions.
 
 A subgraph may contain any nodes or edges of its parent.
 (When an edge is inserted in a subgraph, its nodes
@@ -375,120 +481,233 @@ are also implicitly inserted if necessary.  Similarly,
 insertion of a node or edge automatically implies
 insertion in all containing subgraphs up to the root.)
 Subgraphs of a graph form a hierarchy (a tree).
-Agraph has functions to create, search, and walk subgraphs.
-
-\begin{verbatim}
-Agraph_t     *agfstsubg(Agraph_t *g);
-Agraph_t     *agnxtsubg(Agraph_t *subg);
-\end{verbatim}
+Cgraph has functions to create, search, and iterate over subgraphs.
 
 For example,
 \begin{verbatim}
-Agraph_t *g, *h0, *h1;
-g = agread(stdin,0);
-
-h0 = agsubg(g,"mysubgraph",FALSE);  /* search for subgraph by name */
-h1 = agsubg(g,"mysubgraph",TRUE);   /* create subgraph by name */
-
-assert (g == agparent(h1));     /* agparent is up one level */
-assert (g == agroot(h1));       /* agroot is the top level graph */
-
+  Agraph_t *g, *h;
+
+    /* search for subgraph by name */
+  h = agsubg(g,"mysubgraph",FALSE);  
+  if (!h) 
+      /* create subgraph by name */
+    h = agsubg(g,"mysubgraph",TRUE);   
+
+  for (h = agfstsubg(g); h; h = agnxtsubg(h)) {
+      /* agparent is up one level */
+    assert (g == agparent(h));     
+    /* Use subgraph h */
+  }
 \end{verbatim}
 
-The functions \verb"agsubnode" and \verb"agsubedge" take a subgraph
-pointer, and a pointer to an object from another subgraph of the same
-graph (or possibly a top-level object) and rebind the pointer to a
-copy of the object from the requested subgraph.  If \verb"createflag"
-is nonzero, then the object is created if necessary; otherwise the
-request is only treated as a search and returns 0 for failure.
+The function \verb"agparent" returns the (sub)graph immediately containing the
+argument subgraph. The iteration done using \verb"agfstsubg" and \verb"agnxtsubg" 
+returns only immediate subgraphs. To find subgraphs further down the hierarchy 
+requires a recursive search.
 
+It is not uncommon to want to populate a subgraph with nodes and edges that have
+already been created. This can be done using
+the functions \verb"agsubnode" and \verb"agsubedge", 
 \begin{verbatim}
-Agnode_t *agsubnode(Agraph_t *g, Agnode_t *n, int createflag);
-Agedge_t *agsubedge(Agraph_t *g, Agedge_t *e, int createflag);
+  Agnode_t *agsubnode(Agraph_t *g, Agnode_t *n, int create);
+  Agedge_t *agsubedge(Agraph_t *g, Agedge_t *e, int create);
 \end{verbatim}
+which take a subgraph,
+and an object from another subgraph of the same
+graph (or possibly a top-level object) and add it to the argument subgraph
+if the \verb"create" flag is \verb"TRUE".
+It is also added to all enclosing subgraphs, if necessary.
+If the \verb"create" flag is \verb"FALSE", then the
+request is only treated as a search and returns NULL for failure.
 
 A subgraph can be removed by \verb"agdelsubg(g,subg)" or by
 \verb"agclose(subg)".
 
-When a node is in more than one subgraph, distinct node structures
-are allocated for each instance.  Thus, node pointers comparison cannot 
-meaningfully be used for testing equality if the pointers could have
-come from different subgraphs - use ID instead.
-
-\begin{verbatim}
-    if (u == v) /* wrong */
-    if (AGID(u) == AGID(v))  /* right */
-\end{verbatim}
-
 \section{Utility Functions and Macros}
 \label{sec:utilityfunctionsandmacros}
 
-For convenience, Agraph provides some polymorphic functions and macros
-that apply to all Agraph objects.   (Most of these functions could
+For convenience, Cgraph provides some polymorphic functions and macros
+that apply to all Cgraph objects.   (Most of these functions could
 be implemented in terms of others already described, or by accessing
 fields in the \verb"Agobj_t" base object.
 
 \begin{itemize}
-\item \verb"AGTYPE(obj)":  object type AGRAPH, AGNODE, or AGEDGE
-(a small integer)
+\item \verb"AGTYPE(obj)":  object type - AGRAPH, AGNODE, or AGEDGE
 \item \verb"AGID(obj)": internal object ID (an unsigned long)
 \item \verb"AGSEQ(obj)": object creation timestamp (an integer)
 \item \verb"AGDATA(obj)": data record pointer (an \verb"Agrec_t*")
 \end{itemize}
 
-Other functions, as listed below, return the graph of an object,
-its string name, test whether it is a root graph object, and
-provide a polymorphic interface to remove objects.
+Other useful functions include:
+\begin{verbatim}
+    /* Returns root graph of obj */
+  Agraph_t *agroot(void* obj);        
+    /* Returns root graph of obj or obj if a (sub)graph */
+  Agraph_t *agraphof(void* obj);      
+    /* True of obj belongs to g */
+  int agcontains(Agraph_t *g, void *obj);  
+    /* Delete obj from the (sub)graph */
+  int agdelete(Agraph_t *g, void *obj);    
+    /* Synonym of AGTYPE */
+  int agobjkind(void *obj);           
+\end{verbatim}
+A root graph \verb"g" will always have
 \begin{verbatim}
-Agraph_t *agraphof(void*);
-char *agnameof(void*);
-int  agisarootobj(void*);
-int  agdelete(Agraph_t *g, void *obj);
+  g == agroot(g) == agraphof(g)
 \end{verbatim}
 
-\section{Expert-level tweaks}
+\section{Error Handling}
+\label{sec:errorhandling}
+
+Cgraph provides some basic error handling functions, hampered by the
+lack of exceptions in C. At present, there are basically two types of anomalies: 
+warnings and errors. 
+
+To report an anomaly, one uses:
+\begin{verbatim}
+  typedef enum { AGWARN, AGERR, AGMAX, AGPREV 
+  } agerrlevel_t;
+
+  int agerr(agerrlevel_t level, const char *fmt, ...);
+\end{verbatim}
+The \verb"agerr" function has a \verb"printf"-interface, with the first argument
+indicating the severity of the problem.
+A message is only written if its severity is higher than a programmer-controlled minimum, 
+which is AGWARN by default. The programmer can set this value using \verb"agseterr", 
+which returns the previous value. Calling \verb"agseterr(AGMAX)" turns off the writing of messages.
+
+Sometimes additional context information is only available in functions calling the function 
+where the error is actually caught. In this case, the calling function can indicate that it 
+is continuing the current error by using \verb"AGPREV" as the first argument.
+
+The function \verb"agwarningf" is shorthand for \verb"agerr(AGWARN,...)"; similarly,
+\verb"agerrorf" is shorthand for \verb"agerr(AGERR,...)".
+
+Some applications desire to directly control the writing of messages. Such an application can 
+use the function \verb"agseterrf" to register a function that the library should call to actually 
+write the message:
+\begin{verbatim}
+  typedef int (*agusererrf) (char*);
+
+  agusererrf agseterrf(agusererrf);
+\end{verbatim}
+The previous error function is returned. By default, the messages are written to \verb"stderr".
+Errors not written are stored in a log file. The last recorded error can be retrieved by 
+calling \verb"aglasterr".
+The function \verb"agerrors" returns the maximum severity reported to \verb"agerr".
+The function \verb"agreseterrors" is identical, except it also resets the error level
+as though no errors have been reported.
+
+\section{Strings}
+\label{sec:strings}
+As mentioned, Cgraph maintains a reference-counted shared string pool for each graph.  
+As there are often many identical strings used in a graph, this helps to reduce the
+memory overhead. 
+\begin{verbatim}
+  char *agstrdup(Agraph_t *, char *);
+  char *agstrbind(Agraph_t *, char*);
+  int          agstrfree(Agraph_t *, char *);
+
+  char *agstrdup_html(Agraph_t *, char *);
+  int          aghtmlstr(char *);
+  
+  char *agcanonStr(char *str);
+  char *agstrcanon(char *, char *);
+  char *agcanon(char *, int);
+\end{verbatim}
+Cgraph has functions to directly create and destroy references to shared strings.
+As with any reference-counted object, you can use these as ordinary
+strings, though the data should not be modified. If you need to store the pointer
+in some data structure, you should call \verb"agstrdup(g,s)". This will create a 
+new copy of \verb"s" if necessary, and increment
+the count of references, ensuring that the string will not be freed by some
+other part of the program while you are still using it. Since  \verb"agstrdup" makes
+a copy of the string, the argument string can use temporary storage.
+
+A call to \verb"agstrfree(g,s)" decrements the reference count and, if this becomes
+zero, frees the string.
+The function \verb"agstrbind(g,s)" checks if a shared string identical to \verb"s" exists
+and, if so, returns it. Otherwise, it returns NULL.
+
+The DOT language supports a special type of string, containing HTML-like markups. To make
+sure that the HTML semantics are used, the application should call \verb"agstrdup_html(g,s)"
+rather than \verb"agstrdup(g,s)". The following code makes sure the node's label will be
+interpreted as an HTML-like string and appear as a table. If \verb"agstrdup" were used,
+the label would appear as the literal string \verb"s".
+\begin{verbatim}
+  Agraph_t* g;
+  Agnode_t* n;
+  char* s = "<TABLE><TR><TD>one cell</TD></TR></TABLE>";
+  agset (n, "label", agsgtrdup_html (g,s));
+\end{verbatim}
+The predicate \verb"aghtmlstr" returns \verb"TRUE" if the argument string is marked as an
+HTML-like string. {\bf N.B.} This is only valid if the argument string is a shared string.
+HTML-like strings are also freed using \verb"agstrfree".
+
+The DOT language uses various special characters and escape sequences. When writing out
+strings as concrete text, it is important that these lexical features are used in order
+that the string can be re-read as DOT and be interpreted correctly.
+Cgraph provides three functions to handle this. The simplest is \verb"agcanonStr(s)". 
+It returns a pointer to a canonical version of the input string. It uses an internal 
+buffer, so the returned string should be written or copied before another call to 
+\verb"agcanonStr". \verb"agstrcanon(s,buf)" is identical, except the calling function
+also supplies a buffer where the canonical version may be written. An application should only use
+the returned pointer, as it is possible the buffer will not be used at all. The buffer
+needs to be large enough to hold the canonical version. Normally, an expansion of 
+\verb"2*strlen(s)+2" is sufficient.
+
+Both \verb"agcanonStr" and \verb"agstrcanon" assume that string argument is a
+shared string. For convenience, the library also provides the function \verb"agcanon(s,h)".
+This is identical to \verb"agcanonStr(s)", except \verb"s" can be any string. If \verb"h"
+is \verb"TRUE", the canonicalization assumes \verb"s" is an HTML-like string.
+
+\section{Expert-level Tweaks}
 \label{sec:expertleveltweaks}
 
-{\bf Callbacks.}
+\subsection{Callbacks}
+\label{subsec:callbacks}
+
 There is a way to register client functions to be called
-whenever graph objects are inserted, or modified, or are
-about to be deleted from a graph or subgraph
+whenever graph objects are inserted into or deleted from a graph or subgraph,
+or have their string attributes modified
 The arguments to the callback functions for insertion and
-deletion (an \verb"agobjfnt") are the object and a pointer
-to a closure (a piece of data controlled by the client).
+deletion (an \verb"agobjfn_t") are the containing (sub)graph, the object and a pointer
+to a piece of state data supplied by the application.
 The object update callback (an \verb"agobjupdfn_t") also
 receives the data dictionary entry pointer for the
 name-value pair that was changed.
+The graph argument will be the root graph.
 
 \begin{verbatim}
-typedef void    (*agobjfn_t)(Agobj_t *obj, void *arg);
-typedef void    (*agobjupdfn_t)(Agobj_t *obj, void *arg, Agsym_t *sym);
+  typedef void (*agobjfn_t)(Agraph_t*, Agobj_t*, void*);
+  typedef void (*agobjupdfn_t)(Agraph_t*, Agobj_t*, 
+                void*, Agsym_t*);
 
-struct Agcbdisc_s {
+  struct Agcbdisc_s {
     struct {
-        agobjfn_t       ins;
-        agobjupdfn_t    mod;
-        agobjfn_t       del;
+      agobjfn_t       ins;
+      agobjupdfn_t    mod;
+      agobjfn_t       del;
     } graph, node, edge;
-;
+  };
 \end{verbatim}
 
 Callback functions are installed by \verb"agpushdisc", which also takes
-a pointer to a closure or client data structure \verb"state" that is
+a pointer to the client data structure \verb"state" that is
 later passed to the callback function when it is invoked.
 
 \begin{verbatim}
-void         agpushdisc(Agraph_t *g, Agcbdisc_t *disc, void *state);
+  agpushdisc(Agraph_t *g, Agcbdisc_t *disc, void *state);
 \end{verbatim}
 
-Callbacks are removed by \verb"agpopdisc" [sic], which deletes a
+Callbacks are removed by \verb"agpopdisc", which deletes a
 previously installed set of callbacks anywhere in the stack.
-This function returns zero for success.  (In real life this
+This function returns zero for success.  (In real life, this
 function isn't used much; generally callbacks are set up and
 left alone for the lifetime of a graph.)
 
 \begin{verbatim}
-int          agpopdisc(Agraph_t *g, Agcbdisc_t *disc);
+  int   agpopdisc(Agraph_t *g, Agcbdisc_t *disc);
 \end{verbatim}
 
 The default is for callbacks to be issued synchronously, but it is 
@@ -496,7 +715,8 @@ possible to hold them in a queue of pending callbacks to be delivered
 on demand.  This feature is controlled by the interface:
 
 \begin{verbatim}
-int          agcallbacks(Agraph_t *g, int flag); /* return prev value */
+    /* returns previous value */
+  int     agcallbacks(Agraph_t *g, int flag); 
 \end{verbatim}
 
 If the flag is zero, callbacks are kept pending. 
@@ -505,7 +725,7 @@ and the graph is put into immediate callback mode.
 (Therefore the state must be reset via \verb"agcallbacks"
 if they are to be kept pending again.)
 
-Note: it is a small inconsistency that Agraph depends on the client
+{\bf N.B.}: it is a small inconsistency that Cgraph depends on the client
 to maintain the storage for the callback function structure.
 (Thus it should probably not be allocated on the dynamic stack.)
 The semantics of \verb"agpopdisc" currently identify callbacks by
@@ -513,169 +733,268 @@ the address of this structure so it would take a bit of reworking
 to fix this.  In practice, callback functions are usually passed
 in a static struct.
 
-{\bf Disciplines.}
-A graph has an associated set of methods ("disciplines")
+\subsection{Disciplines}
+\label{subsec:disciplines}
+A graph has an associated set of methods (``disciplines'')
 for file I/O, memory management and graph object ID assignment.
-
 \begin{verbatim}
-struct Agdisc_s {   
-        Agmemdisc_t                     *mem;
-        Agiddisc_t                      *id;
-        Agiodisc_t                      *io;
-} ;
+  typedef struct {   
+    Agmemdisc_t                     *mem;
+    Agiddisc_t                      *id;
+    Agiodisc_t                      *io;
+  } Agdisc_t;
+\end{verbatim}
+A pointer to an \verb"Agdisc_t" structure is used as an argument when
+a graph is created or read using \verb"agopen",
+\verb"agread" and \verb"agconcat". If the pointer is NULL, the default
+Cgraph disciplines are used. An application can pass in its own disciplines
+to override the defaults. Note that it doesn't need to provide disciplines for
+all three fields. If any field is the NULL pointer, Cgraph will use the default
+discipline for that task.
+
+The default disciplines are also accessible by name.
+\begin{verbatim}
+  Agmemdisc_t AgMemDisc;
+  Agiddisc_t  AgIdDisc;
+  Agiodisc_t  AgIoDisc;
+  Agdisc_t    AgDefaultDisc;
 \end{verbatim}
+This is useful because, unlike with \verb"Agdisc_t", all of the fields of
+specific disciplines must be non-NULL.
 
-A pointer to this structure can be passed to \verb"agopen" and
-\verb"agread" (and \verb"agconcat") to override Agraph's defaults.
+Cgraph copies the three individual pointers. Thus, these three structures must remain
+allocated for the life of the graph, though the \verb"Agdisc_t" may be temporary.
 
+\subsubsection{Memory management}
 The memory management discipline allows calling alternative versions
 of malloc, particularly, Vo's Vmalloc, which offers memory allocation
-in arenas or pools.  The benefit is that Agraph can allocate a graph
+in arenas or pools.  The benefit is that Cgraph can allocate a graph
 and its objects within a shared pool,
 to provide fine-grained tracking of its memory resources
 and the option of freeing the entire graph and associated objects
 by closing the area in constant time, if finalization of individual
 graph objects isn't needed.\footnote{This could be fixed.}
 
-Other functions allow access to a graph's heap for memory allocation.
-(It probably only makes sense to use this feature in combination with
-an optional arena-based memory manager, as described below under
-{\bf Disciplines}.)
-
-\begin{verbatim}
-typedef 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);
-} Agmemdisc_t;
-
-void                     *agalloc(Agraph_t *g, size_t size);
-void                     *agrealloc(Agraph_t *g, void *ptr, size_t oldsize, size_t size);
-void                     agfree(Agraph_t *g, void *ptr);
-struct _vmalloc_s        *agheap(Agraph_t *g);
-
-
-typedef 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);
-} Agiddisc_t;
-
-typedef struct Agiodisc_s {
-        int             (*afread)(void *chan, char *buf, int bufsize);
-        int             (*putstr)(void *chan, char *str);
-        int             (*flush)(void *chan);   /* sync */
-        /* error messages? */
-} Agiodisc_t ;
-\end{verbatim}
-
-The file I/O functions were turned into a discipline
-(instead of hard-coding calls to the C stdio library into Agraph)
-because some Agraph clients could have their own stream I/O routines,
-or could ``read'' a graph from a memory buffer instead of an external file.
-(Note, it is also possible to separately redefine \verb"agerror(char*)",
-overriding Agraph's default, for example, to display error messages in a
-screen dialog instead of the standard error stream.)
-
-The ID assignment discipline makes it possible for an Agraph client
-control this namespace.  For instance, in one application, the client
-creates IDs that are pointers into another object space defined by
-a front-end interpreter.  In general, the ID discipline must provide
-a map between internal IDs and external strings.  
-\verb"open" and \verb"close" allow initialization and finalization
-for a given graph; \verb"alloc" and \verb"free" explicitly create
-and destroy IDs.  \verb"map" is called to convert an external string
-name into an ID for a given object type (AGRAPH, AGNODE, or AGEDGE),
-with an optional flag that tells if the ID should be allocated if
-it does not already exist.  \verb"print\" is called to convert an
-internal ID back to a string.
-
-Finally, to make this mechanism accessible, Agraph provides functions
-to create objects by ID instead of external name:
+%Other functions allow access to a graph's heap for memory allocation.
+%(It probably only makes sense to use this feature in combination with
+%an optional arena-based memory manager, as described above.)
 
 \begin{verbatim}
-Agnode_t     *agidnode(Agraph_t *g, unsigned long id, int createflag);
-Agedge_t     *agidedge(Agnode_t *t, Agnode_t *h, unsigned long id, int createflag);
+  typedef struct Agmemdisc_s {
+    void *(*open)(void);
+    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);
+  } Agmemdisc_t;
 \end{verbatim}
 
-{\bf Flattened node and edge lists.}  For flat-out efficiency,
-there is a way of linearizing the splay trees in which node
-and sets are stored, converting them into flat lists.  After
-this they can be walked very quickly.  This is done by:
-
+When a graph is created, but before any memory is allocated, Cgraph calls the 
+discipline's \verb"open" function. The application should then perform any necessary
+initializations of its memory system, and return a pointer to any state data structure
+necessary for subsequent memory allocation. When the graph is closed, Cgraph will 
+call the discipline's \verb"close" function, passing it the associated state, so the application
+can finalize and free any resources involved.
+
+The other three discipline functions \verb"alloc", \verb"resize" and \verb"free" should have semantics
+roughly identical to the standard C library functions \verb"malloc", \verb"realloc" and \verb"free".
+The main difference is that any new memory returned by \verb"alloc" and \verb"resize" should be zeroed out,
+and that \verb"resize" is passed the old buffer size in addition to the requested new size. In addition,
+they all take the memory state as the first argument.
+
+To simplify the use of the memory discipline, Cgraph provides three wrapper functions that hide the
+task of obtaining the memory state. These are the same functions Cgraph uses to handle memory for a graph.
 \begin{verbatim}
-voi     agflatten(Agraph_t *g, int flag);
-int     agisflattened(Agraph_t *g);
+  void *agalloc(Agraph_t *g, size_t size);
+  void *agrealloc(Agraph_t *g, void *ptr, size_t oldsize, 
+                   size_t size);
+  void agfree(Agraph_t *g, void *ptr);
 \end{verbatim}
 
-{\bf Shared string pool.}  As mentioned, Agraph maintains a
-shared string pool per graph.  Agraph has functions to directly
-create and destroy references to shared strings.
+\subsubsection{I/O management}
+The I/O discipline is probably the most frequently used of the three, as the I/O requirements of
+applications vary widely. 
+\begin{verbatim}
+  typedef struct Agiodisc_s {
+    int (*afread)(void *chan, char *buf, int bufsize);
+    int (*putstr)(void *chan, char *str);
+    int (*flush)(void *chan);
+  } Agiodisc_t ;
+\end{verbatim}
+The default I/O discipline uses stdio and the FILE structure for reading and writing. The functions
+\verb"afread", \verb"putstr" and \verb"flush" should have semantics roughly equivalent to 
+\verb"fread", \verb"fputs" and \verb"fflush", with the obvious permutation of arguments.
+
+The implementation of the \verb"agmemread" function of Cgraph provides a typical example of using
+a tailored I/O discipline. The idea is to read a graph from a given string of characters. The 
+implementation of the function is given below.
+The \verb"rdr_t" provides a miniature version of FILE, providing the necessary state information.
+The function \verb"memiofread" fills the role of \verb"afread" using the state provided by \verb"rdr_t".
+The \verb"agmemread" puts everything together, creating the needed state using the argument string, 
+and constructing a discipline structure using \verb"memiofread" and the defaults. It then calls
+\verb"agread" with the state and discipline to actually create the graph.
+
+\lgrindfile{agmemread.tex}
+
+\subsubsection{ID management}
+Graph objects (nodes, edges, subgraphs) use an uninterpreted long integer value as keys.
+The ID discipline gives the application control over how these keys are allocated, and how
+they are mapped to and from strings.
+The ID discipline makes it possible for a Cgraph client
+control this mapping.  For instance, in one application, the client
+may create IDs that are pointers into another object space defined by
+a front-end interpreter.  In general, the ID discipline must provide
+a map between internal IDs and external strings.  
 
 \begin{verbatim}
-char             *agstrdup(Agraph_t *, char *);
-char             *agstrbind(Agraph_t *g, char*);
-int              agstrfree(Agraph_t *, char *);
+  typedef unsigned long ulong;
+
+  typedef struct Agiddisc_s {
+    void *(*open)(Agraph_t *g, Agdisc_t*);
+    long (*map)(void *state, int objtype, char *name, 
+                 ulong *id, int createflag);
+    long (*alloc)(void *state, int objtype, ulong id);
+    void (*free)(void *state, int objtype, ulong id);
+    char *(*print)(void *state, int objtype, ulong id);
+    void (*close)(void *state);
+    void (*idregister) (void *state, int objtype, void *obj);
+  } Agiddisc_t;
 \end{verbatim}
 
-{\bf Error Handling.}  Agraph invokes an internal function, \verb"agerror"
-that prints a message on \verb"stderr" to report a fatal error.  
-An application may provide its own version of this function to
-override fatal error handling.  The error codes are listed below.
-Most of these error should ``never'' occur.\footnote{Also, a graph file
-syntax error really shouldn't be fatal; this can easily be remedied.}
+The \verb"open" function permits the ID discipline to initialize any data structures that it maintains 
+per individual graph. Its return value is then passed as the first argument (\verb"void *state") to all 
+subsequent ID manager calls.
+When the graph is closed, the discipline's \verb"close" function is called to allow for finalizing and
+freeing any resources used.
+
+The \verb"alloc" and \verb"free" functions explicitly create and destroy IDs.  
+The former is used by Cgraph to see if the given ID is available for use. If it is available, the function 
+should allocate it and return \verb"TRUE"; otherwise, it should return \verb"FALSE".
+If it is not available, the calling function will abort the operation.
+\verb"free" is called to inform the ID manager that the object labeled with the given ID is about to be
+deleted.
+
+If supported buy the ID discipline, the \verb"map" function is called 
+to convert a string name into an ID for a given object type 
+(AGRAPH, AGNODE, or AGEDGE), with an optional flag that tells if the 
+ID should be allocated if it does not already exist. 
+
+There are four cases:
+\begin{description}
+\item[{\tt name} \&\& {\tt createflag}] 
+Map the string (e.g., a name in a graph file) 
+into an ID. If the ID manager can comply, then it stores the result 
+in the \verb"id" parameter and returns \verb"TRUE". It is then also responsible for
+being able to print the ID again as a string. Otherwise, the ID manager 
+may return \verb"FALSE" but it must implement the following case, at least 
+in order for the reading and writing of graph files to work.
+\item[!{\tt name} \&\& {\tt createflag}]  
+Create a unique new ID. It may return FALSE if it does not support 
+anonymous objects, but this is strongly discouraged
+in order for Cgraph to support ``local names'' in graph files.
+\item[{\tt name} \&\& !{\tt createflag}]
+Test if \verb"name" has already been mapped and allocated. If so, the ID
+should be returned in the \verb"id" parameter.
+Otherwise, the ID manager may
+either return \verb"FALSE", or may store any unallocated ID into result. 
+This is convenient, for example, if names
+are known to be digit strings that are directly converted into integer values.
+\item[!{\tt name} \&\& !{\tt createflag}] Never used.  
+\end{description}
+
+The \verb"print" function is called to convert an internal ID back to a string.
+It is allowed to return a pointer to a static buffer; 
+a caller must copy its value if needed past subsequent calls. 
+NULL should be returned by ID managers that do not map names.
+
+Note that the \verb"alloc" and \verb"map" functions do not receive pointers to any 
+newly created object. If a client needs to install object pointers in a handle table, 
+it can obtain them via new object callbacks (Section~\ref{subsec:callbacks}).
+
+To make this mechanism accessible, Cgraph provides functions
+to create objects by ID instead of external name:
+\begin{verbatim}
+  Agnode_t *agidnode(Agraph_t *g, unsigned long id, int create);
+  Agedge_t *agidedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, 
+                     unsigned long id, int create);
+  Agraph_t *agidsubg(Agraph_t *g, unsigned long id, int create);
+\end{verbatim}
+Note that, with the default ID discipline, these functions return NULL.
 
+\subsection{Flattened node and edge lists}
+For random access, nodes and edges are usually stored in splay trees. 
+This adds a small but noticeable overhead when traversing the ``lists.''
+For flat-out efficiency,
+there is a way of linearizing the splay trees in which node
+and edge sets are stored, converting them into flat lists.  After
+this they can be traversed very quickly. The function
+\verb"agflatten(Agraph_t *g, int flag)" 
+will flatten the trees if \verb"flag" is \verb"TRUE",
+or reconstruct the trees if \verb"flag" is \verb"FALSE".
+Note that if any call adds or removes a graph object, the corresponding list
+is automatically returned to its tree form.
+
+The library provides various macros to automate the flattening and simplify
+the standard traversals. For example, the following code performs the usual
+traversal over all out-edges of a graph:
 \begin{verbatim}
-void agerror(int code, char *str);
-#define AGERROR_SYNTAX  1       /* error encountered in lexing or parsing */
-#define AGERROR_MEMORY  2       /* out of memory */
-#define AGERROR_UNIMPL  3       /* unimplemented feature */
-#define AGERROR_MTFLOCK 4       /* move to front lock has been set */
-#define AGERROR_CMPND   5       /* conflict in restore_endpoint() */
-#define AGERROR_BADOBJ  6       /* passed an illegal pointer */
-#define AGERROR_IDOVFL  7       /* object ID overflow */
-#define AGERROR_FLAT    8       /* attempt to break a flat lock */
-#define AGERROR_WRONGGRAPH 9    /* mismatched graph and object */
+  Agnode_t* n;
+  Agedge_t* e;
+  Agnoderef_t* nr;
+  Agedgeref_t* er;
+  for (nr = FIRSTNREF(g); nr; nr = NEXTNREF(g,nr)) {
+    n = NODEOF(nr);
+    /* do something with node n */
+    for (er = FIRSTOUTREF(g,nr); er; er = NEXTEREF(g,er)) {
+      e = EDGEOF(er);
+      /* do something with edge e */
+    }
+  }
 \end{verbatim}
+Compare this with the code in shown on page \pageref{traversal}. 
 
 \section{Related Libraries}
 \label{sec:relatedlibraries}
-{\bf Libgraph} is a predecessor of Agraph and lives on as the
-base library of the {\it dot} and {\it neato} layout tools.
-Programs that invoke libdot or libneato APIs therefore need
-libgraph, not Agraph, at least until dot and neato are updated.
+{\bf Libgraph} is a predecessor of Cgraph and is now considered
+obsolete. All of the Graphviz code is now written using Cgraph.
+As some older applications using libgraph
+may need to be converted to Cgraph, we note some of the main
+differences.
 
 A key difference between the two libraries is the handling of
-C data structure attributes.  libgraph hard-wires these
-at the end of the graph, node and edge structs.  That is,
-an application programmer defines the structs graphinfo, nodeinfo
-and edgeinfo before including graph.h, and the library inquires of
+C data structure attributes.  Libgraph hard-wires these
+at the end of the graph, node and edge structuress.  That is,
+an application programmer defines the structs {\tt graphinfo}, {\tt nodeinfo}
+and {\tt edgeinfo} before including {\tt graph.h}, and the library inquires of
 the size of these structures at runtime so it can allocate graph
 objects of the proper size.  Because there is only one shot at
 defining attributes, this design creates an impediment to writing
 separate algorithm libraries.
+The dynamic \verb"Agrec_t" structures, described in Section~\ref{sec:internalattributes}, 
+allows each algorithm to attach its own required data structure.
 
-In Agraph, the nesting of subgraphs forms a tree.
-In Libgraph, a subgraph can belong to more than one parent,
+In Cgraph, the nesting of subgraphs forms a tree.
+In libgraph, a subgraph can belong to more than one parent,
 so they form a DAG (directed acyclic graph). Libgraph
 actually represents this DAG as a special meta-graph
-that is navigated by Libgraph calls.  After gaining
-experience with Libgraph, we decided this complexity
+that is navigated by libgraph calls.  After gaining
+experience with libgraph, we decided this complexity
 was not worth its cost.
 
-Finally, there are some syntactic differences in the APIs.
-Where most Agraph calls take just a graph object,
-the equivalent Libgraph calls take both a graph/subgraph and
-an object, and Libgraph rebinds the object to the given
-graph or subgraph.
-
-{\bf Lgraph} is a successor to Agraph, written in C++ by Gordon Woodhull.
-It follows Agraph's overall graph model (particularly, its subgraphs and
+Finally, there are some small syntactic differences in the APIs.
+For example, in libgraph", the name of a node or graph and
+the head and tail nodes of an edge are
+directly accessible via pointers while in Cgraph, it is necessary to use
+the functions \verb"agnameof", \verb"agtail" and \verb"aghead".
+Libgraph tends to have separate functions for creating and finding
+an object, or for handling different types of objects, e.g., 
+\verb"agnode" and \verb"agfindnode". Instead, Cgraph will use a single function
+with an additional parameter. Overall, the two libraries are vary close, both
+syntactically and semantically, so conversion is fairly straightforward.
+
+{\bf Lgraph} is a successor to Cgraph, written in C++ by Gordon Woodhull.
+It follows Cgraph's overall graph model (particularly, its subgraphs and
 emphasis on efficient dynamic graph operations) but uses the C++ type
 system of templates and inheritance to provide typesafe, modular and
 efficient internal attributes.  (LGraph relies on cdt for dictionary
@@ -683,25 +1002,23 @@ sets, with an STL-like C++ interface layer.)  A fairly mature prototype
 of the Dynagraph system (a successor to dot and neato to handle
 online maintenance of dynamic diagrams) has been prototyped in LGraph.
 See the dgwin (Dynagraph for Windows) page 
-\url{http://www.research.att.com/sw/tools/graphviz/dgwin} for further details. 
+\url{http://www.dynagraph.org/dgwin/} for further details. 
 
-\section{Interface to other languages}
+\section{Interfaces to Other Languages}
 \label{sec:interfacetootherlanguages}
 
-There is a 3rd-party PERL module for Graphviz that contains bindings for
-Libgraph (note, not Agraph) as well as the dot and neato layout programs.
-Graphviz itself contains a TCL/tk binding for Agraph as well as the
-other libraries.
+If enabled, the Graphviz package contains bindings for Cgraph in a variety
+of languages, including Java, Perl, PHP, Tcl, Python and Ruby.
 
 \section{Open Issues}
 \label{sec:openissues}
 
-{\bf Node and Edge Ordering.} The intent in Agraph's design was to
+{\bf Node and Edge Ordering.} The intent in Cgraph's design was to
 eventually support user-defined node and edge set ordering, overriding
 the default (which is object creation timestamp order).  For example,
 in topologically embedded graphs, edge lists could potentially be sorted
 in clockwise order around nodes.
-Because Agraph assumes that all edge sets in the same \verb"Agraph_t"
+Because Cgraph assumes that all edge sets in the same \verb"Agraph_t"
 have the same ordering, there should probably be a new primitive to
 switching node or edge set ordering functions.  Please contact the
 author if you need this feature.
@@ -709,7 +1026,9 @@ author if you need this feature.
 {\bf XML.}  XML dialects such as GXL and GraphML have been proposed
 for graphs.  Although it is simple to encode nodes and edges in XML,
 there are subtleties to representing more complicated structures, such as
-Agraph's subgraphs and nesting of attribute defaults.
+Cgraph's subgraphs and nesting of attribute defaults.
+On the other hand, GXL and GraphML provide notions of compound graphs,
+which are not available in DOT.
 We've prototyped an XML parser and would like to complete and release
 this work if we had a compelling application.  (Simple XML output of
 graphs is not difficult to program.)
@@ -721,37 +1040,38 @@ a graph from objects delivered on demand from a foreign API (such as a
 relational database that stores graphs).  We are now experimenting with
 attacks on some of these problems.
 
-{\bf Additional primitives.}  To be done: Object renaming, cloning, etc.
+{\bf Additional primitives.}  To be done: Object renaming, cloning, first-class
+nodes and edges, etc.
 
 \section{Example}
 \label{sec:example}
 
-The following is a simple Agraph filter that reads a graph and
-emits its strongly connected components, each as a separate graph
-plus an overview map of the relationship between the components.
+The following is a simple Cgraph filter that reads a graph and
+emits its strongly connected components, each as a separate graph,
+plus an overview map of the relationships between the components.
 To save space, the auxiliary functions in the header ingraph.h
-are not shown; the entire program can be found in the graphviz
-source code release under tools/src.
+are not shown; the entire program can be found in the Graphviz
+source code release under \verb"cmd/tools".
 
-About lines 40-50 are the declarations for internal records for
-nodes and edges.  Line 50-80 define access functions and macros
-for fields in these records.  Lines 90-130 define a simple stack
+About lines 32-41 are the declarations for internal records for
+graphs and nodes.  Line 43-48 define access macros
+for fields in these records.  Lines 52-83 define a simple stack
 structure needed for the strongly connected component algorithm
-and down to line 138 are some global definitions for the program.
+and down to line 97 are some global definitions for the program.
 
 The rest of the code can be read from back-to-front. From
-around line 300 to the end is boilerplate code that handles
-command line arguments and opening multiple graph files. 
+around line 262 to the end is boilerplate code that handles
+command-line arguments and opening multiple graph files. 
 The real work is done starting with the function {\it process}
-about line 265, which works on one graph at a time.  After initializing
-the node and edge internal records, it creates a new graph for the
+about line 223, which works on one graph at a time.  After initializing
+the node and graph internal records using {it aginit}, it creates a new graph for the
 overview map, and it calls {\it visit} on unvisited nodes to
 find components.  {\it visit} implements a standard algorithm to form
 the next strongly connected component on a stack.  When one has been
 completed, a new subgraph is created and the nodes of the component
 are installed.  (There is an option to skip trivial components that
 contain only one node.)  {\it nodeInduce} is called to process the
-outedges of nodes in this subgraph.  Such edges either belong to
+out-edges of nodes in this subgraph.  Such edges either belong to
 the component (and are added to it), or else point to a node in
 another component that must already have been processed.
 
index f551a9ce8f2a44868011a86392a09fe239f5c0d8..712d948383c6acd005d49bd792187dbc8492fbcb 100644 (file)
@@ -7,7 +7,7 @@ all : Agraph.pdf
 %.pdf : %.dot
        dot -Tps2 $< | epstopdf --filter --outfile=$@
 
-Agraph.pdf : Agraph.tex
+Agraph.pdf : Agraph.tex sccmap.tex agmemread.tex
        $(PTEX) Agraph.tex
        @if grep "Label(s) may have changed" Agraph.log; then $(PTEX) Agraph.tex; fi
 
@@ -15,7 +15,13 @@ Agraph.ps : Agraph.dvi
        @if grep "Label(s) may have changed" Agraph.log; then $(TEX) Agraph.tex; fi
        $(DVI) -o Agraph.ps Agraph
        
-TEXS = graph.tex sccmap.tex
+TEXS = graph.tex sccmap.tex agmemread.tex
+
+sccmap.tex : sccmap.c
+       lgrind -i -c -t 4 -l C sccmap.c > sccmap.tex
+
+agmemread.tex : agmemread.c
+       lgrind -i -c -t 4 -l C agmemread.c > agmemread.tex
 
 Agraph.aux : Agraph.tex
        $(TEX) Agraph
diff --git a/doc/libgraph/agmemread.c b/doc/libgraph/agmemread.c
new file mode 100644 (file)
index 0000000..69ccbe5
--- /dev/null
@@ -0,0 +1,48 @@
+typedef struct {
+    const char *data;
+    int len;
+    int cur;
+} rdr_t;
+
+static int memiofread(void *chan, char *buf, int bufsize)
+{
+    const char *ptr;
+    char *optr;
+    char c;
+    int l;
+    rdr_t *s;
+
+    if (bufsize == 0) return 0;
+    s = (rdr_t *) chan;
+    if (s->cur >= s->len)
+        return 0;
+    l = 0;
+    ptr = s->data + s->cur;
+    optr = buf;
+    do {
+        *optr++ = c = *ptr++;
+        l++;
+    } while (c && (c != '\n') && (l < bufsize));
+    s->cur += l;
+    return l;
+}
+
+static Agiodisc_t memIoDisc = {memiofread, 0, 0};
+
+Agraph_t *agmemread(const char *cp)
+{
+    rdr_t rdr;
+    Agdisc_t disc;
+    Agiodisc_t memIoDisc;
+
+    memIoDisc.putstr = AgIoDisc.putstr;
+    memIoDisc.flush = AgIoDisc.flush;
+    rdr.data = cp;
+    rdr.len = strlen(cp);
+    rdr.cur = 0;
+
+    disc.mem = NULL;
+    disc.id = NULL;
+    disc.io = &memIoDisc;
+    return agread (&rdr, &disc);
+}
index 521a9a91cb7027ee51d3cad34e3752fcc2d52b35..aec9ff2bdccfcd360e933ca346576f57761b2a4b 100644 (file)
@@ -13,7 +13,9 @@
 %% which was a notable improvement upon Van Jacobsen's tgrind for
 %% plain TeX, which was adapted from vgrind, a troff prettyprinter.
 %% 
-%% Author: Michael Piefel, piefel@cs.tu-berlin.de
+%% LGrind contains non-free code written by Van Jacobson, who does not answer
+%% to any request for changing his licence. This software is therefore not
+%% maintained. I also do not accept any cheques anymore.
 %% Based on Van Jacobson's ``tgrindmac'', a macro package for TeX.
 %% Modified, 1987 by Jerry Leichter. Put '@' in all internal names.
 %% Modified, 1991 by George Reilly. Changed name from tgrind to lgrind.
@@ -21,7 +23,7 @@
 %%          -1999    Hundreds of bells and whistles. No changelog here.
 \NeedsTeXFormat{LaTeX2e}[1996/06/01]
 \ProvidesPackage{lgrind}
-          [1999/05/28 v3.6 LGrind environment and supporting stuff]
+          [2002/01/28 v3.67 LGrind environment and supporting stuff]
 %%stopzone   % VIM syncing
 \newcount\lc@unt
 \newcount\ln@xt
 \ifLGnoprocindex%
   \let\index\@gobble%
 \fi%
-\hfuzz=\LGsloppy
+\hfuzz=\LGsloppy%
 \def\NewPage{\filbreak\bigskip}%
-\ifLGinline
+\ifLGinline%
  \def\L##1{\setbox\ls@far\null{\CF\strut##1}\ignorespaces}%
-\else
- \let\r@ghtlno\relax\let\l@ftlno\relax
- \ifnum\LGnuminterval>\z@
-  \ifLGleftnum
-   \def\l@ftlno{\ifnum\lc@unt>\ln@xt
-     \global\advance\ln@xt by\LGnuminterval
-     \llap{{\normalfont\scriptsize\the\lc@unt\quad}}\fi}
+\else%
+ \let\r@ghtlno\relax\let\l@ftlno\relax%
+ \ifnum\LGnuminterval>\z@%
+  \ifLGleftnum%
+   \def\l@ftlno{\ifnum\lc@unt>\ln@xt%
+     \global\advance\ln@xt by\LGnuminterval%
+     \llap{{\normalfont\scriptsize\the\lc@unt\quad}}\fi}%
    \def\r@ghtlno{\rlap{\enspace\box\procbox}}%
-  \else
-   \def\r@ghtlno{\ifnum\lc@unt>\ln@xt
-     \global\advance\ln@xt by\LGnuminterval
+  \else%
+   \def\r@ghtlno{\ifnum\lc@unt>\ln@xt%
+     \global\advance\ln@xt by\LGnuminterval%
      \rlap{{\normalfont\scriptsize\enspace\the\lc@unt%
-                \enspace\box\procbox}}
+                \enspace\box\procbox}}%
      \else\rlap{\enspace\box\procbox}\fi}%
-  \fi
- \fi
- \def\L##1{\@@par\setbox\ls@far=\null\strut
+  \fi%
+ \fi%
+ \def\L##1{\@@par\setbox\ls@far=\null\strut%
   \global\advance\lc@unt by1%
   \hbox to \linewidth{\hskip\LGindent\l@ftlno ##1\egroup%
   \hfil\r@ghtlno}%
   \ignorespaces}%
-\fi
+\fi%
 \lc@unt=#1\advance\lc@unt by-1%
 \ln@xt=\LGnuminterval\advance\ln@xt by-1%
 \loop\ifnum\lc@unt>\ln@xt\advance\ln@xt by\LGnuminterval\repeat%
 \def\LB{\hbox\bgroup\bgroup\box\ls@far\CF\let\next=}%
 \def\Tab##1{\egroup\setbox\tb@x=\lastbox\TBw@d=\wd\tb@x%
- \advance\TBw@d by 1\@ts\ifdim\TBw@d>##1\@ts
-  \setbox\ls@far=\hbox{\box\ls@far \box\tb@x \sp@ce}\else
+ \advance\TBw@d by 1\@ts\ifdim\TBw@d>##1\@ts%
+  \setbox\ls@far=\hbox{\box\ls@far \box\tb@x \sp@ce}\else%
   \setbox\ls@far=\hbox to ##1\@ts{\box\ls@far \box\tb@x \hfil}\fi\LB}%
 \ifLGinline\def\sp@ce{{\hskip .3333em}}%
 \else \setbox\tb@x=\hbox{\texttt{0}}%
-      \@ts=0.8\wd\tb@x \def\sp@ce{{\hskip 1\@ts}}\fi
-\catcode`\_=\active \@setunder
-\def\CF{\ifc@mment\CMfont\else\ifstr@ng\STfont\fi\fi}
+      \@ts=0.8\wd\tb@x \def\sp@ce{{\hskip 1\@ts}}\fi%
+\catcode`\_=\active \@setunder%
+\def\CF{\ifc@mment\CMfont\else\ifstr@ng\STfont\fi\fi}%
 \def\N##1{{\NOfont ##1}\global\futurelet\next\ic@r}%
 \def\K##1{{\KWfont ##1}\global\futurelet\next\ic@r}%
 \def\V##1{{\VRfont ##1}\global\futurelet\next\ic@r}%
 \def\,{\relax \ifmmode\mskip\thinmuskip \else\thinspace \fi}%
 \def\!{\relax \ifmmode\mskip-\thinmuskip \else\negthinspace \fi}%
 %%stopzone   % VIM syncing
-\def\CH##1##2##3{\relax\ifmmode ##1\relax
+\def\CH##1##2##3{\relax\ifmmode ##1\relax%
 \else\ifstr@ng ##2\relax\else$##3$\fi\fi }%
 \def\|{\CH|||}%  not necessary for T1
 \def\<{\CH<<<}%  dto.
 \def\>{\CH>>>}%  dto.
 \def\-{\CH---}%  minus sign nicer than hyphen
-\def\_{\ifstr@ng {\char'137}\else
+\def\_{\ifstr@ng {\char'137}\else%
   \leavevmode \kern.06em \vbox{\hrule width.35em}%
   \ifdim\fontdimen\@ne\font=\z@ \kern.06em \fi\fi }%
 \def\#{{\STfont\char'043}}%
 \def\2{\CH\backslash {\char'134}\backslash }%          % \
 \def\3{\ifc@mment\ifright@ ''\global\right@false%
-                      \else``\global\right@true \fi
+                      \else``\global\right@true \fi%
    \else{\texttt{\char'042}}\fi}%                      % "
 \def\5{{\texttt{\char'136}}}%                          % ^
 \parindent\z@\parskip\z@ plus 1pt%
-\bgroup\BGfont
+\bgroup\BGfont%
 }
 {\egroup\@@par}           % end of environment lgrind
 \def\lgrinde{\ifLGinline\else\LGsize\fi\begin{lgrind}}
 \end{lgrind}
     \endgroup
     \vskip .5\baselineskip
-    \ifLGnorules\else\hrule\fi
-    \addvspace{0.1in}
+    \ifLGnorules\else\hrule\vspace{0.1in}\fi
 }
 \endinput
 %%
index bae0587c31e25b3dfd118ba06db1df928c25f6da..08d2168e775ba8461501b9a9c69e516de18f25e6 100644 (file)
 % Remember to use the lgrind style
 
 \Head{}
-\File{sccmap.c}{2002}{7}{10}{15:30}{7815}
-\L{\LB{\C{}/*}}
-\L{\LB{}\Tab{4}{This_software_may_only_be_used_by_you_under_license_from_AT\&T_Corp.}}
-\L{\LB{}\Tab{4}{(\3AT\&T\3).}\Tab{15}{A_copy_of_AT\&T{'}s_Source_Code_Agreement_is_available_at}}
-\L{\LB{}\Tab{4}{AT\&T{'}s_Internet_website_having_the_URL:}}
-\L{\LB{}\Tab{4}{\<http://www.research.att.com/sw/tools/graphviz/license/source.html\>}}
-\L{\LB{}\Tab{4}{If_you_received_this_software_without_first_entering_into_a_license}}
-\L{\LB{}\Tab{4}{with_AT\&T,_you_have_an_infringing_copy_of_this_software_and_cannot_use}}
-\L{\LB{}\Tab{4}{it_without_violating_AT\&T{'}s_intellectual_property_rights.}}
-\L{\LB{*/\CE{}}}
-\L{\LB{}}
-\L{\LB{\C{}/*}}
-\L{\LB{_*_Written_by_Stephen_North}}
-\L{\LB{_*_Updated_by_Emden_Gansner}}
-\L{\LB{_*/\CE{}}}
-\L{\LB{}}
-\L{\LB{\C{}/*}}
-\L{\LB{_*_This_is_a_filter_that_reads_a_graph,_searches_for_strongly}}
-\L{\LB{_*_connected_components,_and_writes_each_as_a_separate_graph}}
-\L{\LB{_*_along_with_a_map_of_the_components.}}
-\L{\LB{_*/\CE{}}}
+\File{sccmap.c}{2013}{3}{6}{13:05}{7401}
+\L{\LB{}}
+\L{\LB{\C{}/*************************************************************************}}
+\L{\LB{_*_Copyright_(c)_2011_AT\&T_Intellectual_Property_}}
+\L{\LB{_*_All_rights_reserved._This_program_and_the_accompanying_materials}}
+\L{\LB{_*_are_made_available_under_the_terms_of_the_Eclipse_Public_License_v1.0}}
+\L{\LB{_*_which_accompanies_this_distribution,_and_is_available_at}}
+\L{\LB{_*_http://www.eclipse.org/legal/epl-v10.html}}
+\L{\LB{_*}}
+\L{\LB{_*_Contributors:_See_CVS_logs._Details_at_http://www.graphviz.org/}}
+\L{\LB{_*************************************************************************/\CE{}}}
+\L{\LB{}}
 \L{\LB{\K{\#ifdef}_\V{HAVE\_CONFIG\_H}}}
-\L{\LB{\K{\#include}_\<\V{gvconfig}.\V{h}\>}}
+\L{\LB{\K{\#include}_\S{}\3config.h\3\SE{}}}
 \L{\LB{\K{\#endif}}}
 \L{\LB{}}
 \L{\LB{\K{\#include}_\<\V{stdio}.\V{h}\>}}
+\L{\LB{\K{\#include}_\<\V{stdlib}.\V{h}\>}}
 \L{\LB{\K{\#ifdef}_\V{HAVE\_UNISTD\_H}}}
-\L{\LB{\K{\#include}}\Tab{16}{\<\V{unistd}.\V{h}\>}}
+\L{\LB{\K{\#include}_\<\V{unistd}.\V{h}\>}}
 \L{\LB{\K{\#endif}}}
-\L{\LB{\K{\#include}_\<\V{agraph}.\V{h}\>}}
-\L{\LB{\K{\#include}_\<\V{ingraphs}.\V{h}\>}}
+\L{\LB{\K{\#include}_\S{}\3cgraph.h\3\SE{}}}
+\L{\LB{\K{\#include}_\S{}\3ingraphs.h\3\SE{}}}
 \L{\LB{}}
-\L{\LB{\K{\#ifndef}_\V{HAVE\_GETOPT\_DECL}}}
+\L{\LB{\K{\#ifdef}_\V{HAVE\_GETOPT\_H}}}
 \L{\LB{\K{\#include}_\<\V{getopt}.\V{h}\>}}
+\L{\LB{\K{\#else}}}
+\L{\LB{\K{\#include}_\S{}\3compat\_getopt.h\3\SE{}}}
 \L{\LB{\K{\#endif}}}
 \L{\LB{}}
 \L{\LB{\K{\#define}_\V{INF}_((\K{unsigned}_\K{int})(\-\N{1}))}}
 \L{\LB{}}
 \L{\LB{\K{typedef}_\K{struct}_\V{Agraphinfo\_t}_\{}}
-\L{\LB{}\Tab{4}{\V{Agrec\_t}}\Tab{19}{\V{h};}}
-\L{\LB{}\Tab{4}{\V{Agnode\_t}*}\Tab{19}{\V{rep};}}
+\L{\LB{}\Tab{4}{\V{Agrec\_t}_\V{h};}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_*\V{rep};}}
 \L{\LB{\}_\V{Agraphinfo\_t};}}
 \L{\LB{}}
 \L{\LB{\K{typedef}_\K{struct}_\V{Agnodeinfo\_t}_\{}}
-\L{\LB{}\Tab{4}{\V{Agrec\_t}}\Tab{19}{\V{h};}}
-\L{\LB{}\Tab{4}{\K{unsigned}_\K{int}}\Tab{19}{\V{val};}}
-\L{\LB{}\Tab{4}{\V{Agraph\_t}*}\Tab{19}{\V{scc};}}
+\L{\LB{}\Tab{4}{\V{Agrec\_t}_\V{h};}}
+\L{\LB{}\Tab{4}{\K{unsigned}_\K{int}_\V{val};}}
+\L{\LB{}\Tab{4}{\V{Agraph\_t}_*\V{scc};}}
 \L{\LB{\}_\V{Agnodeinfo\_t};}}
 \L{\LB{}}
-\L{\LB{\K{\#ifdef}_\V{INLINE}}}
 \L{\LB{\K{\#define}_\V{getrep}(\V{g})}\Tab{19}{(((\V{Agraphinfo\_t}*)(\V{g}\-\!\>\V{base}.\V{data}))\-\!\>\V{rep})}}
 \L{\LB{\K{\#define}_\V{setrep}(\V{g},\V{rep})}\Tab{23}{(\V{getrep}(\V{g})_=_\V{rep})}}
 \L{\LB{\K{\#define}_\V{getscc}(\V{n})}\Tab{21}{(((\V{Agnodeinfo\_t}*)((\V{n})\-\!\>\V{base}.\V{data}))\-\!\>\V{scc})}}
 \L{\LB{\K{\#define}_\V{setscc}(\V{n},\V{sub})}\Tab{25}{(\V{getscc}(\V{n})_=_\V{sub})}}
 \L{\LB{\K{\#define}_\V{getval}(\V{n})}\Tab{21}{(((\V{Agnodeinfo\_t}*)((\V{n})\-\!\>\V{base}.\V{data}))\-\!\>\V{val})}}
 \L{\LB{\K{\#define}_\V{setval}(\V{n},\V{newval})}\Tab{28}{(\V{getval}(\V{n})_=_\V{newval})}}
-\L{\LB{\K{\#else}}}
-\L{\LB{\K{static}_\V{Agnode\_t}_*}}
-\index{getrep}\Proc{getrep}\L{\LB{\V{getrep}(\V{Agraph\_t}_*\V{g})_}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{return}_(((\V{Agraphinfo\_t}*)(\V{g}\-\!\>\V{base}.\V{data}))\-\!\>\V{rep});}}
-\L{\LB{\}}}
-\L{\LB{\K{static}_\K{void}_}}
-\index{setrep}\Proc{setrep}\L{\LB{\V{setrep}(\V{Agraph\_t}_*\V{g},_\V{Agnode\_t}_*\V{rep})}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{((\V{Agraphinfo\_t}*)(\V{g}\-\!\>\V{base}.\V{data}))\-\!\>\V{rep}_=_\V{rep};}}
-\L{\LB{\}}}
-\L{\LB{\K{static}_\V{Agraph\_t}_*}}
-\index{getscc}\Proc{getscc}\L{\LB{\V{getscc}(\V{Agnode\_t}_*\V{n})_}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{return}_(((\V{Agnodeinfo\_t}*)(\V{n}\-\!\>\V{base}.\V{data}))\-\!\>\V{scc});}}
-\L{\LB{\}}}
-\L{\LB{\K{static}_\K{void}_}}
-\index{setscc}\Proc{setscc}\L{\LB{\V{setscc}(\V{Agnode\_t}_*\V{n},_\V{Agraph\_t}_*\V{scc})_}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{((\V{Agnodeinfo\_t}*)(\V{n}\-\!\>\V{base}.\V{data}))\-\!\>\V{scc}_=_\V{scc};}}
-\L{\LB{\}}}
-\L{\LB{\K{static}_\K{int}}}
-\index{getval}\Proc{getval}\L{\LB{\V{getval}(\V{Agnode\_t}_*\V{n})_}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{return}_(((\V{Agnodeinfo\_t}*)(\V{n}\-\!\>\V{base}.\V{data}))\-\!\>\V{val});}}
-\L{\LB{\}}}
-\L{\LB{\K{static}_\K{void}_}}
-\index{setval}\Proc{setval}\L{\LB{\V{setval}(\V{Agnode\_t}_*\V{n},_\K{int}_\V{v})}}
-\L{\LB{\{}}
-\L{\LB{}\Tab{2}{((\V{Agnodeinfo\_t}*)(\V{n}\-\!\>\V{base}.\V{data}))\-\!\>\V{val}_=_\V{v};}}
-\L{\LB{\}}}
-\L{\LB{\K{\#endif}}}
 \L{\LB{}}
 \L{\LB{\C{}/*********_stack_***********/\CE{}}}
 \L{\LB{\K{typedef}_\K{struct}_\{}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}**}\Tab{15}{\V{data};}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}**}\Tab{15}{\V{ptr};}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_**\V{data};}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_**\V{ptr};}}
 \L{\LB{\}_\V{Stack};}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}}}
-\index{initStack}\Proc{initStack}\L{\LB{\V{initStack}_(\V{Stack}*_\V{sp},_\K{int}_\V{sz})}}
+\index{initStack}\Proc{initStack}\L{\LB{\K{static}_\K{void}_\V{initStack}(\V{Stack}_*_\V{sp},_\K{int}_\V{sz})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{sp}\-\!\>\V{data}_=_(\V{Agnode\_t}**)\V{malloc}(\V{sz}*\K{sizeof}(\V{Agnode\_t}*));}}
-\L{\LB{}\Tab{2}{\V{sp}\-\!\>\V{ptr}_=_\V{sp}\-\!\>\V{data};}}
+\L{\LB{}\Tab{4}{\V{sp}\-\!\>\V{data}_=_(\V{Agnode\_t}_**)_\V{malloc}(\V{sz}_*_\K{sizeof}(\V{Agnode\_t}_*));}}
+\L{\LB{}\Tab{4}{\V{sp}\-\!\>\V{ptr}_=_\V{sp}\-\!\>\V{data};}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}}}
-\index{freeStack}\Proc{freeStack}\L{\LB{\V{freeStack}_(\V{Stack}*_\V{sp})}}
+\index{freeStack}\Proc{freeStack}\L{\LB{\K{static}_\K{void}_\V{freeStack}(\V{Stack}_*_\V{sp})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{free}_(\V{sp}\-\!\>\V{data});}}
+\L{\LB{}\Tab{4}{\V{free}(\V{sp}\-\!\>\V{data});}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{\#ifdef}_\V{INLINE}}}
-\L{\LB{\K{\#define}_\V{push}(\V{sp},\V{n})_(*((\V{sp})\-\!\>\V{ptr}++)_=_\V{n})}}
-\L{\LB{\K{\#define}_\V{top}(\V{sp})_(*((\V{sp})\-\!\>\V{ptr}_\-_\N{1}))}}
-\L{\LB{\K{\#define}_\V{pop}(\V{sp})_(*(\-\-((\V{sp})\-\!\>\V{ptr})))}}
-\L{\LB{\K{\#else}}}
-\L{\LB{\K{static}_\K{void}}}
-\index{push}\Proc{push}\L{\LB{\V{push}_(\V{Stack}*_\V{sp},_\V{Agnode\_t}*_\V{n})}}
+\index{push}\Proc{push}\L{\LB{\K{static}_\K{void}_\V{push}(\V{Stack}_*_\V{sp},_\V{Agnode\_t}_*_\V{n})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{*(\V{sp}\-\!\>\V{ptr}++)_=_\V{n};}}
+\L{\LB{}\Tab{4}{*(\V{sp}\-\!\>\V{ptr}++)_=_\V{n};}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\V{Agnode\_t}*}}
-\index{top}\Proc{top}\L{\LB{\V{top}_(\V{Stack}*_\V{sp})}}
+\index{top}\Proc{top}\L{\LB{\K{static}_\V{Agnode\_t}_*\V{top}(\V{Stack}_*_\V{sp})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{return}_*(\V{sp}\-\!\>\V{ptr}_\-_\N{1});}}
+\L{\LB{}\Tab{4}{\K{return}_*(\V{sp}\-\!\>\V{ptr}_\-_\N{1});}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\V{Agnode\_t}*}}
-\index{pop}\Proc{pop}\L{\LB{\V{pop}_(\V{Stack}*_\V{sp})}}
+\index{pop}\Proc{pop}\L{\LB{\K{static}_\V{Agnode\_t}_*\V{pop}(\V{Stack}_*_\V{sp})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{sp}\-\!\>\V{ptr}\-\-;}}
-\L{\LB{}\Tab{2}{\K{return}_*(\V{sp}\-\!\>\V{ptr});}}
+\L{\LB{}\Tab{4}{\V{sp}\-\!\>\V{ptr}\-\-;}}
+\L{\LB{}\Tab{4}{\K{return}_*(\V{sp}\-\!\>\V{ptr});}}
 \L{\LB{\}}}
-\L{\LB{\K{\#endif}}}
-\L{\LB{}}
 \L{\LB{}}
 \L{\LB{\C{}/*********_end_stack_***********/\CE{}}}
 \L{\LB{}}
 \L{\LB{\K{typedef}_\K{struct}_\{}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{7}{\V{Comp};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{7}{\V{ID};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{7}{\V{N\_nodes\_in\_nontriv\_SCC};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{Comp};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{ID};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{N\_nodes\_in\_nontriv\_SCC};}}
 \L{\LB{\}_\V{sccstate};}}
 \L{\LB{}}
-\L{\LB{\K{int}}\Tab{15}{\V{wantDegenerateComp};}}
-\L{\LB{\K{int}}\Tab{15}{\V{Silent};}}
-\L{\LB{\K{int}}\Tab{15}{\V{Verbose};}}
-\L{\LB{\K{char}*}\Tab{15}{\V{CmdName};}}
-\L{\LB{\K{char}**}\Tab{15}{\V{Files};}}
+\L{\LB{\K{static}_\K{int}_\V{wantDegenerateComp};}}
+\L{\LB{\K{static}_\K{int}_\V{Silent};}}
+\L{\LB{\K{static}_\K{int}_\V{StatsOnly};}}
+\L{\LB{\K{static}_\K{int}_\V{Verbose};}}
+\L{\LB{\K{static}_\K{char}_*\V{CmdName};}}
+\L{\LB{\K{static}_\K{char}_**\V{Files};}}
+\L{\LB{\K{static}_\V{FILE}_*\V{outfp};}\Tab{32}{\C{}/*_output;_stdout_by_default_*/\CE{}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}_}}
-\index{nodeInduce}\Proc{nodeInduce}\L{\LB{\V{nodeInduce}(\V{Agraph\_t}_*\V{g})}}
+\index{nodeInduce}\Proc{nodeInduce}\L{\LB{\K{static}_\K{void}_\V{nodeInduce}(\V{Agraph\_t}_*_\V{g},_\V{Agraph\_t}_*_\V{map})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}}\Tab{18}{*\V{n},_*\V{rootn};}}
-\L{\LB{}\Tab{2}{\V{Agedge\_t}}\Tab{18}{*\V{e};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{n}))_\{}}
-\L{\LB{}\Tab{4}{\V{rootn}_=_\V{agsubnode}(\V{agroot}(\V{g}),\V{n},\V{FALSE});}}
-\L{\LB{}\Tab{4}{\K{for}_(\V{e}_=_\V{agfstout}(\V{rootn});_\V{e};_\V{e}_=_\V{agnxtout}(\V{e}))_\{}}
-\L{\LB{}\Tab{6}{\K{if}_(\V{agsubnode}(\V{g},\V{aghead}(\V{e}),\V{FALSE}))_\V{agsubedge}(\V{g},\V{e},\V{TRUE});}}
-\L{\LB{}\Tab{6}{\K{else}_\{}}
-\L{\LB{}\Tab{8}{\K{if}_(\V{getscc}(\V{aghead}(\V{e}))_\&\&_\V{getscc}(\V{agtail}(\V{e})))}}
-\L{\LB{}\Tab{10}{\V{agedge}(\V{getrep}(\V{getscc}(\V{agtail}(\V{e}))),\V{getrep}(\V{getscc}(\V{aghead}(\V{e}))),}}
-\L{\LB{}\Tab{12}{\V{NIL}(\K{char}*),\V{TRUE});}}
-\L{\LB{}\Tab{6}{\}}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_*\V{n};}}
+\L{\LB{}\Tab{4}{\V{Agedge\_t}_*\V{e};}}
+\L{\LB{}\Tab{4}{\V{Agraph\_t}_*\V{rootg}_=_\V{agroot}(\V{g});}}
+\L{\LB{}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{g},_\V{n}))_\{}}
+\L{\LB{}\Tab{8}{\K{for}_(\V{e}_=_\V{agfstout}(\V{rootg},_\V{n});_\V{e};_\V{e}_=_\V{agnxtout}(\V{rootg},_\V{e}))_\{}}
+\L{\LB{}\Tab{12}{\K{if}_(\V{agsubnode}(\V{g},_\V{aghead}(\V{e}),_\V{FALSE}))}}
+\L{\LB{}\Tab{16}{\V{agsubedge}(\V{g},_\V{e},_\V{TRUE});}}
+\L{\LB{}\Tab{12}{\K{else}_\{}}
+\L{\LB{}\Tab{16}{\V{Agraph\_t}_*\V{tscc}_=_\V{getscc}(\V{agtail}(\V{e}));}}
+\L{\LB{}\Tab{16}{\V{Agraph\_t}_*\V{hscc}_=_\V{getscc}(\V{aghead}(\V{e}));}}
+\L{\LB{}\Tab{16}{\K{if}_(\V{tscc}_\&\&_\V{hscc})}}
+\L{\LB{}\Tab{20}{\V{agedge}(\V{map},_\V{getrep}(\V{tscc}),}}
+\L{\LB{}\Tab{27}{\V{getrep}(\V{hscc}),_\V{NIL}(\K{char}_*),_\V{TRUE});}}
+\L{\LB{}\Tab{12}{\}}}
+\L{\LB{}\Tab{8}{\}}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{2}{\}}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{int}_}}
-\index{visit}\Proc{visit}\L{\LB{\V{visit}(\V{Agnode\_t}_*\V{n},_\V{Agraph\_t}*_\V{map},_\V{Stack}*_\V{sp},_\V{sccstate}*_\V{st})}}
+\index{visit}\Proc{visit}\L{\LB{\K{static}_\K{int}_\V{visit}(\V{Agnode\_t}_*_\V{n},_\V{Agraph\_t}_*_\V{map},_\V{Stack}_*_\V{sp},_\V{sccstate}_*_\V{st})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{unsigned}_\K{int}}\Tab{16}{\V{m},\V{min};}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}*}\Tab{16}{\V{t};}}
-\L{\LB{}\Tab{2}{\V{Agraph\_t}*}\Tab{16}{\V{subg};}}
-\L{\LB{}\Tab{2}{\V{Agedge\_t}*}\Tab{16}{\V{e};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{min}_=_++(\V{st}\-\!\>\V{ID});}}
-\L{\LB{}\Tab{2}{\V{setval}(\V{n},\V{min});}}
-\L{\LB{}\Tab{2}{\V{push}_(\V{sp},_\V{n});}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{for}_(\V{e}_=_\V{agfstout}(\V{n});_\V{e};_\V{e}_=_\V{agnxtout}(\V{e}))_\{}}
-\L{\LB{}\Tab{4}{\V{t}_=_\V{aghead}(\V{e});}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{getval}(\V{t})_==_\N{0})_\V{m}_=_\V{visit}(\V{t},\V{map},\V{sp},\V{st});}}
-\L{\LB{}\Tab{4}{\K{else}_\V{m}_=_\V{getval}(\V{t});}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{m}_\<_\V{min})_\V{min}_=_\V{m};}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{getval}(\V{n})_==_\V{min})_\{}}
-\L{\LB{}\Tab{4}{\K{if}_(!\V{wantDegenerateComp}_\&\&_(\V{top}(\V{sp})_==_\V{n}))_\{}}
-\L{\LB{}\Tab{6}{\V{setval}(\V{n},\V{INF});}}
-\L{\LB{}\Tab{6}{\V{pop}(\V{sp});}}
+\L{\LB{}\Tab{4}{\K{unsigned}_\K{int}_\V{m},_\V{min};}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_*\V{t};}}
+\L{\LB{}\Tab{4}{\V{Agraph\_t}_*\V{subg};}}
+\L{\LB{}\Tab{4}{\V{Agedge\_t}_*\V{e};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{min}_=_++(\V{st}\-\!\>\V{ID});}}
+\L{\LB{}\Tab{4}{\V{setval}(\V{n},_\V{min});}}
+\L{\LB{}\Tab{4}{\V{push}(\V{sp},_\V{n});}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{for}_(\V{e}_=_\V{agfstout}(\V{n}\-\!\>\V{root},_\V{n});_\V{e};_\V{e}_=_\V{agnxtout}(\V{n}\-\!\>\V{root},_\V{e}))_\{}}
+\L{\LB{}\Tab{8}{\V{t}_=_\V{aghead}(\V{e});}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{getval}(\V{t})_==_\N{0})}}
+\L{\LB{}\Tab{12}{\V{m}_=_\V{visit}(\V{t},_\V{map},_\V{sp},_\V{st});}}
+\L{\LB{}\Tab{8}{\K{else}}}
+\L{\LB{}\Tab{12}{\V{m}_=_\V{getval}(\V{t});}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{m}_\<_\V{min})}}
+\L{\LB{}\Tab{12}{\V{min}_=_\V{m};}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{4}{\K{else}_\{}}
-\L{\LB{}\Tab{6}{\K{char}_\V{name}[\N{32}];}}
-\L{\LB{}\Tab{6}{\V{Agraph\_t}*}\Tab{18}{\V{G}_=_\V{agraphof}(\V{n});;}}
-\L{\LB{}\Tab{6}{\V{sprintf}(\V{name},\S{}\3cluster\_\%d\3\SE{},(\V{st}\-\!\>\V{Comp})++);}}
-\L{\LB{}\Tab{6}{\V{subg}_=_\V{agsubg}(\V{G},\V{name},\V{TRUE});}}
-\L{\LB{}\Tab{6}{\V{agbindrec}(\V{subg},\S{}\3scc\_graph\3\SE{},\K{sizeof}(\V{Agraphinfo\_t}),\V{TRUE});}}
-\L{\LB{}\Tab{6}{\V{setrep}(\V{subg},\V{agnode}(\V{map},\V{name},\V{TRUE}));}}
-\L{\LB{}\Tab{6}{\K{do}_\{}}
-\L{\LB{}\Tab{8}{\V{t}_=_\V{pop}(\V{sp});}}
-\L{\LB{}\Tab{8}{\V{agsubnode}(\V{subg},\V{t},\V{TRUE});}}
-\L{\LB{}\Tab{8}{\V{setval}(\V{t},\V{INF});}}
-\L{\LB{}\Tab{8}{\V{setscc}(\V{t},\V{subg});}}
-\L{\LB{}\Tab{8}{\V{st}\-\!\>\V{N\_nodes\_in\_nontriv\_SCC}++;}}
-\L{\LB{}\Tab{6}{\}_\K{while}_(\V{t}_!=_\V{n});}}
-\L{\LB{}\Tab{6}{\V{nodeInduce}(\V{subg});}}
-\L{\LB{}\Tab{6}{\K{if}_(!\V{Silent})_\V{agwrite}(\V{subg},\V{stdout});}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{getval}(\V{n})_==_\V{min})_\{}}
+\L{\LB{}\Tab{8}{\K{if}_(!\V{wantDegenerateComp}_\&\&_(\V{top}(\V{sp})_==_\V{n}))_\{}}
+\L{\LB{}\Tab{12}{\V{setval}(\V{n},_\V{INF});}}
+\L{\LB{}\Tab{12}{\V{pop}(\V{sp});}}
+\L{\LB{}\Tab{8}{\}_\K{else}_\{}}
+\L{\LB{}\Tab{12}{\K{char}_\V{name}[\N{32}];}}
+\L{\LB{}\Tab{12}{\V{Agraph\_t}_*\V{G}_=_\V{agraphof}(\V{n});;}}
+\L{\LB{}\Tab{12}{\V{sprintf}(\V{name},_\S{}\3cluster\_\%d\3\SE{},_(\V{st}\-\!\>\V{Comp})++);}}
+\L{\LB{}\Tab{12}{\V{subg}_=_\V{agsubg}(\V{G},_\V{name},_\V{TRUE});}}
+\L{\LB{}\Tab{12}{\V{agbindrec}(\V{subg},_\S{}\3scc\_graph\3\SE{},_\K{sizeof}(\V{Agraphinfo\_t}),_\V{TRUE});}}
+\L{\LB{}\Tab{12}{\V{setrep}(\V{subg},_\V{agnode}(\V{map},_\V{name},_\V{TRUE}));}}
+\L{\LB{}\Tab{12}{\K{do}_\{}}
+\L{\LB{}\Tab{16}{\V{t}_=_\V{pop}(\V{sp});}}
+\L{\LB{}\Tab{16}{\V{agsubnode}(\V{subg},_\V{t},_\V{TRUE});}}
+\L{\LB{}\Tab{16}{\V{setval}(\V{t},_\V{INF});}}
+\L{\LB{}\Tab{16}{\V{setscc}(\V{t},_\V{subg});}}
+\L{\LB{}\Tab{16}{\V{st}\-\!\>\V{N\_nodes\_in\_nontriv\_SCC}++;}}
+\L{\LB{}\Tab{12}{\}_\K{while}_(\V{t}_!=_\V{n});}}
+\L{\LB{}\Tab{12}{\V{nodeInduce}(\V{subg},_\V{map});}}
+\L{\LB{}\Tab{12}{\K{if}_(!\V{StatsOnly})}}
+\L{\LB{}\Tab{16}{\V{agwrite}(\V{subg},_\V{outfp});}}
+\L{\LB{}\Tab{8}{\}}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\K{return}_\V{min};}}
+\L{\LB{}\Tab{4}{\K{return}_\V{min};}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{int}_}}
-\index{label}\Proc{label}\L{\LB{\V{label}(\V{Agnode\_t}_*\V{n},_\K{int}_\V{nodecnt},_\K{int}*_\V{edgecnt})}}
+\index{label}\Proc{label}\L{\LB{\K{static}_\K{int}_\V{label}(\V{Agnode\_t}_*_\V{n},_\K{int}_\V{nodecnt},_\K{int}_*\V{edgecnt})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{Agedge\_t}}\Tab{14}{*\V{e};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{setval}(\V{n},\N{1});}}
-\L{\LB{}\Tab{2}{\V{nodecnt}++;}}
-\L{\LB{}\Tab{2}{\K{for}_(\V{e}_=_\V{agfstedge}(\V{n});_\V{e};_\V{e}_=_\V{agnxtedge}(\V{e},\V{n}))_\{}}
-\L{\LB{}\Tab{4}{(*\V{edgecnt})_+=_\N{1};}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{e}\-\!\>\V{node}_==_\V{n})_\V{e}_=_\V{agopp}(\V{e});}}
-\L{\LB{}\Tab{4}{\K{if}_(!\V{getval}(\V{e}\-\!\>\V{node}))}}
-\L{\LB{}\Tab{6}{\V{nodecnt}_=_\V{label}(\V{e}\-\!\>\V{node},\V{nodecnt},\V{edgecnt});}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\K{return}_\V{nodecnt};}}
+\L{\LB{}\Tab{4}{\V{Agedge\_t}_*\V{e};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{setval}(\V{n},_\N{1});}}
+\L{\LB{}\Tab{4}{\V{nodecnt}++;}}
+\L{\LB{}\Tab{4}{\K{for}_(\V{e}_=_\V{agfstedge}(\V{n}\-\!\>\V{root},_\V{n});_\V{e};_\V{e}_=_\V{agnxtedge}(\V{n}\-\!\>\V{root},_\V{e},_\V{n}))_\{}}
+\L{\LB{}\Tab{8}{(*\V{edgecnt})_+=_\N{1};}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{e}\-\!\>\V{node}_==_\V{n})}}
+\L{\LB{}\Tab{12}{\V{e}_=_\V{agopp}(\V{e});}}
+\L{\LB{}\Tab{8}{\K{if}_(!\V{getval}(\V{e}\-\!\>\V{node}))}}
+\L{\LB{}\Tab{12}{\V{nodecnt}_=_\V{label}(\V{e}\-\!\>\V{node},_\V{nodecnt},_\V{edgecnt});}}
+\L{\LB{}\Tab{4}{\}}}
+\L{\LB{}\Tab{4}{\K{return}_\V{nodecnt};}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{int}_}}
-\index{countComponents}\Proc{countComponents}\L{\LB{\V{countComponents}(\V{Agraph\_t}_*\V{g},_\K{int}*_\V{max\_degree},_\K{float}_*\V{nontree\_frac})}}
+\L{\LB{\K{static}_\K{int}}}
+\index{countComponents}\Proc{countComponents}\L{\LB{\V{countComponents}(\V{Agraph\_t}_*_\V{g},_\K{int}_*\V{max\_degree},_\K{float}_*\V{nontree\_frac})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{nc}_=_\N{0};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{sum\_edges}_=_\N{0};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{sum\_nontree}_=_\N{0};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{deg};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{n\_edges};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{13}{\V{n\_nodes};}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}*}\Tab{13}{\V{n};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{n}))_\{}}
-\L{\LB{}\Tab{4}{\K{if}_(!\V{getval}(\V{n}))_\{}}
-\L{\LB{}\Tab{6}{\V{nc}++;}}
-\L{\LB{}\Tab{6}{\V{n\_edges}_=_\N{0};}}
-\L{\LB{}\Tab{6}{\V{n\_nodes}_=_\V{label}(\V{n},\N{0},\&\V{n\_edges});}}
-\L{\LB{}\Tab{6}{\V{sum\_edges}_+=_\V{n\_edges};}}
-\L{\LB{}\Tab{6}{\V{sum\_nontree}_+=_(\V{n\_edges}_\-_\V{n\_nodes}_+_\N{1});}}
+\L{\LB{}\Tab{4}{\K{int}_\V{nc}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{sum\_edges}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{sum\_nontree}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{deg};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{n\_edges};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{n\_nodes};}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_*\V{n};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{g},_\V{n}))_\{}}
+\L{\LB{}\Tab{8}{\K{if}_(!\V{getval}(\V{n}))_\{}}
+\L{\LB{}\Tab{12}{\V{nc}++;}}
+\L{\LB{}\Tab{12}{\V{n\_edges}_=_\N{0};}}
+\L{\LB{}\Tab{12}{\V{n\_nodes}_=_\V{label}(\V{n},_\N{0},_\&\V{n\_edges});}}
+\L{\LB{}\Tab{12}{\V{sum\_edges}_+=_\V{n\_edges};}}
+\L{\LB{}\Tab{12}{\V{sum\_nontree}_+=_(\V{n\_edges}_\-_\V{n\_nodes}_+_\N{1});}}
+\L{\LB{}\Tab{8}{\}}}
+\L{\LB{}\Tab{4}{\}}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{max\_degree})_\{}}
+\L{\LB{}\Tab{8}{\K{int}_\V{maxd}_=_\N{0};}}
+\L{\LB{}\Tab{8}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{g},_\V{n}))_\{}}
+\L{\LB{}\Tab{12}{\V{deg}_=_\V{agdegree}(\V{g},_\V{n},_\V{TRUE},_\V{TRUE});}}
+\L{\LB{}\Tab{12}{\K{if}_(\V{maxd}_\<_\V{deg})}}
+\L{\LB{}\Tab{16}{\V{maxd}_=_\V{deg};}}
+\L{\LB{}\Tab{12}{\V{setval}(\V{n},_\N{0});}}
+\L{\LB{}\Tab{8}{\}}}
+\L{\LB{}\Tab{8}{*\V{max\_degree}_=_\V{maxd};}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{max\_degree})_\{}}
-\L{\LB{}\Tab{4}{\K{int}_\V{maxd}_=_\N{0};}}
-\L{\LB{}\Tab{4}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{g});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{n}))_\{}}
-\L{\LB{}\Tab{6}{\V{deg}_=_\V{agdegree}(\V{n},\V{TRUE},\V{TRUE});}}
-\L{\LB{}\Tab{6}{\K{if}_(\V{maxd}_\<_\V{deg})_\V{maxd}_=_\V{deg};}}
-\L{\LB{}\Tab{6}{\V{setval}(\V{n},\N{0});}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{nontree\_frac})_\{}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{sum\_edges}_\>_\N{0})}}
+\L{\LB{}\Tab{12}{*\V{nontree\_frac}_=_(\K{float})_\V{sum\_nontree}_/_(\K{float})_\V{sum\_edges};}}
+\L{\LB{}\Tab{8}{\K{else}}}
+\L{\LB{}\Tab{12}{*\V{nontree\_frac}_=_\N{0.0};}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{4}{*\V{max\_degree}_=_\V{maxd};}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{nontree\_frac})_\{}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{sum\_edges}_\>_\N{0})_*\V{nontree\_frac}_=_(\K{float})\V{sum\_nontree}_/_(\K{float})\V{sum\_edges};}}
-\L{\LB{}\Tab{4}{\K{else}_*\V{nontree\_frac}_=_\N{0.0};}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\K{return}_\V{nc};}}
+\L{\LB{}\Tab{4}{\K{return}_\V{nc};}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}_}}
-\index{process}\Proc{process}\L{\LB{\V{process}(\V{Agraph\_t}*_\V{G})}}
+\index{process}\Proc{process}\L{\LB{\K{static}_\K{void}_\V{process}(\V{Agraph\_t}_*_\V{G})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{Agnode\_t}*}\Tab{15}{\V{n};}}
-\L{\LB{}\Tab{2}{\V{Agraph\_t}*}\Tab{15}{\V{map};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{15}{\V{nc}_=_\N{0};}}
-\L{\LB{}\Tab{2}{\K{float}}\Tab{15}{\V{nontree\_frac};}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{15}{\V{Maxdegree};}}
-\L{\LB{}\Tab{2}{\V{Stack}}\Tab{15}{\V{stack};}}
-\L{\LB{}\Tab{2}{\V{sccstate}}\Tab{15}{\V{state};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{aginit}(\V{G},\V{AGRAPH},\S{}\3scc\_graph\3\SE{},\K{sizeof}(\V{Agraphinfo\_t}),\V{TRUE});}}
-\L{\LB{}\Tab{2}{\V{aginit}(\V{G},\V{AGNODE},\S{}\3scc\_node\3\SE{},\K{sizeof}(\V{Agnodeinfo\_t}),\V{TRUE});}}
-\L{\LB{}\Tab{2}{\V{state}.\V{Comp}_=_\V{state}.\V{ID}_=_\N{0};}}
-\L{\LB{}\Tab{2}{\V{state}.\V{N\_nodes\_in\_nontriv\_SCC}_=_\N{0};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{Verbose})}}
-\L{\LB{}\Tab{4}{\V{nc}_=_\V{countComponents}(\V{G},\&\V{Maxdegree},\&\V{nontree\_frac});}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{initStack}(\&\V{stack},_\V{agnnodes}(\V{G})_+_\N{1});}}
-\L{\LB{}\Tab{2}{\V{map}_=_\V{agopen}(\S{}\3scc\_map\3\SE{},\V{Agdirected},(\V{Agdisc\_t}_*)\N{0});}}
-\L{\LB{}\Tab{2}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{G});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{n}))}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{getval}(\V{n})_==_\N{0})_\V{visit}(\V{n},\V{map},\&\V{stack},\&\V{state});}}
-\L{\LB{}\Tab{2}{\V{freeStack}(\&\V{stack});}}
-\L{\LB{}\Tab{2}{\K{if}_(!\V{Silent})_\V{agwrite}(\V{map},\V{stdout});}}
-\L{\LB{}\Tab{2}{\V{agclose}(\V{map});}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{Verbose})_}}
-\L{\LB{}\Tab{4}{\V{fprintf}(\V{stderr},\S{}\3\%d_\%d_\%d_\%d_\%.4f_\%d_\%.4f\2n\3\SE{},}}
-\L{\LB{}\Tab{6}{\V{agnnodes}(\V{G}),_\V{agnedges}(\V{G}),_\V{nc},_\V{state}.\V{Comp},}}
-\L{\LB{}\Tab{6}{\V{state}.\V{N\_nodes\_in\_nontriv\_SCC}_/_(\K{double})_\V{agnnodes}(\V{G}),_\V{Maxdegree},}}
-\L{\LB{}\Tab{6}{\V{nontree\_frac});}}
-\L{\LB{}\Tab{2}{\K{else}}}
-\L{\LB{}\Tab{4}{\V{fprintf}(\V{stderr},\S{}\3\%d_nodes,_\%d_edges,_\%d_strong_components\2n\3\SE{},}}
-\L{\LB{}\Tab{6}{\V{agnnodes}(\V{G}),_\V{agnedges}(\V{G}),_\V{state}.\V{Comp});}}
+\L{\LB{}\Tab{4}{\V{Agnode\_t}_*\V{n};}}
+\L{\LB{}\Tab{4}{\V{Agraph\_t}_*\V{map};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{nc}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{float}_\V{nontree\_frac}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{Maxdegree}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\V{Stack}_\V{stack};}}
+\L{\LB{}\Tab{4}{\V{sccstate}_\V{state};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{aginit}(\V{G},_\V{AGRAPH},_\S{}\3scc\_graph\3\SE{},_\K{sizeof}(\V{Agraphinfo\_t}),_\V{TRUE});}}
+\L{\LB{}\Tab{4}{\V{aginit}(\V{G},_\V{AGNODE},_\S{}\3scc\_node\3\SE{},_\K{sizeof}(\V{Agnodeinfo\_t}),_\V{TRUE});}}
+\L{\LB{}\Tab{4}{\V{state}.\V{Comp}_=_\V{state}.\V{ID}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\V{state}.\V{N\_nodes\_in\_nontriv\_SCC}_=_\N{0};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{Verbose})}}
+\L{\LB{}\Tab{8}{\V{nc}_=_\V{countComponents}(\V{G},_\&\V{Maxdegree},_\&\V{nontree\_frac});}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{initStack}(\&\V{stack},_\V{agnnodes}(\V{G})_+_\N{1});}}
+\L{\LB{}\Tab{4}{\V{map}_=_\V{agopen}(\S{}\3scc\_map\3\SE{},_\V{Agdirected},_(\V{Agdisc\_t}_*)_\N{0});}}
+\L{\LB{}\Tab{4}{\K{for}_(\V{n}_=_\V{agfstnode}(\V{G});_\V{n};_\V{n}_=_\V{agnxtnode}(\V{G},_\V{n}))}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{getval}(\V{n})_==_\N{0})}}
+\L{\LB{}\Tab{12}{\V{visit}(\V{n},_\V{map},_\&\V{stack},_\&\V{state});}}
+\L{\LB{}\Tab{4}{\V{freeStack}(\&\V{stack});}}
+\L{\LB{}\Tab{4}{\K{if}_(!\V{StatsOnly})}}
+\L{\LB{}\Tab{8}{\V{agwrite}(\V{map},_\V{outfp});}}
+\L{\LB{}\Tab{4}{\V{agclose}(\V{map});}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{Verbose})}}
+\L{\LB{}\Tab{8}{\V{fprintf}(\V{stderr},_\S{}\3\%d_\%d_\%d_\%d_\%.4f_\%d_\%.4f\2n\3\SE{},}}
+\L{\LB{}\Tab{16}{\V{agnnodes}(\V{G}),_\V{agnedges}(\V{G}),_\V{nc},_\V{state}.\V{Comp},}}
+\L{\LB{}\Tab{16}{\V{state}.\V{N\_nodes\_in\_nontriv\_SCC}_/_(\K{double})_\V{agnnodes}(\V{G}),}}
+\L{\LB{}\Tab{16}{\V{Maxdegree},_\V{nontree\_frac});}}
+\L{\LB{}\Tab{4}{\K{else}_\K{if}_(!\V{Silent})}}
+\L{\LB{}\Tab{8}{\V{fprintf}(\V{stderr},_\S{}\3\%d_nodes,_\%d_edges,_\%d_strong_components\2n\3\SE{},}}
+\L{\LB{}\Tab{16}{\V{agnnodes}(\V{G}),_\V{agnedges}(\V{G}),_\V{state}.\V{Comp});}}
 \L{\LB{}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{char}*_\V{useString}_=_}}
-\L{\LB{\S{}\3Usage:_\%s_[\-sdv?]_\<files\>\2n\2}}
-\L{\LB{}\Tab{2}{\-s_\-_silent\2n\2}}
-\L{\LB{}\Tab{2}{\-d_\-_allow_degenerate_components\2n\2}}
-\L{\LB{}\Tab{2}{\-v_\-_verbose\2n\2}}
-\L{\LB{}\Tab{2}{\-?_\-_print_usage\2n\2}}
+\index{openFile}\Proc{openFile}\L{\LB{\K{static}_\V{FILE}_*\V{openFile}(\K{char}_*\V{name},_\K{char}_*\V{mode})}}
+\L{\LB{\{}}
+\L{\LB{}\Tab{4}{\V{FILE}_*\V{fp};}}
+\L{\LB{}\Tab{4}{\K{char}_*\V{modestr};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{fp}_=_\V{fopen}(\V{name},_\V{mode});}}
+\L{\LB{}\Tab{4}{\K{if}_(!\V{fp})_\{}}
+\L{\LB{}\Tab{8}{\K{if}_(*\V{mode}_==_\S{}{'}r{'}\SE{})}}
+\L{\LB{}\Tab{12}{\V{modestr}_=_\S{}\3reading\3\SE{};}}
+\L{\LB{}\Tab{8}{\K{else}}}
+\L{\LB{}\Tab{12}{\V{modestr}_=_\S{}\3writing\3\SE{};}}
+\L{\LB{}\Tab{8}{\V{fprintf}(\V{stderr},_\S{}\3gvpack:_could_not_open_file_\%s_for_\%s\2n\3\SE{},}}
+\L{\LB{}\Tab{16}{\V{name},_\V{modestr});}}
+\L{\LB{}\Tab{8}{\V{exit}(\N{1});}}
+\L{\LB{}\Tab{4}{\}}}
+\L{\LB{}\Tab{4}{\K{return}_(\V{fp});}}
+\L{\LB{\}}}
+\L{\LB{}}
+\L{\LB{\K{static}_\K{char}_*\V{useString}_=_\S{}\3Usage:_\%s_[\-sdv?]_\<files\>\2n\2}}
+\L{\LB{}\Tab{2}{\-s}\Tab{15}{\-_only_produce_statistics\2n\2}}
+\L{\LB{}\Tab{2}{\-S}\Tab{15}{\-_silent\2n\2}}
+\L{\LB{}\Tab{2}{\-d}\Tab{15}{\-_allow_degenerate_components\2n\2}}
+\L{\LB{}\Tab{2}{\-o\<outfile\>}\Tab{15}{\-_write_to_\<outfile\>_(stdout)\2n\2}}
+\L{\LB{}\Tab{2}{\-v}\Tab{15}{\-_verbose\2n\2}}
+\L{\LB{}\Tab{2}{\-?}\Tab{15}{\-_print_usage\2n\2}}
 \L{\LB{If_no_files_are_specified,_stdin_is_used\2n\3\SE{};}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}}}
-\index{usage}\Proc{usage}\L{\LB{\V{usage}_(\K{int}_\V{v})}}
+\index{usage}\Proc{usage}\L{\LB{\K{static}_\K{void}_\V{usage}(\K{int}_\V{v})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{4}{\V{printf}_(\V{useString},_\V{CmdName});}}
-\L{\LB{}\Tab{4}{\V{exit}_(\V{v});}}
+\L{\LB{}\Tab{4}{\V{printf}(\V{useString},_\V{CmdName});}}
+\L{\LB{}\Tab{4}{\V{exit}(\V{v});}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\K{void}}}
-\index{scanArgs}\Proc{scanArgs}\L{\LB{\V{scanArgs}(\K{int}_\V{argc},\K{char}_**\V{argv})}}
+\index{scanArgs}\Proc{scanArgs}\L{\LB{\K{static}_\K{void}_\V{scanArgs}(\K{int}_\V{argc},_\K{char}_**\V{argv})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{int}}\Tab{17}{\V{c};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{CmdName}_=_\V{argv}[\N{0}];}}
-\L{\LB{}\Tab{2}{\K{while}_((\V{c}_=_\V{getopt}(\V{argc},\V{argv},\S{}\3:?sdv\3\SE{}))_!=_\V{EOF})_\{}}
-\L{\LB{}\Tab{4}{\K{switch}_(\V{c})_\{}}
-\L{\LB{}\Tab{4}{\K{case}_\S{}{'}s{'}\SE{}:_}}
-\L{\LB{}\Tab{6}{\V{Silent}_=_\N{1};_\K{break};}}
-\L{\LB{}\Tab{4}{\K{case}_\S{}{'}d{'}\SE{}:_}}
-\L{\LB{}\Tab{6}{\V{wantDegenerateComp}_=_\N{1};_\K{break};}}
-\L{\LB{}\Tab{4}{\K{case}_\S{}{'}v{'}\SE{}:_}}
-\L{\LB{}\Tab{6}{\V{Verbose}_=_\N{1};_\K{break};}}
-\L{\LB{}\Tab{4}{\K{case}_\S{}{'}?{'}\SE{}:}}
-\L{\LB{}\Tab{6}{\K{if}_(\V{optopt}_==_\S{}{'}?{'}\SE{})_\V{usage}(\N{0});}}
-\L{\LB{}\Tab{6}{\K{else}_\V{fprintf}(\V{stderr},\S{}\3\%s:_option_\-\%c_unrecognized_\-_ignored\2n\3\SE{},_}}
-\L{\LB{}\Tab{8}{\V{CmdName},_\V{c});}}
-\L{\LB{}\Tab{6}{\K{break};}}
+\L{\LB{}\Tab{4}{\K{int}_\V{c};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{CmdName}_=_\V{argv}[\N{0}];}}
+\L{\LB{}\Tab{4}{\V{opterr}_=_\N{0};}}
+\L{\LB{}\Tab{4}{\K{while}_((\V{c}_=_\V{getopt}(\V{argc},_\V{argv},_\S{}\3:o:sdvS\3\SE{}))_!=_\V{EOF})_\{}}
+\L{\LB{}\Tab{8}{\K{switch}_(\V{c})_\{}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}s{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\V{StatsOnly}_=_\N{1};}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}d{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\V{wantDegenerateComp}_=_\N{1};}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}o{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\V{outfp}_=_\V{openFile}(\V{optarg},_\S{}\3w\3\SE{});}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}v{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\V{Verbose}_=_\N{1};}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}S{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\V{Verbose}_=_\N{0};}}
+\L{\LB{}\Tab{12}{\V{Silent}_=_\N{1};}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\K{case}_\S{}{'}?{'}\SE{}:}}
+\L{\LB{}\Tab{12}{\K{if}_(\V{optopt}_==_\S{}{'}?{'}\SE{})}}
+\L{\LB{}\Tab{16}{\V{usage}(\N{0});}}
+\L{\LB{}\Tab{12}{\K{else}}}
+\L{\LB{}\Tab{16}{\V{fprintf}(\V{stderr},_\S{}\3\%s:_option_\-\%c_unrecognized_\-_ignored\2n\3\SE{},}}
+\L{\LB{}\Tab{24}{\V{CmdName},_\V{optopt});}}
+\L{\LB{}\Tab{12}{\K{break};}}
+\L{\LB{}\Tab{8}{\}}}
 \L{\LB{}\Tab{4}{\}}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}\Tab{2}{\V{argv}_+=_\V{optind};}}
-\L{\LB{}\Tab{2}{\V{argc}_\-=_\V{optind};}}
-\L{\LB{}\Tab{2}{}}
-\L{\LB{}\Tab{2}{\K{if}_(\V{argc})_\V{Files}_=_\V{argv};}}
+\L{\LB{}\Tab{4}{\V{argv}_+=_\V{optind};}}
+\L{\LB{}\Tab{4}{\V{argc}_\-=_\V{optind};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{if}_(\V{argc})}}
+\L{\LB{}\Tab{8}{\V{Files}_=_\V{argv};}}
+\L{\LB{}\Tab{4}{\K{if}_(!\V{outfp})}}
+\L{\LB{}\Tab{8}{\V{outfp}_=_\V{stdout};}\Tab{32}{\C{}/*_stdout_the_default_*/\CE{}}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{static}_\V{Agraph\_t}*}}
-\index{gread}\Proc{gread}\L{\LB{\V{gread}_(\V{FILE}*_\V{fp})}}
+\index{gread}\Proc{gread}\L{\LB{\K{static}_\V{Agraph\_t}_*\V{gread}(\V{FILE}_*_\V{fp})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\K{return}_\V{agread}(\V{fp},(\V{Agdisc\_t}*)\N{0});}}
+\L{\LB{}\Tab{4}{\K{return}_\V{agread}(\V{fp},_(\V{Agdisc\_t}_*)_\N{0});}}
 \L{\LB{\}}}
 \L{\LB{}}
-\L{\LB{\K{int}_}}
-\index{main}\Proc{main}\L{\LB{\V{main}(\K{int}_\V{argc},_\K{char}_**\V{argv})}}
+\index{main}\Proc{main}\L{\LB{\K{int}_\V{main}(\K{int}_\V{argc},_\K{char}_**\V{argv})}}
 \L{\LB{\{}}
-\L{\LB{}\Tab{2}{\V{Agraph\_t}*}\Tab{16}{\V{g};}}
-\L{\LB{}\Tab{2}{\V{ingraph\_state}_\V{ig};}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\V{scanArgs}(\V{argc},\V{argv});}}
-\L{\LB{}\Tab{2}{\V{newIngraph}_(\&\V{ig},_\V{Files},_\V{gread});}}
-\L{\LB{}\Tab{2}{}}
-\L{\LB{}\Tab{2}{\K{while}_((\V{g}_=_\V{nextGraph}(\&\V{ig}))_!=_\N{0})_\{}}
-\L{\LB{}\Tab{4}{\K{if}_(\V{agisdirected}(\V{g}))_\V{process}_(\V{g});}}
-\L{\LB{}\Tab{4}{\K{else}_\V{fprintf}_(\V{stderr},_\S{}\3Graph_\%s_in_\%s_is_undirected_\-_ignored\2n\3\SE{},_}}
-\L{\LB{}\Tab{6}{\V{agnameof}(\V{g}),_\V{fileName}(\&\V{ig}));}}
-\L{\LB{}\Tab{4}{\V{agclose}_(\V{g});}}
-\L{\LB{}\Tab{2}{\}}}
-\L{\LB{}}
-\L{\LB{}\Tab{2}{\K{return}_\N{0};}}
-\L{\LB{\}}}
+\L{\LB{}\Tab{4}{\V{Agraph\_t}_*\V{g};}}
+\L{\LB{}\Tab{4}{\V{ingraph\_state}_\V{ig};}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\V{scanArgs}(\V{argc},_\V{argv});}}
+\L{\LB{}\Tab{4}{\V{newIngraph}(\&\V{ig},_\V{Files},_\V{gread});}}
+\L{\LB{}}
+\L{\LB{}\Tab{4}{\K{while}_((\V{g}_=_\V{nextGraph}(\&\V{ig}))_!=_\N{0})_\{}}
+\L{\LB{}\Tab{8}{\K{if}_(\V{agisdirected}(\V{g}))}}
+\L{\LB{}\Tab{12}{\V{process}(\V{g});}}
+\L{\LB{}\Tab{8}{\K{else}}}
+\L{\LB{}\Tab{12}{\V{fprintf}(\V{stderr},_\S{}\3Graph_\%s_in_\%s_is_undirected_\-_ignored\2n\3\SE{},}}
+\L{\LB{}\Tab{20}{\V{agnameof}(\V{g}),_\V{fileName}(\&\V{ig}));}}
+\L{\LB{}\Tab{8}{\V{agclose}(\V{g});}}
+\L{\LB{}\Tab{4}{\}}}
 \L{\LB{}}
+\L{\LB{}\Tab{4}{\K{return}_\N{0};}}
+\L{\LB{\}}}