/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/plugin/core/gvrender_core_dot.c

Go to the documentation of this file.
00001 /* $Id: gvrender_core_dot.c,v 1.19 2007/09/14 16:31:39 ellson Exp $ $Revision: 1.19 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #ifdef WIN32
00022 #include <io.h>
00023 #include "compat.h"
00024 #endif
00025 
00026 #include <stdarg.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 
00030 #include "macros.h"
00031 #include "const.h"
00032 
00033 #include "gvplugin_render.h"
00034 #include "graph.h"
00035 #include "agxbuf.h"
00036 #include "utils.h"
00037 
00038 extern void attach_attrs(graph_t * g);
00039 extern void attach_attrs_and_arrows(graph_t*, int*, int*);
00040 extern char *xml_string(char *str);
00041 extern void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend);
00042 extern void output_point(agxbuf *xbuf, pointf p);
00043 
00044 #define GNEW(t)          (t*)malloc(sizeof(t))
00045 
00046 typedef enum {
00047         FORMAT_DOT,
00048         FORMAT_CANON,
00049         FORMAT_PLAIN,
00050         FORMAT_PLAIN_EXT,
00051         FORMAT_XDOT
00052 } format_type;
00053 
00054 
00055 #define XDOTVERSION "1.2"
00056 
00057 #define NUMXBUFS (EMIT_HLABEL+1)
00058 /* There are as many xbufs as there are values of emit_state_t.
00059  * However, only the first NUMXBUFS are distinct. Nodes, clusters, and
00060  * edges are drawn atomically, so they share the DRAW and LABEL buffers
00061  * are shared.
00062  */
00063 static agxbuf xbuf[NUMXBUFS];
00064 static agxbuf* xbufs[] = {
00065     xbuf+EMIT_GDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_TDRAW, xbuf+EMIT_HDRAW, 
00066     xbuf+EMIT_GLABEL, xbuf+EMIT_CLABEL, xbuf+EMIT_TLABEL, xbuf+EMIT_HLABEL, 
00067     xbuf+EMIT_CDRAW, xbuf+EMIT_CDRAW, xbuf+EMIT_CLABEL, xbuf+EMIT_CLABEL, 
00068 };
00069 
00070 typedef struct {
00071     attrsym_t *g_draw;
00072     attrsym_t *g_l_draw;
00073     attrsym_t *n_draw;
00074     attrsym_t *n_l_draw;
00075     attrsym_t *e_draw;
00076     attrsym_t *h_draw;
00077     attrsym_t *t_draw;
00078     attrsym_t *e_l_draw;
00079     attrsym_t *hl_draw;
00080     attrsym_t *tl_draw;
00081     unsigned char buf[NUMXBUFS][BUFSIZ];
00082 } xdot_state_t;
00083 static xdot_state_t* xd;
00084 
00085 static void xdot_str (GVJ_t *job, char* pfx, char* s)
00086 {   
00087     emit_state_t emit_state = job->obj->emit_state;
00088     char buf[BUFSIZ];
00089     
00090     sprintf (buf, "%s%d -", pfx, (int)strlen(s));
00091     agxbput(xbufs[emit_state], buf);
00092     agxbput(xbufs[emit_state], s);
00093     agxbputc(xbufs[emit_state], ' ');
00094 }
00095 
00096 static void xdot_points(GVJ_t *job, char c, pointf * A, int n)
00097 {
00098     emit_state_t emit_state = job->obj->emit_state;
00099     char buf[BUFSIZ];
00100     int i, rc;
00101 
00102     rc = agxbputc(xbufs[emit_state], c);
00103     sprintf(buf, " %d ", n);
00104     agxbput(xbufs[emit_state], buf);
00105     for (i = 0; i < n; i++)
00106         output_point(xbufs[emit_state], A[i]);
00107 }
00108 
00109 static void xdot_pencolor (GVJ_t *job)
00110 {
00111     xdot_str (job, "c ", job->obj->pencolor.u.string);
00112 }
00113 
00114 static void xdot_fillcolor (GVJ_t *job)
00115 {
00116     xdot_str (job, "C ", job->obj->fillcolor.u.string);
00117 }
00118 
00119 static void xdot_style (GVJ_t *job)
00120 {
00121     unsigned char buf[BUFSIZ];
00122     agxbuf xbuf;
00123     char* p, **s;
00124     int more;
00125 
00126     s = job->obj->rawstyle;
00127     if (!s)
00128         return;
00129     agxbinit(&xbuf, BUFSIZ, buf);
00130     while ((p = *s++)) {
00131         agxbput(&xbuf, p);
00132         while (*p)
00133             p++;
00134         p++;
00135         if (*p) {  /* arguments */
00136             agxbputc(&xbuf, '(');
00137             more = 0;
00138             while (*p) {
00139                 if (more)
00140                     agxbputc(&xbuf, ',');
00141                 agxbput(&xbuf, p);
00142                 while (*p) p++;
00143                 p++;
00144                 more++;
00145             }
00146             agxbputc(&xbuf, ')');
00147         }
00148         xdot_str (job, "S ", agxbuse(&xbuf));
00149     }
00150     agxbfree(&xbuf);
00151 }
00152 
00153 static void xdot_end_node(GVJ_t* job)
00154 {
00155     Agnode_t* n = job->obj->u.n; 
00156     if (agxblen(xbufs[EMIT_NDRAW]))
00157         agxset(n, xd->n_draw->index, agxbuse(xbufs[EMIT_NDRAW]));
00158     if (agxblen(xbufs[EMIT_NLABEL]))
00159         agxset(n, xd->n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL]));
00160 }
00161 
00162 static void xdot_end_edge(GVJ_t* job)
00163 {
00164     Agedge_t* e = job->obj->u.e; 
00165 
00166     if (agxblen(xbufs[EMIT_EDRAW]))
00167         agxset(e, xd->e_draw->index, agxbuse(xbufs[EMIT_EDRAW]));
00168     if (agxblen(xbufs[EMIT_TDRAW]))
00169         agxset(e, xd->t_draw->index, agxbuse(xbufs[EMIT_TDRAW]));
00170     if (agxblen(xbufs[EMIT_HDRAW]))
00171         agxset(e, xd->h_draw->index, agxbuse(xbufs[EMIT_HDRAW]));
00172     if (agxblen(xbufs[EMIT_ELABEL]))
00173         agxset(e, xd->e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL]));
00174     if (agxblen(xbufs[EMIT_TLABEL]))
00175         agxset(e, xd->tl_draw->index, agxbuse(xbufs[EMIT_TLABEL]));
00176     if (agxblen(xbufs[EMIT_HLABEL]))
00177         agxset(e, xd->hl_draw->index, agxbuse(xbufs[EMIT_HLABEL]));
00178 }
00179 
00180 static void xdot_end_cluster(GVJ_t * job)
00181 {
00182     Agraph_t* cluster_g = job->obj->u.sg;
00183 
00184     agxset(cluster_g, xd->g_draw->index, agxbuse(xbufs[EMIT_CDRAW]));
00185     if (GD_label(cluster_g))
00186         agxset(cluster_g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_CLABEL]));
00187 }
00188 
00189 /* 
00190  * John M. suggests:
00191  * You might want to add four more:
00192  *
00193  * _ohdraw_ (optional head-end arrow for edges)
00194  * _ohldraw_ (optional head-end label for edges)
00195  * _otdraw_ (optional tail-end arrow for edges)
00196  * _otldraw_ (optional tail-end label for edges)
00197  * 
00198  * that would be generated when an additional option is supplied to 
00199  * dot, etc. and 
00200  * these would be the arrow/label positions to use if a user want to flip the 
00201  * direction of an edge (as sometimes is there want).
00202  * 
00203  * N.B. John M. asks:
00204  *   By the way, I don't know if you ever plan to add other letters for 
00205  * the xdot spec, but could you reserve "a" and also "A" (for  attribute), 
00206  * "n" and also "N" (for numeric), "w" (for sWitch),  "s" (for string) 
00207  * and "t" (for tooltip) and "x" (for position). We use  those letters in 
00208  * our drawing spec (and also "<" and ">"), so if you  start generating 
00209  * output with them, it could break what we have. 
00210  */
00211 static void
00212 xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows)
00213 {
00214     int i;
00215 
00216     xd = GNEW(xdot_state_t);
00217 
00218     if (GD_has_labels(g) & GRAPH_LABEL)
00219         xd->g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr);
00220     else
00221         xd->g_l_draw = NULL;
00222     if (GD_n_cluster(g))
00223         xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
00224     else
00225         xd->g_draw = NULL;
00226 
00227     xd->n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr);
00228     xd->n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr);
00229 
00230     xd->e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr);
00231     if (e_arrows)
00232         xd->h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr);
00233     else
00234         xd->h_draw = NULL;
00235     if (s_arrows)
00236         xd->t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr);
00237     else
00238         xd->t_draw = NULL;
00239     if (GD_has_labels(g) & EDGE_LABEL)
00240         xd->e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr);
00241     else
00242         xd->e_l_draw = NULL;
00243     if (GD_has_labels(g) & HEAD_LABEL)
00244         xd->hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr);
00245     else
00246         xd->hl_draw = NULL;
00247     if (GD_has_labels(g) & TAIL_LABEL)
00248         xd->tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr);
00249     else
00250         xd->tl_draw = NULL;
00251 
00252     for (i = 0; i < NUMXBUFS; i++)
00253         agxbinit(xbuf+i, BUFSIZ, xd->buf[i]);
00254 }
00255 
00256 static void dot_begin_graph(GVJ_t *job)
00257 {
00258     int e_arrows;            /* graph has edges with end arrows */
00259     int s_arrows;            /* graph has edges with start arrows */
00260     graph_t *g = job->obj->u.g;
00261 
00262     switch (job->render.id) {
00263         case FORMAT_DOT:
00264             attach_attrs(g);
00265             break;
00266         case FORMAT_CANON:
00267             if (HAS_CLUST_EDGE(g))
00268                 undoClusterEdges(g);
00269             break;
00270         case FORMAT_PLAIN:
00271         case FORMAT_PLAIN_EXT:
00272             break;
00273         case FORMAT_XDOT:
00274             attach_attrs_and_arrows(g, &s_arrows, &e_arrows);
00275             xdot_begin_graph(g, s_arrows, e_arrows);
00276     }
00277 }
00278 
00279 static void xdot_end_graph(graph_t* g)
00280 {
00281     int i;
00282 
00283     if (agxblen(xbufs[EMIT_GDRAW])) {
00284         if (!xd->g_draw)
00285             xd->g_draw = safe_dcl(g, g, "_draw_", "", agraphattr);
00286         agxset(g, xd->g_draw->index, agxbuse(xbufs[EMIT_GDRAW]));
00287     }
00288     if (GD_label(g))
00289         agxset(g, xd->g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL]));
00290     agsafeset (g, "xdotversion", XDOTVERSION, "");
00291 
00292     for (i = 0; i < NUMXBUFS; i++)
00293         agxbfree(xbuf+i);
00294     free (xd);
00295 }
00296 
00297 static void dot_end_graph(GVJ_t *job)
00298 {
00299     graph_t *g = job->obj->u.g;
00300 
00301     switch (job->render.id) {
00302         case FORMAT_PLAIN:
00303             write_plain(job, g, job->output_file, FALSE);
00304             break;
00305         case FORMAT_PLAIN_EXT:
00306             write_plain(job, g, job->output_file, TRUE);
00307             break;
00308         case FORMAT_DOT:
00309         case FORMAT_CANON:
00310             if (!(job->flags & OUTPUT_NOT_REQUIRED))
00311                 agwrite(g, job->output_file);
00312             break;
00313         case FORMAT_XDOT:
00314             xdot_end_graph(g);
00315             if (!(job->flags & OUTPUT_NOT_REQUIRED))
00316                 agwrite(g, job->output_file);
00317             break;
00318     }
00319 }
00320 
00321 static void xdot_textpara(GVJ_t * job, pointf p, textpara_t * para)
00322 {
00323     emit_state_t emit_state = job->obj->emit_state;
00324 
00325     char buf[BUFSIZ];
00326     int j;
00327     
00328     sprintf(buf, "F %f ", para->fontsize);
00329     agxbput(xbufs[emit_state], buf);
00330     xdot_str (job, "", para->fontname);
00331     xdot_pencolor(job);
00332 
00333     switch (para->just) {
00334     case 'l':
00335         j = -1; 
00336         break;
00337     case 'r':
00338         j = 1;
00339         break;
00340     default:
00341     case 'n':
00342         j = 0;
00343         break;
00344     }
00345     agxbput(xbufs[emit_state], "T ");
00346     output_point(xbufs[emit_state], p);
00347     sprintf(buf, "%d %d ", j, (int) para->width);
00348     agxbput(xbufs[emit_state], buf);
00349     xdot_str (job, "", para->str);
00350 }
00351 
00352 static void xdot_ellipse(GVJ_t * job, pointf * A, int filled)
00353 {
00354     emit_state_t emit_state = job->obj->emit_state;
00355 
00356     char buf[BUFSIZ];
00357 
00358     xdot_style (job);
00359     xdot_pencolor (job);
00360     if (filled) {
00361         xdot_fillcolor (job);
00362         agxbput(xbufs[emit_state], "E ");
00363     }
00364     else
00365         agxbput(xbufs[emit_state], "e ");
00366     output_point(xbufs[emit_state], A[0]);
00367     sprintf(buf, "%d %d ", ROUND(A[1].x - A[0].x), ROUND(A[1].y - A[0].y));
00368     agxbput(xbufs[emit_state], buf);
00369 }
00370 
00371 static void xdot_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start, int arrow_at_end, int filled)
00372 {
00373     xdot_style (job);
00374     xdot_pencolor (job);
00375     if (filled) {
00376         xdot_fillcolor (job);
00377         xdot_points(job, 'b', A, n);   /* NB - 'B' & 'b' are reversed in comparison to the other items */
00378     }
00379     else
00380         xdot_points(job, 'B', A, n);
00381 }
00382 
00383 static void xdot_polygon(GVJ_t * job, pointf * A, int n, int filled)
00384 {
00385     xdot_style (job);
00386     xdot_pencolor (job);
00387     if (filled) {
00388         xdot_fillcolor (job);
00389         xdot_points(job, 'P', A, n);
00390     }
00391     else
00392         xdot_points(job, 'p', A, n);
00393 }
00394 
00395 static void xdot_polyline(GVJ_t * job, pointf * A, int n)
00396 {
00397     xdot_style (job);
00398     xdot_pencolor (job);
00399     xdot_points(job, 'L', A, n);
00400 }
00401 
00402 void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
00403 {
00404     emit_state_t emit_state = job->obj->emit_state;
00405     char buf[BUFSIZ];
00406     
00407     agxbput(xbufs[emit_state], "I ");
00408     output_point(xbufs[emit_state], b.LL);
00409     sprintf(buf, "%d %d ", ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y));
00410     agxbput(xbufs[emit_state], buf);
00411     xdot_str (job, "", us->name);
00412 }
00413 
00414 gvrender_engine_t dot_engine = {
00415     0,                          /* dot_begin_job */
00416     0,                          /* dot_end_job */
00417     dot_begin_graph,
00418     dot_end_graph,
00419     0,                          /* dot_begin_layer */
00420     0,                          /* dot_end_layer */
00421     0,                          /* dot_begin_page */
00422     0,                          /* dot_end_page */
00423     0,                          /* dot_begin_cluster */
00424     0,                          /* dot_end_cluster */
00425     0,                          /* dot_begin_nodes */
00426     0,                          /* dot_end_nodes */
00427     0,                          /* dot_begin_edges */
00428     0,                          /* dot_end_edges */
00429     0,                          /* dot_begin_node */
00430     0,                          /* dot_end_node */
00431     0,                          /* dot_begin_edge */
00432     0,                          /* dot_end_edge */
00433     0,                          /* dot_begin_anchor */
00434     0,                          /* dot_end_anchor */
00435     0,                          /* dot_textpara */
00436     0,                          /* dot_resolve_color */
00437     0,                          /* dot_ellipse */
00438     0,                          /* dot_polygon */
00439     0,                          /* dot_bezier */
00440     0,                          /* dot_polyline */
00441     0,                          /* dot_comment */
00442     0,                          /* dot_library_shape */
00443 };
00444 
00445 gvrender_engine_t xdot_engine = {
00446     0,                          /* xdot_begin_job */
00447     0,                          /* xdot_end_job */
00448     dot_begin_graph,
00449     dot_end_graph,
00450     0,                          /* xdot_begin_layer */
00451     0,                          /* xdot_end_layer */
00452     0,                          /* xdot_begin_page */
00453     0,                          /* xdot_end_page */
00454     0,                          /* xdot_begin_cluster */
00455     xdot_end_cluster,
00456     0,                          /* xdot_begin_nodes */
00457     0,                          /* xdot_end_nodes */
00458     0,                          /* xdot_begin_edges */
00459     0,                          /* xdot_end_edges */
00460     0,                          /* xdot_begin_node */
00461     xdot_end_node,
00462     0,                          /* xdot_begin_edge */
00463     xdot_end_edge,
00464     0,                          /* xdot_begin_anchor */
00465     0,                          /* xdot_end_anchor */
00466     xdot_textpara,
00467     0,                          /* xdot_resolve_color */
00468     xdot_ellipse,
00469     xdot_polygon,
00470     xdot_bezier,
00471     xdot_polyline,
00472     0,                          /* xdot_comment */
00473     0,                          /* xdot_library_shape */
00474 };
00475 
00476 gvrender_features_t render_features_dot = {
00477     GVRENDER_DOES_TRANSFORM,    /* not really - uses raw graph coords */  /* flags */
00478     0.,                         /* default pad - graph units */
00479     NULL,                       /* knowncolors */
00480     0,                          /* sizeof knowncolors */
00481     COLOR_STRING,               /* color_type */
00482 };
00483 
00484 gvrender_features_t render_features_xdot = {
00485     GVRENDER_DOES_TRANSFORM,    /* not really - uses raw graph coords */  /* flags */
00486     0.,                         /* default pad - graph units */
00487     NULL,                       /* knowncolors */
00488     0,                          /* sizeof knowncolors */
00489     COLOR_STRING,               /* color_type */
00490 };
00491 
00492 gvdevice_features_t device_features_canon = {
00493     LAYOUT_NOT_REQUIRED,        /* flags */
00494     {0.,0.},                    /* default margin - points */
00495     {0.,0.},                    /* default height, width - device units */
00496     {72.,72.},                  /* default dpi */
00497 };
00498 
00499 gvdevice_features_t device_features_dot = {
00500     0,                          /* flags */
00501     {0.,0.},                    /* default margin - points */
00502     {0.,0.},                    /* default page width, height - points */
00503     {72.,72.},                  /* default dpi */
00504 };
00505 
00506 gvplugin_installed_t gvrender_dot_types[] = {
00507     {FORMAT_DOT, "dot", 1, &dot_engine, &render_features_dot},
00508     {FORMAT_XDOT, "xdot", 1, &xdot_engine, &render_features_xdot},
00509     {0, NULL, 0, NULL, NULL}
00510 };
00511 
00512 gvplugin_installed_t gvdevice_dot_types[] = {
00513     {FORMAT_DOT, "dot:dot", 1, NULL, &device_features_dot},
00514     {FORMAT_CANON, "canon:dot", 1, NULL, &device_features_canon},
00515     {FORMAT_PLAIN, "plain:dot", 1, NULL, &device_features_dot},
00516     {FORMAT_PLAIN_EXT, "plain-ext:dot", 1, NULL, &device_features_dot},
00517     {FORMAT_XDOT, "xdot:xdot", 1, NULL, &device_features_dot},
00518     {0, NULL, 0, NULL, NULL}
00519 };

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1