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