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 <event.h>
11 #include <bio.h>
12 #include "page.h"
14 static int gspid; /* globals for atexit */
15 static int gsfd;
16 static void killgs(void);
18 static void
19 killgs(void)
20 {
21 char tmpfile[100];
23 close(gsfd);
24 postnote(PNGROUP, getpid(), "die");
26 /*
27 * from ghostscript's use.txt:
28 * ``Ghostscript currently doesn't do a very good job of deleting temporary
29 * files when it exits; you may have to delete them manually from time to
30 * time.''
31 */
32 sprint(tmpfile, "/tmp/gs_%.5da", (gspid+300000)%100000);
33 if(chatty) fprint(2, "remove %s...\n", tmpfile);
34 remove(tmpfile);
35 sleep(100);
36 postnote(PNPROC, gspid, "die yankee pig dog");
37 }
39 int
40 spawnwriter(GSInfo *g, Biobuf *b)
41 {
42 char buf[4096];
43 int n;
44 int fd;
46 switch(fork()){
47 case -1: return -1;
48 case 0: break;
49 default: return 0;
50 }
52 Bseek(b, 0, 0);
53 fd = g->gsfd;
54 while((n = Bread(b, buf, sizeof buf)) > 0)
55 write(fd, buf, n);
56 fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n");
57 _exits(0);
58 return -1;
59 }
61 int
62 spawnreader(int fd)
63 {
64 int n, pfd[2];
65 char buf[1024];
67 if(pipe(pfd)<0)
68 return -1;
69 switch(fork()){
70 case -1:
71 return -1;
72 case 0:
73 break;
74 default:
75 close(pfd[0]);
76 return pfd[1];
77 }
79 close(pfd[1]);
80 switch(fork()){
81 case -1:
82 wexits("fork failed");
83 case 0:
84 while((n=read(fd, buf, sizeof buf)) > 0) {
85 write(1, buf, n);
86 write(pfd[0], buf, n);
87 }
88 break;
89 default:
90 while((n=read(pfd[0], buf, sizeof buf)) > 0) {
91 write(1, buf, n);
92 write(fd, buf, n);
93 }
94 break;
95 }
96 postnote(PNGROUP, getpid(), "i'm die-ing");
97 _exits(0);
98 return -1;
99 }
101 void
102 spawnmonitor(int fd)
104 char buf[4096];
105 char *xbuf;
106 int n;
107 int out;
108 int first;
110 switch(rfork(RFFDG|RFNOTEG|RFPROC)){
111 case -1:
112 default:
113 return;
115 case 0:
116 break;
119 out = open("/dev/cons", OWRITE);
120 if(out < 0)
121 out = 2;
123 xbuf = buf; /* for ease of acid */
124 first = 1;
125 while((n = read(fd, xbuf, sizeof buf)) > 0){
126 if(first){
127 first = 0;
128 fprint(2, "Ghostscript Error:\n");
130 write(out, xbuf, n);
131 alarm(500);
133 _exits(0);
136 int
137 spawngs(GSInfo *g)
139 char *args[16];
140 char tb[32], gb[32];
141 int i, nargs;
142 int devnull;
143 int stdinout[2];
144 int dataout[2];
145 int errout[2];
147 /*
148 * spawn gs
150 * gs's standard input is fed from stdinout.
151 * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout.
152 * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
153 * gs data output is written to fd 3, which is dataout.
154 */
155 if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0)
156 return -1;
158 nargs = 0;
159 args[nargs++] = "gs";
160 args[nargs++] = "-dNOPAUSE";
161 args[nargs++] = "-dSAFER";
162 args[nargs++] = "-sDEVICE=plan9";
163 args[nargs++] = "-sOutputFile=/fd/3";
164 args[nargs++] = "-dQUIET";
165 args[nargs++] = "-r100";
166 sprint(tb, "-dTextAlphaBits=%d", textbits);
167 sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits);
168 if(textbits)
169 args[nargs++] = tb;
170 if(gfxbits)
171 args[nargs++] = gb;
172 args[nargs++] = "-";
173 args[nargs] = nil;
175 gspid = fork();
176 if(gspid == 0) {
177 close(stdinout[1]);
178 close(dataout[1]);
179 close(errout[1]);
181 /*
182 * Horrible problem: we want to dup fd's 0-4 below,
183 * but some of the source fd's might have those small numbers.
184 * So we need to reallocate those. In order to not step on
185 * anything else, we'll dup the fd's to higher ones using
186 * dup(x, -1), but we need to use up the lower ones first.
187 */
188 while((devnull = open("/dev/null", ORDWR)) < 5)
191 stdinout[0] = dup(stdinout[0], -1);
192 errout[0] = dup(errout[0], -1);
193 dataout[0] = dup(dataout[0], -1);
195 dup(stdinout[0], 0);
196 dup(errout[0], 1);
197 dup(devnull, 2); /* never anything useful */
198 dup(dataout[0], 3);
199 dup(stdinout[0], 4);
200 for(i=5; i<20; i++)
201 close(i);
202 exec("/bin/gs", args);
203 wexits("exec");
205 close(stdinout[0]);
206 close(errout[0]);
207 close(dataout[0]);
208 atexit(killgs);
210 if(teegs)
211 stdinout[1] = spawnreader(stdinout[1]);
213 gsfd = g->gsfd = stdinout[1];
214 g->gsdfd = dataout[1];
215 g->gspid = gspid;
217 spawnmonitor(errout[1]);
218 Binit(&g->gsrd, g->gsfd, OREAD);
220 gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
221 gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
222 waitgs(g);
224 return 0;
227 int
228 gscmd(GSInfo *gs, char *fmt, ...)
230 char buf[1024];
231 int n;
233 va_list v;
234 va_start(v, fmt);
235 n = vseprint(buf, buf+sizeof buf, fmt, v) - buf;
236 if(n <= 0)
237 return n;
239 if(chatty) {
240 fprint(2, "cmd: ");
241 write(2, buf, n);
244 if(write(gs->gsfd, buf, n) != 0)
245 return -1;
247 return n;
250 /*
251 * set the dimensions of the bitmap we expect to get back from GS.
252 */
253 void
254 setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
256 Rectangle pbox;
258 if(chatty)
259 fprint(2, "setdim: bbox=%R\n", bbox);
261 if(ppi)
262 gs->ppi = ppi;
264 gscmd(gs, "mark\n");
265 if(ppi)
266 gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi);
268 if(!Dx(bbox))
269 bbox = Rect(0, 0, 612, 792); /* 8½×11 */
271 switch(landscape){
272 case 0:
273 pbox = bbox;
274 break;
275 case 1:
276 pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
277 break;
279 gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
280 gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
281 gscmd(gs, "currentdevice putdeviceprops pop\n");
282 gscmd(gs, "/#copies 1 store\n");
284 if(!eqpt(bbox.min, ZP))
285 gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y);
287 switch(landscape){
288 case 0:
289 break;
290 case 1:
291 gscmd(gs, "%d 0 translate\n", Dy(bbox));
292 gscmd(gs, "90 rotate\n");
293 break;
296 waitgs(gs);
299 void
300 waitgs(GSInfo *gs)
302 /* we figure out that gs is done by telling it to
303 * print something and waiting until it does.
304 */
305 char *p;
306 Biobuf *b = &gs->gsrd;
307 uchar buf[1024];
308 int n;
310 // gscmd(gs, "(\\n**bstack\\n) print flush\n");
311 // gscmd(gs, "stack flush\n");
312 // gscmd(gs, "(**estack\\n) print flush\n");
313 gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
315 alarm(300*1000);
316 for(;;) {
317 p = Brdline(b, '\n');
318 if(p == nil) {
319 n = Bbuffered(b);
320 if(n <= 0)
321 break;
322 if(n > sizeof buf)
323 n = sizeof buf;
324 Bread(b, buf, n);
325 continue;
327 p[Blinelen(b)-1] = 0;
328 if(chatty) fprint(2, "p: ");
329 if(chatty) write(2, p, Blinelen(b)-1);
330 if(chatty) fprint(2, "\n");
331 if(strstr(p, "Error:")) {
332 alarm(0);
333 fprint(2, "ghostscript error: %s\n", p);
334 wexits("gs error");
337 if(strstr(p, "//GO.SYSIN DD")) {
338 break;
341 alarm(0);