source: trunk/third/tex/xdvi/psgs.c @ 12209

Revision 12209, 21.8 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12208, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1994 Paul Vojta.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include "xdvi.h"
27#include <X11/Xatom.h>
28
29#include <memory.h>
30#include <signal.h>
31#include <sys/file.h>   /* this defines FASYNC */
32
33/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
34#if !defined(O_NONBLOCK) && defined(O_NDELAY)
35#define O_NONBLOCK O_NDELAY
36#endif
37
38/* Condition for retrying a write */
39#include <errno.h>
40
41#ifdef  X_NOT_STDC_ENV
42extern  int     errno;
43#endif
44
45#ifdef  EWOULDBLOCK
46#ifdef  EAGAIN
47#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
48#else   /* EAGAIN */
49#define AGAIN_CONDITION (errno == EWOULDBLOCK)
50#endif  /* EAGAIN */
51#else   /* EWOULDBLOCK */
52#ifdef  EAGAIN
53#define AGAIN_CONDITION (errno == EAGAIN)
54#endif  /* EAGAIN */
55#endif  /* EWOULDBLOCK */
56
57#ifdef  _POSIX_SOURCE
58#include <limits.h>
59#endif
60#ifndef PATH_MAX
61#define PATH_MAX 512
62#endif
63
64#ifdef  STREAMSCONN
65#include <poll.h>
66#endif
67
68#if     HAS_SIGIO && !defined(STRMS2)
69#include <signal.h>
70#ifndef FASYNC
71#undef  HAS_SIGIO
72#define HAS_SIGIO 0
73#endif
74#endif
75
76#ifdef  VFORK
77#if     VFORK == include
78#include <vfork.h>
79#endif
80#else
81#define vfork   fork
82#endif
83
84#ifndef X_GETTIMEOFDAY
85#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*) NULL)
86#endif
87
88#ifndef timercmp
89#define timercmp(a, b, cmp)     ((a)->tv_sec cmp (b)->tv_sec || \
90                ((a)->tv_sec == (b)->tv_sec && (a)->tv_usec cmp (b)->tv_usec))
91#endif  /* timercmp */
92
93extern  _Xconst char    psheader[];
94extern  int             psheaderlen;
95
96#define postscript      resource._postscript
97#define fore_Pixel      resource._fore_Pixel
98#define back_Pixel      resource._back_Pixel
99
100/* global procedures (besides initGS) */
101
102static  void    toggle_gs ARGS((void));
103static  void    destroy_gs ARGS((void));
104static  void    interrupt_gs ARGS((void));
105static  void    endpage_gs ARGS((void));
106static  void    drawbegin_gs ARGS((int, int, _Xconst char *));
107static  void    drawraw_gs ARGS((_Xconst char *));
108static  void    drawfile_gs ARGS((_Xconst char *, FILE *));
109static  void    drawend_gs ARGS((_Xconst char *));
110static  void    beginheader_gs ARGS((void));
111static  void    endheader_gs ARGS((void));
112static  void    newdoc_gs ARGS((void));
113
114static  struct psprocs  gs_procs = {
115        /* toggle */            toggle_gs,
116        /* destroy */           destroy_gs,
117        /* interrupt */         interrupt_gs,
118        /* endpage */           endpage_gs,
119        /* drawbegin */         drawbegin_gs,
120        /* drawraw */           drawraw_gs,
121        /* drawfile */          drawfile_gs,
122        /* drawend */           drawend_gs,
123        /* beginheader */       beginheader_gs,
124        /* endheader */         endheader_gs,
125        /* newdoc */            newdoc_gs};
126
127static  int     std_in[2];
128static  int     std_out[2];
129
130#define GS_in   (std_in[1])
131#define GS_out  (std_out[0])
132
133                /* some arguments are filled in later */
134static  char    arg4[]  = "-dDEVICEWIDTH=xxxxxxxxxx";
135static  char    arg5[]  = "-dDEVICEHEIGHT=xxxxxxxxxx";
136
137static  _Xconst char    *argv[] = {NULL, "-sDEVICE=x11", "-dNOPAUSE", "-q",
138                                   arg4, arg5,
139                                   "-dDEVICEXRESOLUTION=72",
140                                   "-dDEVICEYRESOLUTION=72",
141                                   NULL, NULL, NULL};
142
143static  pid_t           GS_pid;
144static  unsigned int    GS_page_w;      /* how big our current page is */
145static  unsigned int    GS_page_h;
146static  int             GS_mag;         /* magnification currently in use */
147static  int             GS_shrink;      /* shrink factor currently in use */
148static  Boolean         GS_active;      /* if we've started a page yet */
149static  int             GS_pending;     /* number of ack's we're expecting */
150static  _Xconst char    *GS_send_byte;  /* next byte to send to gs */
151static  _Xconst char    *GS_send_end;   /* last + 1 byte to send to gs */
152static  Boolean         GS_in_header;   /* if we're sending a header */
153static  Boolean         GS_in_doc;      /* if we've sent header information */
154static  Boolean         GS_pending_int; /* if interrupt rec'd while in gs_io()*/
155static  Boolean         GS_timeout_set; /* if there's a timeout set */
156static  struct timeval  GS_timeout;     /* when to time out */
157static  Boolean         GS_old;         /* if we're using gs 2.xx */
158
159static  Atom            gs_atom;
160static  Atom            gs_colors_atom;
161
162#define Landscape       90
163
164/*
165 *      Our replacement for setenv(), which is not available on all systems.
166 */
167
168#ifndef HAVE_SETENV     /* define this if you're a performance freak and
169                           if your system has setenv. */
170#define setenv(var, str, repl)  _setenv(var, str)       /* repl always True */
171
172extern  char    **environ;
173
174static  void
175_setenv(var, str)
176        _Xconst char    *var;
177        _Xconst char    *str;
178{
179        int             len1;
180        int             len2;
181        char            *newvar;
182        char            **linep;
183        static  Boolean malloced = False;
184
185        len1 = strlen(var);
186        len2 = strlen(str) + 1;
187        newvar = xmalloc((unsigned int) len1 + len2 + 1, "_setenv");
188        (void) bcopy(var, newvar, len1);
189        newvar[len1++] = '=';
190        (void) bcopy(str, newvar + len1, len2);
191        for (linep = environ; *linep != NULL; ++linep)
192            if (memcmp(*linep, newvar, len1) == 0) {
193                *linep = newvar;
194                return;
195            }
196        len1 = linep - environ;
197        if (malloced)
198            environ = (char **) xrealloc((char *) environ,
199                (unsigned int) (len1 + 2) * sizeof(char *),
200                "string list in _setenv");
201        else {
202            linep = (char **) xmalloc((unsigned int)(len1 + 2) * sizeof(char *),
203                "string list in _setenv");
204            (void) bcopy((char *) environ, (char *) linep,
205                len1 * sizeof(char *));
206            environ = linep;
207            malloced = True;
208        }
209        environ[len1] = newvar;
210        environ[len1 + 1] = NULL;
211}
212
213#endif  /* HAVE_SETENV */
214
215/*
216 *      ghostscript I/O code.  This should send PS code to ghostscript,
217 *      receive acknowledgements, and receive X events in the meantime.
218 *      It also checks for SIGPIPE errors.
219 */
220
221#ifndef STREAMSCONN
222static  int             numfds;
223static  fd_set          readfds;
224static  fd_set          writefds;
225#define XDVI_ISSET(a, b, c)     FD_ISSET(a, b)
226#else   /* STREAMSCONN */
227static  struct pollfd   fds[3] = {{0, POLLOUT, 0},
228                                  {0, POLLIN, 0},
229                                  {0, POLLIN, 0}};
230#define XDVI_ISSET(a, b, c)     (fds[c].revents)
231#endif  /* STREAMSCONN */
232
233#define LINELEN 81
234static  char    line[LINELEN + 1];
235static  char    *linepos        = line;
236static  char    ackstr[]        = "\347\310\376";
237static  char    oldstr[]        = "\347\310\375";
238
239static  void
240showto(q)
241        char    *q;
242{
243        char    *p      = line;
244        char    *p1;
245
246        while (p < q) {
247            p1 = memchr(p, '\n', q - p);
248            if (p1 == NULL) p1 = q;
249            *p1 = '\0';
250            Printf("gs: %s\n", p);
251            p = p1 + 1;
252        }
253}
254
255static  void
256read_from_gs() {
257        int     bytes;
258        char    *line_end;
259        char    *p;
260
261        bytes = read(GS_out, linepos, line + LINELEN - linepos);
262        if (bytes < 0) return;
263        line_end = linepos + bytes;
264        /* Check for ack strings */
265        for (p = line; p < line_end - 2; ++p) {
266            p = memchr(p, '\347', line_end - p - 2);
267            if (p == NULL) break;
268            if (memcmp(p, ackstr, 3) == 0) {
269                --GS_pending;
270                if (debug & DBG_PS)
271                    Printf("Got GS ack; %d pending.\n", GS_pending);
272            }
273            else if (memcmp(p, oldstr, 3) == 0) {
274                if (debug & DBG_PS)
275                    Puts("Using old GS version.");
276                GS_old = True;
277            }
278            else continue;
279
280            showto(p);
281            p += 3;
282            (void) bcopy(p, line, line_end - p);
283            line_end -= p - line;
284            linepos = p = line;
285            --p;
286        }
287        *line_end = '\0';
288        p = rindex(linepos, '\n');
289        if (p != NULL) {
290            ++p;
291            showto(p);
292            (void) bcopy(p, line, line_end - p);
293            line_end -= p - line;
294        }
295        linepos = line_end;
296        /*
297         * Normally we'd hold text until a newline character, but the buffer
298         * is full.  So we flush it, being careful not to cut up an ack string.
299         */
300        if (linepos >= line + LINELEN) {
301            p = line + LINELEN;
302            if ((*--p != '\347' && *--p != '\347' && *--p != '\347')
303                    || (memcmp(p, ackstr, line + LINELEN - p) != 0
304                    && memcmp(p, oldstr, line + LINELEN - p) != 0))
305                p = line + LINELEN;
306            *p = '\0';
307            Printf("gs: %s\n", line);
308            *p = '\347';
309            linepos = line;
310            while (p < line + LINELEN) *linepos++ = *p++;
311        }
312}
313
314/*
315 *      For handling of SIGPIPE signals from gs_io()
316 */
317
318static  Boolean sigpipe_error = False;
319
320/* ARGSUSED */
321static  void
322gs_sigpipe_handler(sig, code, scp, addr)
323        int     sig;
324        int     code;
325        struct sigcontext *scp;
326        char    *addr;
327{
328        sigpipe_error = True;
329}
330
331#ifdef  _POSIX_SOURCE
332static  struct sigaction sigpipe_handler_struct;
333        /* initialized to {gs_sigpipe_handler, (sigset_t) 0, 0} in initGS */
334#endif
335
336/*
337 *      Clean up after gs_io()
338 */
339
340static  void
341post_send()
342{
343        if (sigpipe_error) {
344            Fputs("ghostscript died unexpectedly.\n", stderr);
345            destroy_gs();
346            draw_bbox();
347        }
348
349        if (GS_pending_int) {
350            GS_pending_int = False;
351            interrupt_gs();
352        }
353}
354
355/*
356 *      This routine does two things.  It either sends a string of bytes to
357 *      the GS interpreter, or waits for acknowledgement from GS.
358 */
359
360#define waitack()       gs_io(NULL, 0)
361
362static  void
363gs_io(cp, len)
364        _Xconst char    *cp;
365        int             len;
366{
367        int             bytes;
368#ifdef  _POSIX_SOURCE
369        struct sigaction orig;
370#else
371        void            (*orig)();
372#endif
373        struct timeval  tv;
374#ifndef STREAMSCONN
375        struct timeval  *timeout = (struct timeval *) NULL;
376#else
377        int             timeout = -1;
378        int             retval;
379        int             offset  = 0;
380#endif
381#if     HAS_SIGIO && defined(FASYNC)
382        int             oldflags;
383#endif
384
385        if (GS_pid < 0)
386            return;
387
388        if (cp != NULL) {       /* if sending bytes */
389#ifdef  _POSIX_SOURCE
390            (void) sigaction(SIGPIPE, &sigpipe_handler_struct, &orig);
391#else
392            orig = signal(SIGPIPE, gs_sigpipe_handler);
393#endif
394            sigpipe_error = False;
395            GS_send_byte = cp;
396            GS_send_end = cp + len;
397        }
398        else {          /* if waiting for acknowledgement */
399            if (GS_pending == 0)
400                return;
401#ifdef  STREAMSCONN
402            offset = 1;
403#endif
404        }
405
406#if     HAS_SIGIO && defined(FASYNC)
407        oldflags = fcntl(ConnectionNumber(DISP), F_GETFL, 0);
408        (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags & ~FASYNC);
409#endif
410
411        for (;;) {
412
413            /* Handle timeout. */
414
415            if (GS_timeout_set) {
416                (void) X_GETTIMEOFDAY(&tv);
417#ifndef STREAMSCONN
418                if (!timercmp(&tv, &GS_timeout, <)) {
419                    destroy_gs();
420                    break;
421                }
422                tv.tv_sec = GS_timeout.tv_sec - tv.tv_sec;
423                tv.tv_usec = GS_timeout.tv_usec + 1000000 - tv.tv_usec;
424                if (tv.tv_usec >= 1000000) tv.tv_usec -= 1000000;
425                else --tv.tv_sec;
426                timeout = &tv;
427#else
428                timeout = 1000 * (int) (GS_timeout.tv_sec - tv.tv_sec)
429                    + ((long) GS_timeout.tv_usec - (long) tv.tv_usec) / 1000;
430                if (timeout <= 0) {
431                    destroy_gs();
432                    break;
433                }
434#endif
435            }
436
437#ifndef STREAMSCONN
438            FD_ZERO(&readfds);
439            FD_SET(ConnectionNumber(DISP), &readfds);
440            FD_SET(GS_out, &readfds);
441
442            FD_ZERO(&writefds);
443            if (GS_send_byte != NULL) FD_SET(GS_in, &writefds);
444
445            if (select(numfds, &readfds, &writefds, (fd_set *) NULL, timeout)
446                    < 0 && errno != EINTR) {
447                perror("select (xdvi gs_io)");
448                break;
449            }
450#else   /* STREAMSCONN */
451            fds[0].revents = 0;
452            for (;;) {
453                retval = poll(fds + offset, XtNumber(fds) - offset, timeout);
454                if (retval >= 0 || errno != EAGAIN) break;
455            }
456            if (retval < 0) {
457                perror("poll (xdvi gs_io)");
458                break;
459            }
460#endif  /* STREAMSCONN */
461
462            if (XDVI_ISSET(GS_out, &readfds, 1)) {
463                read_from_gs();
464                if (GS_pending <= 0) {
465                    GS_timeout_set = False;
466                    break;
467                }
468            }
469            if (XDVI_ISSET(GS_in, &writefds, 0)) {
470                bytes = write(GS_in, GS_send_byte, GS_send_end - GS_send_byte);
471                if (bytes == -1) {
472                    if (!AGAIN_CONDITION) perror("xdvi gs_io");
473                }
474                else {
475                    GS_send_byte += bytes;
476                    if (GS_send_byte == GS_send_end) {
477                        GS_send_byte = NULL;
478                        break;
479                    }
480                }
481                if (sigpipe_error) break;
482            }
483            if (XDVI_ISSET(ConnectionNumber(DISP), &readfds, 2)) {
484                ps_read_events(False, False);
485                if (GS_pid < 0) break;  /* if timeout occurred */
486                if (GS_pending <= 0) {
487                    GS_timeout_set = False;
488                    break;
489                }
490            }
491        }
492
493#if     HAS_SIGIO && defined(FASYNC)
494        (void) fcntl(ConnectionNumber(DISP), F_SETFL, oldflags);
495#endif
496
497        if (cp != NULL) {
498            /* put back generic handler for SIGPIPE */
499#ifdef  _POSIX_SOURCE
500            (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
501#else
502            (void) signal(SIGPIPE, orig);
503#endif
504            if (!GS_in_header)
505                post_send();
506        }
507}
508
509/*
510 *      Fork a process to run ghostscript.  This is done using the
511 *      x11 device (which needs to be compiled in).  Normally the x11
512 *      device uses ClientMessage events to communicate with the calling
513 *      program, but we don't do this.  The reason for using the ClientMessage
514 *      events is that otherwise ghostview doesn't know when a non-conforming
515 *      postscript program calls showpage.   That doesn't affect us here,
516 *      since in fact we disable showpage.
517 */
518
519Boolean
520initGS()
521{
522        char    buf[100];
523                /*
524                 * This string reads chunks (delimited by %%xdvimark).
525                 * The first character of a chunk tells whether a given chunk
526                 * is to be done within save/restore or not.
527                 * The `H' at the end tells it that the first group is a
528                 * header; i.e., no save/restore.
529                 * `execute' is unique to ghostscript.
530                 */
531        static  _Xconst char    str1[]  = "\
532/xdvi$run {$error /newerror false put {currentfile cvx execute} stopped pop} \
533  def \
534/xdvi$ack (\347\310\376) def \
535/xdvi$dslen countdictstack def \
536{currentfile read pop 72 eq \
537    {xdvi$run} \
538    {/xdvi$sav save def xdvi$run \
539      clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
540  ifelse \
541  {(%%xdvimark) currentfile =string {readline} stopped \
542    {clear} {pop eq {exit} if} ifelse }loop \
543  flushpage xdvi$ack print flush \
544}loop\nH";
545        static  _Xconst char    str2[]  = "[0 1 1 0 0 0] concat\n\
546revision 300 lt{(\347\310\375) print flush}if\n\
547stop\n%%xdvimark\n";
548
549        gs_atom = XInternAtom(DISP, "GHOSTVIEW", False);
550        /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */
551        Sprintf(buf, "%ld %d 0 0 %u %u 72 72",
552            None,               /* bpixmap */
553            Landscape,          /* orientation */
554            GS_page_h = page_h, GS_page_w = page_w);
555        XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8,
556            PropModeReplace, (unsigned char *) buf, strlen(buf));
557
558        gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False);
559        Sprintf(buf, "%s %ld %ld", resource.gs_palette, fore_Pixel, back_Pixel);
560        XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8,
561            PropModeReplace, (unsigned char *) buf, strlen(buf));
562
563        XSync(DISP, False);             /* update the window */
564
565        if (xpipe(std_in) != 0 || xpipe(std_out) != 0) {
566            perror("[xdvi] pipe");
567            return False;
568        }
569        Fflush(stderr);         /* to avoid double flushing */
570        GS_pid = vfork();
571        if (GS_pid == 0) {              /* child */
572            _Xconst char **argvp = argv + 8;
573
574            Sprintf(arg4 + 14, "%u", GS_page_w);
575            Sprintf(arg5 + 15, "%u", GS_page_h);
576            if (resource.gs_safer) *argvp++ = "-dSAFER";
577            *argvp = "-";
578            Sprintf(buf, "%ld", mane.win);
579            setenv("GHOSTVIEW", buf, True);
580            setenv("DISPLAY", XDisplayString(DISP), True);
581            (void) close(std_in[1]);
582            (void) dup2(std_in[0], 0);
583            (void) close(std_in[0]);
584            (void) close(std_out[0]);
585            (void) dup2(std_out[1], 1);
586            (void) dup2(std_out[1], 2);
587            (void) close(std_out[1]);
588            (void) execvp(argv[0] = resource.gs_path, (char * _Xconst *) argv);
589            Fprintf(stderr, "Execvp of %s failed.\n", argv[0]);
590            Fflush(stderr);
591            _exit(1);
592        }
593        if (GS_pid == -1) {     /* error */
594            perror("[xdvi] vfork");
595            return False;
596        }
597        (void) close(std_in[0]);
598        (void) close(std_out[1]);
599
600        /* Set std_in for non-blocking I/O */
601        (void) fcntl(std_in[1], F_SETFL,
602            fcntl(std_in[1], F_GETFL, 0) | O_NONBLOCK);
603
604#ifdef  _POSIX_SOURCE
605        sigpipe_handler_struct.sa_handler = gs_sigpipe_handler;
606        sigemptyset(&sigpipe_handler_struct.sa_mask);
607#endif
608
609#ifndef STREAMSCONN
610        numfds = ConnectionNumber(DISP);
611        if (numfds < std_in[1]) numfds = std_in[1];
612        if (numfds < std_out[0]) numfds = std_out[0];
613        ++numfds;
614#else   /* STREAMSCONN */
615        fds[0].fd = std_in[1];
616        fds[1].fd = std_out[0];
617        fds[2].fd = ConnectionNumber(DISP);
618#endif  /* STREAMSCONN */
619
620        psp = gs_procs;
621        GS_active = GS_pending_int = GS_timeout_set = False;
622        GS_send_byte = NULL;
623        GS_in_header = True;
624        GS_pending = 1;
625        GS_mag = GS_shrink = -1;
626
627        gs_io(str1, sizeof(str1) - 1);
628        gs_io(psheader, psheaderlen);
629        gs_io(str2, sizeof(str2) - 1);
630        GS_in_header = False;
631        post_send();
632        waitack();
633
634        if (GS_pid < 0) {               /* if something happened */
635            destroy_gs();
636            return False;
637        }
638        if (!postscript) toggle_gs();   /* if we got a 'v' already */
639        else {
640            canit = True;               /* ||| redraw the page */
641            scanned_page = scanned_page_bak = scanned_page_reset;
642            longjmp(canit_env, 1);
643        }
644        return True;
645}
646
647static  void
648toggle_gs()
649{
650        if (debug & DBG_PS) Puts("Toggling GS on or off");
651        if (postscript) psp.drawbegin = drawbegin_gs;
652        else {
653            interrupt_gs();
654            psp.drawbegin = drawbegin_none;
655        }
656}
657
658static  void
659destroy_gs()
660{
661        if (debug & DBG_PS) Puts("Destroying GS process");
662        if (linepos > line) {
663            *linepos = '\0';
664            Printf("gs: %s\n", line);
665            linepos = line;
666        }
667        if (GS_pid >= 0) {
668            if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH)
669                perror("xdvi destroy_gs");
670            GS_pid = -1;
671            scanned_page = scanned_page_bak = scanned_page_reset;
672        }
673        (void) close(GS_in);
674        (void) close(GS_out);
675        GS_active = GS_pending_int = GS_timeout_set = GS_in_doc = False;
676        GS_send_byte = NULL;
677        GS_pending = 0;
678}
679
680static  void
681interrupt_gs()
682{
683        static  _Xconst char    str[]   = " stop\n%%xdvimark\n";
684
685        if (debug & DBG_PS) Puts("Running interrupt_gs()");
686        if (GS_pending <= 0) return;    /* nothing to do */
687        if (GS_timeout_set) return;     /* we've done this already */
688        (void) X_GETTIMEOFDAY(&GS_timeout);     /* set timeout */
689        GS_timeout.tv_sec += 5;
690        GS_timeout_set = True;
691        if (GS_send_byte != NULL) GS_pending_int = True;
692        else {
693            if (GS_active) {
694                /*
695                 * ||| what I'd really like to do here is cause gs to execute
696                 * the interrupt routine in errordict.  But so far (gs 2.6.1)
697                 * that has not been implemented in ghostscript.
698                 */
699                gs_io(str, sizeof(str) - 1);
700                GS_active = False;
701            }
702            psp.interrupt = NullProc;   /* prevent deep recursion in waitack */
703            waitack();
704            psp.interrupt = interrupt_gs;
705        }
706}
707
708static  void
709endpage_gs()
710{
711        static  _Xconst char    str[]   = "stop\n%%xdvimark\n";
712
713        if (debug & DBG_PS) Puts("Running endpage_gs()");
714        if (GS_active) {
715            gs_io(str, sizeof(str) - 1);
716            GS_active = False;
717            waitack();
718        }
719}
720
721/*
722 *      Checks that the GS interpreter is running correctly.
723 */
724
725static  void
726checkgs(in_header)
727        Boolean in_header;
728{
729        char    buf[150];
730
731        /* For gs 2, we pretty much have to start over to enlarge the window. */
732        if (GS_old && (page_w > GS_page_w || page_h > GS_page_h))
733            destroy_gs();
734
735        if (GS_pid < 0)
736            (void) initGS();
737
738        if (!GS_active) {
739            /* check whether page_w or page_h have increased */
740            if (page_w > GS_page_w || page_h > GS_page_h) {
741                ++GS_pending;
742                Sprintf(buf, "H mark /HWSize [%d %d] /ImagingBBox [0 0 %d %d] \
743currentdevice putdeviceprops pop\n\
744initgraphics [0 1 1 0 0 0] concat stop\n%%%%xdvimark\n",
745                    GS_page_w = page_w, GS_page_h = page_h, page_h, page_w);
746                gs_io(buf, strlen(buf));
747                if (!in_header) {
748                    canit = True;               /* ||| redraw the page */
749                    longjmp(canit_env, 1);
750                }
751            }
752
753            if (magnification != GS_mag) {
754                ++GS_pending;
755                Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
756end stop\n%%%%xdvimark\n",
757                    GS_mag = magnification);
758                gs_io(buf, strlen(buf));
759            }
760
761            if (mane.shrinkfactor != GS_shrink) {
762                ++GS_pending;
763                Sprintf(buf,
764                    "H TeXDict begin %d %d div dup \
765/Resolution X /VResolution X \
766end stop\n%%%%xdvimark\n",
767                    pixels_per_inch, GS_shrink = mane.shrinkfactor);
768                gs_io(buf, strlen(buf));
769            }
770        }
771}
772
773static  void
774drawbegin_gs(xul, yul, cp)
775        int             xul, yul;
776        _Xconst char    *cp;
777{
778        char    buf[32];
779        static  _Xconst char    str[]   = " TeXDict begin\n";
780
781        checkgs(False);
782
783        if (!GS_active) {
784            ++GS_pending;
785            gs_io(str, sizeof(str) - 1);
786            GS_active = True;
787        }
788
789        /* This allows the X side to clear the page */
790        XSync(DISP, False);
791
792        Sprintf(buf, "%d %d moveto\n", xul, yul);
793        gs_io(buf, strlen(buf));
794        if (debug & DBG_PS)
795            Printf("drawbegin at %d,%d:  sending `%s'\n", xul, yul, cp);
796        gs_io(cp, strlen(cp));
797}
798
799static  void
800drawraw_gs(cp)
801        _Xconst char    *cp;
802{
803        if (!GS_active)
804            return;
805        if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp);
806        gs_io(cp, strlen(cp));
807        gs_io("\n", 1);
808}
809
810static  void
811drawfile_gs(cp, f)
812        _Xconst char    *cp;
813        FILE            *f;
814{
815        char    buf[PATH_MAX + 7];
816
817        Fclose(f);              /* don't need it */
818        ++n_files_left;
819
820        if (!GS_active)
821            return;
822
823        if (debug & DBG_PS) Printf("printing file %s\n", cp);
824        Sprintf(buf, "(%s)run\n", cp);
825        gs_io(buf, strlen(buf));
826}
827
828static  void
829drawend_gs(cp)
830        _Xconst char    *cp;
831{
832        if (!GS_active)
833            return;
834        if (debug & DBG_PS) Printf("end ps: %s\n", cp);
835        gs_io(cp, strlen(cp));
836        gs_io("\n", 1);
837}
838
839static  void
840beginheader_gs()
841{
842        static  _Xconst char    str[]   = "Hsave /xdvi$doc exch def\n";
843
844        if (debug & DBG_PS) Puts("Running beginheader_gs()");
845
846        checkgs(True);
847
848        if (GS_active) {
849            if (!GS_in_header)
850                oops("Internal error in beginheader_gs().\n");
851            return;
852        }
853
854        GS_in_header = True;
855        ++GS_pending;
856        if (GS_in_doc)
857            gs_io("H", 1);
858        else {
859            gs_io(str, sizeof(str) - 1);
860            GS_in_doc = True;
861        }
862        GS_active = True;
863}
864
865static  void
866endheader_gs()
867{
868        static  _Xconst char    str[]   = "stop\n%%xdvimark\n";
869
870        if (debug & DBG_PS) Puts("Running endheader_gs()");
871
872        if (GS_active) {
873            gs_io(str, sizeof(str) - 1);
874            GS_active = False;
875            GS_in_header = False;
876            post_send();
877            waitack();
878        }
879}
880
881static  void
882newdoc_gs()
883{
884        static  _Xconst char    str[]   =
885                                "Hxdvi$doc restore stop\n%%xdvimark\n";
886
887        if (debug & DBG_PS) Puts("Running newdoc_gs()");
888
889        if (GS_in_doc) {
890            ++GS_pending;
891            gs_io(str, sizeof(str) - 1);
892            GS_mag = GS_shrink = -1;
893            GS_in_doc = False;
894        }
895}
Note: See TracBrowser for help on using the repository browser.