Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
ccomps.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16
17/*
18 * Written by Stephen North
19 * Updated by Emden Gansner
20 */
21
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <cgraph/agxbuf.h>
26#include <cgraph/alloc.h>
27#include <cgraph/cgraph.h>
28#include <cgraph/gv_ctype.h>
29#include <cgraph/ingraphs.h>
30#include <cgraph/prisize_t.h>
31#include <cgraph/stack.h>
32#include <cgraph/unreachable.h>
33#include <cgraph/exit.h>
34#include <common/render.h>
35#include <common/utils.h>
36
37typedef struct {
39 char cc_subg; /* true iff subgraph corresponds to a component */
41
42typedef struct {
44 char mark;
47
48#define GD_cc_subg(g) (((graphinfo_t*)(g->base.data))->cc_subg)
49#define Node_mark(n) (((nodeinfo_t*)(n->base.data))->mark)
50#define ND_ptr(n) (((nodeinfo_t*)(n->base.data))->ptr)
51#define ND_dn(n) ((Agnode_t*)ND_ptr(n))
52#define Node_clust(n) ((Agraph_t*)ND_ptr(n))
53
54#include <getopt.h>
55
56#include <string.h>
57
58 /* internals of libgraph */
59#define TAG_NODE 1
60
61#define INTERNAL 0 /* Basically means all components need to be
62 * generated before output
63 */
64#define EXTERNAL 1
65#define SILENT 2
66#define EXTRACT 3
68#define BY_INDEX 1
69#define BY_SIZE 2
71static char* Cmd;
72static char **Inputs;
73static int verbose;
74static int printMode = INTERNAL;
75static int useClusters = 0;
76static int doEdges = 1; // induce edges
77static int doAll = 1; // induce subgraphs
78static char *suffix = 0;
79static char *outfile = 0;
80static char *rootpath = 0;
81static int sufcnt = 0;
82static int sorted = 0;
83static int sortIndex = 0;
84static int sortFinal;
85static int x_index = -1;
86static int x_final = -1; // require 0 <= x_index <= x_final or x_final= -1
87static int x_mode;
88static char *x_node;
89
90static char *useString =
91 "Usage: ccomps [-svenCx?] [-X[#%]s[-f]] [-o<out template>] <files>\n\
92 -s - silent\n\
93 -x - external\n\
94 -X - extract component\n\
95 -C - use clusters\n\
96 -e - do not induce edges\n\
97 -n - do not induce subgraphs\n\
98 -v - verbose\n\
99 -o - output file template\n\
100 -z - sort by size, largest first\n\
101 -? - print usage\n\
102If no files are specified, stdin is used\n";
103
104static void usage(int v)
105{
106 printf("%s",useString);
107 graphviz_exit(v);
109
110static void split(void) {
111 char *sfx = 0;
112
113 sfx = strrchr(outfile, '.');
114 if (sfx) {
115 suffix = sfx + 1;
116 size_t size = (size_t)(sfx - outfile);
117 rootpath = gv_strndup(outfile, size);
118 } else {
120 }
122
123static void init(int argc, char *argv[])
124{
125 int c;
126 char* endp;
127
128 Cmd = argv[0];
129 opterr = 0;
130 while ((c = getopt(argc, argv, ":zo:xCX:nesv?")) != -1) {
131 switch (c) {
132 case 'o':
133 outfile = optarg;
134 split();
135 break;
136 case 'C':
137 useClusters = 1;
138 break;
139 case 'e':
140 doEdges = 0;
141 break;
142 case 'n':
143 doAll = 0;
144 break;
145 case 'x':
147 break;
148 case 's':
150 break;
151 case 'X':
152 if (*optarg == '#' || *optarg == '%') {
153 char *p = optarg + 1;
154 if (*optarg == '#') x_mode = BY_INDEX;
155 else x_mode = BY_SIZE;
156 if (gv_isdigit(*p)) {
157 x_index = (int)strtol (p, &endp, 10);
159 if (*endp == '-') {
160 p = endp + 1;
161 if (gv_isdigit(*p)) {
162 x_final = atoi (p);
163 if (x_final < x_index) {
165 fprintf(stderr,
166 "ccomps: final index %d < start index %d in -X%s flag - ignored\n",
167 x_final, x_index, optarg);
168 }
169 }
170 else if (*p) {
172 fprintf(stderr,
173 "ccomps: number expected in -X%s flag - ignored\n",
174 optarg);
175 }
176 }
177 else
179 } else
180 fprintf(stderr,
181 "ccomps: number expected in -X%s flag - ignored\n",
182 optarg);
183 } else {
184 x_node = optarg;
186 }
187 break;
188 case 'v':
189 verbose = 1;
190 break;
191 case 'z':
192 sorted = 1;
193 break;
194 case ':':
195 fprintf(stderr,
196 "ccomps: option -%c missing argument - ignored\n", optopt);
197 break;
198 case '?':
199 if (optopt == '\0' || optopt == '?')
200 usage(0);
201 else {
202 fprintf(stderr,
203 "ccomps: option -%c unrecognized\n", optopt);
204 usage(1);
205 }
206 break;
207 default:
208 UNREACHABLE();
209 }
210 }
211 argv += optind;
212 argc -= optind;
213
214 if (sorted) {
215 if (printMode == EXTRACT && x_index >= 0) {
219 }
220 else if (printMode == EXTERNAL) {
221 sortIndex = -1;
223 }
224 else
225 sorted = 0; /* not relevant; turn off */
226 }
227 if (argc > 0)
228 Inputs = argv;
230
231static gv_stack_t Stk;
232
233static void push(Agnode_t * np)
234{
235 Node_mark(np) = -1;
236 stack_push(&Stk, np);
238
239static Agnode_t *pop(void)
240{
241 if (stack_is_empty(&Stk)) {
242 return NULL;
243 }
244 return stack_pop(&Stk);
246
247static int dfs(Agraph_t * g, Agnode_t * n, Agraph_t * out)
248{
249 Agedge_t *e;
250 Agnode_t *other;
251 int cnt = 0;
252
253 push(n);
254 while ((n = pop())) {
255 Node_mark(n) = 1;
256 cnt++;
257 agsubnode(out, n, 1);
258 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
259 if ((other = agtail(e)) == n)
260 other = aghead(e);
261 if (Node_mark(other) == 0)
262 push (other);
263 }
264 }
265 return cnt;
267
268static char *getName(void)
269{
270 agxbuf name = {0};
271
272 if (sufcnt == 0)
273 agxbput(&name, outfile);
274 else {
275 if (suffix)
276 agxbprint(&name, "%s_%d.%s", rootpath, sufcnt, suffix);
277 else
278 agxbprint(&name, "%s_%d", rootpath, sufcnt);
279 }
280 sufcnt++;
281 return agxbdisown(&name);
283
284static void gwrite(Agraph_t * g)
285{
286 FILE *outf;
287 char *name;
288
289 if (!outfile) {
290 agwrite(g, stdout);
291 fflush(stdout);
292 } else {
293 name = getName();
294 outf = fopen(name, "w");
295 if (!outf) {
296 fprintf(stderr, "Could not open %s for writing\n", name);
297 perror("ccomps");
298 free(name);
299 graphviz_exit(EXIT_FAILURE);
300 }
301 free(name);
302 agwrite(g, outf);
303 fclose(outf);
304 }
305}
306
307/* projectG:
308 * If any nodes of subg are in g, create a subgraph of g
309 * and fill it with all nodes of subg in g and their induced
310 * edges in subg. Copy the attributes of subg to g. Return the subgraph.
311 * If not, return null.
312 */
313static Agraph_t *projectG(Agraph_t * subg, Agraph_t * g, int inCluster)
314{
315 Agraph_t *proj = 0;
316 Agnode_t *n;
317 Agnode_t *m;
318
319 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
320 if ((m = agfindnode(g, agnameof(n)))) {
321 if (proj == 0) {
322 proj = agsubg(g, agnameof(subg), 1);
323 }
324 agsubnode(proj, m, 1);
325 }
326 }
327 if (!proj && inCluster) {
328 proj = agsubg(g, agnameof(subg), 1);
329 }
330 if (proj) {
331 if (doEdges) (void)graphviz_node_induce(proj, subg);
332 agcopyattr(subg, proj);
333 }
334
335 return proj;
336}
337
338/* subgInduce:
339 * Project subgraphs of root graph on subgraph.
340 * If non-empty, add to subgraph.
341 */
342static void
343subgInduce(Agraph_t * root, Agraph_t * g, int inCluster)
344{
345 Agraph_t *subg;
346 Agraph_t *proj;
347 int in_cluster;
348
349 for (subg = agfstsubg(root); subg; subg = agnxtsubg(subg)) {
350 if (GD_cc_subg(subg))
351 continue;
352 if ((proj = projectG(subg, g, inCluster))) {
353 in_cluster = inCluster || (useClusters && is_a_cluster(subg));
354 subgInduce(subg, proj, in_cluster);
355 }
356 }
357}
359static void
361{
362 subgInduce(g, out, 0);
365#define PFX1 "%s_cc"
366#define PFX2 "%s_cc_%ld"
367
368/* deriveClusters:
369 * Construct nodes in derived graph corresponding top-level clusters.
370 * Since a cluster might be wrapped in a subgraph, we need to traverse
371 * down into the tree of subgraphs
372 */
373static void deriveClusters(Agraph_t* dg, Agraph_t * g)
374{
375 Agraph_t *subg;
376 Agnode_t *dn;
377 Agnode_t *n;
378
379 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
380 if (is_a_cluster(subg)) {
381 dn = agnode(dg, agnameof(subg), 1);
382 agbindrec (dn, "nodeinfo", sizeof(nodeinfo_t), true);
383 ND_ptr(dn) = (Agobj_t*)subg;
384 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
385 if (ND_ptr(n)) {
386 fprintf (stderr, "Error: node \"%s\" belongs to two non-nested clusters \"%s\" and \"%s\"\n",
387 agnameof (n), agnameof(subg), agnameof(ND_dn(n)));
388 }
389 ND_ptr(n) = (Agobj_t*)dn;
390 }
391 }
392 else {
393 deriveClusters (dg, subg);
394 }
395 }
396}
397
398/* deriveGraph:
399 * Create derived graph dg of g where nodes correspond to top-level nodes
400 * or clusters, and there is an edge in dg if there is an edge in g
401 * between any nodes in the respective clusters.
402 */
403static Agraph_t *deriveGraph(Agraph_t * g)
404{
405 Agraph_t *dg;
406 Agnode_t *dn;
407 Agnode_t *n;
408
409 dg = agopen("dg", Agstrictundirected, (Agdisc_t *) 0);
410
411 deriveClusters (dg, g);
412
413 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
414 if (ND_dn(n))
415 continue;
416 dn = agnode(dg, agnameof(n), 1);
417 agbindrec (dn, "nodeinfo", sizeof(nodeinfo_t), true);
418 ND_ptr(dn) = (Agobj_t*)n;
419 ND_ptr(n) = (Agobj_t*)dn;
420 }
421
422 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
423 Agedge_t *e;
424 Agnode_t *hd;
425 Agnode_t *tl = ND_dn(n);
426 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
427 hd = ND_dn(aghead(e));
428 if (hd == tl)
429 continue;
430 if (hd > tl)
431 agedge(dg, tl, hd, 0, 1);
432 else
433 agedge(dg, hd, tl, 0, 1);
434 }
435 }
436
437 return dg;
438}
439
440/* unionNodes:
441 * Add all nodes in cluster nodes of dg to g
442 */
443static void unionNodes(Agraph_t * dg, Agraph_t * g)
444{
445 Agnode_t *n;
446 Agnode_t *dn;
447 Agraph_t *clust;
448
449 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
450 if (AGTYPE(ND_ptr(dn)) == AGNODE) {
451 agsubnode(g, ND_dn(dn), 1);
452 } else {
453 clust = Node_clust(dn);
454 for (n = agfstnode(clust); n; n = agnxtnode(clust, n))
455 agsubnode(g, n, 1);
456 }
457 }
459
460static int cmp(const void *x, const void *y) {
461// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
462// as the later usage is const. We need the cast because `agnnodes` uses
463// non-const pointers.
464#ifdef __GNUC__
465#pragma GCC diagnostic push
466#pragma GCC diagnostic ignored "-Wcast-qual"
467#endif
468 Agraph_t **p0 = (Agraph_t **)x;
469 Agraph_t **p1 = (Agraph_t **)y;
470#ifdef __GNUC__
471#pragma GCC diagnostic pop
472#endif
473 const int n0 = agnnodes(*p0);
474 const int n1 = agnnodes(*p1);
475 if (n0 < n1) {
476 return 1;
477 }
478 if (n0 > n1) {
479 return -1;
480 }
481 return 0;
482}
484static void
485printSorted (Agraph_t* root, int c_cnt)
486{
487 Agraph_t** ccs = gv_calloc(c_cnt, sizeof(Agraph_t*));
488 Agraph_t* subg;
489 int i = 0, endi;
490
491 for (subg = agfstsubg(root); subg; subg = agnxtsubg(subg)) {
492 if (GD_cc_subg(subg))
493 ccs[i++] = subg;
494 }
495 /* sort by component size, largest first */
496 qsort(ccs, c_cnt, sizeof(Agraph_t *), cmp);
497
498 if (sortIndex >= 0) {
499 if (x_mode == BY_INDEX) {
500 if (sortIndex >= c_cnt) {
501 fprintf(stderr,
502 "ccomps: component %d not found in graph %s - ignored\n",
503 sortIndex, agnameof(root));
504 free(ccs);
505 return;
506 }
507 if (sortFinal >= sortIndex) {
508 endi = sortFinal;
509 if (endi >= c_cnt) endi = c_cnt-1;
510 }
511 else
512 endi = c_cnt-1;
513 for (i = sortIndex; i <= endi ; i++) {
514 subg = ccs[i];
515 if (doAll)
516 subGInduce(root, subg);
517 gwrite(subg);
518 }
519 }
520 else if (x_mode == BY_SIZE) {
521 if (sortFinal == -1)
522 sortFinal = agnnodes(ccs[0]);
523 for (i = 0; i < c_cnt ; i++) {
524 subg = ccs[i];
525 int sz = agnnodes(subg);
526 if (sz > sortFinal) continue;
527 if (sz < sortIndex) break;
528 if (doAll)
529 subGInduce(root, subg);
530 gwrite(subg);
531 }
532 }
533 }
534 else for (i = 0; i < c_cnt; i++) {
535 subg = ccs[i];
536 if (doAll)
537 subGInduce(root, subg);
538 gwrite(subg);
539 }
540 free (ccs);
541}
542
543/* processClusters:
544 * Return 0 if graph is connected.
545 */
546static int processClusters(Agraph_t * g, char* graphName)
547{
548 Agraph_t *dg;
549 long n_cnt, c_cnt;
550 Agraph_t *out;
551 Agnode_t *n;
552 Agraph_t *dout;
553 Agnode_t *dn;
554 int extracted = 0;
555
556 dg = deriveGraph(g);
557
558 if (x_node) {
559 n = agfindnode(g, x_node);
560 if (!n) {
561 fprintf(stderr, "ccomps: node %s not found in graph %s\n",
562 x_node, agnameof(g));
563 return 1;
564 }
565 {
566 agxbuf buf = {0};
567 agxbprint(&buf, PFX1, graphName);
568 char *name = agxbuse(&buf);
569 dout = agsubg(dg, name, 1);
570 out = agsubg(g, name, 1);
571 agxbfree(&buf);
572 }
573 aginit(out, AGRAPH, "graphinfo", sizeof(graphinfo_t), true);
574 GD_cc_subg(out) = 1;
575 dn = ND_dn(n);
576 n_cnt = dfs(dg, dn, dout);
577 unionNodes(dout, out);
578 size_t e_cnt = 0;
579 if (doEdges)
580 e_cnt = graphviz_node_induce(out, out->root);
581 if (doAll)
582 subGInduce(g, out);
583 gwrite(out);
584 if (verbose)
585 fprintf(stderr, " %7ld nodes %7" PRISIZE_T " edges\n", n_cnt,
586 e_cnt);
587 return 0;
588 }
589
590 c_cnt = 0;
591 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
592 if (Node_mark(dn))
593 continue;
594 {
595 agxbuf buf = {0};
596 agxbprint(&buf, PFX2, graphName, c_cnt);
597 char *name = agxbuse(&buf);
598 dout = agsubg(dg, name, 1);
599 out = agsubg(g, name, 1);
600 agxbfree(&buf);
601 }
602 aginit(out, AGRAPH, "graphinfo", sizeof(graphinfo_t), true);
603 GD_cc_subg(out) = 1;
604 n_cnt = dfs(dg, dn, dout);
605 unionNodes(dout, out);
606 size_t e_cnt = 0;
607 if (doEdges)
608 e_cnt = graphviz_node_induce(out, out->root);
609 if (printMode == EXTERNAL) {
610 if (doAll)
611 subGInduce(g, out);
612 gwrite(out);
613 } else if (printMode == EXTRACT) {
614 if (x_mode == BY_INDEX) {
615 if (x_index <= c_cnt) {
616 extracted = 1;
617 if (doAll)
618 subGInduce(g, out);
619 gwrite(out);
620 if (c_cnt == x_final)
621 return 0;
622 }
623 }
624 else if (x_mode == BY_SIZE) {
625 int sz = agnnodes(out);
626 if (x_index <= sz && (x_final == -1 || sz <= x_final)) {
627 extracted = 1;
628 if (doAll)
629 subGInduce(g, out);
630 gwrite(out);
631 }
632 }
633 }
634 if (printMode != INTERNAL)
635 agdelete(g, out);
636 agdelete(dg, dout);
637 if (verbose)
638 fprintf(stderr, "(%4ld) %7ld nodes %7" PRISIZE_T " edges\n",
639 c_cnt, n_cnt, e_cnt);
640 c_cnt++;
641 }
642 if (printMode == EXTRACT && !extracted && x_mode == BY_INDEX) {
643 fprintf(stderr,
644 "ccomps: component %d not found in graph %s - ignored\n",
645 x_index, agnameof(g));
646 return 1;
647 }
648
649 if (sorted)
650 printSorted (g, c_cnt);
651 else if (printMode == INTERNAL)
652 gwrite(g);
653
654 if (verbose)
655 fprintf(stderr, " %7d nodes %7d edges %7ld components %s\n",
656 agnnodes(g), agnedges(g), c_cnt, agnameof(g));
657
658 agclose(dg);
659
660 return (c_cnt ? 1 : 0);
661}
663static void
665{
666 Agraph_t *subg;
667
668 aginit(g, AGRAPH, "graphinfo", sizeof(graphinfo_t), true);
669 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
670 bindGraphinfo (subg);
671 }
672}
673
674/* process:
675 * Return 0 if graph is connected.
676 */
677static int process(Agraph_t * g, char* graphName)
678{
679 long n_cnt, c_cnt;
680 Agraph_t *out;
681 Agnode_t *n;
682 int extracted = 0;
683
684 aginit(g, AGNODE, "nodeinfo", sizeof(nodeinfo_t), true);
685 bindGraphinfo (g);
686
687 if (useClusters)
688 return processClusters(g, graphName);
689
690 if (x_node) {
691 n = agfindnode(g, x_node);
692 if (!n) {
693 fprintf(stderr,
694 "ccomps: node %s not found in graph %s - ignored\n",
695 x_node, agnameof(g));
696 return 1;
697 }
698 {
699 agxbuf name = {0};
700 agxbprint(&name, PFX1, graphName);
701 out = agsubg(g, agxbuse(&name), 1);
702 agxbfree(&name);
703 }
704 aginit(out, AGRAPH, "graphinfo", sizeof(graphinfo_t), true);
705 GD_cc_subg(out) = 1;
706 n_cnt = dfs(g, n, out);
707 size_t e_cnt = 0;
708 if (doEdges)
709 e_cnt = graphviz_node_induce(out, out->root);
710 if (doAll)
711 subGInduce(g, out);
712 gwrite(out);
713 if (verbose)
714 fprintf(stderr, " %7ld nodes %7" PRISIZE_T " edges\n", n_cnt,
715 e_cnt);
716 return 0;
717 }
718
719 c_cnt = 0;
720 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
721 if (Node_mark(n))
722 continue;
723 {
724 agxbuf name = {0};
725 agxbprint(&name, PFX2, graphName, c_cnt);
726 out = agsubg(g, agxbuse(&name), 1);
727 agxbfree(&name);
728 }
729 aginit(out, AGRAPH, "graphinfo", sizeof(graphinfo_t), true);
730 GD_cc_subg(out) = 1;
731 n_cnt = dfs(g, n, out);
732 size_t e_cnt = 0;
733 if (doEdges)
734 e_cnt = graphviz_node_induce(out, out->root);
735 if (printMode == EXTERNAL) {
736 if (doAll)
737 subGInduce(g, out);
738 gwrite(out);
739 } else if (printMode == EXTRACT) {
740 if (x_mode == BY_INDEX) {
741 if (x_index <= c_cnt) {
742 extracted = 1;
743 if (doAll)
744 subGInduce(g, out);
745 gwrite(out);
746 if (c_cnt == x_final)
747 return 0;
748 }
749 }
750 else if (x_mode == BY_SIZE) {
751 int sz = agnnodes(out);
752 if (x_index <= sz && (x_final == -1 || sz <= x_final)) {
753 extracted = 1;
754 if (doAll)
755 subGInduce(g, out);
756 gwrite(out);
757 }
758 }
759 }
760 if (printMode != INTERNAL)
761 agdelete(g, out);
762 if (verbose)
763 fprintf(stderr, "(%4ld) %7ld nodes %7" PRISIZE_T " edges\n",
764 c_cnt, n_cnt, e_cnt);
765 c_cnt++;
766 }
767 if (printMode == EXTRACT && !extracted && x_mode == BY_INDEX) {
768 fprintf(stderr,
769 "ccomps: component %d not found in graph %s - ignored\n",
770 x_index, agnameof(g));
771 return 1;
772 }
773
774 if (sorted)
775 printSorted (g, c_cnt);
776 else if (printMode == INTERNAL)
777 gwrite(g);
778
779 if (verbose)
780 fprintf(stderr, " %7d nodes %7d edges %7ld components %s\n",
781 agnnodes(g), agnedges(g), c_cnt, agnameof(g));
782 return c_cnt > 1;
783}
784
785/* chkGraphName:
786 * If the graph is anonymous, its name starts with '%'.
787 * If we use this as the prefix for subgraphs, they will not be
788 * emitted in agwrite() because cgraph assumes these were anonymous
789 * structural subgraphs all of whose properties are attached directly
790 * to the nodes and edges involved.
791 *
792 * This function checks for an initial '%' and if found, prepends '_'
793 * the the graph name.
794 * NB: static buffer is used.
795 */
796static char*
798{
799 static agxbuf buf;
800 char* s = agnameof(g);
801
802 if (*s != '%') return s;
803 agxbprint(&buf, "_%s", s);
804
805 return agxbuse(&buf);
807
808int main(int argc, char *argv[])
809{
810 Agraph_t *g;
811 ingraph_state ig;
812 int r = 0;
813 init(argc, argv);
814 newIngraph(&ig, Inputs);
815
816 while ((g = nextGraph(&ig)) != 0) {
817 r += process(g, chkGraphName(g));
818 agclose(g);
819 }
820
822
823 graphviz_exit(r);
824}
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
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static char * gv_strndup(const char *original, size_t length)
Definition alloc.h:114
abstract graph C library, Cgraph API
#define graphName(g)
Definition acyclic.c:32
#define INTERNAL
Definition ccomps.c:61
static void init(int argc, char *argv[])
Definition ccomps.c:121
static char ** Inputs
Definition ccomps.c:70
static int verbose
Definition ccomps.c:71
#define ND_dn(n)
Definition ccomps.c:51
static int processClusters(Agraph_t *g, char *graphName)
Definition ccomps.c:544
static char * rootpath
Definition ccomps.c:78
static int printMode
Definition ccomps.c:72
static char * x_node
Definition ccomps.c:86
static int process(Agraph_t *g, char *graphName)
Definition ccomps.c:675
static void gwrite(Agraph_t *g)
Definition ccomps.c:282
#define SILENT
Definition ccomps.c:63
#define ND_ptr(n)
Definition ccomps.c:50
static void split(void)
Definition ccomps.c:108
#define BY_INDEX
Definition ccomps.c:66
static char * suffix
Definition ccomps.c:76
static Agnode_t * pop(void)
Definition ccomps.c:237
static char * Cmd
Definition ccomps.c:69
#define BY_SIZE
Definition ccomps.c:67
static int useClusters
Definition ccomps.c:73
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 int sortIndex
Definition ccomps.c:81
static int sortFinal
Definition ccomps.c:82
static int cmp(const void *x, const void *y)
Definition ccomps.c:458
static void unionNodes(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:441
#define Node_clust(n)
Definition ccomps.c:52
static Agraph_t * projectG(Agraph_t *subg, Agraph_t *g, int inCluster)
Definition ccomps.c:311
#define Node_mark(n)
Definition ccomps.c:49
static int sorted
Definition ccomps.c:80
static char * getName(void)
Definition ccomps.c:266
#define EXTRACT
Definition ccomps.c:64
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 char * chkGraphName(Agraph_t *g)
Definition ccomps.c:795
static gv_stack_t Stk
Definition ccomps.c:229
static int dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out)
Definition ccomps.c:245
static int x_final
Definition ccomps.c:84
static char * useString
Definition ccomps.c:88
static char * outfile
Definition ccomps.c:77
static void bindGraphinfo(Agraph_t *g)
Definition ccomps.c:662
static int x_index
Definition ccomps.c:83
#define PFX2
Definition ccomps.c:364
static int doEdges
Definition ccomps.c:74
static void printSorted(Agraph_t *root, int c_cnt)
Definition ccomps.c:483
static int sufcnt
Definition ccomps.c:79
static int doAll
Definition ccomps.c:75
static void push(Agnode_t *np)
Definition ccomps.c:231
#define EXTERNAL
Definition ccomps.c:62
#define PFX1
Definition ccomps.c:363
static int x_mode
Definition ccomps.c:85
#define GD_cc_subg(g)
Definition ccomps.c:48
bool is_a_cluster(Agraph_t *g)
Definition utils.c:691
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
void free(void *)
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
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:708
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
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
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_isdigit(int c)
Definition gv_ctype.h:41
static const char * usage
Definition gvpr.c:53
Agraph_t * nextGraph(ingraph_state *sp)
Definition ingraphs.c:61
ingraph_state * newIngraph(ingraph_state *sp, char **files)
Definition ingraphs.c:140
supports user-supplied data
#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
user's discipline
Definition cgraph.h:337
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
Agrec_t h
Definition ccomps.c:38
char cc_subg
Definition ccomps.c:39
Agrec_t h
Definition ccomps.c:43
char mark
Definition ccomps.c:44
Agobj_t * ptr
Definition ccomps.c:45
int main()
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30