123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /*
- * gs interface for page.
- * ps.c and pdf.c both use these routines.
- * a caveat: if you run more than one gs, only the last
- * one gets killed by killgs
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <event.h>
- #include <bio.h>
- #include "page.h"
- static int gspid; /* globals for atexit */
- static int gsfd;
- static void killgs(void);
- static void
- killgs(void)
- {
- char tmpfile[100];
- close(gsfd);
- postnote(PNGROUP, getpid(), "die");
- /*
- * from ghostscript's use.txt:
- * ``Ghostscript currently doesn't do a very good job of deleting temporary
- * files when it exits; you may have to delete them manually from time to
- * time.''
- */
- sprint(tmpfile, "/tmp/gs_%.5da", (gspid+300000)%100000);
- if(chatty) fprint(2, "remove %s...\n", tmpfile);
- remove(tmpfile);
- sleep(100);
- postnote(PNPROC, gspid, "die yankee pig dog");
- }
- int
- spawnwriter(GSInfo *g, Biobuf *b)
- {
- char buf[4096];
- int n;
- int fd;
- switch(fork()){
- case -1: return -1;
- case 0: break;
- default: return 0;
- }
- Bseek(b, 0, 0);
- fd = g->gsfd;
- while((n = Bread(b, buf, sizeof buf)) > 0)
- write(fd, buf, n);
- fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n");
- _exits(0);
- return -1;
- }
- int
- spawnreader(int fd)
- {
- int n, pfd[2];
- char buf[1024];
- if(pipe(pfd)<0)
- return -1;
- switch(fork()){
- case -1:
- return -1;
- case 0:
- break;
- default:
- close(pfd[0]);
- return pfd[1];
- }
- close(pfd[1]);
- switch(fork()){
- case -1:
- wexits("fork failed");
- case 0:
- while((n=read(fd, buf, sizeof buf)) > 0) {
- write(1, buf, n);
- write(pfd[0], buf, n);
- }
- break;
- default:
- while((n=read(pfd[0], buf, sizeof buf)) > 0) {
- write(1, buf, n);
- write(fd, buf, n);
- }
- break;
- }
- postnote(PNGROUP, getpid(), "i'm die-ing");
- _exits(0);
- return -1;
- }
- void
- spawnmonitor(int fd)
- {
- char buf[4096];
- char *xbuf;
- int n;
- int out;
- int first;
- switch(rfork(RFFDG|RFNOTEG|RFPROC)){
- case -1:
- default:
- return;
- case 0:
- break;
- }
- out = open("/dev/cons", OWRITE);
- if(out < 0)
- out = 2;
- xbuf = buf; /* for ease of acid */
- first = 1;
- while((n = read(fd, xbuf, sizeof buf)) > 0){
- if(first){
- first = 0;
- fprint(2, "Ghostscript Error:\n");
- }
- write(out, xbuf, n);
- alarm(500);
- }
- _exits(0);
- }
- int
- spawngs(GSInfo *g, char *safer)
- {
- char *args[16];
- char tb[32], gb[32];
- int i, nargs;
- int devnull;
- int stdinout[2];
- int dataout[2];
- int errout[2];
- /*
- * spawn gs
- *
- * gs's standard input is fed from stdinout.
- * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout.
- * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
- * gs data output is written to fd 3, which is dataout.
- */
- if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0)
- return -1;
- nargs = 0;
- args[nargs++] = "gs";
- args[nargs++] = "-dNOPAUSE";
- args[nargs++] = safer;
- args[nargs++] = "-sDEVICE=plan9";
- args[nargs++] = "-sOutputFile=/fd/3";
- args[nargs++] = "-dQUIET";
- args[nargs++] = "-r100";
- sprint(tb, "-dTextAlphaBits=%d", textbits);
- sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits);
- if(textbits)
- args[nargs++] = tb;
- if(gfxbits)
- args[nargs++] = gb;
- args[nargs++] = "-";
- args[nargs] = nil;
- gspid = fork();
- if(gspid == 0) {
- close(stdinout[1]);
- close(dataout[1]);
- close(errout[1]);
- /*
- * Horrible problem: we want to dup fd's 0-4 below,
- * but some of the source fd's might have those small numbers.
- * So we need to reallocate those. In order to not step on
- * anything else, we'll dup the fd's to higher ones using
- * dup(x, -1), but we need to use up the lower ones first.
- */
- while((devnull = open("/dev/null", ORDWR)) < 5)
- ;
- stdinout[0] = dup(stdinout[0], -1);
- errout[0] = dup(errout[0], -1);
- dataout[0] = dup(dataout[0], -1);
- dup(stdinout[0], 0);
- dup(errout[0], 1);
- dup(devnull, 2); /* never anything useful */
- dup(dataout[0], 3);
- dup(stdinout[0], 4);
- for(i=5; i<20; i++)
- close(i);
- exec("/bin/gs", args);
- wexits("exec");
- }
- close(stdinout[0]);
- close(errout[0]);
- close(dataout[0]);
- atexit(killgs);
- if(teegs)
- stdinout[1] = spawnreader(stdinout[1]);
- gsfd = g->gsfd = stdinout[1];
- g->gsdfd = dataout[1];
- g->gspid = gspid;
- spawnmonitor(errout[1]);
- Binit(&g->gsrd, g->gsfd, OREAD);
- gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
- gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
- waitgs(g);
- return 0;
- }
- int
- gscmd(GSInfo *gs, char *fmt, ...)
- {
- char buf[1024];
- int n;
- va_list v;
- va_start(v, fmt);
- n = vseprint(buf, buf+sizeof buf, fmt, v) - buf;
- if(n <= 0)
- return n;
- if(chatty) {
- fprint(2, "cmd: ");
- write(2, buf, n);
- }
- if(write(gs->gsfd, buf, n) != 0)
- return -1;
- return n;
- }
- /*
- * set the dimensions of the bitmap we expect to get back from GS.
- */
- void
- setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
- {
- Rectangle pbox;
- if(chatty)
- fprint(2, "setdim: bbox=%R\n", bbox);
- if(ppi)
- gs->ppi = ppi;
- gscmd(gs, "mark\n");
- if(ppi)
- gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi);
- if(!Dx(bbox))
- bbox = Rect(0, 0, 612, 792); /* 8½×11 */
- switch(landscape){
- case 0:
- pbox = bbox;
- break;
- case 1:
- pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
- break;
- }
- gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
- gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
- gscmd(gs, "currentdevice putdeviceprops pop\n");
- gscmd(gs, "/#copies 1 store\n");
- if(!eqpt(bbox.min, ZP))
- gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y);
- switch(landscape){
- case 0:
- break;
- case 1:
- gscmd(gs, "%d 0 translate\n", Dy(bbox));
- gscmd(gs, "90 rotate\n");
- break;
- }
- waitgs(gs);
- }
- void
- waitgs(GSInfo *gs)
- {
- /* we figure out that gs is done by telling it to
- * print something and waiting until it does.
- */
- char *p;
- Biobuf *b = &gs->gsrd;
- uchar buf[1024];
- int n;
- // gscmd(gs, "(\\n**bstack\\n) print flush\n");
- // gscmd(gs, "stack flush\n");
- // gscmd(gs, "(**estack\\n) print flush\n");
- gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
- alarm(300*1000);
- for(;;) {
- p = Brdline(b, '\n');
- if(p == nil) {
- n = Bbuffered(b);
- if(n <= 0)
- break;
- if(n > sizeof buf)
- n = sizeof buf;
- Bread(b, buf, n);
- continue;
- }
- p[Blinelen(b)-1] = 0;
- if(chatty) fprint(2, "p: ");
- if(chatty) write(2, p, Blinelen(b)-1);
- if(chatty) fprint(2, "\n");
- if(strstr(p, "Error:")) {
- alarm(0);
- fprint(2, "ghostscript error: %s\n", p);
- wexits("gs error");
- }
- if(strstr(p, "//GO.SYSIN DD")) {
- break;
- }
- }
- alarm(0);
- }
|