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 <cursor.h>
11 #include <event.h>
12 #include <bio.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 int
41 spawnwriter(GSInfo *g, Biobuf *b)
42 {
43 char buf[4096];
44 int n;
45 int fd;
47 switch(fork()){
48 case -1: return -1;
49 case 0: break;
50 default: return 0;
51 }
53 Bseek(b, 0, 0);
54 fd = g->gsfd;
55 while((n = Bread(b, buf, sizeof buf)) > 0)
56 write(fd, buf, n);
57 fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n");
58 _exits(0);
59 return -1;
60 }
62 int
63 spawnreader(int fd)
64 {
65 int n, pfd[2];
66 char buf[1024];
68 if(pipe(pfd)<0)
69 return -1;
70 switch(fork()){
71 case -1:
72 return -1;
73 case 0:
74 break;
75 default:
76 close(pfd[0]);
77 return pfd[1];
78 }
80 close(pfd[1]);
81 switch(fork()){
82 case -1:
83 wexits("fork failed");
84 case 0:
85 while((n=read(fd, buf, sizeof buf)) > 0) {
86 write(1, buf, n);
87 write(pfd[0], buf, n);
88 }
89 break;
90 default:
91 while((n=read(pfd[0], buf, sizeof buf)) > 0) {
92 write(1, buf, n);
93 write(fd, buf, n);
94 }
95 break;
96 }
97 postnote(PNGROUP, getpid(), "i'm die-ing");
98 _exits(0);
99 return -1;
102 void
103 spawnmonitor(int fd)
105 char buf[4096];
106 char *xbuf;
107 int n;
108 int out;
109 int first;
111 switch(rfork(RFFDG|RFNOTEG|RFPROC)){
112 case -1:
113 default:
114 return;
116 case 0:
117 break;
120 out = open("/dev/cons", OWRITE);
121 if(out < 0)
122 out = 2;
124 xbuf = buf; /* for ease of acid */
125 first = 1;
126 while((n = read(fd, xbuf, sizeof buf)) > 0){
127 if(first){
128 first = 0;
129 fprint(2, "Ghostscript Error:\n");
131 write(out, xbuf, n);
132 alarm(500);
134 _exits(0);
137 int
138 spawngs(GSInfo *g, char *safer)
140 char *args[16];
141 char tb[32], gb[32];
142 int i, nargs;
143 int devnull;
144 int stdinout[2];
145 int dataout[2];
146 int errout[2];
148 /*
149 * spawn gs
151 * gs's standard input is fed from stdinout.
152 * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout.
153 * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
154 * gs data output is written to fd 3, which is dataout.
155 */
156 if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0)
157 return -1;
159 nargs = 0;
160 args[nargs++] = "gs";
161 args[nargs++] = "-dNOPAUSE";
162 args[nargs++] = safer;
163 args[nargs++] = "-sDEVICE=plan9";
164 args[nargs++] = "-sOutputFile=/fd/3";
165 args[nargs++] = "-dQUIET";
166 args[nargs++] = "-r100";
167 sprint(tb, "-dTextAlphaBits=%d", textbits);
168 sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits);
169 if(textbits)
170 args[nargs++] = tb;
171 if(gfxbits)
172 args[nargs++] = gb;
173 args[nargs++] = "-";
174 args[nargs] = nil;
176 gspid = fork();
177 if(gspid == 0) {
178 close(stdinout[1]);
179 close(dataout[1]);
180 close(errout[1]);
182 /*
183 * Horrible problem: we want to dup fd's 0-4 below,
184 * but some of the source fd's might have those small numbers.
185 * So we need to reallocate those. In order to not step on
186 * anything else, we'll dup the fd's to higher ones using
187 * dup(x, -1), but we need to use up the lower ones first.
188 */
189 while((devnull = open("/dev/null", ORDWR)) < 5)
192 stdinout[0] = dup(stdinout[0], -1);
193 errout[0] = dup(errout[0], -1);
194 dataout[0] = dup(dataout[0], -1);
196 dup(stdinout[0], 0);
197 dup(errout[0], 1);
198 dup(devnull, 2); /* never anything useful */
199 dup(dataout[0], 3);
200 dup(stdinout[0], 4);
201 for(i=5; i<20; i++)
202 close(i);
203 exec("/bin/gs", args);
204 wexits("exec");
206 close(stdinout[0]);
207 close(errout[0]);
208 close(dataout[0]);
209 atexit(killgs);
211 if(teegs)
212 stdinout[1] = spawnreader(stdinout[1]);
214 gsfd = g->gsfd = stdinout[1];
215 g->gsdfd = dataout[1];
216 g->gspid = gspid;
218 spawnmonitor(errout[1]);
219 Binit(&g->gsrd, g->gsfd, OREAD);
221 gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
222 gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
223 waitgs(g);
225 return 0;
228 int
229 gscmd(GSInfo *gs, char *fmt, ...)
231 char buf[1024];
232 int n;
234 va_list v;
235 va_start(v, fmt);
236 n = vseprint(buf, buf+sizeof buf, fmt, v) - buf;
237 if(n <= 0)
238 return n;
240 if(chatty) {
241 fprint(2, "cmd: ");
242 write(2, buf, n);
245 if(write(gs->gsfd, buf, n) != 0)
246 return -1;
248 return n;
251 /*
252 * set the dimensions of the bitmap we expect to get back from GS.
253 */
254 void
255 setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
257 Rectangle pbox;
259 if(chatty)
260 fprint(2, "setdim: bbox=%R\n", bbox);
262 if(ppi)
263 gs->ppi = ppi;
265 gscmd(gs, "mark\n");
266 if(ppi)
267 gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi);
269 if(!Dx(bbox))
270 bbox = Rect(0, 0, 612, 792); /* 8½×11 */
272 if(landscape)
273 pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
274 else
275 pbox = bbox;
277 gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
278 gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
279 gscmd(gs, "currentdevice putdeviceprops pop\n");
280 gscmd(gs, "/#copies 1 store\n");
282 if(!eqpt(bbox.min, ZP))
283 gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y);
285 switch(landscape){
286 case 0:
287 break;
288 case 1:
289 gscmd(gs, "%d 0 translate\n", Dy(bbox));
290 gscmd(gs, "90 rotate\n");
291 break;
294 waitgs(gs);
297 void
298 waitgs(GSInfo *gs)
300 /* we figure out that gs is done by telling it to
301 * print something and waiting until it does.
302 */
303 char *p;
304 Biobuf *b = &gs->gsrd;
305 uchar buf[1024];
306 int n;
308 /* gscmd(gs, "(\\n**bstack\\n) print flush\n"); */
309 /* gscmd(gs, "stack flush\n"); */
310 /* gscmd(gs, "(**estack\\n) print flush\n"); */
311 gscmd(gs, "(\\n/*GO.SYSIN DD\\n) PAGE==\n"); */
313 alarm(300*1000);
314 for(;;) {
315 p = Brdline(b, '\n');
316 if(p == nil) {
317 n = Bbuffered(b);
318 if(n <= 0)
319 break;
320 if(n > sizeof buf)
321 n = sizeof buf;
322 Bread(b, buf, n);
323 continue;
325 p[Blinelen(b)-1] = 0;
326 if(chatty) fprint(2, "p: ");
327 if(chatty) write(2, p, Blinelen(b)-1);
328 if(chatty) fprint(2, "\n");
329 if(strstr(p, "Error:")) {
330 alarm(0);
331 fprint(2, "ghostscript error: %s\n", p);
332 wexits("gs error");
335 if(strstr(p, "//GO.SYSIN DD")) {
336 break;
339 alarm(0);