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" 13 14 static int gspid; /* globals for atexit */ 15 static int gsfd; 16 static void killgs(void); 17 18 static void 19 killgs(void) 20 { 21 char tmpfile[100]; 22 23 close(gsfd); 24 postnote(PNGROUP, getpid(), "die"); 25 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 } 38 39 int 40 spawnwriter(GSInfo *g, Biobuf *b) 41 { 42 char buf[4096]; 43 int n; 44 int fd; 45 46 switch(fork()){ 47 case -1: return -1; 48 case 0: break; 49 default: return 0; 50 } 51 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 } 60 61 int 62 spawnreader(int fd) 63 { 64 int n, pfd[2]; 65 char buf[1024]; 66 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 } 78 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 } 100 101 void 102 spawnmonitor(int fd) 103 { 104 char buf[4096]; 105 char *xbuf; 106 int n; 107 int out; 108 int first; 109 110 switch(rfork(RFFDG|RFNOTEG|RFPROC)){ 111 case -1: 112 default: 113 return; 114 115 case 0: 116 break; 117 } 118 119 out = open("/dev/cons", OWRITE); 120 if(out < 0) 121 out = 2; 122 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"); 129 } 130 write(out, xbuf, n); 131 alarm(500); 132 } 133 _exits(0); 134 } 135 136 int 137 spawngs(GSInfo *g, char *safer) 138 { 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]; 146 147 /* 148 * spawn gs 149 * 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; 157 158 nargs = 0; 159 args[nargs++] = "gs"; 160 args[nargs++] = "-dNOPAUSE"; 161 args[nargs++] = safer; 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; 174 175 gspid = fork(); 176 if(gspid == 0) { 177 close(stdinout[1]); 178 close(dataout[1]); 179 close(errout[1]); 180 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) 189 ; 190 191 stdinout[0] = dup(stdinout[0], -1); 192 errout[0] = dup(errout[0], -1); 193 dataout[0] = dup(dataout[0], -1); 194 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"); 204 } 205 close(stdinout[0]); 206 close(errout[0]); 207 close(dataout[0]); 208 atexit(killgs); 209 210 if(teegs) 211 stdinout[1] = spawnreader(stdinout[1]); 212 213 gsfd = g->gsfd = stdinout[1]; 214 g->gsdfd = dataout[1]; 215 g->gspid = gspid; 216 217 spawnmonitor(errout[1]); 218 Binit(&g->gsrd, g->gsfd, OREAD); 219 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); 223 224 return 0; 225 } 226 227 int 228 gscmd(GSInfo *gs, char *fmt, ...) 229 { 230 char buf[1024]; 231 int n; 232 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; 238 239 if(chatty) { 240 fprint(2, "cmd: "); 241 write(2, buf, n); 242 } 243 244 if(write(gs->gsfd, buf, n) != 0) 245 return -1; 246 247 return n; 248 } 249 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) 255 { 256 Rectangle pbox; 257 258 if(chatty) 259 fprint(2, "setdim: bbox=%R\n", bbox); 260 261 if(ppi) 262 gs->ppi = ppi; 263 264 gscmd(gs, "mark\n"); 265 if(ppi) 266 gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi); 267 268 if(!Dx(bbox)) 269 bbox = Rect(0, 0, 612, 792); /* 8½×11 */ 270 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; 278 } 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"); 283 284 if(!eqpt(bbox.min, ZP)) 285 gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y); 286 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; 294 } 295 296 waitgs(gs); 297 } 298 299 void 300 waitgs(GSInfo *gs) 301 { 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; 309 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"); 314 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; 326 } 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"); 335 } 336 337 if(strstr(p, "//GO.SYSIN DD")) { 338 break; 339 } 340 } 341 alarm(0); 342 } 343