You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
839 lines
21 KiB
839 lines
21 KiB
/* |
|
* Copyright (c) 1994 Paul Vojta. All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
*/ |
|
|
|
/* |
|
* ||| to do: |
|
* *interpreter resource |
|
* -safer argument |
|
* palette resource and arguments |
|
*/ |
|
|
|
#include "oconfig.h" |
|
#ifdef PS_GS /* whole file */ |
|
|
|
#include "kpathsea/c-pathmx.h" |
|
#include <X11/Xatom.h> |
|
#include <sys/time.h> /* for timeval */ |
|
|
|
#include <signal.h> |
|
|
|
#ifdef NeXT |
|
typedef int pid_t; |
|
#endif |
|
|
|
/* 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 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 */ |
|
|
|
|
|
#ifdef STREAMSCONN |
|
#include <poll.h> |
|
#else |
|
#ifdef _AIX |
|
#include <sys/select.h> /* for fd_set stuff on RS/6000 */ |
|
#else |
|
#ifdef HAVE_SYS_BSDTYPES_H |
|
#include <sys/bsdtypes.h> /* for fd_set on ISC 4.0 */ |
|
#endif /* not <sys/bsdtypes.h> */ |
|
#endif /* not _AIX */ |
|
#endif /* not STREAMSCONN */ |
|
|
|
#if HAS_SIGIO |
|
#include <fcntl.h> |
|
#include <signal.h> |
|
#ifndef FASYNC |
|
#undef HAS_SIGIO |
|
#define HAS_SIGIO 0 |
|
#endif |
|
#endif |
|
|
|
#ifdef VFORK |
|
#if VFORK == include |
|
#include <vfork.h> |
|
#endif |
|
#else |
|
#define vfork fork |
|
#endif |
|
|
|
extern _Xconst char psheader[]; |
|
extern int psheaderlen; |
|
|
|
#define postscript _postscript |
|
#define fore_Pixel _fore_Pixel |
|
#define back_Pixel _back_Pixel |
|
|
|
extern void qt_processEvents(); |
|
|
|
/* 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, char *)); |
|
static void drawraw_gs ARGS((char *)); |
|
static void drawfile_gs ARGS((char *)); |
|
static void drawend_gs ARGS((char *)); |
|
|
|
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}; |
|
|
|
static int std_in[2]; |
|
static int std_out[2]; |
|
|
|
#define GS_in (std_in[1]) |
|
#define GS_out (std_out[0]) |
|
|
|
static char *argv[] = {"gs", "-sDEVICE=x11alpha", "-dNOPAUSE", "-dSAFER", "-q", "-", 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 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 Boolean GS_sending; /* if we're in the middle of send() */ |
|
static Boolean GS_pending_int; /* if interrupt rec'd while in send() */ |
|
|
|
static Atom gs_atom; |
|
static Atom gs_colors_atom; |
|
#define XtPageOrientationPortrait 0 |
|
|
|
/* |
|
* Our replacement for setenv(), which is not available on all systems. |
|
*/ |
|
|
|
#ifndef HAVE_SETENV /* define this if you're a performance freak and |
|
if your system has setenv. */ |
|
#define setenv(var, str, repl) _setenv(var, str) /* repl always True */ |
|
|
|
extern char **environ; |
|
|
|
static void |
|
_setenv(var, str) |
|
_Xconst char *var; |
|
_Xconst char *str; |
|
{ |
|
int len1; |
|
int len2; |
|
char *newvar; |
|
char **linep; |
|
static Boolean malloced = False; |
|
|
|
len1 = strlen(var); |
|
len2 = strlen(str) + 1; |
|
newvar = xmalloc((unsigned int) len1 + len2 + 1, "_setenv"); |
|
(void) bcopy(var, newvar, len1); |
|
newvar[len1++] = '='; |
|
(void) bcopy(str, newvar + len1, len2); |
|
for (linep = environ; *linep != NULL; ++linep) |
|
if (memcmp(*linep, newvar, len1) == 0) { |
|
*linep = newvar; |
|
return; |
|
} |
|
len1 = linep - environ; |
|
if (malloced) { |
|
environ = (char **) realloc((char *) environ, |
|
(unsigned int) (len1 + 2) * sizeof(char *)); |
|
if (environ == NULL) |
|
oops("! Cannot allocate %d bytes for string list in _setenv.\n", |
|
(len1 + 2) * sizeof(char *)); |
|
} |
|
else { |
|
linep = (char **) xmalloc((unsigned int)(len1 + 2) * sizeof(char *), |
|
"string list in _setenv"); |
|
(void) bcopy((char *) environ, (char *) linep, |
|
len1 * sizeof(char *)); |
|
environ = linep; |
|
malloced = True; |
|
} |
|
environ[len1] = newvar; |
|
environ[len1 + 1] = NULL; |
|
} |
|
|
|
#endif /* HAVE_SETENV */ |
|
|
|
/* |
|
* 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. |
|
*/ |
|
|
|
#ifndef STREAMSCONN |
|
static int numfds; |
|
static fd_set readfds; |
|
static fd_set writefds; |
|
#define XDVI_ISSET(a, b, c) FD_ISSET(a, b) |
|
#else /* STREAMSCONN */ |
|
struct pollfd fds[3] = {{0, POLLOUT, 0}, |
|
{0, POLLIN, 0}, |
|
{0, POLLIN, 0}}; |
|
#define XDVI_ISSET(a, b, c) (fds[c].revents) |
|
#endif /* STREAMSCONN */ |
|
|
|
#define LINELEN 81 |
|
static char line[LINELEN + 1]; |
|
static char *linepos = line; |
|
static char ackstr[] = "\347\310\376"; |
|
|
|
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); |
|
if (p > line) { |
|
*p = '\0'; |
|
Printf("gs: %s\n", line); |
|
} |
|
p += 3; |
|
(void) bcopy(p, line, line_end - p); |
|
line_end -= p - line; |
|
linepos = p = line; |
|
--p; |
|
} |
|
} |
|
for (;;) { |
|
p = memchr(linepos, '\n', line_end - linepos); |
|
if (p == NULL) break; |
|
*p = '\0'; |
|
Printf("gs: %s\n", line); |
|
++p; |
|
(void) bcopy(p, line, line_end - p); |
|
line_end -= p - line; |
|
linepos = 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) |
|
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 send() |
|
*/ |
|
|
|
static Boolean sigpipe_error = False; |
|
|
|
/* ARGSUSED */ |
|
static void |
|
gs_sigpipe_handler(sig, code, scp, addr) |
|
int sig; |
|
int code; |
|
struct sigcontext *scp; |
|
char *addr; |
|
{ |
|
sigpipe_error = True; |
|
} |
|
|
|
#ifdef _POSIX_SOURCE |
|
static struct sigaction sigpipe_handler_struct; |
|
/* initialized to {gs_sigpipe_handler, (sigset_t) 0, 0} in initGS */ |
|
#endif |
|
|
|
/* |
|
* This actually sends the bytes to ghostscript. |
|
*/ |
|
|
|
static void |
|
send(cp, len) |
|
_Xconst char *cp; |
|
int len; |
|
{ |
|
int bytes; |
|
#ifdef _POSIX_SOURCE |
|
struct sigaction orig; |
|
#else |
|
void (*orig)(); |
|
#endif |
|
#ifdef STREAMSCONN |
|
int retval; |
|
#endif |
|
|
|
if (GS_pid < 0) return; |
|
#ifdef _POSIX_SOURCE |
|
(void) sigaction(SIGPIPE, &sigpipe_handler_struct, &orig); |
|
#else |
|
orig = signal(SIGPIPE, gs_sigpipe_handler); |
|
#endif |
|
sigpipe_error = False; |
|
GS_sending = True; |
|
|
|
#if HAS_SIGIO |
|
(void) fcntl(ConnectionNumber(DISP), F_SETFL, |
|
fcntl(ConnectionNumber(DISP), F_GETFL, 0) & ~FASYNC); |
|
#endif |
|
|
|
#ifndef STREAMSCONN |
|
FD_ZERO(&readfds); |
|
FD_ZERO(&writefds); |
|
#endif |
|
|
|
for (;;) { |
|
|
|
#ifndef STREAMSCONN |
|
FD_SET(ConnectionNumber(DISP), &readfds); |
|
FD_SET(GS_in, &writefds); |
|
FD_SET(GS_out, &readfds); |
|
|
|
if (select(numfds, &readfds, &writefds, (fd_set *) NULL, |
|
(struct timeval *) NULL) < 0 && errno != EINTR) { |
|
perror("select (gs_send)"); |
|
break; |
|
} |
|
#else /* STREAMSCONN */ |
|
for (;;) { |
|
retval = poll(fds, XtNumber(fds), -1); |
|
if (retval >= 0 || errno != EAGAIN) break; |
|
} |
|
if (retval < 0) { |
|
perror("poll (gs_send)"); |
|
break; |
|
} |
|
#endif /* STREAMSCONN */ |
|
|
|
if (XDVI_ISSET(GS_out, &readfds, 1)) |
|
read_from_gs(); |
|
if (XDVI_ISSET(GS_in, &writefds, 0)) { |
|
bytes = write(GS_in, cp, len); |
|
if (bytes == -1) { |
|
if (!AGAIN_CONDITION) perror("gs_send"); |
|
} |
|
else { |
|
cp += bytes; |
|
len -= bytes; |
|
if (len == 0) break; |
|
} |
|
if (sigpipe_error) break; |
|
} |
|
if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { |
|
#ifndef KDVI |
|
allow_can = False; |
|
read_events(False); |
|
allow_can = True; |
|
if (GS_pid < 0) break; /* if timeout occurred */ |
|
#else |
|
qt_processEvents(); |
|
#endif /* KDVI */ |
|
} |
|
} |
|
|
|
#if HAS_SIGIO |
|
(void) fcntl(ConnectionNumber(DISP), F_SETFL, |
|
fcntl(ConnectionNumber(DISP), F_GETFL, 0) | FASYNC); |
|
#endif |
|
|
|
/* put back generic handler for SIGPIPE */ |
|
#ifdef _POSIX_SOURCE |
|
(void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL); |
|
#else |
|
(void) signal(SIGPIPE, orig); |
|
#endif |
|
GS_sending = False; |
|
|
|
if (sigpipe_error) { |
|
Fputs("ghostscript died unexpectedly.\n", stderr); |
|
destroy_gs(); |
|
draw_bbox(); |
|
} |
|
|
|
if (GS_pending_int) { |
|
GS_pending_int = False; |
|
interrupt_gs(); |
|
} |
|
} |
|
|
|
/* |
|
* Wait for acknowledgement from gs. |
|
*/ |
|
|
|
static void |
|
waitack(waittime) |
|
int waittime; |
|
{ |
|
struct timeval tv; |
|
struct timeval tv2; |
|
#ifndef STREAMSCONN |
|
struct timeval *timeout = (struct timeval *) NULL; |
|
#else |
|
int timeout = -1; |
|
int retval; |
|
#endif |
|
#if HAS_SIGIO |
|
int oldflags; |
|
#endif |
|
|
|
if (GS_pending == 0) return; |
|
#if HAS_SIGIO |
|
oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0); |
|
(void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC); |
|
#endif |
|
if (waittime != 0) { |
|
(void) gettimeofday(&tv, (struct timezone *) NULL); |
|
tv.tv_sec += waittime; |
|
#ifndef STREAMSCONN |
|
timeout = &tv2; |
|
#endif |
|
} |
|
#ifndef STREAMSCONN |
|
FD_ZERO(&readfds); |
|
#endif |
|
while (GS_pending > 0) { |
|
if (waittime != 0) { |
|
(void) gettimeofday(&tv2, (struct timezone *) NULL); |
|
#ifndef STREAMSCONN |
|
if (timercmp(&tv2, &tv, >=)) { |
|
destroy_gs(); |
|
break; |
|
} |
|
tv2.tv_sec = tv.tv_sec - tv2.tv_sec; |
|
tv2.tv_usec = tv.tv_usec + 1000000 - tv2.tv_usec; |
|
if (tv2.tv_usec >= 1000000) tv2.tv_usec -= 1000000; |
|
else --tv2.tv_sec; |
|
#else |
|
timeout = 1000 * (int) (tv.tv_sec - tv2.tv_sec) |
|
+ ((long) tv.tv_usec - (long) tv2.tv_usec) / 1000; |
|
if (timeout <= 0) { |
|
destroy_gs(); |
|
break; |
|
} |
|
#endif |
|
} |
|
#ifndef STREAMSCONN |
|
FD_SET(ConnectionNumber(DISP), &readfds); |
|
FD_SET(GS_out, &readfds); |
|
if (select(numfds, &readfds, (fd_set *) NULL, (fd_set *) NULL, |
|
timeout) < 0 && errno != EINTR) { |
|
perror("select (gs_waitack)"); |
|
break; |
|
} |
|
#else /* STREAMSCONN */ |
|
for (;;) { |
|
retval = poll(fds + 1, XtNumber(fds) - 1, timeout); |
|
if (retval >= 0 || errno != EAGAIN) break; |
|
} |
|
if (retval < 0) { |
|
perror("poll (gs_waitack)"); |
|
break; |
|
} |
|
#endif /* STREAMSCONN */ |
|
|
|
|
|
if (XDVI_ISSET(GS_out, &readfds, 1)) |
|
read_from_gs(); |
|
if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) { |
|
#ifndef KDVI |
|
allow_can = False; |
|
read_events(False); |
|
allow_can = True; |
|
#else |
|
qt_processEvents(); |
|
#endif /* KDVI */ |
|
} |
|
} |
|
#if HAS_SIGIO |
|
(void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags); |
|
#endif |
|
/* If you bail out here, change the call in interrupt_gs(). */ |
|
} |
|
|
|
/* |
|
* 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]; |
|
/* |
|
* 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[] = "matrix currentmatrix \ |
|
dup dup 4 get round 4 exch put \ |
|
dup dup 5 get round 5 exch put setmatrix\n\ |
|
stop\n%%xdvimark\n"; |
|
|
|
#ifndef KDVI |
|
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 */ |
|
XtPageOrientationPortrait, |
|
GS_page_w = page_w, GS_page_h = page_h); |
|
XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8, |
|
PropModeReplace, (unsigned char *) buf, strlen(buf)); |
|
|
|
gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False); |
|
Sprintf(buf, "%s %ld %ld", "Color", fore_Pixel, back_Pixel); |
|
XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8, |
|
PropModeReplace, (unsigned char *) buf, strlen(buf)); |
|
|
|
XSync(DISP, False); /* update the window */ |
|
|
|
if (xpipe(std_in) != 0 || xpipe(std_out) != 0) { |
|
perror("pipe"); |
|
return False; |
|
} |
|
Fflush(stderr); /* to avoid double flushing */ |
|
GS_pid = vfork(); |
|
if (GS_pid == 0) { /* child */ |
|
Sprintf(buf, "%ld", mane.win); |
|
setenv("GHOSTVIEW", buf, True); |
|
setenv("DISPLAY", XDisplayString(DISP), True); |
|
(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], argv); |
|
Fprintf(stderr, "Execvp of %s failed.\n", argv[0]); |
|
Fflush(stderr); |
|
_exit(1); |
|
} |
|
#else /* KDVI */ |
|
extern int useAlpha; |
|
extern Window mainwin; |
|
|
|
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 */ |
|
XtPageOrientationPortrait, |
|
GS_page_w = page_w, GS_page_h = page_h); |
|
XChangeProperty(DISP, mainwin, gs_atom, XA_STRING, 8, |
|
PropModeReplace, (unsigned char *) buf, strlen(buf)); |
|
|
|
gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False); |
|
Sprintf(buf, "%s %ld %ld", "Color", fore_Pixel, back_Pixel); |
|
XChangeProperty(DISP, mainwin, gs_colors_atom, XA_STRING, 8, |
|
PropModeReplace, (unsigned char *) buf, strlen(buf)); |
|
|
|
XSync(DISP, False); /* update the window */ |
|
|
|
if (xpipe(std_in) != 0 || xpipe(std_out) != 0) { |
|
perror("pipe"); |
|
return False; |
|
} |
|
Fflush(stderr); /* to avoid double flushing */ |
|
GS_pid = vfork(); |
|
if (GS_pid == 0) { /* child */ |
|
Sprintf(buf, "%ld %ld", mainwin, mane.win); |
|
setenv("GHOSTVIEW", buf, True); |
|
setenv("DISPLAY", XDisplayString(DISP), True); |
|
(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]); |
|
argv[1] = useAlpha ? "-sDEVICE=x11alpha" : "-sDEVICE=x11"; |
|
(void) execvp(argv[0], argv); |
|
Fprintf(stderr, "Execvp of %s failed.\n", argv[0]); |
|
Fflush(stderr); |
|
_exit(1); |
|
} |
|
#endif /* KDVI */ |
|
if (GS_pid == -1) { /* error */ |
|
perror("vfork"); |
|
return False; |
|
} |
|
(void) close(std_in[0]); |
|
(void) close(std_out[1]); |
|
|
|
/* 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 |
|
|
|
#ifndef STREAMSCONN |
|
numfds = ConnectionNumber(DISP); |
|
if (numfds < std_in[1]) numfds = std_in[1]; |
|
if (numfds < std_out[0]) numfds = std_out[0]; |
|
++numfds; |
|
#else /* STREAMSCONN */ |
|
fds[0].fd = std_in[1]; |
|
fds[1].fd = std_out[0]; |
|
fds[2].fd = ConnectionNumber(DISP); |
|
#endif /* STREAMSCONN */ |
|
|
|
psp = gs_procs; |
|
GS_active = GS_sending = GS_pending_int = False; |
|
GS_pending = 1; |
|
GS_mag = GS_shrink = -1; |
|
|
|
send(str1, sizeof(str1) - 1); |
|
send(psheader, psheaderlen); |
|
Sprintf(buf, "[1 0 0 -1 0 %d] concat\n", page_h); |
|
send(buf, strlen(buf)); |
|
send(str2, sizeof(str2) - 1); |
|
waitack(0); |
|
|
|
if (GS_pid < 0) { /* if something happened */ |
|
destroy_gs(); |
|
return False; |
|
} |
|
if (!postscript) toggle_gs(); /* if we got a 'v' already */ |
|
else { |
|
#ifndef KDVI |
|
canit = True; /* ||| redraw the page */ |
|
longjmp(canit_env, 1); |
|
#endif /* KDVI */ |
|
} |
|
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("destroy_gs"); |
|
GS_pid = -1; |
|
} |
|
(void) close(GS_in); |
|
(void) close(GS_out); |
|
GS_active = GS_sending = GS_pending_int = False; |
|
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_sending) 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. |
|
*/ |
|
send(str, sizeof(str) - 1); |
|
GS_active = False; |
|
} |
|
psp.interrupt = NullProc; /* prevent deep recursion in waitack */ |
|
waitack(5); |
|
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) { |
|
send(str, sizeof(str) - 1); |
|
GS_active = False; |
|
waitack(0); |
|
} |
|
} |
|
|
|
static void |
|
drawbegin_gs(xul, yul, cp) |
|
int xul, yul; |
|
char *cp; |
|
{ |
|
char buf[100]; |
|
static _Xconst char str[] = " TeXDict begin\n"; |
|
|
|
/* check page_w and page_h to see that they haven't increased */ |
|
if (page_w > GS_page_w || page_h > GS_page_h) { |
|
/* It would be nice if we could just resize the window, but I |
|
* don't see a convenient way to do that. */ |
|
destroy_gs(); |
|
} |
|
|
|
if (GS_pid < 0) |
|
(void) initGS(); |
|
|
|
if (!GS_active) { |
|
if (magnification != GS_mag) { |
|
Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \ |
|
end stop\n%%%%xdvimark\n", |
|
GS_mag = magnification); |
|
send(buf, strlen(buf)); |
|
++GS_pending; |
|
} |
|
if (mane.shrinkfactor != GS_shrink) { |
|
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); |
|
send(buf, strlen(buf)); |
|
++GS_pending; |
|
} |
|
send(str, sizeof(str) - 1); |
|
GS_active = True; |
|
++GS_pending; |
|
} |
|
|
|
/* This allows the X side to clear the page */ |
|
XSync(DISP, False); |
|
|
|
Sprintf(buf, "%d %d moveto\n", xul, yul); |
|
send(buf, strlen(buf)); |
|
if (debug & DBG_PS) |
|
Printf("drawbegin at %d,%d: sending `%s'\n", xul, yul, cp); |
|
send(cp, strlen(cp)); |
|
} |
|
|
|
static void |
|
drawraw_gs(cp) |
|
char *cp; |
|
{ |
|
int len = strlen(cp); |
|
|
|
if (!GS_active) |
|
return; |
|
if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp); |
|
cp[len] = '\n'; |
|
send(cp, len + 1); |
|
} |
|
|
|
static void |
|
drawfile_gs(cp) |
|
char *cp; |
|
{ |
|
char buf[PATH_MAX + 7]; |
|
|
|
if (!GS_active) |
|
return; |
|
if (debug & DBG_PS) Printf("printing file %s\n", cp); |
|
Sprintf(buf, "(%s)run\n", cp); |
|
send(buf, strlen(buf)); |
|
} |
|
|
|
static void |
|
drawend_gs(cp) |
|
char *cp; |
|
{ |
|
if (!GS_active) |
|
return; |
|
if (debug & DBG_PS) Printf("end ps: %s\n", cp); |
|
send(cp, strlen(cp)); |
|
send("\n", 1); |
|
} |
|
|
|
#endif /* PS_GS */
|
|
|