Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
ccomps.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <limits.h>
12#include <stdlib.h>
13#include <cgraph/agxbuf.h>
14#include <cgraph/alloc.h>
15#include <cgraph/cgraph.h>
16#include <cgraph/gv_ctype.h>
17#include <cgraph/prisize_t.h>
18#include <cgraph/stack.h>
19#include <cgraph/startswith.h>
20#include <common/render.h>
21#include <common/utils.h>
22#include <pack/pack.h>
23#include <stdbool.h>
24
25typedef struct {
26 gv_stack_t data;
27 void (*actionfn) (Agnode_t *, void *);
28 bool (*markfn)(Agnode_t *, int);
29} stk_t;
30
32static bool marked(const stk_t *stk, Agnode_t *n) {
33 return stk->markfn(n, -1);
34}
35
37static void mark(const stk_t *stk, Agnode_t *n) {
38 stk->markfn(n, 1);
39}
40
42static void unmark(const stk_t *stk, Agnode_t *n) {
43 stk->markfn(n, 0);
44}
45
46static void initStk(stk_t *sp, void (*actionfn)(Agnode_t*, void*),
47 bool (*markfn)(Agnode_t *, int))
48{
49 sp->data = (gv_stack_t){0};
50 sp->actionfn = actionfn;
51 sp->markfn = markfn;
52}
53
54static void freeStk (stk_t* sp)
55{
56 stack_reset(&sp->data);
57}
58
59static void push(stk_t *sp, Agnode_t *np) {
60 mark(sp, np);
61 stack_push(&sp->data, np);
62}
63
64static Agnode_t *pop(stk_t* sp)
65{
66 if (stack_is_empty(&sp->data)) {
67 return NULL;
68 }
69
70 return stack_pop(&sp->data);
71}
72
73
74static size_t dfs(Agraph_t * g, Agnode_t * n, void *state, stk_t* stk)
75{
76 Agedge_t *e;
77 Agnode_t *other;
78 size_t cnt = 0;
79
80 push(stk, n);
81 while ((n = pop(stk))) {
82 cnt++;
83 if (stk->actionfn) stk->actionfn(n, state);
84 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
85 if ((other = agtail(e)) == n)
86 other = aghead(e);
87 if (!marked(stk, other))
88 push(stk, other);
89 }
90 }
91 return cnt;
92}
93
94static int isLegal(const char *p) {
95 char c;
96
97 while ((c = *p++)) {
98 if (c != '_' && !gv_isalnum(c))
99 return 0;
100 }
101
102 return 1;
103}
104
105static void insertFn(Agnode_t * n, void *state)
106{
107 agsubnode(state, n, 1);
108}
109
110static bool markFn(Agnode_t *n, int v) {
111 if (v < 0) return ND_mark(n) != 0;
112 const size_t ret = ND_mark(n);
113 ND_mark(n) = v != 0;
114 return ret != 0;
115}
116
117static void setPrefix(agxbuf *xb, const char *pfx) {
118 if (!pfx || !isLegal(pfx)) {
119 pfx = "_cc_";
120 }
121 agxbput(xb, pfx);
122}
123
124/* pccomps:
125 * Return an array of subgraphs consisting of the connected
126 * components of graph g. The number of components is returned in ncc.
127 * All pinned nodes are in one component.
128 * If pfx is non-null and a legal graph name, we use it as the prefix
129 * for the name of the subgraphs created. If not, a simple default is used.
130 * If pinned is non-null, *pinned set to 1 if pinned nodes found
131 * and the first component is the one containing the pinned nodes.
132 * Note that the component subgraphs do not contain any edges. These must
133 * be obtained from the root graph.
134 * Return NULL if graph is empty.
135 */
136Agraph_t **pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned) {
137 size_t c_cnt = 0;
138 agxbuf name = {0};
139 Agraph_t *out = NULL;
140 Agnode_t *n;
141 size_t bnd = 10;
142 bool pin = false;
143 stk_t stk;
144
145 if (agnnodes(g) == 0) {
146 *ncc = 0;
147 return NULL;
148 }
149
150 Agraph_t **ccs = gv_calloc(bnd, sizeof(Agraph_t*));
151
152 initStk(&stk, insertFn, markFn);
153 for (n = agfstnode(g); n; n = agnxtnode(g, n))
154 unmark(&stk, n);
155
156 /* Component with pinned nodes */
157 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
158 if (marked(&stk, n) || !isPinned(n))
159 continue;
160 if (!out) {
161 setPrefix(&name, pfx);
162 agxbprint(&name, "%" PRISIZE_T, c_cnt);
163 out = agsubg(g, agxbuse(&name),1);
164 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
165 ccs[c_cnt] = out;
166 c_cnt++;
167 pin = true;
168 }
169 dfs(g, n, out, &stk);
170 }
171
172 /* Remaining nodes */
173 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
174 if (marked(&stk, n))
175 continue;
176 setPrefix(&name, pfx);
177 agxbprint(&name, "%" PRISIZE_T, c_cnt);
178 out = agsubg(g, agxbuse(&name), 1);
179 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
180 dfs(g, n, out, &stk);
181 if (c_cnt == bnd) {
182 ccs = gv_recalloc(ccs, bnd, bnd * 2, sizeof(Agraph_t*));
183 bnd *= 2;
184 }
185 ccs[c_cnt] = out;
186 c_cnt++;
187 }
188 freeStk (&stk);
189 agxbfree(&name);
190 ccs = gv_recalloc(ccs, bnd, c_cnt, sizeof(Agraph_t*));
191 *ncc = c_cnt;
192 *pinned = pin;
193 return ccs;
194}
195
196/* ccomps:
197 * Return an array of subgraphs consisting of the connected
198 * components of graph g. The number of components is returned in ncc.
199 * If pfx is non-null and a legal graph name, we use it as the prefix
200 * for the name of the subgraphs created. If not, a simple default is used.
201 * Note that the component subgraphs do not contain any edges. These must
202 * be obtained from the root graph.
203 * Returns NULL on error or if graph is empty.
204 */
205Agraph_t **ccomps(Agraph_t *g, size_t *ncc, char *pfx) {
206 size_t c_cnt = 0;
207 agxbuf name = {0};
208 Agraph_t *out;
209 Agnode_t *n;
210 size_t bnd = 10;
211 stk_t stk;
212
213 if (agnnodes(g) == 0) {
214 *ncc = 0;
215 return NULL;
216 }
217
218 Agraph_t **ccs = gv_calloc(bnd, sizeof(Agraph_t*));
219 initStk(&stk, insertFn, markFn);
220 for (n = agfstnode(g); n; n = agnxtnode(g, n))
221 unmark(&stk, n);
222
223 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
224 if (marked(&stk, n))
225 continue;
226 setPrefix(&name, pfx);
227 agxbprint(&name, "%" PRISIZE_T, c_cnt);
228 out = agsubg(g, agxbuse(&name), 1);
229 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
230 if (dfs(g, n, out, &stk) == SIZE_MAX) {
231 freeStk (&stk);
232 free (ccs);
233 agxbfree(&name);
234 *ncc = 0;
235 return NULL;
236 }
237 if (c_cnt == bnd) {
238 ccs = gv_recalloc(ccs, bnd, bnd * 2, sizeof(Agraph_t*));
239 bnd *= 2;
240 }
241 ccs[c_cnt] = out;
242 c_cnt++;
243 }
244 freeStk (&stk);
245 ccs = gv_recalloc(ccs, bnd, c_cnt, sizeof(Agraph_t*));
246 agxbfree(&name);
247 *ncc = c_cnt;
248 return ccs;
249}
250
251typedef struct {
253 char cc_subg; /* true iff subgraph corresponds to a component */
255
256typedef struct {
258 char mark;
259 union {
262 void* v;
263 } ptr;
265
266#define GRECNAME "ccgraphinfo"
267#define NRECNAME "ccgnodeinfo"
268#define GD_cc_subg(g) (((ccgraphinfo_t*)aggetrec(g, GRECNAME, 0))->cc_subg)
269#ifdef DEBUG
271dnodeOf (Agnode_t* v)
272{
274 if (ip)
275 return ip->ptr.n;
276 fprintf (stderr, "nodeinfo undefined\n");
277 return NULL;
278}
279void
281{
282 ((ccgnodeinfo_t*)aggetrec(v, NRECNAME, 0))->ptr.n = n;
283}
284#else
285#define dnodeOf(v) (((ccgnodeinfo_t*)aggetrec(v, NRECNAME, 0))->ptr.n)
286#define dnodeSet(v,w) (((ccgnodeinfo_t*)aggetrec(v, NRECNAME, 0))->ptr.n=w)
287#endif
288
289#define ptrOf(np) (((ccgnodeinfo_t*)((np)->base.data))->ptr.v)
290#define nodeOf(np) (((ccgnodeinfo_t*)((np)->base.data))->ptr.n)
291#define clustOf(np) (((ccgnodeinfo_t*)((np)->base.data))->ptr.g)
292#define clMark(n) (((ccgnodeinfo_t*)(n->base.data))->mark)
293
294/* deriveClusters:
295 * Construct nodes in derived graph corresponding top-level clusters.
296 * Since a cluster might be wrapped in a subgraph, we need to traverse
297 * down into the tree of subgraphs
298 */
299static void deriveClusters(Agraph_t* dg, Agraph_t * g)
300{
301 Agraph_t *subg;
302 Agnode_t *dn;
303 Agnode_t *n;
304
305 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
306 if (is_a_cluster(subg)) {
307 dn = agnode(dg, agnameof(subg), 1);
308 agbindrec (dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
309 clustOf(dn) = subg;
310 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
311 if (dnodeOf(n)) {
312 fprintf (stderr, "Error: node \"%s\" belongs to two non-nested clusters \"%s\" and \"%s\"\n",
313 agnameof (n), agnameof(subg), agnameof(dnodeOf(n)));
314 }
315 dnodeSet(n,dn);
316 }
317 }
318 else {
319 deriveClusters (dg, subg);
320 }
321 }
322}
323
324/* deriveGraph:
325 * Create derived graph dg of g where nodes correspond to top-level nodes
326 * or clusters, and there is an edge in dg if there is an edge in g
327 * between any nodes in the respective clusters.
328 */
330{
331 Agraph_t *dg;
332 Agnode_t *dn;
333 Agnode_t *n;
334
335 dg = agopen("dg", Agstrictundirected, NULL);
336
337 deriveClusters (dg, g);
338
339 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
340 if (dnodeOf(n))
341 continue;
342 dn = agnode(dg, agnameof(n), 1);
343 agbindrec (dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
344 nodeOf(dn) = n;
345 dnodeSet(n,dn);
346 }
347
348 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
349 Agedge_t *e;
350 Agnode_t *hd;
351 Agnode_t *tl = dnodeOf(n);
352 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
353 hd = aghead(e);
354 hd = dnodeOf(hd);
355 if (hd == tl)
356 continue;
357 if (hd > tl)
358 agedge(dg, tl, hd, NULL, 1);
359 else
360 agedge(dg, hd, tl, NULL, 1);
361 }
362 }
363
364 return dg;
365}
366
367/* unionNodes:
368 * Add all nodes in cluster nodes of dg to g
369 */
370static void unionNodes(Agraph_t * dg, Agraph_t * g)
371{
372 Agnode_t *n;
373 Agnode_t *dn;
374 Agraph_t *clust;
375
376 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
377 if (AGTYPE(ptrOf(dn)) == AGNODE) {
378 agsubnode(g, nodeOf(dn), 1);
379 } else {
380 clust = clustOf(dn);
381 for (n = agfstnode(clust); n; n = agnxtnode(clust, n))
382 agsubnode(g, n, 1);
383 }
384 }
385}
386
387static bool clMarkFn(Agnode_t *n, int v) {
388 int ret;
389 if (v < 0) return clMark(n) != 0;
390 ret = clMark(n);
391 clMark(n) = (char) v;
392 return ret != 0;
393}
394
395typedef struct {
398} orig_t;
399
400#define ORIG_REC "orig"
401
404{
405 orig_t* op = (orig_t*)aggetrec(cl, ORIG_REC, 0);
406 assert (op);
407 return op->orig;
408}
409
410/* projectG:
411 * If any nodes of subg are in g, create a subgraph of g
412 * and fill it with all nodes of subg in g and their induced
413 * edges in subg. Copy the attributes of subg to g. Return the subgraph.
414 * If not, return null.
415 * If subg is a cluster, the new subgraph will contain a pointer to it
416 * in the record "orig".
417 */
418static Agraph_t *projectG(Agraph_t * subg, Agraph_t * g, int inCluster)
419{
420 Agraph_t *proj = NULL;
421 Agnode_t *n;
422 Agnode_t *m;
423 orig_t *op;
424
425 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
426 if ((m = agfindnode(g, agnameof(n)))) {
427 if (proj == NULL) {
428 proj = agsubg(g, agnameof(subg), 1);
429 }
430 agsubnode(proj, m, 1);
431 }
432 }
433 if (!proj && inCluster) {
434 proj = agsubg(g, agnameof(subg), 1);
435 }
436 if (proj) {
437 (void)graphviz_node_induce(proj, subg);
438 agcopyattr(subg, proj);
439 if (is_a_cluster(proj)) {
440 op = agbindrec(proj,ORIG_REC, sizeof(orig_t), false);
441 op->orig = subg;
442 }
443 }
444
445 return proj;
446}
447
448/* subgInduce:
449 * Project subgraphs of root graph on subgraph.
450 * If non-empty, add to subgraph.
451 */
452static void
453subgInduce(Agraph_t * root, Agraph_t * g, int inCluster)
454{
455 Agraph_t *subg;
456 Agraph_t *proj;
457 int in_cluster;
458
459 for (subg = agfstsubg(root); subg; subg = agnxtsubg(subg)) {
460 if (GD_cc_subg(subg))
461 continue;
462 if ((proj = projectG(subg, g, inCluster))) {
463 in_cluster = (inCluster || is_a_cluster(subg));
464 subgInduce(subg, proj, in_cluster);
465 }
466 }
467}
468
469static void
471{
472 subgInduce(g, out, 0);
473}
474
475/* cccomps:
476 * Decompose g into "connected" components, where nodes are connected
477 * either by an edge or by being in the same cluster. The components
478 * are returned in an array of subgraphs. ncc indicates how many components
479 * there are. The subgraphs use the prefix pfx in their names, if non-NULL.
480 * Note that cluster subgraph of the main graph, corresponding to a component,
481 * is cloned within the subgraph. Each cloned cluster contains a record pointing
482 * to the real cluster.
483 */
484Agraph_t **cccomps(Agraph_t *g, size_t *ncc, char *pfx) {
485 Agraph_t *dg;
486 size_t n_cnt, c_cnt, e_cnt;
487 agxbuf name = {0};
488 Agraph_t *out;
489 Agraph_t *dout;
490 Agnode_t *dn;
491 stk_t stk;
492 int sz = (int) sizeof(ccgraphinfo_t);
493
494 if (agnnodes(g) == 0) {
495 *ncc = 0;
496 return NULL;
497 }
498
499 /* Bind ccgraphinfo to graph and all subgraphs */
500 aginit(g, AGRAPH, GRECNAME, -sz, false);
501
502 /* Bind ccgraphinfo to graph and all subgraphs */
503 aginit(g, AGNODE, NRECNAME, sizeof(ccgnodeinfo_t), false);
504
505 dg = deriveGraph(g);
506
507 size_t ccs_length = (size_t)agnnodes(dg);
508 Agraph_t **ccs = gv_calloc(ccs_length, sizeof(Agraph_t*));
509 initStk(&stk, insertFn, clMarkFn);
510
511 c_cnt = 0;
512 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
513 if (marked(&stk, dn))
514 continue;
515 setPrefix(&name, pfx);
516 agxbprint(&name, "%" PRISIZE_T, c_cnt);
517 char *name_str = agxbuse(&name);
518 dout = agsubg(dg, name_str, 1);
519 out = agsubg(g, name_str, 1);
520 agbindrec(out, GRECNAME, sizeof(ccgraphinfo_t), false);
521 GD_cc_subg(out) = 1;
522 n_cnt = dfs(dg, dn, dout, &stk);
523 if (n_cnt == SIZE_MAX) {
524 agclose(dg);
525 agclean (g, AGRAPH, GRECNAME);
526 agclean (g, AGNODE, NRECNAME);
527 freeStk (&stk);
528 free(ccs);
529 agxbfree(&name);
530 *ncc = 0;
531 return NULL;
532 }
533 unionNodes(dout, out);
534 e_cnt = graphviz_node_induce(out, NULL);
535 subGInduce(g, out);
536 ccs[c_cnt] = out;
537 agdelete(dg, dout);
538 if (Verbose)
539 fprintf(stderr, "(%4" PRISIZE_T ") %7" PRISIZE_T " nodes %7" PRISIZE_T
540 " edges\n", c_cnt, n_cnt, e_cnt);
541 c_cnt++;
542 }
543
544 if (Verbose)
545 fprintf(stderr, " %7d nodes %7d edges %7" PRISIZE_T " components %s\n",
546 agnnodes(g), agnedges(g), c_cnt, agnameof(g));
547
548 agclose(dg);
549 agclean (g, AGRAPH, GRECNAME);
550 agclean (g, AGNODE, NRECNAME);
551 freeStk (&stk);
552 ccs = gv_recalloc(ccs, ccs_length, c_cnt, sizeof(Agraph_t*));
553 agxbfree(&name);
554 *ncc = c_cnt;
555 return ccs;
556}
557
558/* isConnected:
559 * Returns 1 if the graph is connected.
560 * Returns 0 if the graph is not connected.
561 * Returns -1 if the graph is error.
562 */
564{
565 Agnode_t *n;
566 int ret = 1;
567 size_t cnt = 0;
568 stk_t stk;
569
570 if (agnnodes(g) == 0)
571 return 1;
572
573 initStk(&stk, NULL, markFn);
574 for (n = agfstnode(g); n; n = agnxtnode(g, n))
575 unmark(&stk, n);
576
577 n = agfstnode(g);
578 cnt = dfs(g, agfstnode(g), NULL, &stk);
579 freeStk (&stk);
580 if (cnt == SIZE_MAX) { /* dfs failed */
581 return -1;
582 }
583 if (cnt != (size_t) agnnodes(g))
584 ret = 0;
585 return ret;
586}
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:84
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:77
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:213
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
abstract graph C library, Cgraph API
static Agnode_t * pop(void)
Definition ccomps.c:237
static void deriveClusters(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:371
static Agraph_t * deriveGraph(Agraph_t *g)
Definition ccomps.c:401
static void unionNodes(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:441
static Agraph_t * projectG(Agraph_t *subg, Agraph_t *g, int inCluster)
Definition ccomps.c:311
static void subGInduce(Agraph_t *g, Agraph_t *out)
Definition ccomps.c:358
static void subgInduce(Agraph_t *root, Agraph_t *g, int inCluster)
Definition ccomps.c:341
static int dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out)
Definition ccomps.c:245
static void push(Agnode_t *np)
Definition ccomps.c:231
#define GD_cc_subg(g)
Definition ccomps.c:48
bool is_a_cluster(Agraph_t *g)
Definition utils.c:691
static int Verbose
Definition gml2gv.c:22
void free(void *)
#define SIZE_MAX
Definition gmlscan.c:347
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
int agnedges(Agraph_t *g)
Definition graph.c:164
int agnnodes(Agraph_t *g)
Definition graph.c:158
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:9
int agcopyattr(void *oldobj, void *newobj)
copies all of the attributes from one object to another
Definition attr.c:552
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:260
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:23
#define agtail(e)
Definition cgraph.h:889
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:93
#define aghead(e)
Definition cgraph.h:890
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:84
Agdesc_t Agstrictundirected
strict undirected
Definition graph.c:276
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:96
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:44
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:147
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:261
#define agfindnode(g, n)
Definition types.h:611
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:19
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agrec_t * aggetrec(void *obj, const char *name, int move_to_front)
find record in circular list and do optional move-to-front and lock
Definition rec.c:40
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:169
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:88
void agclean(Agraph_t *g, int kind, char *rec_name)
calls agdelrec for all objects of the same class in an entire graph
Definition rec.c:201
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:77
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:82
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:57
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static lexstate_t state
Definition htmllex.c:61
#define ND_mark(n)
Definition acyclic.c:28
static void unmark(const stk_t *stk, Agnode_t *n)
unset a mark on n
Definition ccomps.c:42
static bool marked(const stk_t *stk, Agnode_t *n)
does n have a mark set?
Definition ccomps.c:32
#define clMark(n)
Definition ccomps.c:292
static void freeStk(stk_t *sp)
Definition ccomps.c:54
Agraph_t ** pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned)
Definition ccomps.c:136
static int isLegal(const char *p)
Definition ccomps.c:94
static void setPrefix(agxbuf *xb, const char *pfx)
Definition ccomps.c:117
#define dnodeOf(v)
Definition ccomps.c:285
static void mark(const stk_t *stk, Agnode_t *n)
set a mark on n
Definition ccomps.c:37
static void insertFn(Agnode_t *n, void *state)
Definition ccomps.c:105
static bool markFn(Agnode_t *n, int v)
Definition ccomps.c:110
#define GRECNAME
Definition ccomps.c:266
#define nodeOf(np)
Definition ccomps.c:290
#define ORIG_REC
Definition ccomps.c:400
Agraph_t ** ccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:205
int isConnected(Agraph_t *g)
Definition ccomps.c:563
Agraph_t ** cccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:484
#define clustOf(np)
Definition ccomps.c:291
static bool clMarkFn(Agnode_t *n, int v)
Definition ccomps.c:387
static void initStk(stk_t *sp, void(*actionfn)(Agnode_t *, void *), bool(*markfn)(Agnode_t *, int))
Definition ccomps.c:46
#define dnodeSet(v, w)
Definition ccomps.c:286
#define NRECNAME
Definition ccomps.c:267
#define ptrOf(np)
Definition ccomps.c:289
Agraph_t * mapClust(Agraph_t *cl)
Definition ccomps.c:403
#define isPinned(n)
Definition macros.h:17
support for connected components
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
Implementation of a dynamically expanding stack data structure.
static void stack_push(gv_stack_t *stack, void *item)
Definition stack.h:21
static void * stack_pop(gv_stack_t *stack)
Definition stack.h:33
static void stack_reset(gv_stack_t *stack)
Definition stack.h:35
static bool stack_is_empty(const gv_stack_t *stack)
Definition stack.h:17
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
Agrec_t h
Definition ccomps.c:257
Agraph_t * g
Definition ccomps.c:260
void * v
Definition ccomps.c:262
union ccgnodeinfo_t::@103 ptr
Agnode_t * n
Definition ccomps.c:261
char cc_subg
Definition ccomps.c:253
Agrec_t h
Definition ccomps.c:252
Agrec_t h
Definition ccomps.c:396
Agraph_t * orig
Definition ccomps.c:397
Definition ccomps.c:25
gv_stack_t data
Definition ccomps.c:26
void(* actionfn)(Agnode_t *, void *)
Definition ccomps.c:27
bool(* markfn)(Agnode_t *, int)
Definition ccomps.c:28