1 /*
2 * post.c
3 */
4
5 /*
6 * mpage: a program to reduce pages of print so that several pages
7 * of output appear on one printed page.
8 *
9 * Copyright (c) 1994-2004 Marcel J.E. Mol, The Netherlands
10 * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 *
26 */
27
28
29 #include "mpage.h"
30 #include <string.h>
31
32
33 /*
34 * character spaces used throughout for holding the current line from
35 * the input file
36 */
37 static char currline[LINESIZE];
38 static char *file_name;
39
40 /*
41 * for ps documents, used to remember if we have come across the
42 * tailer section. reset at the beginning of processing for each file
43 */
44 static int ps_at_trailer;
45
46 /*
47 * this is the type of postscript document we are processing
48 */
49 static int ps_posttype;
50
51 /*
52 * set to one if we have a inputline that must be preceded by something...
53 * used for dvips output without PS comments.
54 */
55 static int have_line = 0;
56
57 /*
58 * number of output lines on current logical page
59 */
60 static int plcnt;
61
62
63 int have_showsheet = 0;
64
65 char ps_roff_xi [16]; /* to hold the DITROFF xi line... */
66
67 static char * tex1; /* to capture important dvi2ps lines... */
68 static char * tex2;
69
70 /*
71 * Function declarations
72 */
73 static int ps_gettype();
74 static void do_post_doc();
75 #if 0
76 static void do_other_doc();
77 #endif
78 static void ps_copyprolog();
79 static void ps_roff_copyprolog();
80 static void ps_mpage_copyprolog();
81 static void ps_skip_to_page();
82 static int do_post_sheet();
83 static void ps_sheetsetup();
84 static int post_onepage();
85 static int post_flush_onepage();
86 static int post_one_line();
87 static void do_roff_tailer();
88 int ps_check();
89 void do_ps_doc();
90
91 static int post_flush_onepage();
92 static int ps_store_to_page();
93
94 /*
95 * Peek at the first two chacters on the open file and check for the
96 * two character postscript flag "%!". If the file is not postscript
97 * then the characters are pushed back into the input stream (hopefully).
98 */
99 int
ps_check(infd)100 ps_check(infd)
101 FILE *infd;
102 {
103 int firstchar;
104 int secondchar;
105
106 Debug(DB_PSCHECK, "%%ps_check: in ps_check\n", 0);
107
108 /*
109 * eliminate blank files
110 */
111 if ((firstchar = fgetc(infd)) == EOF) {
112 Debug(DB_PSCHECK, "%%ps_check: file is blank\n", 0);
113 return 0;
114 }
115
116 /*
117 * Skip any CTRL-D chars
118 * Hope there are no text files starting with ctrl-d's
119 */
120 while (firstchar == 4)
121 firstchar = fgetc(infd);
122
123 /*
124 * eliminate non-postscript files
125 */
126 if (firstchar != '%') {
127 Debug(DB_PSCHECK, "%ps_check: 1st char is '%c' not '%'\n", firstchar);
128 if (ungetc(firstchar, infd) == EOF) {
129 fprintf(stderr, "%s: Lost first character of file ", MPAGE);
130 fprintf(stderr, "while checking for postscript\n.");
131 }
132 return 0;
133 }
134 Debug(DB_PSCHECK, "%%ps_check: 1st char is '%c'\n", firstchar);
135 /*
136 * eliminate one character files (containing only a %)
137 */
138 if ((secondchar = fgetc(infd)) == EOF) {
139 Debug(DB_PSCHECK, "%%ps_check: no second char\n", 0);
140 if (ungetc(firstchar, infd) == EOF) {
141 fprintf(stderr, "%s: Lost first character of file ", MPAGE);
142 fprintf(stderr, "while checking for postscript\n.");
143 }
144 return 0;
145 }
146 /*
147 * eliminate files that don't have the full two character
148 * sequence of "%!".
149 */
150 if (secondchar != '!') {
151 Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c' not '!'\n", secondchar);
152 if (ungetc(secondchar, infd) == EOF) {
153 fprintf(stderr, "%s: Lost first two characters of ", MPAGE);
154 fprintf(stderr, "file while checking for postscript\n.");
155 return 0;
156 }
157 if (ungetc(firstchar, infd) == EOF) {
158 fprintf(stderr, "%s: Lost first character of file ", MPAGE);
159 fprintf(stderr, "while checking for postscript.\n");
160 }
161 return 0;
162 }
163 /*
164 * for post script files the first two characters (the "%!") are
165 * digested by this routine. It's just easier than dealing
166 * with the problems encounted if the characters can't be ungetc'ed.
167 */
168 Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c'\n", secondchar);
169 Debug(DB_PSCHECK, "%%ps_check: input is postscript\n", 0);
170
171 return 1;
172
173 } /* ps_check */
174
175
176
177 static int
ps_gettype(fd,outfd)178 ps_gettype(fd, outfd)
179 FILE *fd;
180 FILE *outfd;
181 {
182 int ps_type, end_comments;
183
184 Debug(DB_PSDOC, "%%ps_gettype: in ps_gettype\n", 0);
185 /*
186 * error check for truncated files
187 */
188 if (fgets(currline, LINESIZE-1, fd) == NULL) {
189 Debug(DB_PSDOC, "%%ps_gettype: got eof on first line\n", 0);
190 return PS_NONE;
191 }
192 /*
193 * check for non-conforming postscript
194 * Note that %! is already gone down the drain...
195 */
196 if (strncmp(currline, PS_FLAG, strlen(PS_FLAG)) != 0) {
197 Debug(DB_PSDOC, "%%ps_gettype: no match PS_FLAG \"%s\"\n", currline);
198 return PS_OTHER;
199 }
200 /*
201 * we have some form of conforming postscript, try to identify the
202 * type
203 */
204 Debug(DB_PSDOC, "%%ps_gettype: conforming postscript\n", 0);
205 end_comments = 0;
206 ps_type = PS_CONFORM;
207 while (!end_comments) {
208 /*
209 * if we get end of file then we assume non-conforming PS
210 */
211 if (fgets(currline, LINESIZE-1, fd) == NULL) {
212 Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0);
213 return PS_OTHER;
214 }
215 /*
216 * if we have run out of leading comments then assume
217 * conforming PS (because we had a valid "%!" line)
218 */
219 if (currline[0] != '%') {
220 Debug(DB_PSDOC, "%%ps_gettype: out off comments\n", 0);
221 fprintf(outfd, "%s", currline);
222 return PS_CONFORM;
223 }
224 /*
225 * print out the comment line with an extra % to disguise the comment
226 */
227 fprintf(outfd, "%%%s", currline);
228 /*
229 * check for the end of the leading comments section
230 */
231 if (strncmp(currline, "%%EndComments", 13) == 0)
232 end_comments = 1;
233 /*
234 * Some tricky way to handle MS-windows postscript files...
235 * probably doesn't work.
236 */
237 if (strncmp(currline, "%%Pages:", 8) == 0 &&
238 ps_type == PS_MSWINDOWS)
239 return ps_type;
240 /*
241 * once we know the type of PS, we no longer need to keep
242 * checking.
243 */
244 if (ps_type != PS_CONFORM)
245 continue;
246 /*
247 * check for mpage output
248 */
249 if (!strncmp(currline, "%%Creator: ", 11)) {
250 if (!strncmp(currline+11, MPAGE, strlen(MPAGE))) {
251 Debug(DB_PSDOC, "%%ps_gettype: mpage document\n", 0);
252 ps_type = PS_MPAGE;
253 }
254 else if (!strncmp(currline+11, "Windows PSCRIPT", 15)) {
255 Debug(DB_PSDOC, "%%ps_gettype: windows document\n", 0);
256 ps_type = PS_MSWINDOWS;
257 }
258 else if (!strncmp(currline+11, "dvips", 5)) {
259 Debug(DB_PSDOC, "%%ps_gettype: dvips\n", 0);
260 ps_type = PS_TEX;
261 }
262 }
263 /*
264 * check for psroff/tex output
265 */
266 if (strncmp(currline, "%%Title: ", 9) == 0) {
267 if (strstr(currline, "ditroff")) {
268 Debug(DB_PSDOC, "%%ps_gettype: psroff\n", 0);
269 ps_type = PS_PSROFF;
270 }
271 else if (strstr(currline, ".dvi")) {
272 Debug(DB_PSDOC, "%%ps_gettype: dvi2ps\n", 0);
273 ps_type = PS_TEX;
274 }
275 }
276 if (strncmp(currline, "%DVIPS", 6) == 0) {
277 Debug(DB_PSDOC, "%%ps_gettype: dvips\n", 0);
278 if (ps_type != PS_TEX)
279 ps_type = PS_TEX2;
280 return ps_type;
281 }
282 }
283 #ifdef DEBUG
284 if (ps_type == PS_CONFORM) {
285 Debug(DB_PSDOC, "%%ps_gettype: unknown type, conforming PS\n", 0);
286 }
287 #endif
288
289 return ps_type;
290
291 } /* ps_gettype */
292
293
294
295 void
do_ps_doc(fd,asheet,outfd,fname)296 do_ps_doc(fd, asheet, outfd, fname)
297 FILE *fd;
298 struct sheet *asheet;
299 FILE *outfd;
300 char * fname;
301 {
302
303 Debug(DB_PSDOC, "%%do_ps_doc: postscript document\n", 0);
304
305 file_name = fname;
306 ps_posttype = ps_gettype(fd,outfd);
307 Debug(DB_PSDOC, "%%do_ps_doc: document type is %d\n", ps_posttype);
308 if (ps_posttype != PS_NONE)
309 do_post_doc(fd, asheet, outfd);
310
311 return;
312
313 } /* do_ps_doc */
314
315
316
317 static void
do_post_doc(fd,asheet,outfd)318 do_post_doc(fd, asheet, outfd)
319 FILE *fd;
320 struct sheet *asheet;
321 FILE *outfd;
322 {
323
324 ps_at_trailer = FALSE;
325 Debug(DB_POST, "%%do_post_doc: prolog\n", 0);
326 ps_copyprolog(fd, outfd);
327 /*
328 * while there is still input, print pages
329 */
330 Debug(DB_POST, "%%do_post_doc: pages\n", 0);
331 do_sheets(do_post_sheet, fd, asheet, outfd);
332 Debug(DB_POST, "%%do_post_doc: trailer\n", 0);
333 do_roff_tailer(fd, outfd);
334
335 return;
336
337 } /* do_post_doc */
338
339
340 #if 0
341 /* not used yet... */
342 static void
343 do_other_doc(fd, asheet, outfd)
344 FILE *fd;
345 struct sheet *asheet;
346 FILE *outfd;
347 {
348
349 ps_at_trailer = FALSE;
350 ps_copyprolog(fd, outfd);
351
352 return;
353
354 } /* do_other_doc */
355 #endif
356
357
358
359 static void
ps_copyprolog(fd,outfd)360 ps_copyprolog(fd, outfd)
361 FILE *fd;
362 FILE *outfd;
363 {
364 size_t len;
365
366 Debug(DB_PSDOC, "%%ps_copyprolog: adding mpage prolog\n", 0);
367 if (!have_showsheet) {
368 #if 1
369 fprintf(outfd, "/showsheet /showpage load def\n");
370 #else
371 fprintf(outfd, "/showsheet { showpage } bind def\n");
372 #endif
373 fprintf(outfd, "/showpage { } def\n");
374 have_showsheet = 1;
375 }
376 had_ps = 1;
377 Debug(DB_PSDOC, "%%ps_copyprolog: copying prolog\n", 0);
378 if (ps_posttype == PS_PSROFF) {
379 Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_roff_copyprolog\n",0);
380 ps_roff_copyprolog(fd, outfd);
381 return;
382 }
383 if (ps_posttype == PS_MPAGE) {
384 Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_mpage_copyprolog\n",0);
385 ps_mpage_copyprolog(fd, outfd);
386 return;
387 }
388 while (fgets(currline, LINESIZE-1, fd) != NULL) {
389 if (strncmp(currline, "%%Page:", 7) == 0) {
390 fprintf(outfd, "%% %s", currline);
391 return;
392 }
393 if (ps_posttype == PS_TEX || ps_posttype == PS_TEX2) {
394 if (ps_posttype == PS_TEX2 && strstr(currline, " bop ")) {
395 /* dvips output without comments... */
396 have_line = 1;
397 return;
398 }
399 if (strncmp(currline, "TeXDict", 7) == 0) {
400 /* SHOULD PROBABLY REMOVE THIS. SEE BELOW /dictionarystack */
401 /*
402 * Hope all dvi2ps progs work the same:
403 * capture the TeX init code so we can run it 'manually' for
404 * every page. This is needed as this code sets up a gstate
405 * that conflicts with mpage...
406 * This trick seems to work for text, but figures within the dvi
407 * file seem to have a mind of their own...
408 */
409 if (tex1)
410 free(tex1);
411 len = strlen(currline)+1;
412 tex1 = malloc(len);
413 (void)strlcpy(tex1, currline, len);
414 fprintf(outfd, "%s", currline);
415
416 fgets(currline, LINESIZE-1, fd);
417 if (tex2)
418 free(tex2);
419 len = strlen(currline)+1;
420 tex2 = malloc(len);
421 (void)strlcpy(tex2, currline, len);
422 }
423 }
424 fprintf(outfd, "%s", currline);
425 }
426 Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
427 fprintf(outfd, "%%%%EndProlog\n");
428
429 return;
430
431 } /* ps_copyprolog */
432
433
434
435 static void
ps_roff_copyprolog(fd,outfd)436 ps_roff_copyprolog(fd, outfd)
437 FILE *fd;
438 FILE *outfd;
439 {
440
441 Debug(DB_PSDOC, "%%ps_roff_copyprolog: copying psroff prolog\n", 0);
442 while(fgets(currline, LINESIZE-1, fd) != NULL) {
443 /* if (strcmp(currline, "xi\n") == 0) */
444 if (strstr(currline, "xi\n")) {
445 fprintf(outfd, "%%%s", currline);
446 (void)strlcpy(ps_roff_xi, currline, sizeof(ps_roff_xi));
447 }
448 else if (strncmp(currline, "%%Page:", 7) == 0) {
449 fprintf(outfd, "/p { } def\n");
450 fprintf(outfd, "/xt { } def\n");
451 fprintf(outfd, "/xs { } def\n");
452 fprintf(outfd, "%% %s", currline);
453 Debug(DB_PSDOC, "%%ps_copyprolog: Done\n", 0);
454 return;
455 }
456 else
457 fprintf(outfd, "%s", currline);
458 }
459 Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
460 fprintf(outfd, "/p { } def\n");
461 fprintf(outfd, "/xt { } def\n");
462 fprintf(outfd, "/xs { } def\n");
463 fprintf(outfd, "%%%%EndProlog\n");
464
465 return;
466
467 } /* ps_roff_copyprolog */
468
469
470
471 static void
ps_mpage_copyprolog(fd,outfd)472 ps_mpage_copyprolog(fd, outfd)
473 FILE *fd;
474 FILE *outfd;
475 {
476
477 Debug(DB_PSDOC, "%%ps_mpage_copyprolog: skipping mpage prolog\n", 0);
478 while(fgets(currline, LINESIZE-1, fd) != NULL) {
479 if (strncmp(currline, "%%Page:", 7) == 0) {
480 fprintf(outfd, "%% %s", currline);
481 Debug(DB_PSDOC, "%%ps_copyprolog: Done\n", 0);
482 return;
483 }
484 }
485 } /* ps_mpage_copyprolog */
486
487
488
489 static void
ps_skip_to_page(fd)490 ps_skip_to_page(fd)
491 FILE *fd;
492 {
493
494 Debug(DB_PSDOC, "%%ps_skip to page: reading until %%%%Page:\n", 0);
495 while(fgets(currline, LINESIZE-1, fd) != NULL) {
496 Debug(DB_PSDOC, "%% %s", currline);
497 if (strncmp(currline, "%%Page:", 7) == 0)
498 return;
499 }
500 Debug(DB_PSDOC, "%%ps_skip_to_page: eof before %%%%Page:\n", 0);
501
502 return;
503
504 } /* ps_skip_to_page */
505
506
507
508 static char *stored_page = NULL;
509 static int stored_page_size = 0;
510
511 static int
ps_store_to_page(fd)512 ps_store_to_page(fd)
513 FILE *fd;
514 {
515 int totlen = 0;
516
517 Debug(DB_PSDOC, "%%ps_store to page: reading until %%%%Page:\n", 0);
518 while(fgets(currline, LINESIZE-1, fd) != NULL) {
519 int len;
520 if (strncmp(currline, "%%Page:", 7) == 0)
521 return totlen;
522 len = strlen(currline);
523 totlen += len;
524 if (totlen > stored_page_size){
525 stored_page = realloc(stored_page, totlen);
526 stored_page_size = totlen;
527 }
528 /* do not copy the '\0' */
529 memcpy(stored_page + totlen - len, currline, len);
530 Debug(DB_PSDOC, "%% %s", currline);
531 }
532 Debug(DB_PSDOC, "%%ps_store_to_page: eof before %%%%Page:\n", 0);
533
534 return totlen;
535
536 } /* ps_store_to_page */
537
538
539
540 /* GPN */
541 /* #define NSCALE to take care of previous scaling */
542 #ifdef NSCALE
543 char *NScale = "/gpnsavematrix {orgmatrix currentmatrix pop} bind def\n"
544 "/gpnrestorematrix {orgmatrix setmatrix} bind def\n"
545 "/orgmatrix matrix def\n"
546 "gpnsavematrix\n"
547 "orgmatrix orgmatrix invertmatrix pop\n"
548 "/gpnxs\n"
549 " orgmatrix 0 get 0.0000 eq\n"
550 " {orgmatrix 1 get abs}\n"
551 " {orgmatrix 0 get abs}\n"
552 " ifelse def\n"
553 "/gpnys\n"
554 " orgmatrix 3 get 0.0000 eq\n"
555 " {orgmatrix 2 get abs}\n"
556 " {orgmatrix 3 get abs}\n"
557 " ifelse def\n"
558 "/gpnxs gpnxs gscurrentresolution 0 get 72 div mul def\n"
559 "/gpnys gpnys gscurrentresolution 1 get 72 div mul def\n";
560 #endif /* NSCALE */
561
562 static int
do_post_sheet(fd,asheet,outfd)563 do_post_sheet(fd, asheet, outfd)
564 FILE *fd;
565 struct sheet *asheet;
566 FILE *outfd;
567 {
568 int rtn_val = FILE_MORE;
569 int sh_high, sh_wide;
570 struct pagepoints *stored_points = NULL, *flush_points = NULL;
571 int flush = 0, totlen = 0;
572
573 do {
574 if ((points->pp_origin_x == 0 && !points->skip) || opt_file || flush) {
575 /*
576 * keep track of the pages processed
577 */
578 ps_pagenum++;
579 fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum);
580 # ifdef DEBUG
581 if (Debug_flag & DB_PSMPAGE)
582 fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum);
583 # endif /* DEBUG */
584 #if 0
585 /* seems to give memory problems... */
586 fprintf(outfd, "/sheetsave save def\n");
587 #endif
588
589 /*
590 * Now is the time to print a sheet header...
591 * for now, this has to be done before outline...
592 */
593 sheetheader(outfd, file_name);
594
595 /*
596 * print the page outline
597 */
598 mp_outline(outfd, asheet);
599
600 /*
601 * run through the list of base points for putting reduced pages
602 * on the printed page
603 */
604 if (!flush)
605 points = asheet->sh_pagepoints;
606 else
607 points++;
608 }
609
610 while ((points->pp_origin_x!=0 || points->skip) && rtn_val == FILE_MORE) {
611
612 /* GPN. skip this page ?*/
613 if (points->skip!=0) {
614 switch (points->skip) {
615 case SKIP_PS:
616 /*
617 * Skip this page. User needs another run with the other
618 * of -O/-E option.
619 */
620 ps_skip_to_page(fd);
621 points++;
622 continue;
623 case STORE_PS:
624 /*
625 * stored_page could also be an array
626 * if more than one page
627 * is needed
628 */
629 totlen = ps_store_to_page(fd);
630 stored_points = points;
631 flush = STORE_PS;
632 points++;
633 continue;
634 case FLUSH_PS:
635 if (stored_points) {
636 /*
637 * Ok I have to print the page and start a new one.
638 * This could be more elegant, but for now...
639 */
640 /*
641 fprintf(outfd, "showsheet\n");
642 ps_pagenum++;
643 fprintf(outfd, "%%%%Page: %d %d\n",
644 ps_pagenum, ps_pagenum);
645 sheetheader(outfd, file_name);
646 mp_outline(outfd, asheet);
647 */
648 flush = FLUSH_PS;
649 flush_points = points;
650 points = stored_points;
651 }
652 else
653 flush = 0;
654 }
655 }
656
657 /*
658 * Save current graphics context so we can scale/translate
659 * from known position and size.
660 */
661 fprintf(outfd, "gsave\n");
662
663 /*
664 * print one reduced page by moving to the proper point,
665 * turning to the proper aspect, scaling to the proper
666 * size, and setting up a clip path to prevent overwritting;
667 * then print a reduced page of output.
668 */
669 Debug(DB_PSMPAGE, "%%%% %%%%ReducedPageStartsHere\n", outfd);
670 # ifdef DEBUG
671 if (Debug_flag & DB_PSMPAGE) {
672 fprintf(outfd, "( %d %d translate %d rotate\\n)",
673 points->pp_origin_x(), points->pp_origin_y(),
674 asheet->sh_rotate);
675 fprintf(outfd, " print flush\n");
676 }
677 # endif /* DEBUG */
678
679 #ifdef NSCALE /*GPN*/
680 fprintf (outfd, NScale);
681
682 fprintf(outfd, "%d gpnxs mul %d gpnxs mul translate %d rotate\n",
683 points->pp_origin_x(), points->pp_origin_y(),
684 asheet->sh_rotate);
685 #else /* NSCALE */
686 fprintf(outfd, "%d %d translate\n",
687 points->pp_origin_x(), points->pp_origin_y());
688 if (asheet->sh_rotate)
689 fprintf(outfd, "%d rotate\n", asheet->sh_rotate);
690
691 #endif
692 sh_wide = (*asheet->sh_width)();
693 sh_high = (*asheet->sh_height)();
694
695 /* output the clip path */
696 #ifdef NSCALE /*GPN*/
697 fprintf(outfd, "0 0 moveto 0 %d gpnys mul lineto %d gpnxs mul"
698 " %d gpnys mul lineto ",
699 sh_high, sh_wide, sh_high);
700 fprintf(outfd, "%d gpnxs mul 0 lineto\n", sh_wide);
701 fprintf(outfd, "closepath clip\n");
702 #else /* NSCALE */
703 #if 0
704 fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ",
705 sh_high, sh_wide, sh_high);
706 fprintf(outfd, "%d 0 lineto\n", sh_wide);
707 #else
708 fprintf(outfd, "1 1 moveto 1 %d lineto %d %d lineto ",
709 sh_high - 1, sh_wide - 1, sh_high - 1);
710 fprintf(outfd, "%d 1 lineto\n", sh_wide - 1);
711 #endif
712 fprintf(outfd, "closepath clip newpath\n");
713 #endif /* NSCALE */
714
715 if (opt_square) {
716 int newhigh = sh_high, newwide = sh_wide;
717
718 if (sh_wide * ps_height > sh_high * ps_width)
719 newwide = (sh_high * ps_width) / ps_height;
720 else
721 newhigh = (sh_wide * ps_height) / ps_width;
722
723 #ifdef NSCALE /*GPN*/
724 fprintf(outfd, "%d gpnxs mul %d gpnys mul translate\n",
725 #else
726 fprintf(outfd, "%d %d translate\n",
727 #endif
728
729 (sh_wide - newwide) / 2, (sh_high - newhigh) / 2);
730 sh_wide = newwide;
731 sh_high = newhigh;
732 }
733
734 fprintf(outfd, "%d %d div %d %d div scale\n",
735 sh_wide, ps_width, sh_high, ps_height);
736
737 /*
738 * Take extra page margins into account
739 */
740 fprintf(outfd, "%d %d div %d %d div scale\n",
741 ps_width, ps_width + pagemargin_left + pagemargin_right,
742 ps_height, ps_height + pagemargin_top + pagemargin_bottom);
743 #ifndef NSCALE
744 fprintf(outfd, "%d %d translate\n", pagemargin_left, pagemargin_bottom);
745 #endif
746
747 #if 0
748 /* does not seem to be neccessary. seems to create dictionary
749 * stack underflows...
750 */
751 if ((ps_posttype == PS_TEX || ps_posttype == PS_TEX2) && tex1)
752 /* start dvi2ps init every page */
753 fprintf(outfd, "%s%s", tex1, tex2);
754 #endif
755
756 /*
757 * do the individual sheet setup
758 */
759 ps_sheetsetup(outfd);
760 /*
761 * place one reduce page on the printed page
762 */
763 plcnt = 0;
764 if (flush == FLUSH_PS) {
765 rtn_val = post_flush_onepage(totlen, asheet, outfd);
766 stored_points = NULL;
767 points = flush_points;
768 }
769 else {
770 rtn_val = post_onepage(fd, asheet, outfd);
771 points++;
772 }
773 /*
774 * clean up after mpage has drawn its page
775 */
776 fprintf(outfd, "grestore\n");
777 }
778 #if 0
779 fprintf(outfd, "sheetsave restore\n");
780 #endif
781
782 /*
783 * print the sheet
784 */
785 if (points->pp_origin_x == 0 || (rtn_val == FILE_EOF && opt_file))
786 fprintf(outfd, "showsheet\n");
787
788 } while (flush && rtn_val == FILE_MORE);
789
790 if (stored_points) {
791
792 flush_points = points;
793 points = stored_points;
794
795 /*
796 * Save current graphics context so we can scale/translate
797 * from known position and size.
798 */
799 fprintf(outfd, "gsave\n");
800
801 /*
802 * print one reduced page by moving to the proper point,
803 * turning to the proper aspect, scaling to the proper
804 * size, and setting up a clip path to prevent overwritting;
805 * then print a reduced page of output.
806 */
807 Debug(DB_PSMPAGE, "%%%% %%%%ReducedPageStartsHere\n", outfd);
808 # ifdef DEBUG
809 if (Debug_flag & DB_PSMPAGE) {
810 fprintf(outfd, "( %d %d translate %d rotate\\n)",
811 points->pp_origin_x(), points->pp_origin_y(),
812 asheet->sh_rotate);
813 fprintf(outfd, " print flush\n");
814 }
815 # endif /* DEBUG */
816
817 #ifdef NSCALE /*GPN*/
818 fprintf (outfd, NScale);
819 fprintf(outfd, "%d gpnxs mul %d gpnxs mul translate %d rotate\n",
820 points->pp_origin_x(), points->pp_origin_y(),
821 asheet->sh_rotate);
822 #else /* NSCALE */
823 fprintf(outfd, "%d %d translate\n",
824 points->pp_origin_x(), points->pp_origin_y());
825 if (asheet->sh_rotate)
826 fprintf(outfd, "%d rotate\n", asheet->sh_rotate);
827
828 #endif
829 sh_wide = (*asheet->sh_width)();
830 sh_high = (*asheet->sh_height)();
831
832 /* output the clip path */
833 #ifdef NSCALE /*GPN*/
834 fprintf(outfd, "0 0 moveto 0 %d gpnys mul lineto %d gpnxs mul"
835 " %d gpnys mul lineto ",
836 sh_high, sh_wide, sh_high);
837 fprintf(outfd, "%d gpnxs mul 0 lineto\n", sh_wide);
838 fprintf(outfd, "closepath clip\n");
839 #else /* NSCALE */
840 #if 0
841 fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ",
842 sh_high, sh_wide, sh_high);
843 fprintf(outfd, "%d 0 lineto\n", sh_wide);
844 #else
845 fprintf(outfd, "1 1 moveto 1 %d lineto %d %d lineto ",
846 sh_high - 1, sh_wide - 1, sh_high - 1);
847 fprintf(outfd, "%d 1 lineto\n", sh_wide - 1);
848 #endif
849 fprintf(outfd, "closepath clip newpath\n");
850 #endif /* NSCALE */
851
852 if (opt_square) {
853 int newhigh = sh_high, newwide = sh_wide;
854
855 if (sh_wide * ps_height > sh_high * ps_width)
856 newwide = (sh_high * ps_width) / ps_height;
857 else
858 newhigh = (sh_wide * ps_height) / ps_width;
859
860 #ifdef NSCALE /*GPN*/
861 fprintf(outfd, "%d gpnxs mul %d gpnys mul translate\n",
862 #else
863 fprintf(outfd, "%d %d translate\n",
864 #endif
865
866 (sh_wide - newwide) / 2, (sh_high - newhigh) / 2);
867 sh_wide = newwide;
868 sh_high = newhigh;
869 }
870
871 fprintf(outfd, "%d %d div %d %d div scale\n",
872 sh_wide, ps_width, sh_high, ps_height);
873
874 /*
875 * Take extra page margins into account
876 */
877 fprintf(outfd, "%d %d div %d %d div scale\n",
878 ps_width, ps_width + pagemargin_left + pagemargin_right,
879 ps_height, ps_height + pagemargin_top + pagemargin_bottom);
880 #ifndef NSCALE
881 fprintf(outfd, "%d %d translate\n", pagemargin_left, pagemargin_bottom);
882 #endif
883
884 #if 0
885 /* does not seem to be neccessary. seems to create dictionary
886 * stack underflows...
887 */
888 if ((ps_posttype == PS_TEX || ps_posttype == PS_TEX2) && tex1)
889 /* start dvi2ps init every page */
890 fprintf(outfd, "%s%s", tex1, tex2);
891 #endif
892
893 /*
894 * do the individual sheet setup
895 */
896 ps_sheetsetup(outfd);
897 /*
898 * place one reduce page on the printed page
899 */
900 plcnt = 0;
901 rtn_val = post_flush_onepage(totlen, asheet, outfd);
902 stored_points = NULL;
903
904 /*
905 * clean up after mpage as drawn its page
906 */
907 fprintf(outfd, "grestore\n");
908 #if 0
909 fprintf(outfd, "sheetsave restore\n");
910 #endif
911
912 /*
913 * print the sheet
914 */
915 if (points->pp_origin_x == 0 || (rtn_val == FILE_EOF && opt_file))
916 fprintf(outfd, "showsheet\n");
917 }
918
919 /*
920 * let the upper level know about the status of possible EOF
921 */
922 return rtn_val;
923
924 } /* do_post_sheet */
925
926
927
928 static void
ps_sheetsetup(outfd)929 ps_sheetsetup(outfd)
930 FILE *outfd;
931 {
932
933 switch (ps_posttype) {
934 case PS_PSROFF: fprintf(outfd, "%s", ps_roff_xi);
935 fprintf(outfd, "/p {} def\n");
936 break;
937 /*
938 case PS_MPAGE: fprintf(outfd, "/showpage {} def\n");
939 break;
940 */
941 }
942
943 return;
944
945 } /* ps_sheetsetup */
946
947
948
949 static int
post_onepage(fd,asheet,outfd)950 post_onepage(fd, asheet, outfd)
951 FILE *fd;
952 struct sheet *asheet;
953 FILE *outfd;
954 {
955 int indoc = 0;
956
957 Debug(DB_PSROFF, "%%post_onepage: Begin page\n", 0);
958 if (ps_at_trailer) {
959 Debug(DB_PSROFF, "%%post_onepage: still at trailer\n", 0);
960 return FILE_EOF;
961 }
962
963 if (have_line) {
964 fprintf(outfd, "%s", currline);
965 have_line = 0;
966 }
967
968 while(fgets(currline, LINESIZE-1, fd) != NULL) {
969 int line_rc;
970 line_rc = post_one_line(currline, fd, outfd, &indoc, 0);
971 if (line_rc != FILE_CONT)
972 return line_rc;
973 }
974 Debug(DB_PSROFF, "%%post_onepage: eof\n", 0);
975
976 return FILE_EOF;
977
978 } /* post_onepage */
979
980
981
982 static int
post_flush_onepage(totlen,asheet,outfd)983 post_flush_onepage(totlen, asheet, outfd)
984 int totlen;
985 struct sheet *asheet;
986 FILE *outfd;
987 {
988 int indoc = 0;
989
990 Debug(DB_PSROFF, "%%post_flush_onepage: Begin page\n", 0);
991
992 /*
993 if (ps_at_trailer) {
994 Debug(DB_PSROFF, "%%post_flush_onepage: still at trailer\n", 0);
995 return FILE_EOF;
996 }
997 */
998
999 if (have_line) {
1000 fprintf(outfd, "%s", currline);
1001 have_line = 0;
1002 }
1003
1004 memgets_init(stored_page, totlen);
1005 while (memgets(currline, LINESIZE-1) != NULL) {
1006 int line_rc;
1007 line_rc = post_one_line(currline, (FILE *) NULL, outfd, &indoc, 1);
1008 if (line_rc != FILE_CONT)
1009 return line_rc;
1010 }
1011 Debug(DB_PSROFF, "%%post_flush_onepage: eof\n", 0);
1012
1013 return FILE_MORE;
1014
1015 } /* post_flush_onepage */
1016
1017
1018
1019 static int
post_one_line(line,fd,outfd,indoc,flush_page)1020 post_one_line(line, fd, outfd, indoc, flush_page)
1021 char * line;
1022 FILE *fd;
1023 FILE *outfd;
1024 int * indoc;
1025 int flush_page;
1026 {
1027 size_t len;
1028
1029 if (strncmp(line, "%%BeginDocument", 15) == 0) {
1030 (*indoc)++;
1031 }
1032 if (strncmp(line, "%%EndDocument", 13) == 0) {
1033 (*indoc)--;
1034 }
1035 if (!*indoc) {
1036 if (strncmp(line, "%%Page:", 7) == 0) {
1037 fprintf(outfd, "%% %s", line);
1038 /*
1039 * only if there is already output to this logical page
1040 */
1041 if (!plcnt)
1042 return FILE_CONT;
1043 Debug(DB_PSROFF, "%%post_one_line: next page\n", 0);
1044 return FILE_MORE;
1045 }
1046 if (opt_killtrail && (strncmp(line, "%%Trailer", 9) == 0 ||
1047 strncmp(line, "%%PSTrailer", 11) == 0)) {
1048 fprintf(outfd, "%% %s", line);
1049 Debug(DB_PSROFF, "%%post_one_line: found trailer\n", 0);
1050 ps_at_trailer = TRUE;
1051 return FILE_EOF;
1052 }
1053 /* For netscape output */
1054 if (strncmp(line, "%%EOF", 5) == 0) {
1055 fprintf(outfd, "%% %s", line);
1056 Debug(DB_PSROFF, "%%post_one_line: Netscape EOF\n", 0);
1057 return FILE_EOF;
1058 }
1059 if (ps_posttype == PS_MPAGE && strncmp(line, "showsheet", 9) == 0)
1060 return FILE_CONT;
1061 if (ps_posttype == PS_TEX || ps_posttype == PS_TEX2) {
1062 if (ps_posttype == PS_TEX2 &&
1063 (strstr(line, "eop\n") || strstr(line, "eop end\n"))) {
1064 fprintf(outfd, "%s", line);
1065 Debug(DB_PSROFF, "%%post_one_line: found TEX eop\n", 0);
1066 return FILE_MORE;
1067 }
1068 if (strncmp(line, "TeXDict", 7) == 0) {
1069 /*
1070 * Hope all dvi2ps progs work the same:
1071 * capture the TeX init code so we can run it 'manually' for
1072 * every page. This is needed as this code sets up a gstate
1073 * that conflicts with mpage...
1074 * This trick seems to work for text, but figures within the dvi
1075 * file seem to have a mind of their own...
1076 */
1077 if (tex1)
1078 free(tex1);
1079 len = strlen(line)+1;
1080 tex1 = malloc(len);
1081 (void)strlcpy(tex1, line, len);
1082 fprintf(outfd, "%s", line);
1083 flush_page ? memgets(line, LINESIZE-1) :
1084 fgets(line, LINESIZE-1, fd);
1085 if (tex2)
1086 free(tex2);
1087 len = strlen(line)+1;
1088 tex2 = malloc(len);
1089 (void)strlcpy(tex2, line, len);
1090 }
1091 }
1092 }
1093 fprintf(outfd, "%s", line);
1094 plcnt++;
1095
1096 return FILE_CONT;
1097
1098 } /* post_one_line */
1099
1100
1101
1102 static void
do_roff_tailer(fd,outfd)1103 do_roff_tailer(fd, outfd)
1104 FILE *fd, *outfd;
1105 {
1106 #ifdef DEBUG
1107 int i = 0;
1108 #endif
1109
1110 Debug(DB_PSDOC, "%%do_roff_trailer: looking for eof\n", 0);
1111 while(fgets(currline, LINESIZE-1, fd) != NULL) {
1112 #ifdef DEBUG
1113 i++;
1114 Debug(DB_PSDOC, "%%%s", currline);
1115 #endif
1116 ;
1117 }
1118 Debug(DB_PSDOC, "%%do_roff_trailer: tailer of %d lines\n", i);
1119
1120 return;
1121
1122 } /* do_roff_tailer */
1123
1124