gs.c 6.4 KB

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