2 /* Copyright (c) 1995, 1998, 1999, 2000, 2001 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions to generate the bitmap output file from the Mup input.
6 * Includes functions for running Mup to produce PostScript, and to run
7 * Ghostscript on the output of Mup */
14 #include <sys/types.h>
22 /* bitmap for message to tell user to wait while we do our thing... */
25 char Small_adjust[200]; /* PostScript instructions to add to get small
26 * version of output (small enough for a whole page
27 * to fit on the screen) */
28 char Large_adjust[200]; /* PostScript instructions to add for the large,
29 * scroll-able version of the output */
30 double Reduction_factor;/* how to adjust for small version */
31 char Papersize[32]; /* -sPAPERSIZE argument to Ghostscript */
33 static void do_genfile P((int fd, int do_full));
34 static void copyfile P((int srcfile, long start, long end, int destfile));
35 static void genfile P((char *outfile, int do_full));
38 /* generate one of the bitmap files if not already generated,
39 * either full or partial page based on value of fullpgmode.
40 * Return file descriptor of appropriate bitmap */
45 int fullpgmode; /* if YES, generate full-page version */
48 if (fullpgmode == YES) {
49 /* if bitmap file not already created, make it now */
50 if (Fullbitmaps <= 0) {
51 Fullbitmaps = create_tmpfile(Fullfile);
53 /* generate Postscript to scale and translate
54 * output appropriately */
55 sprintf(Small_adjust, "%f %f translate\n%f %f scale\n",
57 * ((1.0 - Reduction_factor) / 2.0),
58 LINES_PER_PAGE - (LINES_PER_PAGE
60 * Conf_info_p->adjust) - 4,
62 Reduction_factor * Conf_info_p->adjust);
64 /* tell user to wait */
65 ( *(Conf_info_p->bitmap) ) (Waitmsg_bitmap,
66 Waitmsg_width, Waitmsg_height);
67 /* generate the bitmap */
68 genfile(Fullfile, YES);
72 Fullbitmaps = open(Fullfile, O_RDONLY | O_BINARY, 0);
74 Fullbitmaps = open(Fullfile, O_RDONLY, 0);
79 /* if bitmap file not already created, make it now */
80 if (Partbitmaps <= 0) {
81 Partbitmaps = create_tmpfile(Partfile);
83 sprintf(Large_adjust, "%f %f translate\n%f %f scale\n",
84 0.0, (1.0 - Conf_info_p->adjust)
86 1.0, Conf_info_p->adjust);
88 /* tell user to wait */
89 ( *(Conf_info_p->bitmap) ) (Waitmsg_bitmap,
90 Waitmsg_width, Waitmsg_height);
91 /* generate the bitmap */
92 genfile(Partfile, NO);
96 Partbitmaps = open(Partfile, O_RDONLY | O_BINARY, 0);
98 Partbitmaps = open(Partfile, O_RDONLY, 0);
105 /* generate a file containing bitmap representations of pages */
108 genfile(outfile, do_full)
110 char *outfile; /* put bitmaps in this file */
111 int do_full; /* YES if to do full version of page */
114 char outfileopt[L_tmpnam+14]; /* space for -sOutputFile=outfile */
115 int ret; /* return value from Ghostscript */
116 struct stat statinfo;
118 int pip[2]; /* for pipe to gs */
119 int child; /* Ghostscript's process ID */
122 /* create a pipe to Ghostscript */
123 if (pipe(pip) != 0) {
124 Exit_errmsg = "can't set up pipe\n";
125 (*Conf_info_p->cleanup) (1);
128 /* execute Ghostscript */
129 switch (child = fork()) {
131 /* connect its input to the pipe. Discard stdout and stderr */
138 sprintf(outfileopt, "-sOutputFile=%s", outfile);
139 execlp("gs", "gs", "-sDEVICE=bit", Papersize, "-dQUIET",
140 outfileopt, "-", (char *) 0);
143 Exit_errmsg = "can't exec Ghostscript";
144 (*Conf_info_p->cleanup) (1);
149 /* generate the file */
150 do_genfile(pip[1], do_full);
153 /* wait for Ghostscript to complete */
154 while ( wait(&ret) != child )
156 if (ret != 0 || stat(Gs_errfile, &statinfo) == 0) {
157 Exit_errmsg = "Ghostscript failed\n";
158 (*Conf_info_p->cleanup) (1);
163 /* DOS can't do pipes, so use a temp file instead. */
165 char pstmpfile[L_tmpnam];
166 static char message[128]; /* buffer for error message */
169 /* make a temp file for the modified PostScript */
170 tmpf = create_tmpfile(pstmpfile);
171 do_genfile(tmpf, do_full);
174 /* execute Ghostscript on the temp file */
175 sprintf(outfileopt, "-sOutputFile=%s", outfile);
176 ret = spawnlp(P_WAIT, "gs", "gs", "-sDEVICE=bit", Papersize,
177 "-dQUIET", "-dNOPAUSE", outfileopt, pstmpfile, (char *) 0);
180 /* try executing gs386 instead */
181 /**** probably should check for a specific return code ****/
182 ret = spawnlp(P_WAIT, "gs386", "gs386", "-sDEVICE=bit",
183 Papersize, "-dQUIET", "-dNOPAUSE",
184 outfileopt, pstmpfile, (char *) 0);
187 /* remove the temp file */
189 if (ret != 0 || stat(Gs_errfile, &statinfo) == 0) {
192 sprintf(message, "Ghostscript error %d (gs386 may be missing from your PATH?)\n", ret);
195 sprintf(message, "Ghostscript error %d\n", ret);
197 Exit_errmsg = message;
198 (*Conf_info_p->cleanup) (1);
201 Exit_errmsg = "unsupported platform\n";
202 (*Conf_info_p->cleanup) (1);
208 /* determine proper PAPERSIZE, and set parameter appropirately for that
211 /* table to translate width and height to PAPERSIZE name */
212 struct PaperSizeInfo {
213 int x; /* width, must be <= MAX_BITS_PER_LINE */
214 int y; /* height, must be <= MAX_LINES_PER_PAGE */
215 char *sizename; /* name of paper size */
216 double reduction; /* how much to multiply by in small mode */
218 { 612, 792, "letter", 0.48 }, /* default has to be first */
219 { 540, 720, "note", 0.525 },
220 { 612, 1008, "legal", 0.375 },
221 { 595, 842, "a4", 0.46 },
222 { 421, 595, "a5", 0.65 },
223 { 297, 421, "a6", 0.8 },
224 { 612, 936, "flsa", 0.41 },
225 { 396, 612, "halfletter", 0.63 },
229 /* How many points away from a standard paper size we allow to
230 * account for roundoffs, since user was specifying in inches or cm
231 * rather than points, so they may be off somewhat */
242 /* if we've already been called once, we're already done */
243 if (Papersize[0] == '-') {
247 /* go through table till we find a standard size that matches */
248 for (i = 0; Size_table[i].x != 0; i++) {
249 if ( (x > Size_table[i].x - FUZZ)
250 && (x < Size_table[i].x + FUZZ)
251 && (y > Size_table[i].y - FUZZ)
252 && (y < Size_table[i].y + FUZZ) ) {
254 /* close enough to a standard size,
255 * so we'll go with it */
260 if (Size_table[i].x == 0) {
261 /* if not found in table, use the default (letter) */
265 /* set appropriate parameters */
266 Bits_per_line = Size_table[i].x;
267 Lines_per_page = Size_table[i].y;
268 Bytes_per_line = (Bits_per_line >> 3) + ((Bits_per_line & 0x7) ? 1 : 0);
269 Reduction_factor = Size_table[i].reduction;
270 sprintf(Papersize, "-sPAPERSIZE=%s", Size_table[i].sizename);
274 /* generate bitmap from PostScript by calling Ghostscript */
277 do_genfile(fd, do_full)
279 int fd; /* file descriptor to write to */
280 int do_full; /* if YES, do full page mode */
283 struct Pginfo *pg_p; /* for info about each page */
284 char errhandler[200]; /* PostScript error handler redefinition */
287 /* arrange to quit Ghostscript on errors (shouldn't get errors
288 * from Mup output, but could run out of memory, causing VMerror) */
289 sprintf(errhandler, "/handleerror { $error begin (%s) (w) file dup errorname 100 string cvs writestring (\\n) writestring end quit } def\n", Gs_errfile);
290 write(fd, errhandler, strlen(errhandler));
292 /* copy the prolog */
293 copyfile(Psfile, Beginprolog, Endprolog, fd);
295 /* for each page add proper scaling, etc information */
296 for (pg_p = Pagehead; pg_p != (struct Pginfo *) 0;
298 write(fd, "save\n", 5);
299 if (do_full == YES) {
302 write(fd, "0.2 setgray\n", 12);
303 sprintf(tmpbuff, "0 0 moveto 0 %d lineto %d %d lineto %d 0 lineto closepath fill\n",
308 write(fd, tmpbuff, strlen(tmpbuff));
310 write(fd, Small_adjust, strlen(Small_adjust));
311 write(fd, "1 setgray\n", 10);
312 write(fd, tmpbuff, strlen(tmpbuff));
313 write(fd, "0 setgray\n", 10);
316 write(fd, Large_adjust, strlen(Large_adjust));
319 /* copy a page worth of PostScript */
320 copyfile(Psfile, pg_p->begin, pg_p->end, fd);
321 write(fd, "restore\n", 8);
324 /* finish up the Ghostscript input */
325 write(fd, "quit\n", 5);
329 /* copy a portion of one file descriptor to another file description */
332 copyfile(srcfile, start, end, destfile)
334 int srcfile; /* read from this file */
335 long start; /* start at this offset in srcfile */
336 long end; /* go this far in srcfile */
337 int destfile; /* write to current position in this file */
340 char buff[BUFSIZ]; /* buffer for copying */
341 int size; /* how much to copy at once */
342 long remaining; /* how much still to be copied */
345 /* go to specified spot in source file */
346 lseek(srcfile, start, SEEK_SET);
348 /* copy a block at a time, last piece will be wahatever is left */
349 for (remaining = end - start; remaining > 0L; remaining -= BUFSIZ) {
350 size = (remaining >= BUFSIZ ? BUFSIZ : remaining);
352 if (read(srcfile, buff, size) == size) {
353 if (write(destfile, buff, size) != size) {
354 Exit_errmsg = "File write failed (probably out of disk space)\n";
355 ( *(Conf_info_p)->cleanup) (1);
359 Exit_errmsg = "Read failed\n";
360 ( *(Conf_info_p)->cleanup) (1);
366 /* execute Mup, putting output in Psfile */
371 char **argv; /* arguments to pass to Mup */
379 switch(child = fork()) {
381 /* arrange to put output in Psfile */
387 fprintf(stderr, "failed to execute Mup\n");
390 fprintf(stderr, "failed to fork Mup\n");
395 /* wait for Mup to complete */
396 while (wait(&ret) != child)
406 /* arrange to put output in Psfile */
411 if ((ret = spawnvp(P_WAIT, "mup", argv)) != 0) {
413 perror("Mup failed");
419 fprintf(stderr, "unsupported platform\n");