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