Back to index

tetex-bin  3.0
psnews.c
Go to the documentation of this file.
00001 /*========================================================================*\
00002 
00003 Copyright (c) 1994-2004  Paul Vojta
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to
00007 deal in the Software without restriction, including without limitation the
00008 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00009 sell copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00018 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00019 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00020 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00021 OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 NOTES:
00024        This code was originally written by Ricardo Telichevesky
00025        (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
00026        (lms@rle-vlsi-mit.edu).
00027        It was largely influenced by similar code in the SeeTeX/XTeX
00028        package by Dirk Grunwald (grunwald@colorado.edu).
00029 
00030 \*========================================================================*/
00031 
00032 /* ||| To do:
00033  *     ALWAYS_CLOSE_SERVER_CONNECTION?
00034  *     Is there some way of interrupting a process?
00035  *     fork
00036  *     extra bytes on input
00037  */
00038 
00039 #ifdef PS_NEWS       /* whole file */
00040 
00041 #include <signal.h>
00042 #include <sys/file.h>       /* this defines FASYNC */
00043 #include <X11/X.h>
00044 #include <X11/Xlib.h>
00045 #undef SYSV   /* To avoid defined SYSV_{WAIT,UCONTEXT} in xview/notify.h.  */
00046 #include <NeWS/psio.h>
00047 #include <xvps/pscanvas.h>
00048 
00049 /* Condition for retrying a write */
00050 #include <errno.h>
00051 #include <setjmp.h>
00052 
00053 #include "xdvi-config.h"
00054 #include "xdvi.h"
00055 #include "events.h"
00056 #include "dvi-init.h"
00057 #include "dvi-draw.h"
00058 
00059 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
00060 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
00061 #define       O_NONBLOCK O_NDELAY
00062 #endif
00063 
00064 #ifdef X_NOT_STDC_ENV
00065 extern int errno;
00066 #endif
00067 
00068 #ifdef EWOULDBLOCK
00069 #ifdef EAGAIN
00070 #define       AGAIN_CONDITION      (errno == EWOULDBLOCK || errno == EAGAIN)
00071 #else /* EAGAIN */
00072 #define       AGAIN_CONDITION      (errno == EWOULDBLOCK)
00073 #endif /* EAGAIN */
00074 #else /* EWOULDBLOCK */
00075 #ifdef EAGAIN
00076 #define       AGAIN_CONDITION      (errno == EAGAIN)
00077 #endif /* EAGAIN */
00078 #endif /* EWOULDBLOCK */
00079 
00080 #if HAVE_POLL
00081 # include <poll.h>
00082 # define XIO_IN POLLIN
00083 # define XIO_OUT POLLOUT
00084 #else
00085 # define XIO_IN 1
00086 # define XIO_OUT 2
00087 #endif
00088 
00089 
00090 #if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
00091 # define FLAKY_SIGPOLL      1
00092 #endif
00093 
00094 char *strtok(char *, const char *);
00095 
00096 /* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server
00097    connection all the time */
00098 #undef ALWAYS_CLOSE_SERVER_CONNECTION
00099 
00100 
00101 /*
00102  * Some setup code.
00103  */
00104 static const char str0[] =
00105     "/OW2? version cvi 2 eq def "
00106     "OW2? "
00107     "{ /setlinewidth { pop } def} "
00108     "{ /NeWS 3 0 findpackage beginpackage "
00109     "  /X11 3 0 findpackage beginpackage} "
00110     "ifelse "
00111     "currentcanvas /Color get "
00112     "currentcanvas /Colormap get getcubedescription null eq and "
00113     "   {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped "
00114     "    {pop pop pop pop pop} {exit} ifelse "
00115     "    2 div cvi dup 1 eq {exit} if} loop pop} "
00116     "if\n";
00117 /*
00118  * This string reads chunks (delimited by %%xdvimark).
00119  * The first character of a chunk tells whether a given chunk
00120  * is to be done within save/restore or not.
00121  * The `H' at the end tells it that the first group is a
00122  * header; i.e., no save/restore.
00123  */
00124 static const char preamble[] =
00125     "/xdvi$line 81 string def "
00126     "/xdvi$run {$error null ne {$error /newerror false put} if "
00127     " {currentfile cvx stopped "
00128     " $error null eq {false} {$error /newerror get} ifelse and "
00129     " {handleerror} if} stopped pop} def "
00130     "/xdvi$dslen countdictstack def "
00131     "{currentfile read not {exit} if 72 eq "
00132     "    {xdvi$run} "
00133     "    {/xdvi$sav save def xdvi$run "
00134     "      clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} "
00135     "  ifelse "
00136     "  {(%%xdvimark) currentfile xdvi$line {readline} stopped "
00137     "    {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if "
00138     "  58 tagprint flush "
00139     "}loop\nH";
00140 
00141 extern const char psheader[];
00142 extern int psheaderlen;
00143 
00144 static const char preamble2[] = " stop\n%%xdvimark\n";
00145 #define       stopstring    preamble2
00146 
00147 /* global procedures (besides initNeWS) */
00148 
00149 static void toggleNeWS(int flag);
00150 static void destroyNeWS(void);
00151 static void interruptNeWS(void);
00152 static void endpageNeWS(void);
00153 static void drawbeginNeWS(int, int, const char *);
00154 static void drawbeginNeWS_box(int, int, const char *);
00155 static void drawrawNeWS(const char *);
00156 static void drawrawNeWS_box(const char *);
00157 static void drawfileNeWS(const char *, FILE *);
00158 static void drawendNeWS(const char *);
00159 static void beginheaderNeWS(void);
00160 static void endheaderNeWS(void);
00161 static void newdocNeWS(void);
00162 
00163 static struct psprocs news_procs = {
00164     /* toggle */ toggleNeWS,
00165     /* destroy */ destroyNeWS,
00166     /* interrupt */ interruptNeWS,
00167     /* endpage */ endpageNeWS,
00168     /* drawbegin */ drawbeginNeWS,
00169     /* drawraw */ drawrawNeWS,
00170     /* drawfile */ drawfileNeWS,
00171     /* drawend */ drawendNeWS,
00172     /* beginheader */ beginheaderNeWS,
00173     /* endheader */ endheaderNeWS,
00174     /* newdoc */ newdocNeWS
00175 };
00176 
00177 /* define local static variables */
00178 static int NeWS_mag; /* magnification currently in use */
00179 static int NeWS_shrink;     /* shrink factor currently in use */
00180 static unsigned int NeWS_page_w;   /* how big our current page is */
00181 static unsigned int NeWS_page_h;
00182 static Boolean NeWS_active; /* if we've started a page yet */
00183 static int NeWS_pending;    /* number of ack's we're expecting */
00184 static const char *NeWS_send_byte; /* next byte to send to NeWS */
00185 static const char *NeWS_send_end;  /* last + 1 byte to send */
00186 static Boolean NeWS_in_header;     /* if we're sending a header */
00187 static Boolean NeWS_in_doc; /* if we've sent header information */
00188 static int NeWS_ev_mask;    /* events for which we'll stop */
00189 static Boolean NeWS_destroyed = False;
00190 
00191 #define       NEWS_MASK_NORMAL     EV_GE_NEWPAGE
00192 #define       NEWS_MASK_HEADER     EV_GE_PS_TOGGLE
00193 #define       NEWS_MASK_INIT              (EV_GE_TERM | EV_PS_TOGGLE)
00194 
00195 
00196 /*
00197  *     NeWS I/O code.  This should send PS code to NeWS,
00198  *     receive acknowledgements, and receive X events in the meantime.
00199  *     It also checks for SIGPIPE errors.
00200  */
00201 
00202 static void read_from_NeWS(void);
00203 static void write_to_NeWS(void);
00204 
00205 static struct xio    NeWS_xout     = {NULL, 0, XIO_IN,
00206 #if HAVE_POLL
00207     NULL,
00208 #endif
00209     read_from_NeWS, write_to_NeWS};
00210 
00211 static struct xio    NeWS_xin      = {NULL, 0, XIO_IN,
00212 #if HAVE_POLL
00213     NULL,
00214 #endif
00215     read_from_NeWS, NULL};
00216 
00217 
00218 /*---------------------------------------------------------------------------*
00219   psio_sigpipe_handler  ()
00220 
00221   Arguments: sig, code, scp, addr (see man page for signal)
00222   Returns: (void)
00223   Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set.
00224 
00225   Description:
00226   Handler for SIGPIPE error generated by a broken pipe in the connection
00227   to the NeWS server; this may be duer to some abnormal condition, or some
00228   hairy PostScript code containing commands not implemented by the server.
00229 
00230 +----------------------------------------------------------------------------*/
00231 
00232 static Boolean sigpipe_error = False;
00233 
00234 static struct sigaction psio_sigpipe_handler_struct;
00235        /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */
00236 
00237 static RETSIGTYPE
00238 psio_sigpipe_handler(int sig, int code, struct sigcontext *scp, char *addr)
00239 {
00240     sigpipe_error = True;
00241 }
00242 
00243 
00244 /*
00245  *     read_from_NeWS - This does the actual retrieving of acknowledgements.
00246  *     If other bytes appear on the file - tough.
00247  */
00248 
00249 static void
00250 read_from_NeWS(void)
00251 {
00252     for (;;) {
00253        int retval;
00254 
00255        retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58);
00256        if (retval == 0)
00257            break;
00258        if (retval < 0) {
00259            fprintf(stderr, "[xdvik] ps_checkfor: %d\n", retval);
00260            return;
00261        }
00262        (void)ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58);
00263        --NeWS_pending;
00264        if (NeWS_pending == 0)
00265            globals.ev.flags |= EV_ACK;
00266        if (globals.debug & DBG_PS)
00267            printf("Got NeWS ack; %d pending.\n", NeWS_pending);
00268     }
00269 }
00270 
00271 
00272 /*
00273  *     write_to_NeWS - Write to the PostScript interpreter.
00274  */
00275 
00276 static void
00277 write_to_NeWS(void)
00278 {
00279     int       old_flags;
00280     int       bytes;
00281 
00282     old_flags = fcntl(PostScript->file, F_GETFL, 0);
00283     if (old_flags < 0) return;
00284     /* set to be non-blocking */
00285     if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK) < 0)
00286        return;
00287 
00288     for (;;) {
00289        bytes = write(PostScript->file, NeWS_send_byte,
00290               NeWS_send_end - NeWS_send_byte);
00291        if (bytes < 0) {
00292            if (AGAIN_CONDITION)
00293               break;
00294            perror("xdvi NeWS_send");
00295            break;
00296        }
00297        NeWS_send_byte += bytes;
00298        if (NeWS_send_byte == NeWS_send_end) {
00299            NeWS_send_byte = NULL;
00300            NeWS_xout.xio_events &= ~XIO_OUT;
00301 #if HAVE_POLL
00302            /* This check is necessary, since write_to_NeWS can be called
00303               directly. */
00304            if (NeWS_xout.pfd != NULL)
00305               NeWS_xout.pfd->events &= ~POLLOUT;
00306            globals.ev.flags |= EV_ACK;
00307            break;
00308 #endif
00309        }
00310     }
00311 
00312     fcntl(PostScript->file, F_SETFL, old_flags);
00313 }
00314 
00315 
00316 /*
00317  *     Clean up after NeWS_send()
00318  */
00319 
00320 static void
00321 post_send(void)
00322 {
00323     if (sigpipe_error) {
00324        fputs("NeWS died unexpectedly.\n", stderr);
00325        destroyNeWS();
00326        draw_bbox();
00327     }
00328 }
00329 
00330 
00331 /*
00332  *     Main routine for writing to the NeWS interpreter.
00333  */
00334 
00335 static void
00336 NeWS_send(const char *cp, size_t len)
00337 {
00338     struct sigaction orig;
00339 
00340     if (PostScript == (PSFILE *) NULL || (globals.ev.flags & NeWS_ev_mask))
00341        return;
00342 
00343     (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
00344     sigpipe_error = False;
00345 
00346     NeWS_send_byte = cp;
00347     NeWS_send_end = cp + len;
00348     NeWS_xout.xio_events |= XIO_OUT;
00349 #if HAVE_POLL
00350     if (NeWS_xout.pfd != NULL)
00351        NeWS_xout.pfd->events |= POLLOUT;
00352 #endif
00353 
00354     write_to_NeWS();
00355     (void) read_events(NeWS_ev_mask | EV_ACK);
00356 
00357     if (!(globals.ev.flags & EV_ACK)) {   /* if interrupted */
00358        /* ||| Do somthing more severe here */
00359     }
00360 
00361     globals.ev.flags &= ~EV_ACK;
00362 
00363     /* put back generic handler for SIGPIPE */
00364     (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
00365 
00366     if (!NeWS_in_header)
00367        post_send();
00368 }
00369 
00370 /*
00371  *     Wait for acknowledgement from NeWS.  With NeWS we have no choice but
00372  *     to wait (||| I think).
00373  */
00374 
00375 static void
00376 waitack(void)
00377 {
00378     if (PostScript == (PSFILE *) NULL)
00379        return;
00380 
00381     if (NeWS_pending > 0)
00382        (void) read_events(EV_GE_ACK);
00383 
00384     if (globals.ev.flags & EV_ACK) {
00385        globals.ev.flags &= ~EV_ACK;
00386        return;
00387     }
00388 
00389     /* ||| Do something more serious here */
00390 }
00391 
00392 
00393 /*---------------------------------------------------------------------------*
00394   initNeWS()
00395 
00396   Arguments: None.
00397   Returns: True if and only if initialization succeeded
00398   Side-Effects: Static variables may be set.
00399 
00400   Description:
00401   Initializes variables for the application main loop.
00402 
00403 +----------------------------------------------------------------------------*/
00404 
00405 Boolean initNeWS()
00406 {
00407     static NeWStoken newstoken;
00408 
00409     /* now try to open the connection to the NeWS server */
00410     if (ps_open_PostScript() == (PSFILE *) NULL)
00411        return False;
00412 
00413     psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler;
00414     sigemptyset(&psio_sigpipe_handler_struct.sa_mask);
00415 
00416 #if !FLAKY_SIGPOLL
00417     if (fcntl(PostScript->file, F_SETOWN, getpid()) == -1)
00418        perror("xdvi: fcntl F_SETOWN");
00419     if (fcntl(PostScript->file, F_SETFL,
00420               fcntl(PostScript->file, F_GETFL, 0) | FASYNC) == -1)
00421        perror("xdvi: fcntl F_SETFL");
00422 #endif /* not FLAKY_SIGPOLL */
00423     if (PostScriptInput->file != PostScript->file) {
00424 #if !FLAKY_SIGPOLL
00425        if (fcntl(PostScriptInput->file, F_SETOWN, getpid()) == -1)
00426            perror("xdvi: fcntl F_SETOWN");
00427        if (fcntl(PostScriptInput->file, F_SETFL,
00428                   fcntl(PostScriptInput->file, F_GETFL, 0) | FASYNC) == -1)
00429            perror("xdvi: fcntl F_SETFL");
00430 #endif /* not FLAKY_SIGPOLL */
00431        NeWS_xout.xio_events &= ~XIO_IN;
00432        NeWS_xin.fd = PostScriptInput->file;
00433        set_io(&NeWS_xin);
00434     }
00435     NeWS_xout.fd = PostScript->file;
00436     set_io(&NeWS_xout);
00437 
00438     NeWS_active = False;
00439     NeWS_in_header = True;
00440     NeWS_ev_mask = NEWS_MASK_INIT;
00441     NeWS_pending = 1;
00442 
00443     ps_flush_PostScript();
00444     NeWS_send(str0, (sizeof str0) - 1);
00445     /* get xid of window, then make this window the NeWS canvas */
00446     (void)ps_token_from_xid(mane.win, &newstoken);
00447     if (newstoken != -1) {
00448        ps_setcanvas(newstoken);
00449        ps_flush_PostScript();
00450 
00451        NeWS_send(preamble, (sizeof preamble) - 1);
00452        NeWS_send(psheader, psheaderlen);
00453        NeWS_send(preamble2, (sizeof preamble2) - 1);
00454        NeWS_in_header = False;
00455        post_send();
00456        waitack();
00457     }
00458 
00459     if (NeWS_destroyed)
00460        return False;
00461 
00462     /* success */
00463 
00464     NeWS_mag = NeWS_shrink = -1;
00465     NeWS_page_w = globals.page.w;
00466     NeWS_page_h = globals.page.h;
00467 
00468     psp = news_procs;
00469     if (!resource.postscript)
00470        toggleNeWS(0);       /* if we got a 'v' already */
00471 
00472     return True;
00473 }
00474 
00475 
00476 /*---------------------------------------------------------------------------*
00477   toggleNeWS(int flag)
00478 
00479   Arguments: flag for toggling PostScript
00480   Returns: (void)
00481   Side-Effects: psp.drawbegin is changed
00482 
00483   Description:
00484   Used to toggle the rendering of PostScript by the NeWS server
00485   Callable from within read_events().
00486 
00487 +----------------------------------------------------------------------------*/
00488 
00489 static void
00490 toggleNeWS(int flag)
00491 {
00492     if (globals.debug & DBG_PS)
00493        fprintf(stdout, "Toggling NeWS to %d", flag);
00494 
00495     switch (flag) {
00496     case 0:
00497        psp.drawbegin = drawbegin_none;
00498        break;
00499     case 1:
00500        psp.drawbegin = drawbeginNeWS;
00501        break;
00502     default:
00503        psp.drawbegin = drawbeginNeWS_box;
00504        break;
00505     }
00506 }
00507 
00508 
00509 /*---------------------------------------------------------------------------*
00510   destroyNeWS()
00511 
00512   Arguments: none
00513   Returns: (void)
00514   Side-Effects: the pointer to the NeWS file is nulled
00515 
00516   Description:
00517   Close the connection to the NeWS server; used when rendering is terminated
00518   in any way.
00519 
00520 +----------------------------------------------------------------------------*/
00521 
00522 static void
00523 destroyNeWS(void)
00524 {
00525     psp = no_ps_procs;
00526     NeWS_destroyed = True;
00527     scanned_page = scanned_page_ps = scanned_page_reset;
00528 }
00529 
00530 
00531 /*---------------------------------------------------------------------------*
00532   interruptNeWS()
00533 
00534   Arguments: none
00535   Returns: void
00536 
00537   Description:
00538   Close the connection to the NeWS server; used when rendering is terminated
00539   because of an interruption in the viewing of the current page.
00540   ||| It would be nice if we could asynchronously ``wake up'' a NeWS process
00541   (preferably by sending something along the X socket); then we could do
00542   better than just to wait.
00543 
00544 +----------------------------------------------------------------------------*/
00545 
00546 static void
00547 interruptNeWS(void)
00548 {
00549     if (globals.debug & DBG_PS)
00550        puts("Running interruptNeWS()");
00551     if (NeWS_pending <= 0) return; /* if nothing to do */
00552 
00553     if (NeWS_active) {
00554        NeWS_send(stopstring, (sizeof stopstring) - 1);
00555        NeWS_active = False;
00556     }
00557 
00558     for (;;) {
00559        ps_flush_PostScript();
00560        if (NeWS_pending <= 0) break;
00561        waitack();
00562     }
00563 }
00564 
00565 
00566 /*---------------------------------------------------------------------------*
00567   endpageNeWS()
00568 
00569   Arguments: none
00570   Returns: (void)
00571   Side-Effects: the NeWS_active variable is cleared.
00572 
00573   Description:
00574   Should be called at the end of a page to end this chunk for the NeWS server.
00575 
00576 +----------------------------------------------------------------------------*/
00577 
00578 static void
00579 endpageNeWS(void)
00580 {
00581     if (globals.debug & DBG_PS)
00582        puts("endpage sent to NeWS Server");
00583     if (NeWS_active) {
00584        NeWS_send(stopstring, (sizeof stopstring) - 1);
00585        NeWS_active = False;
00586        waitack();
00587     }
00588 }
00589 
00590 
00591 /*---------------------------------------------------------------------------*
00592   drawbeginNeWS  ()
00593 
00594   Arguments: xul, yul - coordinates of the upper left corner of the figure
00595             cp - string with the bounding box line data
00596   Returns: (void)
00597 
00598   Description:
00599   Opens a connection to the NeWS server and send in the preamble and the
00600   bounding box information after correctly computing resolution factors.
00601   In case no rendering is to be done, outlines the figure.  An outline is
00602   also generated whenever the PostScript code is too hairy and generates
00603   a SIGPIPE signal.
00604 
00605 +----------------------------------------------------------------------------*/
00606 
00607 static void
00608 drawbeginNeWS(int xul, int yul, const char *cp)
00609 {
00610     char buf[100];
00611     static const char str[] = " TeXDict begin\n";
00612     static const char str2[] = "Hinitgraphics stop\n%%xdvimark\n";
00613 
00614     if (globals.debug & DBG_PS) {
00615        printf("xul= %d yul= %d\n", xul, yul);
00616        printf("String = < %s >\n", cp);
00617     }
00618 
00619     /* catch up on the X side */
00620     XSync(DISP, False);
00621 
00622     if (!NeWS_active) {
00623        /* send initialization to NeWS server */
00624        if (NeWS_page_w < globals.page.w || NeWS_page_h < globals.page.h) {
00625            if (globals.ev.flags & NEWS_MASK_NORMAL)
00626               longjmp(globals.ev.canit, 1);
00627            ++NeWS_pending;
00628            NeWS_page_w = globals.page.w;
00629            NeWS_page_h = globals.page.h;
00630            NeWS_send(str2, (sizeof str2) - 1);
00631        }
00632        if (magnification != NeWS_mag) {
00633            if (globals.ev.flags & NEWS_MASK_NORMAL)
00634               longjmp(globals.ev.canit, 1);
00635            ++NeWS_pending;
00636            sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def "
00637                   "end stop\n%%%%xdvimark\n",
00638                   NeWS_mag = magnification);
00639            NeWS_send(buf, strlen(buf));
00640        }
00641        if (mane.shrinkfactor != NeWS_shrink) {
00642            if (globals.ev.flags & NEWS_MASK_NORMAL)
00643               longjmp(globals.ev.canit, 1);
00644            ++NeWS_pending;
00645            sprintf(buf, "H TeXDict begin %d %d div dup "
00646                   "/Resolution X /VResolution X "
00647                   "end stop\n%%%%xdvimark\n",
00648                   resource.pixels_per_inch,
00649                   NeWS_shrink = mane.shrinkfactor);
00650            NeWS_send(buf, strlen(buf));
00651        }
00652        if (globals.ev.flags & NEWS_MASK_NORMAL)
00653            longjmp(globals.ev.canit, 1);
00654        ++NeWS_pending;
00655        NeWS_send(str, (sizeof str) - 1);
00656        NeWS_active = True;
00657     }
00658 
00659     sprintf(buf, "%d %d moveto\n", xul, yul);
00660     NeWS_send(buf, strlen(buf));
00661     NeWS_send(cp, strlen(cp));
00662 }
00663 
00664 static void
00665 drawbeginNeWS_box(int xul, int yul, const char *cp)
00666 {
00667     drawbeginNeWS(xul, yul, cp);
00668     draw_bbox();
00669 }
00670 
00671 
00672 /*---------------------------------------------------------------------------*
00673   drawrawNeWS()
00674 
00675   Arguments: origcp - the raw string to be sent to the postscript interpreter
00676   Returns: (void)
00677   Side-Effects: (none)
00678 
00679   Description:
00680   If there is a valid connection to the NeWS server, just send the string to
00681   the interpreter, else leave.
00682 
00683 +----------------------------------------------------------------------------*/
00684 
00685 static void
00686 drawrawNeWS(const char *origcp)
00687 {
00688     const char *pt, *ptm1, *ocp1;
00689     static char *cp;
00690     char *cp1;
00691     static unsigned int cplen = 0;
00692     unsigned int len;
00693     double angle;
00694     Boolean found = False;
00695 
00696     if (!NeWS_active)
00697        return;
00698 
00699     if (globals.debug & DBG_PS)
00700        printf("Raw PS sent to context: <%s>\n", origcp);
00701 
00702     /* take a look at the string:  NeWS bums on certain rotations */
00703     len = strlen(origcp) + 4;
00704     if (cplen < len) {
00705        if (cplen != 0)
00706            free(cp);
00707        cplen = len;
00708        cp = xmalloc(cplen);
00709     }
00710     ocp1 = origcp;
00711     pt = origcp;
00712     while (*pt == ' ' || *pt == '\t')
00713        ++pt;
00714     cp1 = cp;
00715     for (;;) {
00716        ptm1 = pt;
00717        while (*pt != '\0' && *pt != ' ' && *pt != '\t')
00718            ++pt;
00719        if (*pt == '\0')
00720            break;
00721        while (*pt == ' ' || *pt == '\t')
00722            ++pt;
00723        if (strncmp(pt, "rotate", 6) == 0
00724            && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) {
00725            /* found rotate; check angle */
00726            if (sscanf(ptm1, "%lf", &angle) >= 1) {
00727               found = True;
00728               while (angle > 360.0)
00729                   angle -= 360;
00730               while (angle < -360.0)
00731                   angle += 360;
00732               if (angle == 90.0) {
00733                   angle = 89.999;
00734                   (void)memcpy(cp1, ocp1, ptm1 - ocp1);
00735                   cp1 += ptm1 - ocp1;
00736                   strcpy(cp1, "89.999 rotate ");
00737                   cp1 += strlen(cp1);
00738                   while (*pt != '\0' && *pt != ' ' && *pt != '\t')
00739                      ++pt;
00740                   while (*pt == ' ' || *pt == '\t')
00741                      ++pt;
00742                   ocp1 = pt;
00743               }
00744               else if (angle == -90.0) {
00745                   angle = -89.999;
00746                   (void)memcpy(cp1, ocp1, ptm1 - ocp1);
00747                   cp1 += ptm1 - ocp1;
00748                   strcpy(cp1, "-89.999 rotate ");
00749                   cp1 += strlen(cp1);
00750                   while (*pt != '\0' && *pt != ' ' && *pt != '\t')
00751                      ++pt;
00752                   while (*pt == ' ' || *pt == '\t')
00753                      ++pt;
00754                   ocp1 = pt;
00755               }
00756               else if (angle == 0.0) {
00757                   (void)memcpy(cp1, ocp1, ptm1 - ocp1);
00758                   cp1 += ptm1 - ocp1;
00759                   while (*pt != '\0' && *pt != ' ' && *pt != '\t')
00760                      ++pt;
00761                   while (*pt == ' ' || *pt == '\t')
00762                      ++pt;
00763                   ocp1 = pt;
00764               }
00765            }
00766        }
00767     }
00768     strcpy(cp1, ocp1);
00769     if ((globals.debug & DBG_PS) && found) {
00770        printf("String is now <%s>\n", cp);
00771        printf("Found rotate string.  Angle is %g degrees.\n", angle);
00772     }
00773 
00774     len = strlen(cp);
00775     cp[len] = '\n';
00776     NeWS_send(cp, len + 1);
00777 }
00778 
00779 
00780 /*---------------------------------------------------------------------------*
00781   drawfileNeWS()
00782 
00783   Arguments: cp - string with the postscript file pathname
00784             psfile - file, already opened
00785   Returns: (void)
00786   Side-Effects: none
00787 
00788   Description:
00789   Postscript file containing the figure is opened and sent to the NeWS server.
00790   Figure is outlined in case hairy code produces a SIGPIPE signal.
00791 
00792 +----------------------------------------------------------------------------*/
00793 
00794 static void
00795 drawfileNeWS(const char *cp, FILE *psfile)
00796 {
00797     char buffer[1025];
00798     int blen;
00799     struct sigaction orig;
00800 
00801     if (!NeWS_active) {
00802        fclose(psfile);
00803        return;
00804     }
00805 
00806     if (globals.debug & DBG_PS)
00807        printf("printing file %s\n", cp);
00808 
00809     sigpipe_error = False;
00810     for (;;) {
00811        blen = fread(buffer, sizeof(char), 1024, psfile);
00812        if (blen == 0) break;
00813        NeWS_send(buffer, blen);
00814        if (sigpipe_error || (globals.ev.flags & NeWS_ev_mask))
00815            break;
00816     }
00817     fclose(psfile);
00818 
00819     if (sigpipe_error) {
00820        fputs("NeWS died unexpectedly.\n", stderr);
00821        destroyNeWS();
00822        draw_bbox();
00823     }
00824 }
00825 
00826 
00827 /*---------------------------------------------------------------------------*
00828   drawendNeWS()
00829 
00830   Arguments: cp - string with indication of the end of the special
00831   Returns: (void)
00832 
00833   Description:
00834   Sends the indication of end of the figure PostScript code.
00835 
00836 +----------------------------------------------------------------------------*/
00837 
00838 static void
00839 drawendNeWS(const char *cp)
00840 {
00841     if (!NeWS_active)
00842        return;
00843 
00844     if (globals.debug & DBG_PS)
00845        puts("drawend sent to NeWS Server");
00846     NeWS_send(cp, strlen(cp));
00847     NeWS_send("\n", 1);
00848 }
00849 
00850 
00851 /*---------------------------------------------------------------------------*
00852   beginheaderNeWS()
00853 
00854   Arguments: none
00855   Returns: (void)
00856 
00857   Description:
00858   Prepares the PostScript interpreter for receipt of header code.
00859 
00860 +----------------------------------------------------------------------------*/
00861 
00862 static void
00863 beginheaderNeWS(void)
00864 {
00865     static const char str[] = "Hsave /xdvi$doc exch def\n";
00866 
00867     if (globals.debug & DBG_PS)
00868        puts("Running beginheaderNeWS()");
00869 
00870     if (NeWS_active) {
00871        if (!NeWS_in_header)
00872            XDVI_FATAL((stderr, "Internal error in beginheaderNeWS()."));
00873        return;
00874     }
00875 
00876     if (globals.ev.flags & NEWS_MASK_HEADER)
00877        longjmp(globals.ev.canit, 1);
00878 
00879     NeWS_in_header = True;
00880     NeWS_ev_mask = NEWS_MASK_HEADER;
00881     ++NeWS_pending;
00882     if (NeWS_in_doc)
00883        NeWS_send("H", 1);
00884     else {
00885        NeWS_send(str, (sizeof str) - 1);
00886        NeWS_in_doc = True;
00887     }
00888     NeWS_active = True;
00889 }
00890 
00891 
00892 /*---------------------------------------------------------------------------*
00893   endheaderNeWS()
00894 
00895   Arguments: none
00896   Returns: (void)
00897 
00898   Description:
00899   Prepares the PostScript interpreter for receipt of header code.
00900 
00901 +----------------------------------------------------------------------------*/
00902 
00903 static void
00904 endheaderNeWS(void)
00905 {
00906     static const char str[] = "stop\n%%xdvimark\n";
00907 
00908     if (globals.debug & DBG_PS)
00909        puts("Running endheaderNeWS()");
00910 
00911     if (NeWS_active) {
00912        NeWS_send(str, (sizeof str) - 1);
00913        NeWS_active = False;
00914        post_send();
00915        waitack();
00916        NeWS_in_header = False;
00917        NeWS_ev_mask = NEWS_MASK_NORMAL;
00918     }
00919 }
00920 
00921 
00922 /*---------------------------------------------------------------------------*
00923   newdocNeWS()
00924 
00925   Arguments: none
00926   Returns: (void)
00927 
00928   Description:
00929   Clears out headers stored from the previous document.
00930 
00931 +----------------------------------------------------------------------------*/
00932 
00933 static void
00934 newdocNeWS(void)
00935 {
00936     static const char str[] = "H xdvi$doc restore stop\n%%xdvimark\n";
00937 
00938     if (globals.debug & DBG_PS)
00939        puts("Running newdocNeWS()");
00940 
00941     if (NeWS_in_doc) {
00942        ++NeWS_pending;
00943        NeWS_send(str, (sizeof str) - 1);
00944        NeWS_mag = NeWS_shrink = -1;
00945        NeWS_in_doc = False;
00946     }
00947 }
00948 #else
00949 /* silence `empty compilation unit' warnings */
00950 static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
00951 #endif /* PS_NEWS */