Graphviz  2.35.20130930.0449
mifgen.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 
15 #include "render.h"
16 
17 #define NONE 0
18 #define NODE 1
19 #define EDGE 2
20 #define CLST 3
21 
22 /* MIF font modifiers */
23 #define REGULAR 0
24 #define BOLD 1
25 #define ITALIC 2
26 
27 /* MIF patterns */
28 #define P_SOLID 0
29 #define P_NONE 15
30 #define P_DOTTED 4 /* i wasn't sure about this */
31 #define P_DASHED 11 /* or this */
32 
33 /* MIF bold line constant */
34 #define WIDTH_NORMAL 1
35 #define WIDTH_BOLD 3
36 
37 static int N_pages;
38 /* static point Pages; */
39 static double Scale;
40 static int Rot;
41 static box PB;
42 static int onetime = TRUE;
43 
44 typedef struct context_t {
47  double fontsz;
48 } context_t;
49 
50 #define MAXNEST 4
51 static context_t cstk[MAXNEST];
52 static int SP;
53 
54 static char *FillStr = "<Fill 3>";
55 static char *NoFillStr = "<Fill 15>";
56 
57 static void mif_reset(void)
58 {
59  onetime = TRUE;
60 }
61 
62 
63 static void init_mif(void)
64 {
65  SP = 0;
66  cstk[0].color_ix = 0; /* MIF color index 0-7 */
67  cstk[0].fontfam = "Times"; /* font family name */
68  cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */
69  cstk[0].pen = P_SOLID; /* pen pattern style, default is solid */
70  cstk[0].fill = P_NONE;
71  cstk[0].penwidth = WIDTH_NORMAL;
72 }
73 
74 static pointf mifpt(pointf p)
75 {
76  pointf tmp, rv;
77  tmp.x = p.x * Scale;
78  tmp.y = Scale * p.y;
79  if (Rot == 0) {
80  rv.x = tmp.x;
81  rv.y = PB.UR.y - PB.LL.y - tmp.y;
82  } else {
83  rv.x = PB.UR.x - PB.LL.x - tmp.y;
84  rv.y = tmp.x;
85  }
86  return rv;
87 }
88 
89 static void mifptarray(point * A, int n)
90 {
91  int i;
92  pointf p;
93 
94  fprintf(Output_file, " <NumPoints %d>\n", n);
95  for (i = 0; i < n; i++) {
96  p.x = A[i].x;
97  p.y = A[i].y;
98  p = mifpt(p);
99  fprintf(Output_file, " <Point %.2f %.2f>\n", p.x, p.y);
100  }
101 }
102 
103 static void mif_font(context_t * cp)
104 {
105  char *fw, *fa;
106 
107  fw = fa = "Regular";
108  switch (cp->fontopt) {
109  case BOLD:
110  fw = "Bold";
111  break;
112  case ITALIC:
113  fa = "Italic";
114  break;
115  }
116  fprintf(Output_file,
117  "<Font <FFamily `%s'> <FSize %.1f pt> <FWeight %s> <FAngle %s>>\n",
118  cp->fontfam, Scale * cp->fontsz, fw, fa);
119 }
120 
121 static void mif_color(int i)
122 {
123  static char *mifcolor[] = {
124  "black", "white", "red", "green", "blue", "cyan",
125  "magenta", "yellow", "comment",
126  "aquamarine", "plum", "peru", "pink", "mediumpurple", "grey",
127  "lightgrey", "lightskyblue", "lightcoral", "yellowgreen",
128  (char *) 0
129  };
130  if (i <= 8)
131  fprintf(Output_file, "<Separation %d>\n", i);
132  if (i > 8)
133  fprintf(Output_file, "<ObColor `%s'>\n", mifcolor[i]);
134 }
135 
136 static void mif_style(context_t * cp)
137 {
138  fprintf(Output_file, "<Pen %d> <Fill %d> <PenWidth %d>\n",
139  cp->pen, cp->fill, cp->penwidth);
140 }
141 
142 static void mif_comment(char *str)
143 {
144  fprintf(Output_file, "# %s\n", str);
145 }
146 
147 static void
148 mif_begin_job(FILE * ofp, graph_t * g, const char **lib, char *info[], point pages)
149 {
150  /* Pages = pages; */
151  N_pages = pages.x * pages.y;
152  fprintf(Output_file,
153  "<MIFFile 3.00> # Generated by %s version %s (%s)\n", info[0],
154  info[1], info[2]);
155  fprintf(Output_file, "# Title: %s\n", agnameof(g));
156  fprintf(Output_file, "# Pages: %d\n", N_pages);
157  fprintf(Output_file, "<Units Upt>\n");
158  fprintf(Output_file, "<ColorCatalog \n");
159  fprintf(Output_file, " <Color \n");
160  fprintf(Output_file, " <ColorTag `Black'>\n");
161  fprintf(Output_file, " <ColorCyan 0.000000>\n");
162  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
163  fprintf(Output_file, " <ColorYellow 0.000000>\n");
164  fprintf(Output_file, " <ColorBlack 100.000000>\n");
165  fprintf(Output_file, " <ColorAttribute ColorIsBlack>\n");
166  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
167  fprintf(Output_file, " > # end of Color\n");
168  fprintf(Output_file, " <Color \n");
169  fprintf(Output_file, " <ColorTag `White'>\n");
170  fprintf(Output_file, " <ColorCyan 0.000000>\n");
171  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
172  fprintf(Output_file, " <ColorYellow 0.000000>\n");
173  fprintf(Output_file, " <ColorBlack 0.000000>\n");
174  fprintf(Output_file, " <ColorAttribute ColorIsWhite>\n");
175  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
176  fprintf(Output_file, " > # end of Color\n");
177  fprintf(Output_file, " <Color \n");
178  fprintf(Output_file, " <ColorTag `Red'>\n");
179  fprintf(Output_file, " <ColorCyan 0.000000>\n");
180  fprintf(Output_file, " <ColorMagenta 100.000000>\n");
181  fprintf(Output_file, " <ColorYellow 100.000000>\n");
182  fprintf(Output_file, " <ColorBlack 0.000000>\n");
183  fprintf(Output_file, " <ColorAttribute ColorIsRed>\n");
184  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
185  fprintf(Output_file, " > # end of Color\n");
186  fprintf(Output_file, " <Color \n");
187  fprintf(Output_file, " <ColorTag `Green'>\n");
188  fprintf(Output_file, " <ColorCyan 100.000000>\n");
189  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
190  fprintf(Output_file, " <ColorYellow 100.000000>\n");
191  fprintf(Output_file, " <ColorBlack 0.000000>\n");
192  fprintf(Output_file, " <ColorAttribute ColorIsGreen>\n");
193  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
194  fprintf(Output_file, " > # end of Color\n");
195  fprintf(Output_file, " <Color \n");
196  fprintf(Output_file, " <ColorTag `Blue'>\n");
197  fprintf(Output_file, " <ColorCyan 100.000000>\n");
198  fprintf(Output_file, " <ColorMagenta 100.000000>\n");
199  fprintf(Output_file, " <ColorYellow 0.000000>\n");
200  fprintf(Output_file, " <ColorBlack 0.000000>\n");
201  fprintf(Output_file, " <ColorAttribute ColorIsBlue>\n");
202  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
203  fprintf(Output_file, " > # end of Color\n");
204  fprintf(Output_file, " <Color \n");
205  fprintf(Output_file, " <ColorTag `Cyan'>\n");
206  fprintf(Output_file, " <ColorCyan 100.000000>\n");
207  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
208  fprintf(Output_file, " <ColorYellow 0.000000>\n");
209  fprintf(Output_file, " <ColorBlack 0.000000>\n");
210  fprintf(Output_file, " <ColorAttribute ColorIsCyan>\n");
211  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
212  fprintf(Output_file, " > # end of Color\n");
213  fprintf(Output_file, " <Color \n");
214  fprintf(Output_file, " <ColorTag `Magenta'>\n");
215  fprintf(Output_file, " <ColorCyan 0.000000>\n");
216  fprintf(Output_file, " <ColorMagenta 100.000000>\n");
217  fprintf(Output_file, " <ColorYellow 0.000000>\n");
218  fprintf(Output_file, " <ColorBlack 0.000000>\n");
219  fprintf(Output_file, " <ColorAttribute ColorIsMagenta>\n");
220  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
221  fprintf(Output_file, " > # end of Color\n");
222  fprintf(Output_file, " <Color \n");
223  fprintf(Output_file, " <ColorTag `Yellow'>\n");
224  fprintf(Output_file, " <ColorCyan 0.000000>\n");
225  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
226  fprintf(Output_file, " <ColorYellow 100.000000>\n");
227  fprintf(Output_file, " <ColorBlack 0.000000>\n");
228  fprintf(Output_file, " <ColorAttribute ColorIsYellow>\n");
229  fprintf(Output_file, " <ColorAttribute ColorIsReserved>\n");
230  fprintf(Output_file, " > # end of Color\n");
231  fprintf(Output_file, " <Color \n");
232  fprintf(Output_file, " <ColorTag `aquamarine'>\n");
233  fprintf(Output_file, " <ColorCyan 100.000000>\n");
234  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
235  fprintf(Output_file, " <ColorYellow 18.000000>\n");
236  fprintf(Output_file, " <ColorBlack 0.000000>\n");
237  fprintf(Output_file, " > # end of Color\n");
238  fprintf(Output_file, " <Color \n");
239  fprintf(Output_file, " <ColorTag `plum'>\n");
240  fprintf(Output_file, " <ColorCyan 0.000000>\n");
241  fprintf(Output_file, " <ColorMagenta 100.000000>\n");
242  fprintf(Output_file, " <ColorYellow 0.000000>\n");
243  fprintf(Output_file, " <ColorBlack 33.000000>\n");
244  fprintf(Output_file, " > # end of Color\n");
245  fprintf(Output_file, " <Color \n");
246  fprintf(Output_file, " <ColorTag `peru'>\n");
247  fprintf(Output_file, " <ColorCyan 0.000000>\n");
248  fprintf(Output_file, " <ColorMagenta 24.000000>\n");
249  fprintf(Output_file, " <ColorYellow 100.000000>\n");
250  fprintf(Output_file, " <ColorBlack 32.000000>\n");
251  fprintf(Output_file, " > # end of Color\n");
252  fprintf(Output_file, " <Color \n");
253  fprintf(Output_file, " <ColorTag `pink'>\n");
254  fprintf(Output_file, " <ColorCyan 0.000000>\n");
255  fprintf(Output_file, " <ColorMagenta 50.000000>\n");
256  fprintf(Output_file, " <ColorYellow 0.000000>\n");
257  fprintf(Output_file, " <ColorBlack 0.000000>\n");
258  fprintf(Output_file, " > # end of Color\n");
259  fprintf(Output_file, " <Color \n");
260  fprintf(Output_file, " <ColorTag `mediumpurple'>\n");
261  fprintf(Output_file, " <ColorCyan 40.000000>\n");
262  fprintf(Output_file, " <ColorMagenta 100.000000>\n");
263  fprintf(Output_file, " <ColorYellow 0.000000>\n");
264  fprintf(Output_file, " <ColorBlack 0.000000>\n");
265  fprintf(Output_file, " > # end of Color\n");
266  fprintf(Output_file, " <Color \n");
267  fprintf(Output_file, " <ColorTag `grey'>\n");
268  fprintf(Output_file, " <ColorCyan 0.000000>\n");
269  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
270  fprintf(Output_file, " <ColorYellow 0.000000>\n");
271  fprintf(Output_file, " <ColorBlack 50.000000>\n");
272  fprintf(Output_file, " > # end of Color\n");
273  fprintf(Output_file, " <Color \n");
274  fprintf(Output_file, " <ColorTag `lightgrey'>\n");
275  fprintf(Output_file, " <ColorCyan 0.000000>\n");
276  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
277  fprintf(Output_file, " <ColorYellow 0.000000>\n");
278  fprintf(Output_file, " <ColorBlack 25.000000>\n");
279  fprintf(Output_file, " > # end of Color\n");
280  fprintf(Output_file, " <Color \n");
281  fprintf(Output_file, " <ColorTag `lightskyblue'>\n");
282  fprintf(Output_file, " <ColorCyan 38.000000>\n");
283  fprintf(Output_file, " <ColorMagenta 33.000000>\n");
284  fprintf(Output_file, " <ColorYellow 0.000000>\n");
285  fprintf(Output_file, " <ColorBlack 0.000000>\n");
286  fprintf(Output_file, " > # end of Color\n");
287  fprintf(Output_file, " <Color \n");
288  fprintf(Output_file, " <ColorTag `lightcoral'>\n");
289  fprintf(Output_file, " <ColorCyan 0.000000>\n");
290  fprintf(Output_file, " <ColorMagenta 50.000000>\n");
291  fprintf(Output_file, " <ColorYellow 60.000000>\n");
292  fprintf(Output_file, " <ColorBlack 0.000000>\n");
293  fprintf(Output_file, " > # end of Color\n");
294  fprintf(Output_file, " <Color \n");
295  fprintf(Output_file, " <ColorTag `yellowgreen'>\n");
296  fprintf(Output_file, " <ColorCyan 31.000000>\n");
297  fprintf(Output_file, " <ColorMagenta 0.000000>\n");
298  fprintf(Output_file, " <ColorYellow 100.000000>\n");
299  fprintf(Output_file, " <ColorBlack 0.000000>\n");
300  fprintf(Output_file, " > # end of Color\n");
301  fprintf(Output_file, "> # end of ColorCatalog\n");
302 }
303 
304 static void mif_end_job(void)
305 {
306  fprintf(Output_file, "# end of MIFFile\n");
307 }
308 
309 static void mif_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb)
310 {
311  PB = bb;
312  if (onetime) {
313  fprintf(Output_file, "<BRect %d %d %d %d>\n",
314  PB.LL.x, PB.UR.y, PB.UR.x - PB.LL.x, PB.UR.y - PB.LL.y);
315  init_mif();
316  onetime = FALSE;
317  }
318 }
319 
320 static void
321 mif_begin_page(graph_t * g, point page, double scale, int rot,
322  point offset)
323 {
324  /* int page_number; */
325  /* point sz; */
326 
327  Scale = scale;
328  Rot = rot;
329  /* page_number = page.x + page.y * Pages.x + 1; */
330  /* sz = sub_points(PB.UR,PB.LL); */
331  fprintf(Output_file,
332  " <ArrowStyle <TipAngle 15> <BaseAngle 90> <Length %.1f> <HeadType Filled>>\n",
333  14 * Scale);
334 }
335 
336 static void mif_begin_context(void)
337 {
338  assert(SP + 1 < MAXNEST);
339  cstk[SP + 1] = cstk[SP];
340  SP++;
341 }
342 
343 static void mif_end_context(void)
344 {
345  int c, psp = SP - 1;
346  assert(SP > 0);
347  if (cstk[SP].color_ix != (c = cstk[psp].color_ix))
348  mif_color(c);
349  if (cstk[SP].font_was_set)
350  mif_font(&(cstk[psp]));
351  if (cstk[SP].style_was_set)
352  mif_style(&(cstk[psp]));
353  /*free(cstk[psp].fontfam); */
354  SP = psp;
355 }
356 
357 static void mif_set_font(char *name, double size)
358 {
359  char *p, *q;
360  context_t *cp;
361 
362  cp = &(cstk[SP]);
363  cp->font_was_set = TRUE;
364  cp->fontsz = size;
365  p = strdup(name);
366  if ((q = strchr(p, '-'))) {
367  *q++ = 0;
368  if (strcasecmp(q, "italic") == 0)
369  cp->fontopt = ITALIC;
370  else if (strcasecmp(q, "bold") == 0)
371  cp->fontopt = BOLD;
372  }
373  cp->fontfam = p;
374  mif_font(&cstk[SP]);
375 }
376 
377 static void mif_set_color(char *name)
378 {
379  int i;
380  char *tok;
381 
382  static char *mifcolor[] = {
383  "black", "white", "red", "green", "blue", "cyan",
384  "magenta", "yellow", "comment",
385  "aquamarine", "plum", "peru", "pink", "mediumpurple", "grey",
386  "lightgrey", "lightskyblue", "lightcoral", "yellowgreen",
387  (char *) 0
388  };
389 
390  tok = canontoken(name);
391  for (i = 0; mifcolor[i]; i++) {
392  if (strcasecmp(mifcolor[i], tok) == 0) {
393  cstk[SP].color_ix = i;
394  mif_color(i);
395  return;
396  }
397  }
398  agerr(AGERR, "color %s not supported in MIF\n", name);
399 }
400 
401 static void mif_set_style(char **s)
402 {
403  char *line;
404  context_t *cp;
405 
406  cp = &(cstk[SP]);
407  while ((line = *s++)) {
408  if (streq(line, "solid"))
409  cp->pen = P_SOLID;
410  else if (streq(line, "dashed"))
411  cp->pen = P_DASHED;
412  else if (streq(line, "dotted"))
413  cp->pen = P_DOTTED;
414  else if (streq(line, "invis"))
415  cp->pen = P_NONE;
416  else if (streq(line, "bold"))
417  cp->penwidth = WIDTH_BOLD;
418  else if (streq(line, "filled"))
419  cp->fill = P_SOLID;
420  else if (streq(line, "unfilled"))
421  cp->fill = P_NONE;
422  else {
423  agerr(AGERR,
424  "mif_set_style: unsupported style %s - ignoring\n",
425  line);
426  }
427  cp->style_was_set = TRUE;
428  }
429  if (cp->style_was_set)
430  mif_style(cp);
431 }
432 
433 static char *mif_string(char *s)
434 {
435  static char *buf = NULL;
436  static int bufsize = 0;
437  int pos = 0;
438  char *p, esc;
439 
440  if (!buf) {
441  bufsize = 64;
442  buf = N_GNEW(bufsize, char);
443  }
444 
445  p = buf;
446  while (*s) {
447  if (pos > (bufsize - 8)) {
448  bufsize *= 2;
449  buf = grealloc(buf, bufsize);
450  p = buf + pos;
451  }
452  esc = 0;
453  switch (*s) {
454  case '\t':
455  esc = 't';
456  break;
457  case '>':
458  case '\'':
459  case '`':
460  case '\\':
461  esc = *s;
462  break;
463  }
464  if (esc) {
465  *p++ = '\\';
466  *p++ = esc;
467  pos += 2;
468  } else {
469  *p++ = *s;
470  pos++;
471  }
472  s++;
473  }
474  *p = '\0';
475  return buf;
476 }
477 
478 static void mif_textpara(point p, textpara_t * para)
479 {
480  pointf mp;
481  char *anchor;
482 
483  mp.x = p.x;
484  mp.y = p.y - cstk[SP].fontsz / 2 + 2;
485  switch (para->just) {
486  case 'l':
487  anchor = "Left";
488  break;
489  case 'r':
490  anchor = "Right";
491  break;
492  default:
493  case 'n':
494  anchor = "Center";
495  break;
496  }
497  mp = mifpt(mp);
498  fprintf(Output_file,
499  "<TextLine <Angle %d> <TLOrigin %.2f %.2f> <TLAlignment %s>",
500  Rot, mp.x, mp.y, anchor);
501  fprintf(Output_file, " <String `%s'>>\n", mif_string(para->str));
502 }
503 
504 static void mif_bezier(point * A, int n, int arrow_at_start,
505  int arrow_at_end, int filled)
506 {
507  fprintf(Output_file,
508  "<PolyLine <Fill 15> <Smoothed Yes> <HeadCap Square>\n");
509  mifptarray(A, n);
510  fprintf(Output_file, ">\n");
511 }
512 
513 static void mif_polygon(point * A, int n, int filled)
514 {
515  fprintf(Output_file, "<Polygon %s\n", (filled ? FillStr : NoFillStr));
516  mifptarray(A, n);
517  fprintf(Output_file, ">\n");
518 }
519 
520 static void mif_ellipse(point p, int rx, int ry, int filled)
521 {
522  pointf tl, mp;
523  tl.x = p.x - rx;
524  tl.y = p.y + ry;
525  if (Rot) {
526  int t;
527  t = rx;
528  rx = ry;
529  ry = t;
530  }
531  mp = mifpt(tl);
532  fprintf(Output_file, "<Ellipse %s <BRect %.2f %.2f %.1f %.1f>>\n",
533  filled ? FillStr : NoFillStr,
534  mp.x, mp.y, Scale * (rx + rx), Scale * (ry + ry));
535 }
536 
537 static void mif_polyline(point * A, int n)
538 {
539  fprintf(Output_file, "<PolyLine <HeadCap Square>\n");
540  mifptarray(A, n);
541  fprintf(Output_file, ">\n");
542 }
543 
544 static void mif_usershape(usershape_t *us, boxf b, point *A, int n, boolean filled)
545 {
546  static boolean onetime = TRUE;
547  if (onetime) {
548  agerr(AGERR, "custom shapes not available with this driver\n");
549  onetime = FALSE;
550  }
551 }
552 
553 codegen_t MIF_CodeGen = {
554  mif_reset,
555  mif_begin_job, mif_end_job,
556  mif_begin_graph, 0, /* mif_end_graph */
557  mif_begin_page, 0, /* mif_end_page */
558  0, /* mif_begin_layer */ 0, /* mif_end_layer */
559  0, /* mif_begin_cluster */ 0, /* mif_end_cluster */
560  0, /* mif_begin_nodes */ 0, /* mif_end_nodes */
561  0, /* mif_begin_edges */ 0, /* mif_end_edges */
562  0, /* mif_begin_node */ 0, /* mif_end_node */
563  0, /* mif_begin_edge */ 0, /* mif_end_edge */
564  mif_begin_context, mif_end_context,
565  0, /* mif_begin_anchor */ 0, /* mif_end_anchor */
566  mif_set_font, mif_textpara,
567  mif_set_color, mif_set_color, mif_set_style,
568  mif_ellipse, mif_polygon,
569  mif_bezier, mif_polyline,
570  0, /* bezier_has_arrows */
571  mif_comment,
572  mif_usershape
573 };