00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00059
00060
00061
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) {
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
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
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;
00259 int s_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);
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,
00416 0,
00417 dot_begin_graph,
00418 dot_end_graph,
00419 0,
00420 0,
00421 0,
00422 0,
00423 0,
00424 0,
00425 0,
00426 0,
00427 0,
00428 0,
00429 0,
00430 0,
00431 0,
00432 0,
00433 0,
00434 0,
00435 0,
00436 0,
00437 0,
00438 0,
00439 0,
00440 0,
00441 0,
00442 0,
00443 };
00444
00445 gvrender_engine_t xdot_engine = {
00446 0,
00447 0,
00448 dot_begin_graph,
00449 dot_end_graph,
00450 0,
00451 0,
00452 0,
00453 0,
00454 0,
00455 xdot_end_cluster,
00456 0,
00457 0,
00458 0,
00459 0,
00460 0,
00461 xdot_end_node,
00462 0,
00463 xdot_end_edge,
00464 0,
00465 0,
00466 xdot_textpara,
00467 0,
00468 xdot_ellipse,
00469 xdot_polygon,
00470 xdot_bezier,
00471 xdot_polyline,
00472 0,
00473 0,
00474 };
00475
00476 gvrender_features_t render_features_dot = {
00477 GVRENDER_DOES_TRANSFORM,
00478 0.,
00479 NULL,
00480 0,
00481 COLOR_STRING,
00482 };
00483
00484 gvrender_features_t render_features_xdot = {
00485 GVRENDER_DOES_TRANSFORM,
00486 0.,
00487 NULL,
00488 0,
00489 COLOR_STRING,
00490 };
00491
00492 gvdevice_features_t device_features_canon = {
00493 LAYOUT_NOT_REQUIRED,
00494 {0.,0.},
00495 {0.,0.},
00496 {72.,72.},
00497 };
00498
00499 gvdevice_features_t device_features_dot = {
00500 0,
00501 {0.,0.},
00502 {0.,0.},
00503 {72.,72.},
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 };