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 / psnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-28  |  21.2 KB  |  831 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.  * NOTES:
  26.  *    This code was originally written by Ricardo Telichevesky
  27.  *    (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
  28.  *    (lms@rle-vlsi-mit.edu).
  29.  *    It was largely influenced by similar code in the SeeTeX/XTeX
  30.  *    package by Dirk Grunwald (grunwald@colorado.edu).
  31.  */
  32.  
  33. /* ||| To do:
  34.  *    ALWAYS_CLOSE_SERVER_CONNECTION?
  35.  *    Is there some way of interrupting a process?
  36.  *    fork
  37.  *    extra bytes on input
  38.  */
  39.  
  40. #ifdef PS_NEWS /* whole file */
  41.  
  42. #include "config.h"
  43. #include <signal.h>
  44. #include <X11/X.h>
  45. #include <X11/Xlib.h>
  46. #undef SYSV /* To avoid defined SYSV_{WAIT,UCONTEXT} in xview/notify.h.  */
  47. #include <NeWS/psio.h>
  48. #include <xvps/pscanvas.h>
  49.  
  50. /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
  51. #if !defined(O_NONBLOCK) && defined(O_NDELAY)
  52. #define    O_NONBLOCK O_NDELAY
  53. #endif
  54.  
  55. /* Condition for retrying a write */
  56. #include <errno.h>
  57. #ifdef    EWOULDBLOCK
  58. #ifdef    EAGAIN
  59. #define    AGAIN_CONDITION    (errno == EWOULDBLOCK || errno == EAGAIN)
  60. #else    /* EAGAIN */
  61. #define    AGAIN_CONDITION    (errno == EWOULDBLOCK)
  62. #endif    /* EAGAIN */
  63. #else    /* EWOULDBLOCK */
  64. #ifdef    EAGAIN
  65. #define    AGAIN_CONDITION    (errno == EAGAIN)
  66. #endif    /* EAGAIN */
  67. #endif    /* EWOULDBLOCK */
  68.  
  69. #ifdef    STREAMSCONN
  70. #include <poll.h>
  71. #endif
  72.  
  73. #if    HAS_SIGIO
  74. #include <fcntl.h>
  75. #include <signal.h>
  76. #ifndef    FASYNC
  77. #undef    HAS_SIGIO
  78. #define    HAS_SIGIO 0
  79. #endif
  80. #endif
  81.  
  82.  
  83. #define    Fprintf    (void) fprintf
  84.  
  85.  
  86. /* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server
  87.    connection all the time */
  88. #undef    ALWAYS_CLOSE_SERVER_CONNECTION
  89.  
  90.  
  91.         /*
  92.          * Some setup code.
  93.          */
  94. static    _Xconst    char    str0[]    = "\
  95. /OW2? version cvi 2 eq def \
  96. OW2? \
  97. { /setlinewidth { pop } def} \
  98. { /NeWS 3 0 findpackage beginpackage \
  99.   /X11 3 0 findpackage beginpackage} \
  100. ifelse \
  101. currentcanvas /Color get \
  102. currentcanvas /Colormap get getcubedescription null eq and \
  103.    {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped \
  104.     {pop pop pop pop pop} {exit} ifelse \
  105.     2 div cvi dup 1 eq {exit} if} loop pop} \
  106. if\n";
  107.         /*
  108.          * This string reads chunks (delimited by %%xdvimark).
  109.          * The first character of a chunk tells whether a given chunk
  110.          * is to be done within save/restore or not.
  111.          * The `H' at the end tells it that the first group is a
  112.          * header; i.e., no save/restore.
  113.          */
  114. static    _Xconst    char    preamble[]    = "\
  115. /xdvi$line 81 string def \
  116. /xdvi$run {$error null ne {$error /newerror false put} if \
  117.  {currentfile cvx stopped \
  118.  $error null eq {false} {$error /newerror get} ifelse and \
  119.  {handleerror} if} stopped pop} def \
  120. /xdvi$dslen countdictstack def \
  121. {currentfile read not {exit} if 72 eq \
  122.     {xdvi$run} \
  123.     {/xdvi$sav save def xdvi$run \
  124.       clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
  125.   ifelse \
  126.   {(%%xdvimark) currentfile xdvi$line {readline} stopped \
  127.     {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if \
  128.   58 tagprint flush \
  129. }loop\nH";
  130.  
  131. extern    _Xconst    char    psheader[];
  132. extern    int    psheaderlen;
  133.  
  134. static    _Xconst    char    preamble2[]    = " stop\n%%xdvimark\n";
  135. #define    stopstring    preamble2
  136.  
  137. #define    postscript    resource._postscript
  138.  
  139.  
  140. /* global procedures (besides initNeWS) */
  141.  
  142. static    void    toggleNeWS ARGS((void));
  143. static    void    destroyNeWS ARGS((void));
  144. static    void    interruptNeWS ARGS((void));
  145. static    void    endpageNeWS ARGS((void));
  146. static    void    drawbeginNeWS ARGS((Drawable, int, int, int, int, double,
  147.                 char *));
  148. static    void    drawrawNeWS ARGS((char *));
  149. static    void    drawfileNeWS ARGS((char *));
  150. static    void    drawendNeWS ARGS((char *));
  151.  
  152. static    struct psprocs    news_procs = {
  153.     /* toggle */        toggleNeWS,
  154.     /* destroy */        destroyNeWS,
  155.     /* interrupt */        interruptNeWS,
  156.     /* endpage */        endpageNeWS,
  157.     /* drawbegin */        drawbeginNeWS,
  158.     /* drawraw */        drawrawNeWS,
  159.     /* drawfile */        drawfileNeWS,
  160.     /* drawend */        drawendNeWS};
  161.  
  162. /* signal handler to hairy PostScript code */
  163. static void psio_sigpipe_handler();
  164.  
  165. /* define local static variables */
  166. static    int    NeWS_mag;        /* magnification currently in use */
  167. static    int    NeWS_shrink;        /* shrink factor currently in use */
  168. static    Boolean    NeWS_active;        /* if we've started a page yet */
  169. static    int    NeWS_pending;        /* number of ack's we're expecting */
  170. static    int    NeWS_sending;        /* level of nesting in send() */
  171. static    Boolean    NeWS_pending_int;    /* if interrupt rec'd while in send() */
  172. static    Boolean    NeWS_destroyed    = False;
  173.  
  174.  
  175. /*
  176.  *    NeWS I/O code.  This should send PS code to NeWS,
  177.  *    receive acknowledgements, and receive X events in the meantime.
  178.  *    It also checks for SIGPIPE errors.
  179.  */
  180.  
  181. #ifndef    STREAMSCONN
  182. static    int        numfds;
  183. static    fd_set        readfds;
  184. static    fd_set        writefds;
  185. #define    XDVI_ISSET(a, b, c)    FD_ISSET(a, b)
  186. #else    /* STREAMSCONN */
  187. struct pollfd        fds[3] = {{0, POLLOUT, 0},
  188.                   {0, POLLIN, 0},
  189.                   {0, POLLIN, 0}};
  190. #define    XDVI_ISSET(a, b, c)    (fds[c].revents)
  191. #endif    /* STREAMSCONN */
  192.  
  193.  
  194. /*---------------------------------------------------------------------------*
  195.   psio_sigpipe_handler  ()
  196.  
  197.   Arguments: sig, code, scp, addr (see man page for signal)
  198.   Returns: (void)
  199.   Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set.
  200.  
  201.   Description:
  202.   Handler for SIGPIPE error generated by a broken pipe in the connection
  203.   to the NeWS server; this may be duer to some abnormal condition, or some
  204.   hairy PostScript code containing commands not implemented by the server.
  205.  
  206. +----------------------------------------------------------------------------*/
  207.  
  208. static    Boolean    sigpipe_error = False;
  209.  
  210. static    struct sigaction psio_sigpipe_handler_struct;
  211.     /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */
  212.  
  213. /* ARGSUSED */
  214. static    void
  215. psio_sigpipe_handler(sig, code, scp, addr)
  216.     int        sig;
  217.     int        code;
  218.     struct sigcontext *scp;
  219.     char        *addr;
  220. {
  221.     sigpipe_error = True;
  222. }
  223.  
  224.  
  225. /*
  226.  *    read_from_NeWS - This does the actual retrieving of acknowledgements.
  227.  *    If other bytes appear on the file - tough.
  228.  */
  229.  
  230. static    void
  231. read_from_NeWS()
  232. {
  233.     for (;;) {
  234.         int retval;
  235.  
  236.         retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58);
  237.         if (retval == 0) break;
  238.         if (retval < 0) {
  239.         Fprintf(stderr, "ps_checkfor: %d\n", retval);
  240.         return;
  241.         }
  242.         (void) ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58);
  243.         --NeWS_pending;
  244.         if (debug & DBG_PS)
  245.         Printf("Got NeWS ack; %d pending.\n", NeWS_pending);
  246.     }
  247. }
  248.  
  249.  
  250. /*
  251.  *    This actually sends the bytes to NeWS.
  252.  */
  253.  
  254. static    void
  255. send(cp, len)
  256.     _Xconst    char    *cp;
  257.     int        len;
  258. {
  259.     struct sigaction orig;
  260. #ifdef    STREAMSCONN
  261.     int    retval;
  262. #endif
  263.  
  264.     if (PostScript == (PSFILE *) NULL) return;
  265.  
  266.     if (!NeWS_sending) {
  267.         (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
  268.         sigpipe_error = False;
  269.     }
  270.     ++NeWS_sending;
  271.  
  272. #if    HAS_SIGIO
  273.     (void) fcntl(ConnectionNumber(DISP), F_SETFL,
  274.         fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC);
  275. #endif
  276.  
  277. #ifndef    STREAMSCONN
  278.     FD_ZERO(&readfds);
  279.     FD_ZERO(&writefds);
  280. #endif
  281.  
  282.     for (;;) {
  283.  
  284. #ifndef    STREAMSCONN
  285.         FD_SET(ConnectionNumber(DISP), &readfds);
  286.         FD_SET(PostScript->file, &writefds);
  287.         FD_SET(PostScriptInput->file, &readfds);
  288.  
  289.         if (select(numfds, &readfds, &writefds, (fd_set *) NULL,
  290.             (struct timeval *) NULL) < 0 && errno != EINTR) {
  291.         perror("select (NeWS_send)");
  292.         break;
  293.         }
  294. #else    /* STREAMSCONN */
  295.         for (;;) {
  296.         retval = poll(fds, XtNumber(fds), -1);
  297.         if (retval >= 0 || errno != EAGAIN) break;
  298.         }
  299.         if (retval < 0) {
  300.         perror("poll (NeWS_send)");
  301.         break;
  302.         }
  303. #endif    /* STREAMSCONN */
  304.  
  305.         if (XDVI_ISSET(PostScriptInput->file, &readfds, 1))
  306.         read_from_NeWS();
  307.         if (XDVI_ISSET(PostScript->file, &writefds, 0)) {
  308.         int    old_flags;
  309.         int    bytes;
  310.  
  311.         old_flags = fcntl(PostScript->file, F_GETFL, 0);
  312.         if (old_flags < 0) break;
  313.         /* set to be non-blocking */
  314.         if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK)
  315.             < 0)
  316.             break;
  317.         bytes = write(PostScript->file, cp, len);
  318.         if (bytes == -1) {
  319.             if (!AGAIN_CONDITION) perror("psnews_send");
  320.         }
  321.         else {
  322.             cp += bytes;
  323.             len -= bytes;
  324.         }
  325.         if (fcntl(PostScript->file, F_SETFL, old_flags) < 0) break;
  326.         if (len == 0 || sigpipe_error) break;
  327.         }
  328.         if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
  329.         allow_can = False;
  330.         read_events(False);
  331.         allow_can = True;
  332.         if (PostScript == (PSFILE *) NULL) break;    /* if timeout occurred */
  333.         }
  334.     }
  335.  
  336. #if    HAS_SIGIO
  337.     (void) fcntl(ConnectionNumber(DISP), F_SETFL,
  338.         fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC);
  339. #endif
  340.  
  341.     if (--NeWS_sending == 0) {
  342.         /* put back generic handler for SIGPIPE */
  343.         (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
  344.  
  345.         if (sigpipe_error) {
  346.         Fputs("NeWS died unexpectedly.\n", stderr);
  347.         destroyNeWS();
  348.         draw_bbox();
  349.         }
  350.  
  351.         if (NeWS_pending_int) {
  352.         NeWS_pending_int = False;
  353.         interruptNeWS();
  354.         }
  355.     }
  356. }
  357.  
  358. /*
  359.  *    Wait for acknowledgement from NeWS.  With NeWS we have no choice but
  360.  *    to wait (||| I think).
  361.  */
  362.  
  363. static    void
  364. waitack()
  365. {
  366. #ifdef    STREAMSCONN
  367.     int    retval;
  368. #endif
  369. #if    HAS_SIGIO
  370.     int    oldflags;
  371. #endif
  372.  
  373.     if (PostScript == (PSFILE *) NULL) return;
  374.  
  375. #if    HAS_SIGIO
  376.     oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0);
  377.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC);
  378. #endif
  379. #ifndef    STREAMSCONN
  380.     FD_ZERO(&readfds);
  381. #endif
  382.     while (NeWS_pending > 0) {
  383. #ifndef    STREAMSCONN
  384.         FD_SET(ConnectionNumber(DISP), &readfds);
  385.         FD_SET(PostScriptInput->file, &readfds);
  386.         if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL,
  387.             (struct timeval *) NULL) < 0 && errno != EINTR) {
  388.         perror("select (gs_waitack)");
  389.         break;
  390.         }
  391. #else    /* STREAMSCONN */
  392.         for (;;) {
  393.         retval = poll(fds + 1, XtNumber(fds) - 1, -1);
  394.         if (retval >= 0 || errno != EAGAIN) break;
  395.         }
  396.         if (retval < 0) {
  397.         perror("poll (gs_waitack)");
  398.         break;
  399.         }
  400. #endif    /* STREAMSCONN */
  401.  
  402.  
  403.         if (XDVI_ISSET(PostScriptInput->file, &readfds, 1))
  404.         read_from_NeWS();
  405.         if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
  406.         allow_can = False;
  407.         read_events(False);
  408.         allow_can = True;
  409.         if (PostScript == (PSFILE *) NULL) break;    /* if timeout occurred */
  410.         }
  411.     }
  412. #if    HAS_SIGIO
  413.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags);
  414. #endif
  415. }
  416.  
  417.  
  418. /*---------------------------------------------------------------------------*
  419.   initNeWS()
  420.  
  421.   Arguments: None.
  422.   Returns: True if and only if initialization succeeded
  423.   Side-Effects: Static variables may be set.
  424.  
  425.   Description:
  426.   Initializes variables for the application main loop.
  427.  
  428. +----------------------------------------------------------------------------*/
  429.  
  430. Boolean
  431. initNeWS()
  432. {
  433.     static    NeWStoken newstoken;
  434.  
  435.     /* now try to open the connection to the NeWS server */
  436.     if (ps_open_PostScript() == (PSFILE *) NULL)
  437.         return False;
  438.  
  439. #ifndef    STREAMSCONN
  440.     numfds = ConnectionNumber(DISP);
  441.     if (numfds < PostScript->file) numfds = PostScript->file;
  442.     if (numfds < PostScriptInput->file) numfds = PostScriptInput->file;
  443.     ++numfds;
  444. #else    /* STREAMSCONN */
  445.     fds[0].fd = PostScript->file;
  446.     fds[1].fd = PostScriptInput->file;
  447.     fds[2].fd = ConnectionNumber(DISP);
  448. #endif    /* STREAMSCONN */
  449.  
  450.     psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler;
  451.     sigemptyset(&psio_sigpipe_handler_struct.sa_mask);
  452.  
  453.     NeWS_active = NeWS_pending_int = False;
  454.     NeWS_sending = 0;
  455.     NeWS_pending = 1;
  456.  
  457.     ps_flush_PostScript();
  458.     send(str0, sizeof(str0) - 1);
  459.     /* get xid of window, then make this window the NeWS canvas */
  460.     (void) ps_token_from_xid(mane.win, &newstoken);
  461.     if (newstoken != -1) {
  462.         ps_setcanvas(newstoken);
  463.         ps_flush_PostScript();
  464.         send(preamble, sizeof(preamble) - 1);
  465.         send(psheader, psheaderlen);
  466.         send(preamble2, sizeof(preamble2) - 1);
  467.     }
  468.  
  469.     if (NeWS_destroyed) return False;
  470.  
  471.     /* success */
  472.  
  473.     NeWS_mag = NeWS_shrink = -1;
  474.  
  475.     psp = news_procs;
  476.     if (!postscript) toggleNeWS();    /* if we got a 'v' already */
  477.  
  478.     return True;
  479. }
  480.  
  481.  
  482. /*---------------------------------------------------------------------------*
  483.   toggleNeWS()
  484.  
  485.   Arguments: none
  486.   Returns: (void)
  487.   Side-Effects: psp.drawbegin is changed
  488.  
  489.   Description:
  490.   Used to toggle the rendering of PostScript by the NeWS server
  491.  
  492. +----------------------------------------------------------------------------*/
  493.  
  494. static    void
  495. toggleNeWS()
  496. {
  497.     if (postscript) psp.drawbegin = drawbeginNeWS;
  498.     else {
  499.         interruptNeWS();
  500.         psp.drawbegin = drawbegin_none;
  501.     }
  502. }
  503.  
  504.  
  505. /*---------------------------------------------------------------------------*
  506.   destroyNeWS()
  507.  
  508.   Arguments: none
  509.   Returns: (void)
  510.   Side-Effects: the pointer to the NeWS file is nulled
  511.  
  512.   Description:
  513.   Close the connection to the NeWS server; used when rendering is terminated
  514.   in any way.
  515.  
  516. +----------------------------------------------------------------------------*/
  517.  
  518. static    void
  519. destroyNeWS()
  520. {
  521.     psp = no_ps_procs;
  522.     NeWS_destroyed = True;
  523. }
  524.  
  525.  
  526. /*---------------------------------------------------------------------------*
  527.   interruptNeWS()
  528.  
  529.   Arguments: none
  530.   Returns: void
  531.  
  532.   Description:
  533.   Close the connection to the NeWS server; used when rendering is terminated
  534.   because of an interruption in the viewing of the current page.
  535.   ||| It would be nice if we could asynchronously ``wake up'' a NeWS process
  536.   (preferably by sending something along the X socket); then we could do
  537.   better than just to wait.
  538.  
  539. +----------------------------------------------------------------------------*/
  540.  
  541. static    void
  542. interruptNeWS()
  543. {
  544.     if (debug & DBG_PS) Puts("Running interruptNeWS()");
  545.     if (NeWS_sending) NeWS_pending_int = True;
  546.     else {
  547.         if (NeWS_active) {
  548.         send(stopstring, sizeof(stopstring) - 1);
  549.         NeWS_active = False;
  550.         }
  551.         psp.interrupt = NullProc;    /* prevent deep recursion in waitack */
  552.         waitack();
  553.         psp.interrupt = interruptNeWS;
  554.     }
  555. }
  556.  
  557.  
  558. /*---------------------------------------------------------------------------*
  559.   endpageNeWS()
  560.  
  561.   Arguments: none
  562.   Returns: (void)
  563.   Side-Effects: the NeWS_active variable is cleared.
  564.  
  565.   Description:
  566.   Should be called at the end of a page to end this chunk for the NeWS server.
  567.  
  568. +----------------------------------------------------------------------------*/
  569.  
  570. static    void
  571. endpageNeWS()
  572. {
  573.     if (debug & DBG_PS)
  574.         Puts("endpage sent to NeWS Server");
  575.     if (NeWS_active) {
  576.         send(stopstring, sizeof(stopstring) - 1);
  577.         NeWS_active = False;
  578.         waitack();
  579.     }
  580. }
  581.  
  582.  
  583. /*---------------------------------------------------------------------------*
  584.   drawbeginNeWS  ()
  585.  
  586.   Arguments: xul, yul - coordinates of the upper left corner of the figure
  587.          cp - string with the bounding box line data
  588.   Returns: (void)
  589.  
  590.   Description:
  591.   Opens a connection to the NeWS server and send in the preamble and the
  592.   bounding box information after correctly computing resolution factors.
  593.   In case no rendering is to be done, outlines the figure.  An outline is
  594.   also generated whenever the PostScript code is too hairy and generates
  595.   a SIGPIPE signal.
  596.  
  597. +----------------------------------------------------------------------------*/
  598.  
  599. static    void
  600. drawbeginNeWS(xul, yul, cp)
  601.     int        xul, yul;
  602.     char        *cp;
  603. {
  604.     char    buf[100];
  605.     static    _Xconst    char    str[]    = " TeXDict begin\n";
  606.  
  607.     if (debug & DBG_PS) {
  608.         Printf("xul= %d yul= %d\n", xul, yul);
  609.         Printf("String = < %s >\n", cp);
  610.     }
  611.  
  612.     /* catch up on the X side */
  613.     XSync(DISP, 0);
  614.  
  615.     if (!NeWS_active) {
  616.         /* send initialization to NeWS server */
  617.         if (magnification != NeWS_mag) {
  618.         Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
  619. end stop\n%%%%xdvimark\n",
  620.             NeWS_mag = magnification);
  621.         send(buf, strlen(buf));
  622.         ++NeWS_pending;
  623.         }
  624.         if (mane.shrinkfactor != NeWS_shrink) {
  625.         Sprintf(buf, "H TeXDict begin %d %d div dup \
  626. /Resolution X /VResolution X \
  627. end stop\n%%%%xdvimark\n",
  628.             pixels_per_inch, NeWS_shrink = mane.shrinkfactor);
  629.         send(buf, strlen(buf));
  630.         ++NeWS_pending;
  631.         }
  632.         send(str, sizeof(str) - 1);
  633.         NeWS_active = True;
  634.         ++NeWS_pending;
  635.     }
  636.  
  637.     Sprintf(buf, "%d %d moveto\n", xul, yul);
  638.     send(buf, strlen(buf));
  639.     send(cp, strlen(cp));
  640. }
  641.  
  642.  
  643. /*---------------------------------------------------------------------------*
  644.   drawrawNeWS()
  645.  
  646.   Arguments: origcp - the raw string to be sent to the postscript interpreter
  647.   Returns: (void)
  648.   Side-Effects: (none)
  649.  
  650.   Description:
  651.   If there is a valid connection to the NeWS server, just send the string to
  652.   the interpreter, else leave.
  653.  
  654. +----------------------------------------------------------------------------*/
  655.  
  656. static    void
  657. drawrawNeWS(origcp)
  658.     char    *origcp;
  659. {
  660.     char        *pt, *ptm1, *cp1, *ocp1;
  661.     static    char    *cp;
  662.     static    unsigned int cplen = 0;
  663.     unsigned int    len;
  664.     double        angle;
  665.     Boolean        found    = False;
  666.  
  667.     if (!NeWS_active)
  668.         return;
  669.  
  670.     if (debug & DBG_PS)
  671.         Printf("Raw PS sent to context: <%s>\n", origcp);
  672.  
  673.     /* take a look at the string:  NeWS bums on certain rotations */
  674.     len = strlen(origcp) + 4;
  675.     if (cplen < len) {
  676.         if (cplen != 0) free(cp);
  677.         cplen = len;
  678.         cp = xmalloc(cplen, "string in drawrawNeWS");
  679.     }
  680.     ocp1 = origcp;
  681.     pt = origcp;
  682.     while (*pt == ' ' || *pt == '\t') ++pt;
  683.     cp1 = cp;
  684.     for (;;) {
  685.         ptm1 = pt;
  686.         while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
  687.         if (*pt == '\0') break;
  688.         while (*pt == ' ' || *pt == '\t') ++pt;
  689.         if (strncmp(pt, "rotate", 6) == 0
  690.             && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) {
  691.         /* found rotate; check angle */
  692.         if (sscanf(ptm1, "%lf", &angle) >= 1) {
  693.             found = True;
  694.             while (angle > 360.0)
  695.             angle -= 360;
  696.             while (angle < -360.0)
  697.             angle += 360;
  698.             if (angle == 90.0) {
  699.             angle = 89.999;
  700.             (void) memcpy(cp1, ocp1, ptm1 - ocp1);
  701.             cp1 += ptm1 - ocp1;
  702.             Strcpy(cp1, "89.999 rotate ");
  703.             cp1 += strlen(cp1);
  704.             while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
  705.             while (*pt == ' ' || *pt == '\t') ++pt;
  706.             ocp1 = pt;
  707.             } else if (angle == -90.0) {
  708.             angle = -89.999;
  709.             (void) memcpy(cp1, ocp1, ptm1 - ocp1);
  710.             cp1 += ptm1 - ocp1;
  711.             Strcpy(cp1, "-89.999 rotate ");
  712.             cp1 += strlen(cp1);
  713.             while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
  714.             while (*pt == ' ' || *pt == '\t') ++pt;
  715.             ocp1 = pt;
  716.             } else if (angle == 0.0) {
  717.             (void) memcpy(cp1, ocp1, ptm1 - ocp1);
  718.             cp1 += ptm1 - ocp1;
  719.             while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
  720.             while (*pt == ' ' || *pt == '\t') ++pt;
  721.             ocp1 = pt;
  722.             }
  723.         }
  724.         }
  725.     }
  726.     Strcpy(cp1, ocp1);
  727.     if ((debug & DBG_PS) && found) {
  728.         Printf("String is now <%s>\n", cp);
  729.         Printf("Found rotate string.  Angle is %g degrees.\n", angle);
  730.     }
  731.  
  732.     len = strlen(cp);
  733.     cp[len] = '\n';
  734.     send(cp, len + 1);
  735. }
  736.  
  737.  
  738. /*---------------------------------------------------------------------------*
  739.   drawfileNeWS()
  740.  
  741.   Arguments: cp - string with the postscript file pathname
  742.   Returns: (void)
  743.   Side-Effects: none
  744.  
  745.   Description:
  746.   Postscript file containing the figure is opened and sent to the NeWS server.
  747.   Figure is outlined in case hairy code produces a SIGPIPE signal.
  748.  
  749. +----------------------------------------------------------------------------*/
  750.  
  751. static    void
  752. drawfileNeWS(cp)
  753.     char    *cp;
  754. {
  755.     char        buffer[1025];
  756.     int        blen;
  757.     int        bytes;
  758.     FILE        *psfile;
  759.     struct sigaction orig;
  760.  
  761.     if (!NeWS_active)
  762.         return;
  763.  
  764. #ifndef    VMS
  765.     if ((psfile = xfopen(cp, "r")) == NULL)
  766. #else
  767.     if ((psfile = xfopen(cp, "r", "?")) == NULL)
  768. #endif
  769.     {
  770.         Fprintf(stderr,"[%%NeWS Server: cannot access file %s%%]\n", cp);
  771.         draw_bbox();
  772.     } else {
  773.         if (debug & DBG_PS)
  774.         Printf("printing file %s\n", cp);
  775.         /* some hairy PS code generates SIGPIPE signals; handle them */
  776.         (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
  777.         sigpipe_error = False;
  778.         NeWS_sending = 1;
  779.         if (!sigpipe_error)
  780.         for (;;) {
  781.             blen = fread(buffer, sizeof(char), 1024, psfile);
  782.             if (blen == 0) break;
  783.             send(buffer, blen);
  784.             if (sigpipe_error) break;
  785.         }
  786.         (void) fclose(psfile);
  787.  
  788.         --NeWS_sending;
  789.         /* put back generic handler for SIGPIPE */
  790.         (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
  791.  
  792.         if (sigpipe_error) {
  793.         Fputs("NeWS died unexpectedly.\n", stderr);
  794.         destroyNeWS();
  795.         draw_bbox();
  796.         }
  797.  
  798.         if (NeWS_pending_int) {
  799.         NeWS_pending_int = False;
  800.         interruptNeWS();
  801.         }
  802.     }
  803. }
  804.  
  805.  
  806. /*---------------------------------------------------------------------------*
  807.   drawendNeWS()
  808.  
  809.   Arguments: cp - string with indication of the end of the special
  810.   Returns: (void)
  811.  
  812.   Description:
  813.   Sends the indication of end of the figure PostScript code.
  814.  
  815. +----------------------------------------------------------------------------*/
  816.  
  817. static    void
  818. drawendNeWS(cp)
  819.     char    *cp;
  820. {
  821.     if (!NeWS_active)
  822.         return;
  823.  
  824.     if (debug & DBG_PS)
  825.         Puts("drawend sent to NeWS Server");
  826.     send(cp, strlen(cp));
  827.     send("\n", 1);
  828. }
  829.  
  830. #endif /* PS_NEWS */
  831.