gs.c (6449B)
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" 14 15 static int gspid; /* globals for atexit */ 16 static int gsfd; 17 static void killgs(void); 18 19 static void 20 killgs(void) 21 { 22 char tmpfile[100]; 23 24 close(gsfd); 25 postnote(PNGROUP, getpid(), "die"); 26 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 } 39 40 void 41 spawnreader(void *cp) 42 { 43 int n, fd, pfd[2]; 44 char buf[1024]; 45 46 recv(cp, &fd); 47 48 if(pipe(pfd)<0) 49 wexits("pipe failed"); 50 51 send(cp, &pfd[1]); 52 53 while((n=read(pfd[0], buf, sizeof buf)) > 0) { 54 write(1, buf, n); 55 write(fd, buf, n); 56 } 57 58 close(pfd[0]); 59 threadexits(0); 60 } 61 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; 71 72 recv(cp, &fd); 73 74 out = open("/dev/tty", OWRITE); 75 if(out < 0) 76 out = 2; 77 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 } 90 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]; 103 104 /* 105 * spawn gs 106 * 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; 114 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; 131 132 gspid = fork(); 133 if(gspid == 0) { 134 close(stdinp[1]); 135 close(stdoutp[0]); 136 close(dataout[0]); 137 close(errout[0]); 138 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) 147 ; 148 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); 153 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"); 163 } 164 close(stdinp[0]); 165 close(stdoutp[1]); 166 close(errout[1]); 167 close(dataout[1]); 168 atexit(killgs); 169 170 cp = chancreate(sizeof(int), 0); 171 if(teegs) { 172 proccreate(spawnreader, cp, mainstacksize); 173 send(cp, &stdoutp[0]); 174 recv(cp, &stdoutp[0]); 175 } 176 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; 182 183 proccreate(spawnmonitor, cp, mainstacksize); 184 send(cp, &errout[0]); 185 chanfree(cp); 186 187 Binit(&g->gsrd, stdoutp[0], OREAD); 188 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"); 192 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); 198 199 return 0; 200 } 201 202 int 203 gscmd(GSInfo *gs, char *fmt, ...) 204 { 205 char buf[1024]; 206 int n; 207 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; 213 214 if(chatty) { 215 fprint(2, "cmd: "); 216 write(2, buf, n); 217 } 218 219 if(write(gs->gsfd, buf, n) != 0) 220 return -1; 221 222 return n; 223 } 224 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) 230 { 231 Rectangle pbox; 232 233 if(chatty) 234 fprint(2, "setdim: bbox=%R\n", bbox); 235 236 if(ppi) 237 gs->ppi = ppi; 238 239 gscmd(gs, "mark\n"); 240 if(ppi) 241 gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi); 242 243 if(!Dx(bbox)) 244 bbox = Rect(0, 0, 612, 792); /* 8½×11 */ 245 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; 253 } 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"); 258 259 if(!eqpt(bbox.min, ZP)) 260 gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y); 261 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; 269 } 270 271 waitgs(gs); 272 } 273 274 void 275 waitgs(GSInfo *gs) 276 { 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; 284 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"); 289 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; 301 } 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"); 310 } 311 312 if(strstr(p, "//GO.SYSIN DD")) { 313 break; 314 } 315 } 316 alarm(0); 317 }