Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / mif.trm
diff --git a/term/mif.trm b/term/mif.trm
new file mode 100644 (file)
index 0000000..5aab925
--- /dev/null
@@ -0,0 +1,1000 @@
+/* Hello, Emacs, this is -*-C-*-
+ * $Id: mif.trm,v 1.33 2006/07/21 02:35:47 sfeam Exp $
+ */
+
+/* GNUPLOT -- mif.trm */
+
+/*[
+ * Copyright 1992, 1993, 1998, 2004
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code.  Modifications are to
+ * be distributed as patches to the released version.  Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ *   1. distribute the corresponding source modifications from the
+ *    released version in the form of a patch file along with the binaries,
+ *   2. add special version identification to distinguish your version
+ *    in addition to the base release version number,
+ *   3. provide your name and address as the primary contact for the
+ *    support of your modified version, and
+ *   4. retain our contact information in regard to use of the base
+ *    software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+/*
+ * This file is included by ../term.c.
+ *
+ * This terminal driver was developed for
+ *      gnuplot for unix version 3.0 (patchlevel 1)
+ *      gnuplot for unix version 3.2 (patchlevel 2)
+ *
+ * This terminal driver supports:
+ *      Frame Maker MIF format version 3.00
+ *
+ * Options for this terminal driver (set terminal mif [options]):
+ *      colour /        Draw primitives with line types >= 0 in colour (sep. 2-7)
+ *      monochrome      Draw primitives in black (sep. 0)
+ *
+ *      polyline /      Draw lines as continuous curves
+ *      vectors         Draw lines as collections of vectors
+ *
+ *      help / ?        Print short usage description on stderr
+ *
+ * Properties for this terminal driver:
+ *     -Gnuplot size of worksheet:              MIF_XMAX * MIF_YMAX
+ *     -Unit in MIF output:                     cm
+ *     -Plot primitives with the same pen will
+ *      be grouped in the same MIF group.
+ *     -Plot primitives with line types >= 0
+ *      will as default be drawn in colour.
+ *     -Lines are plotted as collections of
+ *      vectors, or as continuous lines (default)
+ *     -Plot primitives in a plot will be in a
+ *      Frame in MIF. Several plot Frames will
+ *      be collected in one large Frame.
+ *     -Point size of MIF output characters:    MIF_PSIZE
+ *     -Used font for MIF output characters:    Times
+ *     -Supports vertical text
+ *     -points and dots as characters
+ *     -character formats for TextLines
+ *
+ * AUTHORS:
+ *      Olof Franksson, Physics IV, KTH, S-100 44 Stockholm, Sweden
+ *
+ * NEW TERMINAL FORMAT:  David C. Schooley
+
+ * COMMENTS:
+ *      Send comments and/or suggestions to olof@fysik4.kth.se
+ *
+ * CHANGES:
+ *     Changed to new terminal format 9/29/95          schooley@ee.gatech.edu
+ *      Changed order of routine declarations.          olof@fysik4.kth.se
+ *      Changed mechanism for pen pattern selection.    kssingvo@immd4.informatik.uni-erlangen.de
+ *      Support for vertical text.                      kssingvo@immd4.informatik.uni-erlangen.de
+ *      Fixed plot bug for "set size XS,YS", XS/YS > 1. olof@fysik4.kth.se
+ *     Support colored text                            merritt@u.washington.edu
+ *     Support box fill and pattern fill               merritt@u.washington.edu
+ *
+ */
+
+#include "driver.h"
+
+#ifdef TERM_REGISTER
+register_term(mif)
+#endif
+
+
+
+#ifdef TERM_PROTO
+TERM_PUBLIC void MIF_init __PROTO((void));
+TERM_PUBLIC void MIF_graphics __PROTO((void));
+TERM_PUBLIC void MIF_text __PROTO((void));
+TERM_PUBLIC void MIF_linetype __PROTO((int linetype));
+TERM_PUBLIC void MIF_move __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void MIF_vector __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void MIF_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC int MIF_text_angle __PROTO((int ang));
+TERM_PUBLIC void MIF_reset __PROTO((void));
+TERM_PUBLIC void MIF_options __PROTO((void));
+TERM_PUBLIC int MIF_justify_text __PROTO((enum JUSTIFY mode));
+TERM_PUBLIC void MIF_point __PROTO((unsigned int x, unsigned int y, int number));
+TERM_PUBLIC void MIF_boxfill __PROTO((int style, unsigned int x1, unsigned int y1,
+           unsigned int width, unsigned int height));
+TERM_PUBLIC void MIF_filled_polygon __PROTO((int points, gpiPoint* corners));
+
+/** Coordinates **/
+/* The cast to float is not necessary because we are dividing by a float */
+/* On OSK the cast to a float is not allowed in a constant expression wich */
+/* is used by the declaration and initialization of mif_line */
+/* Converts gnuplot units to MIF units */
+#define GNP_TO_MIF(P)   ((P) / 1000.0)
+/* Basic unit: 0.01 mm (15cm -> 15*10*100=15000) */
+#define MIF_XMAX 15000
+/* Basic unit: 0.01 mm (10cm -> 10*10*100=10000) */
+#define MIF_YMAX 10000
+
+#define MIF_XLAST (MIF_XMAX - 1)
+#define MIF_YLAST (MIF_YMAX - 1)
+
+static int insert_mif_line __PROTO((double fx, double fy));
+static int proc_group_id __PROTO((int group_id));
+static void free_mif_line __PROTO((void));
+static void put_mif_line __PROTO((void));
+static void MIF_set_font __PROTO((const char *));
+static void mif_put_point __PROTO((unsigned int x, unsigned int y, int np));
+
+#endif
+
+#ifndef TERM_PROTO_ONLY
+#ifdef TERM_BODY
+
+#ifndef cfree
+# define cfree free
+#endif
+
+static struct mif_line {       /* Line point structure specification */
+    float fpos_x;              /* Line point X coordinate */
+    float fpos_y;              /*            Y coordinate */
+    struct mif_line *next;     /* Pointer to next line point */
+    struct mif_line *prev;     /* Pointer to previous line point */
+} mif_line =
+{                              /* Current position structure. Adjust for orign. Local for this file. */
+    GNP_TO_MIF(0),
+       GNP_TO_MIF(MIF_YLAST),
+       &mif_line,
+       &mif_line
+};
+
+/** Characters **/
+#define MIF_PSIZE 9            /* Point size of used characters */
+
+#define MIF_VCHAR (MIF_YMAX/31)        /* Distance between rows (a guess) */
+#define MIF_HCHAR (MIF_XMAX/95)        /* Distance between characters (a guess) */
+
+/** Scale marks **/
+#define MIF_VTIC  (MIF_YMAX/150)       /* Size of scale mark (vert) */
+#define MIF_HTIC  (MIF_XMAX/225)       /* Size of scale mark (hor) */
+
+/** Drawing properties **/
+static char mif_justify[64];   /* How to justify the used text */
+static char mif_pen[64], mif_pen_width[64], mif_separation[64];                /* How to plot */
+static char mif_textcolor[64]; /* EAM parallels separation */
+
+static int mif_text_ang = 0;           /* Rotation angle of text */
+
+static int mif_fill_patterns[] = {7,12,3,0,9,8,14,13};
+#define MIF_FILL_SOLID  0
+#define MIF_FILL_NONE  15
+
+#define MIF_NPENS 16           /* Number of MIF pen types */
+static int mif_pentype = 0;    /* Pen type to use. Also used to create groups for graphics */
+#define MIF_PEN_TO_GROUP(P)     ( 1 + (P) )    /* Map pen type to group number. Must be >= 1 */
+
+static int mif_pattern_table[MIF_NPENS] =
+{ /* Table, which pattern should be used for drawing */
+    0,                         /* border  */
+    1,                         /* not used */
+    2, 3, 4, 8, 12, 13,                /* other lines: functions, data, ... (5 is used for grid; 6,7 is (nearly) invisible) */
+    5,                         /* grid */
+    9, 10, 11, 12, 13, 14, 15  /* not used */
+};
+
+/** MIF groups administration **/
+#define MIF_NGROUP_ID           20
+static struct mif_group_id {
+    int group_existance;
+/* This group id should generate a MIF group */
+#define MIF_GROUP_EXISTS        1
+/* This group id should not generate a MIF group */
+#define MIF_GROUP_NOT_EXISTS    0
+
+    int group_id;
+#define MIF_INVALID_GROUP_ID    0      /* An invalid MIF group ID */
+
+} mif_group_id[MIF_NGROUP_ID]; /* List of used group ID:s and corresponding MIF groups existance */
+
+/** Semaphores **/
+static int mif_initialized = 0;        /* != 0 when output is active */
+static int mif_in_frame = 0;   /* != 0 when inside a plot frame */
+static int mif_frameno = -1;   /* Current frame number */
+static int mif_colour = TRUE;  /* == TRUE when colour should be used */
+static int mif_polyline = TRUE;        /* == TRUE when lines are drawn as continuous curves */
+
+struct mpt {                   /* point definition structure */
+    int chr;                   /* character for point */
+    float x_offset, y_offset;  /* offset for vertical positioning */
+    char *font;                        /* font */
+};
+
+static char zgnuplot[] = "ZGnuplot"; /* character formats */
+static char zgnuplotp[] = "ZGnuplotP";
+static char zgnuplotd[] = "ZGnuplotD";
+static const char *mif_font = NULL; /* actual character format */
+
+static struct mpt mpt[POINT_TYPES + 1] =
+{                              /* point definition data */
+    {'.', 0.000, 0.005, zgnuplotd, /* dot */ },
+
+    {'G', 0.002, 0.084, zgnuplotp, /* diamond */ },
+    {';', 0.002, 0.084, zgnuplotp, /* plus */ },
+    {'n', 0.002, 0.084, zgnuplotp, /* box */ },
+    {'5', 0.002, 0.084, zgnuplotp, /* X */ },
+    {'s', 0.002, 0.062, zgnuplotp, /* triangle */ },
+    {'K', 0.005, 0.075, zgnuplotp, /* star */ },
+};
+
+/* diamond is offset 0, dot is offset -1 */
+static struct mpt *mif_point = &(mpt[1]);
+
+
+/** Declaration of routine/s for internal use **/
+static int insert_mif_line __PROTO((double fx, double fy));
+static int proc_group_id __PROTO((int group_id));
+
+enum MIF_id {
+    MIF_MONOCHROME, MIF_COLOR, MIF_VECTORS, MIF_POLYLINE, MIF_HELP,
+    MIF_OTHER
+};
+
+static struct gen_table MIF_opts[] =
+{
+    { "m$onochrome", MIF_MONOCHROME },
+    { "c$olor", MIF_COLOR },
+    { "c$olour", MIF_COLOR },
+    { "v$ectors", MIF_VECTORS },
+    { "p$olyline", MIF_POLYLINE },
+    { "h$elp", MIF_HELP },
+    { "?$", MIF_HELP },
+    { NULL, MIF_OTHER }
+};
+
+/** Routine/s **/
+
+/* Called when this terminal type is set in order to parse options */
+TERM_PUBLIC void
+MIF_options()
+{
+    while (!END_OF_COMMAND) {
+       switch(lookup_table(&MIF_opts[0],c_token)) {
+       /* Colour options */
+       case MIF_MONOCHROME:
+           mif_colour = FALSE;
+           c_token++;
+           break;
+       case MIF_COLOR:
+           mif_colour = TRUE;
+           c_token++;
+           break;
+       /* Curve options */
+       case MIF_VECTORS:
+           mif_polyline = FALSE;
+           c_token++;
+           break;
+       case MIF_POLYLINE:
+           mif_polyline = TRUE;
+           c_token++;
+           break;
+       /* Short help */
+       case MIF_HELP:
+       case MIF_OTHER:
+       default:
+           fprintf(stderr, "\
+Usage: set terminal mif [options]\n\
+\toptions:\n\
+\t\tcolour /        Draw primitives with line types >= 0 in colour (sep. 2-7)\n\
+\t\tmonochrome      Draw primitives in black (sep. 0)\n\n\
+\t\tpolyline /      Draw lines as continuous curves\n\
+\t\tvectors         Draw lines as collections of vectors\n\n\
+\t\thelp / ?        Print short usage description on stderr\n");
+           c_token++;
+           break;
+       }
+    }
+    sprintf(term_options, "%s %s",
+           (mif_colour == TRUE) ? "colour" : "monochrome",
+           (mif_polyline == TRUE) ? "polyline" : "vectors");
+}
+
+/* Deallocate the used line structure elements */
+static void
+free_mif_line()
+{
+    struct mif_line *tline;
+
+    while (mif_line.prev != &mif_line) {
+       /* Unlink */
+       tline = mif_line.prev;
+       mif_line.prev = mif_line.prev->prev;
+       mif_line.prev->next = &mif_line;
+
+       /* Deallocate */
+       free(tline);
+    }
+
+    /* Make sure that the list will be empty */
+    mif_line.prev = &mif_line;
+    mif_line.next = &mif_line;
+}
+
+/* Draw the pending line. Change current position. */
+static void
+put_mif_line()
+{
+    int np, i;
+    struct mif_line *tline;
+
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Count the number of available points */
+       for (tline = mif_line.next, np = 1; tline != &mif_line; tline = tline->next, np++);
+
+       /* Draw line (at least two points) */
+       if (np >= 2) {
+
+           /* Line preamble */
+           fprintf(gpoutfile, "\t<PolyLine <GroupID %d> %s %s %s <Fill 15>\n",
+                   MIF_PEN_TO_GROUP(mif_pentype), mif_pen, mif_pen_width, mif_separation);
+
+           /* Draw the line elements */
+           fprintf(gpoutfile, "\t\t<NumPoints %d> ", np);
+           for (i = 0, tline = &mif_line; i < np; i++, tline = tline->next) {
+               if (i % 4 == 0)
+                   fputs("\n\t\t", gpoutfile);
+               fprintf(gpoutfile, "<Point  %.3f %.3f> ",
+                       tline->fpos_x, tline->fpos_y);
+           }
+
+           /* Line post amble */
+           fputs("\n\t>\n", gpoutfile);
+
+           /* Register the used group ID */
+           proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
+
+           /* Avoid to redraw this. The MIF system should remember it. */
+           mif_pen[0] = '\0';
+           mif_pen_width[0] = '\0';
+           mif_separation[0] = '\0';
+
+           /* Move current position to end of line */
+           mif_line.fpos_x = mif_line.prev->fpos_x;
+           mif_line.fpos_y = mif_line.prev->fpos_y;
+
+           /* Restore the line */
+           free_mif_line();
+       }
+    }                          /* Line processed */
+}
+
+/* Filled box support - Ethan Merritt <merritt@u.washington.edu> */
+TERM_PUBLIC void
+MIF_boxfill(int style, unsigned int x1, unsigned int y1,
+           unsigned int width, unsigned int height)
+{
+    int fill_pattern;
+
+    int fillpar = style >> 4;
+    style &= 0xf;
+    switch (style) {
+       default:
+       case FS_EMPTY:  fill_pattern = 7;
+                       break;
+       case FS_SOLID:  fill_pattern = MIF_FILL_SOLID;
+                       break;
+       case FS_PATTERN:fill_pattern = mif_fill_patterns[fillpar % 8];
+                       break;
+    }
+
+    /* Object preamble */
+    fprintf(gpoutfile, "\t<Rectangle <GroupID %d> %s\n",
+           MIF_PEN_TO_GROUP(mif_pentype), mif_separation);
+
+    /* Set fill type */
+    fprintf(gpoutfile, "\t\t<Fill %d>\n", fill_pattern);
+
+    /* Draw the box */
+    fprintf(gpoutfile, "\t\t<ShapeRect %.3f %.3f %.3f %.3f>\n",
+       GNP_TO_MIF(x1), GNP_TO_MIF(MIF_YLAST - (y1+height)),
+       GNP_TO_MIF(width), GNP_TO_MIF(height));
+
+    /* End of object */
+    fputs("\n\t>\n", gpoutfile);
+
+    /* Register the used group ID */
+    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
+
+}
+
+/* Filled polygon. Ethan Merritt <merritt@u.washington.edu> */
+TERM_PUBLIC void
+MIF_filled_polygon(int points, gpiPoint* corners)
+{
+    int i;
+
+    /* Object preamble */
+    fprintf(gpoutfile, "\t<Polygon <GroupID %d>\n",
+           MIF_PEN_TO_GROUP(mif_pentype));
+
+    /* Set fill type */
+    fprintf(gpoutfile, "\t\t<Fill %d>\n", MIF_FILL_SOLID);
+
+    /* Draw the line elements */
+    fprintf(gpoutfile, "\t\t<NumPoints %d> ", points);
+    for (i=0; i<points; i++) {
+       fprintf(gpoutfile, "<Point  %.3f %.3f> ",
+               GNP_TO_MIF(corners[i].x),
+               GNP_TO_MIF(MIF_YLAST - corners[i].y));
+    }
+
+    /* End of object */
+    fputs("\n\t>\n", gpoutfile);
+
+    /* Register the used group ID */
+    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
+
+}
+
+/* Draw a point */
+static void
+mif_put_point(unsigned int x, unsigned int y, int np)
+{
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Draw pending line */
+       if (mif_polyline == TRUE)
+           put_mif_line();
+
+       /* Adjust current position for text-graphics alignment */
+       MIF_move(x, y);
+
+       /* center text */
+       MIF_justify_text(CENTRE);
+
+       /* Draw the point */
+       fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s\n",
+               MIF_PEN_TO_GROUP(mif_pentype),
+               mif_textcolor);
+
+       MIF_set_font(mif_point[np].font);
+
+       fprintf(gpoutfile, "\t\t<TLOrigin  %.3f %.3f> %s <String `%c'>\n",
+               mif_line.fpos_x + mif_point[np].x_offset,
+               mif_line.fpos_y + mif_point[np].y_offset,
+               mif_justify,
+               mif_point[np].chr);
+       fputs("\t>\n", gpoutfile);
+
+       /* Register the used group ID */
+       proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
+
+       /* Avoid to redraw this. The MIF system should remember it. */
+       mif_justify[0] = '\0';
+
+    }                          /* Point processed */
+}
+
+
+/*
+ *  draw points
+ */
+TERM_PUBLIC void
+MIF_point(unsigned int x, unsigned int y, int number)
+{
+    if (number < 0) {          /* dot */
+       number = -1;
+    } else {                   /* point */
+       number %= POINT_TYPES;
+    }
+    mif_put_point(x, y, number);
+}
+
+
+/* Set up a MIF output file */
+TERM_PUBLIC void
+MIF_init()
+{
+    int i;
+
+    /* Process if not inside a MIF file and Frame */
+    if (mif_initialized == 0 && mif_in_frame == 0) {
+       /* Tell this terminal driver that the output is initialized and
+        * no current frames are processed */
+       mif_initialized = 1;
+       mif_in_frame = 0;
+
+       /* Reset internal position */
+       free_mif_line();
+       mif_line.fpos_x = GNP_TO_MIF(0);
+       mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
+
+       /* Reset drawing properties strings */
+       mif_pen[0] = '\0';
+       mif_pen_width[0] = '\0';
+       mif_separation[0] = '\0';
+
+       MIF_justify_text(LEFT);
+
+       /* Reset group ID generator */
+       for (i = 0; i < MIF_NGROUP_ID; i++) {
+           mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
+           mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
+       }
+
+       /* Identify ourselves */
+       /*bs show borders */
+       /* Setup a default environment to use */
+       fprintf(gpoutfile, "\
+<MIFFile 3.00> # Generated by gnuplot version %s patchlevel %s; identifies this as a MIF file\n\
+#\n\
+# show borders\n\
+<Document\n<DBordersOn Yes>\n>\n\
+# Set a default pen pattern, pen width, unit and font for subsequent objects\n\
+<Pen 0>\n\
+<Fill 15>\n\
+<PenWidth 0.5 pt>\n\
+<Separation 0>\n\
+<Units Ucm>\n\
+<FontCatalog\n\
+\t<Font <FTag `%s'><FFamily `Times'><FSize %d><FPlain Yes>>\n\
+\t<Font <FTag `%s'><FFamily `ZapfDingbats'><FSize 7.0 pt><FPlain Yes>>\n\
+\t<Font <FTag `%s'><FFamily `Symbol'><FSize 5.0 pt><FPlain Yes>>\n\
+>\n\
+#\n",
+               gnuplot_version, gnuplot_patchlevel,
+               zgnuplot, MIF_PSIZE,
+               zgnuplotp,
+               zgnuplotd);
+    }                          /* MIF file created */
+}
+
+/* Finish of a MIF output file */
+TERM_PUBLIC void
+MIF_reset()
+{
+    /* Process if inside a MIF file and not inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame == 0) {
+       /* Finish off the MIF file */
+       fputs("\
+#\n\
+# End of MIFFile\n", gpoutfile);
+
+       /* Tell this terminal driver that the output is finished */
+       mif_initialized = 0;
+
+       /* bs: reset frame number */
+       mif_frameno = -1;
+
+    }                          /* MIF file finished */
+}
+
+/* Start plotting a Frame (-> graphics mode) */
+TERM_PUBLIC void
+MIF_graphics()
+{
+    int i;
+
+    /* Process if not inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame == 0) {
+       /* Tell that this terminal driver is working with a plot frame */
+       mif_in_frame = 1;
+
+       /* Update frame number */
+       mif_frameno++;
+
+       /* Set current position */
+       free_mif_line();
+       mif_line.fpos_x = GNP_TO_MIF(0);
+       mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
+
+       /* Set drawing properties */
+       mif_pen[0] = '\0';
+       mif_pen_width[0] = '\0';
+       mif_separation[0] = '\0';
+
+       MIF_justify_text(LEFT);
+
+       /* Reset group ID generator */
+       for (i = 0; i < MIF_NGROUP_ID; i++) {
+           mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
+           mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
+       }
+
+       /* Frame preamble */
+       fprintf(gpoutfile, "\
+#\n\
+# Frame number %d with plot of graphics\n\
+<Frame\n\
+\t<Pen 15>\n\
+\t<Fill 15>\n\
+\t<PenWidth  0.5 pt>\n\
+\t<Separation 0>\n\
+\t<BRect 2.000 %.3f %.3f %.3f>\n\
+\t<NSOffset  0.000>\n\
+\t<BLOffset  0.000>\n",
+           mif_frameno,
+           ((float) mif_frameno) * GNP_TO_MIF(MIF_YMAX + 100),
+           GNP_TO_MIF(MIF_XMAX), GNP_TO_MIF(MIF_YMAX));
+    }                          /* Frame created */
+}
+
+/* Stop plotting a Frame (-> text mode) */
+TERM_PUBLIC void
+MIF_text()
+{
+    int i;
+
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Draw pending line */
+       if (mif_polyline == TRUE)
+           put_mif_line();
+
+       /* Group the used plot primitives */
+       fputs("\
+\t#\n\
+\t# Group the the objects in groups to make the chart easier to manipulate\n\
+\t# after it's imported into FrameMaker.\n", gpoutfile);
+
+       for (i = 0; i < MIF_NGROUP_ID; i++) {
+           if (mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
+               mif_group_id[i].group_existance == MIF_GROUP_EXISTS) {
+               fprintf(gpoutfile, "\
+\t<Group\n\
+\t\t<ID %d>\n\
+\t>\n", mif_group_id[i].group_id);
+           }
+       }
+
+       /* Frame post amble */
+       fprintf(gpoutfile, "\
+>\n\
+# End of Frame number %d\n\
+#\n",
+               mif_frameno);
+
+       /* Tell that this terminal driver is not working with a plot frame */
+       mif_in_frame = 0;
+    }                          /* Frame finshed */
+}
+
+/* Select type of line in grapics */
+/* NOTE: actually written to output the first time a primitive
+ * is drawn AFTER this call */
+/* -2=border, -1=X/Y-axis, 0-13=lines, and 14-=mapped back */
+TERM_PUBLIC void
+MIF_linetype(int linetype)
+{
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Draw pending line */
+       if (mif_polyline == TRUE)
+           put_mif_line();
+
+       /* Translate gnuplot pen types to MIF pen types */
+       if (linetype < 0) {     /* Special lines */
+           if (linetype == LT_AXIS) {
+               mif_pentype = 8 + MIF_NPENS;    /* -1 */
+               if (mif_colour == TRUE)
+                   sprintf(mif_separation, " <Separation 0> ");
+           } else {
+               mif_pentype = 0 + MIF_NPENS;    /* -2 or less */
+               if (mif_colour == TRUE)
+                   sprintf(mif_separation, " <Separation 0> ");
+           }
+           sprintf(mif_pen_width, " <PenWidth 1.0 pt> ");
+           /* EAM - set text color to black */
+           sprintf(mif_textcolor, " <Font <FSeparation 0>> ");
+       } else {                /* Normal lines */
+           mif_pentype = (linetype) % MIF_NPENS;       /* 0-(MIF_NPENS-1) */
+           sprintf(mif_pen_width, " <PenWidth 0.1 pt> ");
+           if (mif_colour == TRUE)
+               sprintf(mif_separation, " <Separation %d> ",
+                       2 + (mif_pentype % 6)); /* 2-7 */
+           /* EAM - set text color also */
+           if (mif_colour == TRUE)
+               sprintf(mif_textcolor, " <Font <FSeparation %d>> ",
+                       2 + (mif_pentype % 6)); /* 2-7 */
+       }
+
+       /* Set pen type */
+       sprintf(mif_pen, " <Pen %d> ",
+               mif_pattern_table[mif_pentype % MIF_NPENS]);
+
+    }                          /* Primitive processed */
+}
+
+/* Allow arbitrary text rotation */
+TERM_PUBLIC int
+MIF_text_angle(int ang)
+{
+    mif_text_ang = ang;
+    return (TRUE);
+}
+
+/* Justify following text lines (MIF_put_text()) relative to the
+ * insertion point
+ * NOTE: actually written to output in text primitives which are
+ * drawn AFTER this call */
+TERM_PUBLIC int
+MIF_justify_text(enum JUSTIFY mode)
+{
+    int rval = TRUE;
+
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+       switch (mode) {
+       case LEFT:
+           sprintf(mif_justify, " <TLAlignment Left> ");
+           break;
+       case CENTRE:
+           sprintf(mif_justify, " <TLAlignment Center> ");
+           break;
+       case RIGHT:
+           sprintf(mif_justify, " <TLAlignment Right> ");
+           break;
+       default:
+           rval = FALSE;
+           break;
+       }
+
+    }
+    /* Primitive processed */
+    else {
+       rval = FALSE;
+    }
+
+    return (rval);
+}
+
+/* Draw a vector from current position to (x, y) and change current position.
+ * NOTE: actually written to output the first time another primitive
+ * is called AFTER this call */
+TERM_PUBLIC void
+MIF_vector(unsigned int x, unsigned int y)
+{
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Setup the vector as a part of the line */
+       insert_mif_line(GNP_TO_MIF(x), GNP_TO_MIF(MIF_YLAST - (int) y));
+
+       /* Draw pending line -> vector */
+       if (mif_polyline == FALSE)
+           put_mif_line();
+
+    }                          /* Vector processed */
+}
+
+/* Move current position */
+TERM_PUBLIC void
+MIF_move(unsigned int x, unsigned int y)
+{
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Draw pending line */
+       if (mif_polyline == TRUE)
+           put_mif_line();
+
+       mif_line.fpos_x = GNP_TO_MIF(x);
+       mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST - (int) y);
+    }
+}
+
+
+/* set font */
+static void
+MIF_set_font(const char *font)
+{
+    if (font != mif_font) {
+       fprintf(gpoutfile, "\t\t<Font\n\t\t\t<FTag `%s'>\n\t\t>\n", font);
+       mif_font = font;
+    }
+}
+
+
+/* Draw the text string str at (x, y). Adjust according to MIF_justify_text().
+ * Change current position. */
+TERM_PUBLIC void
+MIF_put_text(unsigned int x, unsigned int y, const char str[])
+{
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Draw pending line */
+       if (mif_polyline == TRUE)
+           put_mif_line();
+
+       /* Adjust current position for text-graphics alignment */
+       MIF_move(x, y - MIF_VCHAR / 5);
+
+       if (strlen(str) > 0) {
+
+           /* Draw the text */
+           fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s %s %s %s\n",
+                   MIF_PEN_TO_GROUP(mif_pentype), mif_pen,
+                   mif_pen_width, mif_separation, mif_textcolor);
+
+           MIF_set_font(zgnuplot);
+
+           fprintf(gpoutfile, "\
+\t\t<TLOrigin  %.3f %.3f> %s <Angle %d> <String `%s'>\n\
+\t>\n",
+                   mif_line.fpos_x, mif_line.fpos_y, mif_justify,
+                   mif_text_ang, str);
+
+           /* Register the used group ID */
+           proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
+
+           /* Avoid to redraw this. The MIF system should remember it. */
+           mif_pen[0] = '\0';
+           mif_pen_width[0] = '\0';
+           mif_separation[0] = '\0';
+
+           mif_justify[0] = '\0';      /* Independent of linetype */
+       }
+    }                          /* Text processed */
+}
+
+
+/* Insert one point in the line */
+static int
+insert_mif_line(double fx, double fy)
+{
+    int rval = TRUE;
+
+    if ((mif_line.prev->next = (struct mif_line *) gp_alloc(sizeof(struct mif_line),
+       "MIF driver")) != (struct mif_line *) NULL) {
+       /* Link */
+       mif_line.prev->next->next = &mif_line;
+       mif_line.prev->next->prev = mif_line.prev;
+       mif_line.prev = mif_line.prev->next;
+
+       /* Fill */
+       mif_line.prev->fpos_x = fx;
+       mif_line.prev->fpos_y = fy;
+
+       rval = TRUE;
+    } else {                   /* Failed to allocate */
+       /* Relink */
+       mif_line.prev->next = &mif_line;
+
+       rval = FALSE;
+    }
+
+    return (rval);
+}
+
+/* Register group ID. Update group ID existance. */
+/* Returns:     1       group_id belongs to a MIF group
+               0       group_id does not belong to a MIF group
+              -1       not inside a Frame
+              -2       group ID list is full
+ */
+static int
+proc_group_id(int group_id)
+{
+    int i, rval = 0;
+
+    /* Process if inside a Frame */
+    if (mif_initialized != 0 && mif_in_frame != 0) {
+
+       /* Find out the group ID, or a free group ID slot index. */
+       for (i = 0; i < MIF_NGROUP_ID &&
+            mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
+            mif_group_id[i].group_id != group_id;
+            i++) {
+           /* Don't check the group_existance variable */
+       }
+
+       if (i < MIF_NGROUP_ID) {
+           if (mif_group_id[i].group_id == MIF_INVALID_GROUP_ID) {
+               /* Register as new group ID for eventual use as MIF group */
+               mif_group_id[i].group_id = group_id;
+               mif_group_id[i].group_existance = MIF_GROUP_NOT_EXISTS;
+           } else {
+               /* If second use of this group ID -> create a new MIF group */
+               if (mif_group_id[i].group_id == group_id) {
+                   mif_group_id[i].group_existance = MIF_GROUP_EXISTS;
+                   /* NOTE: a group MUST have at least two members. */
+                   rval = 1;
+               }
+           }
+       } else {
+           rval = -2;          /* No place for this group ID in the list */
+       }
+
+    }
+    /* Group ID processed */
+    else {
+       rval = -1;              /* Not inside a Frame */
+    }
+
+    /* Return MIF group status */
+    return (rval);
+}
+
+
+#endif
+
+
+#ifdef TERM_TABLE
+
+TERM_TABLE_START(mif_driver)
+    "mif", "Frame maker MIF 3.00 format",
+    MIF_XMAX, MIF_YMAX, MIF_VCHAR, MIF_HCHAR,
+    MIF_VTIC, MIF_HTIC, MIF_options, MIF_init, MIF_reset,
+    MIF_text, null_scale, MIF_graphics, MIF_move, MIF_vector,
+    MIF_linetype, MIF_put_text, MIF_text_angle,
+    MIF_justify_text, MIF_point, do_arrow, set_font_null,
+    0, /* pointsize */
+    0, /* flags */
+    0, 0, /* suspend, resume */
+    MIF_boxfill,
+    0  /* linewidth */
+#ifdef USE_MOUSE
+    , 0, 0, 0, 0, 0
+#endif
+    ,0 /* make_palette */
+    ,0 /* previous_palette */
+    ,0 /* set_color */
+    ,MIF_filled_polygon /* filled_polygon */
+TERM_TABLE_END(mif_driver)
+
+#undef LAST_TERM
+#define LAST_TERM mif_driver
+
+#endif
+#endif /* TERM_PROTO_ONLY */
+
+#ifdef TERM_HELP
+START_HELP(mif)
+"1 mif",
+"?commands set terminal mif",
+"?set terminal mif",
+"?set term mif",
+"?terminal mif",
+"?term mif",
+"?mif",
+" The `mif` terminal driver produces Frame Maker MIF format version 3.00.  It",
+" plots in MIF Frames with the size 15*10 cm, and plot primitives with the same",
+" pen will be grouped in the same MIF group.  Plot primitives in a `gnuplot`",
+" page will be plotted in a MIF Frame, and several MIF Frames are collected in",
+" one large MIF Frame.  The MIF font used for text is \"Times\".",
+"",
+" Several options may be set in the MIF 3.00 driver.",
+"",
+" Syntax:",
+"       set terminal mif {color | colour | monochrome} {polyline | vectors}",
+"                        {help | ?}",
+"",
+" `colour` plots lines with line types >= 0 in colour (MIF sep. 2--7) and",
+" `monochrome` plots all line types in black (MIF sep. 0).",
+" `polyline` plots curves as continuous curves and `vectors` plots curves as",
+" collections of vectors.",
+" `help` and `?` print online help on standard error output---both print a",
+" short description of the usage; `help` also lists the options.",
+"",
+" Examples:",
+"       set term mif colour polylines    # defaults",
+"       set term mif                     # defaults",
+"       set term mif vectors",
+"       set term mif help"
+END_HELP(mif)
+#endif /* TERM_HELP */