Graphviz 13.0.0~dev.20250121.0651
Loading...
Searching...
No Matches
write.c
Go to the documentation of this file.
1
9/*************************************************************************
10 * Copyright (c) 2011 AT&T Intellectual Property
11 * All rights reserved. This program and the accompanying materials
12 * are made available under the terms of the Eclipse Public License v1.0
13 * which accompanies this distribution, and is available at
14 * https://www.eclipse.org/legal/epl-v10.html
15 *
16 * Contributors: Details at https://graphviz.org
17 *************************************************************************/
18
19#include <assert.h>
20#include <limits.h>
21#include <stdbool.h>
22#include <stddef.h>
23#include <stdio.h> /* need sprintf() */
24#include <ctype.h>
25#include <cgraph/cghdr.h>
26#include <inttypes.h>
27#include <util/gv_ctype.h>
28#include <util/strcasecmp.h>
29
30#define EMPTY(s) (((s) == 0) || (s)[0] == '\0')
31#define MAX(a,b) ((a)>(b)?(a):(b))
32#define CHKRV(v) {if ((v) == EOF) return EOF;}
33
34typedef void iochan_t;
35
36static int ioput(Agraph_t * g, iochan_t * ofile, char *str)
37{
38 return AGDISC(g, io)->putstr(ofile, str);
39
40}
41
42#define MAX_OUTPUTLINE 128
43#define MIN_OUTPUTLINE 60
44static int Level;
47
48typedef struct {
49 uint64_t *preorder_number; // of a graph or subgraph
50 uint64_t *node_last_written; // postorder number of subg when node was last written
51 uint64_t *edge_last_written; // postorder number of subg when edge was last written
53
54static int write_body(Agraph_t *g, iochan_t *ofile, write_info_t *wr_info);
55
57static void after_write(write_info_t);
58
59static int indent(Agraph_t * g, iochan_t * ofile)
60{
61 int i;
62 for (i = Level; i > 0; i--)
63 CHKRV(ioput(g, ofile, "\t"));
64 return 0;
65}
66
67// alphanumeric, '.', '-', or non-ascii; basically, chars used in unquoted ids
68static bool is_id_char(char c) {
69 return gv_isalnum(c) || c == '.' || c == '-' || !isascii(c);
70}
71
72// is the prefix of this string a recognized Graphviz escape sequence?
73// https://graphviz.org/docs/attr-types/escString/
74static bool is_escape(const char *str) {
75 assert(str != NULL);
76
77 if (*str != '\\')
78 return false;
79
80 if (str[1] == 'E')
81 return true;
82 if (str[1] == 'G')
83 return true;
84 if (str[1] == 'H')
85 return true;
86 if (str[1] == 'L')
87 return true;
88 if (str[1] == 'N')
89 return true;
90 if (str[1] == 'T')
91 return true;
92
93 if (str[1] == 'l')
94 return true;
95 if (str[1] == 'n')
96 return true;
97 if (str[1] == 'r')
98 return true;
99
100 if (str[1] == '\\')
101 return true;
102
103 if (str[1] == '"')
104 return true;
105
106 return false;
107}
108
109/* Canonicalize ordinary strings.
110 * Assumes buf is large enough to hold output.
111 */
112static char *_agstrcanon(char *arg, char *buf)
113{
114 char *s, *p;
115 char uc;
116 int cnt = 0, dotcnt = 0;
117 bool needs_quotes = false;
118 bool part_of_escape = false;
119 bool maybe_num;
120 bool backslash_pending = false;
121 static const char *tokenlist[] /* must agree with scan.l */
122 = { "node", "edge", "strict", "graph", "digraph", "subgraph",
123 NULL
124 };
125 const char **tok;
126
127 if (EMPTY(arg))
128 return "\"\"";
129 s = arg;
130 p = buf;
131 *p++ = '\"';
132 uc = *s++;
133 maybe_num = gv_isdigit(uc) || uc == '.' || uc == '-';
134 while (uc) {
135 if (uc == '\"' && !part_of_escape) {
136 *p++ = '\\';
137 needs_quotes = true;
138 } else if (!part_of_escape && is_escape(&s[-1])) {
139 needs_quotes = true;
140 part_of_escape = true;
141 } else if (maybe_num) {
142 if (uc == '-') {
143 if (cnt) {
144 maybe_num = false;
145 needs_quotes = true;
146 }
147 }
148 else if (uc == '.') {
149 if (dotcnt++) {
150 maybe_num = false;
151 needs_quotes = true;
152 }
153 }
154 else if (!gv_isdigit(uc)) {
155 maybe_num = false;
156 needs_quotes = true;
157 }
158 part_of_escape = false;
159 }
160 else if (!(gv_isalnum(uc) || uc == '_' || !isascii(uc))) {
161 needs_quotes = true;
162 part_of_escape = false;
163 } else {
164 part_of_escape = false;
165 }
166 *p++ = uc;
167 uc = *s++;
168 cnt++;
169
170 /* If breaking long strings into multiple lines, only allow breaks after a non-id char, not a backslash, where the next char is an
171 * id char.
172 */
173 if (Max_outputline) {
174 if (uc && backslash_pending && !(is_id_char(p[-1]) || p[-1] == '\\') && is_id_char(uc)) {
175 *p++ = '\\';
176 *p++ = '\n';
177 needs_quotes = true;
178 backslash_pending = false;
179 cnt = 0;
180 } else if (uc && (cnt >= Max_outputline)) {
181 if (!(is_id_char(p[-1]) || p[-1] == '\\') && is_id_char(uc)) {
182 *p++ = '\\';
183 *p++ = '\n';
184 needs_quotes = true;
185 cnt = 0;
186 } else {
187 backslash_pending = true;
188 }
189 }
190 }
191 }
192 *p++ = '\"';
193 *p = '\0';
194 if (needs_quotes || (cnt == 1 && (*arg == '.' || *arg == '-')))
195 return buf;
196
197 /* Use quotes to protect tokens (example, a node named "node") */
198 /* It would be great if it were easier to use flex here. */
199 for (tok = tokenlist; *tok; tok++)
200 if (!strcasecmp(*tok, arg))
201 return buf;
202 return arg;
203}
204
208static char *agcanonhtmlstr(const char *arg, char *buf)
209{
210 sprintf(buf, "<%s>", arg);
211 return buf;
212}
213
219char *agstrcanon(char *arg, char *buf)
220{
221 if (aghtmlstr(arg))
222 return agcanonhtmlstr(arg, buf);
223 else
224 return _agstrcanon(arg, buf);
225}
226
227static char *getoutputbuffer(const char *str)
228{
229 static char *rv;
230 static size_t len = 0;
231 size_t req;
232
233 req = MAX(2 * strlen(str) + 2, BUFSIZ);
234 if (req > len) {
235 char *r = realloc(rv, req);
236 if (r == NULL)
237 return NULL;
238 rv = r;
239 len = req;
240 }
241 return rv;
242}
243
249char *agcanonStr(char *str)
250{
251 char *buffer = getoutputbuffer(str);
252 if (buffer == NULL)
253 return NULL;
254 return agstrcanon(str, buffer);
255}
256
257static int _write_canonstr(Agraph_t *g, iochan_t *ofile, char *str, bool chk) {
258 if (chk) {
259 str = agcanonStr(str);
260 } else {
261 char *buffer = getoutputbuffer(str);
262 if (buffer == NULL)
263 return EOF;
264 str = _agstrcanon(str, buffer);
265 }
266 return ioput(g, ofile, str);
267}
268
270static int write_canonstr(Agraph_t *g, iochan_t *ofile, char *str, bool known) {
271 char *s;
272
273 /* str may not have been allocated by agstrdup, so we first need to turn it
274 * into a valid refstr
275 */
276 s = known ? str : agstrdup(g, str);
277
278 int r = _write_canonstr(g, ofile, s, true);
279
280 if (!known) {
281 agstrfree(g, s, false);
282 }
283 return r;
284}
285
286static int write_dict(Agraph_t * g, iochan_t * ofile, char *name,
287 Dict_t * dict, bool top) {
288 int cnt = 0;
289 Dict_t *view;
290 Agsym_t *sym, *psym;
291
292 if (!top)
293 view = dtview(dict, NULL);
294 else
295 view = 0;
296 for (sym = dtfirst(dict); sym; sym = dtnext(dict, sym)) {
297 if (EMPTY(sym->defval) && !sym->print) { /* try to skip empty str (default) */
298 if (view == NULL)
299 continue; /* no parent */
300 psym = dtsearch(view, sym);
301 assert(psym);
302 if (EMPTY(psym->defval) && psym->print)
303 continue; /* also empty in parent */
304 }
305 if (cnt++ == 0) {
306 CHKRV(indent(g, ofile));
307 CHKRV(ioput(g, ofile, name));
308 CHKRV(ioput(g, ofile, " ["));
309 Level++;
310 } else {
311 CHKRV(ioput(g, ofile, ",\n"));
312 CHKRV(indent(g, ofile));
313 }
314 CHKRV(write_canonstr(g, ofile, sym->name, true));
315 CHKRV(ioput(g, ofile, "="));
316 CHKRV(write_canonstr(g, ofile, sym->defval, true));
317 }
318 if (cnt > 0) {
319 Level--;
320 if (cnt > 1) {
321 CHKRV(ioput(g, ofile, "\n"));
322 CHKRV(indent(g, ofile));
323 }
324 CHKRV(ioput(g, ofile, "];\n"));
325 }
326 if (!top)
327 dtview(dict, view); /* restore previous view */
328 return 0;
329}
330
331static int write_dicts(Agraph_t *g, iochan_t *ofile, bool top) {
332 Agdatadict_t *def;
333 if ((def = agdatadict(g, false))) {
334 CHKRV(write_dict(g, ofile, "graph", def->dict.g, top));
335 CHKRV(write_dict(g, ofile, "node", def->dict.n, top));
336 CHKRV(write_dict(g, ofile, "edge", def->dict.e, top));
337 }
338 return 0;
339}
340
341static int write_hdr(Agraph_t *g, iochan_t *ofile, bool top) {
342 char *name, *sep, *kind, *strict;
343 bool root = false;
344 bool hasName = true;
345
346 strict = "";
347 if (!top && agparent(g))
348 kind = "sub";
349 else {
350 root = true;
351 if (g->desc.directed)
352 kind = "di";
353 else
354 kind = "";
355 if (agisstrict(g))
356 strict = "strict ";
359 }
360 name = agnameof(g);
361 sep = " ";
362 if (!name || name[0] == LOCALNAMEPREFIX) {
363 sep = name = "";
364 hasName = false;
365 }
366 CHKRV(indent(g, ofile));
367 CHKRV(ioput(g, ofile, strict));
368
369 /* output "<kind>graph" only for root graphs or graphs with names */
370 if (root || hasName) {
371 CHKRV(ioput(g, ofile, kind));
372 CHKRV(ioput(g, ofile, "graph "));
373 }
374 if (hasName)
375 CHKRV(write_canonstr(g, ofile, name, false));
376 CHKRV(ioput(g, ofile, sep));
377 CHKRV(ioput(g, ofile, "{\n"));
378 Level++;
379 CHKRV(write_dicts(g, ofile, top));
380 AGATTRWF(g) = true;
381 return 0;
382}
383
384static int write_trl(Agraph_t * g, iochan_t * ofile)
385{
386 (void)g;
387 Level--;
388 CHKRV(indent(g, ofile));
389 CHKRV(ioput(g, ofile, "}\n"));
390 return 0;
391}
392
397static bool is_anonymous(Agraph_t *g) {
398 assert(g != NULL);
399
400 // handle the common case inline for performance
401 if (AGDISC(g, id) == &AgIdDisc) {
402 // replicate `idprint`
403 const IDTYPE id = AGID(g);
404 if (id % 2 != 0) {
405 return true;
406 }
407 return *(char *)(uintptr_t)id == LOCALNAMEPREFIX;
408 }
409
410 const char *const name = agnameof(g);
411 return name == NULL || name[0] == LOCALNAMEPREFIX;
412}
413
415{
416 int i, n;
417 Agattr_t *sdata, *pdata, *rdata;
418 Agdatadict_t *dd;
419
420 if (!is_anonymous(g))
421 return false;
422 if ((sdata = agattrrec(g)) && (pdata = agattrrec(agparent(g)))) {
423 rdata = agattrrec(agroot(g));
424 n = dtsize(rdata->dict);
425 for (i = 0; i < n; i++)
426 if (sdata->str[i] && pdata->str[i]
427 && strcmp(sdata->str[i], pdata->str[i]))
428 return false;
429 }
430 dd = agdatadict(g, false);
431 if (!dd)
432 return true;
433 if (dtsize(dd->dict.n) > 0 || dtsize(dd->dict.e) > 0)
434 return false;
435 return true;
436}
437
438static bool has_no_edges(Agraph_t * g, Agnode_t * n)
439{
440 return agfstin(g, n) == NULL && agfstout(g, n) == NULL;
441}
442
444{
445 Agattr_t *data;
446 Agsym_t *sym;
447
448 (void)g;
449 if ((data = agattrrec(n))) {
450 for (sym = dtfirst(data->dict); sym; sym = dtnext(data->dict, sym)) {
451 if (data->str[sym->id] != sym->defval)
452 return true;
453 }
454 }
455 return false;
456}
457
458static int write_subgs(Agraph_t *g, iochan_t *ofile, write_info_t *wr_info) {
459 Agraph_t *subg;
460
461 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
462 if (irrelevant_subgraph(subg)) {
463 write_subgs(subg, ofile, wr_info);
464 }
465 else {
466 CHKRV(write_hdr(subg, ofile, false));
467 CHKRV(write_body(subg, ofile, wr_info));
468 CHKRV(write_trl(subg, ofile));
469 }
470 }
471 return 0;
472}
473
474static int write_edge_name(Agedge_t *e, iochan_t *ofile, bool terminate) {
475 char *p;
476 Agraph_t *g;
477
478 p = agnameof(e);
479 g = agraphof(e);
480 if (!EMPTY(p)) {
481 if (!terminate) {
482 Level++;
483 }
484 CHKRV(ioput(g, ofile, "\t[key="));
485 CHKRV(write_canonstr(g, ofile, p, false));
486 if (terminate)
487 CHKRV(ioput(g, ofile, "]"));
488 return 1;
489 }
490 return 0;
491}
492
493
494static int write_nondefault_attrs(void *obj, iochan_t * ofile,
495 Dict_t * defdict)
496{
497 Agattr_t *data;
498 Agsym_t *sym;
499 Agraph_t *g;
500 int cnt = 0;
501 int rv;
502
503 if (AGTYPE(obj) == AGINEDGE || AGTYPE(obj) == AGOUTEDGE) {
504 CHKRV(rv = write_edge_name(obj, ofile, false));
505 if (rv)
506 cnt++;
507 }
508 data = agattrrec(obj);
509 g = agraphof(obj);
510 if (data)
511 for (sym = dtfirst(defdict); sym; sym = dtnext(defdict, sym)) {
512 if (AGTYPE(obj) == AGINEDGE || AGTYPE(obj) == AGOUTEDGE) {
513 if (Tailport && sym->id == Tailport->id)
514 continue;
515 if (Headport && sym->id == Headport->id)
516 continue;
517 }
518 if (data->str[sym->id] != sym->defval) {
519 if (cnt++ == 0) {
520 CHKRV(ioput(g, ofile, "\t["));
521 Level++;
522 } else {
523 CHKRV(ioput(g, ofile, ",\n"));
524 CHKRV(indent(g, ofile));
525 }
526 CHKRV(write_canonstr(g, ofile, sym->name, true));
527 CHKRV(ioput(g, ofile, "="));
528 CHKRV(write_canonstr(g, ofile, data->str[sym->id], true));
529 }
530 }
531 if (cnt > 0) {
532 CHKRV(ioput(g, ofile, "]"));
533 Level--;
534 }
535 AGATTRWF(obj) = true;
536 return 0;
537}
538
539static int write_nodename(Agnode_t * n, iochan_t * ofile)
540{
541 char *name;
542 Agraph_t *g;
543
544 name = agnameof(n);
545 g = agraphof(n);
546 if (name) {
547 CHKRV(write_canonstr(g, ofile, name, false));
548 } else {
549 char buf[sizeof("__SUSPECT") + 20];
550 snprintf(buf, sizeof(buf), "_%" PRIu64 "_SUSPECT", AGID(n)); /* could be deadly wrong */
551 CHKRV(ioput(g, ofile, buf));
552 }
553 return 0;
554}
555
556static int attrs_written(void *obj)
557{
558 return AGATTRWF(obj);
559}
560
561static int write_node(Agraph_t *subg, Agnode_t *n, iochan_t *ofile, Dict_t *d,
562 write_info_t *wr_info) {
563 Agraph_t *g;
564
565 g = agraphof(n);
566 CHKRV(indent(g, ofile));
567 CHKRV(write_nodename(n, ofile));
568 if (!attrs_written(n))
569 CHKRV(write_nondefault_attrs(n, ofile, d));
570 wr_info->node_last_written[AGSEQ(n)] =
571 wr_info->preorder_number[AGSEQ(subg)];
572 return ioput(g, ofile, ";\n");
573}
574
575/* node must be written if it wasn't already emitted because of
576 * a subgraph or one of its predecessors, and if it is a singleton
577 * or has non-default attributes.
578 */
579static bool write_node_test(Agraph_t *g, Agnode_t *n, write_info_t *wr_info) {
580 /* test if node was already written in g or a subgraph of g */
581 if (wr_info->node_last_written[AGSEQ(n)] >=
582 wr_info->preorder_number[AGSEQ(g)]) return false;
583
584 if (has_no_edges(g, n) || not_default_attrs(g, n))
585 return true;
586 return false;
587}
588
589static int write_port(Agedge_t * e, iochan_t * ofile, Agsym_t * port)
590{
591 char *val;
592 Agraph_t *g;
593
594 if (!port)
595 return 0;
596 g = agraphof(e);
597 val = agxget(e, port);
598 if (val[0] == '\0')
599 return 0;
600
601 CHKRV(ioput(g, ofile, ":"));
602 if (aghtmlstr(val)) {
603 CHKRV(write_canonstr(g, ofile, val, true));
604 } else {
605 char *s = strchr(val, ':');
606 if (s) {
607 *s = '\0';
608 CHKRV(_write_canonstr(g, ofile, val, false));
609 CHKRV(ioput(g, ofile, ":"));
610 CHKRV(_write_canonstr(g, ofile, s + 1, false));
611 *s = ':';
612 } else {
613 CHKRV(_write_canonstr(g, ofile, val, false));
614 }
615 }
616 return 0;
617}
618
619static bool write_edge_test(Agraph_t *g, Agedge_t *e, write_info_t *wr_info) {
620 if (wr_info->edge_last_written[AGSEQ(e)] >=
621 wr_info->preorder_number[AGSEQ(g)]) return false;
622 return true;
623}
624
625static int write_edge(Agraph_t *subg, Agedge_t *e, iochan_t *ofile, Dict_t *d,
626 write_info_t *wr_info) {
627 Agnode_t *t, *h;
628 Agraph_t *g;
629
630 t = AGTAIL(e);
631 h = AGHEAD(e);
632 g = agraphof(t);
633 CHKRV(indent(g, ofile));
634 CHKRV(write_nodename(t, ofile));
635 CHKRV(write_port(e, ofile, Tailport));
636 CHKRV(ioput(g, ofile, (agisdirected(agraphof(t)) ? " -> " : " -- ")));
637 CHKRV(write_nodename(h, ofile));
638 CHKRV(write_port(e, ofile, Headport));
639 if (!attrs_written(e)) {
640 CHKRV(write_nondefault_attrs(e, ofile, d));
641 } else {
642 CHKRV(write_edge_name(e, ofile, true));
643 }
644 wr_info->edge_last_written[AGSEQ(e)] =
645 wr_info->preorder_number[AGSEQ(subg)];
646 return ioput(g, ofile, ";\n");
647}
648
649static int write_body(Agraph_t *g, iochan_t *ofile, write_info_t *wr_info) {
650 Agnode_t *n, *prev;
651 Agedge_t *e;
652 Agdatadict_t *dd;
653
654 CHKRV(write_subgs(g, ofile, wr_info));
655 dd = agdatadict(g, false);
656 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
657 if (write_node_test(g, n, wr_info))
658 CHKRV(write_node(g, n, ofile, dd ? dd->dict.n : 0, wr_info));
659 prev = n;
660 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
661 if (prev != aghead(e) && write_node_test(g, aghead(e), wr_info)) {
662 CHKRV(write_node(g, aghead(e), ofile, dd ? dd->dict.n : 0, wr_info));
663 prev = aghead(e);
664 }
665 if (write_edge_test(g, e, wr_info))
666 CHKRV(write_edge(g, e, ofile, dd ? dd->dict.e : 0, wr_info));
667 }
668
669 }
670 return 0;
671}
672
673static void set_attrwf(Agraph_t * g, bool toplevel, bool value)
674{
675 Agraph_t *subg;
676 Agnode_t *n;
677 Agedge_t *e;
678
679 AGATTRWF(g) = value;
680 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
681 set_attrwf(subg, false, value);
682 }
683 if (toplevel) {
684 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
685 AGATTRWF(n) = value;
686 for (e = agfstout(g, n); e; e = agnxtout(g, e))
687 AGATTRWF(e) = value;
688 }
689 }
690}
691
693int agwrite(Agraph_t * g, void *ofile)
694{
695 char* s;
696 Level = 0; /* re-initialize tab level */
697 s = agget(g, "linelength");
698 if (s != NULL && gv_isdigit(*s)) {
699 unsigned long len = strtoul(s, NULL, 10);
700 if ((len == 0 || len >= MIN_OUTPUTLINE) && len <= INT_MAX)
701 Max_outputline = (int)len;
702 }
703 write_info_t wr_info = before_write(g);
704 CHKRV(write_hdr(g, ofile, true));
705 CHKRV(write_body(g, ofile, &wr_info));
706 CHKRV(write_trl(g, ofile));
707 after_write(wr_info);
709 return AGDISC(g, io)->flush(ofile);
710}
711
712static uint64_t subgdfs(Agraph_t *g, uint64_t ix, write_info_t *wr_info) {
713 uint64_t ix0 = ix;
714 Agraph_t *subg;
715
716 wr_info->preorder_number[AGSEQ(g)] = ix0;
717 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
718 ix0 = subgdfs(subg, ix0, wr_info);
719 }
720 return ix0 + 1;
721}
722
724 write_info_t wr_info = {0};
725 set_attrwf(g, true, false);
726
727 wr_info.preorder_number = gv_calloc(g->clos->seq[AGRAPH] + 1, sizeof(uint64_t));
728 wr_info.node_last_written = gv_calloc(g->clos->seq[AGNODE] + 1, sizeof(uint64_t));
729 wr_info.edge_last_written = gv_calloc(g->clos->seq[AGEDGE] + 1, sizeof(uint64_t));
730 subgdfs(g, 1, &wr_info);
731 return wr_info;
732}
733
734static void after_write(write_info_t wr_info) {
735 free(wr_info.preorder_number);
736 free(wr_info.node_last_written);
737 free(wr_info.edge_last_written);
738}
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define dtsearch(d, o)
Definition cdt.h:183
CDT_API int dtsize(Dt_t *)
Definition dtsize.c:12
CDT_API Dt_t * dtview(Dt_t *, Dt_t *)
Definition dtview.c:91
#define dtnext(d, o)
Definition cdt.h:180
#define dtfirst(d)
Definition cdt.h:179
cgraph.h additions
#define AGDISC(g, d)
Definition cghdr.h:48
#define LOCALNAMEPREFIX
Definition cghdr.h:46
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:206
Agattr_t * agattrrec(void *obj)
Definition attr.c:236
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:371
char * agget(void *obj, char *name)
Definition attr.c:465
Agdatadict_t * agdatadict(Agraph_t *g, bool cflag)
Definition attr.c:49
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:481
Agiddisc_t AgIdDisc
Definition id.c:91
#define TAILPORT_ID
Definition cgraph.h:895
#define HEADPORT_ID
Definition cgraph.h:896
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define aghead(e)
Definition cgraph.h:889
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
#define AGTAIL(e)
Definition cgraph.h:884
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:55
#define AGHEAD(e)
Definition cgraph.h:885
int agisdirected(Agraph_t *g)
Definition graph.c:186
int agisstrict(Agraph_t *g)
Definition graph.c:196
int agwrite(Agraph_t *g, void *ofile)
Return 0 on success, EOF on failure.
Definition write.c:693
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
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
uint64_t IDTYPE
unique per main graph ID
Definition cgraph.h:73
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
#define AGATTRWF(obj)
Definition cgraph.h:226
Agraph_t * agroot(void *obj)
Definition obj.c:168
#define AGSEQ(obj)
Definition cgraph.h:225
@ AGOUTEDGE
Definition cgraph.h:207
@ AGEDGE
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:401
char * agstrcanon(char *arg, char *buf)
Definition write.c:219
int agstrfree(Agraph_t *, const char *, bool is_html)
Definition refstr.c:378
char * agstrdup(Agraph_t *, const char *)
returns a pointer to a reference-counted copy of the argument string, creating one if necessary
Definition refstr.c:370
char * agcanonStr(char *str)
Definition write.c:249
Agraph_t * agparent(Agraph_t *g)
Definition subg.c:88
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:75
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:80
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
$2 u p prev
Definition htmlparse.y:297
textitem scanner parser str
Definition htmlparse.y:224
static Agedge_t * top(edge_stack_t *sp)
Definition tred.c:73
ViewInfo * view
Definition viewport.c:37
platform abstraction for case-insensitive string functions
string attribute container
Definition cgraph.h:633
char ** str
the attribute string values indexed by Agsym_s.id
Definition cgraph.h:636
uint64_t seq[3]
Definition cgraph.h:414
Dict_t * n
Definition cgraph.h:654
Dict_t * e
Definition cgraph.h:654
struct Agdatadict_s::@64 dict
Dict_t * g
Definition cgraph.h:654
unsigned directed
Definition cgraph.h:285
graph or subgraph
Definition cgraph.h:424
Agclos_t * clos
shared resources
Definition cgraph.h:439
Agdesc_t desc
Definition cgraph.h:426
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:641
char * name
Definition cgraph.h:643
int id
index in Agattr_s.str
Definition cgraph.h:645
char * defval
Definition cgraph.h:644
unsigned char print
Definition cgraph.h:648
Definition legal.c:50
Definition cdt.h:100
Definition types.h:48
uint64_t * node_last_written
Definition write.c:50
uint64_t * preorder_number
Definition write.c:49
uint64_t * edge_last_written
Definition write.c:51
static tok_t tok(const char *input, const char *separators)
begin tokenization of a new string
Definition tokenize.h:43
Definition grammar.c:93
static bool is_anonymous(Agraph_t *g)
Definition write.c:397
static Agsym_t * Headport
Definition write.c:46
static int write_canonstr(Agraph_t *g, iochan_t *ofile, char *str, bool known)
Definition write.c:270
void iochan_t
Definition write.c:34
#define MIN_OUTPUTLINE
Definition write.c:43
static bool not_default_attrs(Agraph_t *g, Agnode_t *n)
Definition write.c:443
static uint64_t subgdfs(Agraph_t *g, uint64_t ix, write_info_t *wr_info)
Definition write.c:712
static int ioput(Agraph_t *g, iochan_t *ofile, char *str)
Definition write.c:36
static char * _agstrcanon(char *arg, char *buf)
Definition write.c:112
static int attrs_written(void *obj)
Definition write.c:556
static int write_dicts(Agraph_t *g, iochan_t *ofile, bool top)
Definition write.c:331
#define CHKRV(v)
Definition write.c:32
static int write_port(Agedge_t *e, iochan_t *ofile, Agsym_t *port)
Definition write.c:589
static int write_dict(Agraph_t *g, iochan_t *ofile, char *name, Dict_t *dict, bool top)
Definition write.c:286
static void set_attrwf(Agraph_t *g, bool toplevel, bool value)
Definition write.c:673
static int write_nodename(Agnode_t *n, iochan_t *ofile)
Definition write.c:539
static bool is_escape(const char *str)
Definition write.c:74
static void after_write(write_info_t)
Definition write.c:734
static int write_trl(Agraph_t *g, iochan_t *ofile)
Definition write.c:384
static bool has_no_edges(Agraph_t *g, Agnode_t *n)
Definition write.c:438
static int Level
Definition write.c:44
static bool irrelevant_subgraph(Agraph_t *g)
Definition write.c:414
static int write_edge(Agraph_t *subg, Agedge_t *e, iochan_t *ofile, Dict_t *d, write_info_t *wr_info)
Definition write.c:625
static int write_edge_name(Agedge_t *e, iochan_t *ofile, bool terminate)
Definition write.c:474
static int indent(Agraph_t *g, iochan_t *ofile)
Definition write.c:59
static int _write_canonstr(Agraph_t *g, iochan_t *ofile, char *str, bool chk)
Definition write.c:257
static int write_body(Agraph_t *g, iochan_t *ofile, write_info_t *wr_info)
Definition write.c:649
#define MAX_OUTPUTLINE
Definition write.c:42
static bool is_id_char(char c)
Definition write.c:68
static bool write_node_test(Agraph_t *g, Agnode_t *n, write_info_t *wr_info)
Definition write.c:579
static Agsym_t * Tailport
Definition write.c:46
#define EMPTY(s)
Definition write.c:30
static int write_subgs(Agraph_t *g, iochan_t *ofile, write_info_t *wr_info)
Definition write.c:458
static char * getoutputbuffer(const char *str)
Definition write.c:227
static int write_nondefault_attrs(void *obj, iochan_t *ofile, Dict_t *defdict)
Definition write.c:494
static bool write_edge_test(Agraph_t *g, Agedge_t *e, write_info_t *wr_info)
Definition write.c:619
static char * agcanonhtmlstr(const char *arg, char *buf)
Definition write.c:208
static int write_node(Agraph_t *subg, Agnode_t *n, iochan_t *ofile, Dict_t *d, write_info_t *wr_info)
Definition write.c:561
static int Max_outputline
Definition write.c:45
static write_info_t before_write(Agraph_t *)
Definition write.c:723
#define MAX(a, b)
Definition write.c:31
static int write_hdr(Agraph_t *g, iochan_t *ofile, bool top)
Definition write.c:341