of bugs on the way.
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;
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)) {
#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)
{
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,
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 */
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]));
- }
-}
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 *);
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)
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;
#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;
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) {
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;
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;
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,