From: erg Date: Wed, 26 Jan 2011 23:57:53 +0000 (+0000) Subject: Fix bug 1480; simplify code in emit.c constructing internal object ids; X-Git-Tag: LAST_LIBGRAPH~32^2~1085 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a2ac878bba75ebe6fb2dfd9de6410e32f23f849d;p=graphviz Fix bug 1480; simplify code in emit.c constructing internal object ids; add the id field to TD and TABLE elements; use graph id attribute as prefix for xml ids, if supplied. --- diff --git a/lib/common/emit.c b/lib/common/emit.c index 9e350870f..e32399747 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -44,6 +44,7 @@ void* init_xdot (Agraph_t* g) xdot* xd = NULL; if ((p = agget(g, "_draw_")) && p[0]) { +#define DEBUG 1 #ifdef DEBUG if (Verbose) { start_timer(); @@ -169,25 +170,75 @@ initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target, char return assigned; } +/* genObjId: + * Use id of root graph if any, plus kind and internal id of object + */ +char* +getObjId (GVJ_t* job, void* obj, agxbuf* xb) +{ + char* id; + graph_t* root = job->gvc->g; + char* gid = GD_drawing(root)->id; + long idnum; + char* pfx; + char buf[30]; /* large enough for decimal 64-bit int */ + + id = agget(obj, "id"); + if (id && *id) + return id; + + switch (agobjkind(obj)) { +#ifndef WITH_CGRAPH + case AGGRAPH: + idnum = ((graph_t*)obj)->meta_node->id; +#else + case AGRAPH: + idnum = AGID((graph_t*)obj); +#endif + pfx = "graph"; + break; + case AGNODE: + idnum = AGID((node_t*)obj); + pfx = "node"; + break; + case AGEDGE: + idnum = AGID((edge_t*)obj); + pfx = "edge"; + break; + } + + if (gid) { + agxbput (xb, gid); + agxbputc (xb, '_'); + } + agxbput (xb, pfx); + sprintf (buf, "%ld", idnum); + agxbput (xb, buf); + + return agxbuse(xb); +} + static void -initObjMapData (GVJ_t* job, textlabel_t *lab, char *otyp, long int idnum, void* gobj) +initObjMapData (GVJ_t* job, textlabel_t *lab, void* gobj) { char* lbl; char* url = agget(gobj, "href"); char* tooltip = agget(gobj, "tooltip"); char* target = agget(gobj, "target"); - char* id = agget(gobj, "id"); - char buf[50]; + char* id; + unsigned char buf[SMALLBUF]; + agxbuf xb; + + agxbinit(&xb, SMALLBUF, buf); if (lab) lbl = lab->text; else lbl = NULL; if (!url || !*url) /* try URL as an alias for href */ url = agget(gobj, "URL"); - if (!id || !*id) { /* no external id, so use the internal one */ - sprintf(buf, "%s%ld", otyp, idnum); - id = buf; - } + id = getObjId (job, gobj, &xb); initMapData (job, lbl, url, tooltip, target, id, gobj); + + agxbfree(&xb); } static void map_point(GVJ_t *job, pointf pf) @@ -1217,7 +1268,7 @@ static void emit_begin_node(GVJ_t * job, node_t * n) else obj->z = 0.0; } - initObjMapData (job, ND_label(n), "node", AGID(n), n); + initObjMapData (job, ND_label(n), n); if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) && (obj->url || obj->explicit_tooltip)) { @@ -1950,7 +2001,7 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles) { obj_state_t *obj; int flags = job->flags; - char *s, buf[50]; + char *s; textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL; pointf *pbs = NULL; int i, nump, *pbs_n = NULL, pbs_poly_n = 0; @@ -2001,16 +2052,14 @@ static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles) } if (flags & GVRENDER_DOES_MAPS) { - s = agget(e, "id"); - if (!s || !*s) { /* no external id, so use the internal one */ -#ifndef WITH_CGRAPH - sprintf(buf,"edge%d", AGID(e)); -#else - sprintf(buf,"edge%ld", AGID(e)); -#endif - s = buf; - } + agxbuf xb; + unsigned char xbuf[SMALLBUF]; + + agxbinit(&xb, SMALLBUF, xbuf); + s = getObjId (job, e, &xb); obj->id = strdup_and_subst_obj(s, (void*)e); + agxbfree(&xb); + if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0])) dflt_url = strdup_and_subst_obj(s, (void*)e); if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0])) @@ -2840,11 +2889,7 @@ static void emit_begin_graph(GVJ_t * job, graph_t * g) obj->u.g = g; obj->emit_state = EMIT_GDRAW; -#ifndef WITH_CGRAPH - initObjMapData (job, GD_label(g), "graph", g->meta_node->id, g); -#else - initObjMapData (job, GD_label(g), "graph", AGID(g), g); -#endif + initObjMapData (job, GD_label(g), g); gvrender_begin_graph(job, g); } @@ -3054,11 +3099,7 @@ static void emit_begin_cluster(GVJ_t * job, Agraph_t * sg) obj->u.sg = sg; obj->emit_state = EMIT_CDRAW; -#ifndef WITH_CGRAPH - initObjMapData (job, GD_label(sg), "graph", sg->meta_node->id, sg); -#else - initObjMapData (job, GD_label(sg), "graph", AGID(sg), sg); -#endif + initObjMapData (job, GD_label(sg), sg); gvrender_begin_cluster(job, sg); } diff --git a/lib/common/htmllex.c b/lib/common/htmllex.c index 838943c3d..99eac0392 100644 --- a/lib/common/htmllex.c +++ b/lib/common/htmllex.c @@ -141,6 +141,12 @@ static int targetfn(htmldata_t * p, char *v) return 0; } +static int idfn(htmldata_t * p, char *v) +{ + p->id = strdup(v); + return 0; +} + /* doInt: * Scan v for integral value. Check that * the value is >= min and <= max. Return value in ul. @@ -396,6 +402,7 @@ static attr_item tbl_items[] = { {"fixedsize", (attrFn) fixedsizefn}, {"height", (attrFn) heightfn}, {"href", (attrFn) hreffn}, + {"id", (attrFn) idfn}, {"port", (attrFn) portfn}, {"target", (attrFn) targetfn}, {"title", (attrFn) titlefn}, @@ -416,6 +423,7 @@ static attr_item cell_items[] = { {"fixedsize", (attrFn) fixedsizefn}, {"height", (attrFn) heightfn}, {"href", (attrFn) hreffn}, + {"id", (attrFn) idfn}, {"port", (attrFn) portfn}, {"rowspan", (attrFn) rowspanfn}, {"target", (attrFn) targetfn}, diff --git a/lib/common/htmltable.c b/lib/common/htmltable.c index de55bdb51..edb1ffd70 100644 --- a/lib/common/htmltable.c +++ b/lib/common/htmltable.c @@ -47,12 +47,15 @@ typedef struct { void *obj; graph_t *g; char* imgscale; + char* objid; + boolean objid_set; } htmlenv_t; typedef struct { char *url; char *tooltip; char *target; + char *id; boolean explicit_tooltip; point LL; point UR; @@ -258,24 +261,46 @@ static void doFill(GVJ_t * job, char *color, boxf BF) * Initialize fields in job->obj pertaining to anchors. * In particular, this also sets the output rectangle. * If there is something to do, close current anchor if - * necesary, start the anchor and returns 1. + * necessary, start the anchor and returns 1. * Otherwise, it returns 0. * * FIX: Should we provide a tooltip if none is set, as is done * for nodes, edges, etc. ? */ static int -initAnchor (GVJ_t* job, htmldata_t* data, boxf b, htmlmap_data_t* save, +initAnchor (GVJ_t* job, htmlenv_t* env, htmldata_t* data, boxf b, htmlmap_data_t* save, int closePrev) { obj_state_t *obj = job->obj; int changed; + char* id; + static int anchorId; + int internalId = 0; + agxbuf xb; + char intbuf[30]; /* hold 64-bit decimal integer */ + unsigned char buf[SMALLBUF]; save->url = obj->url; save->tooltip = obj->tooltip; save->target = obj->target; + save->id = obj->id; save->explicit_tooltip = obj->explicit_tooltip; - changed = initMapData (job, NULL, data->href, data->title, data->target, "\\N", obj->u.g); + id = data->id; + if (!id || !*id) { /* no external id, so use the internal one */ + agxbinit(&xb, SMALLBUF, buf); + if (!env->objid) { + env->objid = strdup (getObjId (job, obj->u.n, &xb)); + env->objid_set = 1; + } + agxbput (&xb, env->objid); + sprintf (intbuf, "_%d", anchorId++); + agxbput (&xb, intbuf); + id = agxbuse (&xb); + internalId = 1; + } + changed = initMapData (job, NULL, data->href, data->title, data->target, id, obj->u.g); + if (internalId) + agxbfree (&xb); if (changed) { if (closePrev && (save->url || save->explicit_tooltip)) @@ -313,6 +338,7 @@ endAnchor (GVJ_t* job, htmlmap_data_t* save, int openPrev) RESET(url); RESET(tooltip); RESET(target); + RESET(id); obj->explicit_tooltip = save->explicit_tooltip; if (openPrev && (obj->url || obj->explicit_tooltip)) gvrender_begin_anchor(job, @@ -342,7 +368,7 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) pts.UR.y += pos.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) - anchor = initAnchor(job, &tbl->data, pts, &saved, 1); + anchor = initAnchor(job, env, &tbl->data, pts, &saved, 1); else anchor = 0; @@ -361,7 +387,7 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) endAnchor (job, &saved, 1); if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { - if (initAnchor(job, &tbl->data, pts, &saved, 0)) + if (initAnchor(job, env, &tbl->data, pts, &saved, 0)) endAnchor (job, &saved, 0); } @@ -414,7 +440,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) pts.UR.y += pos.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) - inAnchor = initAnchor(job, &cp->data, pts, &saved, 1); + inAnchor = initAnchor(job, env, &cp->data, pts, &saved, 1); else inAnchor = 0; @@ -436,7 +462,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) endAnchor (job, &saved, 1); if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { - if (initAnchor(job, &cp->data, pts, &saved, 0)) + if (initAnchor(job, env, &cp->data, pts, &saved, 0)) endAnchor (job, &saved, 0); } } @@ -485,6 +511,7 @@ freeObj (GVJ_t * job) obj->url = NULL; obj->tooltip = NULL; obj->target = NULL; + obj->id = NULL; pop_obj_state(job); } @@ -502,6 +529,8 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp) env.finfo.size = tp->fontsize; env.finfo.size = tp->fontsize; env.imgscale = agget (job->obj->u.n, "imagescale"); + env.objid = job->obj->id; + env.objid_set = 0; if ((env.imgscale == NULL) || (env.imgscale[0] == '\0')) env.imgscale = "false"; if (lp->kind == HTML_TBL) { @@ -518,6 +547,8 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp) } else { emit_html_txt(job, lp->u.txt, &env); } + if (env.objid_set) + free (env.objid); freeObj (job); } @@ -538,6 +569,7 @@ void free_html_data(htmldata_t * dp) free(dp->href); free(dp->port); free(dp->target); + free(dp->id); free(dp->title); free(dp->bgcolor); free(dp->pencolor); diff --git a/lib/common/htmltable.h b/lib/common/htmltable.h index 84f4c4d68..5ae805cba 100644 --- a/lib/common/htmltable.h +++ b/lib/common/htmltable.h @@ -66,6 +66,7 @@ extern "C" { char *port; char *target; char *title; + char *id; char *bgcolor; char *pencolor; signed char space; diff --git a/lib/common/input.c b/lib/common/input.c index 0b0d891eb..bf2ce61dd 100644 --- a/lib/common/input.c +++ b/lib/common/input.c @@ -834,12 +834,19 @@ void graph_init(graph_t * g, boolean use_rankdir) /* background */ GD_drawing(g)->xdots = init_xdot (g); + + /* initialize id, if any */ + + if ((p = agget(g, "id")) && *p) + GD_drawing(g)->id = strdup_and_subst_obj(p, g); } void graph_cleanup(graph_t *g) { if (GD_drawing(g)->xdots) freeXDot ((xdot*)GD_drawing(g)->xdots); + if (GD_drawing(g)->id) + free (GD_drawing(g)->id); free(GD_drawing(g)); GD_drawing(g) = NULL; free_label(GD_label(g)); diff --git a/lib/common/render.h b/lib/common/render.h index 8d4e1ac54..5b58adec0 100644 --- a/lib/common/render.h +++ b/lib/common/render.h @@ -101,6 +101,7 @@ extern "C" { extern void dotneato_write(GVC_t * gvc, graph_t *g); extern void dotneato_write_one(GVC_t * gvc, graph_t *g); extern void emit_clusters(GVJ_t * job, Agraph_t * g, int flags); + extern char* getObjId (GVJ_t* job, void* obj, agxbuf* xb); /* extern void emit_begin_edge(GVJ_t * job, edge_t * e, char**); */ /* extern void emit_end_edge(GVJ_t * job); */ extern void emit_graph(GVJ_t * job, graph_t * g); diff --git a/lib/common/types.h b/lib/common/types.h index 90e5c7461..f2e790e3f 100644 --- a/lib/common/types.h +++ b/lib/common/types.h @@ -232,6 +232,7 @@ extern "C" { boolean centered; ratio_t ratio_kind; void* xdots; + char* id; } layout_t; /* for "record" shapes */