diff options
Diffstat (limited to 'Build/source/texk/windvi/psgs.c')
-rw-r--r-- | Build/source/texk/windvi/psgs.c | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/Build/source/texk/windvi/psgs.c b/Build/source/texk/windvi/psgs.c new file mode 100644 index 00000000000..6bd13208150 --- /dev/null +++ b/Build/source/texk/windvi/psgs.c @@ -0,0 +1,854 @@ +/*========================================================================*\ + +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. + +\*========================================================================*/ + +#ifdef PS_GS /* whole file */ + +#include "xdvi-config.h" +#include "kpathsea/c-pathmx.h" +#include <X11/Xatom.h> +#include <sys/time.h> /* for timeval */ + +#include <signal.h> +#include <sys/file.h> /* this defines FASYNC */ + +/* if POSIX O_NONBLOCK is not available, use O_NDELAY */ +#if !defined(O_NONBLOCK) && defined(O_NDELAY) +#define O_NONBLOCK O_NDELAY +#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 + +#if HAVE_VFORK_H +# include <vfork.h> +#endif + +#ifndef X_GETTIMEOFDAY +#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*) NULL) +#endif + +#ifndef timercmp +#define timercmp(a, b, cmp) ((a)->tv_sec cmp (b)->tv_sec || \ + ((a)->tv_sec == (b)->tv_sec && (a)->tv_usec cmp (b)->tv_usec)) +#endif /* timercmp */ + +extern _Xconst char psheader[]; +extern int psheaderlen; + +#define postscript resource._postscript +#define fore_Pixel resource._fore_Pixel +#define back_Pixel resource._back_Pixel + +/* global procedures (besides initGS) */ + +static void toggle_gs ARGS((void)); +static void destroy_gs ARGS((void)); +static void interrupt_gs ARGS((void)); +static void endpage_gs ARGS((void)); +static void drawbegin_gs ARGS((int, int, _Xconst char *)); +static void drawraw_gs ARGS((_Xconst char *)); +static void drawfile_gs ARGS((_Xconst char *, FILE *)); +static void drawend_gs ARGS((_Xconst char *)); +static void beginheader_gs ARGS((void)); +static void endheader_gs ARGS((void)); +static void newdoc_gs ARGS((void)); + +static struct psprocs gs_procs = { + /* toggle */ toggle_gs, + /* destroy */ destroy_gs, + /* interrupt */ interrupt_gs, + /* endpage */ endpage_gs, + /* drawbegin */ drawbegin_gs, + /* drawraw */ drawraw_gs, + /* drawfile */ drawfile_gs, + /* drawend */ drawend_gs, + /* beginheader */ beginheader_gs, + /* endheader */ endheader_gs, + /* newdoc */ newdoc_gs}; + +static int std_in[2]; +static int std_out[2]; + +#define GS_in (std_in[1]) +#define GS_out (std_out[0]) + + /* some arguments are filled in later */ +static char arg4[] = "-dDEVICEWIDTH=xxxxxxxxxx"; +static char arg5[] = "-dDEVICEHEIGHT=xxxxxxxxxx"; + +static _Xconst char *argv[] = {NULL, NULL, "-dNOPAUSE", "-q", arg4, arg5, + "-dDEVICEXRESOLUTION=72", + "-dDEVICEYRESOLUTION=72", + NULL, NULL, NULL}; + +static pid_t GS_pid; +static unsigned int GS_page_w; /* how big our current page is */ +static unsigned int GS_page_h; +static Boolean GS_alpha; /* if we are using the alpha driver */ +static int GS_mag; /* magnification currently in use */ +static int GS_shrink; /* shrink factor currently in use */ +static Boolean GS_active; /* if we've started a page yet */ +static int GS_pending; /* number of ack's we're expecting */ +static _Xconst char *GS_send_byte; /* next byte to send to gs */ +static _Xconst char *GS_send_end; /* last + 1 byte to send to gs */ +static Boolean GS_in_header; /* if we're sending a header */ +static Boolean GS_in_doc; /* if we've sent header information */ +static Boolean GS_pending_int; /* if interrupt rec'd while in gs_io()*/ +static Boolean GS_timeout_set; /* if there's a timeout set */ +static struct timeval GS_timeout; /* when to time out */ +static Boolean GS_old; /* if we're using gs 2.xx */ + +static Atom gs_atom; +static Atom gs_colors_atom; + +#define Landscape 90 + +/* + * ghostscript I/O code. This should send PS code to ghostscript, + * 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 + +#define LINELEN 81 +static char line[LINELEN + 1]; +static char *linepos = line; +static char ackstr[] = "\347\310\376"; +static char oldstr[] = "\347\310\375"; + +static void +showto(q) + char *q; +{ + char *p = line; + char *p1; + + while (p < q) { + p1 = memchr(p, '\n', q - p); + if (p1 == NULL) p1 = q; + *p1 = '\0'; + Printf("gs: %s\n", p); + p = p1 + 1; + } +} + +static void +read_from_gs() { + int bytes; + char *line_end; + char *p; + + bytes = read(GS_out, linepos, line + LINELEN - linepos); + if (bytes < 0) return; + line_end = linepos + bytes; + /* Check for ack strings */ + for (p = line; p < line_end - 2; ++p) { + p = memchr(p, '\347', line_end - p - 2); + if (p == NULL) break; + if (memcmp(p, ackstr, 3) == 0) { + --GS_pending; + if (debug & DBG_PS) + Printf("Got GS ack; %d pending.\n", GS_pending); + } + else if (memcmp(p, oldstr, 3) == 0) { + if (debug & DBG_PS) + Puts("Using old GS version."); + GS_old = True; + } + else continue; + + showto(p); + p += 3; + (void) bcopy(p, line, line_end - p); + line_end -= p - line; + linepos = p = line; + --p; + } + *line_end = '\0'; + p = strrchr(linepos, '\n'); + if (p != NULL) { + ++p; + showto(p); + (void) bcopy(p, line, line_end - p); + line_end -= p - line; + } + linepos = line_end; + /* + * Normally we'd hold text until a newline character, but the buffer + * is full. So we flush it, being careful not to cut up an ack string. + */ + if (linepos >= line + LINELEN) { + p = line + LINELEN; + if ((*--p != '\347' && *--p != '\347' && *--p != '\347') + || (memcmp(p, ackstr, line + LINELEN - p) != 0 + && memcmp(p, oldstr, line + LINELEN - p) != 0)) + p = line + LINELEN; + *p = '\0'; + Printf("gs: %s\n", line); + *p = '\347'; + linepos = line; + while (p < line + LINELEN) *linepos++ = *p++; + } +} + +/* + * For handling of SIGPIPE signals from gs_io() + */ + +static Boolean sigpipe_error = False; + +/* ARGSUSED */ +static RETSIGTYPE +gs_sigpipe_handler(sig, code, scp, addr) + int sig; + int code; + struct sigcontext *scp; + char *addr; +{ + sigpipe_error = True; +} + +#if HAVE_SIGACTION +static struct sigaction sigpipe_handler_struct; + /* initialized to {gs_sigpipe_handler, (sigset_t) 0, 0} in initGS */ +#endif + +/* + * Clean up after gs_io() + */ + +static void +post_send() +{ + if (sigpipe_error) { + Fputs("ghostscript died unexpectedly.\n", stderr); + destroy_gs(); + draw_bbox(); + } + + if (GS_pending_int) { + GS_pending_int = False; + interrupt_gs(); + } +} + +/* + * This routine does two things. It either sends a string of bytes to + * the GS interpreter, or waits for acknowledgement from GS. + */ + +#define waitack() gs_io(NULL, 0) + +static void +gs_io(cp, len) + _Xconst char *cp; + int len; +{ + int bytes; +#if HAVE_SIGACTION + struct sigaction orig; +#else + RETSIGTYPE (*orig)(); +#endif + struct timeval tv; +#if HAVE_POLL + int timeout = -1; + int retval; + int offset = 0; +#else + struct timeval *timeout = (struct timeval *) NULL; +#endif +#if !defined(FLAKY_SIGPOLL) && defined(FASYNC) + int oldflags; +#endif + + if (GS_pid < 0) + return; + + if (cp != NULL) { /* if sending bytes */ +#if HAVE_SIGACTION + (void) sigaction(SIGPIPE, &sigpipe_handler_struct, &orig); +#else + orig = signal(SIGPIPE, gs_sigpipe_handler); +#endif + sigpipe_error = False; + GS_send_byte = cp; + GS_send_end = cp + len; + } + else { /* if waiting for acknowledgement */ + if (GS_pending == 0) + return; +#if HAVE_POLL + offset = 1; +#endif + } + +#if !defined(FLAKY_SIGPOLL) && defined(FASYNC) + oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0); + (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC); +#endif + + for (;;) { + + /* Handle timeout. */ + + if (GS_timeout_set) { + (void) X_GETTIMEOFDAY(&tv); +#if HAVE_POLL + timeout = 1000 * (int) (GS_timeout.tv_sec - tv.tv_sec) + + ((long) GS_timeout.tv_usec - (long) tv.tv_usec) / 1000; + if (timeout <= 0) { + destroy_gs(); + break; + } +#else + if (!timercmp(&tv, &GS_timeout, <)) { + destroy_gs(); + break; + } + tv.tv_sec = GS_timeout.tv_sec - tv.tv_sec; + tv.tv_usec = GS_timeout.tv_usec + 1000000 - tv.tv_usec; + if (tv.tv_usec >= 1000000) tv.tv_usec -= 1000000; + else --tv.tv_sec; + timeout = &tv; +#endif + } + + if (terminate_flag) { + ps_destroy(); + exit(0); + } + +#if HAVE_POLL + fds[0].revents = 0; + for (;;) { + retval = poll(fds + offset, XtNumber(fds) - offset, timeout); + if (retval >= 0 || errno != EAGAIN) break; + } + if (retval < 0) { + if (errno == EINTR) + continue; + else { + perror("poll (xdvik gs_io)"); + break; + } + } +#else + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(DISP), &readfds); + FD_SET(GS_out, &readfds); + + FD_ZERO(&writefds); + if (GS_send_byte != NULL) FD_SET(GS_in, &writefds); + + if (select(numfds, &readfds, &writefds, (fd_set *) NULL, timeout) + < 0 && errno != EINTR) { + perror("select (xdvik gs_io)"); + break; + } +#endif + + if (XDVI_ISSET(GS_out, &readfds, 1)) { + read_from_gs(); + if (GS_pending <= 0) { + GS_timeout_set = False; + break; + } + } + if (XDVI_ISSET(GS_in, &writefds, 0)) { + bytes = write(GS_in, GS_send_byte, GS_send_end - GS_send_byte); + if (bytes == -1) { + if (!AGAIN_CONDITION) perror("xdvik gs_io"); + } + else { + GS_send_byte += bytes; + if (GS_send_byte == GS_send_end) { + GS_send_byte = NULL; + break; + } + } + if (sigpipe_error) break; + } + if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { + ps_read_events(False, False); + if (GS_pid < 0) break; /* if timeout occurred */ + if (GS_pending <= 0) { + GS_timeout_set = False; + break; + } + } + } + +#if !defined(FLAKY_SIGPOLL) && defined(FASYNC) + (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags); +#endif + + if (cp != NULL) { + /* put back generic handler for SIGPIPE */ +#if HAVE_SIGACTION + (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL); +#else + (void) signal(SIGPIPE, orig); +#endif + if (!GS_in_header) + post_send(); + } +} + +/* + * Fork a process to run ghostscript. This is done using the + * x11 device (which needs to be compiled in). Normally the x11 + * device uses ClientMessage events to communicate with the calling + * program, but we don't do this. The reason for using the ClientMessage + * events is that otherwise ghostview doesn't know when a non-conforming + * postscript program calls showpage. That doesn't affect us here, + * since in fact we disable showpage. + */ + +Boolean +initGS() +{ + char buf[100]; + static Boolean did_putenv = False; + /* + * 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. + * `execute' is unique to ghostscript. + */ + static _Xconst char str1[] = "\ +/xdvi$run {$error /newerror false put {currentfile cvx execute} stopped pop} \ + def \ +/xdvi$ack (\347\310\376) def \ +/xdvi$dslen countdictstack def \ +{currentfile read pop 72 eq \ + {xdvi$run} \ + {xdvi$run \ + clear countdictstack xdvi$dslen sub {end} repeat } \ + ifelse \ + {(%%xdvimark) currentfile =string {readline} stopped \ + {clear} {pop eq {exit} if} ifelse }loop \ + flushpage xdvi$ack print flush \ +}loop\nH"; + static _Xconst char str2[] = "[0 1 1 0 0 0] concat\n\ +revision 300 lt{(\347\310\375) print flush}if\n\ +stop\n%%xdvimark\n"; + + gs_atom = XInternAtom(DISP, "GHOSTVIEW", False); + /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */ + Sprintf(buf, "%ld %d 0 0 %u %u 72 72", + None, /* bpixmap */ + Landscape, /* orientation */ + GS_page_h = page_h, GS_page_w = page_w); + XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8, + PropModeReplace, (unsigned char *) buf, strlen(buf)); + GS_alpha = resource.gs_alpha; + + gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False); + Sprintf(buf, "%s %ld %ld", resource.gs_palette, fore_Pixel, back_Pixel); + XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8, + PropModeReplace, (unsigned char *) buf, strlen(buf)); + + if (!did_putenv) { + Sprintf(buf, "%ld", mane.win); + xputenv("GHOSTVIEW", buf); + xputenv("DISPLAY", XDisplayString(DISP)); + did_putenv = True; + } + + XSync(DISP, False); /* update the window */ + + if (xpipe(std_in) != 0 || xpipe(std_out) != 0) { + perror("[xdvik] pipe"); + return False; + } + Fflush(stderr); /* to avoid double flushing */ + GS_pid = vfork(); + if (GS_pid == 0) { /* child */ + _Xconst char **argvp = argv + 8; + + argv[1] = resource.gs_alpha ? "-sDEVICE=x11alpha" : "-sDEVICE=x11"; + Sprintf(arg4 + 14, "%u", GS_page_w); + Sprintf(arg5 + 15, "%u", GS_page_h); + if (resource.gs_safer) *argvp++ = "-dSAFER"; + *argvp = "-"; + (void) close(std_in[1]); + (void) dup2(std_in[0], 0); + (void) close(std_in[0]); + (void) close(std_out[0]); + (void) dup2(std_out[1], 1); + (void) dup2(std_out[1], 2); + (void) close(std_out[1]); + (void) execvp(argv[0] = resource.gs_path, (char * _Xconst *) argv); + Fprintf(stderr, "Execvp of %s failed.\n", argv[0]); + Fflush(stderr); + _exit(1); + } + + (void) close(std_in[0]); + (void) close(std_out[1]); + + if (GS_pid == -1) { /* error */ + perror("[xdvik] vfork"); + (void) close(GS_in); + (void) close(GS_out); + return False; + } + + /* Set std_in for non-blocking I/O */ + (void) fcntl(std_in[1], F_SETFL, + fcntl(std_in[1], F_GETFL, 0) | O_NONBLOCK); + +#ifdef _POSIX_SOURCE + sigpipe_handler_struct.sa_handler = gs_sigpipe_handler; + sigemptyset(&sigpipe_handler_struct.sa_mask); +#endif + +#if HAVE_POLL + fds[0].fd = std_in[1]; + fds[1].fd = std_out[0]; + fds[2].fd = ConnectionNumber(DISP); +#else + numfds = ConnectionNumber(DISP); + if (numfds < std_in[1]) numfds = std_in[1]; + if (numfds < std_out[0]) numfds = std_out[0]; + ++numfds; +#endif + + psp = gs_procs; + GS_active = GS_pending_int = GS_timeout_set = False; + GS_send_byte = NULL; + GS_in_header = True; + GS_pending = 1; + GS_mag = GS_shrink = -1; + + gs_io(str1, sizeof(str1) - 1); + gs_io(psheader, psheaderlen); + gs_io(str2, sizeof(str2) - 1); + GS_in_header = False; + post_send(); + waitack(); + + if (GS_pid < 0) { /* if something happened */ + destroy_gs(); + return False; + } + if (!postscript) toggle_gs(); /* if we got a 'v' already */ + else { + canit = True; /* ||| redraw the page */ + scanned_page = scanned_page_bak = scanned_page_reset; + longjmp(canit_env, 1); + } + return True; +} + +static void +toggle_gs() +{ + if (debug & DBG_PS) Puts("Toggling GS on or off"); + if (postscript) psp.drawbegin = drawbegin_gs; + else { + interrupt_gs(); + psp.drawbegin = drawbegin_none; + } +} + +static void +destroy_gs() +{ + if (debug & DBG_PS) Puts("Destroying GS process"); + if (linepos > line) { + *linepos = '\0'; + Printf("gs: %s\n", line); + linepos = line; + } + if (GS_pid >= 0) { + if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH) + perror("xdvik destroy_gs"); + GS_pid = -1; + scanned_page = scanned_page_bak = scanned_page_reset; + (void) close(GS_in); + (void) close(GS_out); + } + GS_active = GS_pending_int = GS_timeout_set = GS_in_doc = False; + GS_send_byte = NULL; + GS_pending = 0; +} + +static void +interrupt_gs() +{ + static _Xconst char str[] = " stop\n%%xdvimark\n"; + + if (debug & DBG_PS) Puts("Running interrupt_gs()"); + if (GS_pending <= 0) return; /* nothing to do */ + if (GS_timeout_set) return; /* we've done this already */ + (void) X_GETTIMEOFDAY(&GS_timeout); /* set timeout */ + GS_timeout.tv_sec += 5; + GS_timeout_set = True; + if (GS_send_byte != NULL) GS_pending_int = True; + else { + if (GS_active) { + /* + * ||| what I'd really like to do here is cause gs to execute + * the interrupt routine in errordict. But so far (gs 2.6.1) + * that has not been implemented in ghostscript. + */ + gs_io(str, sizeof(str) - 1); + GS_active = False; + } + psp.interrupt = NullProc; /* prevent deep recursion in waitack */ + waitack(); + psp.interrupt = interrupt_gs; + } +} + +static void +endpage_gs() +{ + static _Xconst char str[] = "stop\n%%xdvimark\n"; + + if (debug & DBG_PS) Puts("Running endpage_gs()"); + if (GS_active) { + gs_io(str, sizeof(str) - 1); + GS_active = False; + waitack(); + } +} + +/* + * Checks that the GS interpreter is running correctly. + */ + +static void +checkgs(in_header) + Boolean in_header; +{ + char buf[150]; + + /* For gs 2, we pretty much have to start over to enlarge the window. */ + if ((GS_old && (page_w > GS_page_w || page_h > GS_page_h)) + || GS_alpha != resource.gs_alpha) + destroy_gs(); + + if (GS_pid < 0) + (void) initGS(); + + if (!GS_active) { + /* check whether page_w or page_h have increased */ + if (page_w > GS_page_w || page_h > GS_page_h) { + ++GS_pending; + Sprintf(buf, "H mark /HWSize [%d %d] /ImagingBBox [0 0 %d %d] \ +currentdevice putdeviceprops pop\n\ +initgraphics [0 1 1 0 0 0] concat stop\n%%%%xdvimark\n", + GS_page_w = page_w, GS_page_h = page_h, page_h, page_w); + gs_io(buf, strlen(buf)); + if (!in_header) { + canit = True; /* ||| redraw the page */ + longjmp(canit_env, 1); + } + } + + if (magnification != GS_mag) { + ++GS_pending; + Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \ +end stop\n%%%%xdvimark\n", + GS_mag = magnification); + gs_io(buf, strlen(buf)); + } + + if (mane.shrinkfactor != GS_shrink) { + ++GS_pending; + Sprintf(buf, + "H TeXDict begin %d %d div dup \ +/Resolution X /VResolution X \ +end stop\n%%%%xdvimark\n", + pixels_per_inch, GS_shrink = mane.shrinkfactor); + gs_io(buf, strlen(buf)); + } + } +} + +static void +drawbegin_gs(xul, yul, cp) + int xul, yul; + _Xconst char *cp; +{ + char buf[32]; + static _Xconst char str[] = " TeXDict begin\n"; + + checkgs(False); + + if (!GS_active) { + ++GS_pending; + gs_io(str, sizeof(str) - 1); + GS_active = True; + } + + /* This allows the X side to clear the page */ + XSync(DISP, False); + + Sprintf(buf, "%d %d moveto\n", xul, yul); + gs_io(buf, strlen(buf)); + if (debug & DBG_PS) + Printf("drawbegin at %d,%d: sending `%s'\n", xul, yul, cp); + gs_io(cp, strlen(cp)); +} + +static void +drawraw_gs(cp) + _Xconst char *cp; +{ + if (!GS_active) + return; + if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp); + gs_io(cp, strlen(cp)); + gs_io("\n", 1); +} + +static void +drawfile_gs(cp, f) + _Xconst char *cp; + FILE *f; +{ + Fclose(f); /* don't need it */ + ++n_files_left; + + if (!GS_active) + return; + + if (debug & DBG_PS) Printf("printing file %s\n", cp); + + gs_io("(", 1); + gs_io(cp, strlen(cp)); + gs_io(")run\n", 5); +} + +static void +drawend_gs(cp) + _Xconst char *cp; +{ + if (!GS_active) + return; + if (debug & DBG_PS) Printf("end ps: %s\n", cp); + gs_io(cp, strlen(cp)); + gs_io("\n", 1); +} + +static void +beginheader_gs() +{ + static _Xconst char str[] = "Hsave /xdvi$doc exch def\n"; + + if (debug & DBG_PS) Puts("Running beginheader_gs()"); + + checkgs(True); + + if (GS_active) { + if (!GS_in_header) + oops("Internal error in beginheader_gs().\n"); + return; + } + + GS_in_header = True; + ++GS_pending; + if (GS_in_doc) + gs_io("H", 1); + else { + gs_io(str, sizeof(str) - 1); + GS_in_doc = True; + } + GS_active = True; +} + +static void +endheader_gs() +{ + static _Xconst char str[] = "stop\n%%xdvimark\n"; + + if (debug & DBG_PS) Puts("Running endheader_gs()"); + + if (GS_active) { + gs_io(str, sizeof(str) - 1); + GS_active = False; + GS_in_header = False; + post_send(); + waitack(); + } +} + +static void +newdoc_gs() +{ + static _Xconst char str[] = + "Hxdvi$doc restore stop\n%%xdvimark\n"; + + if (debug & DBG_PS) Puts("Running newdoc_gs()"); + + if (GS_in_doc) { + ++GS_pending; + gs_io(str, sizeof(str) - 1); + GS_mag = GS_shrink = -1; + GS_in_doc = False; + } +} + +#endif /* PS_GS */ |