Graphviz  2.29.20120524.0446
lib/common/mpgen.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 /* mpgen.c 1999-Feb-23 Jim Hefferon jim@joshua.smcvt.edu 
00015  *  Adapted from psgen.c.  See 1st_read.mp.
00016  */
00017 #include "render.h"
00018 #ifndef WIN32
00019 #include <unistd.h>
00020 #endif
00021 #include <sys/stat.h>
00022 
00023 
00024 #define NONE    0
00025 #define NODE    1
00026 #define EDGE    2
00027 #define CLST    3
00028 
00029 /* static       point   Pages; */
00030 /* static       box             PB; */
00031 static int onetime = TRUE;
00032 
00033 static const char       **U_lib;
00034 
00035 typedef struct grcontext_t {
00036     char *color, *font;
00037     double size;
00038 } grcontext_t;
00039 
00040 #define STACKSIZE 32            /* essentially infinite? */
00041 static grcontext_t S[STACKSIZE];
00042 static int SP = 0;
00043 
00044 static void mp_reset(void)
00045 {
00046     onetime = TRUE;
00047 }
00048 
00049 /* mp_cat_libfile:
00050  * Write library files onto the given file pointer.
00051  * arglib is an NULL-terminated array of char*
00052  * Each non-trivial entry should be the name of a file to be included.
00053  * stdlib is an NULL-terminated array of char*
00054  * Each of these is a line of a standard library to be included.
00055  * If any item in arglib is the empty string, the stdlib is not used.
00056  * The stdlib is printed first, if used, followed by the user libraries.
00057  * We check that for web-safe file usage.
00058  */
00059 static void mp_cat_libfile(FILE * ofp, const char **arglib, const char **stdlib)
00060 {
00061     FILE *fp;
00062     const char **s, *bp, *p, *path;
00063     int i;
00064     boolean use_stdlib = TRUE;
00065 
00066     /* check for empty string to turn off stdlib */
00067     if (arglib) {
00068         for (i = 0; use_stdlib && ((p = arglib[i])); i++) {
00069             if (*p == '\0')
00070                 use_stdlib = FALSE;
00071         }
00072     }
00073     if (use_stdlib)
00074         for (s = stdlib; *s; s++) {
00075             fputs(*s, ofp);
00076             fputc('\n', ofp);
00077         }
00078     if (arglib) {
00079         for (i = 0; (p = arglib[i]) != 0; i++) {
00080             if (*p == '\0')
00081                 continue;       /* ignore empty string */
00082             path = safefile(p); /* make sure filename is okay */
00083             if (!path) {
00084                 agerr(AGWARN, "can't find library file %s\n", p);
00085             }
00086             else if ((fp = fopen(path, "r"))) {
00087                 while ((bp = Fgets(fp)))
00088                     fputs(bp, ofp);
00089                 fputc('\n', ofp); /* append a newline just in case */
00090                 fclose (fp);
00091             } else
00092                 agerr(AGWARN, "can't open library file %s\n", path);
00093         }
00094     }
00095 }
00096 
00097 static void
00098 mp_begin_job(FILE * ofp, graph_t * g, const char **lib, char *info[], point pages)
00099 {
00100     /* pages and libraries not here (yet?) */
00101     /* Pages = pages; */
00102     U_lib = lib;
00103     /* N_pages = pages.x * pages.y; */
00104     /* Cur_page = 0; */
00105 
00106     fprintf(Output_file, "%%--- graphviz MetaPost input\n");
00107     fprintf(Output_file, "%% Created by program: %s version %s (%s)\n",
00108             info[0], info[1], info[2]);
00109     fprintf(Output_file, "%% Title: %s\n", agnameof(g));
00110     fprintf(Output_file,
00111             "%%  Put this between beginfig and endfig.  See 1st_read.mp.\n");
00112     fprintf(Output_file, "%% \n");
00113 }
00114 
00115 static void mp_end_job(void)
00116 {
00117     fprintf(Output_file, "%%  End of graphviz MetaPost input\n");
00118     fprintf(Output_file, "%%  \n");
00119 }
00120 
00121 static void mp_comment(char *str)
00122 {
00123     fprintf(Output_file, "%% %s\n", str);
00124 }
00125 
00126 static void mp_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb)
00127 {
00128     /* PB = bb; */
00129     static const char *mp_lib[] = {0};
00130     if (onetime) {
00131         fprintf(Output_file, "%% BoundingBox: %d %d %d %d\n",
00132                 bb.LL.x, bb.LL.y, bb.UR.x + 1, bb.UR.y + 1);
00133                 mp_cat_libfile(Output_file,U_lib,mp_lib);
00134         onetime = FALSE;
00135     }
00136 }
00137 
00138 static void
00139 mp_begin_page(graph_t * g, point page, double scale, int rot, point offset)
00140 {
00141     assert(SP == 0);
00142     S[SP].font = "";
00143     S[SP].color = "black";
00144     S[SP].size = 0.0;
00145 }
00146 
00147 static void mp_begin_context(void)
00148 {
00149     if (SP == STACKSIZE - 1)
00150         agerr(AGWARN, "mpgen stack overflow\n");
00151     else {
00152         SP++;
00153         S[SP] = S[SP - 1];
00154     }
00155 }
00156 
00157 static void mp_end_context(void)
00158 {
00159     if (SP == 0)
00160         agerr(AGWARN, "mpgen stack underflow\n");
00161     else
00162         SP--;
00163 }
00164 
00165 static void mp_set_font(char *name, double size)
00166 {
00167     if (strcmp(S[SP].font, name) || (size != S[SP].size)) {
00168         fprintf(Output_file, "%% GV set font: %.2f /%s ignored\n", size,
00169                 name);
00170         S[SP].font = name;
00171         S[SP].size = size;
00172     }
00173 }
00174 
00175 static void mp_set_color(char *name)
00176 {
00177     static char *op[] = { "graph", "node", "edge", "sethsb" };
00178     gvcolor_t color;
00179 
00180     if (strcmp(name, S[SP].color)) {
00181         colorxlate(name, &color, HSVA_DOUBLE);
00182         fprintf(Output_file, "%% GV set color: %.3f %.3f %.3f %scolor\n",
00183                 color.u.HSVA[0], color.u.HSVA[1], color.u.HSVA[2], op[Obj]);
00184     }
00185     S[SP].color = name;
00186 }
00187 
00188 static void mp_set_style(char **s)
00189 {
00190     char *line, *p;
00191 
00192     while ((p = line = *s++)) {
00193         while (*p)
00194             p++;
00195         p++;
00196         while (*p) {
00197             fprintf(Output_file, "%% GV set style: %s \n", p);
00198             while (*p)
00199                 p++;
00200             p++;
00201         }
00202         fprintf(Output_file, "%% GV set style:: %s\n", line);
00203     }
00204 }
00205 
00206 static char *mp_string(char *s)
00207 {
00208     static char *buf = NULL;
00209     static int bufsize = 0;
00210     int pos = 0;
00211     char *p;
00212 
00213     if (!buf) {
00214         bufsize = 64;
00215         buf = N_GNEW(bufsize, char);
00216     }
00217 
00218     p = buf;
00219     while (*s) {
00220         if (pos > (bufsize - 8)) {
00221             bufsize *= 2;
00222             buf = grealloc(buf, bufsize);
00223             p = buf + pos;
00224         }
00225         if ((*s == LPAREN) || (*s == RPAREN)) {
00226             *p++ = '\\';
00227             pos++;
00228         }
00229         *p++ = *s++;
00230         pos++;
00231     }
00232     *p = '\0';
00233     return buf;
00234 }
00235 
00236 static void mp_textpara(point p, textpara_t * para)
00237 {
00238     fprintf(Output_file, "label(btex %s etex,(%dbp,%dbp)) withcolor %s;\n",
00239             mp_string(para->str), p.x, p.y, S[SP].color);
00240 }
00241 
00242 static void
00243 mp_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled)
00244 {
00245     int j;
00246     if (arrow_at_start || arrow_at_end)
00247         agerr(AGERR, "mp_bezier illegal arrow args\n");
00248     fprintf(Output_file, "draw (%dbp,%dbp) ", A[0].x, A[0].y);
00249     for (j = 1; j < n; j += 3)
00250         fprintf(Output_file,
00251                 "\n  ..controls (%dbp,%dbp) and (%dbp,%dbp).. (%dbp,%dbp)",
00252                 A[j].x, A[j].y, A[j + 1].x, A[j + 1].y, A[j + 2].x,
00253                 A[j + 2].y);
00254     fprintf(Output_file, " withcolor %s;\n", S[SP].color);
00255 }
00256 
00257 static void mp_polygon(point * A, int n, int filled)
00258 {
00259     int j;
00260     if (filled) {
00261         fprintf(Output_file, "  fill (%dbp,%dbp)", A[0].x, A[0].y);
00262         for (j = 1; j < n; j++)
00263             fprintf(Output_file, "\n  --(%dbp,%dbp)", A[j].x, A[j].y);
00264         fprintf(Output_file, "\n  --cycle withcolor %s;\n", S[SP].color);
00265     }
00266     fprintf(Output_file, "draw (%dbp,%dbp)  ", A[0].x, A[0].y);
00267     for (j = 1; j < n; j++)
00268         fprintf(Output_file, "\n  --(%dbp,%dbp)", A[j].x, A[j].y);
00269     fprintf(Output_file, "\n  --cycle withcolor %s;\n", S[SP].color);
00270 }
00271 
00272 static void mp_ellipse(point p, int rx, int ry, int filled)
00273 {
00274     if (filled)
00275         fprintf(Output_file,
00276                 "  fill fullcircle xscaled %dbp yscaled %dbp shifted (%dbp,%dbp) withcolor %s;\n",
00277                 2 * rx, 2 * ry, p.x, p.y, S[SP].color);
00278     fprintf(Output_file,
00279             "draw fullcircle xscaled %dbp yscaled %dbp shifted (%dbp,%dbp);\n",
00280             2 * rx, 2 * ry, p.x, p.y);
00281 }
00282 
00283 static void mp_polyline(point * A, int n)
00284 {
00285     int j;
00286 
00287     fprintf(Output_file, "draw (%dbp,%dbp) ", A[0].x, A[0].y);
00288     for (j = 1; j < n; j++)
00289         fprintf(Output_file, "\n  --(%dbp,%dbp)", A[j].x, A[j].y);
00290     fprintf(Output_file, " withcolor %s;\n", S[SP].color);
00291 }
00292 
00293 static void mp_usershape(usershape_t *us, boxf b, point *A, int n, boolean filled)
00294 {
00295     int j;
00296     fprintf(Output_file, "%%GV USER SHAPE [ ");
00297     for (j = 0; j < n; j++)
00298         fprintf(Output_file, "%d %d ", A[j].x, A[j].y);
00299     fprintf(Output_file, "%d %d ", A[0].x, A[0].y);
00300     fprintf(Output_file, "]  %d %s %s ignored\n", n,
00301             (filled ? "true" : "false"), us->name);
00302 }
00303 
00304 codegen_t MP_CodeGen = {
00305     mp_reset,
00306     mp_begin_job, mp_end_job,
00307     mp_begin_graph, 0,          /* mp_end_graph */
00308     mp_begin_page, 0,           /* mp_end_page */
00309     0, /* mp_begin_layer */ 0,  /* mp_end_layer */
00310     0, /* mp_begin_cluster */ 0,        /* mp_end_cluster */
00311     0, /* mp_begin_nodes */ 0,  /* mp_end_nodes */
00312     0, /* mp_begin_edges */ 0,  /* mp_end_edges */
00313     0, /* mp_begin_node */  0,  /* mp_end_node */
00314     0, /* mp_begin_edge */  0,  /* mp_end_edge */
00315     mp_begin_context, mp_end_context,
00316     0, /* mp_begin_anchor */ 0, /* mp_end_anchor */
00317     mp_set_font, mp_textpara,
00318     mp_set_color, mp_set_color, mp_set_style,
00319     mp_ellipse, mp_polygon,
00320     mp_bezier, mp_polyline,
00321     0,                          /* bezier_has_arrows */
00322     mp_comment,
00323     mp_usershape
00324 };