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