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