Graphviz 14.1.2~dev.20260118.1035
Loading...
Searching...
No Matches
gxl2gv.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include "config.h"
17
18#include <assert.h>
19#include "convert.h"
20#include <stdbool.h>
21#include <stdio.h>
22#include <util/agxbuf.h>
23#include <util/alloc.h>
24#include <util/exit.h>
25#include <util/gv_ctype.h>
26#include <util/list.h>
27#include <util/startswith.h>
28#include <util/streq.h>
29#include <util/unreachable.h>
30#ifdef HAVE_EXPAT
31#include <expat.h>
32#include <limits.h>
33#include <stdlib.h>
34
35#ifndef XML_STATUS_ERROR
36#define XML_STATUS_ERROR 0
37#endif
38
39#define NAMEBUF 100
40
41#define GXL_ATTR "_gxl_"
42#define GXL_ID "_gxl_id"
43#define GXL_ROLE "_gxl_role"
44#define GXL_HYPER "_gxl_hypergraph"
45#define GXL_FROM "_gxl_fromorder"
46#define GXL_TO "_gxl_toorder"
47#define GXL_TYPE "_gxl_type"
48#define GXL_COMP "_gxl_composite_"
49#define GXL_LOC "_gxl_locator_"
50
51typedef enum {
52 TAG_NONE,
53 TAG_GRAPH,
54 TAG_NODE,
55 TAG_EDGE,
56 TAG_HTML_LIKE_STRING,
57} attr_t;
58
59typedef struct {
60 agxbuf xml_attr_name;
61 agxbuf xml_attr_value;
62 agxbuf composite_buffer;
63 bool listen;
64 attr_t closedElementType;
65 attr_t globalAttrType;
66 bool compositeReadState;
67 bool edgeinverted;
68 Dt_t *nameMap;
69} userdata_t;
70
71static Agraph_t *root; /* root graph */
72static attr_t Current_class; /* Current element type */
73static Agraph_t *G; /* Current graph */
74static Agnode_t *N; /* Set if Current_class == TAG_NODE */
75static Agedge_t *E; /* Set if Current_class == TAG_EDGE */
76
77static LIST(Agraph_t *) Gstack;
78
79typedef struct {
80 Dtlink_t link;
81 char *name;
82 char *unique_name;
83} namev_t;
84
85static void *make_nitem(void *p, Dtdisc_t *disc){
86 (void)disc;
87 namev_t *objp = p;
88
89 namev_t *np = malloc(sizeof(namev_t));
90 if (np == NULL)
91 return NULL;
92 np->name = objp->name;
93 np->unique_name = 0;
94 return np;
95}
96
97static void free_nitem(void *name) {
98 namev_t *np = name;
99 free(np->unique_name);
100 free(np);
101}
102
103static Dtdisc_t nameDisc = {
104 .key = offsetof(namev_t, name),
105 .size = -1,
106 .link = offsetof(namev_t, link),
107 .makef = make_nitem,
108 .freef = free_nitem,
109};
110
111static userdata_t genUserdata(void) {
112 userdata_t user = {0};
113 user.listen = false;
114 user.closedElementType = TAG_NONE;
115 user.globalAttrType = TAG_NONE;
116 user.compositeReadState = false;
117 user.edgeinverted = false;
118 user.nameMap = dtopen(&nameDisc, Dtoset);
119 return user;
120}
121
122static void freeUserdata(userdata_t ud) {
123 dtclose(ud.nameMap);
124 agxbfree(&ud.xml_attr_name);
125 agxbfree(&ud.xml_attr_value);
126 agxbfree(&ud.composite_buffer);
127}
128
129static void addToMap(Dt_t * map, char *name, char *uniqueName)
130{
131 namev_t obj;
132 namev_t *objp;
133
134 obj.name = name;
135 objp = dtinsert(map, &obj);
136 assert(objp->unique_name == 0);
137 objp->unique_name = gv_strdup(uniqueName);
138}
139
140static char *mapLookup(Dt_t *nm, const char *name) {
141 namev_t *objp = dtmatch(nm, name);
142 if (objp)
143 return objp->unique_name;
144 else
145 return 0;
146}
147
148static int isAnonGraph(const char *name)
149{
150 if (*name++ != '%')
151 return 0;
152 while (gv_isdigit(*name))
153 name++; /* skip over digits */
154 return (*name == '\0');
155}
156
157static void push_subg(Agraph_t * g)
158{
159 // insert the new graph
160 LIST_PUSH_BACK(&Gstack, g);
161
162 // save the root if this is the first graph
163 if (LIST_SIZE(&Gstack) == 1) {
164 root = g;
165 }
166
167 // update the top graph
168 G = g;
169}
170
171static Agraph_t *pop_subg(void)
172{
173 // is the stack empty?
174 if (LIST_IS_EMPTY(&Gstack)) {
175 fprintf(stderr, "gxl2gv: Gstack underflow in graph parser\n");
176 graphviz_exit(EXIT_FAILURE);
177 }
178
179 // pop the top graph
180 Agraph_t *g = LIST_POP_BACK(&Gstack);
181
182 // update the top graph
183 if (!LIST_IS_EMPTY(&Gstack))
184 G = *LIST_BACK(&Gstack);
185
186 return g;
187}
188
189static Agnode_t *bind_node(const char *name)
190{
191 N = agnode(G, (char *) name, 1);
192 return N;
193}
194
195static Agedge_t *bind_edge(const char *tail, const char *head)
196{
197 Agnode_t *tailNode, *headNode;
198 char *key = 0;
199
200 tailNode = agnode(G, (char *) tail, 1);
201 headNode = agnode(G, (char *) head, 1);
202 E = agedge(G, tailNode, headNode, key, 1);
203 return E;
204}
205
206static int get_xml_attr(char *attrname, const char **atts)
207{
208 int count = 0;
209 while (atts[count] != NULL) {
210 if (streq(attrname, atts[count])) {
211 return count + 1;
212 }
213 count += 2;
214 }
215 return -1;
216}
217
218static void setName(Dt_t * names, Agobj_t * n, char *value)
219{
220 Agsym_t *const ap = agattr_text(root, AGTYPE(n), GXL_ID, "");
221 agxset(n, ap, agnameof(n));
222 char *const oldName = agxget(n, ap); // set/get gives us new copy
223 addToMap(names, oldName, value);
224 agrename(n, value);
225}
226
227static char *defval = "";
228
229static void
230setNodeAttr(Agnode_t * np, char *name, char *value, userdata_t * ud,
231 bool is_html)
232{
233 if (streq(name, "name")) {
234 setName(ud->nameMap, &np->base, value);
235 } else {
236 Agsym_t *ap = agattr_text(root, AGNODE, name, 0);
237 if (!ap)
238 ap = agattr_text(root, AGNODE, name, defval);
239 if (is_html) {
240 agxset_html(np, ap, value);
241 } else {
242 agxset(np, ap, value);
243 }
244 }
245}
246
247#define NODELBL "node:"
248#define NLBLLEN (sizeof(NODELBL)-1)
249#define EDGELBL "edge:"
250#define ELBLLEN (sizeof(EDGELBL)-1)
251
252/* setGlobalNodeAttr:
253 * Set global node attribute.
254 * The names must always begin with "node:".
255 */
256static void
257setGlobalNodeAttr(Agraph_t * g, char *name, char *value)
258{
259 if (!startswith(name, NODELBL))
260 fprintf(stderr,
261 "Warning: global node attribute %s in graph %s does not begin with the prefix %s\n",
262 name, agnameof(g), NODELBL);
263 else
264 name += NLBLLEN;
265 if ((g != root) && !agattr_text(root, AGNODE, name, 0))
266 agattr_text(root, AGNODE, name, defval);
267 agattr_text(G, AGNODE, name, value);
268}
269
270static void
271setEdgeAttr(Agedge_t * ep, char *name, char *value, userdata_t * ud,
272 bool is_html)
273{
274 Agsym_t *ap;
275 char *attrname;
276
277 if (streq(name, "headport")) {
278 if (ud->edgeinverted)
279 attrname = "tailport";
280 else
281 attrname = "headport";
282 ap = agattr_text(root, AGEDGE, attrname, 0);
283 if (!ap)
284 ap = agattr_text(root, AGEDGE, attrname, defval);
285 } else if (streq(name, "tailport")) {
286 if (ud->edgeinverted)
287 attrname = "headport";
288 else
289 attrname = "tailport";
290 ap = agattr_text(root, AGEDGE, attrname, 0);
291 if (!ap)
292 ap = agattr_text(root, AGEDGE, attrname, defval);
293 } else {
294 ap = agattr_text(root, AGEDGE, name, 0);
295 if (!ap)
296 ap = agattr_text(root, AGEDGE, name, defval);
297 }
298
299 if (is_html) {
300 agxset_html(ep, ap, value);
301 } else {
302 agxset(ep, ap, value);
303 }
304}
305
306/* setGlobalEdgeAttr:
307 * Set global edge attribute.
308 * The names always begin with "edge:".
309 */
310static void
311setGlobalEdgeAttr(Agraph_t * g, char *name, char *value)
312{
313 if (!startswith(name, EDGELBL))
314 fprintf(stderr,
315 "Warning: global edge attribute %s in graph %s does not begin with the prefix %s\n",
316 name, agnameof(g), EDGELBL);
317 else
318 name += ELBLLEN;
319 if ((g != root) && !agattr_text(root, AGEDGE, name, 0))
320 agattr_text(root, AGEDGE, name, defval);
321 agattr_text(g, AGEDGE, name, value);
322}
323
324static void
325setGraphAttr(Agraph_t * g, char *name, char *value, userdata_t * ud)
326{
327 Agsym_t *ap;
328
329 if ((g == root) && streq(name, "strict") && streq(value, "true")) {
330 g->desc.strict = true;
331 } else if (streq(name, "name"))
332 setName(ud->nameMap, &g->base, value);
333 else {
334 ap = agattr_text(root, AGRAPH, name, 0);
335 if (ap)
336 agxset(g, ap, value);
337 else if (g == root)
338 agattr_text(root, AGRAPH, name, value);
339 else {
340 ap = agattr_text(root, AGRAPH, name, defval);
341 agxset(g, ap, value);
342 }
343 }
344}
345
346static void setAttr(char *name, char *value, userdata_t * ud, bool is_html)
347{
348 switch (Current_class) {
349 case TAG_GRAPH:
350 setGraphAttr(G, name, value, ud);
351 break;
352 case TAG_NODE:
353 setNodeAttr(N, name, value, ud, is_html);
354 break;
355 case TAG_EDGE:
356 setEdgeAttr(E, name, value, ud, is_html);
357 break;
358 default:
359 break;
360 }
361}
362
363/*------------- expat handlers ----------------------------------*/
364
365static void
366startElementHandler(void *userData, const char *name, const char **atts)
367{
368 int pos;
369 userdata_t *ud = userData;
370 Agraph_t *g = NULL;
371
372 if (streq(name, "gxl")) {
373 /* do nothing */
374 } else if (streq(name, "graph")) {
375 const char *edgeMode = "";
376 char buf[NAMEBUF]; /* holds % + number */
377
378 Current_class = TAG_GRAPH;
379 if (ud->closedElementType == TAG_GRAPH) {
380 fprintf(stderr,
381 "Warning: Node contains more than one graph.\n");
382 }
383 pos = get_xml_attr("id", atts);
384 if (pos <= 0) {
385 fprintf(stderr, "Error: Graph has no ID attribute.\n");
386 graphviz_exit(EXIT_FAILURE);
387 }
388 const char *id = atts[pos];
389 pos = get_xml_attr("edgemode", atts);
390 if (pos > 0) {
391 edgeMode = atts[pos];
392 }
393
394 if (LIST_IS_EMPTY(&Gstack)) {
395 if (streq(edgeMode, "directed")) {
396 g = agopen((char *) id, Agdirected, &AgDefaultDisc);
397 } else if (streq(edgeMode, "undirected")) {
398 g = agopen((char *) id, Agundirected, &AgDefaultDisc);
399 } else {
400 fprintf(stderr,
401 "Warning: graph has no edgemode attribute");
402 fprintf(stderr, " - assume directed\n");
403 g = agopen((char *) id, Agdirected, &AgDefaultDisc);
404 }
405 push_subg(g);
406 } else {
407 Agraph_t *subg;
408 if (isAnonGraph(id)) {
409 static int anon_id = 1;
410 snprintf(buf, sizeof(buf), "%%%d", anon_id++);
411 id = buf;
412 }
413 subg = agsubg(G, (char *) id, 1);
414 push_subg(subg);
415 }
416
417 pos = get_xml_attr("role", atts);
418 if (pos > 0) {
419 setGraphAttr(G, GXL_ROLE, (char *) atts[pos], ud);
420 }
421
422 pos = get_xml_attr("hypergraph", atts);
423 if (pos > 0) {
424 setGraphAttr(G, GXL_HYPER, (char *) atts[pos], ud);
425 }
426
427 } else if (streq(name, "node")) {
428 Current_class = TAG_NODE;
429 pos = get_xml_attr("id", atts);
430 if (pos > 0) {
431 const char *attrname;
432 attrname = atts[pos];
433
434 if (attrname != NULL && !streq(attrname, "")) {
435 bind_node(attrname);
436 }
437 }
438
439 } else if (streq(name, "edge")) {
440 const char *head = "", *tail = "";
441 char *tname;
442 Agnode_t *t;
443
444 Current_class = TAG_EDGE;
445 pos = get_xml_attr("from", atts);
446 if (pos > 0)
447 tail = atts[pos];
448 pos = get_xml_attr("to", atts);
449 if (pos > 0)
450 head = atts[pos];
451
452 tname = mapLookup(ud->nameMap, tail);
453 if (tname)
454 tail = tname;
455
456 tname = mapLookup(ud->nameMap, head);
457 if (tname)
458 head = tname;
459
460 bind_edge(tail, head);
461
462 t = AGTAIL(E);
463 tname = agnameof(t);
464
465 if (streq(tname, tail)) {
466 ud->edgeinverted = false;
467 } else if (streq(tname, head)) {
468 ud->edgeinverted = true;
469 }
470
471 pos = get_xml_attr("fromorder", atts);
472 if (pos > 0) {
473 setEdgeAttr(E, GXL_FROM, (char *) atts[pos], ud, false);
474 }
475
476 pos = get_xml_attr("toorder", atts);
477 if (pos > 0) {
478 setEdgeAttr(E, GXL_TO, (char *) atts[pos], ud, false);
479 }
480
481 pos = get_xml_attr("id", atts);
482 if (pos > 0) {
483 setEdgeAttr(E, GXL_ID, (char *) atts[pos], ud, false);
484 }
485 } else if (streq(name, "attr")) {
486 const char *attrname = atts[get_xml_attr("name", atts)];
487
488 agxbput(&ud->xml_attr_name, attrname);
489 pos = get_xml_attr("kind", atts);
490
491 if (pos > 0) {
492 if (streq("node", atts[pos]))
493 ud->globalAttrType = TAG_NODE;
494 else if (streq("edge", atts[pos]))
495 ud->globalAttrType = TAG_EDGE;
496 else if (streq("graph", atts[pos]))
497 ud->globalAttrType = TAG_GRAPH;
498 else if (streq("HTML-like string", atts[pos]))
499 ud->globalAttrType = TAG_HTML_LIKE_STRING;
500 } else {
501 ud->globalAttrType = TAG_NONE;
502 }
503
504 } else if (streq(name, "string")
505 || streq(name, "bool")
506 || streq(name, "int") || streq(name, "float")) {
507
508 ud->listen = true;
509 if (ud->compositeReadState) {
510 agxbprint(&ud->composite_buffer, "<%s>", name);
511 }
512 } else if (streq(name, "rel") || streq(name, "relend")) {
513 fprintf(stderr, "%s element is ignored by DOT\n", name);
514 } else if (streq(name, "type")) {
515 pos = get_xml_attr("xlink:href", atts);
516 if (pos > 0) {
517 setAttr(GXL_TYPE, (char *) atts[pos], ud, false);
518 }
519 } else if (streq(name, "locator")) {
520 pos = get_xml_attr("xlink:href", atts);
521 if (pos > 0) {
522 const char *href = atts[pos];
523 agxbprint(&ud->xml_attr_value, "%s%s", GXL_LOC, href);
524 }
525 } else if (streq(name, "seq")
526 || streq(name, "set")
527 || streq(name, "bag")
528 || streq(name, "tup") || streq(name, "enum")) {
529
530 ud->compositeReadState = true;
531 agxbprint(&ud->composite_buffer, "<%s>", name);
532 } else {
533 /* must be some extension */
534 fprintf(stderr,
535 "Unknown node %s; DOT does not support extensions.\n",
536 name);
537 }
538}
539
540static void endElementHandler(void *userData, const char *name)
541{
542 userdata_t *ud = userData;
543
544 if (streq(name, "graph")) {
545 pop_subg();
546 ud->closedElementType = TAG_GRAPH;
547 } else if (streq(name, "node")) {
548 Current_class = TAG_GRAPH;
549 N = 0;
550 ud->closedElementType = TAG_NODE;
551 } else if (streq(name, "edge")) {
552 Current_class = TAG_GRAPH;
553 E = 0;
554 ud->closedElementType = TAG_EDGE;
555 ud->edgeinverted = false;
556 } else if (streq(name, "attr")) {
557 agxbuf new_name = {0};
558 char *value;
559
560 ud->closedElementType = TAG_NONE;
561 if (ud->compositeReadState) {
562 agxbprint(&new_name, "%s%s", GXL_COMP, agxbuse(&ud->xml_attr_name));
563 value = agxbuse(&ud->composite_buffer);
564 agxbclear(&ud->xml_attr_value);
565 ud->compositeReadState = false;
566 } else {
567 agxbput(&new_name, agxbuse(&ud->xml_attr_name));
568 value = agxbuse(&ud->xml_attr_value);
569 }
570
571 switch (ud->globalAttrType) {
572 case TAG_NONE:
573 setAttr(agxbuse(&new_name), value, ud, false);
574 break;
575 case TAG_NODE:
576 setGlobalNodeAttr(G, agxbuse(&new_name), value);
577 break;
578 case TAG_EDGE:
579 setGlobalEdgeAttr(G, agxbuse(&new_name), value);
580 break;
581 case TAG_GRAPH:
582 setGraphAttr(G, agxbuse(&new_name), value, ud);
583 break;
584 case TAG_HTML_LIKE_STRING:
585 setAttr(agxbuse(&new_name), value, ud, true);
586 break;
587 default:
588 UNREACHABLE();
589 }
590 agxbfree(&new_name);
591 ud->globalAttrType = TAG_NONE;
592 } else if (streq(name, "string")
593 || streq(name, "bool")
594 || streq(name, "int") || streq(name, "float")) {
595 ud->listen = false;
596 if (ud->compositeReadState) {
597 agxbprint(&ud->composite_buffer, "</%s>", name);
598 }
599 } else if (streq(name, "seq")
600 || streq(name, "set")
601 || streq(name, "bag")
602 || streq(name, "tup") || streq(name, "enum")) {
603 agxbprint(&ud->composite_buffer, "</%s>", name);
604 }
605}
606
607static void characterDataHandler(void *userData, const char *s, int length)
608{
609 userdata_t *ud = userData;
610
611 assert(length >= 0 && "Expat returned negative length data");
612 size_t len = (size_t)length;
613
614 if (!ud->listen)
615 return;
616
617 if (ud->compositeReadState) {
618 agxbput_n(&ud->composite_buffer, s, len);
619 return;
620 }
621
622 agxbput_n(&ud->xml_attr_value, s, len);
623}
624
625Agraph_t *gxl_to_gv(FILE * gxlFile)
626{
627 char buf[BUFSIZ];
628 int done;
629 userdata_t udata = genUserdata();
630 XML_Parser parser = XML_ParserCreate(NULL);
631
632 XML_SetUserData(parser, &udata);
633 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
634 XML_SetCharacterDataHandler(parser, characterDataHandler);
635
636 Current_class = TAG_GRAPH;
637 root = 0;
638 do {
639 size_t len = fread(buf, 1, sizeof(buf), gxlFile);
640 if (len == 0)
641 break;
642 done = len < sizeof(buf);
643 assert(len <= INT_MAX && "too large data for Expat API");
644 if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) {
645 fprintf(stderr,
646 "%s at line %lu\n",
647 XML_ErrorString(XML_GetErrorCode(parser)),
648 XML_GetCurrentLineNumber(parser));
649 graphviz_exit(1);
650 }
651 } while (!done);
652 XML_ParserFree(parser);
653 freeUserdata(udata);
654 LIST_FREE(&Gstack);
655
656 return root;
657}
658
659#endif
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
Definition agxbuf.h:268
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static void agxbclear(agxbuf *xb)
resets pointer to data
Definition agxbuf.h:312
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
Definition alloc.h:101
#define N(n)
Definition bcomps.c:58
#define dtmatch(d, o)
Definition cdt.h:185
#define dtinsert(d, o)
Definition cdt.h:186
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:10
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:306
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:11
int agrename(Agobj_t *obj, char *newname)
Definition obj.c:43
Agsym_t * setAttr(graph_t *g, void *obj, char *name, char *value, Agsym_t *ap)
Definition utils.c:704
static Extype_t length(Exid_t *rhs, Exdisc_t *disc)
Definition compile.c:1606
DOT-GXL converter API for gxl2gv.c and gv2gxl.c.
#define head
Definition dthdr.h:15
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
static Dtdisc_t disc
Definition exparse.y:209
#define E
Definition gdefs.h:6
#define G
Definition gdefs.h:7
static double len(glCompPoint p)
Definition glutils.c:138
void * malloc(YYSIZE_T)
void free(void *)
node NULL
Definition grammar.y:181
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:336
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:524
int agxset_html(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:543
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:460
Agdisc_t AgDefaultDisc
Definition graph.c:277
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:255
#define AGTAIL(e)
Definition cgraph.h:973
Agdesc_t Agundirected
undirected
Definition graph.c:274
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:44
Agdesc_t Agdirected
directed
Definition graph.c:272
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:143
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:55
#define GXL_FROM
Definition gv2gxl.c:35
static Dtdisc_t nameDisc
Definition gv2gxl.c:67
static char * mapLookup(Dt_t *nm, char *name)
Definition gv2gxl.c:203
static void * make_nitem(void *p, Dtdisc_t *disc)
Definition gv2gxl.c:57
#define GXL_COMP
Definition gv2gxl.c:38
#define GXL_LOC
Definition gv2gxl.c:39
#define GXL_ID
Definition gv2gxl.c:34
#define GXL_TYPE
Definition gv2gxl.c:37
static void addToMap(Dt_t *map, char *name, char *uniqueName)
Definition gv2gxl.c:244
#define GXL_TO
Definition gv2gxl.c:36
#define GXL_HYPER
Definition gv2gxl.c:33
#define GXL_ROLE
Definition gv2gxl.c:32
replacements for ctype.h functions
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
agxbput(xb, staging)
#define XML_STATUS_ERROR
Definition htmllex.c:38
type-generic dynamically expanding list
#define LIST(type)
Definition list.h:55
#define LIST_BACK(list)
Definition list.h:191
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_FREE(list)
Definition list.h:370
#define LIST_POP_BACK(list)
Definition list.h:407
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_PUSH_BACK(list, item)
Definition list.h:384
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
Definition startswith.h:11
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
unsigned strict
Definition cgraph.h:286
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
Agdesc_t desc
Definition cgraph.h:426
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
Definition cdt.h:98
int key
Definition cdt.h:85
char * unique_name
Definition gv2gxl.c:54
char * name
Definition gv2gxl.c:53
Definition grammar.c:90
#define UNREACHABLE()
Definition unreachable.h:30