Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / pm.trm
diff --git a/term/pm.trm b/term/pm.trm
new file mode 100644 (file)
index 0000000..cd780ec
--- /dev/null
@@ -0,0 +1,1322 @@
+/* Hello, Emacs, this is -*-C-*-
+ * $Id: pm.trm,v 1.53 2006/07/21 02:35:47 sfeam Exp $
+ */
+
+/* GNUPLOT - pm.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.
+]*/
+
+/*
+ *    pm.trm  --- inboard terminal driver for Presentation Manager
+ *            --- after X-11 driver, by R.W.Fearick 31/1/92.
+ *    v1.1 11/8/92 -- speed things up
+ *
+ *    since March 1998: additions for mouse support implemented by Petr Mikulik
+ *      last change: January 2000
+ *      for mouse support, pm.trm has to be compiled with USE_MOUSE, e.g.
+ *      gcc ... -DUSE_MOUSE ...
+ *    January 1999: terminal entries for PM3D functionality by Petr Mikulik
+ */
+
+#include "driver.h"
+
+#ifdef TERM_REGISTER
+register_term(pm)
+#endif
+
+#ifdef TERM_PROTO
+TERM_PUBLIC void PM_init __PROTO((void));
+TERM_PUBLIC void PM_options __PROTO((void));
+TERM_PUBLIC void PM_reset __PROTO((void));
+TERM_PUBLIC void PM_text __PROTO((void));
+TERM_PUBLIC void PM_graphics __PROTO((void));
+TERM_PUBLIC void PM_linetype __PROTO((int lt));
+TERM_PUBLIC void PM_move __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC void PM_vector __PROTO((unsigned int x, unsigned int y));
+TERM_PUBLIC int PM_text_angle __PROTO((int ang));
+TERM_PUBLIC void PM_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC int PM_justify_text __PROTO((enum JUSTIFY mode));
+TERM_PUBLIC void PM_point __PROTO((unsigned int x, unsigned int y, int number));
+TERM_PUBLIC void PM_suspend __PROTO((void));
+TERM_PUBLIC void PM_resume __PROTO((void));
+TERM_PUBLIC void PM_fillbox __PROTO((int style, unsigned int x, unsigned int y, unsigned int w, unsigned int h));
+TERM_PUBLIC void PM_linewidth __PROTO((double linewidth));
+#ifdef USE_MOUSE
+TERM_PUBLIC void PM_set_ruler __PROTO((int, int));
+TERM_PUBLIC void PM_set_cursor __PROTO((int, int, int));
+TERM_PUBLIC void PM_put_tmptext __PROTO((int, const char str[]));
+TERM_PUBLIC void PM_set_clipboard __PROTO((const char[]));
+#endif
+TERM_PUBLIC int PM_make_palette (t_sm_palette *);
+#if 0
+TERM_PUBLIC void PM_previous_palette (void);
+#endif
+TERM_PUBLIC void PM_set_color (t_colorspec *);
+TERM_PUBLIC void PM_filled_polygon (int, gpiPoint *);
+#ifdef WITH_IMAGE
+TERM_PUBLIC void PM_image __PROTO((unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor));
+#endif
+#ifndef PM_OLD_ENHANCED_TEXT
+/* To support "set term pm enhanced" */
+TERM_PUBLIC void PM_enhanced_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
+TERM_PUBLIC void PM_enhanced_open __PROTO((char * fontname, double fontsize,
+                       double base, TBOOLEAN widthflag, TBOOLEAN showflag,
+                       int overprint));
+TERM_PUBLIC void PM_enhanced_flush __PROTO((void));
+#endif
+
+/* define PM world coordinate limits */
+
+#define PM_XMAX 19500
+#define PM_YMAX 12500
+
+/* approximations for typical font/screen sizes */
+#define PM_VCHAR (550)
+#define PM_HCHAR (220)
+/* Note: VCHAR AND HCHAR sizes in gnuplot 3.5 were 415 and 242,
+   in X11 are 500 and 195, respectively.
+*/
+#if 0 /* Sizes of gnuplot 3.6 and 3.7: */
+#  define PM_VTIC (200)
+#  define PM_HTIC (200)
+#else /* Sizes as X11: */
+#  define PM_VTIC (125)
+#  define PM_HTIC (130)
+/* Note: sizes for VTIC and HTIC in gnuplot 3.5 were 122 and 128, respectively.
+*/
+#endif
+
+#endif
+
+#ifdef TERM_BODY
+
+#include <stdio.h>
+#include <process.h>
+#include <io.h>
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSMISC
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#include "os2/pm_msgs.h"
+       
+#define PM_nopts 1
+
+/* path for pm program */
+static char PM_path[256] = "";
+/* track mode to avoid redraw after hitting break */
+static int PM_mode = 0;
+static HEV hev;
+static int PM_termmode = 0;
+static int PM_must_reset_opts = FALSE;
+static int PM_must_abort = 0;
+
+static char PM_opts[256] = "";
+static int PM_optargs = 0;
+static int PM_plot_number = 0;
+static char PM_term_title[128] = "";
+
+static int mouseGnupmdrv = 0; /* PM set to 1 if we are connected to a mouseable gnupmdrv */
+
+static FILE *PM_pipe = NULL;
+static FILE *PM_savepipe = NULL;
+
+
+#ifndef PM_OLD_ENHANCED_TEXT
+
+/* track current state of pm terminal */
+/* this is only needed for enhanced text */
+static char * PM_font = NULL; 
+static double PM_fontsize = 12.0;
+static unsigned int PM_x = 0;
+static unsigned int PM_y = 0;
+static enum JUSTIFY PM_justification = LEFT;
+static double PM_angle = 0.;  /* unit is radian */
+
+/* state variables for enhanced text processing */
+static TBOOLEAN ENHpm_opened_string;
+static TBOOLEAN ENHpm_show = TRUE;
+static int ENHpm_overprint = 0;
+static TBOOLEAN ENHpm_widthflag = TRUE;
+static TBOOLEAN ENHpm_sizeonly = FALSE;
+static double ENHpm_base;
+
+#endif
+
+static void PM_reset_opts(void);
+static void PM_query(void);
+static void PM_make_servername(char *);
+static void PM_abortplot();
+static void PM_query_font(void);
+
+
+TERM_PUBLIC void
+PM_init()
+{
+    static char buffer[1024];
+    int pid;
+    int rc;
+    int spawnmode;
+    PPIB pib;
+    PTIB tib;
+    char semname[32];
+    char pipename[32];
+    char tempname[32];
+
+    term_force_init = TRUE;
+    if (PM_savepipe != NULL && PM_termmode == 0) {
+       PM_pipe = PM_savepipe;
+    }
+    if ((PM_pipe == NULL) && (PM_termmode & 2)) {
+       /* check if term is running */
+       PM_make_servername(tempname);
+       strcpy(pipename, "\\pipe\\");
+       strcat(pipename, tempname);
+/*        sprintf( pipename, "\\pipe\\gpServ%d", PM_plot_number ) ; */
+       DosGetInfoBlocks(&tib, &pib);
+       PM_pipe = fopen(pipename, "r+b");
+       if (PM_pipe != NULL) {
+           setvbuf(PM_pipe, buffer, _IOFBF, 1024);
+           pid = pib->pib_ulpid;
+           fwrite(&pid, 1, 4, PM_pipe);
+           fflush(PM_pipe);
+           /* set new options */
+/*            PM_reset_opts() ; */
+       }
+    }
+    /* else we start up term here */
+    if (PM_pipe == NULL) {
+       if (PM_termmode & 2) {
+           PM_make_servername(tempname);
+/*            sprintf( tempname, "gpServ%d", PM_plot_number ) ; */
+       } else {
+           static int gpid = 0;
+           gpid++;
+           sprintf(tempname, "gp%X%d", getpid(), gpid);
+       }
+       strcpy(semname, "\\sem32\\");
+       strcpy(pipename, "\\pipe\\");
+       strcat(semname, tempname);
+       strcat(pipename, tempname);
+       strcat(PM_path, "\\gnupmdrv.exe");
+       rc = access(PM_path, 0);
+       /* find exe file */
+       if (rc != 0)
+           rc = DosSearchPath(0x0002,  /* search GNUPLOT environment */
+                              "GNUPLOT",
+                              "gnupmdrv.exe",
+                              PM_path,
+                              256);
+
+       if (rc != 0)
+           rc = DosSearchPath(0x0003,  /* then try current directory & path */
+                              "PATH",
+                              "gnupmdrv.exe",
+                              PM_path,
+                              256);
+       if (rc != 0) {
+           fputs("Cannot find gnupmdrv.exe !\n", stderr);
+           exit(3);
+       }
+       rc = DosCreateEventSem(semname, &hev, 1, 0);
+       if (rc != 0) {
+           fputs("Cannot create semaphore !\n", stderr);
+           exit(3);
+       }
+       spawnmode = P_SESSION | P_DEFAULT;
+       if (PM_optargs != 0)
+           spawnmode |= P_UNRELATED;
+       pid = spawnl(spawnmode, PM_path, PM_path, tempname, PM_opts, NULL);
+       if (pid == -1) {
+           fputs("Cannot spawn gnupmdrv.exe !\n", stderr);
+           exit(3);
+       }
+       DosGetInfoBlocks(&tib, &pib);
+       DosWaitEventSem(hev, 10000);
+       DosCloseEventSem(hev);
+       PM_pipe = fopen(pipename, "r+b");
+       if (PM_pipe == NULL) {
+           fputs("Cannot open pipe to gnupmdrv.exe !\n", stderr);
+           exit(3);
+       } else if (PM_termmode == 0)
+           PM_savepipe = PM_pipe;
+       setvbuf(PM_pipe, buffer, _IOFBF, 1024);
+       pid = pib->pib_ulpid;
+       fwrite(&pid, 1, 4, PM_pipe);
+       fflush(PM_pipe);
+    } else {
+       if (PM_must_reset_opts)
+           PM_reset_opts();
+    }
+#ifdef USE_MOUSE
+    /* PM: notify gnupmdrv that this is mouse-enhanced terminal */
+    putc( GR_MOUSECAPABLE, PM_pipe ) ;
+    fflush( PM_pipe ) ;
+    /* we catch mouseable gnupmdrv's answer in PM_query by 0xABCD */
+#endif
+    PM_query();
+}
+
+
+static void
+PM_make_servername(char *str)
+{
+    if (PM_term_title[0]) {
+       int hash = 0;
+       char *p = PM_term_title + 1;
+       int match = PM_term_title[0];
+       while (*p != match) {
+           hash = (hash << 1) + hash + *p++;
+       }
+       hash %= (256 * 256 * 256 - 1);
+       sprintf(str, "gp%x", hash);
+    } else
+       sprintf(str, "gpServ%d", PM_plot_number);
+}
+
+
+TERM_PUBLIC void
+PM_options()
+{
+    int old_termmode = PM_termmode;
+    PM_termmode = 0;
+    term_options[0] = NUL;
+    PM_term_title[0] = NUL;
+    PM_opts[0] = NUL;
+    PM_optargs = 0;
+    while (!END_OF_COMMAND) {
+       if (almost_equals(c_token, "pe$rsist")) {
+           strcat(PM_opts, "-p ");
+           strcat(term_options, "persist ");
+           PM_termmode |= 1;
+           PM_optargs = 1;
+           if (!(old_termmode & 1))
+               PM_pipe = NULL;
+       } else if (almost_equals(c_token, "s$erver")) {
+           strcat(PM_opts, "-s ");
+           strcat(term_options, "server ");
+           PM_termmode |= 2;
+           PM_optargs = 1;
+           if (!(old_termmode & 2))
+               PM_pipe = NULL;
+           if (isanumber(c_token + 1)) {
+               struct value t;
+               char *p = PM_opts + strlen(PM_opts);
+               c_token++;
+               PM_plot_number = (int) real(const_express(&t));
+               sprintf(p, "%d", PM_plot_number);
+               sprintf(term_options + strlen(term_options), "%d", PM_plot_number);
+           }
+       } else if (almost_equals(c_token, "w$idelines")) {
+           strcat(PM_opts, "-w ");
+           strcat(term_options, "widelines ");
+           PM_optargs = 1;
+       } else if (almost_equals(c_token, "e$nhanced")) {
+           strcat(term_options, "enhanced ");
+#ifdef PM_OLD_ENHANCED_TEXT
+           PM_optargs = 1;
+           strcat(PM_opts, "-e ");
+           term->put_text = PM_put_text;
+#else
+           term->put_text = PM_enhanced_put_text;
+#endif
+           term->flags |= TERM_ENHANCED_TEXT;
+       } else if (almost_equals(c_token, "noe$nhanced")) {
+           strcat(term_options, "noenhanced ");
+           term->put_text = PM_put_text;
+           term->flags &= ~TERM_ENHANCED_TEXT;
+       } else if (isstring(c_token)) {
+           copy_str(PM_term_title, c_token, 127);
+       }
+#if 0
+       else if (almost_equals(c_token, "po$rtrait")) {
+           strcat(PM_opts, "-l ");
+           strcat(term_options, "portrait ");
+           PM_optargs = 1;
+       }
+#endif
+       c_token++;
+    }
+    if (PM_term_title[0]) {
+       strcat(PM_opts, " ");
+       strcat(term_options, " ");
+       strcat(PM_opts, PM_term_title);
+       strcat(term_options, PM_term_title);
+    }
+    PM_must_reset_opts = TRUE;
+}
+
+
+static void
+PM_reset_opts()
+{
+    int len;
+    putc(SET_OPTIONS, PM_pipe);
+    len = strlen(PM_opts) + 1;
+    fwrite(&len, sizeof(int), 1, PM_pipe);
+    fwrite(PM_opts, 1, len, PM_pipe);
+    for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
+       /* pad rest of int with zeros */
+       putc(NUL, PM_pipe);
+    }
+    fflush(PM_pipe);
+    PM_must_reset_opts = FALSE;
+}
+
+
+static void
+PM_query()
+{
+    int rc;
+    ULONG cbR;
+    putc(GR_QUERY, PM_pipe);
+    fflush(PM_pipe);
+    rc = DosRead(fileno(PM_pipe), &term->h_char, sizeof(int), &cbR);
+    if (term->h_char == 0xABCD) {
+      /* PM we have got greetings from mouseable gnupmdrv */
+      mouseGnupmdrv = 1; /*  thus set mouseGnupmdrv on and reread h_char */
+      rc = DosRead( fileno(PM_pipe), &term->h_char, sizeof(int), &cbR ) ;
+      }
+    rc = DosRead(fileno(PM_pipe), &term->v_char, sizeof(int), &cbR);
+}
+
+
+# ifdef USE_MOUSE
+/* update menu items in PM terminal */
+void
+PM_update_menu_items()
+{
+    /* connected to a mouseable gnupmdrv */
+    if ((PM_pipe != NULL) && (mouseGnupmdrv)) {
+       struct t_gpPMmenu gpPMmenu;
+
+       PM_set_gpPMmenu(&gpPMmenu);
+       putc(SET_MENU, PM_pipe);
+       fwrite(&gpPMmenu, sizeof(gpPMmenu), 1, PM_pipe);
+    }
+}
+#endif
+
+
+TERM_PUBLIC void
+PM_reset()
+{
+    putc(GR_RESET, PM_pipe);
+    fflush(PM_pipe);
+    term_force_init = FALSE;
+    if (PM_termmode > 0) {
+       fclose(PM_pipe);
+       PM_pipe = NULL;
+    }
+}
+
+
+TERM_PUBLIC void
+PM_suspend()
+{
+    putc(GR_SUSPEND, PM_pipe);
+    fflush(PM_pipe);
+}
+
+
+TERM_PUBLIC void
+PM_resume()
+{
+    putc(GR_RESUME, PM_pipe);
+    fflush(PM_pipe);
+}
+
+
+TERM_PUBLIC void
+PM_text()
+{
+    fflush(PM_pipe);
+    if (PM_mode != SET_TEXT) {
+       putc(SET_TEXT, PM_pipe);
+       fflush(PM_pipe);
+#if 0
+        keep_term_initialised = term_initialised ;
+        term_initialised = FALSE ; /* need to force init */
+#endif
+    }
+
+    PM_mode = SET_TEXT;
+#ifdef USE_MOUSE
+    {
+       /* FIXME 20040712: 'extern' in a source file is always wrong. */
+       extern TBOOLEAN allowmotion;
+       allowmotion = TRUE;
+    }
+#endif
+}
+
+
+TERM_PUBLIC void
+PM_graphics()
+{
+    static int last_encoding = -999;
+    putc(SET_GRAPHICS, PM_pipe);
+    fflush(PM_pipe);
+#ifdef USE_MOUSE
+    PM_update_menu_items();
+#endif
+    if (encoding != last_encoding) {
+       int cp;
+       switch (encoding) {
+           case S_ENC_ISO8859_2: cp = 912; break;
+           case S_ENC_CP437: cp = 437; break;
+           case S_ENC_CP850: cp = 850; break;
+           default: /*  S_ENC_DEFAULT, S_ENC_ISO8859_1 */
+                    cp = 0; break;
+       };
+       putc(SET_SPECIAL, PM_pipe);
+       putc('c', PM_pipe); /*  set codepage */
+       fwrite(&cp, sizeof(int), 1, PM_pipe);
+       fflush(PM_pipe);
+       last_encoding = encoding;
+    }
+    PM_mode = SET_GRAPHICS;
+}
+
+
+TERM_PUBLIC void
+PM_move(unsigned int x, unsigned int y)
+{
+    if (PM_must_abort)
+       PM_abortplot();
+
+    putc(GR_MOVE, PM_pipe);
+    fwrite(&x, sizeof(int), 1, PM_pipe);
+    fwrite(&y, sizeof(int), 1, PM_pipe);
+
+#ifndef PM_OLD_ENHANCED_TEXT
+    /* save current position, only needed for enhanced text */
+    PM_x = x; 
+    PM_y = y;
+#endif
+}
+
+
+TERM_PUBLIC void
+PM_vector(unsigned int x, unsigned int y)
+{
+    if (PM_must_abort)
+       PM_abortplot();
+    putc(GR_DRAW, PM_pipe);
+    fwrite(&x, sizeof(int), 1, PM_pipe);
+    fwrite(&y, sizeof(int), 1, PM_pipe);
+}
+
+
+TERM_PUBLIC void
+PM_linetype(int lt)
+{
+    putc(SET_LINE, PM_pipe);
+    fwrite(&lt, sizeof(int), 1, PM_pipe);
+}
+
+
+TERM_PUBLIC int
+PM_text_angle(int ang)
+{
+    putc(SET_ANGLE, PM_pipe);
+    fwrite(&ang, sizeof(int), 1, PM_pipe);
+#ifndef PM_OLD_ENHANCED_TEXT
+    /* store text angle, only needed for enhanced text */
+    PM_angle = (double)ang * M_PI / 180.;
+#endif
+    return TRUE;
+}
+
+
+TERM_PUBLIC void
+PM_put_text(unsigned int x, unsigned int y, const char *str)
+{
+    int len;
+
+    if (PM_must_abort)
+       PM_abortplot();
+
+#ifdef PM_OLD_ENHANCED_TEXT
+    if (ignore_enhanced_text) {
+       putc(SET_SPECIAL, PM_pipe);
+       putc('e', PM_pipe); /* switch the enhanced mode off */
+       putc('0', PM_pipe);
+    }
+#endif
+
+    putc(GR_TEXT, PM_pipe);
+    fwrite(&x, sizeof(int), 1, PM_pipe);
+    fwrite(&y, sizeof(int), 1, PM_pipe);
+    len = strlen(str) + 1;
+    fwrite(&len, sizeof(int), 1, PM_pipe);
+    fwrite(str, 1, len, PM_pipe);
+    for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
+       /* pad rest of int with zeros */
+       putc(NUL, PM_pipe);
+    }
+
+#ifdef PM_OLD_ENHANCED_TEXT
+    if (ignore_enhanced_text) {
+       putc(SET_SPECIAL, PM_pipe);
+       putc('e', PM_pipe); /* restore the enhanced mode */
+       putc('2', PM_pipe);
+    }
+#endif
+}
+
+
+TERM_PUBLIC int
+PM_justify_text(enum JUSTIFY mode)
+{
+#ifdef PM_OLD_ENHANCED_TEXT
+    if (ignore_enhanced_text) {
+       putc(SET_SPECIAL, PM_pipe);
+       putc('e', PM_pipe); /* switch the enhanced mode off */
+       putc('0', PM_pipe);
+    }
+#endif
+       
+    putc(SET_JUSTIFY, PM_pipe);
+    fwrite(&mode, sizeof(int), 1, PM_pipe);
+
+#ifndef PM_OLD_ENHANCED_TEXT
+    /* store text justification, only needed for enhanced text */
+    PM_justification = mode;
+#else
+    if (ignore_enhanced_text) {
+       putc(SET_SPECIAL, PM_pipe);
+       putc('e', PM_pipe); /* restore the enhanced mode */
+       putc('2', PM_pipe);
+    }
+#endif
+    return TRUE;
+}
+
+
+TERM_PUBLIC int
+PM_set_font(const char *font)
+{
+    unsigned int len;
+
+    putc(SET_FONT, PM_pipe);
+    if (font == NULL)
+        len = 0;
+    else
+        len = strlen(font);
+
+    if (len==0) {
+        fwrite(&len, sizeof(int), 1, PM_pipe);
+    } else {
+        len += 1;
+        fwrite(&len, sizeof(int), 1, PM_pipe);
+        fwrite(font, 1, len, PM_pipe);
+        for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
+           /* pad rest of int with zeros */
+           putc(NUL, PM_pipe);
+        }
+    }
+
+    return TRUE;
+}
+
+
+#ifndef PM_OLD_ENHANCED_TEXT
+
+/* PM_query_font:
+       get current font name and size from gnupmdrv and
+       save them to PM_font and PM_fontsize
+*/
+static void PM_query_font(void)
+{
+    unsigned int len, fontsize;
+    char *newfont;
+    ULONG cbR, rc;
+
+    putc(GR_QUERY_FONT, PM_pipe);
+    fflush(PM_pipe);  
+
+    free( PM_font );
+    rc = DosRead(fileno(PM_pipe), &len, sizeof(int), &cbR);
+    newfont = (char *)malloc( len + 1 ); 
+    rc = DosRead(fileno(PM_pipe), newfont, len*sizeof(char), &cbR);
+    newfont[len] = '\0';
+    
+    PM_font = (char *)malloc( len + 1 ); 
+    sscanf( newfont, "%i.%s", &fontsize, PM_font );
+    PM_fontsize = (double)fontsize;
+    free(newfont);
+}
+
+#endif
+
+
+TERM_PUBLIC void
+PM_point(unsigned int x, unsigned int y, int number)
+/*
+** tell the driver we are plotting a point so it can decide whether to
+** use colour or not
+*/
+{
+    int mode;
+    mode = 1;
+    putc(SET_POINTMODE, PM_pipe);
+    fwrite(&mode, sizeof(int), 1, PM_pipe);
+    do_point(x, y, number);
+    mode = 0;
+    putc(SET_POINTMODE, PM_pipe);
+    fwrite(&mode, sizeof(int), 1, PM_pipe);
+}
+
+
+void
+PM_abortplot(void)
+{
+    PM_must_abort = 0;
+    term_reset();
+    (void) putc('\n', stderr);
+    bail_to_command_line();
+}
+
+
+void
+PM_intc_cleanup(void)
+{
+    if (PM_pipe == NULL || PM_mode == SET_TEXT)
+       PM_abortplot();
+    PM_must_abort = 1;
+}
+
+
+int
+PM_pause(char *str)
+/*
+** pause - using message box on PM screen
+*/
+{
+    int len, rc;
+    ULONG cbR;
+    char buf[256];
+    char *bp;
+
+    if (PM_pipe == NULL)
+       return 2;
+    bp = buf;
+    putc(GR_PAUSE, PM_pipe);
+    len = strlen(str) + 1;
+    fwrite(&len, sizeof(int), 1, PM_pipe);
+    fwrite(str, 1, len, PM_pipe);
+    for (rc = sizeof(int) - len % sizeof(int); rc > 0; rc--) {
+       /* pad rest of int with zeros */
+       putc(NUL, PM_pipe);
+    }
+    fflush(PM_pipe);
+    rc = DosRead(fileno(PM_pipe), &len, sizeof(int), &cbR);
+    return len;
+}
+
+
+TERM_PUBLIC void
+PM_fillbox(int style, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
+{
+    putc(SET_FILLBOX, PM_pipe);
+    fwrite(&style, sizeof(style), 1, PM_pipe);
+    fwrite(&x, sizeof(x), 1, PM_pipe);
+    fwrite(&y, sizeof(y), 1, PM_pipe);
+    fwrite(&w, sizeof(w), 1, PM_pipe);
+    fwrite(&h, sizeof(h), 1, PM_pipe);
+}
+
+
+TERM_PUBLIC void
+PM_linewidth(double linewidth)
+{
+    int lw;
+    lw = linewidth * 100;
+    putc(SET_LINEWIDTH, PM_pipe);
+    fwrite(&lw, sizeof(int), 1, PM_pipe);
+}
+
+
+TERM_PUBLIC int
+PM_make_palette(t_sm_palette * palette)
+{
+    if (palette == NULL) {
+       ULONG rc, cbR;
+       int PM_nColors;
+
+       /* query maximum number of colours in palette */
+       putc(GR_MAKE_PALETTE, PM_pipe);
+       putc(0, PM_pipe);
+       fflush(PM_pipe);
+       rc = DosRead(fileno(PM_pipe), &PM_nColors, sizeof(int), &cbR);
+       return PM_nColors;
+    }
+
+    if (sm_palette.colors > 0) {
+       ULONG *rgbTable;
+       unsigned int i;
+
+       /* Note: gvpm sources have also limit 256, is it limit of PM palette?
+          I suppose yes, thus let colours passed as unsigned char through the pipe.
+          Gray interval [0;1] will be mapped to interval [0;255] whose r,g,b
+          components are mapped by the array below.
+        */
+       putc(GR_MAKE_PALETTE, PM_pipe);
+       putc(1, PM_pipe);
+       rgbTable = (ULONG *) malloc(sizeof(ULONG) * sm_palette.colors);
+       for (i = 0; i < sm_palette.colors; i++) {
+           ULONG r, g, b;
+
+           r = (ULONG) (palette->color[i].r * 255 + 0.5);
+           g = (ULONG) (palette->color[i].g * 255 + 0.5);
+           b = (ULONG) (palette->color[i].b * 255 + 0.5);
+           rgbTable[i] = (r << 16) + (g << 8) + b;     /*  PM API likes this form */
+       }
+       fwrite(&sm_palette.colors, sizeof(int), 1, PM_pipe);
+       fwrite(rgbTable, sizeof(ULONG) * sm_palette.colors, 1, PM_pipe);
+       free(rgbTable);
+    }
+    return 0;
+}
+
+
+#if 0
+/* switch back to the palette used before calling make_palette */
+TERM_PUBLIC void
+PM_previous_palette()
+{
+    putc(GR_RELEASE_PALETTE, PM_pipe);
+}
+#endif
+
+
+TERM_PUBLIC void
+PM_set_color(t_colorspec *colorspec)
+{
+    switch (colorspec->type) {
+    case TC_FRAC:
+       if (sm_palette.colors == 0) {
+           rgb255_color rgb255;
+           unsigned int rgb;
+
+           rgb255maxcolors_from_gray(colorspec->value, &rgb255);
+           rgb = (rgb255.r << 16) + (rgb255.g << 8) + rgb255.b;
+           putc(GR_SET_RGBCOLOR, PM_pipe);
+           fwrite(&rgb, sizeof(int), 1, PM_pipe);
+       } else {
+           unsigned char colorindex;
+
+           /* map [0;1] to interval [0;sm_palette.colors-1] */
+           colorindex = ((colorspec->value * (sm_palette.colors - 1.)) + 0.5);
+           putc(GR_SET_COLOR, PM_pipe);
+           fwrite(&colorindex, sizeof(colorindex), 1, PM_pipe);
+       }
+       break;
+    case TC_LT:
+       PM_linetype(colorspec->lt);
+       break;
+    case TC_RGB:
+       putc(GR_SET_RGBCOLOR, PM_pipe);
+       fwrite(&(colorspec->lt), sizeof(int), 1, PM_pipe);
+       /* fflush(PM_pipe); */ /* FIXME: why should that be necessary? */
+       break;
+    }
+}
+
+
+TERM_PUBLIC void PM_filled_polygon ( int points, gpiPoint *corners )
+{
+    int i;
+    putc(GR_FILLED_POLYGON, PM_pipe);
+    fwrite(&points, sizeof(int), 1, PM_pipe); /*  tell him number of corners */
+    for (i = 0; i < points; i++) {
+       fwrite(&corners[i].x, sizeof(int), 1, PM_pipe);
+       fwrite(&corners[i].y, sizeof(int), 1, PM_pipe);
+    }
+}
+
+
+#ifdef USE_MOUSE
+
+TERM_PUBLIC void
+PM_put_tmptext(int i, const char str[])
+{
+    if (PM_pipe) {
+       putc(PUT_TMPTEXT, PM_pipe);
+       fwrite(&i, sizeof(int), 1, PM_pipe);
+       i = strlen(str) + 1;
+       fwrite(&i, sizeof(int), 1, PM_pipe);
+       fwrite(&str[0], i, 1, PM_pipe);
+       fflush(PM_pipe);
+    }
+}
+
+
+TERM_PUBLIC void
+PM_set_ruler(int x, int y)
+{
+    if (PM_pipe) {
+       putc(SET_RULER, PM_pipe);
+       fwrite(&x, sizeof(int), 1, PM_pipe);
+       fwrite(&y, sizeof(int), 1, PM_pipe);
+       fflush(PM_pipe);
+    }
+}
+
+
+TERM_PUBLIC void
+PM_set_cursor(int c, int x, int y)
+{
+    if (PM_pipe) {
+       putc(SET_CURSOR, PM_pipe);
+       fwrite(&c, sizeof(int), 1, PM_pipe);
+       fwrite(&x, sizeof(int), 1, PM_pipe);
+       fwrite(&y, sizeof(int), 1, PM_pipe);
+       fflush(PM_pipe);
+    }
+}
+
+
+TERM_PUBLIC void
+PM_set_clipboard(const char s[])
+{
+    if (PM_pipe) {
+       int i = strlen(s);
+       putc(SET_CLIPBOARD, PM_pipe);
+       fwrite(&i, sizeof(int), 1, PM_pipe);
+       fwrite(s, i+1, 1, PM_pipe);
+       fflush(PM_pipe);
+    }
+}
+
+#endif /* USE_MOUSE */
+
+
+#ifdef WITH_IMAGE
+
+TERM_PUBLIC void
+PM_image(unsigned int M, unsigned int N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
+{
+    PBYTE rgb_image;
+    unsigned int image_size;
+    unsigned int pad_bytes;
+
+    /* IC_PALETTE and IC_RGB images are converted to a 24bit RGB format
+       suitable for OS/2's presentation manager:
+        - sequence of lines is reversed 
+        - each line starts at a 4 byte boundary
+    */
+
+    /* fprintf(stderr, "PM_image: %i x %i, mode=%s\n", M, N, color_mode==IC_RGB?"IC_RGB":"IC_PALETTE" ); */
+    pad_bytes = (4 - (3 * M) % 4) % 4; /* scan lines start on ULONG boundaries */
+    image_size = (M + pad_bytes ) * N * 3;
+    rgb_image = (PBYTE) gp_alloc(image_size, "PM RGB image");
+
+    if (color_mode == IC_PALETTE) {
+       unsigned int x, y;
+
+       rgb_image += N * (3 * M + pad_bytes);
+       for (y=0; y<N; y++) {
+           rgb_image -= 3 * M + pad_bytes;
+           for(x=0; x<M; x++) {
+               rgb255_color rgb255;
+               rgb255maxcolors_from_gray(*image++, &rgb255);
+               *(rgb_image++) = rgb255.b;
+               *(rgb_image++) = rgb255.g;
+               *(rgb_image++) = rgb255.r;
+           }
+           rgb_image -= 3 * M;
+       }
+    } else if (color_mode == IC_RGB) {
+       unsigned int x, y;
+
+       rgb_image += N * (3 * M + pad_bytes);
+       for (y=0; y<N; y++) {
+           rgb_image -= 3 * M + pad_bytes;
+           for(x=0; x<M; x++) {
+               rgb255_color rgb255;
+               rgb255.r = (BYTE) (*image++ * 255 + 0.5);
+               rgb255.g = (BYTE) (*image++ * 255 + 0.5);
+               rgb255.b = (BYTE) (*image++ * 255 + 0.5);
+               *(rgb_image++) = rgb255.b;
+               *(rgb_image++) = rgb255.g;
+               *(rgb_image++) = rgb255.r;
+           }
+           rgb_image -= 3 * M;
+       }
+    }
+
+    if ((color_mode == IC_PALETTE) || (color_mode == IC_RGB)) {
+       unsigned int i;
+
+       /* transfer data to gnupmdrv */
+       putc(GR_RGB_IMAGE, PM_pipe);
+       fwrite(&M, sizeof(M), 1, PM_pipe);
+       fwrite(&N, sizeof(N), 1, PM_pipe);
+       for (i=0; i<4; i++) {
+           fwrite(&(corner[i].x), sizeof(int), 1, PM_pipe);
+           fwrite(&(corner[i].y), sizeof(int), 1, PM_pipe);
+       }
+       fwrite(&image_size, sizeof(image_size), 1, PM_pipe);
+       fwrite(rgb_image, image_size, 1, PM_pipe);
+       fflush(PM_pipe);
+    }
+
+    free(rgb_image);
+}
+
+#endif /* WITH_IMAGE */
+
+
+#ifndef PM_OLD_ENHANCED_TEXT
+
+TERM_PUBLIC void
+PM_enhanced_open(
+    char *fontname,
+    double fontsize, double base,
+    TBOOLEAN widthflag, TBOOLEAN showflag,
+    int overprint)
+{
+    static const int pm_scale = 35; /* scaling of base offset */  
+    static unsigned int ENHpm_xsave, ENHpm_ysave;
+    char *fontstring;
+
+    /* There are two special cases:
+     * overprint = 3 means save current position
+     * overprint = 4 means restore saved position
+     */
+    if (overprint == 3) {
+       ENHpm_xsave = PM_x;
+       ENHpm_ysave = PM_y;
+       return;
+    } else if (overprint == 4) {
+       PM_x = ENHpm_xsave;
+       PM_y = ENHpm_ysave;
+       return;
+    }
+
+    if (!ENHpm_opened_string) {
+       ENHpm_opened_string = TRUE;
+
+       /* Start new text fragment */
+       enhanced_cur_text = &enhanced_text[0];
+
+       /* Keep track of whether we are supposed to show this string */
+       ENHpm_show = showflag;
+
+       /* 0/1/2  no overprint / 1st pass / 2nd pass */
+       ENHpm_overprint = overprint;
+
+       /* widthflag FALSE means do not update text position after printing */
+       ENHpm_widthflag = widthflag;
+
+       /* Select font */
+       /* FIXME: It would be nice to have fractional font sizes 
+                 for super- and subscripts. */
+       /* FIXME: sometimes fontname has zero length */
+       if ((fontname != NULL) && strlen(fontname) > 0) {
+           fontstring = malloc( strlen(fontname) + 16 );
+           sprintf( fontstring, "%s,%i", fontname, (int)fontsize );
+       }
+       else {
+           fontstring = malloc( strlen(PM_font) + 16 );
+           sprintf( fontstring, "%s,%i", PM_font, (int)fontsize );
+       }
+       PM_set_font( fontstring );
+       free( fontstring );
+       PM_query_font();
+
+       /* Scale fractional font height to vertical units of display */
+       /* FIXME:       
+               Font scaling is not done properly (yet) and will lead to
+               non-optimal results for most font and size selections.
+               The old gnupmdrv code used FONTINFO information for super-
+               and subscripts.
+       */
+       ENHpm_base = pm_scale * base;
+    }
+}
+
+
+TERM_PUBLIC void
+PM_enhanced_flush()
+{
+    static unsigned int ENHpm_xsave, ENHpm_ysave;
+
+    if (ENHpm_opened_string) {
+       int width, height;
+       unsigned int mode;
+       unsigned int x, y, len;
+       ULONG rc, cbR;
+
+       *enhanced_cur_text = '\0';
+       
+       if (PM_must_abort)
+           PM_abortplot();
+
+       /* print the string fragment, perhaps invisibly */
+       /* NB: base expresses offset from current y pos */
+       x = PM_x - ENHpm_base * sin(PM_angle);
+       y = PM_y + ENHpm_base * cos(PM_angle);
+       mode = ((ENHpm_show && !ENHpm_sizeonly) ? 0x01 : 0x00 );
+       len = strlen(enhanced_text) + 1;
+
+       /* send message to gnupmdrv */
+       putc(GR_ENH_TEXT, PM_pipe);
+       fwrite(&x, sizeof(int), 1, PM_pipe);
+       fwrite(&y, sizeof(int), 1, PM_pipe);
+       /* write 'mode indicator' (currently show switch only) */
+       fwrite(&mode, sizeof(int), 1, PM_pipe); 
+       fwrite(&len, sizeof(int), 1, PM_pipe);
+       fwrite(enhanced_text, 1, len, PM_pipe);
+       for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
+           /* pad rest of int with zeros */
+           putc(NUL, PM_pipe);
+       }
+
+       /* answer from gnupmdrv is length of text */
+       fflush(PM_pipe);
+       rc = DosRead(fileno(PM_pipe), &width, sizeof(int), &cbR);
+       rc = DosRead(fileno(PM_pipe), &height, sizeof(int), &cbR);
+
+       /* update drawing position according to len */
+       if (!ENHpm_widthflag) {
+           width = 0; 
+           height = 0;
+       }
+       if (ENHpm_sizeonly) {
+           /* This is the first pass for justified printing.        */
+           /* We just adjust the starting position for second pass. */
+           if (PM_justification == RIGHT) {
+               PM_x -= width;
+               PM_y -= height;
+           }
+           else if (PM_justification == CENTRE) {
+               PM_x -= width / 2;
+               PM_y -= height / 2;
+           }
+           /* nothing to do for LEFT justified text */
+       }
+       else if (ENHpm_overprint == 1) {
+           /* Save current position */
+           ENHpm_xsave = PM_x + width;
+           ENHpm_ysave = PM_y + height;
+           /* First pass of overprint, leave position in center of fragment */
+           PM_x += width / 2;
+           PM_y += height / 2;
+       }
+       else if (ENHpm_overprint == 2) {
+           /* Restore current position,                          */
+           /* this sets the position behind the overprinted text */
+           PM_x = ENHpm_xsave;
+           PM_y = ENHpm_ysave;
+       }
+       else {
+           /* Normal case is to update position to end of fragment */
+           PM_x += width;
+           PM_y += height;
+       }
+
+       ENHpm_opened_string = FALSE;
+    }
+}
+
+
+TERM_PUBLIC void
+PM_enhanced_put_text(unsigned int x, unsigned int y, const char *str)
+{
+    char *original_string = (char *)str;
+    unsigned int pass, num_passes;
+
+    /* If no enhanced text processing is needed, we can use the plain  */
+    /* vanilla put_text() routine instead of this fancy recursive one. */
+    if (ignore_enhanced_text || !strpbrk(str, "{}^_@&~")) {
+       PM_put_text(x,y,str);
+       return;
+    }
+
+    /* Set up global variables needed by enhanced_recursion() */
+    ENHpm_opened_string = FALSE;
+    enhanced_fontscale = 1.0;
+    strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));
+
+    /* Tell the terminal to move the drawing position */
+    /* we store the current position to PM_x and PM_y */
+    PM_x = x; 
+    PM_y = y;
+
+    /* Text justification requires two passes. During the first pass we */
+    /* don't draw anything, we just measure the space it will take.     */
+    /* Without justification one pass is enough                         */
+    if (PM_justification == LEFT) {
+       num_passes = 1;
+    }
+    else {
+       num_passes = 2;
+       ENHpm_sizeonly = TRUE; 
+    }
+
+    for( pass=1; pass <= num_passes; pass++ ) {
+
+       /* This will restore the default font 
+          and update PM_font and PM_fontsize */
+       PM_set_font(NULL); 
+       PM_query_font(); 
+
+       /* Set the recursion going. We say to keep going until a
+       * closing brace, but we don't really expect to find one.
+       * If the return value is not the nul-terminator of the
+       * string, that can only mean that we did find an unmatched
+       * closing brace in the string. We increment past it (else
+       * we get stuck in an infinite loop) and try again.
+       */
+       while (*(str = enhanced_recursion((char *)str, TRUE,
+                       NULL, PM_fontsize,
+                       0.0, TRUE, TRUE, 0))) {
+           (term->enhanced_flush)();
+
+           /* I think we can only get here if *str == '}' */
+           enh_err_check(str);
+
+           if (!*++str)
+               break; /* end of string */
+
+           /* else carry on and process the rest of the string */
+       }
+
+       /* In order to do text justification we need to do a second pass that */
+       /* uses information stored during the first pass.                     */
+       /* see PM_enhanced_flush()                                            */
+       if (pass == 1) {
+           /* do the actual printing in the next pass */
+           ENHpm_sizeonly = FALSE;
+           str = original_string;
+       }
+    }
+
+    /* restore default font */
+    PM_set_font(NULL); 
+}
+
+#endif /* PM_OLD_ENHANCED_TEXT */
+
+
+/* helper function */
+void
+pm_raise_terminal_window()
+{
+    putc(SET_SPECIAL, PM_pipe);
+    putc('^', PM_pipe); /* raise window */
+    fflush(PM_pipe);
+}
+
+void
+pm_lower_terminal_window()
+{
+    putc(SET_SPECIAL, PM_pipe);
+    putc('_', PM_pipe); /* lower window */
+    fflush(PM_pipe);
+}
+
+
+#endif /* TERM_BODY */
+
+#ifdef TERM_TABLE
+TERM_TABLE_START(PM_driver)
+    "pm", "OS/2 Presentation Manager",
+    PM_XMAX, PM_YMAX, PM_VCHAR, PM_HCHAR,
+    PM_VTIC, PM_HTIC, PM_options, PM_init, PM_reset,
+    PM_text, null_scale, PM_graphics, PM_move, PM_vector,
+    PM_linetype, PM_put_text, PM_text_angle,
+    PM_justify_text, PM_point, do_arrow, PM_set_font,
+    0 /*pointsize */ , TERM_CAN_MULTIPLOT|TERM_NO_OUTPUTFILE, 
+    PM_suspend, PM_resume,
+    PM_fillbox, PM_linewidth
+#ifdef USE_MOUSE
+    , 0 /* PM_waitforinput */,
+    PM_put_tmptext, PM_set_ruler, PM_set_cursor, PM_set_clipboard
+#endif
+    , PM_make_palette,
+    0, /* PM_previous_palette */
+    PM_set_color,
+    PM_filled_polygon
+#ifdef WITH_IMAGE
+    , PM_image
+#endif
+#ifndef PM_OLD_ENHANCED_TEXT
+    , PM_enhanced_open, PM_enhanced_flush, do_enh_writec
+#endif
+TERM_TABLE_END(PM_driver)
+
+#undef LAST_TERM
+#define LAST_TERM PM_driver
+
+#endif /* TERM_TABLE */
+
+#ifdef TERM_HELP
+START_HELP(pm)
+"1 pm",
+"?commands set terminal pm",
+"?set terminal pm",
+"?set term pm",
+"?terminal pm",
+"?term pm",
+"?pm",
+" The `pm` terminal driver provides an OS/2 Presentation Manager window in",
+" which the graph is plotted.  The window is opened when the first graph is",
+" plotted.  This window has its own online help as well as facilities for",
+" printing, copying to the clipboard and some line type and color adjustments.",
+" The `multiplot` option is supported.",
+"",
+" Syntax:",
+"       set terminal pm {server {n}} {persist} {widelines} {enhanced} {\"title\"}",
+"",
+" If `persist` is specified, each graph appears in its own window and all",
+" windows remain open after `gnuplot` exits.  If `server` is specified, all",
+" graphs appear in the same window, which remains open when `gnuplot` exits.",
+" This option takes an optional numerical argument which specifies an instance",
+" of the server process.  Thus multiple server windows can be in use at the",
+" same time.",
+"",
+" If `widelines` is specified, all plots will be drawn with wide lines.  If",
+" `enhanced` is specified, sub- and superscripts and multiple fonts are",
+" enabled using the same syntax as the `enhanced postscript` option (see",
+" `set terminal postscript enhanced` for details).  Font names for the basic",
+" PostScript fonts may be abbreviated to single letters.",
+"",
+" If `title` is specified, it will be used as the title of the plot window.",
+" It will also be used as the name of the server instance, and will override",
+" the optional numerical argument.",
+"",
+" Linewidths may be changed with `set linestyle`."
+END_HELP(pm)
+#endif /* TERM_HELP */