From: erg Date: Mon, 6 Nov 2006 21:58:55 +0000 (+0000) Subject: Fully integrate xdot output into the plugin architecture, fixing a variety X-Git-Tag: LAST_LIBGRAPH~32^2~5819 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3f181491d436480e3e14480aa44f2f0243f1cb81;p=graphviz Fully integrate xdot output into the plugin architecture, fixing a variety of bugs on the way. --- diff --git a/lib/common/emit.c b/lib/common/emit.c index 6dc9f576f..df91d8e98 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -1300,7 +1300,7 @@ static char* default_pencolor(char *pencolor, char *deflt) return buf; } -void emit_edge_graphics(GVJ_t * job, edge_t * e) +static void emit_edge_graphics(GVJ_t * job, edge_t * e) { int i, j, cnum, numc = 0; char *color, *pencolor, *fillcolor, *style; @@ -2361,7 +2361,7 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags) if (obj->url || obj->explicit_tooltip) gvrender_end_anchor(job); if (GD_label(sg)) - emit_label(job, EMIT_GLABEL, GD_label(sg)); + emit_label(job, EMIT_CLABEL, GD_label(sg)); if (flags & EMIT_PREORDER) { for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) { diff --git a/lib/common/output.c b/lib/common/output.c index c418b56a3..2c95c896d 100644 --- a/lib/common/output.c +++ b/lib/common/output.c @@ -17,10 +17,6 @@ #include "render.h" #include "agxbuf.h" -static int e_arrows; /* graph has edges with end arrows */ -static int s_arrows; /* graph has edges with start arrows */ -static attrsym_t *g_draw; -static attrsym_t *g_l_draw; static void printptf(FILE * f, point pt) { @@ -149,7 +145,7 @@ static void set_record_rects(node_t * n, field_t * f, agxbuf * xb) static void rec_attach_bb(graph_t * g) { int c; - char buf[32]; + char buf[BUFSIZ]; point pt; sprintf(buf, "%d,%d,%d,%d", GD_bb(g).LL.x, GD_bb(g).LL.y, @@ -164,8 +160,10 @@ static void rec_attach_bb(graph_t * g) rec_attach_bb(GD_clust(g)[c]); } -void attach_attrs(graph_t * g) +void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep) { + int e_arrows; /* graph has edges with end arrows */ + int s_arrows; /* graph has edges with start arrows */ int i, j, sides; char buf[BUFSIZ]; /* Used only for small strings */ unsigned char xbuffer[BUFSIZ]; /* Initial buffer for xb */ @@ -297,155 +295,14 @@ void attach_attrs(graph_t * g) if (HAS_CLUST_EDGE(g)) undoClusterEdges(g); + + *sp = s_arrows; + *ep = e_arrows; } -static int isInvis(char *style) +void attach_attrs(graph_t * g) { - char **styles = 0; - char **sp; - char *p; - - if (style[0]) { - styles = parse_style(style); - sp = styles; - while ((p = *sp++)) { - if (streq(p, "invis")) - return 1; - } - } - return 0; + int e, s; + attach_attrs_and_arrows (g, &s, &e); } -/* - * John M. suggests: - * You might want to add four more: - * - * _ohdraw_ (optional head-end arrow for edges) - * _ohldraw_ (optional head-end label for edges) - * _otdraw_ (optional tail-end arrow for edges) - * _otldraw_ (optional tail-end label for edges) - * - * that would be generated when an additional option is supplied to dot, etc. and - * these would be the arrow/label positions to use if a user want to flip the - * direction of an edge (as sometimes is there want). - * - * N.B. John M. asks: - * By the way, I don't know if you ever plan to add other letters for - * the xdot spec, but could you reserve "a" and also "A" (for attribute), - * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string) - * and "t" (for tooltip) and "x" (for position). We use those letters in - * our drawing spec (and also "<" and ">"), so if you start generating - * output with them, it could break what we have. - */ - -#define XDOTVERSION "1.1" - -void extend_attrs(GVJ_t * job, graph_t *g, agxbuf** xbufs) -{ - node_t *n; - edge_t *e; - attrsym_t *n_draw = NULL; - attrsym_t *n_l_draw = NULL; - attrsym_t *e_draw = NULL; - attrsym_t *h_draw = NULL; - attrsym_t *t_draw = NULL; - attrsym_t *e_l_draw = NULL; - attrsym_t *hl_draw = NULL; - attrsym_t *tl_draw = NULL; - unsigned char buf0[BUFSIZ]; - unsigned char buf1[BUFSIZ]; - unsigned char buf2[BUFSIZ]; - unsigned char buf3[BUFSIZ]; - unsigned char buf4[BUFSIZ]; - unsigned char buf5[BUFSIZ]; - - agsafeset (g, "xdotversion", XDOTVERSION, ""); - if (GD_has_labels(g) & GRAPH_LABEL) - g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr); - else - g_l_draw = NULL; - if (GD_n_cluster(g)) - g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); - else - g_draw = NULL; - - n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr); - n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr); - - e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr); - if (e_arrows) - h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr); - if (s_arrows) - t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr); - if (GD_has_labels(g) & EDGE_LABEL) - e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr); - if (GD_has_labels(g) & HEAD_LABEL) - hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr); - if (GD_has_labels(g) & TAIL_LABEL) - tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr); - - agxbinit(xbufs[0], BUFSIZ, buf0); - agxbinit(xbufs[1], BUFSIZ, buf1); - agxbinit(xbufs[2], BUFSIZ, buf2); - agxbinit(xbufs[3], BUFSIZ, buf3); - agxbinit(xbufs[4], BUFSIZ, buf4); - agxbinit(xbufs[5], BUFSIZ, buf5); - - for (n = agfstnode(g); n; n = agnxtnode(g, n)) { - if (ND_shape(n) && !isInvis(late_string(n, N_style, ""))) { - ND_shape(n)->fns->codefn(job, n); - agxset(n, n_draw->index, agxbuse(xbufs[EMIT_NDRAW])); - agxset(n, n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL])); - } - if (State < GVSPLINES) - continue; - for (e = agfstout(g, n); e; e = agnxtout(g, e)) { - if (ED_edge_type(e) == IGNORED) - continue; - if (isInvis(late_string(e, E_style, ""))) - continue; - if (ED_spl(e) == NULL) - continue; - - emit_begin_edge (job, e); - emit_edge_graphics (job, e); - emit_end_edge (job); - agxset(e, e_draw->index, agxbuse(xbufs[EMIT_EDRAW])); - if (t_draw) agxset(e, t_draw->index, agxbuse(xbufs[EMIT_TDRAW])); - if (h_draw) agxset(e, h_draw->index, agxbuse(xbufs[EMIT_HDRAW])); - if (e_l_draw) agxset(e, e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL])); - if (tl_draw) agxset(e, tl_draw->index, agxbuse(xbufs[EMIT_TLABEL])); - if (hl_draw) agxset(e, hl_draw->index, agxbuse(xbufs[EMIT_HLABEL])); - } - } - - emit_background(job, g); - if (agxblen(xbufs[EMIT_GDRAW])) { - if (!g_draw) - g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); - agxset(g, g_draw->index, agxbuse(xbufs[EMIT_GDRAW])); - } - if (GD_label(g)) { - emit_label(job, EMIT_GLABEL, GD_label(g)); - agxset(g, g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL])); - } - emit_clusters(job, g, 0); - agxbfree(xbufs[0]); - agxbfree(xbufs[1]); - agxbfree(xbufs[2]); - agxbfree(xbufs[3]); - agxbfree(xbufs[4]); - agxbfree(xbufs[5]); -} - -void extend_attrs_glabel(graph_t *sg, agxbuf **xbufs) -{ - if (!g_draw) - g_draw = safe_dcl(sg->root, sg, "_draw_", "", agraphattr); - agxset(sg, g_draw->index, agxbuse(xbufs[EMIT_CDRAW])); - if (GD_label(sg)) { - if (!g_l_draw) - g_l_draw = safe_dcl(sg->root, sg, "_ldraw_", "", agraphattr); - agxset(sg, g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL])); - } -} diff --git a/lib/common/render.h b/lib/common/render.h index 5d73f590b..1615f87b9 100644 --- a/lib/common/render.h +++ b/lib/common/render.h @@ -96,7 +96,6 @@ extern "C" { extern void emit_background(GVJ_t * job, graph_t *g); extern void emit_clusters(GVJ_t * job, Agraph_t * g, int flags); extern void emit_begin_edge(GVJ_t * job, edge_t * e); - extern void emit_edge_graphics(GVJ_t * job, edge_t * e); extern void emit_end_edge(GVJ_t * job); extern void emit_graph(GVJ_t * job, graph_t * g); extern void emit_label(GVJ_t * job, emit_state_t emit_state, textlabel_t *); @@ -144,7 +143,6 @@ extern "C" { extern void translate_bb(Agraph_t *, int); extern void write_attributed_dot(graph_t *g, FILE *f); extern void write_canonical_dot(graph_t *g, FILE *f); - extern void write_extended_dot(GVJ_t * job, graph_t *g, FILE *f); extern void write_plain(GVJ_t * job, graph_t * g, FILE * f, bool extend); #if defined(_BLD_dot) && defined(_DLL) diff --git a/lib/gvc/gvcjob.h b/lib/gvc/gvcjob.h index f991d032d..eeb8f1f26 100644 --- a/lib/gvc/gvcjob.h +++ b/lib/gvc/gvcjob.h @@ -132,35 +132,13 @@ extern "C" { typedef enum {MAP_RECTANGLE, MAP_CIRCLE, MAP_POLYGON, } map_shape_t; typedef enum {ROOTGRAPH_OBJTYPE, CLUSTER_OBJTYPE, NODE_OBJTYPE, EDGE_OBJTYPE} obj_type; -#if 0 - typedef enum {EMIT_GDRAW, EMIT_CDRAW, EMIT_NDRAW, EMIT_EDRAW, EMIT_TDRAW, EMIT_HDRAW, - EMIT_GLABEL, EMIT_CLABEL, EMIT_NLABEL, EMIT_ELABEL, EMIT_TLABEL, EMIT_HLABEL} emit_state_t; -#else - -/* FIXME - There are places in the core that rely on there being exactly 6 emit_states ! */ -#define emit_state_t int - -/* value specifying emit state */ -#define EMIT_DRAW 0 -#define EMIT_GDRAW EMIT_DRAW -#define EMIT_CDRAW EMIT_DRAW -#define EMIT_NDRAW EMIT_DRAW -#define EMIT_EDRAW EMIT_DRAW - -/* values specifying emit state for arrowheads */ -#define EMIT_TDRAW 1 -#define EMIT_HDRAW 2 - -/* values specifying emit state for labels */ -#define EMIT_LABEL 3 -#define EMIT_GLABEL EMIT_LABEL -#define EMIT_CLABEL EMIT_LABEL -#define EMIT_NLABEL EMIT_LABEL -#define EMIT_ELABEL EMIT_LABEL -#define EMIT_TLABEL 4 -#define EMIT_HLABEL 5 -#endif + /* See comment in gvrender_core_dot.c */ + typedef enum { + EMIT_GDRAW, EMIT_CDRAW, EMIT_TDRAW, EMIT_HDRAW, + EMIT_GLABEL, EMIT_CLABEL, EMIT_TLABEL, EMIT_HLABEL, + EMIT_NDRAW, EMIT_EDRAW, EMIT_NLABEL, EMIT_ELABEL, + } emit_state_t; typedef struct obj_state_s obj_state_t; diff --git a/plugin/core/gvrender_core_dot.c b/plugin/core/gvrender_core_dot.c index bc7880bd0..03654bc42 100644 --- a/plugin/core/gvrender_core_dot.c +++ b/plugin/core/gvrender_core_dot.c @@ -36,25 +36,44 @@ #include "utils.h" extern void attach_attrs(graph_t * g); +extern void attach_attrs_and_arrows(graph_t*, int*, int*); extern char *xml_string(char *str); extern void write_plain(GVJ_t * job, graph_t * g, FILE * f, bool extend); -extern void extend_attrs(GVJ_t * job, graph_t *g, agxbuf** xbufs); -extern void extend_attrs_glabel(graph_t *sg, agxbuf **xbufs); + +#define GNEW(t) (t*)malloc(sizeof(t)) typedef enum { FORMAT_DOT, FORMAT_CANON, FORMAT_PLAIN, FORMAT_PLAIN_EXT, FORMAT_XDOT } format_type; -static agxbuf xbuf0; -static agxbuf xbuf1; -static agxbuf xbuf2; -static agxbuf xbuf3; -static agxbuf xbuf4; -static agxbuf xbuf5; -static agxbuf* xbufs[6] = { - &xbuf0, &xbuf1, - &xbuf2, &xbuf3, - &xbuf4, &xbuf5, +#define XDOTVERSION "1.1" + +#define NUMXBUFS (EMIT_HLABEL+1) +/* There are as many xbufs as there are values of emit_state_t. + * However, only the first NUMXBUFS are distinct. Nodes, clusters, and + * edges are drawn atomically, so they share the DRAW and LABEL buffers + * are shared. + */ +static agxbuf xbuf[NUMXBUFS]; +static agxbuf* xbufs[] = { + xbuf+EMIT_GDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_TDRAW, xbuf+EMIT_HDRAW, + xbuf+EMIT_GLABEL, xbuf+EMIT_CLABEL, xbuf+EMIT_TLABEL, xbuf+EMIT_HLABEL, + xbuf+EMIT_CDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_CLABEL, xbuf+EMIT_CLABEL, }; +typedef struct { + attrsym_t *g_draw; + attrsym_t *g_l_draw; + attrsym_t *n_draw; + attrsym_t *n_l_draw; + attrsym_t *e_draw; + attrsym_t *h_draw; + attrsym_t *t_draw; + attrsym_t *e_l_draw; + attrsym_t *hl_draw; + attrsym_t *tl_draw; + unsigned char buf[NUMXBUFS][BUFSIZ]; +} xdot_state_t; +static xdot_state_t* xd; + static void xdot_str (GVJ_t *job, char* pfx, char* s) { emit_state_t emit_state = job->obj->emit_state; @@ -125,8 +144,113 @@ static void xdot_style (GVJ_t *job) agxbfree(&xbuf); } +static void xdot_end_node(GVJ_t* job) +{ + Agnode_t* n = job->obj->u.n; + if (agxblen(xbufs[EMIT_NDRAW])) + agxset(n, xd->n_draw->index, agxbuse(xbufs[EMIT_NDRAW])); + if (agxblen(xbufs[EMIT_NLABEL])) + agxset(n, xd->n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL])); +} + +static void xdot_end_edge(GVJ_t* job) +{ + Agedge_t* e = job->obj->u.e; + + if (agxblen(xbufs[EMIT_EDRAW])) + agxset(e, xd->e_draw->index, agxbuse(xbufs[EMIT_EDRAW])); + if (agxblen(xbufs[EMIT_TDRAW])) + agxset(e, xd->t_draw->index, agxbuse(xbufs[EMIT_TDRAW])); + if (agxblen(xbufs[EMIT_HDRAW])) + agxset(e, xd->h_draw->index, agxbuse(xbufs[EMIT_HDRAW])); + if (agxblen(xbufs[EMIT_ELABEL])) + agxset(e, xd->e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL])); + if (agxblen(xbufs[EMIT_TLABEL])) + agxset(e, xd->tl_draw->index, agxbuse(xbufs[EMIT_TLABEL])); + if (agxblen(xbufs[EMIT_HLABEL])) + agxset(e, xd->hl_draw->index, agxbuse(xbufs[EMIT_HLABEL])); +} + +static void xdot_end_cluster(GVJ_t * job) +{ + Agraph_t* cluster_g = job->obj->u.sg; + + agxset(cluster_g, xd->g_draw->index, agxbuse(xbufs[EMIT_CDRAW])); + if (GD_label(cluster_g)) + agxset(cluster_g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL])); +} + +/* + * John M. suggests: + * You might want to add four more: + * + * _ohdraw_ (optional head-end arrow for edges) + * _ohldraw_ (optional head-end label for edges) + * _otdraw_ (optional tail-end arrow for edges) + * _otldraw_ (optional tail-end label for edges) + * + * that would be generated when an additional option is supplied to + * dot, etc. and + * these would be the arrow/label positions to use if a user want to flip the + * direction of an edge (as sometimes is there want). + * + * N.B. John M. asks: + * By the way, I don't know if you ever plan to add other letters for + * the xdot spec, but could you reserve "a" and also "A" (for attribute), + * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string) + * and "t" (for tooltip) and "x" (for position). We use those letters in + * our drawing spec (and also "<" and ">"), so if you start generating + * output with them, it could break what we have. + */ +static void +xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows) +{ + int i; + + xd = GNEW(xdot_state_t); + + if (GD_has_labels(g) & GRAPH_LABEL) + xd->g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr); + else + xd->g_l_draw = NULL; + if (GD_n_cluster(g)) + xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); + else + xd->g_draw = NULL; + + xd->n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr); + xd->n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr); + + xd->e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr); + if (e_arrows) + xd->h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr); + else + xd->h_draw = NULL; + if (s_arrows) + xd->t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr); + else + xd->t_draw = NULL; + if (GD_has_labels(g) & EDGE_LABEL) + xd->e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr); + else + xd->e_l_draw = NULL; + if (GD_has_labels(g) & HEAD_LABEL) + xd->hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr); + else + xd->hl_draw = NULL; + if (GD_has_labels(g) & TAIL_LABEL) + xd->tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr); + else + xd->tl_draw = NULL; + + for (i = 0; i < NUMXBUFS; i++) + agxbinit(xbuf+i, BUFSIZ, xd->buf[i]); +} + static void dot_begin_graph(GVJ_t *job) { + int e_arrows; /* graph has edges with end arrows */ + int s_arrows; /* graph has edges with start arrows */ graph_t *g = job->obj->u.g; switch (job->render.id) { @@ -141,10 +265,29 @@ static void dot_begin_graph(GVJ_t *job) case FORMAT_PLAIN_EXT: break; case FORMAT_XDOT: - attach_attrs(g); + attach_attrs_and_arrows(g, &s_arrows, &e_arrows); + xdot_begin_graph(g, s_arrows, e_arrows); } } +static void xdot_end_graph(graph_t* g) +{ + int i; + + if (agxblen(xbufs[EMIT_GDRAW])) { + if (!xd->g_draw) + xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); + agxset(g, xd->g_draw->index, agxbuse(xbufs[EMIT_GDRAW])); + } + if (GD_label(g)) + agxset(g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL])); + agsafeset (g, "xdotversion", XDOTVERSION, ""); + + for (i = 0; i < NUMXBUFS; i++) + agxbfree(xbuf+i); + free (xd); +} + static void dot_end_graph(GVJ_t *job) { graph_t *g = job->obj->u.g; @@ -162,18 +305,13 @@ static void dot_end_graph(GVJ_t *job) agwrite(g, job->output_file); break; case FORMAT_XDOT: - extend_attrs(job, g, xbufs); + xdot_end_graph(g); if (!(job->flags & OUTPUT_NOT_REQUIRED)) agwrite(g, job->output_file); break; } } -static void xdot_end_cluster(GVJ_t *job) -{ - extend_attrs_glabel(job->obj->u.sg, xbufs); -} - static void xdot_textpara(GVJ_t * job, pointf p, textpara_t * para) { emit_state_t emit_state = job->obj->emit_state; @@ -301,9 +439,9 @@ gvrender_engine_t xdot_engine = { 0, /* xdot_begin_edges */ 0, /* xdot_end_edges */ 0, /* xdot_begin_node */ - 0, /* xdot_end_node */ + xdot_end_node, 0, /* xdot_begin_edge */ - 0, /* xdot_end_edge */ + xdot_end_edge, 0, /* xdot_begin_anchor */ 0, /* xdot_end_anchor */ xdot_textpara,