gs.c 6.8 KB

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