Blob


1 /*
2 * gs interface for page.
3 * ps.c and pdf.c both use these routines.
4 * a caveat: if you run more than one gs, only the last
5 * one gets killed by killgs
6 */
7 #include <u.h>
8 #include <libc.h>
9 #include <draw.h>
10 #include <thread.h>
11 #include <bio.h>
12 #include <cursor.h>
13 #include "page.h"
15 static int gspid; /* globals for atexit */
16 static int gsfd;
17 static void killgs(void);
19 static void
20 killgs(void)
21 {
22 char tmpfile[100];
24 close(gsfd);
25 postnote(PNGROUP, getpid(), "die");
27 /*
28 * from ghostscript's use.txt:
29 * ``Ghostscript currently doesn't do a very good job of deleting temporary
30 * files when it exits; you may have to delete them manually from time to
31 * time.''
32 */
33 sprint(tmpfile, "/tmp/gs_%.5da", (gspid+300000)%100000);
34 if(chatty) fprint(2, "remove %s...\n", tmpfile);
35 remove(tmpfile);
36 sleep(100);
37 postnote(PNPROC, gspid, "die yankee pig dog");
38 }
40 void
41 spawnreader(void *cp)
42 {
43 int n, fd, pfd[2];
44 char buf[1024];
46 recv(cp, &fd);
48 if(pipe(pfd)<0)
49 wexits("pipe failed");
51 send(cp, &pfd[1]);
53 while((n=read(pfd[0], buf, sizeof buf)) > 0) {
54 write(1, buf, n);
55 write(fd, buf, n);
56 }
58 close(pfd[0]);
59 threadexits(0);
60 }
62 void
63 spawnmonitor(void *cp)
64 {
65 char buf[4096];
66 char *xbuf;
67 int fd;
68 int n;
69 int out;
70 int first;
72 recv(cp, &fd);
74 out = open("/dev/tty", OWRITE);
75 if(out < 0)
76 out = 2;
78 xbuf = buf; /* for ease of acid */
79 first = 1;
80 while((n = read(fd, xbuf, sizeof buf)) > 0){
81 if(first){
82 first = 0;
83 fprint(2, "Ghostscript Error:\n");
84 }
85 write(out, xbuf, n);
86 alarm(500);
87 }
88 threadexits(0);
89 }
91 int
92 spawngs(GSInfo *g, char *safer)
93 {
94 Channel *cp;
95 char *args[16];
96 char tb[32], gb[32];
97 int i, nargs;
98 int devnull;
99 int stdinp[2];
100 int stdoutp[2];
101 int dataout[2];
102 int errout[2];
104 /*
105 * spawn gs
107 * gs's standard input is fed from stdinout.
108 * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout.
109 * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
110 * gs data output is written to fd 3, which is dataout.
111 */
112 if(pipe(stdinp)<0 || pipe(stdoutp)<0 || pipe(dataout)<0 || pipe(errout)<0)
113 return -1;
115 nargs = 0;
116 args[nargs++] = "gs";
117 args[nargs++] = "-dNOPAUSE";
118 args[nargs++] = "-dNOPROMPT";
119 args[nargs++] = "-dDELAYSAFER";
120 args[nargs++] = "-dQUIET";
121 args[nargs++] = "-sDEVICE=bmp16m";
122 args[nargs++] = "-sOutputFile=/dev/fd/3";
123 args[nargs++] = "-r100";
124 sprint(tb, "-dTextAlphaBits=%d", textbits);
125 sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits);
126 if(textbits)
127 args[nargs++] = tb;
128 if(gfxbits)
129 args[nargs++] = gb;
130 args[nargs] = nil;
132 gspid = fork();
133 if(gspid == 0) {
134 close(stdinp[1]);
135 close(stdoutp[0]);
136 close(dataout[0]);
137 close(errout[0]);
139 /*
140 * Horrible problem: we want to dup fd's 0-4 below,
141 * but some of the source fd's might have those small numbers.
142 * So we need to reallocate those. In order to not step on
143 * anything else, we'll dup the fd's to higher ones using
144 * dup(x, -1), but we need to use up the lower ones first.
145 */
146 while((devnull = open("/dev/null", ORDWR)) < 5)
149 stdinp[0] = dup(stdinp[0], -1);
150 stdoutp[1] = dup(stdoutp[1], -1);
151 errout[1] = dup(errout[1], -1);
152 dataout[1] = dup(dataout[1], -1);
154 dup(stdinp[0], 0);
155 dup(errout[1], 1);
156 dup(devnull, 2); /* never anything useful */
157 dup(dataout[1], 3);
158 dup(stdoutp[1], 4);
159 for(i=5; i<20; i++)
160 close(i);
161 execvp("gs", args);
162 wexits("exec");
164 close(stdinp[0]);
165 close(stdoutp[1]);
166 close(errout[1]);
167 close(dataout[1]);
168 atexit(killgs);
170 cp = chancreate(sizeof(int), 0);
171 if(teegs) {
172 proccreate(spawnreader, cp, mainstacksize);
173 send(cp, &stdoutp[0]);
174 recv(cp, &stdoutp[0]);
177 gsfd = g->gsfd = stdinp[1];
178 g->gspid = gspid;
179 g->g.fd = dataout[0];
180 g->g.name = "gs pipe";
181 g->g.type = Ibmp;
183 proccreate(spawnmonitor, cp, mainstacksize);
184 send(cp, &errout[0]);
185 chanfree(cp);
187 Binit(&g->gsrd, stdoutp[0], OREAD);
189 gscmd(g, "/PAGEDIDSHOWPAGE false def\n");
190 gscmd(g, "/showpage { /PAGEDIDSHOWPAGE true def showpage } bind def\n");
191 gscmd(g, "/PAGEFLUSH { PAGEDIDSHOWPAGE not {showpage} if /PAGEDIDSHOWPAGE false def } def\n");
193 gscmd(g, "/PAGEOUT (/dev/fd/4) (w) file def\n");
194 if(!strcmp(safer, "-dSAFER"))
195 gscmd(g, ".setsafe\n");
196 gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
197 waitgs(g);
199 return 0;
202 int
203 gscmd(GSInfo *gs, char *fmt, ...)
205 char buf[1024];
206 int n;
208 va_list v;
209 va_start(v, fmt);
210 n = vseprint(buf, buf+sizeof buf, fmt, v) - buf;
211 if(n <= 0)
212 return n;
214 if(chatty) {
215 fprint(2, "cmd: ");
216 write(2, buf, n);
219 if(write(gs->gsfd, buf, n) != 0)
220 return -1;
222 return n;
225 /*
226 * set the dimensions of the bitmap we expect to get back from GS.
227 */
228 void
229 setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
231 Rectangle pbox;
233 if(chatty)
234 fprint(2, "setdim: bbox=%R\n", bbox);
236 if(ppi)
237 gs->ppi = ppi;
239 gscmd(gs, "mark\n");
240 if(ppi)
241 gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi);
243 if(!Dx(bbox))
244 bbox = Rect(0, 0, 612, 792); /* 8½×11 */
246 switch(landscape){
247 case 0:
248 pbox = bbox;
249 break;
250 default:
251 pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
252 break;
254 gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
255 gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
256 gscmd(gs, "currentdevice putdeviceprops pop\n");
257 gscmd(gs, "/#copies 1 store\n");
259 if(!eqpt(bbox.min, ZP))
260 gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y);
262 switch(landscape){
263 case 0:
264 break;
265 case 1:
266 gscmd(gs, "%d 0 translate\n", Dy(bbox));
267 gscmd(gs, "90 rotate\n");
268 break;
271 waitgs(gs);
274 void
275 waitgs(GSInfo *gs)
277 /* we figure out that gs is done by telling it to
278 * print something and waiting until it does.
279 */
280 char *p;
281 Biobuf *b = &gs->gsrd;
282 uchar buf[1024];
283 int n;
285 // gscmd(gs, "(\\n**bstack\\n) print flush\n");
286 // gscmd(gs, "stack flush\n");
287 // gscmd(gs, "(**estack\\n) print flush\n");
288 gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
290 alarm(300*1000);
291 for(;;) {
292 p = Brdline(b, '\n');
293 if(p == nil) {
294 n = Bbuffered(b);
295 if(n <= 0)
296 break;
297 if(n > sizeof buf)
298 n = sizeof buf;
299 Bread(b, buf, n);
300 continue;
302 p[Blinelen(b)-1] = 0;
303 if(chatty) fprint(2, "p: ");
304 if(chatty) write(2, p, Blinelen(b)-1);
305 if(chatty) fprint(2, "\n");
306 if(strstr(p, "Error:")) {
307 alarm(0);
308 fprint(2, "ghostscript error: %s\n", p);
309 wexits("gs error");
312 if(strstr(p, "//GO.SYSIN DD")) {
313 break;
316 alarm(0);