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