summaryrefslogtreecommitdiff
path: root/Build/source/texk/windvi/psnews.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/windvi/psnews.c')
-rw-r--r--Build/source/texk/windvi/psnews.c969
1 files changed, 969 insertions, 0 deletions
diff --git a/Build/source/texk/windvi/psnews.c b/Build/source/texk/windvi/psnews.c
new file mode 100644
index 00000000000..4e66e6ca588
--- /dev/null
+++ b/Build/source/texk/windvi/psnews.c
@@ -0,0 +1,969 @@
+/*========================================================================*\
+
+Copyright (c) 1994-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTES:
+ This code was originally written by Ricardo Telichevesky
+ (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
+ (lms@rle-vlsi-mit.edu).
+ It was largely influenced by similar code in the SeeTeX/XTeX
+ package by Dirk Grunwald (grunwald@colorado.edu).
+
+\*========================================================================*/
+
+/* ||| To do:
+ * ALWAYS_CLOSE_SERVER_CONNECTION?
+ * Is there some way of interrupting a process?
+ * fork
+ * extra bytes on input
+ */
+
+#ifdef PS_NEWS /* whole file */
+
+#include "xdvi-config.h"
+#include <signal.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#undef SYSV /* To avoid defined SYSV_{WAIT,UCONTEXT} in xview/notify.h. */
+#include <NeWS/psio.h>
+#include <xvps/pscanvas.h>
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#endif
+
+/* Condition for retrying a write */
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef EWOULDBLOCK
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+#else /* EAGAIN */
+#define AGAIN_CONDITION (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#else /* EWOULDBLOCK */
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EAGAIN)
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+#else
+# if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# else
+# if HAVE_SELECT_H
+# include <select.h>
+# endif
+# endif
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+#define FLAKY_SIGPOLL 1
+#endif
+
+char *strtok ARGS((char *, _Xconst char *));
+
+#define Fprintf (void) fprintf
+
+
+/* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server
+ connection all the time */
+#undef ALWAYS_CLOSE_SERVER_CONNECTION
+
+
+ /*
+ * Some setup code.
+ */
+static _Xconst char str0[] = "\
+/OW2? version cvi 2 eq def \
+OW2? \
+{ /setlinewidth { pop } def} \
+{ /NeWS 3 0 findpackage beginpackage \
+ /X11 3 0 findpackage beginpackage} \
+ifelse \
+currentcanvas /Color get \
+currentcanvas /Colormap get getcubedescription null eq and \
+ {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped \
+ {pop pop pop pop pop} {exit} ifelse \
+ 2 div cvi dup 1 eq {exit} if} loop pop} \
+if\n";
+ /*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ */
+static _Xconst char preamble[] = "\
+/xdvi$line 81 string def \
+/xdvi$run {$error null ne {$error /newerror false put} if \
+ {currentfile cvx stopped \
+ $error null eq {false} {$error /newerror get} ifelse and \
+ {handleerror} if} stopped pop} def \
+/xdvi$dslen countdictstack def \
+{currentfile read not {exit} if 72 eq \
+ {xdvi$run} \
+ {/xdvi$sav save def xdvi$run \
+ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
+ ifelse \
+ {(%%xdvimark) currentfile xdvi$line {readline} stopped \
+ {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if \
+ 58 tagprint flush \
+}loop\nH";
+
+extern _Xconst char psheader[];
+extern int psheaderlen;
+
+static _Xconst char preamble2[] = " stop\n%%xdvimark\n";
+#define stopstring preamble2
+
+#define postscript resource._postscript
+
+
+/* global procedures (besides initNeWS) */
+
+static void toggleNeWS ARGS((void));
+static void destroyNeWS ARGS((void));
+static void interruptNeWS ARGS((void));
+static void endpageNeWS ARGS((void));
+static void drawbeginNeWS ARGS((int, int, _Xconst char *));
+static void drawrawNeWS ARGS((_Xconst char *));
+static void drawfileNeWS ARGS((_Xconst char *, FILE *));
+static void drawendNeWS ARGS((_Xconst char *));
+static void beginheaderNeWS ARGS((void));
+static void endheaderNeWS ARGS((void));
+static void newdocNeWS ARGS((void));
+
+static struct psprocs news_procs = {
+ /* toggle */ toggleNeWS,
+ /* destroy */ destroyNeWS,
+ /* interrupt */ interruptNeWS,
+ /* endpage */ endpageNeWS,
+ /* drawbegin */ drawbeginNeWS,
+ /* drawraw */ drawrawNeWS,
+ /* drawfile */ drawfileNeWS,
+ /* drawend */ drawendNeWS,
+ /* beginheader */ beginheaderNeWS,
+ /* endheader */ endheaderNeWS,
+ /* newdoc */ newdocNeWS};
+
+/* signal handler to hairy PostScript code */
+static RETSIGTYPE psio_sigpipe_handler();
+
+/* define local static variables */
+static int NeWS_mag; /* magnification currently in use */
+static int NeWS_shrink; /* shrink factor currently in use */
+static unsigned int NeWS_page_w; /* how big our current page is */
+static unsigned int NeWS_page_h;
+static Boolean NeWS_active; /* if we've started a page yet */
+static int NeWS_pending; /* number of ack's we're expecting */
+static int NeWS_sending; /* level of nesting in send() */
+static Boolean NeWS_in_header; /* if we're sending a header */
+static Boolean NeWS_in_doc; /* if we've sent header information */
+static Boolean NeWS_pending_int; /* if interrupt rec'd while in send() */
+static Boolean NeWS_destroyed = False;
+
+
+/*
+ * NeWS I/O code. This should send PS code to NeWS,
+ * receive acknowledgements, and receive X events in the meantime.
+ * It also checks for SIGPIPE errors.
+ */
+
+#if HAVE_POLL
+static struct pollfd fds[3] = {{0, POLLOUT, 0},
+ {0, POLLIN, 0},
+ {0, POLLIN, 0}};
+#define XDVI_ISSET(a, b, c) (fds[c].revents)
+#else
+static int numfds;
+static fd_set readfds;
+static fd_set writefds;
+#define XDVI_ISSET(a, b, c) FD_ISSET(a, b)
+#endif
+
+
+/*---------------------------------------------------------------------------*
+ psio_sigpipe_handler ()
+
+ Arguments: sig, code, scp, addr (see man page for signal)
+ Returns: (void)
+ Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set.
+
+ Description:
+ Handler for SIGPIPE error generated by a broken pipe in the connection
+ to the NeWS server; this may be duer to some abnormal condition, or some
+ hairy PostScript code containing commands not implemented by the server.
+
++----------------------------------------------------------------------------*/
+
+static Boolean sigpipe_error = False;
+
+static struct sigaction psio_sigpipe_handler_struct;
+ /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */
+
+/* ARGSUSED */
+static RETSIGTYPE
+psio_sigpipe_handler(sig, code, scp, addr)
+ int sig;
+ int code;
+ struct sigcontext *scp;
+ char *addr;
+{
+ sigpipe_error = True;
+}
+
+
+/*
+ * read_from_NeWS - This does the actual retrieving of acknowledgements.
+ * If other bytes appear on the file - tough.
+ */
+
+static void
+read_from_NeWS()
+{
+ for (;;) {
+ int retval;
+
+ retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58);
+ if (retval == 0) break;
+ if (retval < 0) {
+ Fprintf(stderr, "[xdvik] ps_checkfor: %d\n", retval);
+ return;
+ }
+ (void) ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58);
+ --NeWS_pending;
+ if (debug & DBG_PS)
+ Printf("Got NeWS ack; %d pending.\n", NeWS_pending);
+ }
+}
+
+
+/*
+ * Clean up after send()
+ */
+
+static void
+post_send()
+{
+ if (sigpipe_error) {
+ Fputs("NeWS died unexpectedly.\n", stderr);
+ destroyNeWS();
+ draw_bbox();
+ }
+
+ if (NeWS_pending_int) {
+ NeWS_pending_int = False;
+ interruptNeWS();
+ }
+}
+
+
+/*
+ * This actually sends the bytes to NeWS.
+ */
+
+static void
+send(cp, len)
+ _Xconst char *cp;
+ int len;
+{
+ struct sigaction orig;
+#if HAVE_POLL
+ int retval;
+#endif
+
+ if (PostScript == (PSFILE *) NULL) return;
+
+ if (!NeWS_sending) {
+ (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
+ sigpipe_error = False;
+ }
+ ++NeWS_sending;
+
+#ifndef FLAKY_SIGPOLL
+ (void) fcntl(ConnectionNumber(DISP), F_SETFL,
+ fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC);
+#endif
+
+#if ! HAVE_POLL
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+#endif
+
+ for (;;) {
+
+ if (terminate_flag) {
+ ps_destroy();
+ exit(0);
+ }
+
+#if HAVE_POLL
+ for (;;) {
+ retval = poll(fds, XtNumber(fds), -1);
+ if (retval >= 0 || errno != EAGAIN) break;
+ }
+ if (retval < 0) {
+ if (errno == EINTR)
+ continue;
+ else {
+ perror("poll (xdvi NeWS_send)");
+ break;
+ }
+ }
+#else
+ FD_SET(ConnectionNumber(DISP), &readfds);
+ FD_SET(PostScript->file, &writefds);
+ FD_SET(PostScriptInput->file, &readfds);
+
+ if (select(numfds, &readfds, &writefds, (fd_set *) NULL,
+ (struct timeval *) NULL) < 0 && errno != EINTR) {
+ perror("select (xdvi NeWS_send)");
+ break;
+ }
+#endif
+
+ if (XDVI_ISSET(PostScriptInput->file, &readfds, 1))
+ read_from_NeWS();
+ if (XDVI_ISSET(PostScript->file, &writefds, 0)) {
+ int old_flags;
+ int bytes;
+
+ old_flags = fcntl(PostScript->file, F_GETFL, 0);
+ if (old_flags < 0) break;
+ /* set to be non-blocking */
+ if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK)
+ < 0)
+ break;
+ bytes = write(PostScript->file, cp, len);
+ if (bytes == -1) {
+ if (!AGAIN_CONDITION) perror("xdvi NeWS_send");
+ }
+ else {
+ cp += bytes;
+ len -= bytes;
+ }
+ if (fcntl(PostScript->file, F_SETFL, old_flags) < 0) break;
+ if (len == 0 || sigpipe_error) break;
+ }
+ if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
+ ps_read_events(False, False);
+ if (PostScript == (PSFILE *) NULL) break; /* if timeout occurred */
+ }
+ }
+
+#ifndef FLAKY_SIGPOLL
+ (void) fcntl(ConnectionNumber(DISP), F_SETFL,
+ fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC);
+#endif
+
+ if (--NeWS_sending == 0) {
+ /* put back generic handler for SIGPIPE */
+ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
+
+ if (!NeWS_in_header) post_send();
+ }
+}
+
+/*
+ * Wait for acknowledgement from NeWS. With NeWS we have no choice but
+ * to wait (||| I think).
+ */
+
+static void
+waitack()
+{
+#if HAVE_POLL
+ int retval;
+#endif
+#ifndef FLAKY_SIGPOLL
+ int oldflags;
+#endif
+
+ if (PostScript == (PSFILE *) NULL) return;
+
+#ifndef FLAKY_SIGPOLL
+ oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0);
+ (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC);
+#endif
+#if ! HAVE_POLL
+ FD_ZERO(&readfds);
+#endif
+ while (NeWS_pending > 0) {
+#if HAVE_POLL
+ for (;;) {
+ retval = poll(fds + 1, XtNumber(fds) - 1, -1);
+ if (retval >= 0 || errno != EAGAIN) break;
+ }
+ if (retval < 0) {
+ if (errno == EINTR)
+ continue;
+ else {
+ perror("poll (xdvi NeWS_waitack)");
+ break;
+ }
+ }
+#else
+ FD_SET(ConnectionNumber(DISP), &readfds);
+ FD_SET(PostScriptInput->file, &readfds);
+ if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL,
+ (struct timeval *) NULL) < 0 && errno != EINTR) {
+ perror("select (xdvi NeWS_waitack)");
+ break;
+ }
+#endif
+
+
+ if (XDVI_ISSET(PostScriptInput->file, &readfds, 1))
+ read_from_NeWS();
+ if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
+ ps_read_events(False, False);
+ if (PostScript == (PSFILE *) NULL) /* if timeout occurred*/
+ break;
+ }
+ }
+#ifndef FLAKY_SIGPOLL
+ (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags);
+#endif
+}
+
+
+/*---------------------------------------------------------------------------*
+ initNeWS()
+
+ Arguments: None.
+ Returns: True if and only if initialization succeeded
+ Side-Effects: Static variables may be set.
+
+ Description:
+ Initializes variables for the application main loop.
+
++----------------------------------------------------------------------------*/
+
+Boolean
+initNeWS()
+{
+ static NeWStoken newstoken;
+
+ /* now try to open the connection to the NeWS server */
+ if (ps_open_PostScript() == (PSFILE *) NULL)
+ return False;
+
+#if HAVE_POLL
+ fds[0].fd = PostScript->file;
+ fds[1].fd = PostScriptInput->file;
+ fds[2].fd = ConnectionNumber(DISP);
+#else
+ numfds = ConnectionNumber(DISP);
+ if (numfds < PostScript->file) numfds = PostScript->file;
+ if (numfds < PostScriptInput->file) numfds = PostScriptInput->file;
+ ++numfds;
+#endif
+
+ psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler;
+ sigemptyset(&psio_sigpipe_handler_struct.sa_mask);
+
+ NeWS_active = NeWS_pending_int = False;
+ NeWS_sending = 0;
+ NeWS_in_header = True;
+ NeWS_pending = 1;
+
+ ps_flush_PostScript();
+ send(str0, sizeof(str0) - 1);
+ /* get xid of window, then make this window the NeWS canvas */
+ (void) ps_token_from_xid(mane.win, &newstoken);
+ if (newstoken != -1) {
+ ps_setcanvas(newstoken);
+ ps_flush_PostScript();
+ send(preamble, sizeof(preamble) - 1);
+ send(psheader, psheaderlen);
+ send(preamble2, sizeof(preamble2) - 1);
+ NeWS_in_header = False;
+ post_send();
+ waitack();
+ }
+
+ if (NeWS_destroyed) return False;
+
+ /* success */
+
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_page_w = page_w;
+ NeWS_page_h = page_h;
+
+ psp = news_procs;
+ if (!postscript) toggleNeWS(); /* if we got a 'v' already */
+
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ toggleNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: psp.drawbegin is changed
+
+ Description:
+ Used to toggle the rendering of PostScript by the NeWS server
+
++----------------------------------------------------------------------------*/
+
+static void
+toggleNeWS()
+{
+ if (postscript) psp.drawbegin = drawbeginNeWS;
+ else {
+ interruptNeWS();
+ psp.drawbegin = drawbegin_none;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ destroyNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the pointer to the NeWS file is nulled
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ in any way.
+
++----------------------------------------------------------------------------*/
+
+static void
+destroyNeWS()
+{
+ psp = no_ps_procs;
+ NeWS_destroyed = True;
+ scanned_page = scanned_page_bak = scanned_page_reset;
+}
+
+
+/*---------------------------------------------------------------------------*
+ interruptNeWS()
+
+ Arguments: none
+ Returns: void
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ because of an interruption in the viewing of the current page.
+ ||| It would be nice if we could asynchronously ``wake up'' a NeWS process
+ (preferably by sending something along the X socket); then we could do
+ better than just to wait.
+
++----------------------------------------------------------------------------*/
+
+static void
+interruptNeWS()
+{
+ if (debug & DBG_PS) Puts("Running interruptNeWS()");
+ if (NeWS_sending) NeWS_pending_int = True;
+ else {
+ if (NeWS_active) {
+ send(stopstring, sizeof(stopstring) - 1);
+ NeWS_active = False;
+ }
+ psp.interrupt = NullProc; /* prevent deep recursion in waitack */
+ waitack();
+ psp.interrupt = interruptNeWS;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ endpageNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the NeWS_active variable is cleared.
+
+ Description:
+ Should be called at the end of a page to end this chunk for the NeWS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+endpageNeWS()
+{
+ if (debug & DBG_PS)
+ Puts("endpage sent to NeWS Server");
+ if (NeWS_active) {
+ send(stopstring, sizeof(stopstring) - 1);
+ NeWS_active = False;
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawbeginNeWS ()
+
+ Arguments: xul, yul - coordinates of the upper left corner of the figure
+ cp - string with the bounding box line data
+ Returns: (void)
+
+ Description:
+ Opens a connection to the NeWS server and send in the preamble and the
+ bounding box information after correctly computing resolution factors.
+ In case no rendering is to be done, outlines the figure. An outline is
+ also generated whenever the PostScript code is too hairy and generates
+ a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawbeginNeWS(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+{
+ char buf[100];
+ static _Xconst char str[] = " TeXDict begin\n";
+ static _Xconst char str2[] = "Hinitgraphics stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) {
+ Printf("xul= %d yul= %d\n", xul, yul);
+ Printf("String = < %s >\n", cp);
+ }
+
+ /* catch up on the X side */
+ XSync(DISP, False);
+
+ if (!NeWS_active) {
+ /* send initialization to NeWS server */
+ if (NeWS_page_w < page_w || NeWS_page_h < page_h) {
+ NeWS_page_w = page_w;
+ NeWS_page_h = page_h;
+ send(str2, sizeof(str2) - 1);
+ ++NeWS_pending;
+ }
+ if (magnification != NeWS_mag) {
+ Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
+end stop\n%%%%xdvimark\n",
+ NeWS_mag = magnification);
+ send(buf, strlen(buf));
+ ++NeWS_pending;
+ }
+ if (mane.shrinkfactor != NeWS_shrink) {
+ Sprintf(buf, "H TeXDict begin %d %d div dup \
+/Resolution X /VResolution X \
+end stop\n%%%%xdvimark\n",
+ pixels_per_inch, NeWS_shrink = mane.shrinkfactor);
+ send(buf, strlen(buf));
+ ++NeWS_pending;
+ }
+ send(str, sizeof(str) - 1);
+ NeWS_active = True;
+ ++NeWS_pending;
+ }
+
+ Sprintf(buf, "%d %d moveto\n", xul, yul);
+ send(buf, strlen(buf));
+ send(cp, strlen(cp));
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawrawNeWS()
+
+ Arguments: origcp - the raw string to be sent to the postscript interpreter
+ Returns: (void)
+ Side-Effects: (none)
+
+ Description:
+ If there is a valid connection to the NeWS server, just send the string to
+ the interpreter, else leave.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawrawNeWS(origcp)
+ _Xconst char *origcp;
+{
+ _Xconst char *pt, *ptm1, *ocp1;
+ static char *cp;
+ char *cp1;
+ static unsigned int cplen = 0;
+ unsigned int len;
+ double angle;
+ Boolean found = False;
+
+ if (!NeWS_active)
+ return;
+
+ if (debug & DBG_PS)
+ Printf("Raw PS sent to context: <%s>\n", origcp);
+
+ /* take a look at the string: NeWS bums on certain rotations */
+ len = strlen(origcp) + 4;
+ if (cplen < len) {
+ if (cplen != 0) free(cp);
+ cplen = len;
+ cp = xmalloc(cplen);
+ }
+ ocp1 = origcp;
+ pt = origcp;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ cp1 = cp;
+ for (;;) {
+ ptm1 = pt;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ if (*pt == '\0') break;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ if (strncmp(pt, "rotate", 6) == 0
+ && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) {
+ /* found rotate; check angle */
+ if (sscanf(ptm1, "%lf", &angle) >= 1) {
+ found = True;
+ while (angle > 360.0)
+ angle -= 360;
+ while (angle < -360.0)
+ angle += 360;
+ if (angle == 90.0) {
+ angle = 89.999;
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ Strcpy(cp1, "89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ } else if (angle == -90.0) {
+ angle = -89.999;
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ Strcpy(cp1, "-89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ } else if (angle == 0.0) {
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ }
+ }
+ }
+ }
+ Strcpy(cp1, ocp1);
+ if ((debug & DBG_PS) && found) {
+ Printf("String is now <%s>\n", cp);
+ Printf("Found rotate string. Angle is %g degrees.\n", angle);
+ }
+
+ len = strlen(cp);
+ cp[len] = '\n';
+ send(cp, len + 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawfileNeWS()
+
+ Arguments: cp - string with the postscript file pathname
+ psfile - file, already opened
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Postscript file containing the figure is opened and sent to the NeWS server.
+ Figure is outlined in case hairy code produces a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawfileNeWS(cp, psfile)
+ _Xconst char *cp;
+ FILE *psfile;
+{
+ char buffer[1025];
+ int blen;
+ struct sigaction orig;
+
+ if (!NeWS_active) {
+ Fclose(psfile);
+ ++n_files_left;
+ return;
+ }
+
+ if (debug & DBG_PS)
+ Printf("printing file %s\n", cp);
+ /* some hairy PS code generates SIGPIPE signals; handle them */
+ (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
+ sigpipe_error = False;
+ NeWS_sending = 1;
+ if (!sigpipe_error)
+ for (;;) {
+ blen = fread(buffer, sizeof(char), 1024, psfile);
+ if (blen == 0) break;
+ send(buffer, blen);
+ if (sigpipe_error) break;
+ }
+ Fclose(psfile);
+ ++n_files_left;
+
+ --NeWS_sending;
+ /* put back generic handler for SIGPIPE */
+ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
+
+ if (sigpipe_error) {
+ Fputs("NeWS died unexpectedly.\n", stderr);
+ destroyNeWS();
+ draw_bbox();
+ }
+
+ if (NeWS_pending_int) {
+ NeWS_pending_int = False;
+ interruptNeWS();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawendNeWS()
+
+ Arguments: cp - string with indication of the end of the special
+ Returns: (void)
+
+ Description:
+ Sends the indication of end of the figure PostScript code.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawendNeWS(cp)
+ _Xconst char *cp;
+{
+ if (!NeWS_active)
+ return;
+
+ if (debug & DBG_PS)
+ Puts("drawend sent to NeWS Server");
+ send(cp, strlen(cp));
+ send("\n", 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ beginheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+beginheaderNeWS()
+{
+ static _Xconst char str[] = "Hsave /xdvi$doc exch def\n";
+
+ if (debug & DBG_PS) Puts("Running beginheaderNeWS()");
+
+ if (NeWS_active) {
+ if (!NeWS_in_header)
+ oops("Internal error in beginheaderNeWS().\n");
+ return;
+ }
+
+ NeWS_in_header = True;
+ if (NeWS_in_doc)
+ send("H", 1);
+ else {
+ send(str, sizeof(str) - 1);
+ NeWS_in_doc = True;
+ }
+ NeWS_active = True;
+ ++NeWS_pending;
+}
+
+
+/*---------------------------------------------------------------------------*
+ endheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+endheaderNeWS()
+{
+ static _Xconst char str[] = "stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) Puts("Running endheaderNeWS()");
+
+ if (NeWS_active) {
+ send(str, sizeof(str) - 1);
+ NeWS_active = False;
+ NeWS_in_header = False;
+ post_send();
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ newdocNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Clears out headers stored from the previous document.
+
++----------------------------------------------------------------------------*/
+
+static void
+newdocNeWS()
+{
+ static _Xconst char str[] =
+ "H xdvi$doc restore stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) Puts("Running newdocNeWS()");
+
+ if (NeWS_in_doc) {
+ send(str, sizeof(str) - 1);
+ ++NeWS_pending;
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_in_doc = False;
+ }
+}
+
+#endif /* PS_NEWS */