35#ifndef XML_STATUS_ERROR
36#define XML_STATUS_ERROR 0
41#define GRAPHML_ID "_graphml_id"
52static char*
gname =
"";
56static void pushString(strs_t *stk,
const char *
s) {
62 strs_push_back(stk,
copy);
65static void popString(strs_t *stk) {
67 if (strs_is_empty(stk)) {
68 fprintf(stderr,
"PANIC: graphml2gv: empty element stack\n");
72 strs_resize(stk, strs_size(stk) - 1,
NULL);
75static char *topString(strs_t *stk) {
77 if (strs_is_empty(stk)) {
78 fprintf(stderr,
"PANIC: graphml2gv: empty element stack\n");
82 return *strs_back(stk);
85static void freeString(strs_t *stk) {
92 int closedElementType;
101static graph_stack_t Gstack;
103static userdata_t genUserdata(
char *dfltname) {
104 userdata_t user = {0};
105 user.elements = (strs_t){0};
106 user.closedElementType = TAG_NONE;
107 user.edgeinverted =
false;
108 user.gname = dfltname;
112static void freeUserdata(userdata_t ud) {
113 freeString(&ud.elements);
116static int isAnonGraph(
const char *name) {
121 return (*name ==
'\0');
127 if (graph_stack_is_empty(&Gstack)) {
132 graph_stack_push_back(&Gstack, g);
140 if (graph_stack_is_empty(&Gstack)) {
141 fprintf(stderr,
"graphml2gv: Gstack underflow in graph parser\n");
146 Agraph_t *g = graph_stack_pop_back(&Gstack);
149 if (!graph_stack_is_empty(&Gstack)) {
150 G = *graph_stack_back(&Gstack);
156static Agnode_t *bind_node(
const char *name)
158 return agnode(
G, (
char *)name, 1);
161static Agedge_t *bind_edge(
const char *tail,
const char *
head)
166 tailNode =
agnode(
G, (
char *) tail, 1);
168 E =
agedge(
G, tailNode, headNode, key, 1);
172static int get_xml_attr(
char *attrname,
const char **atts)
175 while (atts[count] !=
NULL) {
176 if (strcmp(attrname, atts[count]) == 0) {
184static char *defval =
"";
186static void setEdgeAttr(
Agedge_t *ep,
char *name,
const char *value,
191 if (strcmp(name,
"headport") == 0) {
192 if (ud->edgeinverted)
193 attrname =
"tailport";
195 attrname =
"headport";
200 }
else if (strcmp(name,
"tailport") == 0) {
201 if (ud->edgeinverted)
202 attrname =
"headport";
204 attrname =
"tailport";
220startElementHandler(
void *userData,
const char *name,
const char **atts)
223 userdata_t *ud = userData;
226 if (strcmp(name,
"graphml") == 0) {
228 }
else if (strcmp(name,
"graph") == 0) {
229 const char *edgeMode =
"";
234 if (ud->closedElementType == TAG_GRAPH) {
236 "Warning: Node contains more than one graph.\n");
238 pos = get_xml_attr(
"id", atts);
244 pos = get_xml_attr(
"edgedefault", atts);
246 edgeMode = atts[pos];
249 if (graph_stack_is_empty(&Gstack)) {
250 if (strcmp(edgeMode,
"directed") == 0) {
252 }
else if (strcmp(edgeMode,
"undirected") == 0) {
257 "Warning: graph has no edgedefault attribute - assume directed\n");
265 if (isAnonGraph(
id)) {
266 static int anon_id = 1;
267 snprintf(buf,
sizeof(buf),
"%%%d", anon_id++);
270 subg =
agsubg(
G, (
char *)
id, 1);
274 pushString(&ud->elements,
id);
275 }
else if (strcmp(name,
"node") == 0) {
276 pos = get_xml_attr(
"id", atts);
278 const char *attrname;
279 attrname = atts[pos];
281 fprintf(stderr,
"node %s outside graph, ignored\n",attrname);
285 pushString(&ud->elements, attrname);
288 }
else if (strcmp(name,
"edge") == 0) {
289 const char *
head =
"", *tail =
"";
293 pos = get_xml_attr(
"source", atts);
296 pos = get_xml_attr(
"target", atts);
301 fprintf(stderr,
"edge source %s target %s outside graph, ignored\n",tail,
head);
303 bind_edge(tail,
head);
308 if (strcmp(tname, tail) == 0) {
309 ud->edgeinverted =
false;
310 }
else if (strcmp(tname,
head) == 0) {
311 ud->edgeinverted =
true;
314 pos = get_xml_attr(
"id", atts);
316 setEdgeAttr(
E, GRAPHML_ID, atts[pos], ud);
322 "Unknown node %s - ignoring.\n",
327static void endElementHandler(
void *userData,
const char *name)
329 userdata_t *ud = userData;
331 if (strcmp(name,
"graph") == 0) {
333 popString(&ud->elements);
334 ud->closedElementType = TAG_GRAPH;
335 }
else if (strcmp(name,
"node") == 0) {
336 char *ele_name = topString(&ud->elements);
337 if (ud->closedElementType == TAG_GRAPH) {
341 popString(&ud->elements);
342 ud->closedElementType = TAG_NODE;
343 }
else if (strcmp(name,
"edge") == 0) {
345 ud->closedElementType = TAG_EDGE;
346 ud->edgeinverted =
false;
350static Agraph_t *graphml_to_gv(
char *graphname, FILE *graphmlFile,
int *rv) {
353 userdata_t udata = genUserdata(graphname);
354 XML_Parser parser = XML_ParserCreate(
NULL);
357 XML_SetUserData(parser, &udata);
358 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
362 size_t len = fread(buf, 1,
sizeof(buf), graphmlFile);
365 done =
len <
sizeof(buf);
366 assert(
len <= INT_MAX);
370 XML_ErrorString(XML_GetErrorCode(parser)),
371 XML_GetCurrentLineNumber(parser));
376 XML_ParserFree(parser);
385 static FILE *savef =
NULL;
396 if ((rv = fopen(
Files[
cnt++],
"r")) != 0)
399 fprintf(stderr,
"Can't open %s\n",
Files[
cnt - 1]);
406static const char *
use =
"Usage: %s [-gd?] [-o<file>] [<graphs>]\n\
407 -g<name> : use <name> as template for graph names\n\
408 -o<file> : output to <file> (stdout)\n\
412static void usage(
int v)
422 sp = strrchr(
path,
'/');
430static void initargs(
int argc,
char **argv)
436 while ((c = getopt(argc, argv,
":vg:o:")) != -1) {
450 fprintf(stderr,
"%s: option -%c missing argument\n",
CmdName, optopt);
457 fprintf(stderr,
"%s: option -%c unrecognized\n",
CmdName,
494 int rv = 0, gcnt = 0;
506 fprintf (stderr,
"%s: %d nodes %d edges\n",
513 graph_stack_free(&Gstack);
518 fputs(
"graphml2gv: not configured for conversion from GXL to GV\n", stderr);
Agobj_t * copy(Agraph_t *g, Agobj_t *obj)
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
DOT-GXL converter API for gxl2gv.c and gv2gxl.c.
static void initargs(int argc, char **argv)
static char * cmdName(char *path)
static NORETURN void graphviz_exit(int status)
static double len(glCompPoint p)
static FILE * getFile(void)
static char * nameOf(agxbuf *buf, char *name, int cnt)
static int cnt(Dict_t *d, Dtlink_t **set)
int agnedges(Agraph_t *g)
int agnnodes(Agraph_t *g)
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
int agxset(void *obj, Agsym_t *sym, const char *value)
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Agdesc_t Agundirected
undirected
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Agdesc_t Agdirected
directed
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
char * agnameof(void *)
returns a string descriptor for the object.
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Agraph_t * graph(char *name)
replacements for ctype.h functions
static bool gv_isdigit(int c)
static const char * usage
#define DEFINE_LIST_WITH_DTOR(name, type, dtor)
#define DEFINE_LIST(name, type)
static FILE * openFile(const char *argv0, const char *name, const char *mode)