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 / psdps.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  16KB  |  629 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. #ifdef PS_DPS /* whole file */
  34.  
  35. #include "config.h"
  36. #include <errno.h>
  37. #include <signal.h>
  38. #include <sys/types.h>
  39. #include <sys/time.h>
  40. #include <X11/X.h>
  41. #include <X11/Xlib.h>
  42. #include <DPS/XDPSlib.h>
  43. #include <DPS/dpsXclient.h>
  44. #include <DPS/dpsexcept.h>
  45. #include <DPS/dpsclient.h>
  46.  
  47. #ifdef    STREAMSCONN
  48. #include <poll.h>
  49. #endif
  50.  
  51. #if    HAS_SIGIO
  52. #include <fcntl.h>
  53. #include <signal.h>
  54. #ifndef    FASYNC
  55. #undef    HAS_SIGIO
  56. #define    HAS_SIGIO 0
  57. #endif
  58. #endif
  59.  
  60. #if !defined (HAVE_ISINF) && defined (HAVE_IEEEFP_H)
  61.  
  62. /* Date: Wed, 23 Nov 1994 11:37:37 -0800
  63. From: Blair Zajac <blair@olympia.gps.caltech.edu>
  64. Subject: Linking Xdvi with libdps on Solaris
  65.  
  66. I just read a posting by Casper Dik, the one who knows all, about linking
  67. against the DPS library (libdps) on Solaris.  The problem is that Sun
  68. compiles its DPS library using their own compilers, and the resulting
  69. library needs the isinf() function, which isn't supplied in any system
  70. library.  This function only comes with the SparcCompilers.  However,
  71. here is a solution to this problem.
  72.  
  73. 5.3) Why do I get isinf undefined when linking with libdps?
  74.  
  75.     That's a bug in libdps.  Sun compiles and links its software
  76.     with its own compilers.  The isinf() function is shipped with
  77.     the SunPRO compilers, but not defined in any Solaris 2.x library.
  78.     
  79.     [The suggested workaround is to use the following code.]  */
  80.  
  81. #include <ieeefp.h>
  82. int
  83. isinf (double x)
  84. {
  85.   return !finite(x) && x==x;
  86. }
  87. #endif /* (not isinf) and (have <ieeefp.h>) */
  88.  
  89.         /*
  90.          * This string reads chunks (delimited by %%xdvimark).
  91.          * The first character of a chunk tells whether a given chunk
  92.          * is to be done within save/restore or not.
  93.          * The `H' at the end tells it that the first group is a
  94.          * header; i.e., no save/restore.
  95.          */
  96. static    char    preamble[]    = "\
  97. /xdvi$line 81 string def \
  98. /xdvi$run {{$error null ne {$error /newerror false put}if \
  99.  currentfile cvx stopped \
  100.  $error null eq {false} {$error /newerror get} ifelse and \
  101.  {handleerror} if} stopped pop} def \
  102. /xdvi$dslen countdictstack def \
  103. {currentfile read not {exit} if 72 eq \
  104.   {xdvi$run} \
  105.   {/xdvi$sav save def xdvi$run \
  106.    clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
  107.  ifelse \
  108.  {(%%xdvimark) currentfile xdvi$line {readline} stopped \
  109.   {clear} {pop eq {exit} if} ifelse }loop \
  110.  (xdvi$Ack\n) print flush \
  111. }loop\nH";
  112.  
  113. extern    char    psheader[];
  114. extern    int    psheaderlen;
  115.  
  116. #define    postscript    resource._postscript
  117.  
  118.  
  119. /* global procedures (besides initDPS) */
  120.  
  121. static    void    toggleDPS ARGS((void));
  122. static    void    destroyDPS ARGS((void));
  123. static    void    interruptDPS ARGS((void));
  124. static    void    endpageDPS ARGS((void));
  125. static    void    drawbeginDPS ARGS((int, int, char *));
  126. static    void    drawrawDPS ARGS((char *));
  127. static    void    drawfileDPS ARGS((char *));
  128. static    void    drawendDPS ARGS((char *));
  129.  
  130. static    struct psprocs    dps_procs = {
  131.     /* toggle */        toggleDPS,
  132.     /* destroy */        destroyDPS,
  133.     /* interrupt */        interruptDPS,
  134.     /* endpage */        endpageDPS,
  135.     /* drawbegin */        drawbeginDPS,
  136.     /* drawraw */        drawrawDPS,
  137.     /* drawfile */        drawfileDPS,
  138.     /* drawend */        drawendDPS};
  139.  
  140. static    DPSContext DPS_ctx = NULL;
  141. static    DPSSpace DPS_space = NULL;
  142. static    int    DPS_mag;        /* magnification currently in use */
  143. static    int    DPS_shrink;        /* shrink factor currently in use */
  144. static    Boolean    DPS_active;        /* if we've started a page */
  145. static    int    DPS_pending;        /* number of ack's we're expecting */
  146.  
  147.  
  148. #if    0
  149. static    void    DPSErrorProcHandler();
  150. #else
  151. #define    DPSErrorProcHandler    DPSDefaultErrorProc
  152. #endif
  153.  
  154.  
  155. static    char    ackstr[]    = "xdvi$Ack\n";
  156.  
  157. #define    LINELEN    21
  158. #define    BUFLEN    (LINELEN + sizeof(ackstr))
  159. static    char    line[BUFLEN + 1];
  160. static    char    *linepos    = line;
  161.  
  162. static    void
  163. TextProc(ctxt, buf, count)
  164.     DPSContext    ctxt;
  165.     char        *buf;
  166.     unsigned long    count;
  167. {
  168.     int    i;
  169.     char    *p;
  170.     char    *p0;
  171.  
  172.     while (count > 0) {
  173.         i = line + BUFLEN - linepos;
  174.         if (i > count) i = count;
  175.         (void) bcopy(buf, linepos, i);
  176.         linepos += i;
  177.         buf += i;
  178.         count -= i;
  179.         p0 = line;
  180.         for (;;) {
  181.         if (p0 >= linepos) {
  182.             linepos = line;
  183.             break;
  184.         }
  185.         p = memchr(p0, '\n', linepos - p0);
  186.         if (p == NULL) {
  187.             if (p0 != line) {
  188.             (void) bcopy(p0, line, linepos - p0);
  189.             linepos -= p0 - line;
  190.             }
  191.             else if (linepos == line + BUFLEN) {
  192.             char    c;
  193.             
  194.             c = line[LINELEN];
  195.             line[LINELEN] = '\0';
  196.             Printf("DPS: %s\n", line);
  197.             line[LINELEN] = c;
  198.             linepos -= LINELEN;
  199.             (void) bcopy(line + LINELEN, line, linepos - line);
  200.             }
  201.             break;
  202.         }
  203.         if (p >= p0 + 8 && memcmp(p - 8, ackstr, 9) == 0) {
  204.             --DPS_pending;
  205.             if (debug & DBG_PS)
  206.             Printf("Got DPS ack; %d pending.\n", DPS_pending);
  207.             ++p;
  208.             (void) bcopy(p, p - 9, linepos - p);
  209.             linepos -= 9;
  210.             continue;
  211.         }
  212.         *p = '\0';
  213.         Printf("DPS: %s\n", p0);
  214.         p0 = p + 1;
  215.         }
  216.     }
  217. }
  218.  
  219.  
  220. /*---------------------------------------------------------------------------*
  221.   waitack()
  222.  
  223.   Arguments: none.
  224.  
  225.   Returns: (void)
  226.  
  227.   Description:
  228.   Waits until the requisite number of acknowledgements has been received from
  229.   the context.
  230.  
  231. +----------------------------------------------------------------------------*/
  232.  
  233. #ifndef    STREAMSCONN
  234. #ifdef _AIX
  235. #include <sys/select.h>
  236. #else
  237. #ifdef HAVE_SYS_BSDTYPES_H
  238. #include <sys/bsdtypes.h> /* for fd_set on ISC 4.0 */
  239. #endif
  240. #endif /* _AIX */
  241. static    fd_set        readfds;
  242. #define    XDVI_ISSET(a, b, c)    FD_ISSET(a, b)
  243. #else    /* STREAMSCONN */
  244. struct pollfd        fds[1] = {{0, POLLIN, 0}};
  245. #define    XDVI_ISSET(a, b, c)    (fds[c].revents)
  246. #endif    /* STREAMSCONN */
  247.  
  248. static    void
  249. waitack()
  250. {
  251. #ifdef    STREAMSCONN
  252.     int        retval;
  253. #endif
  254. #if    HAS_SIGIO
  255.     int        oldflags;
  256. #endif
  257.  
  258. #if    HAS_SIGIO
  259.     oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0);
  260.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC);
  261. #endif
  262. #ifndef    STREAMSCONN
  263.     FD_ZERO(&readfds);
  264. #endif
  265.     while (DPS_pending > 0) {
  266. #ifndef    STREAMSCONN
  267.         FD_SET(ConnectionNumber(DISP), &readfds);
  268.         if (select(ConnectionNumber(DISP) + 1, &readfds, (fd_set *) NULL,
  269.             (fd_set *) NULL, (struct timeval *) NULL) < 0
  270.             && errno != EINTR) {
  271.         perror("select (DPS_waitack)");
  272.         break;
  273.         }
  274. #else    /* STREAMSCONN */
  275.         for (;;) {
  276.         retval = poll(fds, XtNumber(fds), -1);
  277.         if (retval >= 0 || errno != EAGAIN) break;
  278.         }
  279.         if (retval < 0) {
  280.         perror("poll (DPS_waitack)");
  281.         break;
  282.         }
  283. #endif    /* STREAMSCONN */
  284.  
  285.         if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 0)) {
  286.         allow_can = False;
  287.         read_events(False);
  288.         allow_can = True;
  289.         if (DPS_ctx == NULL) break;    /* if interrupt occurred */
  290.         }
  291.     }
  292. #if    HAS_SIGIO
  293.     (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags);
  294. #endif
  295. }
  296.  
  297.  
  298. /*---------------------------------------------------------------------------*
  299.   initDPS()
  300.  
  301.   Arguments: (none)
  302.   Returns: (void)
  303.   Side-Effects: DPS_ctx may be set as well as other static variables.
  304.  
  305.   Description:
  306.   Initializes variables from the application main loop.  Checks to see if
  307.   a connection to the DPS server can be opened.
  308.  
  309. +----------------------------------------------------------------------------*/
  310.  
  311. Boolean
  312. initDPS()
  313. {
  314.   /* now try to create a context */
  315.   DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, ruleGC, 0, 0,
  316.                     TextProc, DPSDefaultErrorProc, NULL);
  317.   if (DPS_ctx == NULL)
  318.     return False;
  319.  
  320.   DPS_space = DPSSpaceFromContext(DPS_ctx);
  321.   DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1);
  322.   DPSWritePostScript(DPS_ctx, psheader, psheaderlen);
  323.   DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
  324.  
  325. #ifdef    STREAMSCONN
  326.     fds[0].fd = ConnectionNumber(DISP);
  327. #endif    /* STREAMSCONN */
  328.  
  329.   DPS_mag = DPS_shrink = -1;
  330.   DPS_active = False;
  331.   DPS_pending = 1;
  332.   DPSFlushContext(DPS_ctx);
  333.   psp = dps_procs;
  334.  
  335.   return True;
  336. }
  337.  
  338.  
  339. /*---------------------------------------------------------------------------*
  340.   toggleDPS()
  341.  
  342.   Arguments: none
  343.   Returns: (void)
  344.   Side-Effects: psp.drawbegin is changed.
  345.  
  346.   Description:
  347.   Used to toggle the rendering of PostScript by the DPS server
  348.  
  349. +----------------------------------------------------------------------------*/
  350.  
  351. static    void
  352. toggleDPS()
  353. {
  354.   if (debug & DBG_PS) Puts("Toggling DPS on or off");
  355.   if (postscript) psp.drawbegin = drawbeginDPS;
  356.   else {
  357.     interruptDPS();
  358.     psp.drawbegin = drawbegin_none;
  359.   }
  360. }
  361.  
  362.  
  363. /*---------------------------------------------------------------------------*
  364.   destroyDPS()
  365.  
  366.   Arguments: none
  367.   Returns: (void)
  368.   Side-Effects: the context is nulled out and destroyed.
  369.  
  370.   Description:
  371.   Close the connection to the DPS server; used when rendering is terminated
  372.   in any way.
  373.  
  374. +----------------------------------------------------------------------------*/
  375.  
  376. static    void
  377. destroyDPS()
  378. {
  379.   if (debug & DBG_PS)
  380.     Puts("Calling destroyDPS()");
  381.   if (linepos > line) {
  382.     *linepos = '\0';
  383.     Printf("DPS: %s\n", line);
  384.   }
  385.   DPSDestroySpace(DPS_space);
  386.   psp = no_ps_procs;
  387. }
  388.  
  389.  
  390. /*---------------------------------------------------------------------------*
  391.   interruptDPS()
  392.  
  393.   Arguments: none
  394.   Returns: (void)
  395.   Side-Effects: the context may be nulled out and destroyed.
  396.  
  397.   Description:
  398.   Close the connection to the DPS server; used when rendering is terminated
  399.   because of an interruption in the viewing of the current page.
  400.  
  401. +----------------------------------------------------------------------------*/
  402.  
  403. static    void
  404. interruptDPS()
  405. {
  406.   if (debug & DBG_PS)
  407.     Puts("Running interruptDPS()");
  408.  
  409.   if (DPS_pending > 0) {
  410.     if (debug & DBG_PS)
  411.       Printf("interruptDPS: code is now %d\n", XDPSGetContextStatus(DPS_ctx));
  412.  
  413.     /*
  414.      * I would really like to use DPSInterruptContext() here, but (at least
  415.      * on an RS6000) I can't get it to work.
  416.      */
  417.  
  418.     DPSDestroyContext(DPS_ctx);
  419.     DPS_ctx = NULL;
  420.     DPS_active = False;
  421.     DPS_pending = 0;
  422.   }
  423. }
  424.  
  425.  
  426. /*---------------------------------------------------------------------------*
  427.   endpageDPS()
  428.  
  429.   Arguments: none
  430.   Returns: (void)
  431.   Side-Effects: the DPS_active variable is cleared.
  432.  
  433.   Description:
  434.   Should be called at the end of a page to end this chunk for the DPS server.
  435.  
  436. +----------------------------------------------------------------------------*/
  437.  
  438. static    void
  439. endpageDPS()
  440. {
  441.   if (DPS_active) {
  442.     if (debug & DBG_PS)
  443.       Puts("Endpage sent to context");
  444.     DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
  445.     DPSFlushContext(DPS_ctx);
  446.     DPS_active = False;
  447.     waitack();
  448.   }
  449. }
  450.  
  451.  
  452. /*---------------------------------------------------------------------------*
  453.   drawbeginDPS  ()
  454.  
  455.   Arguments: xul, yul - coordinates of the upper left corner of the figure
  456.              cp - string with the bounding box line data
  457.   Returns: (void)
  458.   Side-Effects: DPS_ctx is set is set and connection to DPS server is
  459.                 opened.
  460.  
  461.   Description:
  462.   Opens a connection to the DPS server and send in the preamble and the
  463.   bounding box information after correctly computing resolution factors.
  464.   In case no rendering is to be done, outlines the figure.
  465.   An outline is also generated whenever the a context cannot be allocated
  466.  
  467. +----------------------------------------------------------------------------*/
  468.  
  469. static    void
  470. drawbeginDPS(xul, yul, cp)
  471.   int xul, yul;
  472.   char *cp;
  473. {
  474.   /* static char faulty_display_vs[]
  475.    * ="DECWINDOWS DigitalEquipmentCorporation UWS4.2LA"; */
  476.  
  477.   if (debug & DBG_PS)
  478.     Printf("Begin drawing at xul= %d, yul= %d.\n", xul, yul);
  479.  
  480.   /* we assume that I cannot write the file to the postscript context */
  481.   if (DPS_ctx == NULL) {
  482.     DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, ruleGC, 0, 0,
  483.                      TextProc, DPSErrorProcHandler, DPS_space);
  484.     if (DPS_ctx == NULL) {
  485.       psp = no_ps_procs;
  486.       draw_bbox();
  487.       return;
  488.     }
  489.     /* XDPSSetStatusMask(DPS_ctx, PSNEEDSINPUTMASK, 0, 0); */
  490.     DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1);
  491.     /* DPSWritePostScript(DPS_ctx, psheader, psheaderlen); */
  492.     DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
  493.     DPS_mag = DPS_shrink = -1;
  494.     DPS_active = False;
  495.     DPS_pending = 1;
  496.   }
  497.  
  498.   if (!DPS_active) {
  499.     /* send initialization to context */
  500.     if (magnification != DPS_mag) {
  501.     DPSPrintf(DPS_ctx, "H TeXDict begin /DVImag %d 1000 div def \
  502. end stop\n%%%%xdvimark\n",
  503.         DPS_mag = magnification);
  504.     ++DPS_pending;
  505.     }
  506.     if (mane.shrinkfactor != DPS_shrink) {
  507.     DPSPrintf(DPS_ctx, "H TeXDict begin %d %d div dup \
  508. /Resolution X /VResolution X \
  509. end stop\n%%%%xdvimark\n",
  510.         pixels_per_inch, DPS_shrink = mane.shrinkfactor);
  511.     ++DPS_pending;
  512.     }
  513.     DPSPrintf(DPS_ctx, " TeXDict begin\n");
  514.     DPS_active = True;
  515.     ++DPS_pending;
  516.   }
  517.  
  518.   DPSPrintf(DPS_ctx, "%d %d moveto\n", xul, yul);
  519.   DPSPrintf(DPS_ctx, "%s\n", cp);
  520. }
  521.  
  522.  
  523. /*---------------------------------------------------------------------------*
  524.  
  525.   drawrawDPS()
  526.  
  527.   Arguments: cp - the raw string to be sent to the postscript interpreter
  528.   Returns: (void)
  529.   Side-Effects: (none)
  530.  
  531.   Description:
  532.   If there is a valid postscript context, just send the string to the
  533.   interpreter, else leave.
  534.  
  535. +----------------------------------------------------------------------------*/
  536.  
  537. static    void
  538. drawrawDPS(cp)
  539.   char *cp;
  540. {
  541.   if (!DPS_active)
  542.     return;
  543.  
  544.   if (debug & DBG_PS)
  545.     Printf("Sending raw PS to context: %s\n", cp);
  546.  
  547.   read_events(False);
  548.   DPSPrintf(DPS_ctx,"%s\n", cp);
  549. }
  550.  
  551.  
  552. /*---------------------------------------------------------------------------*
  553.   drawfileDPS()
  554.  
  555.   Arguments: cp - string with the postscript file pathname
  556.   Returns: (void)
  557.   Side-Effects: none
  558.  
  559.   Description:
  560.   Postscript file containing the figure is opened and sent to the DPS server.
  561.  
  562. +----------------------------------------------------------------------------*/
  563.  
  564. static    void
  565. drawfileDPS(cp)
  566.   char *cp;
  567. {
  568.   char buffer[1025];
  569.   int blen;
  570.   FILE *psfile;
  571.  
  572.   if (!DPS_active)
  573.     return;
  574.  
  575. #ifndef    VMS
  576.   if ((psfile = xfopen(cp, "r")) == NULL)
  577. #else
  578.   if ((psfile = xfopen(cp, "r", "?")) == NULL)
  579. #endif
  580.   {
  581.     Fprintf(stderr, "[%%Display PostScript: cannot access file %s%%]\n", cp);
  582.   } else {
  583.     if (debug & DBG_PS)
  584.       Printf("sending file %s\n", cp);
  585.     allow_can = False;
  586.     for (;;) {
  587.       read_events(False);
  588.       if (canit || !DPS_active) break;    /* alt_canit is not a factor here */
  589.       blen = fread(buffer, sizeof(char), 1024, psfile);
  590.       if (blen == 0) break;
  591.       DPSWritePostScript(DPS_ctx, buffer, blen);
  592.     }
  593.     fclose(psfile);
  594.     allow_can = True;
  595.     if (canit) {
  596.       interruptDPS();
  597.       longjmp(canit_env, 1);
  598.     }
  599.   }
  600. }
  601.  
  602.  
  603. /*---------------------------------------------------------------------------*
  604.   drawendDPS()
  605.  
  606.   Arguments: cp - string with indication of the end of the special
  607.   Returns: (void)
  608.   Side-Effects: none
  609.  
  610.   Description:
  611.   Sends the indication of end of the figure PostScript code.
  612.  
  613. +----------------------------------------------------------------------------*/
  614.  
  615. static    void
  616. drawendDPS(cp)
  617.   char *cp;
  618. {
  619.   if (!DPS_active)
  620.     return;
  621.  
  622.   if (debug & DBG_PS)
  623.     Printf("End PS: %s\n", cp);
  624.   read_events(False);
  625.   DPSPrintf(DPS_ctx,"%s\n", cp);
  626. }
  627.  
  628. #endif /* PS_DPS */
  629.