home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / xdvik / psgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-28  |  19.0 KB  |  779 lines

  1. /*
  2.  * Copyright (c) 1994 Paul Vojta.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23.  * SUCH DAMAGE.
  24.  */
  25.  
  26. /*
  27.  * |||    to do:
  28.  *    *interpreter resource
  29.  *    -safer argument
  30.  *    palette resource and arguments
  31.  */
  32.  
  33. #ifdef PS_GS /* whole file */
  34.  
  35. #include "config.h"
  36. #include "kpathsea/c-pathmx.h"
  37. #include <X11/Xatom.h>
  38. #include <sys/time.h> /* for timeval */
  39.  
  40. #include <signal.h>
  41.  
  42. /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
  43. #if !defined(O_NONBLOCK) && defined(O_NDELAY)
  44. #define    O_NONBLOCK O_NDELAY
  45. #endif
  46.  
  47. /* Condition for retrying a write */
  48. #include <errno.h>
  49. #ifdef    EWOULDBLOCK
  50. #ifdef    EAGAIN
  51. #define    AGAIN_CONDITION    (errno == EWOULDBLOCK || errno == EAGAIN)
  52. #else    /* EAGAIN */
  53. #define    AGAIN_CONDITION    (errno == EWOULDBLOCK)
  54. #endif    /* EAGAIN */
  55. #else    /* EWOULDBLOCK */
  56. #ifdef    EAGAIN
  57. #define    AGAIN_CONDITION    (errno == EAGAIN)
  58. #endif    /* EAGAIN */
  59. #endif    /* EWOULDBLOCK */
  60.  
  61.  
  62. #ifdef    STREAMSCONN
  63. #include <poll.h>
  64. #else
  65. #ifdef _AIX
  66. #include <sys/select.h> /* for fd_set stuff on RS/6000 */
  67. #else
  68. #ifdef HAVE_SYS_BSDTYPES_H
  69. #include <sys/bsdtypes.h> /* for fd_set on ISC 4.0 */
  70. #endif /* not <sys/bsdtypes.h> */
  71. #endif /* not _AIX */
  72. #endif /* not STREAMSCONN */
  73.  
  74. #if    HAS_SIGIO
  75. #include <fcntl.h>
  76. #include <signal.h>
  77. #ifndef    FASYNC
  78. #undef    HAS_SIGIO
  79. #define    HAS_SIGIO 0
  80. #endif
  81. #endif
  82.  
  83. #ifdef    VFORK
  84. #if    VFORK == include
  85. #include <vfork.h>
  86. #endif
  87. #else
  88. #define    vfork    fork
  89. #endif
  90.  
  91. extern    _Xconst    char    psheader[];
  92. extern    int        psheaderlen;
  93.  
  94. #define    postscript    resource._postscript
  95. #define    fore_Pixel    resource._fore_Pixel
  96. #define    back_Pixel    resource._back_Pixel
  97.  
  98. /* global procedures (besides initGS) */
  99.  
  100. static    void    toggle_gs ARGS((void));
  101. static    void    destroy_gs ARGS((void));
  102. static    void    interrupt_gs ARGS((void));
  103. static    void    endpage_gs ARGS((void));
  104. static    void    drawbegin_gs ARGS((int, int, char *));
  105. static    void    drawraw_gs ARGS((char *));
  106. static    void    drawfile_gs ARGS((char *));
  107. static    void    drawend_gs ARGS((char *));
  108.  
  109. static    struct psprocs    gs_procs = {
  110.     /* toggle */        toggle_gs,
  111.     /* destroy */        destroy_gs,
  112.     /* interrupt */        interrupt_gs,
  113.     /* endpage */        endpage_gs,
  114.     /* drawbegin */        drawbegin_gs,
  115.     /* drawraw */        drawraw_gs,
  116.     /* drawfile */        drawfile_gs,
  117.     /* drawend */        drawend_gs};
  118.  
  119. static    int    std_in[2];
  120. static    int    std_out[2];
  121.  
  122. #define    GS_in    (std_in[1])
  123. #define    GS_out    (std_out[0])
  124.  
  125. static    char    *argv[]    = {"gs", "-sDEVICE=x11", "-dNOPAUSE", "-q", "-", NULL};
  126.  
  127. static    pid_t        GS_pid;
  128. static    unsigned int    GS_page_w;    /* how big our current page is */
  129. static    unsigned int    GS_page_h;
  130. static    int        GS_mag;        /* magnification currently in use */
  131. static    int        GS_shrink;    /* shrink factor currently in use */
  132. static    Boolean        GS_active;    /* if we've started a page yet */
  133. static    int        GS_pending;    /* number of ack's we're expecting */
  134. static    Boolean        GS_sending;    /* if we're in the middle of send() */
  135. static    Boolean        GS_pending_int;    /* if interrupt rec'd while in send() */
  136.  
  137. static    Atom    gs_atom;
  138. static    Atom    gs_colors_atom;
  139. #define    XtPageOrientationPortrait 0
  140.  
  141. /*
  142.  *    Our replacement for setenv(), which is not available on all systems.
  143.  */
  144.  
  145. #ifndef    HAVE_SETENV    /* define this if you're a performance freak and
  146.                if your system has setenv. */
  147. #define    setenv(var, str, repl)    _setenv(var, str)    /* repl always True */
  148.  
  149. extern    char    **environ;
  150.  
  151. static    void
  152. _setenv(var, str)
  153.     _Xconst    char    *var;
  154.     _Xconst    char    *str;
  155. {
  156.     int        len1;
  157.     int        len2;
  158.     char        *newvar;
  159.     char        **linep;
  160.     static    Boolean    malloced = False;
  161.  
  162.     len1 = strlen(var);
  163.     len2 = strlen(str) + 1;
  164.     newvar = xmalloc((unsigned int) len1 + len2 + 1, "_setenv");
  165.     (void) bcopy(var, newvar, len1);
  166.     newvar[len1++] = '=';
  167.     (void) bcopy(str, newvar + len1, len2);
  168.     for (linep = environ; *linep != NULL; ++linep)
  169.         if (memcmp(*linep, newvar, len1) == 0) {
  170.         *linep = newvar;
  171.         return;
  172.         }
  173.     len1 = linep - environ;
  174.     if (malloced) {
  175.         environ = (char **) realloc((char *) environ,
  176.         (unsigned int) (len1 + 2) * sizeof(char *));
  177.         if (environ == NULL)
  178.         oops("! Cannot allocate %d bytes for string list in _setenv.\n",
  179.             (len1 + 2) * sizeof(char *));
  180.     }
  181.     else {
  182.         linep = (char **) xmalloc((unsigned int)(len1 + 2) * sizeof(char *),
  183.         "string list in _setenv");
  184.         (void) bcopy((char *) environ, (char *) linep,
  185.         len1 * sizeof(char *));
  186.         environ = linep;
  187.         malloced = True;
  188.     }
  189.     environ[len1] = newvar;
  190.     environ[len1 + 1] = NULL;
  191. }
  192.  
  193. #endif    /* HAVE_SETENV */
  194.  
  195. /*
  196.  *    ghostscript I/O code.  This should send PS code to ghostscript,
  197.  *    receive acknowledgements, and receive X events in the meantime.
  198.  *    It also checks for SIGPIPE errors.
  199.  */
  200.  
  201. #ifndef    STREAMSCONN
  202. static    int        numfds;
  203. static    fd_set        readfds;
  204. static    fd_set        writefds;
  205. #define    XDVI_ISSET(a, b, c)    FD_ISSET(a, b)
  206. #else    /* STREAMSCONN */
  207. struct pollfd        fds[3] = {{0, POLLOUT, 0},
  208.                   {0, POLLIN, 0},
  209.                   {0, POLLIN, 0}};
  210. #define    XDVI_ISSET(a, b, c)    (fds[c].revents)
  211. #endif    /* STREAMSCONN */
  212.  
  213. #define    LINELEN    81
  214. static    char    line[LINELEN + 1];
  215. static    char    *linepos    = line;
  216. static    char    ackstr[]    = "\347\310\376";
  217.  
  218. static    void
  219. read_from_gs() {
  220.     int    bytes;
  221.     char    *line_end;
  222.     char    *p;
  223.  
  224.     bytes = read(GS_out, linepos, line + LINELEN - linepos);
  225.     if (bytes < 0) return;
  226.     line_end = linepos + bytes;
  227.     /* Check for ack strings */
  228.     for (p = line; p < line_end - 2; ++p) {
  229.         p = memchr(p, '\347', line_end - p - 2);
  230.         if (p == NULL) break;
  231.         if (memcmp(p, ackstr, 3) == 0) {
  232.         --GS_pending;
  233.         if (debug & DBG_PS)
  234.             Printf("Got GS ack; %d pending.\n", GS_pending);
  235.         if (p > line) {
  236.             *p = '\0';
  237.             Printf("gs: %s\n", line);
  238.         }
  239.         p += 3;
  240.         (void) bcopy(p, line, line_end - p);
  241.         line_end -= p - line;
  242.         linepos = p = line;
  243.         --p;
  244.         }
  245.     }
  246.     for (;;) {
  247.         p = memchr(linepos, '\n', line_end - linepos);
  248.         if (p == NULL) break;
  249.         *p = '\0';
  250.         Printf("gs: %s\n", line);
  251.         ++p;
  252.         (void) bcopy(p, line, line_end - p);
  253.         line_end -= p - line;
  254.         linepos = line;
  255.     }
  256.     linepos = line_end;
  257.     /*
  258.      * Normally we'd hold text until a newline character, but the buffer
  259.      * is full.  So we flush it, being careful not to cut up an ack string.
  260.      */
  261.     if (linepos >= line + LINELEN) {
  262.         p = line + LINELEN;
  263.         if ((*--p != '\347' && *--p != '\347' && *--p != '\347')
  264.             || memcmp(p, ackstr, line + LINELEN - p) != 0)
  265.         p = line + LINELEN;
  266.         *p = '\0';
  267.         Printf("gs: %s\n", line);
  268.         *p = '\347';
  269.         linepos = line;
  270.         while (p < line + LINELEN) *linepos++ = *p++;
  271.     }
  272. }
  273.  
  274. /*
  275.  *    For handling of SIGPIPE signals from send()
  276.  */
  277.  
  278. static    Boolean    sigpipe_error = False;
  279.  
  280. /* ARGSUSED */
  281. static    void
  282. gs_sigpipe_handler(sig, code, scp, addr)
  283.     int    sig;
  284.     int    code;
  285.     struct sigcontext *scp;
  286.     char    *addr;
  287. {
  288.     sigpipe_error = True;
  289. }
  290.  
  291. #ifdef    _POSIX_SOURCE
  292. static    struct sigaction sigpipe_handler_struct;
  293.     /* initialized to {gs_sigpipe_handler, (sigset_t) 0, 0} in initGS */
  294. #endif
  295.  
  296. /*
  297.  *    This actually sends the bytes to ghostscript.
  298.  */
  299.  
  300. static    void
  301. send(cp, len)
  302.     _Xconst    char    *cp;
  303.     int        len;
  304. {
  305.     int    bytes;
  306. #ifdef    _POSIX_SOURCE
  307.     struct sigaction orig;
  308. #else
  309.     void        (*orig)();
  310. #endif
  311. #ifdef    STREAMSCONN
  312.     int    retval;
  313. #endif
  314.  
  315.     if (GS_pid < 0) return;
  316. #ifdef    _POSIX_SOURCE
  317.     (void) sigaction(SIGPIPE, &sigpipe_handler_struct, &orig);
  318. #else
  319.     orig = signal(SIGPIPE, gs_sigpipe_handler);
  320. #endif
  321.     sigpipe_error = False;
  322.     GS_sending = True;
  323.  
  324. #if    HAS_SIGIO
  325.     (void) fcntl(ConnectionNumber(DISP), F_SETFL,
  326.         fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC);
  327. #endif
  328.  
  329. #ifndef    STREAMSCONN
  330.     FD_ZERO(&readfds);
  331.     FD_ZERO(&writefds);
  332. #endif
  333.  
  334.     for (;;) {
  335.  
  336. #ifndef    STREAMSCONN
  337.         FD_SET(ConnectionNumber(DISP), &readfds);
  338.         FD_SET(GS_in, &writefds);
  339.         FD_SET(GS_out, &readfds);
  340.  
  341.         if (select(numfds, &readfds, &writefds, (fd_set *) NULL,
  342.             (struct timeval *) NULL) < 0 && errno != EINTR) {
  343.         perror("select (gs_send)");
  344.         break;
  345.         }
  346. #else    /* STREAMSCONN */
  347.         for (;;) {
  348.         retval = poll(fds, XtNumber(fds), -1);
  349.         if (retval >= 0 || errno != EAGAIN) break;
  350.         }
  351.         if (retval < 0) {
  352.         perror("poll (gs_send)");
  353.         break;
  354.         }
  355. #endif    /* STREAMSCONN */
  356.  
  357.         if (XDVI_ISSET(GS_out, &readfds, 1))
  358.         read_from_gs();
  359.         if (XDVI_ISSET(GS_in, &writefds, 0)) {
  360.         bytes = write(GS_in, cp, len);
  361.         if (bytes == -1) {
  362.             if (!AGAIN_CONDITION) perror("gs_send");
  363.         }
  364.         else {
  365.             cp += bytes;
  366.             len -= bytes;
  367.             if (len == 0) break;
  368.         }
  369.         if (sigpipe_error) break;
  370.         }
  371.         if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
  372.         allow_can = False;
  373.         read_events(False);
  374.         allow_can = True;
  375.         if (GS_pid < 0) break;    /* if timeout occurred */
  376.         }
  377.     }
  378.  
  379. #if    HAS_SIGIO
  380.     (void) fcntl(ConnectionNumber(DISP), F_SETFL,
  381.         fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC);
  382. #endif
  383.  
  384.     /* put back generic handler for SIGPIPE */
  385. #ifdef    _POSIX_SOURCE
  386.     (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
  387. #else
  388.     (void) signal(SIGPIPE, orig);
  389. #endif
  390.     GS_sending = False;
  391.  
  392.     if (sigpipe_error) {
  393.         Fputs("ghostscript died unexpectedly.\n", stderr);
  394.         destroy_gs();
  395.         draw_bbox();
  396.     }
  397.  
  398.     if (GS_pending_int) {
  399.         GS_pending_int = False;
  400.         interrupt_gs();
  401.     }
  402. }
  403.  
  404. /*
  405.  *    Wait for acknowledgement from gs.
  406.  */
  407.  
  408. static    void
  409. waitack(waittime)
  410.     int    waittime;
  411. {
  412.     struct timeval    tv;
  413.     struct timeval    tv2;
  414. #ifndef    STREAMSCONN
  415.     struct timeval    *timeout = (struct timeval *) NULL;
  416. #else
  417.     int        timeout    = -1;
  418.     int        retval;
  419. #endif
  420. #if    HAS_SIGIO
  421.     int        oldflags;
  422. #endif
  423.  
  424.     if (GS_pending == 0) return;
  425. #if    HAS_SIGIO
  426.     oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0);
  427.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC);
  428. #endif
  429.     if (waittime != 0) {
  430.         (void) gettimeofday(&tv, (struct timezone *) NULL);
  431.         tv.tv_sec += waittime;
  432. #ifndef    STREAMSCONN
  433.         timeout = &tv2;
  434. #endif
  435.     }
  436. #ifndef    STREAMSCONN
  437.     FD_ZERO(&readfds);
  438. #endif
  439.     while (GS_pending > 0) {
  440.         if (waittime != 0) {
  441.         (void) gettimeofday(&tv2, (struct timezone *) NULL);
  442. #ifndef    STREAMSCONN
  443.         if (timercmp(&tv2, &tv, >=)) {
  444.             destroy_gs();
  445.             break;
  446.         }
  447.         tv2.tv_sec = tv.tv_sec - tv2.tv_sec;
  448.         tv2.tv_usec = tv.tv_usec + 1000000 - tv2.tv_usec;
  449.         if (tv2.tv_usec >= 1000000) tv2.tv_usec -= 1000000;
  450.         else --tv2.tv_sec;
  451. #else
  452.         timeout = 1000 * (int) (tv.tv_sec - tv2.tv_sec)
  453.             + ((long) tv.tv_usec - (long) tv2.tv_usec) / 1000;
  454.         if (timeout <= 0) {
  455.             destroy_gs();
  456.             break;
  457.         }
  458. #endif
  459.         }
  460. #ifndef    STREAMSCONN
  461.         FD_SET(ConnectionNumber(DISP), &readfds);
  462.         FD_SET(GS_out, &readfds);
  463.         if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL,
  464.             timeout) < 0 && errno != EINTR) {
  465.         perror("select (gs_waitack)");
  466.         break;
  467.         }
  468. #else    /* STREAMSCONN */
  469.         for (;;) {
  470.         retval = poll(fds + 1, XtNumber(fds) - 1, timeout);
  471.         if (retval >= 0 || errno != EAGAIN) break;
  472.         }
  473.         if (retval < 0) {
  474.         perror("poll (gs_waitack)");
  475.         break;
  476.         }
  477. #endif    /* STREAMSCONN */
  478.  
  479.  
  480.         if (XDVI_ISSET(GS_out, &readfds, 1))
  481.         read_from_gs();
  482.         if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
  483.         allow_can = False;
  484.         read_events(False);
  485.         allow_can = True;
  486.         }
  487.     }
  488. #if    HAS_SIGIO
  489.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags);
  490. #endif
  491.     /* If you bail out here, change the call in interrupt_gs(). */
  492. }
  493.  
  494. /*
  495.  *    Fork a process to run ghostscript.  This is done using the
  496.  *    x11 device (which needs to be compiled in).  Normally the x11
  497.  *    device uses ClientMessage events to communicate with the calling
  498.  *    program, but we don't do this.  The reason for using the ClientMessage
  499.  *    events is that otherwise ghostview doesn't know when a non-conforming
  500.  *    postscript program calls showpage.   That doesn't affect us here,
  501.  *    since in fact we disable showpage.
  502.  */
  503.  
  504. Boolean
  505. initGS()
  506. {
  507.     char    buf[100];
  508.         /*
  509.          * This string reads chunks (delimited by %%xdvimark).
  510.          * The first character of a chunk tells whether a given chunk
  511.          * is to be done within save/restore or not.
  512.          * The `H' at the end tells it that the first group is a
  513.          * header; i.e., no save/restore.
  514.          * `execute' is unique to ghostscript.
  515.          */
  516.     static    _Xconst    char    str1[]    = "\
  517. /xdvi$run {{currentfile cvx execute} stopped pop} def \
  518. /xdvi$ack (\347\310\376) def \
  519. /xdvi$dslen countdictstack def \
  520. {currentfile read pop 72 eq \
  521.     {xdvi$run} \
  522.     {xdvi$run \
  523.       clear countdictstack xdvi$dslen sub {end} repeat } \
  524.   ifelse \
  525.   {(%%xdvimark) currentfile =string {readline} stopped \
  526.     {clear $error /newerror false put} {pop eq {exit} if} ifelse }loop \
  527.   flushpage xdvi$ack print flush \
  528. }loop\nH";
  529.     static    _Xconst    char    str2[]    = "matrix currentmatrix \
  530. dup dup 4 get round 4 exch put \
  531. dup dup 5 get round 5 exch put setmatrix\n\
  532. stop\n%%xdvimark\n";
  533.  
  534.     gs_atom = XInternAtom(DISP, "GHOSTVIEW", False);
  535.     /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */
  536.     Sprintf(buf, "%ld %d 0 0 %u %u 72 72",
  537.         None,            /* bpixmap */ 
  538.         XtPageOrientationPortrait,
  539.         GS_page_w = page_w, GS_page_h = page_h);
  540.     XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8,
  541.         PropModeReplace, (unsigned char *) buf, strlen(buf));
  542.  
  543.     gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False);
  544.     Sprintf(buf, "%s %ld %ld", "Color", fore_Pixel, back_Pixel);
  545.     XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8,
  546.         PropModeReplace, (unsigned char *) buf, strlen(buf));
  547.  
  548.     XSync(DISP, False);        /* update the window */
  549.  
  550.     if (xpipe(std_in) != 0 || xpipe(std_out) != 0) {
  551.         perror("pipe");
  552.         return False;
  553.     }
  554.     Fflush(stderr);        /* to avoid double flushing */
  555.     GS_pid = vfork();
  556.     if (GS_pid == 0) {        /* child */
  557.         Sprintf(buf, "%ld", mane.win);
  558.         setenv("GHOSTVIEW", buf, True);
  559.         setenv("DISPLAY", XDisplayString(DISP), True);
  560.         (void) close(std_in[1]);
  561.         (void) dup2(std_in[0], 0);
  562.         (void) close(std_in[0]);
  563.         (void) close(std_out[0]);
  564.         (void) dup2(std_out[1], 1);
  565.         (void) dup2(std_out[1], 2);
  566.         (void) close(std_out[1]);
  567.         (void) execvp(argv[0], argv);
  568.         Fprintf(stderr, "Execvp of %s failed.\n", argv[0]);
  569.         Fflush(stderr);
  570.         _exit(1);
  571.     }
  572.     if (GS_pid == -1) {    /* error */
  573.         perror("vfork");
  574.         return False;
  575.     }
  576.     (void) close(std_in[0]);
  577.     (void) close(std_out[1]);
  578.  
  579.     /* Set std_in for non-blocking I/O */
  580.     (void) fcntl(std_in[1], F_SETFL,
  581.         fcntl(std_in[1], F_GETFL, 0) | O_NONBLOCK);
  582.  
  583. #ifdef    _POSIX_SOURCE
  584.     sigpipe_handler_struct.sa_handler = gs_sigpipe_handler;
  585.     sigemptyset(&sigpipe_handler_struct.sa_mask);
  586. #endif
  587.  
  588. #ifndef    STREAMSCONN
  589.     numfds = ConnectionNumber(DISP);
  590.     if (numfds < std_in[1]) numfds = std_in[1];
  591.     if (numfds < std_out[0]) numfds = std_out[0];
  592.     ++numfds;
  593. #else    /* STREAMSCONN */
  594.     fds[0].fd = std_in[1];
  595.     fds[1].fd = std_out[0];
  596.     fds[2].fd = ConnectionNumber(DISP);
  597. #endif    /* STREAMSCONN */
  598.  
  599.     psp = gs_procs;
  600.     GS_active = GS_sending = GS_pending_int = False;
  601.     GS_pending = 1;
  602.     GS_mag = GS_shrink = -1;
  603.  
  604.     send(str1, sizeof(str1) - 1);
  605.     send(psheader, psheaderlen);
  606.     Sprintf(buf, "[1 0 0 -1 0 %d] concat\n", page_h);
  607.     send(buf, strlen(buf));
  608.     send(str2, sizeof(str2) - 1);
  609.     waitack(0);
  610.  
  611.     if (GS_pid < 0) {        /* if something happened */
  612.         destroy_gs();
  613.         return False;
  614.     }
  615.     if (!postscript) toggle_gs();    /* if we got a 'v' already */
  616.     else {
  617.         canit = True;        /* ||| redraw the page */
  618.         longjmp(canit_env, 1);
  619.     }
  620.     return True;
  621. }
  622.  
  623. static    void
  624. toggle_gs()
  625. {
  626.     if (debug & DBG_PS) Puts("Toggling GS on or off");
  627.     if (postscript) psp.drawbegin = drawbegin_gs;
  628.     else {
  629.         interrupt_gs();
  630.         psp.drawbegin = drawbegin_none;
  631.     }
  632.         
  633. }
  634.  
  635. static    void
  636. destroy_gs()
  637. {
  638.     if (debug & DBG_PS) Puts("Destroying GS process");
  639.     if (linepos > line) {
  640.         *linepos = '\0';
  641.         Printf("gs: %s\n", line);
  642.         linepos = line;
  643.     }
  644.     if (GS_pid >= 0) {
  645.         if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH)
  646.         perror("destroy_gs");
  647.         GS_pid = -1;
  648.     }
  649.     (void) close(GS_in);
  650.     (void) close(GS_out);
  651.     GS_active = GS_sending = GS_pending_int = False;
  652.     GS_pending = 0;
  653. }
  654.  
  655. static    void
  656. interrupt_gs()
  657. {
  658.     static    _Xconst    char    str[]    = " stop\n%%xdvimark\n";
  659.  
  660.     if (debug & DBG_PS) Puts("Running interrupt_gs()");
  661.     if (GS_sending) GS_pending_int = True;
  662.     else {
  663.         if (GS_active) {
  664.         /*
  665.          * ||| what I'd really like to do here is cause gs to execute
  666.          * the interrupt routine in errordict.  But so far (gs 2.6.1)
  667.          * that has not been implemented in ghostscript.
  668.          */
  669.         send(str, sizeof(str) - 1);
  670.         GS_active = False;
  671.         }
  672.         psp.interrupt = NullProc;    /* prevent deep recursion in waitack */
  673.         waitack(5);
  674.         psp.interrupt = interrupt_gs;
  675.     }
  676. }
  677.  
  678. static    void
  679. endpage_gs()
  680. {
  681.     static    _Xconst    char    str[]    = "stop\n%%xdvimark\n";
  682.  
  683.     if (debug & DBG_PS) Puts("Running endpage_gs()");
  684.     if (GS_active) {
  685.         send(str, sizeof(str) - 1);
  686.         GS_active = False;
  687.         waitack(0);
  688.     }
  689. }
  690.  
  691. static    void
  692. drawbegin_gs(xul, yul, cp)
  693.     int    xul, yul;
  694.     char    *cp;
  695. {
  696.     char    buf[100];
  697.     static    _Xconst    char    str[]    = " TeXDict begin\n";
  698.  
  699.     /* check page_w and page_h to see that they haven't increased */
  700.     if (page_w > GS_page_w || page_h > GS_page_h) {
  701.         /* It would be nice if we could just resize the window, but I
  702.          * don't see a convenient way to do that. */
  703.         destroy_gs();
  704.     }
  705.  
  706.     if (GS_pid < 0)
  707.         (void) initGS();
  708.  
  709.     if (!GS_active) {
  710.         if (magnification != GS_mag) {
  711.         Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
  712. end stop\n%%%%xdvimark\n",
  713.             GS_mag = magnification);
  714.         send(buf, strlen(buf));
  715.         ++GS_pending;
  716.         }
  717.         if (mane.shrinkfactor != GS_shrink) {
  718.         Sprintf(buf,
  719.             "H TeXDict begin %d %d div dup \
  720. /Resolution X /VResolution X \
  721. end stop\n%%%%xdvimark\n",
  722.             pixels_per_inch, GS_shrink = mane.shrinkfactor);
  723.         send(buf, strlen(buf));
  724.         ++GS_pending;
  725.         }
  726.         send(str, sizeof(str) - 1);
  727.         GS_active = True;
  728.         ++GS_pending;
  729.     }
  730.  
  731.     /* This allows the X side to clear the page */
  732.     XSync(DISP, False);
  733.  
  734.     Sprintf(buf, "%d %d moveto\n", xul, yul);
  735.     send(buf, strlen(buf));
  736.     if (debug & DBG_PS)
  737.         Printf("drawbegin at %d,%d:  sending `%s'\n", xul, yul, cp);
  738.     send(cp, strlen(cp));
  739. }
  740.  
  741. static    void
  742. drawraw_gs(cp)
  743.     char    *cp;
  744. {
  745.     int    len    = strlen(cp);
  746.  
  747.     if (!GS_active)
  748.         return;
  749.     if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp);
  750.     cp[len] = '\n';
  751.     send(cp, len + 1);
  752. }
  753.  
  754. static    void
  755. drawfile_gs(cp)
  756.     char    *cp;
  757. {
  758.     char    buf[PATH_MAX + 7];
  759.  
  760.     if (!GS_active)
  761.         return;
  762.     if (debug & DBG_PS) Printf("printing file %s\n", cp);
  763.     Sprintf(buf, "(%s)run\n", cp);
  764.     send(buf, strlen(buf));
  765. }
  766.  
  767. static    void
  768. drawend_gs(cp)
  769.     char    *cp;
  770. {
  771.     if (!GS_active)
  772.         return;
  773.     if (debug & DBG_PS) Printf("end ps: %s\n", cp);
  774.     send(cp, strlen(cp));
  775.     send("\n", 1);
  776. }
  777.  
  778. #endif /* PS_GS */
  779.