|
Graphviz
2.31.20130618.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include <ctype.h> 00016 #include <setjmp.h> 00017 #include "render.h" 00018 #include "pack.h" 00019 00020 static jmp_buf jbuf; 00021 00022 #define MARKED(n) ND_mark(n) 00023 #define MARK(n) (ND_mark(n) = 1) 00024 #define ONSTACK(n) (ND_mark(n) = 1) 00025 #define UNMARK(n) (ND_mark(n) = 0) 00026 00027 typedef void (*dfsfn) (Agnode_t *, void *); 00028 00029 #if 0 00030 static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state) 00031 { 00032 Agedge_t *e; 00033 Agnode_t *other; 00034 00035 MARK(n); 00036 action(n, state); 00037 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { 00038 if ((other = agtail(e)) == n) 00039 other = aghead(e); 00040 if (!MARKED(other)) 00041 dfs(g, other, action, state); 00042 } 00043 } 00044 #endif 00045 00046 typedef struct blk_t { 00047 Agnode_t **data; 00048 Agnode_t **endp; 00049 struct blk_t *prev; 00050 struct blk_t *next; 00051 } blk_t; 00052 00053 typedef struct { 00054 blk_t *fstblk; 00055 blk_t *curblk; 00056 Agnode_t **curp; 00057 } stk_t; 00058 00059 #define INITBUF 1024 00060 #define BIGBUF 1000000 00061 00062 static void initStk(stk_t* sp, blk_t* bp, Agnode_t** base) 00063 { 00064 bp->data = base; 00065 bp->endp = bp->data + INITBUF; 00066 bp->prev = bp->next = NULL; 00067 sp->curblk = sp->fstblk = bp; 00068 sp->curp = sp->curblk->data; 00069 } 00070 00071 static void freeBlk (blk_t* bp) 00072 { 00073 free (bp->data); 00074 free (bp); 00075 } 00076 00077 static void freeStk (stk_t* sp) 00078 { 00079 blk_t* bp; 00080 blk_t* nxtbp; 00081 00082 for (bp = sp->fstblk->next; bp; bp = nxtbp) { 00083 nxtbp = bp->next; 00084 freeBlk (bp); 00085 } 00086 } 00087 00088 static void push(stk_t* sp, Agnode_t * np) 00089 { 00090 if (sp->curp == sp->curblk->endp) { 00091 if (sp->curblk->next == NULL) { 00092 blk_t *bp = GNEW(blk_t); 00093 if (bp == 0) { 00094 agerr(AGERR, "gc: Out of memory\n"); 00095 longjmp(jbuf, 1); 00096 } 00097 bp->prev = sp->curblk; 00098 bp->next = NULL; 00099 bp->data = N_GNEW(BIGBUF, Agnode_t *); 00100 if (bp->data == 0) { 00101 agerr(AGERR, "gc: Out of memory\n"); 00102 longjmp(jbuf, 1); 00103 } 00104 bp->endp = bp->data + BIGBUF; 00105 sp->curblk->next = bp; 00106 } 00107 sp->curblk = sp->curblk->next; 00108 sp->curp = sp->curblk->data; 00109 } 00110 ONSTACK(np); 00111 *sp->curp++ = np; 00112 } 00113 00114 static Agnode_t *pop(stk_t* sp) 00115 { 00116 if (sp->curp == sp->curblk->data) { 00117 if (sp->curblk == sp->fstblk) 00118 return 0; 00119 sp->curblk = sp->curblk->prev; 00120 sp->curp = sp->curblk->endp; 00121 } 00122 sp->curp--; 00123 return *sp->curp; 00124 } 00125 00126 00127 static void dfs(Agraph_t * g, Agnode_t * n, dfsfn action, void *state, stk_t* stk) 00128 { 00129 Agedge_t *e; 00130 Agnode_t *other; 00131 00132 push (stk, n); 00133 while ((n = pop(stk))) { 00134 MARK(n); 00135 action(n, state); 00136 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { 00137 if ((other = agtail(e)) == n) 00138 other = aghead(e); 00139 if (!MARKED(other)) 00140 push(stk, other); 00141 } 00142 } 00143 } 00144 00145 static int isLegal(char *p) 00146 { 00147 unsigned char c; 00148 00149 while ((c = *(unsigned char *) p++)) { 00150 if ((c != '_') && !isalnum(c)) 00151 return 0; 00152 } 00153 00154 return 1; 00155 } 00156 00157 /* insertFn: 00158 */ 00159 static void insertFn(Agnode_t * n, void *state) 00160 { 00161 #ifndef WITH_CGRAPH 00162 aginsert((Agraph_t *) state, n); 00163 #else /* WITH_CGRAPH */ 00164 agsubnode((Agraph_t *) state,n,1); 00165 #endif /* WITH_CGRAPH */ 00166 } 00167 00168 /* pccomps: 00169 * Return an array of subgraphs consisting of the connected 00170 * components of graph g. The number of components is returned in ncc. 00171 * All pinned nodes are in one component. 00172 * If pfx is non-null and a legal graph name, we use it as the prefix 00173 * for the name of the subgraphs created. If not, a simple default is used. 00174 * If pinned is non-null, *pinned set to 1 if pinned nodes found 00175 * and the first component is the one containing the pinned nodes. 00176 * Note that the component subgraphs do not contain any edges. These must 00177 * be obtained from the root graph. 00178 * Return NULL on error or if graph is empty. 00179 */ 00180 Agraph_t **pccomps(Agraph_t * g, int *ncc, char *pfx, boolean * pinned) 00181 { 00182 int c_cnt = 0; 00183 char buffer[SMALLBUF]; 00184 char *name; 00185 Agraph_t *out = 0; 00186 Agnode_t *n; 00187 Agraph_t **ccs; 00188 int len; 00189 int bnd = 10; 00190 boolean pin = FALSE; 00191 stk_t stk; 00192 blk_t blk; 00193 Agnode_t* base[INITBUF]; 00194 int error = 0; 00195 00196 if (agnnodes(g) == 0) { 00197 *ncc = 0; 00198 return 0; 00199 } 00200 if (!pfx || !isLegal(pfx)) { 00201 pfx = "_cc_"; 00202 } 00203 len = strlen(pfx); 00204 if (len + 25 <= SMALLBUF) 00205 name = buffer; 00206 else 00207 name = (char *) gmalloc(len + 25); 00208 strcpy(name, pfx); 00209 00210 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 00211 UNMARK(n); 00212 00213 ccs = N_GNEW(bnd, Agraph_t *); 00214 00215 initStk (&stk, &blk, base); 00216 if (setjmp(jbuf)) { 00217 error = 1; 00218 goto packerror; 00219 } 00220 /* Component with pinned nodes */ 00221 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00222 if (MARKED(n) || !isPinned(n)) 00223 continue; 00224 if (!out) { 00225 sprintf(name + len, "%d", c_cnt); 00226 #ifndef WITH_CGRAPH 00227 out = agsubg(g, name); 00228 #else /* WITH_CGRAPH */ 00229 out = agsubg(g, name,1); 00230 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); //node custom data 00231 #endif /* WITH_CGRAPH */ 00232 ccs[c_cnt] = out; 00233 c_cnt++; 00234 pin = TRUE; 00235 } 00236 dfs (g, n, insertFn, out, &stk); 00237 } 00238 00239 /* Remaining nodes */ 00240 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00241 if (MARKED(n)) 00242 continue; 00243 sprintf(name + len, "%d", c_cnt); 00244 #ifndef WITH_CGRAPH 00245 out = agsubg(g, name); 00246 #else /* WITH_CGRAPH */ 00247 out = agsubg(g, name,1); 00248 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); //node custom data 00249 #endif /* WITH_CGRAPH */ 00250 dfs(g, n, insertFn, out, &stk); 00251 if (c_cnt == bnd) { 00252 bnd *= 2; 00253 ccs = RALLOC(bnd, ccs, Agraph_t *); 00254 } 00255 ccs[c_cnt] = out; 00256 c_cnt++; 00257 } 00258 packerror: 00259 freeStk (&stk); 00260 if (name != buffer) 00261 free(name); 00262 if (error) { 00263 int i; 00264 *ncc = 0; 00265 for (i=0; i < c_cnt; i++) { 00266 agclose (ccs[i]); 00267 } 00268 free (ccs); 00269 ccs = NULL; 00270 } 00271 else { 00272 ccs = RALLOC(c_cnt, ccs, Agraph_t *); 00273 *ncc = c_cnt; 00274 *pinned = pin; 00275 } 00276 return ccs; 00277 } 00278 00279 /* ccomps: 00280 * Return an array of subgraphs consisting of the connected 00281 * components of graph g. The number of components is returned in ncc. 00282 * If pfx is non-null and a legal graph name, we use it as the prefix 00283 * for the name of the subgraphs created. If not, a simple default is used. 00284 * Note that the component subgraphs do not contain any edges. These must 00285 * be obtained from the root graph. 00286 * Returns NULL on error or if graph is empty. 00287 */ 00288 Agraph_t **ccomps(Agraph_t * g, int *ncc, char *pfx) 00289 { 00290 int c_cnt = 0; 00291 char buffer[SMALLBUF]; 00292 char *name; 00293 Agraph_t *out; 00294 Agnode_t *n; 00295 Agraph_t **ccs; 00296 int len; 00297 int bnd = 10; 00298 stk_t stk; 00299 blk_t blk; 00300 Agnode_t* base[INITBUF]; 00301 00302 if (agnnodes(g) == 0) { 00303 *ncc = 0; 00304 return 0; 00305 } 00306 if (!pfx || !isLegal(pfx)) { 00307 pfx = "_cc_"; 00308 } 00309 len = strlen(pfx); 00310 if (len + 25 <= SMALLBUF) 00311 name = buffer; 00312 else { 00313 if (!(name = (char *) gmalloc(len + 25))) return NULL; 00314 } 00315 strcpy(name, pfx); 00316 00317 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 00318 UNMARK(n); 00319 00320 ccs = N_GNEW(bnd, Agraph_t *); 00321 initStk (&stk, &blk, base); 00322 if (setjmp(jbuf)) { 00323 freeStk (&stk); 00324 free (ccs); 00325 if (name != buffer) 00326 free(name); 00327 *ncc = 0; 00328 return NULL; 00329 } 00330 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00331 if (MARKED(n)) 00332 continue; 00333 sprintf(name + len, "%d", c_cnt); 00334 #ifndef WITH_CGRAPH 00335 out = agsubg(g, name); 00336 #else /* WITH_CGRAPH */ 00337 out = agsubg(g, name,1); 00338 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); //node custom data 00339 #endif /* WITH_CGRAPH */ 00340 dfs(g, n, insertFn, out, &stk); 00341 if (c_cnt == bnd) { 00342 bnd *= 2; 00343 ccs = RALLOC(bnd, ccs, Agraph_t *); 00344 } 00345 ccs[c_cnt] = out; 00346 c_cnt++; 00347 } 00348 freeStk (&stk); 00349 ccs = RALLOC(c_cnt, ccs, Agraph_t *); 00350 if (name != buffer) 00351 free(name); 00352 *ncc = c_cnt; 00353 return ccs; 00354 } 00355 00356 /* cntFn: 00357 */ 00358 static void cntFn(Agnode_t * n, void *s) 00359 { 00360 *(int *) s += 1; 00361 } 00362 00363 /* isConnected: 00364 * Returns 1 if the graph is connected. 00365 * Returns 0 if the graph is not connected. 00366 * Returns -1 if the graph is error. 00367 */ 00368 int isConnected(Agraph_t * g) 00369 { 00370 Agnode_t *n; 00371 int ret = 1; 00372 int cnt = 0; 00373 stk_t stk; 00374 blk_t blk; 00375 Agnode_t* base[INITBUF]; 00376 00377 for (n = agfstnode(g); n; n = agnxtnode(g, n)) 00378 UNMARK(n); 00379 00380 n = agfstnode(g); 00381 if (n) { 00382 initStk (&stk, &blk, base); 00383 if (setjmp(jbuf)) { 00384 freeStk (&stk); 00385 return -1; 00386 } 00387 dfs(g, n, cntFn, &cnt, &stk); 00388 if (cnt != agnnodes(g)) 00389 ret = 0; 00390 freeStk (&stk); 00391 } 00392 return ret; 00393 } 00394 00395 /* nodeInduce: 00396 * Given a subgraph, adds all edges in the root graph both of whose 00397 * endpoints are in the subgraph. 00398 * If g is a connected component, this will be all edges attached to 00399 * any node in g. 00400 * Returns the number of edges added. 00401 */ 00402 int nodeInduce(Agraph_t * g) 00403 { 00404 Agnode_t *n; 00405 Agraph_t *root = g->root; 00406 Agedge_t *e; 00407 int e_cnt = 0; 00408 00409 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00410 for (e = agfstout(root, n); e; e = agnxtout(root, e)) { 00411 if (agcontains(g, aghead(e))) { /* test will always be true */ 00412 #ifndef WITH_CGRAPH 00413 aginsert(g, e); /* for connected component */ 00414 #else /* WITH_CGRAPH */ 00415 agsubedge(g,e,1); 00416 #endif /* WITH_CGRAPH */ 00417 e_cnt++; 00418 } 00419 } 00420 } 00421 return e_cnt; 00422 }
1.7.5