/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/pack/ccomps.c

Go to the documentation of this file.
00001 /* $Id: ccomps.c,v 1.3 2006/12/07 22:49:37 erg Exp $ $Revision: 1.3 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 
00018 #include <render.h>
00019 #include <pack.h>
00020 #include <ctype.h>
00021 
00022 #define MARKED(n) ((n)->u.mark)
00023 #define MARK(n) ((n)->u.mark = 1)
00024 #define UNMARK(n) ((n)->u.mark = 0)
00025 
00026 typedef void (*dfsfn) (Agnode_t *, void *);
00027 
00028 static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state)
00029 {
00030     Agedge_t *e;
00031     Agnode_t *other;
00032 
00033     MARK(n);
00034     action(n, state);
00035     for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00036         if ((other = e->tail) == n)
00037             other = e->head;
00038         if (!MARKED(other))
00039             dfs(g, other, action, state);
00040     }
00041 }
00042 
00043 static int isLegal(char *p)
00044 {
00045     unsigned char c;
00046 
00047     while ((c = *(unsigned char *) p++)) {
00048         if ((c != '_') && !isalnum(c))
00049             return 0;
00050     }
00051 
00052     return 1;
00053 }
00054 
00055 /* insertFn:
00056  */
00057 static void insertFn(Agnode_t * n, void *state)
00058 {
00059     aginsert((Agraph_t *) state, n);
00060 }
00061 
00062 /* pccomps:
00063  * Return an array of subgraphs consisting of the connected 
00064  * components of graph g. The number of components is returned in ncc. 
00065  * All pinned nodes are in one component.
00066  * If pfx is non-null and a legal graph name, we use it as the prefix
00067  * for the name of the subgraphs created. If not, a simple default is used.
00068  * If pinned is non-null, *pinned set to 1 if pinned nodes found
00069  * and the first component is the one containing the pinned nodes.
00070  * Note that the component subgraphs do not contain any edges. These must
00071  * be obtained from the root graph.
00072  */
00073 Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned)
00074 {
00075     int c_cnt = 0;
00076     char buffer[SMALLBUF];
00077     char *name;
00078     Agraph_t *out = 0;
00079     Agnode_t *n;
00080     Agraph_t **ccs;
00081     int len;
00082     int bnd = 10;
00083     boolean pin = FALSE;
00084 
00085     if (agnnodes(g) == 0) {
00086         *ncc = 0;
00087         return 0;
00088     }
00089     if (!pfx || !isLegal(pfx)) {
00090         pfx = "_cc_";
00091     }
00092     len = strlen(pfx);
00093     if (len + 25 <= SMALLBUF)
00094         name = buffer;
00095     else
00096         name = (char *) gmalloc(len + 25);
00097     strcpy(name, pfx);
00098 
00099     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00100         UNMARK(n);
00101 
00102     ccs = N_GNEW(bnd, Agraph_t *);
00103 
00104     /* Component with pinned nodes */
00105     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00106         if (MARKED(n) || !isPinned(n))
00107             continue;
00108         if (!out) {
00109             sprintf(name + len, "%d", c_cnt);
00110             out = agsubg(g, name);
00111             ccs[c_cnt] = out;
00112             c_cnt++;
00113             pin = TRUE;
00114         }
00115         dfs(g, n, insertFn, out);
00116     }
00117 
00118     /* Remaining nodes */
00119     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00120         if (MARKED(n))
00121             continue;
00122         sprintf(name + len, "%d", c_cnt);
00123         out = agsubg(g, name);
00124         dfs(g, n, insertFn, out);
00125         if (c_cnt == bnd) {
00126             bnd *= 2;
00127             ccs = RALLOC(bnd, ccs, Agraph_t *);
00128         }
00129         ccs[c_cnt] = out;
00130         c_cnt++;
00131     }
00132 
00133     ccs = RALLOC(c_cnt, ccs, Agraph_t *);
00134     if (name != buffer)
00135         free(name);
00136     *ncc = c_cnt;
00137     *pinned = pin;
00138     return ccs;
00139 }
00140 
00141 /* ccomps:
00142  * Return an array of subgraphs consisting of the connected
00143  * components of graph g. The number of components is returned in ncc.
00144  * If pfx is non-null and a legal graph name, we use it as the prefix
00145  * for the name of the subgraphs created. If not, a simple default is used.
00146  * Note that the component subgraphs do not contain any edges. These must
00147  * be obtained from the root graph.
00148  */
00149 Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx)
00150 {
00151     int c_cnt = 0;
00152     char buffer[SMALLBUF];
00153     char *name;
00154     Agraph_t *out;
00155     Agnode_t *n;
00156     Agraph_t **ccs;
00157     int len;
00158     int bnd = 10;
00159 
00160     if (agnnodes(g) == 0) {
00161         *ncc = 0;
00162         return 0;
00163     }
00164     if (!pfx || !isLegal(pfx)) {
00165         pfx = "_cc_";
00166     }
00167     len = strlen(pfx);
00168     if (len + 25 <= SMALLBUF)
00169         name = buffer;
00170     else
00171         name = (char *) gmalloc(len + 25);
00172     strcpy(name, pfx);
00173 
00174     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00175         UNMARK(n);
00176 
00177     ccs = N_GNEW(bnd, Agraph_t *);
00178     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00179         if (MARKED(n))
00180             continue;
00181         sprintf(name + len, "%d", c_cnt);
00182         out = agsubg(g, name);
00183         dfs(g, n, insertFn, out);
00184         if (c_cnt == bnd) {
00185             bnd *= 2;
00186             ccs = RALLOC(bnd, ccs, Agraph_t *);
00187         }
00188         ccs[c_cnt] = out;
00189         c_cnt++;
00190     }
00191     ccs = RALLOC(c_cnt, ccs, Agraph_t *);
00192     if (name != buffer)
00193         free(name);
00194     *ncc = c_cnt;
00195     return ccs;
00196 }
00197 
00198 /* cntFn:
00199  */
00200 static void cntFn(Agnode_t * n, void *s)
00201 {
00202     *(int *) s += 1;
00203 }
00204 
00205 /* isConnected:
00206  * Returns true if the graph is connected.
00207  */
00208 int isConnected(Agraph_t * g)
00209 {
00210     Agnode_t *n;
00211     int ret = 1;
00212     int cnt = 0;
00213 
00214     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00215         UNMARK(n);
00216 
00217     n = agfstnode(g);
00218     if (n) {
00219         dfs(g, n, cntFn, &cnt);
00220         if (cnt != agnnodes(g))
00221             ret = 0;
00222     }
00223     return ret;
00224 }
00225 
00226 /* nodeInduce:
00227  * Given a subgraph, adds all edges in the root graph both of whose
00228  * endpoints are in the subgraph.
00229  * If g is a connected component, this will be all edges attached to
00230  * any node in g.
00231  * Returns the number of edges added.
00232  */
00233 int nodeInduce(Agraph_t * g)
00234 {
00235     Agnode_t *n;
00236     Agraph_t *root = g->root;
00237     Agedge_t *e;
00238     int e_cnt = 0;
00239 
00240     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00241         for (e = agfstout(root, n); e; e = agnxtout(root, e)) {
00242             if (agcontains(g, e->head)) {       /* test will always be true */
00243                 aginsert(g, e); /* for connected component  */
00244                 e_cnt++;
00245             }
00246         }
00247     }
00248     return e_cnt;
00249 }

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1