tgs.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tgs.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 
     8 #include 
     9 #include 
    10 #include 
    11 #include 
    12 #include 
    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 }