Commit message: attempted fix for null pointer deference on malformed input
CVE: CVE-2019-11023
CWE: CWE-476
Vulnerability description: The agroot() function in cgraph\obj.c in libcgraph.a in Graphviz 2.39.20160612.1140 has a NULL pointer dereference, as demonstrated by graphml2gv.

Project: graphviz

void agmethod_init(Agraph_t * g, void *obj)
{
    if (g->clos->callbacks_enabled)
	aginitcb(g, obj, g->clos->cb);
    else
	agrecord_callback(g, obj, CB_INITIALIZE, NILsym);
}

Project: graphviz

int agpopdisc(Agraph_t * g, Agcbdisc_t * cbd)
{
    Agcbstack_t *stack_ent;

    stack_ent = g->clos->cb;
    if (stack_ent) {
	if (stack_ent->f == cbd)
	    g->clos->cb = stack_ent->prev;
	else {
	    while (stack_ent && (stack_ent->prev->f != cbd))
		stack_ent = stack_ent->prev;
	    if (stack_ent && stack_ent->prev)
		stack_ent->prev = stack_ent->prev->prev;
	}
	if (stack_ent) {
	    agfree(g, stack_ent);
	    return SUCCESS;
	}
    }
    return FAILURE;
}

Project: graphviz

static void popString(slist ** stk)
{
    slist *sp = *stk;
    if (!sp) {
	fprintf(stderr, "PANIC: graphml2gv: empty element stack\n");
	exit(1);
    }
    *stk = sp->next;
    free(sp);
}

Project: graphviz

static void characterDataHandler(void *userData, const char *s, int length)
{
    userdata_t *ud = (userdata_t *) userData;

    if (!ud->listen)
	return;

    if (ud->compositeReadState) {
	agxbput_n(&ud->composite_buffer, (char *) s, length);
	return;
    }

    agxbput_n(&ud->xml_attr_value, (char *) s, length);
}

Project: graphviz

int agdelete(Agraph_t * g, void *obj)
{
    if ((AGTYPE((Agobj_t *) obj) == AGRAPH) && (g != agparent(obj))) {
	agerr(AGERR, "agdelete on wrong graph");
	return FAILURE;
    }

    switch (AGTYPE((Agobj_t *) obj)) {
    case AGNODE:
	return agdelnode(g, obj);
    case AGINEDGE:
    case AGOUTEDGE:
	return agdeledge(g, obj);
    case AGRAPH:
	return agclose(obj);
    default:
	agerr(AGERR, "agdelete on bad object");
    }
    return SUCCESS;		/* not reached */
}

Project: graphviz

setNodeAttr(Agnode_t * np, char *name, char *value, userdata_t * ud)
{
    Agsym_t *ap;

    if (strcmp(name, "name") == 0) {
	setName(ud->nameMap, (Agobj_t *) np, value);
    } else {
	ap = agattr(root, AGNODE, name, 0);
	if (!ap)
	    ap = agattr(root, AGNODE, name, defval);
	agxset(np, ap, value);
    }
}

Project: graphviz

startElementHandler(void *userData, const char *name, const char **atts)
{
    int pos;
    userdata_t *ud = (userdata_t *) userData;
    Agraph_t *g = NULL;

    if (strcmp(name, "graphml") == 0) {
	/* do nothing */
    } else if (strcmp(name, "graph") == 0) {
	const char *edgeMode = "";
	const char *id;
	Agdesc_t dir;
	char buf[NAMEBUF];	/* holds % + number */

	Current_class = TAG_GRAPH;
	if (ud->closedElementType == TAG_GRAPH) {
	    fprintf(stderr,
		    "Warning: Node contains more than one graph.\n");
	}
	pos = get_xml_attr("id", atts);
	if (pos > 0) {
	    id = atts[pos];
	}
	else
	    id = ud->gname;
	pos = get_xml_attr("edgedefault", atts);
	if (pos > 0) {
	    edgeMode = atts[pos];
	}

	if (GSP == 0) {
	    if (strcmp(edgeMode, "directed") == 0) {
		dir = Agdirected;
	    } else if (strcmp(edgeMode, "undirected") == 0) {
		dir = Agundirected;
	    } else {
		if (Verbose) {
		    fprintf(stderr,
			"Warning: graph has no edgedefault attribute - assume directed\n");
		}
		dir = Agdirected;
	    }
	    g = agopen((char *) id, dir, &AgDefaultDisc);
	    push_subg(g);
	} else {
	    Agraph_t *subg;
	    if (isAnonGraph((char *) id)) {
		static int anon_id = 1;
		sprintf(buf, "%%%d", anon_id++);
		id = buf;
	    }
	    subg = agsubg(G, (char *) id, 1);
	    push_subg(subg);
	}

	pushString(&ud->elements, id);
    } else if (strcmp(name, "node") == 0) {
	Current_class = TAG_NODE;
	pos = get_xml_attr("id", atts);
	if (pos > 0) {
	    const char *attrname;
	    attrname = atts[pos];
            if (G == 0)
                fprintf(stderr,"node %s outside graph, ignored\n",attrname);
	    else
                bind_node(attrname);

	    pushString(&ud->elements, attrname);
	}

    } else if (strcmp(name, "edge") == 0) {
	const char *head = "", *tail = "";
	char *tname;
	Agnode_t *t;

	Current_class = TAG_EDGE;
	pos = get_xml_attr("source", atts);
	if (pos > 0)
	    tail = atts[pos];
	pos = get_xml_attr("target", atts);
	if (pos > 0)
	    head = atts[pos];

	tname = mapLookup(ud->nameMap, (char *) tail);
	if (tname)
	    tail = tname;

	tname = mapLookup(ud->nameMap, (char *) head);
	if (tname)
	    head = tname;

        if (G == 0)
            fprintf(stderr,"edge source %s target %s outside graph, ignored\n",(char*)tail,(char*)head);
        else {
            bind_edge(tail, head);

            t = AGTAIL(E);
	    tname = agnameof(t);

	    if (strcmp(tname, tail) == 0) {
	        ud->edgeinverted = FALSE;
	    } else if (strcmp(tname, head) == 0) {
	        ud->edgeinverted = TRUE;
	    }

	    pos = get_xml_attr("id", atts);
	    if (pos > 0) {
	        setEdgeAttr(E, GRAPHML_ID, (char *) atts[pos], ud);
	    }
        }
    } else {
	/* must be some extension */
	fprintf(stderr,
		"Unknown node %s - ignoring.\n",
		name);
    }
}

Project: graphviz

static Agnode_t *bind_node(const char *name)
{
    N = agnode(G, (char *) name, 1);
    return N;
}

Project: graphviz

int agcontains(Agraph_t* g, void* obj)
{
    Agraph_t* subg;

    if (agroot (g) != agroot (obj)) return 0;
    switch (AGTYPE(obj)) {
    case AGRAPH:
	subg = (Agraph_t *) obj;
	do {
	    if (subg == g) return 1;
	} while ((subg = agparent (subg)));
	return 0;
    case AGNODE: 
        return (agidnode(g, AGID(obj), 0) != 0);
    default:
        return (agsubedge(g, (Agedge_t *) obj, 0) != 0);
    }
}

Project: graphviz

void agmethod_delete(Agraph_t * g, void *obj)
{
    if (g->clos->callbacks_enabled)
	agdelcb(g, obj, g->clos->cb);
    else
	agrecord_callback(g, obj, CB_DELETION, NILsym);
}

Project: graphviz

setGraphAttr(Agraph_t * g, char *name, char *value, userdata_t * ud)
{
    Agsym_t *ap;

    if ((g == root) && !strcmp(name, "strict") && !strcmp(value, "true")) {
	g->desc.strict = 1;
    } else if (strcmp(name, "name") == 0)
	setName(ud->nameMap, (Agobj_t *) g, value);
    else {
	ap = agattr(root, AGRAPH, name, 0);
	if (ap)
	    agxset(g, ap, value);
	else if (g == root)
	    agattr(root, AGRAPH, name, value);
	else {
	    ap = agattr(root, AGRAPH, name, defval);
	    agxset(g, ap, value);
	}
    }
}

Project: graphviz

int agrename(Agobj_t * obj, char *newname)
{
    Agraph_t *g;
    IDTYPE old_id, new_id;

    switch (AGTYPE(obj)) {
    case AGRAPH:
	old_id = AGID(obj);
	g = agraphof(obj);
	/* can we reserve the id corresponding to newname? */
	if (agmapnametoid(agroot(g), AGTYPE(obj), newname,
			  &new_id, FALSE) == 0)
	    return FAILURE;
	if (new_id == old_id)
	    return SUCCESS;
	if (agmapnametoid(agroot(g), AGTYPE(obj), newname,
			  &new_id, TRUE) == 0)
	    return FAILURE;
        /* obj* is unchanged, so no need to re agregister() */
	if (agparent(g) && agidsubg(agparent(g), new_id, 0))
	    return FAILURE;
	agfreeid(g, AGRAPH, old_id);
	AGID(g) = new_id;
	break;
    case AGNODE:
	return agrelabel_node((Agnode_t *) obj, newname);
	agrename(obj, newname);
	break;
    case AGINEDGE:
    case AGOUTEDGE:
	return FAILURE;
    }
    return SUCCESS;
}

Project: graphviz

int agobjkind(void *arg)
{
	return AGTYPE(arg);
}

Project: graphviz

static char *topString(slist * stk)
{
    if (!stk) {
	fprintf(stderr, "PANIC: graphml2gv: empty element stack\n");
	exit(1);
    }
    return stk->buf;
}

Project: graphviz

static void usage(int v)
{
    fprintf(stderr, use, CmdName);
    exit(v);
}

Project: graphviz

void agupdcb(Agraph_t * g, void *obj, Agsym_t * sym, Agcbstack_t * cbstack)
{
    agobjupdfn_t fn;

    if (cbstack == NIL(Agcbstack_t *))
	return;
    agupdcb(g, obj, sym, cbstack->prev);
    fn = NIL(agobjupdfn_t);
    switch (AGTYPE(obj)) {
    case AGRAPH:
	fn = cbstack->f->graph.mod;
	break;
    case AGNODE:
	fn = cbstack->f->node.mod;
	break;
    case AGEDGE:
	fn = cbstack->f->edge.mod;
	break;
    }
    if (fn)
	fn(g, obj, cbstack->state, sym);
}

Project: graphviz

Agraph_t *agroot(void* obj)
{
    // fixes CVE-2019-11023 by moving the problem to the caller :-)
    if (obj == 0) return NILgraph; 
    switch (AGTYPE(obj)) {
    case AGINEDGE:
    case AGOUTEDGE:
	return ((Agedge_t *) obj)->node->root;
    case AGNODE:
	return ((Agnode_t *) obj)->root;
    case AGRAPH:
	return ((Agraph_t *) obj)->root;
    default:			/* actually can't occur if only 2 bit tags */
	agerr(AGERR, "agroot of a bad object");
	return NILgraph;
    }
}

Project: graphviz

static namev_t *make_nitem(Dt_t * d, namev_t * objp, Dtdisc_t * disc)
{
    namev_t *np = NEW(namev_t);
    np->name = objp->name;
    np->unique_name = 0;
    return np;
}

Project: graphviz

static void freeUserdata(userdata_t * ud)
{
    dtclose(ud->nameMap);
    agxbfree(&(ud->xml_attr_name));
    agxbfree(&(ud->xml_attr_value));
    agxbfree(&(ud->composite_buffer));
    freeString(ud->elements);
    free(ud);
}

Project: graphviz

static void free_nitem(Dt_t * d, namev_t * np, Dtdisc_t * disc)
{
    free(np->unique_name);
    free(np);
}

Project: graphviz

static char *mapLookup(Dt_t * nm, char *name)
{
    namev_t *objp = dtmatch(nm, name);
    if (objp)
	return objp->unique_name;
    else
	return 0;
}

Project: graphviz

static Agraph_t *pop_subg(void)
{
    Agraph_t *g;
    if (GSP == 0) {
	fprintf(stderr, "graphml2gv: Gstack underflow in graph parser\n");
	exit(1);
    }
    g = Gstack[--GSP];
    if (GSP > 0)
	G = Gstack[GSP - 1];
    return g;
}

Project: graphviz

static int isAnonGraph(char *name)
{
    if (*name++ != '%')
	return 0;
    while (isdigit(*name))
	name++;			/* skip over digits */
    return (*name == '\0');
}

Project: graphviz

static FILE *openFile(char *name, char *mode)
{
    FILE *fp;
    char *modestr;

    fp = fopen(name, mode);
    if (!fp) {
	if (*mode == 'r')
	    modestr = "reading";
	else
	    modestr = "writing";
	fprintf(stderr, "%s: could not open file %s for %s\n",
		CmdName, name, modestr);
	perror(name);
	exit(1);
    }
    return fp;
}

Project: graphviz

static void freeString(slist * stk)
{
    slist *sp;

    while (stk) {
	sp = stk->next;
	free(stk);
	stk = sp;
    }
}

Project: graphviz

static void setAttr(char *name, char *value, userdata_t * ud)
{
    switch (Current_class) {
    case TAG_GRAPH:
	setGraphAttr(G, name, value, ud);
	break;
    case TAG_NODE:
	setNodeAttr(N, name, value, ud);
	break;
    case TAG_EDGE:
	setEdgeAttr(E, name, value, ud);
	break;
    }
}

Project: graphviz

static void initargs(int argc, char **argv)
{
    int c;

    CmdName = cmdName(argv[0]);
    opterr = 0;
    while ((c = getopt(argc, argv, ":vg:o:")) != -1) {
	switch (c) {
	case 'g':
	    gname = optarg;
	    break;
	case 'v':
	    Verbose = 1;
	    break;
	case 'o':
	    outFile = openFile(optarg, "w");
	    break;
	case ':':
	    fprintf(stderr, "%s: option -%c missing argument\n", CmdName, optopt);
	    usage(1);
	    break;
	case '?':
	    if (optopt == '?')
		usage(0);
	    else {
		fprintf(stderr, "%s: option -%c unrecognized\n", CmdName,
			optopt);
		usage(1);
	    }
	}
    }

    argv += optind;
    argc -= optind;

    if (argc)
	Files = argv;
    if (!outFile)
	outFile = stdout;
}

Project: graphviz

void agdelcb(Agraph_t * g, void *obj, Agcbstack_t * cbstack)
{
    agobjfn_t fn;

    if (cbstack == NIL(Agcbstack_t *))
	return;
    agdelcb(g, obj, cbstack->prev);
    fn = NIL(agobjfn_t);
    switch (AGTYPE(obj)) {
    case AGRAPH:
	fn = cbstack->f->graph.del;
	break;
    case AGNODE:
	fn = cbstack->f->node.del;
	break;
    case AGEDGE:
	fn = cbstack->f->edge.del;
	break;
    }
    if (fn)
	fn(g, obj, cbstack->state);
}

Project: graphviz

Agraph_t *agraphof(void *obj)
{
    switch (AGTYPE(obj)) {
    case AGINEDGE:
    case AGOUTEDGE:
	return ((Agedge_t *) obj)->node->root;
    case AGNODE:
	return ((Agnode_t *) obj)->root;
    case AGRAPH:
	return (Agraph_t *) obj;
    default:			/* actually can't occur if only 2 bit tags */
	agerr(AGERR, "agraphof a bad object");
	return NILgraph;
    }
}

Project: graphviz

static void addToMap(Dt_t * map, char *name, char *uniqueName)
{
    namev_t obj;
    namev_t *objp;

    obj.name = name;
    objp = dtinsert(map, &obj);
    assert(objp->unique_name == 0);
    objp->unique_name = strdup(uniqueName);
}

Project: graphviz

static Agedge_t *bind_edge(const char *tail, const char *head)
{
    Agnode_t *tailNode, *headNode;
    char *key = 0;

    tailNode = agnode(G, (char *) tail, 1);
    headNode = agnode(G, (char *) head, 1);
    E = agedge(G, tailNode, headNode, key, 1);
    return E;
}

Project: graphviz

void aginitcb(Agraph_t * g, void *obj, Agcbstack_t * cbstack)
{
    agobjfn_t fn;

    if (cbstack == NIL(Agcbstack_t *))
	return;
    aginitcb(g, obj, cbstack->prev);
    fn = NIL(agobjfn_t);
    switch (AGTYPE(obj)) {
    case AGRAPH:
	fn = cbstack->f->graph.ins;
	break;
    case AGNODE:
	fn = cbstack->f->node.ins;
	break;
    case AGEDGE:
	fn = cbstack->f->edge.ins;
	break;
    }
    if (fn)
	fn(g, obj, cbstack->state);
}

Project: graphviz

Agraph_t *graphml_to_gv(char* gname, FILE * graphmlFile, int* rv)
{
    char buf[BUFSIZE];
    int done;
    userdata_t *udata = genUserdata(gname);
    XML_Parser parser = XML_ParserCreate(NULL);

    *rv = 0;
    XML_SetUserData(parser, udata);
    XML_SetElementHandler(parser, startElementHandler, endElementHandler);
    XML_SetCharacterDataHandler(parser, characterDataHandler);

    Current_class = TAG_GRAPH;
    root = 0;
    do {
	size_t len = fread(buf, 1, sizeof(buf), graphmlFile);
	if (len == 0)
	    break;
	done = len < sizeof(buf);
	if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
	    fprintf(stderr,
		    "%s at line %lu\n",
		    XML_ErrorString(XML_GetErrorCode(parser)),
		    XML_GetCurrentLineNumber(parser));
	    *rv = 1;
	    break;
	}
    } while (!done);
    XML_ParserFree(parser);
    freeUserdata(udata);

    return root;
}

Project: graphviz

setGlobalEdgeAttr(Agraph_t * g, char *name, char *value, userdata_t * ud)
{
    if (strncmp(name, EDGELBL, ELBLLEN))
	fprintf(stderr,
		"Warning: global edge attribute %s in graph %s does not begin with the prefix %s\n",
		name, agnameof(g), EDGELBL);
    else
	name += ELBLLEN;
    if ((g != root) && !agattr(root, AGEDGE, name, 0))
	agattr(root, AGEDGE, name, defval);
    agattr(g, AGEDGE, name, value);
}

Project: graphviz

static void endElementHandler(void *userData, const char *name)
{
    userdata_t *ud = (userdata_t *) userData;

    if (strcmp(name, "graph") == 0) {
	pop_subg();
	popString(&ud->elements);
	ud->closedElementType = TAG_GRAPH;
    } else if (strcmp(name, "node") == 0) {
	char *ele_name = topString(ud->elements);
	if (ud->closedElementType == TAG_GRAPH) {
	    Agnode_t *node = agnode(root, ele_name, 0);
	    if (node) agdelete(root, node);
	}
	popString(&ud->elements);
	Current_class = TAG_GRAPH;
	N = 0;
	ud->closedElementType = TAG_NODE;
    } else if (strcmp(name, "edge") == 0) {
	Current_class = TAG_GRAPH;
	E = 0;
	ud->closedElementType = TAG_EDGE;
	ud->edgeinverted = FALSE;
    } else if (strcmp(name, "attr") == 0) {
	char *name;
	char *value;
	char buf[SMALLBUF] = GRAPHML_COMP;
	char *dynbuf = 0;

	ud->closedElementType = TAG_NONE;
	if (ud->compositeReadState) {
	    int len = sizeof(GRAPHML_COMP) + agxblen(&ud->xml_attr_name);
	    if (len <= SMALLBUF) {
		name = buf;
	    } else {
		name = dynbuf = N_NEW(len, char);
		strcpy(name, GRAPHML_COMP);
	    }
	    strcpy(name + sizeof(GRAPHML_COMP) - 1,
		   agxbuse(&ud->xml_attr_name));
	    value = agxbuse(&ud->composite_buffer);
	    agxbclear(&ud->xml_attr_value);
	    ud->compositeReadState = FALSE;
	} else {
	    name = agxbuse(&ud->xml_attr_name);
	    value = agxbuse(&ud->xml_attr_value);
	}

	switch (ud->globalAttrType) {
	case TAG_NONE:
	    setAttr(name, value, ud);
	    break;
	case TAG_NODE:
	    setGlobalNodeAttr(G, name, value, ud);
	    break;
	case TAG_EDGE:
	    setGlobalEdgeAttr(G, name, value, ud);
	    break;
	case TAG_GRAPH:
	    setGraphAttr(G, name, value, ud);
	    break;
	}
	if (dynbuf)
	    free(dynbuf);
	ud->globalAttrType = TAG_NONE;
    } 
}

Project: graphviz

void agmethod_upd(Agraph_t * g, void *obj, Agsym_t * sym)
{
    if (g->clos->callbacks_enabled)
	agupdcb(g, obj, sym, g->clos->cb);
    else
	agrecord_callback(g, obj, CB_UPDATE, sym);
}

Project: graphviz

static void pushString(slist ** stk, const char *s)
{
    int sz = ROUND2(sizeof(slist) + strlen(s), sizeof(void *));
    slist *sp = (slist *) N_NEW(sz, char);
    strcpy(sp->buf, s);
    sp->next = *stk;
    *stk = sp;
}

Project: graphviz

static char *cmdName(char *path)
{
    char *sp;

    sp = strrchr(path, '/');
    if (sp)
	sp++;
    else
	sp = path;
    return sp;
}

Project: graphviz

static void setName(Dt_t * names, Agobj_t * n, char *value)
{
    Agsym_t *ap;
    char *oldName;

    ap = agattr(root, AGTYPE(n), GRAPHML_ID, "");
    agxset(n, ap, agnameof(n));
    oldName = agxget(n, ap);	/* set/get gives us new copy */
    addToMap(names, oldName, value);
    agrename(n, value);
}

Project: graphviz

static userdata_t *genUserdata(char* dfltname)
{
    userdata_t *user = NEW(userdata_t);
    agxbinit(&(user->xml_attr_name), NAMEBUF, 0);
    agxbinit(&(user->xml_attr_value), SMALLBUF, 0);
    agxbinit(&(user->composite_buffer), SMALLBUF, 0);
    user->listen = FALSE;
    user->elements = 0;
    user->closedElementType = TAG_NONE;
    user->globalAttrType = TAG_NONE;
    user->compositeReadState = FALSE;
    user->edgeinverted = FALSE;
    user->gname = dfltname;
    user->nameMap = dtopen(&nameDisc, Dtoset);
    return user;
}

Project: graphviz

static void push_subg(Agraph_t * g)
{
    if (GSP == STACK_DEPTH) {
	fprintf(stderr, "graphml2gv: Too many (> %d) nestings of subgraphs\n",
		STACK_DEPTH);
	exit(1);
    } else if (GSP == 0)
	root = g;
    G = Gstack[GSP++] = g;
}

Project: graphviz

void *aggetuserptr(Agraph_t * g, Agcbdisc_t * cbd)
{
    Agcbstack_t *stack_ent;

    for (stack_ent = g->clos->cb; stack_ent; stack_ent = stack_ent->prev)
	if (stack_ent->f == cbd)
	    return stack_ent->state;
    return NIL(void *);
}

Project: graphviz

static FILE *getFile(void)
{
    FILE *rv = NULL;
    static FILE *savef = NULL;
    static int cnt = 0;

    if (Files == NULL) {
	if (cnt++ == 0) {
	    rv = stdin;
	}
    } else {
	if (savef)
	    fclose(savef);
	while (Files[cnt]) {
	    if ((rv = fopen(Files[cnt++], "r")) != 0)
		break;
	    else
		fprintf(stderr, "Can't open %s\n", Files[cnt - 1]);
	}
    }
    savef = rv;
    return rv;
}

Project: graphviz

nameOf (char* name, int cnt)
{
    static char* buf = 0;

    if (*name == '\0')
	return name;
    if (cnt) {
	if (!buf)
	    buf = N_NEW (strlen(name)+32,char);  /* 32 to handle any integer plus null byte */
	sprintf (buf, "%s%d", name, cnt);
	return buf;
    }
    else
	return name;
}

Project: graphviz

void agpushdisc(Agraph_t * g, Agcbdisc_t * cbd, void *state)
{
    Agcbstack_t *stack_ent;

    stack_ent = AGNEW(g, Agcbstack_t);
    stack_ent->f = cbd;
    stack_ent->state = state;
    stack_ent->prev = g->clos->cb;
    g->clos->cb = stack_ent;
}

Project: graphviz

setGlobalNodeAttr(Agraph_t * g, char *name, char *value, userdata_t * ud)
{
    if (strncmp(name, NODELBL, NLBLLEN))
	fprintf(stderr,
		"Warning: global node attribute %s in graph %s does not begin with the prefix %s\n",
		name, agnameof(g), NODELBL);
    else
	name += NLBLLEN;
    if ((g != root) && !agattr(root, AGNODE, name, 0))
	agattr(root, AGNODE, name, defval);
    agattr(G, AGNODE, name, value);
}

Project: graphviz

int main(int argc, char **argv)
{
    Agraph_t *G;
    Agraph_t *prev = 0;
    FILE *inFile;
    int rv, gcnt = 0;

#ifdef HAVE_EXPAT
    initargs(argc, argv);
    while ((inFile = getFile())) {
	while ((G = graphml_to_gv(nameOf(gname, gcnt), inFile, &rv))) {
	    gcnt++;
	    if (prev)
		agclose(prev);
	    prev = G;
	    if (Verbose) 
		fprintf (stderr, "%s: %d nodes %d edges\n",
		    agnameof (G), agnnodes(G), agnedges(G));
	    agwrite(G, outFile);
	    fflush(outFile);
	}
    }
    exit(rv);
#else
    fputs("cvtgxl: not configured for conversion from GXL to GV\n", stderr);
    exit(1);
#endif
}

Project: graphviz

static int get_xml_attr(char *attrname, const char **atts)
{
    int count = 0;
    while (atts[count] != NULL) {
	if (strcmp(attrname, atts[count]) == 0) {
	    return count + 1;
	}
	count += 2;
    }
    return -1;
}

Project: graphviz

setEdgeAttr(Agedge_t * ep, char *name, char *value, userdata_t * ud)
{
    Agsym_t *ap;
    char *attrname;

    if (strcmp(name, "headport") == 0) {
	if (ud->edgeinverted)
	    attrname = "tailport";
	else
	    attrname = "headport";
	ap = agattr(root, AGEDGE, attrname, 0);
	if (!ap)
	    ap = agattr(root, AGEDGE, attrname, defval);
	agxset(ep, ap, value);
    } else if (strcmp(name, "tailport") == 0) {
	if (ud->edgeinverted)
	    attrname = "headport";
	else
	    attrname = "tailport";
	ap = agattr(root, AGEDGE, attrname, 0);
	if (!ap)
	    ap = agattr(root, AGEDGE, attrname, defval);
	agxset(ep, ap, value);
    } else {
	ap = agattr(root, AGEDGE, name, 0);
	if (!ap)
	    ap = agattr(root, AGEDGE, name, defval);
	agxset(ep, ap, value);
    }
}