Graphviz 15.1.0~dev.20260610.0127
Loading...
Searching...
No Matches
actions.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 v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Code for main functions in gpr
13 */
14
15#include "config.h"
16
17#include <ast/ast.h>
18#include <ast/error.h>
19#include <cgraph/agstrcanon.h>
20#include <gvpr/actions.h>
21#include <gvpr/compile.h>
22#include <limits.h>
23#include <stdbool.h>
24#include <stddef.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29#include <util/agxbuf.h>
30#include <util/alloc.h>
31#include <util/gv_ctype.h>
32#include <util/strcasecmp.h>
33#include <util/unreachable.h>
34#include <util/unused.h>
35
36static const char *kinds(Agobj_t *obj) {
37 if (AGTYPE(obj) == AGRAPH)
38 return "graph";
39 if (AGTYPE(obj) == AGNODE)
40 return "node";
41 return "edge";
42}
43
44/* Return common root if objects belong to same root graph.
45 * NULL otherwise
46 */
47Agraph_t *sameG(void *obj1, void *obj2, char *fn, char *msg) {
48 Agraph_t *const root = agroot(agraphof(obj1));
49 if (root != agroot(agraphof(obj2))) {
50 if (msg)
51 error(ERROR_WARNING, "%s in %s() belong to different graphs", msg, fn);
52 else
53 error(ERROR_WARNING, "%s and %s in %s() belong to different graphs",
54 kinds(obj1), kinds(obj2), fn);
55 return 0;
56 }
57 return root;
58}
59
61int indexOf(char *s1, char *s2) {
62 char *s = strstr(s1, s2);
63 return s == NULL ? -1 : (int)(s - s1);
64}
65
67long rindexOf(char *s1, char *s2) {
68 char c1 = *s2;
69 char *p;
70 size_t len1 = strlen(s1);
71 size_t len2 = strlen(s2);
72
73 if (c1 == '\0') {
74 assert(len1 <= LONG_MAX);
75 return (long)len1;
76 }
77 if (len2 > len1)
78 return -1;
79 p = s1 + (len1 - len2);
80 while (true) {
81 if (strncmp(p, s2, len2) == 0)
82 return p - s1;
83 if (p == s1)
84 break;
85 p--;
86 }
87 return -1;
88}
89
91size_t match(char *str, char *pat) {
92 size_t sub[2];
93
94 if (strgrpmatch(str, pat, sub, 1, 0)) {
95 return (sub[0]);
96 } else
97 return SIZE_MAX;
98}
99
100/* Copy attributes from src to tgt. Overrides currently
101 * defined values.
102 * FIX: we should probably use the default value of the source
103 * graph when initializing the attribute, rather than "".
104 * NOTE: We do not assume src and tgt have the same kind.
105 */
106int copyAttr(Agobj_t *src, Agobj_t *tgt) {
107 Agraph_t *srcg;
108 Agraph_t *tgtg;
109 Agsym_t *sym = 0;
110 Agsym_t *tsym = 0;
111 int skind = AGTYPE(src);
112 int tkind = AGTYPE(tgt);
113 char *val;
114
115 srcg = agraphof(src);
116 tgtg = agraphof(tgt);
117 while ((sym = agnxtattr(srcg, skind, sym))) {
118 tsym = agattrsym(tgt, sym->name);
119 if (!tsym)
120 tsym = agattr_text(tgtg, tkind, sym->name, sym->defval);
121 val = agxget(src, sym);
122 if (aghtmlstr(val)) {
123 val = agstrdup_html(tgtg, val);
124 agxset(tgt, tsym, val);
125 agstrfree(tgtg, val, true);
126 } else
127 agxset(tgt, tsym, val);
128 }
129 return 0;
130}
131
132/* Create new object of type AGTYPE(obj) with all of its
133 * attributes.
134 * If obj is an edge, only create end nodes if necessary.
135 * If obj is a graph, if g is null, create a top-level
136 * graph. Otherwise, create a subgraph of g.
137 * Assume obj != NULL.
138 */
140 Agobj_t *nobj = 0;
141 Agedge_t *e;
142 Agnode_t *h;
143 Agnode_t *t;
144 int kind = AGTYPE(obj);
145 char *name;
146
147 if (kind != AGRAPH && !g) {
148 exerror("NULL graph with non-graph object in copy()");
149 return 0;
150 }
151
152 switch (kind) {
153 case AGNODE:
154 name = agnameof(obj);
155 nobj = (Agobj_t *)openNode(g, name);
156 break;
157 case AGRAPH:
158 name = agnameof(obj);
159 if (g)
160 nobj = (Agobj_t *)openSubg(g, name);
161 else
162 nobj = (Agobj_t *)openG(name, ((Agraph_t *)obj)->desc);
163 break;
164 case AGINEDGE:
165 case AGOUTEDGE:
166 e = (Agedge_t *)obj;
167 t = openNode(g, agnameof(agtail(e)));
168 h = openNode(g, agnameof(aghead(e)));
169 name = agnameof(AGMKOUT(e));
170 nobj = (Agobj_t *)openEdge(g, t, h, name);
171 break;
172 default:
173 UNREACHABLE();
174 }
175 if (nobj)
176 copyAttr(obj, nobj);
177
178 return nobj;
179}
180
186
187static Agedge_t *mapEdge(Dt_t *emap, Agedge_t *e) {
188 edgepair_t *ep = dtmatch(emap, &e);
189 if (ep)
190 return ep->val;
191 else
192 return NULL;
193}
194
196static Agraph_t *cloneSubg(Agraph_t *tgt, Agraph_t *g, Dt_t *emap) {
197 Agraph_t *ng;
198 Agraph_t *sg;
199 Agnode_t *t;
200 Agnode_t *newt;
201 Agedge_t *e;
202 Agedge_t *newe;
203 char *name;
204
205 ng = (Agraph_t *)copy(tgt, OBJ(g));
206 if (!ng)
207 return 0;
208 for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
209 newt = agnode(tgt, agnameof(t), 0);
210 if (!newt) {
211 exerror("node %s not found in cloned graph %s", agnameof(t),
212 agnameof(tgt));
213 return 0;
214 } else
215 agsubnode(ng, newt, 1);
216 }
217 for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
218 for (e = agfstout(g, t); e; e = agnxtout(g, e)) {
219 newe = mapEdge(emap, e);
220 if (!newe) {
221 name = agnameof(AGMKOUT(e));
222 if (name)
223 exerror("edge (%s,%s)[%s] not found in cloned graph %s",
224 agnameof(agtail(e)), agnameof(aghead(e)), name,
225 agnameof(tgt));
226 else
227 exerror("edge (%s,%s) not found in cloned graph %s",
228 agnameof(agtail(e)), agnameof(aghead(e)), agnameof(tgt));
229 return 0;
230 } else
231 agsubedge(ng, newe, 1);
232 }
233 }
234 for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
235 if (!cloneSubg(ng, sg, emap)) {
236 exerror("error cloning subgraph %s from graph %s", agnameof(sg),
237 agnameof(g));
238 return 0;
239 }
240 }
241 return ng;
242}
243
244static int cmppair(void *k1, void *k2) {
245 const Agedge_t **key1 = k1;
246 const Agedge_t **key2 = k2;
247 if (*key1 > *key2)
248 return 1;
249 else if (*key1 < *key2)
250 return -1;
251 else
252 return 0;
253}
254
256 .key = offsetof(edgepair_t, key),
257 .size = sizeof(Agedge_t *),
258 .link = offsetof(edgepair_t, link),
259 .comparf = cmppair,
260};
261
263static void cloneGraph(Agraph_t *tgt, Agraph_t *src) {
264 Agedge_t *e;
265 Agedge_t *ne;
266 Agnode_t *t;
267 Agraph_t *sg;
268 char *name;
269 Dt_t *emap = dtopen(&edgepair, Dtoset);
270 edgepair_t *data = gv_calloc(agnedges(src), sizeof(edgepair_t));
271 edgepair_t *ep = data;
272
273 for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
274 if (!copy(tgt, &t->base)) {
275 exerror("error cloning node %s from graph %s", agnameof(t),
276 agnameof(src));
277 }
278 }
279 for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
280 for (e = agfstout(src, t); e; e = agnxtout(src, e)) {
281 if (!(ne = (Agedge_t *)copy(tgt, &e->base))) {
282 name = agnameof(AGMKOUT(e));
283 if (name)
284 exerror("error cloning edge (%s,%s)[%s] from graph %s",
285 agnameof(agtail(e)), agnameof(aghead(e)), name,
286 agnameof(src));
287 else
288 exerror("error cloning edge (%s,%s) from graph %s",
289 agnameof(agtail(e)), agnameof(aghead(e)), agnameof(src));
290 goto done;
291 }
292 ep->key = e;
293 ep->val = ne;
294 dtinsert(emap, ep++);
295 }
296 }
297 for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) {
298 if (!cloneSubg(tgt, sg, emap)) {
299 exerror("error cloning subgraph %s from graph %s", agnameof(sg),
300 agnameof(src));
301 }
302 }
303
304done:
305 dtclose(emap);
306 free(data);
307}
308
309Agraph_t *cloneG(Agraph_t *g, char *name) {
310 Agraph_t *ng;
311
312 if (!name || *name == '\0')
313 name = agnameof(g);
314 ng = openG(name, g->desc);
315 if (ng) {
316 copyAttr(&g->base, &ng->base);
317 cloneGraph(ng, g);
318 }
319 return ng;
320}
321
322/* Create new object of type AGTYPE(obj) with all of its
323 * attributes and substructure.
324 * If obj is an edge, end nodes are cloned if necessary.
325 * If obj is a graph, if g is null, create a clone top-level
326 * graph. Otherwise, create a clone subgraph of g.
327 * Assume obj != NULL.
328 */
330 Agobj_t *nobj = 0;
331 Agedge_t *e;
332 Agnode_t *h;
333 Agnode_t *t;
334 int kind = AGTYPE(obj);
335 char *name;
336
337 if (kind != AGRAPH && !g) {
338 exerror("NULL graph with non-graph object in clone()");
339 return 0;
340 }
341
342 switch (kind) {
343 case AGNODE: /* same as copy node */
344 name = agnameof(obj);
345 nobj = (Agobj_t *)openNode(g, name);
346 if (nobj)
347 copyAttr(obj, nobj);
348 break;
349 case AGRAPH:
350 name = agnameof(obj);
351 if (g)
352 nobj = (Agobj_t *)openSubg(g, name);
353 else
354 nobj = (Agobj_t *)openG(name, ((Agraph_t *)obj)->desc);
355 if (nobj) {
356 copyAttr(obj, nobj);
357 cloneGraph((Agraph_t *)nobj, (Agraph_t *)obj);
358 }
359 break;
360 case AGINEDGE:
361 case AGOUTEDGE:
362 e = (Agedge_t *)obj;
363 t = (Agnode_t *)cloneO(g, OBJ(agtail(e)));
364 h = (Agnode_t *)cloneO(g, OBJ(aghead(e)));
365 name = agnameof(AGMKOUT(e));
366 nobj = (Agobj_t *)openEdge(g, t, h, name);
367 if (nobj)
368 copyAttr(obj, nobj);
369 break;
370 default:
371 UNREACHABLE();
372 }
373
374 return nobj;
375}
376
377#define CCMARKED(n) (((nData(n))->iu.integer) & 2)
378#define CCMARK(n) (((nData(n))->iu.integer) |= 2)
379#define CCUNMARK(n) (((nData(n))->iu.integer) &= ~2)
380
381static void cc_dfs(Agraph_t *g, Agraph_t *comp, Agnode_t *n) {
382 Agedge_t *e;
383 Agnode_t *other;
384
385 CCMARK(n);
386 agidnode(comp, AGID(n), 1);
387 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
388 if (agtail(e) == n)
389 other = aghead(e);
390 else
391 other = agtail(e);
392 if (!CCMARKED(other))
393 cc_dfs(g, comp, other);
394 }
395}
396
399 Agraph_t *cg;
400 Agnode_t *np;
401 static int id;
402 char name[64];
403
404 if (!(n = agidnode(g, AGID(n), 0)))
405 return 0; /* n not in g */
406 for (np = agfstnode(g); np; np = agnxtnode(g, np))
407 CCUNMARK(np);
408
409 snprintf(name, sizeof(name), "_cc_%d", id++);
410 cg = openSubg(g, name);
411 cc_dfs(g, cg, n);
412
413 return cg;
414}
415
416/* Return edge, if any, between t and h with given key.
417 * Edge is in g.
418 */
419Agedge_t *isEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key) {
420 Agraph_t *root;
421
422 root = sameG(t, h, "isEdge", "tail and head node");
423 if (!root)
424 return 0;
425 if (g) {
426 if (root != agroot(g))
427 return 0;
428 } else
429 g = root;
430
431 return agedge(g, t, h, key, 0);
432}
433
434/* Insert node n into subgraph g.
435 * Return image of n
436 */
437Agnode_t *addNode(Agraph_t *gp, Agnode_t *np, int doAdd) {
438 if (!sameG(gp, np, "addNode", 0))
439 return 0;
440 return agsubnode(gp, np, doAdd);
441}
442
443/* Insert edge e into subgraph g.
444 * Return image of e
445 */
446Agedge_t *addEdge(Agraph_t *gp, Agedge_t *ep, int doAdd) {
447 if (!sameG(gp, ep, "addEdge", 0))
448 return 0;
449 return agsubedge(gp, ep, doAdd);
450}
451
452/* Set lock so that graph g will not be deleted.
453 * g must be a root graph.
454 * If v > 0, set lock
455 * If v = 0, unset lock and delete graph is necessary.
456 * If v < 0, no op
457 * Always return previous lock state.
458 * Return -1 on error.
459 */
460int lockGraph(Agraph_t *g, int v) {
461 gdata *data;
462
463 if (g != agroot(g)) {
464 error(ERROR_WARNING, "Graph argument to lock() is not a root graph");
465 return -1;
466 }
467 data = gData(g);
468 const int oldv = data->lock.locked;
469 if (v > 0)
470 data->lock.locked = true;
471 else if (v == 0 && oldv) {
472 if (data->lock.zombie)
473 agclose(g);
474 else
475 data->lock = (gvlock_t){0};
476 }
477 return oldv;
478}
479
480/* Remove obj from g.
481 * obj may belong to a subgraph of g, so we first must map
482 * obj to its version in g.
483 * If g is null, remove object from root graph.
484 * If obj is a (sub)graph, close it. The g parameter is unused.
485 * Return 0 on success, non-zero on failure.
486 */
488 gdata *data;
489 if (AGTYPE(obj) == AGRAPH) {
490 g = (Agraph_t *)obj;
491 if (g != agroot(g))
492 return agclose(g);
493 data = gData(g);
494 if (data->lock.locked) {
495 error(ERROR_WARNING, "Cannot delete locked graph %s", agnameof(g));
496 data->lock.zombie = true;
497 return -1;
498 } else
499 return agclose(g);
500 }
501
502 /* node or edge */
503 if (!g)
504 g = agroot(agraphof(obj));
505 if (obj)
506 return agdelete(g, obj);
507 else
508 return -1;
509}
510
511/* If the graph is passed in from a library, its output discipline
512 * might not use stdio. In this case, we push a stdio discipline on
513 * the graph, write it, and then pop it off.
514 */
515int sfioWrite(Agraph_t *g, FILE *fp) {
516 int rv;
517
518 Agiodisc_t *saveio = g->clos->disc.io;
519 g->clos->disc.io = &AgIoDisc;
520 rv = agwrite(g, fp);
521 g->clos->disc.io = saveio;
522 return rv;
523}
524
525/* Write graph into file f.
526 * Return 0 on success
527 */
528int writeFile(Agraph_t *g, char *f) {
529 int rv;
530
531 if (!f) {
532 exerror("NULL string passed to writeG");
533 return 1;
534 }
535 FILE *fp = fopen(f, "w");
536 if (!fp) {
537 exwarn("Could not open %s for writing in writeG", f);
538 return 1;
539 }
540 rv = sfioWrite(g, fp);
541 fclose(fp);
542 return rv;
543}
544
545/* Read graph from file f.
546 * Return 0 on failure
547 */
549 Agraph_t *gp;
550
551 if (!f) {
552 exerror("NULL string passed to readG");
553 return 0;
554 }
555 FILE *fp = fopen(f, "r");
556 if (!fp) {
557 exwarn("Could not open %s for reading in readG", f);
558 return 0;
559 }
560 gp = readG(fp);
561 fclose(fp);
562
563 return gp;
564}
565
566int fwriteFile(Expr_t *ex, Agraph_t *g, long long fd) {
567 FILE *sp;
568
569 if (fd < 0 || fd >= (long long)elementsof(ex->file) || !(sp = ex->file[fd])) {
570 exerror("fwriteG: %lld: invalid descriptor", fd);
571 return 0;
572 }
573 return sfioWrite(g, sp);
574}
575
576Agraph_t *freadFile(Expr_t *ex, long long fd) {
577 FILE *sp;
578
579 if (fd < 0 || fd >= (long long)elementsof(ex->file) || !(sp = ex->file[fd])) {
580 exerror("freadG: %lld: invalid descriptor", fd);
581 return 0;
582 }
583 return readG(sp);
584}
585
586int openFile(Expr_t *ex, const char *fname, const char *mode) {
587 int idx;
588
589 /* find open index */
590 for (idx = 3; (size_t)idx < elementsof(ex->file); idx++)
591 if (!ex->file[idx])
592 break;
593 if ((size_t)idx == elementsof(ex->file)) {
594 exerror("openF: no available descriptors");
595 return -1;
596 }
597 ex->file[idx] = fopen(fname, mode);
598 if (ex->file[idx])
599 return idx;
600 else
601 return -1;
602}
603
604int closeFile(Expr_t *ex, long long fd) {
605 int rv;
606
607 if (0 <= fd && fd <= 2) {
608 exerror("closeF: cannot close standard stream %lld", fd);
609 return -1;
610 }
611 if (fd < 0 || fd >= (long long)elementsof(ex->file)) {
612 exerror("closeG: %lld: invalid descriptor", fd);
613 return -1;
614 }
615 if (!ex->file[fd]) {
616 exerror("closeF: stream %lld not open", fd);
617 return -1;
618 }
619 rv = fclose(ex->file[fd]);
620 if (!rv)
621 ex->file[fd] = 0;
622 return rv;
623}
624
625/*
626 * Read single line from stream.
627 * Return "" on EOF.
628 */
629char *readLine(Expr_t *ex, long long fd) {
630 FILE *sp;
631 int c;
632 char *line;
633
634 if (fd < 0 || fd >= (long long)elementsof(ex->file) || !(sp = ex->file[fd])) {
635 exerror("readL: %lld: invalid descriptor", fd);
636 return "";
637 }
638
639 agxbuf tmps = {0};
640 while ((c = getc(sp)) > 0 && c != '\n')
641 agxbputc(&tmps, (char)c);
642 if (c == '\n')
643 agxbputc(&tmps, (char)c);
644 line = exstring(ex, agxbuse(&tmps));
645 agxbfree(&tmps);
646 return line;
647}
648
651 char lkind, rkind;
652 if (l == NULL) {
653 if (r == NULL)
654 return 0;
655 else
656 return -1;
657 } else if (r == NULL) {
658 return 1;
659 }
660 if (AGID(l) < AGID(r))
661 return -1;
662 else if (AGID(l) > AGID(r))
663 return 1;
664 lkind = AGTYPE(l);
665 rkind = AGTYPE(r);
666 if (lkind == 3)
667 lkind = 2;
668 if (rkind == 3)
669 rkind = 2;
670 if (lkind == rkind)
671 return 0;
672 else if (lkind < rkind)
673 return -1;
674 else
675 return 1;
676}
677
679char *toLower(Expr_t *pgm, char *src) {
680
681 const size_t len = strlen(src);
682 char *dst = exstralloc(pgm, len + 1);
683 if (dst == NULL) {
684 return NULL;
685 }
686
687 for (size_t i = 0; i < len; ++i) {
688 dst[i] = gv_tolower(src[i]);
689 }
690
691 dst[len] = '\0';
692 return dst;
693}
694
696char *toUpper(Expr_t *pgm, char *src) {
697
698 const size_t len = strlen(src);
699 char *dst = exstralloc(pgm, len + 1);
700 if (dst == NULL) {
701 return NULL;
702 }
703
704 for (size_t i = 0; i < len; ++i) {
705 dst[i] = gv_toupper(src[i]);
706 }
707
708 dst[len] = '\0';
709 return dst;
710}
711
713char *toHtml(Agraph_t *g, char *arg) { return agstrdup_html(g, arg); }
714
716char *canon(Expr_t *pgm, char *arg) {
717 char *const buffer = exstralloc(pgm, agstrcanon_bytes(arg));
718 return agstrcanon(arg, buffer);
719}
720
721#undef S
722
723// force the upcoming ../common/colxlate.c functions to not be exported
724#ifdef COLORPROCS_API
725#undef COLORPROCS_API
726#endif
727#ifdef GVDLL
728#undef GVDLL
729#endif
730#ifdef GVC_EXPORTS
731#undef GVC_EXPORTS
732#endif
733#define COLORPROCS_API static UNUSED
734
735#include "../common/colxlate.c"
736
738char *colorx(Expr_t *ex, const char *incolor, char *fmt) {
739 gvcolor_t color = {{{0}}, 0};
741 int rc;
742 int alpha;
743
744 if (*fmt == '\0' || *incolor == '\0')
745 return "";
746 if (*fmt == 'R') {
747 type = RGBA_BYTE;
748 if (!strcmp(fmt, "RGBA"))
749 alpha = 1;
750 else
751 alpha = 0;
752 } else if (*fmt == 'H') {
754 if (!strcmp(fmt, "HSVA"))
755 alpha = 1;
756 else
757 alpha = 0;
758 } else
759 return "";
760
761 rc = colorxlate(incolor, &color, type);
762 if (rc != COLOR_OK)
763 return "";
764
765 agxbuf fp = {0};
766
767 switch (type) {
768 case HSVA_DOUBLE:
769 agxbprint(&fp, "%.03f %.03f %.03f", color.u.HSVA[0], color.u.HSVA[1],
770 color.u.HSVA[2]);
771 if (alpha)
772 agxbprint(&fp, " %.03f", color.u.HSVA[3]);
773 break;
774 case RGBA_BYTE:
775 agxbprint(&fp, "#%02x%02x%02x", color.u.rgba[0], color.u.rgba[1],
776 color.u.rgba[2]);
777 if (alpha)
778 agxbprint(&fp, "%02x", color.u.rgba[3]);
779 break;
780 default:
781 break;
782 }
783
784 char *result = exstring(ex, agxbuse(&fp));
785 agxbfree(&fp);
786 return result;
787}
Agedge_t * isEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key)
Definition actions.c:419
int indexOf(char *s1, char *s2)
return index of leftmost string s2 in string s1, or -1
Definition actions.c:61
int openFile(Expr_t *ex, const char *fname, const char *mode)
Definition actions.c:586
static const char * kinds(Agobj_t *obj)
Definition actions.c:36
static Agedge_t * mapEdge(Dt_t *emap, Agedge_t *e)
Definition actions.c:187
Agraph_t * freadFile(Expr_t *ex, long long fd)
Definition actions.c:576
Agobj_t * cloneO(Agraph_t *g, Agobj_t *obj)
Definition actions.c:329
#define CCUNMARK(n)
Definition actions.c:379
size_t match(char *str, char *pat)
return index of pattern pat in string str, or SIZE_MAX
Definition actions.c:91
int deleteObj(Agraph_t *g, Agobj_t *obj)
Definition actions.c:487
int writeFile(Agraph_t *g, char *f)
Definition actions.c:528
int fwriteFile(Expr_t *ex, Agraph_t *g, long long fd)
Definition actions.c:566
long rindexOf(char *s1, char *s2)
return index of rightmost string s2 in string s1, or -1
Definition actions.c:67
int sfioWrite(Agraph_t *g, FILE *fp)
Definition actions.c:515
static void cloneGraph(Agraph_t *tgt, Agraph_t *src)
clone node, edge and subgraph structure from src to tgt
Definition actions.c:263
Agraph_t * sameG(void *obj1, void *obj2, char *fn, char *msg)
Definition actions.c:47
#define CCMARKED(n)
Definition actions.c:377
char * toLower(Expr_t *pgm, char *src)
convert characters to lowercase
Definition actions.c:679
Agraph_t * cloneG(Agraph_t *g, char *name)
Definition actions.c:309
int lockGraph(Agraph_t *g, int v)
Definition actions.c:460
char * canon(Expr_t *pgm, char *arg)
canonicalize a string for printing
Definition actions.c:716
#define CCMARK(n)
Definition actions.c:378
int copyAttr(Agobj_t *src, Agobj_t *tgt)
Definition actions.c:106
static void cc_dfs(Agraph_t *g, Agraph_t *comp, Agnode_t *n)
Definition actions.c:381
char * toHtml(Agraph_t *g, char *arg)
create a string marked as HTML
Definition actions.c:713
Agnode_t * addNode(Agraph_t *gp, Agnode_t *np, int doAdd)
Definition actions.c:437
static Dtdisc_t edgepair
Definition actions.c:255
int compare(Agobj_t *l, Agobj_t *r)
lexicographic ordering of objects
Definition actions.c:650
Agobj_t * copy(Agraph_t *g, Agobj_t *obj)
Definition actions.c:139
static int cmppair(void *k1, void *k2)
Definition actions.c:244
Agraph_t * readFile(char *f)
Definition actions.c:548
Agraph_t * compOf(Agraph_t *g, Agnode_t *n)
return connected component of node
Definition actions.c:398
char * colorx(Expr_t *ex, const char *incolor, char *fmt)
RGB, RGBA, HSV, HSVA.
Definition actions.c:738
static Agraph_t * cloneSubg(Agraph_t *tgt, Agraph_t *g, Dt_t *emap)
clone subgraph sg in tgt
Definition actions.c:196
Agedge_t * addEdge(Agraph_t *gp, Agedge_t *ep, int doAdd)
Definition actions.c:446
char * toUpper(Expr_t *pgm, char *src)
convert characters to uppercase
Definition actions.c:696
char * readLine(Expr_t *ex, long long fd)
Definition actions.c:629
int closeFile(Expr_t *ex, long long fd)
Definition actions.c:604
Helpers for dealing with agstrcanon
static size_t agstrcanon_bytes(const char *str)
how many bytes are needed to canonicalize the given string
Definition agstrcanon.h:11
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:295
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define elementsof(x)
Definition ast.h:33
int strgrpmatch(char *, char *, size_t *, int, int)
Definition strmatch.c:507
#define dtmatch(d, o)
Definition cdt.h:185
#define dtinsert(d, o)
Definition cdt.h:186
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:10
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:306
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:11
#define sub(h, i)
Definition closest.c:62
color_type_t
Definition color.h:26
@ HSVA_DOUBLE
Definition color.h:26
@ RGBA_BYTE
Definition color.h:26
#define COLOR_OK
Definition color.h:44
void colorxlate(char *str, agxbuf *buf)
Definition colxlate.c:48
Agedge_t * openEdge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *key)
Definition compile.c:2495
Agraph_t * openG(char *name, Agdesc_t desc)
Definition compile.c:2467
Agraph_t * openSubg(Agraph_t *g, char *name)
Definition compile.c:2475
Agnode_t * openNode(Agraph_t *g, char *name)
Definition compile.c:2485
Agraph_t * readG(FILE *fp)
Definition compile.c:2456
#define OBJ(p)
Definition compile.h:52
#define gData(g)
Definition compile.h:58
mode
Definition cvtgxl.c:33
static char * fname
#define ERROR_WARNING
Definition error.h:35
void exwarn(const char *format,...)
Definition exerror.c:77
void exerror(const char *format,...)
Definition exerror.c:63
char * exstring(Expr_t *ex, char *s)
Definition exeval.c:1964
void * exstralloc(Expr_t *ex, size_t sz)
Definition exeval.c:1972
expr procedure type
Definition exparse.y:208
static double len(glCompPoint p)
Definition glutils.c:138
void free(void *)
#define SIZE_MAX
Definition gmlscan.c:347
node NULL
Definition grammar.y:181
int agnedges(Agraph_t *g)
Definition graph.c:165
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:333
Agsym_t * agattrsym(void *obj, char *name)
looks up a string attribute for a graph object given as an argument
Definition attr.c:146
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
Definition attr.c:362
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:521
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:457
Agiodisc_t AgIoDisc
Definition io.c:41
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:255
#define AGMKOUT(e)
Definition cgraph.h:971
Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Definition edge.c:350
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
#define agtail(e)
Definition cgraph.h:977
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:97
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:669
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:143
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:254
Agnode_t * agidnode(Agraph_t *g, IDTYPE id, int createflag)
Definition node.c:125
Agraph_t * agraphof(void *obj)
Definition obj.c:187
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
#define AGID(obj)
returns the unique integer ID associated with the object
Definition cgraph.h:221
#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:22
Agraph_t * agroot(void *obj)
Definition obj.c:170
@ AGOUTEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGINEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
int aghtmlstr(const char *)
Definition refstr.c:440
char * agstrcanon(char *, char *)
Definition write.c:219
int agstrfree(Agraph_t *, const char *, bool is_html)
Definition refstr.c:417
char * agstrdup_html(Agraph_t *, const char *)
returns a pointer to a reference-counted HTML-like copy of the argument string, creating one if neces...
Definition refstr.c:397
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:75
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:80
static uint64_t id
Definition gv2gml.c:42
replacements for ctype.h functions
static char gv_toupper(int c)
Definition gv_ctype.h:93
static char gv_tolower(int c)
Definition gv_ctype.h:81
static void color(Agraph_t *g)
Definition gvcolor.c:118
textitem scanner parser str
Definition htmlparse.y:218
table Syntax error
Definition htmlparse.y:288
NEATOPROCS_API void s1(graph_t *, node_t *)
Definition stuff.c:651
#define alpha
Definition shapes.c:4034
static double cg(SparseMatrix A, const double *precond, int n, int dim, double *x0, double *rhs, double tol, double maxit)
platform abstraction for case-insensitive string functions
Agdisc_t disc
Definition cgraph.h:411
Agiodisc_t * io
Definition cgraph.h:338
Agobj_t base
Definition cgraph.h:269
IO services.
Definition cgraph.h:326
Agobj_t base
Definition cgraph.h:260
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
graph or subgraph
Definition cgraph.h:424
Agobj_t base
Definition cgraph.h:425
Agclos_t * clos
shared resources
Definition cgraph.h:434
Agdesc_t desc
Definition cgraph.h:426
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
char * name
Definition cgraph.h:642
char * defval
Definition cgraph.h:643
Definition expr.h:207
FILE * file[10]
Definition expr.h:210
Definition cdt.h:98
int key
Definition cdt.h:85
Dtlink_t link
Definition actions.c:182
Agedge_t * key
Definition actions.c:183
Agedge_t * val
Definition actions.c:184
gvlock_t lock
Definition compile.h:45
bool locked
is the lock currently taken?
Definition compile.h:39
bool zombie
was a deletion request recorded while locked?
Definition compile.h:40
Definition grammar.c:90
#define UNREACHABLE()
Definition unreachable.h:30
abstraction for squashing compiler warnings for unused symbols