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