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