chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mupdisp / genfile.c
... / ...
CommitLineData
1
2/* Copyright (c) 1995, 1998, 1999, 2000, 2001 by Arkkra Enterprises */
3/* All rights reserved */
4
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 */
8
9
10#ifdef __WATCOMC__
11#include <process.h>
12#include <errno.h>
13#endif
14#include <sys/types.h>
15#include <sys/stat.h>
16#include "mupdisp.h"
17
18#ifdef unix
19#include <sys/wait.h>
20#endif
21
22/* bitmap for message to tell user to wait while we do our thing... */
23#include "waitmsg.bm"
24
25char 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) */
28char Large_adjust[200]; /* PostScript instructions to add for the large,
29 * scroll-able version of the output */
30double Reduction_factor;/* how to adjust for small version */
31char Papersize[32]; /* -sPAPERSIZE argument to Ghostscript */
32
33static void do_genfile P((int fd, int do_full));
34static void copyfile P((int srcfile, long start, long end, int destfile));
35static void genfile P((char *outfile, int do_full));
36\f
37
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 */
41
42int
43gen1file(fullpgmode)
44
45int fullpgmode; /* if YES, generate full-page version */
46
47{
48 if (fullpgmode == YES) {
49 /* if bitmap file not already created, make it now */
50 if (Fullbitmaps <= 0) {
51 Fullbitmaps = create_tmpfile(Fullfile);
52
53 /* generate Postscript to scale and translate
54 * output appropriately */
55 sprintf(Small_adjust, "%f %f translate\n%f %f scale\n",
56 BITS_PER_LINE
57 * ((1.0 - Reduction_factor) / 2.0),
58 LINES_PER_PAGE - (LINES_PER_PAGE
59 * Reduction_factor
60 * Conf_info_p->adjust) - 4,
61 Reduction_factor,
62 Reduction_factor * Conf_info_p->adjust);
63
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);
69 }
70 close (Fullbitmaps);
71#ifdef O_BINARY
72 Fullbitmaps = open(Fullfile, O_RDONLY | O_BINARY, 0);
73#else
74 Fullbitmaps = open(Fullfile, O_RDONLY, 0);
75#endif
76 return(Fullbitmaps);
77 }
78 else {
79 /* if bitmap file not already created, make it now */
80 if (Partbitmaps <= 0) {
81 Partbitmaps = create_tmpfile(Partfile);
82
83 sprintf(Large_adjust, "%f %f translate\n%f %f scale\n",
84 0.0, (1.0 - Conf_info_p->adjust)
85 * LINES_PER_PAGE,
86 1.0, Conf_info_p->adjust);
87
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);
93 }
94 close (Partbitmaps);
95#ifdef O_BINARY
96 Partbitmaps = open(Partfile, O_RDONLY | O_BINARY, 0);
97#else
98 Partbitmaps = open(Partfile, O_RDONLY, 0);
99#endif
100 return(Partbitmaps);
101 }
102}
103\f
104
105/* generate a file containing bitmap representations of pages */
106
107static void
108genfile(outfile, do_full)
109
110char *outfile; /* put bitmaps in this file */
111int do_full; /* YES if to do full version of page */
112
113{
114 char outfileopt[L_tmpnam+14]; /* space for -sOutputFile=outfile */
115 int ret; /* return value from Ghostscript */
116 struct stat statinfo;
117#ifdef unix
118 int pip[2]; /* for pipe to gs */
119 int child; /* Ghostscript's process ID */
120
121
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);
126 }
127
128 /* execute Ghostscript */
129 switch (child = fork()) {
130 case 0:
131 /* connect its input to the pipe. Discard stdout and stderr */
132 close(0);
133 dup(pip[0]);
134 close(1);
135 dup(Nulldev);
136 close(2);
137 dup(Nulldev);
138 sprintf(outfileopt, "-sOutputFile=%s", outfile);
139 execlp("gs", "gs", "-sDEVICE=bit", Papersize, "-dQUIET",
140 outfileopt, "-", (char *) 0);
141 /*FALLTHRU*/
142 case -1:
143 Exit_errmsg = "can't exec Ghostscript";
144 (*Conf_info_p->cleanup) (1);
145 break;
146 default:
147 close(pip[0]);
148
149 /* generate the file */
150 do_genfile(pip[1], do_full);
151 close(pip[1]);
152
153 /* wait for Ghostscript to complete */
154 while ( wait(&ret) != child )
155 ;
156 if (ret != 0 || stat(Gs_errfile, &statinfo) == 0) {
157 Exit_errmsg = "Ghostscript failed\n";
158 (*Conf_info_p->cleanup) (1);
159 }
160 }
161#else
162#ifdef __WATCOMC__
163 /* DOS can't do pipes, so use a temp file instead. */
164 int tmpf;
165 char pstmpfile[L_tmpnam];
166 static char message[128]; /* buffer for error message */
167
168
169 /* make a temp file for the modified PostScript */
170 tmpf = create_tmpfile(pstmpfile);
171 do_genfile(tmpf, do_full);
172 close(tmpf);
173
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);
178
179 if (ret != 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);
185 }
186
187 /* remove the temp file */
188 unlink(pstmpfile);
189 if (ret != 0 || stat(Gs_errfile, &statinfo) == 0) {
190 unlink(outfile);
191 if (ret == -1) {
192 sprintf(message, "Ghostscript error %d (gs386 may be missing from your PATH?)\n", ret);
193 }
194 else {
195 sprintf(message, "Ghostscript error %d\n", ret);
196 }
197 Exit_errmsg = message;
198 (*Conf_info_p->cleanup) (1);
199 }
200#else
201 Exit_errmsg = "unsupported platform\n";
202 (*Conf_info_p->cleanup) (1);
203#endif
204#endif
205}
206\f
207
208/* determine proper PAPERSIZE, and set parameter appropirately for that
209 * page size */
210
211/* table to translate width and height to PAPERSIZE name */
212struct 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 */
217} Size_table[] = {
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 },
226 { 0, 0, (char *) 0 }
227};
228
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 */
232#define FUZZ 24
233
234void
235get_paper_size(x, y)
236
237int x, y;
238
239{
240 int i;
241
242 /* if we've already been called once, we're already done */
243 if (Papersize[0] == '-') {
244 return;
245 }
246
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) ) {
253
254 /* close enough to a standard size,
255 * so we'll go with it */
256 break;
257 }
258 }
259
260 if (Size_table[i].x == 0) {
261 /* if not found in table, use the default (letter) */
262 i = 0;
263 }
264
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);
271}
272\f
273
274/* generate bitmap from PostScript by calling Ghostscript */
275
276static void
277do_genfile(fd, do_full)
278
279int fd; /* file descriptor to write to */
280int do_full; /* if YES, do full page mode */
281
282{
283 struct Pginfo *pg_p; /* for info about each page */
284 char errhandler[200]; /* PostScript error handler redefinition */
285
286
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));
291
292 /* copy the prolog */
293 copyfile(Psfile, Beginprolog, Endprolog, fd);
294
295 /* for each page add proper scaling, etc information */
296 for (pg_p = Pagehead; pg_p != (struct Pginfo *) 0;
297 pg_p = pg_p->next) {
298 write(fd, "save\n", 5);
299 if (do_full == YES) {
300 char tmpbuff[100];
301
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",
304 Lines_per_page,
305 Bits_per_line,
306 Lines_per_page,
307 Bits_per_line);
308 write(fd, tmpbuff, strlen(tmpbuff));
309
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);
314 }
315 else {
316 write(fd, Large_adjust, strlen(Large_adjust));
317 }
318
319 /* copy a page worth of PostScript */
320 copyfile(Psfile, pg_p->begin, pg_p->end, fd);
321 write(fd, "restore\n", 8);
322 }
323
324 /* finish up the Ghostscript input */
325 write(fd, "quit\n", 5);
326}
327\f
328
329/* copy a portion of one file descriptor to another file description */
330
331static void
332copyfile(srcfile, start, end, destfile)
333
334int srcfile; /* read from this file */
335long start; /* start at this offset in srcfile */
336long end; /* go this far in srcfile */
337int destfile; /* write to current position in this file */
338
339{
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 */
343
344
345 /* go to specified spot in source file */
346 lseek(srcfile, start, SEEK_SET);
347
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);
351
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);
356 }
357 }
358 else {
359 Exit_errmsg = "Read failed\n";
360 ( *(Conf_info_p)->cleanup) (1);
361 }
362 }
363}
364\f
365
366/* execute Mup, putting output in Psfile */
367
368void
369run_mup(argv)
370
371char **argv; /* arguments to pass to Mup */
372
373{
374 int ret;
375 int child;
376
377
378#ifdef unix
379 switch(child = fork()) {
380 case 0:
381 /* arrange to put output in Psfile */
382 close(1);
383 dup(Psfile);
384
385 /* execute Mup */
386 execvp("mup", argv);
387 fprintf(stderr, "failed to execute Mup\n");
388 exit(1);
389 case -1:
390 fprintf(stderr, "failed to fork Mup\n");
391 generalcleanup(1);
392 /*NOTREACHED*/
393 break;
394 default:
395 /* wait for Mup to complete */
396 while (wait(&ret) != child)
397 ;
398 if (ret != 0) {
399 unlink(Mupfile);
400 generalcleanup(ret);
401 }
402 break;
403 }
404#else
405#ifdef __WATCOMC__
406 /* arrange to put output in Psfile */
407 close(1);
408 dup(Psfile);
409
410 /* execute Mup */
411 if ((ret = spawnvp(P_WAIT, "mup", argv)) != 0) {
412 if (errno != 0) {
413 perror("Mup failed");
414 }
415 unlink(Mupfile);
416 exit(ret);
417 }
418#else
419 fprintf(stderr, "unsupported platform\n");
420#endif
421#endif
422}