home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / TOOLS / MPAGE / MPAGE.ZIP / mp_post.c < prev    next >
Text File  |  1997-09-25  |  15KB  |  545 lines

  1. # include <stdio.h>
  2. # include <sys/types.h>
  3.  
  4. # ifndef lint
  5. static char *rcs_id =
  6.   "@(#) $Header: mp_post.c,v 2.9 89/08/09 11:30:39 mark Exp $";
  7. # endif
  8.  
  9. # include "mp_head.h"
  10.  
  11. /*
  12.  * mpage:    a program to reduce pages of print so that several pages
  13.  *           of output appear on one printed page.
  14.  *
  15.  * Written by:
  16.  *   ...!uunet!\                       Mark Hahn, Sr Systems Engineer
  17.  *              >pyrdc!mark            Pyramid Technology Corporation
  18.  * ...!pyramid!/                       Vienna, Va    (703)848-2050
  19.  *
  20.  *
  21.  * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia
  22.  *  
  23.  *     Permission is granted to anyone to make or distribute verbatim
  24.  *     copies of this document as received, in any medium, provided
  25.  *     that this copyright notice notice is preserved, and that the
  26.  *     distributor grants the recipient permission for further
  27.  *     redistribution as permitted by this notice.
  28.  *
  29.  */
  30.  
  31. /* $Log:    mp_post.c,v $
  32.  * Revision 2.9  89/08/09  11:30:39  mark
  33.  * fixed bug in get_psstr.  it did not return a value if it failed
  34.  * to find a string in parparentheses.  the code "lucked-out" on risc
  35.  * machines but failed on machines that use different locations for
  36.  * the function arguments and return values, (680x0s and VAXen).
  37.  * (First time I've seen poor coding work on a RISC but be-fuddle a CISC.
  38.  * 
  39.  * Revision 2.8  89/05/25  10:25:34  mark
  40.  * add new debugging keyword for tracking the processing of postscript
  41.  * documents.
  42.  * 
  43.  * Revision 2.7  89/05/25  10:20:38  mark
  44.  * changed the format of debugging prints in the PS code.
  45.  * 
  46.  * Revision 2.6  89/05/25  08:58:30  mark
  47.  * rearranged the rcs header keywords for better readability.
  48.  * 
  49.  * Revision 2.5  89/05/25  08:49:49  mark
  50.  * added code to disable showpage durring the printing of postscript
  51.  * documents.  we define our own routine to do the showpage.
  52.  * 
  53.  * Revision 2.4  89/05/23  09:39:36  mark
  54.  * Changes to deal with %%BeginSetup sections.  We now scan all the way
  55.  * to the first %%Page comment assuming this will cover everything.
  56.  * Actually we should do something more intelligent, saving the %%BeginSetup
  57.  * section and putting after our page reduction but before the page is
  58.  * printed.
  59.  * 
  60.  * Revision 2.3  89/05/22  14:40:56  mark
  61.  * Fixed the type-o in the rcs identification string
  62.  * 
  63.  * Revision 2.2  89/05/22  14:37:56  mark
  64.  * Added rcs identification usable with the "what" program
  65.  * 
  66.  * Revision 2.1  89/05/22  14:31:22  mark
  67.  * New Major Revision
  68.  * 
  69.  * Revision 1.2  89/05/22  13:49:58  mark
  70.  * placed the log keywork after the initial notice
  71.  * 
  72.  * Revision 1.1  89/05/22  13:48:43  mark
  73.  * Initial revision
  74.  *  */
  75.  
  76. /*
  77.  * character spaces used throughout for holding the current line from
  78.  * the input file
  79.  */
  80. static char currline[LINESIZE];
  81. /*
  82.  * for ps documents, used to remember if we have come across the
  83.  * tailer section.  reset at the beginning of processing for each file
  84.  */
  85. static int ps_at_trailer;
  86.  
  87. /*
  88.  * this is the type of postscript document we are processing
  89.  */
  90. static int ps_posttype;
  91.  
  92. /*
  93.  * peek at the first two chacters on the open file and check for the
  94.  * two character postscript flag "%!".  If the file is not postscript
  95.  * then the characters are pushed back into the input stream (hopefully).
  96.  */
  97. ps_check(infd)
  98.  FILE *infd;
  99. {
  100.     int firstchar;
  101.     int secondchar;
  102.     
  103.     Debug(DB_PSCHECK, "%%ps_check: in ps_check\n", 0);
  104.     /*
  105.      * eliminate blank files
  106.      */
  107.     if ((firstchar = fgetc(infd)) == EOF) {
  108.         Debug(DB_PSCHECK, "%%ps_check: file is blank\n", 0);
  109.         return 0;
  110.     }
  111.     /*
  112.      * eliminate non-postscript files
  113.      */
  114.     if (firstchar != '%') {
  115.         Debug(DB_PSCHECK, "%ps_check: 1st char is '%c' not '%'\n",
  116.               firstchar);
  117.         if (ungetc(firstchar, infd) == EOF) {
  118.             fprintf(stderr, "%s: Lost first character of file ",
  119.                 MPAGE);
  120.             fprintf(stderr, "while checking for postscript.");
  121.         }
  122.         return 0;
  123.     }
  124.     Debug(DB_PSCHECK, "%%ps_check: 1st char is '%c'\n", firstchar);
  125.     /*
  126.      * eliminate one character files (containing only a %)
  127.      */
  128.     if ((secondchar = fgetc(infd)) == EOF) {
  129.         Debug(DB_PSCHECK, "%%ps_check: no second char\n", 0);
  130.         if (ungetc(firstchar, infd) == EOF) {
  131.             fprintf(stderr, "%s: Lost first character of file ",
  132.                 MPAGE);
  133.             fprintf(stderr, "while checking for postscript.");
  134.         }
  135.         return 0;
  136.     }
  137.     /*
  138.      * eliminate files that don't have the full two character
  139.      * sequence of "%!".
  140.      */
  141.     if (secondchar != '!') {
  142.         Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c' not '!'\n",
  143.               secondchar);
  144.         if (ungetc(secondchar, infd) == EOF) {
  145.             fprintf(stderr, "%s: Lost first two characters of ",
  146.                 MPAGE);
  147.             fprintf(stderr, "file while checking for postscript.");
  148.             return 0;
  149.         }
  150.         if (ungetc(firstchar, infd) == EOF) {
  151.             fprintf(stderr, "%s: Lost first character of file ",
  152.                 MPAGE);
  153.             fprintf(stderr, "while checking for postscript.");
  154.         }
  155.         return 0;
  156.     }
  157.     /*
  158.      * for post script files the first two characters (the "%!") are
  159.      * digested by this routine.  It's just easier than dealing
  160.      * with the problems encounted if the characters can't be ungetc'ed.
  161.      */
  162.     Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c'\n", secondchar);
  163.     Debug(DB_PSCHECK, "%%ps_check: input is postscript\n", 0);
  164.     return 1;
  165. }
  166.  
  167. ps_gettype(fd, outfd)
  168.  FILE *fd;
  169.  FILE *outfd;
  170. {
  171.     int type_known, ps_type, end_comments;
  172.     char *get_psstr();
  173.  
  174.     Debug(DB_PSDOC, "%%ps_gettype: in ps_gettype\n", 0);
  175.     /*
  176.      * error check for truncated files
  177.      */
  178.     if (fgets(currline, LINESIZE-1, fd) == NULL) {
  179.         Debug(DB_PSDOC, "%%ps_gettype: got eof on first line\n", 0);
  180.         return PS_NONE;
  181.     }
  182.     /*
  183.      * check for non-conforming postscript
  184.      */
  185.     if (strncmp(currline, PS_FLAG, strlen(PS_FLAG)) != 0) {
  186.         Debug(DB_PSDOC, "%%ps_gettype: no match PS_FLAG \"%s\"\n",
  187.               currline);
  188.         return PS_OTHER;
  189.     }
  190.     /*
  191.      * we have some form of conforming postscript, try to identify the
  192.      * type
  193.      */
  194.     Debug(DB_PSDOC, "%%ps_gettype: conforming postscript\n", 0);
  195.     end_comments = 0;
  196.     type_known = 0;
  197.     while (!end_comments) {
  198.         /*
  199.          * if we get end of file then we assume non-conforming PS
  200.          */
  201.         if (fgets(currline, LINESIZE-1, fd) == NULL) {
  202.             Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0);
  203.             return PS_OTHER;
  204.         }
  205.         /*
  206.          * if we have run out of leading comments then assume 
  207.          * conforming PS (because we had a valid "%!" line)
  208.          */
  209.         if (currline[0] != '%') {
  210.             Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0);
  211.             fprintf(outfd, "%s", currline);
  212.             return PS_CONFORM;
  213.         }
  214.         /*
  215.          * print out the comment line with an extra % to disguise
  216.          * the comment
  217.          */
  218.         fprintf(outfd, "%%%s", currline);
  219.         /*
  220.          * check for the end of the leading comments section
  221.          */
  222.         if (strncmp(currline, "%%EndComments", 13) == 0) {
  223.             end_comments = 1;
  224.         }
  225.         /*
  226.          * once we know the type of PS, we no longer need to keep
  227.          * checking.
  228.          */
  229.         if (type_known) {
  230.             continue;
  231.         }
  232.         /*
  233.          * check for mpage output
  234.          */
  235.         if (strncmp(currline, "%%Creator: mpage", 16) == 0) {
  236.             Debug(DB_PSDOC, "%%ps_gettype: mpage document\n", 0);
  237.             type_known = 1;
  238.             ps_type = PS_MPAGE;
  239.         }
  240.         /*
  241.          * check for psroff output
  242.          */
  243.         if (strncmp(currline, "%%Title: ", 9) == 0) {
  244.             if (strcmp(get_psstr(currline), "ditroff") == 0) {
  245.                 Debug(DB_PSDOC, "%%ps_gettype: psroff\n", 0);
  246.                 type_known = 1;
  247.                 ps_type = PS_PSROFF;
  248.             }
  249.         }
  250.     }
  251.     if (type_known) {
  252.         return ps_type;
  253.     }
  254.     Debug(DB_PSDOC, "%%ps_gettype: unknow type conforming PS\n", 0);
  255.     return PS_CONFORM;
  256. }
  257.  
  258. /*
  259.  * get_psstr will extract (and return a pointer to) a string in parentheses.
  260.  * it is used for checking for psroff (ditroff) postscript.
  261.  */
  262. char *get_psstr(line)
  263.  char *line;
  264. {
  265.     char space[LINESIZE];
  266.     char *p1, *p2;
  267.  
  268.     p1 = line;
  269.     while (*p1) {
  270.         if (*p1 == '(') {
  271.             p1++;
  272.             p2 = space;
  273.             while (*p1 && (*p1 != ')')) {
  274.                 *p2++ = *p1++;
  275.             }
  276.             *p2 = 0;
  277.             return space;
  278.         }
  279.         p1++;
  280.     }
  281.     return line;
  282. }
  283.     
  284. do_ps_doc(fd, asheet, outfd)
  285.  FILE *fd;
  286.  struct sheet *asheet;
  287.  FILE *outfd;
  288. {
  289.     Debug(DB_PSDOC, "%%do_ps_doc: postscript document\n", 0);
  290.     ps_posttype = ps_gettype(fd,outfd);
  291.     Debug(DB_PSDOC, "%%do_ps_doc: document type is %d\n", ps_posttype);
  292.     switch(ps_posttype) {
  293.     case PS_NONE:
  294.         /*
  295.          * why bother?
  296.          */
  297.         break;
  298.     default:
  299.         do_post_doc(fd, asheet, outfd);
  300.         break;
  301.     }
  302. }
  303.  
  304. do_post_doc(fd, asheet, outfd)
  305.  FILE *fd;
  306.  struct sheet *asheet;
  307.  FILE *outfd;
  308. {
  309.     ps_at_trailer = FALSE;
  310.     Debug(DB_POST, "%%do_post_doc: prolog\n", 0);
  311.     ps_copyprolog(fd, outfd);
  312.     Debug(DB_POST, "%%do_post_doc: pages\n", 0);
  313.     /*
  314.      * while there is still input, print pages
  315.      */
  316.     while (do_post_sheet(fd, asheet, outfd) != FILE_EOF)
  317.       ;
  318.     Debug(DB_POST, "%%do_post_doc: trailer\n", 0);
  319.     do_roff_tailer(fd, outfd);
  320. }
  321.  
  322. do_other_doc(fd, asheet, outfd)
  323.  FILE *fd;
  324.  struct sheet *asheet;
  325.  FILE *outfd;
  326. {
  327.     ps_at_trailer = FALSE;
  328.     ps_copyprolog(fd, outfd);
  329. }
  330.  
  331. ps_copyprolog(fd, outfd)
  332.  FILE *fd;
  333.  FILE *outfd;
  334. {
  335.     char *rtn;
  336.  
  337.     Debug(DB_PSDOC, "%%ps_copyprolog: adding mpage prolog\n", 0);
  338.     fprintf(outfd, "/showsheet { showpage } bind def\n");
  339.     fprintf(outfd, "/showpage { } def\n");
  340.     Debug(DB_PSDOC, "%%ps_copyprolog: copying prolog\n", 0);
  341.     if (ps_posttype == PS_PSROFF) {
  342.         Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_roff_prolog\n",0);
  343.         ps_roff_copyprolog(fd, outfd);
  344.         return;
  345.     }
  346.     rtn = fgets(currline, LINESIZE-1, fd);
  347.     while (rtn) {
  348.         if (strncmp(currline, "%%Page:", 7) == 0) {
  349.             fprintf(outfd, "%% %s", currline);
  350.             return;
  351.         }
  352.         fprintf(outfd, "%s", currline);
  353.         rtn = fgets(currline, LINESIZE-1, fd);
  354.     }
  355.     Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
  356.     fprintf(outfd, "%%%%EndProlog\n");
  357. }
  358.  
  359. ps_roff_copyprolog(fd, outfd)
  360.  FILE *fd;
  361.  FILE *outfd;
  362. {
  363.  
  364.     Debug(DB_PSDOC, "%%ps_roff_copyprolog: copying psroff prolog\n", 0);
  365.     while(fgets(currline, LINESIZE-1, fd) != NULL) {
  366.         if (strcmp(currline, "xi\n") == 0) {
  367.             fprintf(outfd, "%%%s", currline); 
  368.         } else if (strncmp(currline, "%%Page:", 7) == 0) {
  369.             fprintf(outfd, "/p { } def\n");
  370.             fprintf(outfd, "/xt { } def\n");
  371.             fprintf(outfd, "/xs { } def\n");
  372.             fprintf(outfd, "%% %s", currline);
  373.             Debug(DB_PSDOC, "%%ps_copyprolog: Done \n", 0);
  374.             return;
  375.         } else {
  376.             fprintf(outfd, "%s", currline);
  377.         }
  378.  
  379.     }
  380.     Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
  381.     fprintf(outfd, "/p { } def\n");
  382.     fprintf(outfd, "/xt { } def\n");
  383.     fprintf(outfd, "/xs { } def\n");
  384.     fprintf(outfd, "%%%%EndProlog\n");
  385. }
  386.  
  387. ps_skip_to_page(fd)
  388.  FILE *fd;
  389. {
  390.     Debug(DB_PSDOC, "%%ps_skip to page: copying psroff prolog\n", 0);
  391.     while(fgets(currline, LINESIZE-1, fd) != NULL) {
  392.         Debug(DB_PSDOC, "%% %s", currline);
  393.         if (strncmp(currline, "%%Page:", 7) == 0) {
  394.             return;
  395.         }
  396.     }
  397.     Debug(DB_PSDOC, "%%ps_skip_to_page: eof before %%%%Page:\n", 0);
  398. }
  399.  
  400. do_post_sheet(fd, asheet, outfd)
  401.  FILE *fd;
  402.  struct sheet *asheet;
  403.  FILE *outfd;
  404. {
  405.     char **outline;
  406.     struct pagepoints *points;
  407.     int rtn_val;
  408.  
  409.     /*
  410.      * keep track of the pages printed
  411.      */
  412.     ps_pagenum += 1;
  413.     fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum);
  414. # ifdef DEBUG
  415.     if (Debug_flag & DB_PSMPAGE) {
  416.         fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum);
  417.     }
  418. # endif DEBUG
  419.     /*
  420.      * print the page outline
  421.      */
  422.     mp_outline(outfd, asheet);
  423.     /*
  424.      * run through the list of base points for putting reduced pages
  425.      * on the printed page
  426.      */
  427.     points = asheet->sh_pagepoints;
  428.     while (points->pp_origin_x != 0) {
  429.         /*
  430.          * print one reduced page by moveing to the proper point,
  431.          * turning to the proper aspect, scaling to the proper
  432.          * size, and setting up a clip path to prevent overwritting;
  433.          * the print a reduced page of output
  434.          */
  435. # ifdef DEBUG
  436.         if (Debug_flag & DB_PSMPAGE) {
  437.             fprintf(outfd, "%%%% %%%%ReducedPageStartsHere\n");
  438.         }
  439. # endif DEBUG
  440.         fprintf(outfd, "/sheetsave save def\n");
  441.         fprintf(outfd, "gsave\n");
  442. # ifdef DEBUG
  443.         if (Debug_flag & DB_PSMPAGE) {
  444.             fprintf(outfd, "(    %d %d translate %d rotate\\n)",
  445.                 points->pp_origin_x(), points->pp_origin_y(),
  446.                 asheet->sh_rotate);
  447.             fprintf(outfd, " print flush\n");
  448.         }
  449. # endif DEBUG
  450.         fprintf(outfd, "%d %d translate %d rotate\n",
  451.                points->pp_origin_x(), points->pp_origin_y(),
  452.                asheet->sh_rotate);
  453.         fprintf(outfd, "%d %d div %d %d div scale\n",
  454.                (*asheet->sh_width)(), ps_width, 
  455.                (*asheet->sh_height)(), ps_height);
  456.         /* output the clip path */
  457.         fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ",
  458.             ps_height, ps_width, ps_height);
  459.         fprintf(outfd, "%d 0 lineto\n", ps_width);
  460.         fprintf(outfd, "closepath clip newpath\n");
  461.         /*
  462.          * do the individual sheet setup
  463.          */
  464.         ps_sheetsetup(outfd);
  465.         /*
  466.          * place one reduce page on the printed page
  467.          */
  468.         rtn_val = post_onepage(fd, asheet, outfd);
  469.         /*
  470.          * clean up after mpage as drawn its page
  471.          */
  472.         fprintf(outfd, "grestore sheetsave restore\n");
  473.         points++;
  474.     }
  475.     /*
  476.      * print the sheet
  477.      */
  478.     fprintf(outfd, "showsheet\n");
  479.     /*
  480.      * let the upper level know about the status of possible EOF
  481.      */
  482.     return rtn_val;
  483. }
  484.  
  485. ps_sheetsetup(outfd)
  486.  FILE *outfd;
  487. {
  488.     switch (ps_posttype) {
  489.     case PS_PSROFF:
  490.         fprintf(outfd, "xi\n");
  491.         fprintf(outfd, "/p {} def\n");
  492.         break;
  493.     case PS_MPAGE:
  494.         fprintf(outfd, "/showpage {} def\n");
  495.         break;
  496.     }
  497. }
  498.  
  499. post_onepage(fd, asheet, outfd)
  500.  FILE *fd;
  501.  struct sheet *asheet;
  502.  FILE *outfd;
  503. {
  504.     int len;
  505.     char *test;
  506.  
  507.     Debug(DB_PSROFF, "%%post_onepage: Begin page\n", 0);
  508.     if (ps_at_trailer) {
  509.         Debug(DB_PSROFF, "%%post_onepage: still at trailer\n", 0);
  510.         return FILE_EOF;
  511.     }
  512.     while(fgets(currline, LINESIZE-1, fd) != NULL) {
  513.         if (strncmp(currline, "%%Page:",7) == 0) {
  514.             fprintf(outfd, "%% %s", currline);
  515.             Debug(DB_PSROFF, "%%post_onepage: next page\n", 0);
  516.             return FILE_MORE;
  517.         }
  518.  
  519.         if (strncmp(currline, "%%Trailer",8) == 0) {
  520.             fprintf(outfd, "%% %s", currline);
  521.             Debug(DB_PSROFF, "%%post_onepage: found trailer\n", 0);
  522.             ps_at_trailer = TRUE;
  523.             return FILE_EOF;
  524.         }
  525.         fprintf(outfd, "%s", currline);
  526.     }
  527.     Debug(DB_PSROFF, "%%post_onepage: eof\n", 0);
  528.     return FILE_EOF;
  529. }
  530.  
  531. do_roff_tailer(fd, outfd)
  532.  FILE *fd, *outfd;
  533. {
  534.     int i;
  535.  
  536.     Debug(DB_PSDOC, "%%do_roff_trailer: looking for eof\n", 0);
  537.     i = 0;
  538.     while(fgets(currline, LINESIZE-1, fd) != NULL) {
  539.         i++;
  540.         Debug(DB_PSDOC, "%%%s", currline);
  541.     }
  542.     Debug(DB_PSDOC, "%%do_roff_trailer: tailer of %d lines\n", i);
  543. }
  544.  
  545.