home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume27 / psf3 / part07 / psfdoub.c < prev   
Encoding:
C/C++ Source or Header  |  1992-01-20  |  17.0 KB  |  645 lines

  1. /* ta=4 */
  2.  
  3. /****************************************************************************
  4. *                p s f d o u b  . c                                            *
  5. *                                                                            *
  6. *    Filter a "single sided" document to become a "double sided document"    *
  7. *                                                                            *
  8. *    Tony Field.       tony@ajfcal.cuc.ab.ca                                    *
  9. *                                                                            *
  10. *    The basic algorithm for "print_book()"  was based on a routine written    *
  11. *    by Tom Neff (tneff@well.uucp) named "book" which printed 5.5x8.5         *
  12. *    double sided on an HP LaserJet.                                            *
  13. ****************************************************************************/
  14. /*
  15.  * $Id: psfdoub.c,v 3.2 1992/01/19 05:50:33 ajf Exp ajf $
  16.  *
  17. */
  18. /*    psfdoub prints simple reverse order or double sided.
  19.  
  20.     if the printer is "Normal", i.e. stacks face down, then psf
  21.     calls psfdoub to print simple reverse order or double sided.
  22.     
  23.     if the printer is  "Reverse", i.e. stacks face up, then psf
  24.     calls psfdoub to print the file in reverse to make the page order
  25.     as though it were "Normal".  It also calls psfdoub to print
  26.     in book format. 
  27.  
  28.     Separate page traversal strategies are needed for "Normal"
  29.     and "Reverse" printers because of the different stacking methods.
  30.     
  31.     psfdoub will NOT print reversed order books or double sided!
  32.     All book and double sided output is in normal order as
  33.     far as the user is concerned.
  34.  
  35.     Double sided print requires two scans over the data. The first scan
  36.     by "psf" generates postscript output in normal (non-double sided)
  37.     form. A second scan examines the postscript and re-orders the output
  38.     to the printer. The second pass is always done by the "psfdoub" filter.
  39.  
  40.     Psf generates extra information to make it easy for psfdoub to work.
  41.     It simply constructs pointers to each of the %%Page: beginning
  42.     in the print file.  (see function terminate_printer())  psfdoub
  43.     uses the pointers to "skip about" the file while it does the
  44.     actual page layout.
  45.     
  46.     If the target printer has two paper hoppers (i.e. #define HOPPER is
  47.     defined and "nslots > 2") then psf creates a temp file and system("psfdoub
  48.     fname") is called to immediately generate the double sided output.
  49.     The user does not have to manually invoke psfdoub.
  50.  
  51.     If HOPPER is not defined or nslots <= 1, psf simply creates an
  52.     appropriate output file and the user must manually invoke psfdoub to
  53.     print the file.
  54.  
  55.     Double sided print is forced into this routine. It would have been
  56.     simple except for the fact that 2-up "book" format is supported.
  57.     The excuse for this strategy is, of course, to minimize the amount
  58.     of file processing overhead when double sided printing is done.
  59.     
  60.     If the double sided printing is for 8.5x5.5 inch paper printed
  61.     two-up, then psf carefully forgets (in function set_frame())
  62.     to put in page scale, rotation, and translation information.  
  63.     The psfdoub filter reads the page layout and carefully re-inserts 
  64.     these when appropriate.  If 2-up "books" are made, each logical
  65.     page becomes a separate page on the output temp file.
  66.     the psf-generated control information is assumed to be at the
  67.     end of the postscript print file.  The postscript file must contain
  68.     a line like:
  69.                     %PsfPtr: 21118
  70.                     
  71.     If the %PsPtr line is missing, then the file is NOT a book format.
  72.     The format of this information is described in function read_control().
  73.                 
  74.     psfdoub does little to normal double sided print other than to change
  75.     the order in which the pages are printed.  It also adjusts the
  76.     %%Pages: value to reflect the actual page count printed.
  77.     
  78.     psfdoub re-inserts translation, rotation and scale information eliminated
  79.     by psf if the double sided print is to make an 8.5x5.5 "book".
  80.  
  81.     Of course, a bunch of "very ugly" logic is needed for the "book"
  82.     format to re-insert the postscript for page control - but it does work...
  83. */
  84.  
  85. #include <stdio.h>
  86. #include <string.h>
  87. #include <signal.h>
  88. #include <malloc.h>
  89. #include <ctype.h>
  90. #include "psf.h"
  91.  
  92. /*    If books are made by generating two print files with the -s side count
  93.     then set SIDECOUNT = 0  (i.e. no alternate paper hopper is available.
  94.     
  95.     If books are made by switching to the alternate print hopper for
  96.     the second side, then set SIDECOUNT = 3  (i.e. second hopper is available
  97.     
  98.     Leave this set to 0.
  99. */
  100.  
  101. #define    SIDECOUNT    0
  102.  
  103. static int nsheets, nhalves;
  104. static int row;
  105. static int lpage, rpage;
  106. void catch();
  107. void trim();
  108.  
  109. char    slots[NSLOTS][200] = 
  110. {            "statusdict begin 1 setpapertray end",
  111.             "statusdict begin 2 setpapertray end",
  112.             "", "", "", ""
  113. } ;
  114. int        nslots = 2;
  115.  
  116. char    order_default[20] = "Normal";
  117. char    order_normal[100] = "\0";
  118. char    order_reverse[100] = "\0";
  119. char    *order_command = NULL;
  120.  
  121.  
  122. char    line[LONG_STR + 1];
  123. char    scale[100];
  124. int        max_frame;
  125. int        landscape;
  126. int        real_width;
  127. int        height;
  128. int        width;
  129. int     dx_home[4];
  130. int     dy_home[4];
  131. int        npage;
  132. long    *pg_loc;
  133. long    trailer_loc;
  134. int        phys_page;
  135. int        side;
  136. int        bookwork;
  137. int        alternate_tray = 0;
  138. int        second_side = 0;
  139. int        reverse_requested;        /*    user requested reverse?            */
  140. int        reverse_order;            /*    actually reverse the sequence?    */
  141. int        need_showpage = 0;        /*    is pending show page needed?     */
  142.  
  143. FILE    *input_fp;
  144. FILE    *output_fp;
  145.  
  146. char    *pgmname;
  147. char    *defref;
  148.  
  149. main(argc, argv)
  150. int        argc;
  151. char    *argv[];
  152. {    int        c, i, j;
  153.     extern char *optarg;
  154.     extern int    optind;
  155.     FILE    *pdef;
  156.     char    *env_fname;            /*    environment specified output file */
  157.     char    *getenv();
  158.     char    in_fname[100];
  159.     
  160.     /*    user may specify def file with -u */
  161.  
  162.     reverse_requested = 0;
  163.     for (i = 0;  i < argc;  i++)
  164.     {
  165.         if (strncmp (argv[i], "-u", 2) == 0)
  166.         {    if (strlen (argv[i]) > 2)
  167.                 defref = argv[i] + 2;
  168.             else
  169.                 defref = argv[i+1];
  170.             break;
  171.         }
  172.     }
  173.     if (i >= argc)
  174.     {    if ((defref = getenv ("PSFDEF")) == NULL)
  175.             defref = PDEF;
  176.     }
  177.  
  178.     if ((pdef = fopen (defref, "r")) != NULL)
  179.     {    char    line_type[200];
  180.         int        number;
  181.     
  182.         while (fgets (line, 200, pdef))
  183.         {    if (strncmp (line, "*printer", 8) == 0)
  184.                 break;
  185.         }
  186.         nslots = 0;
  187.         fgets (line, 200, pdef);        /*    skip printer name     */
  188.  
  189.         while (fgets (line, 200, pdef))
  190.         {    trim (line);
  191.             sscanf (line, "%s%d", line_type, &number);
  192.  
  193.             if (strcmp (line_type, "*order") == 0)
  194.             {    fgets (line, 200, pdef);
  195.                 line[19] = 0;
  196.                 trim (line);
  197.                 strcpy (order_default, line);
  198.                 if (number > 1)
  199.                 {    if (fgets (line, 200, pdef) == NULL)
  200.                         bad_file();
  201.                     trim (line);
  202.                     line[99] = 0;
  203.                     strcpy (order_normal, line);
  204.                     if (fgets (line, 200, pdef) == NULL)
  205.                         bad_file();
  206.                     trim (line);
  207.                     line[99] = 0;
  208.                     strcpy (order_reverse, line);
  209.                 }
  210.             }
  211.  
  212.             else if (strcmp (line_type, "*slots") == 0)
  213.             {    for (j = 0;  j < NSLOTS;  j++)
  214.                     slots[j][0] = 0;
  215.                 for (i = j = 0;  i < number;  i++)
  216.                 {    if (fgets (line, 200, pdef) == NULL)
  217.                         bad_file();
  218.                     if (i >= NSLOTS)
  219.                         continue;
  220.                     line[99] = 0;
  221.                     trim (line);
  222.                     strcpy (slots[i], line);
  223.                     j = i;
  224.                 }
  225.                 nslots = j + 1;
  226.             }
  227.  
  228.             else if (strcmp (line_type, "*eof") == 0)
  229.                 break;
  230.         }
  231.         fclose (pdef);
  232.     }
  233.  
  234.     pgmname = argv[0];
  235.     if (argc == 1  ||  strcmp (argv[1], "-") == 0)
  236.         usage ();
  237.  
  238.     side = SIDECOUNT;            /* print size 1, 2, or both = 3 */
  239.  
  240.     while ((c = getopt(argc, argv, "123vu:-")) != -1)
  241.     {    switch (c)
  242.         {
  243.         case '1':
  244.         case '2':
  245.         case '3':
  246.             side = c - '0';
  247.             break;
  248.         case 'v':
  249.             reverse_requested = 1;
  250.             break;
  251.         case 'u':        /* alread processed */
  252.             break;
  253.         default:
  254.             usage ();
  255.         }
  256.     }
  257.     if (strcmp (order_default, "Reverse") == 0)
  258.     {    reverse_order = 1;
  259.     }
  260.     else
  261.         reverse_order = 0;
  262.     if (reverse_requested)
  263.         reverse_order = !reverse_order;
  264.     if (reverse_order  &&  order_reverse[0])
  265.         order_command = order_reverse;
  266.     else if (reverse_order == 0  &&  order_normal[0])
  267.         order_command = order_normal;
  268.     else
  269.         order_command = NULL;
  270.  
  271.     if (reverse_requested  &&  side != 0)
  272.     {    fprintf (stderr, "Cannot print double sided or book in reverse order.\n");
  273.         exit (1);
  274.     }
  275.  
  276.     if (side == 3  &&  nslots < 2)
  277.     {    fprintf (stderr, "Cannot use -3: only one output tray\n");
  278.         usage();
  279.     }
  280.  
  281.     if ( side >= 4)
  282.     {    fprintf (stderr, "Print side must be 1, 2, or 3\n");
  283.         usage ();
  284.     }
  285.  
  286.     if (optind >= argc)
  287.         strcpy (in_fname, BOOKFILE);
  288.     else
  289.         strcpy (in_fname, argv[optind]);
  290.  
  291.     if (env_fname = getenv ("PSFLP"))
  292. #if defined(MSDOS)  ||  defined (__MSDOS__)
  293.     {    if ((output_fp = fopen (env_fname, "wt")) == NULL)
  294. #else
  295.     {    if ((output_fp = fopen (env_fname, "w")) == NULL)
  296. #endif
  297.         {    fprintf (stderr, "Cannot open output file %s\n", env_fname);
  298.             exit (1);
  299.         }
  300.     }
  301.     else
  302.         output_fp = stdout;
  303.  
  304.     if ((pg_loc = (long *) malloc (sizeof (long) * MAX_PAGES)) == NULL)
  305.     {    fprintf (stderr, "%s: cannot allocate enough memory\n", pgmname);
  306.         exit (1);
  307.     }
  308.     
  309.     if ((input_fp = fopen(in_fname, "r")) == NULL)
  310.     {
  311.         fprintf(stderr, "%s: Error opening %s!\n", pgmname, in_fname);
  312.         exit (1);
  313.     }
  314.     (void)    signal (SIGINT, catch);        /*    for lpd quit */
  315.     read_control (input_fp);
  316.     get_prologue ();
  317.     if (reverse_order  &&  side == 0)
  318.         reverse_pages ();
  319.     else if (bookwork)
  320.         print_book ();
  321.     else
  322.         print_double ();
  323.     get_trailer ();
  324.     exit (0);
  325. }
  326.  
  327. /****************************************************************************
  328. *    read_control()                                                            *
  329. *    Read the control information at the end of the file for the page         *
  330. *    dimensions and byte address of the start of each page.                    *
  331. *    Each of the parameter lines is a comment with the form %Psfxxxx: yyyy    *
  332. ****************************************************************************/
  333.  
  334. read_control (fp)
  335. FILE    *fp;
  336. {    char    tail[100];
  337.     int        i, j;
  338.     long    atol(), psfloc;
  339.     
  340.     /*    %PsfPtr: xxx  --> xxx is the pointer to the first %Psf... line
  341.         in the file.  Seek to the indicated byte position to begin
  342.         reading the Psf generated information which looks like:
  343.  
  344.                 %%Trailer                            <--- (a)
  345.                 %%DocumentFonts: Courier
  346.                 %%Pages: 8
  347.                 %PsfScale: 0.63194 0.79558 scale    <--- (b)
  348.                 %PsfMargin: 2 1 612 769 626
  349.                 %PsfHome: 0 0 0
  350.                 %PsfHome: 1 626 0
  351.                 %PsfHome: 2 0 0
  352.                 %PsfHome: 3 0 0
  353.                 %PsfPg: 0 405            <--- byte offsets to page
  354.                 %PsfPg: 1 3885
  355.                 %PsfPg: 2 7023
  356.                     ...
  357.                 %PsfPg: 9999 21072        <--- points to (a) above
  358.                 %PsfPtr: 21118            <--- points to (b) above
  359.                 <ctrl/d>
  360.     */
  361.     fseek (fp, -50L, 2);
  362.     fread (tail, 50, 1, fp);
  363.     if ((i = tscan (tail, "%PsfPtr:")) == -1)
  364.     {    fprintf (stderr, "%s: File is not in psf book format\n", pgmname);
  365.         exit (1);
  366.     }
  367.     psfloc = atol (tail + i + 9);        /*    beginning  of psf information */
  368.     fseek (fp, psfloc, 0);
  369.     
  370.     fgets (scale, 99, fp);
  371.     strcpy (tail, scale + 11);            /* get rid of the %psf comment */
  372.     strcpy (scale, tail);
  373.  
  374.     /*    fetch psf data.    */
  375.                                                         /*    %PsfMargin:    */
  376.     fscanf (fp, "%s %d %d %d %d %d", tail,
  377.                 &max_frame, &landscape, &real_width, &height, &width);
  378.  
  379.     bookwork = (max_frame == 2  &&  landscape && !reverse_requested);
  380.     for (i = 0;  i < 4;  i++)                            /*    %PsfHome:    */
  381.         fscanf (fp, "%s %d %d %d",  tail, &j, &dx_home[i], &dy_home[i]);
  382.  
  383.     npage = 0;                                            /*    %PsfPg:        */
  384.     while (fscanf (fp, "%s %d %ld", tail, &i, &pg_loc[npage]) == 3)
  385.     {
  386.         if (i == 9999)
  387.         {    trailer_loc = pg_loc[npage];
  388.             break;
  389.         }
  390.         npage++;
  391.     }
  392.     fseek (fp, 0L, 0);
  393. }
  394.  
  395. /****************************************************************************
  396. *    get_prologue()                                                            *
  397. *    Read the prologue and pass it directly to the output                    *
  398. ****************************************************************************/
  399.  
  400. get_prologue ()
  401. {
  402.     fgets (line, LONG_STR, input_fp);        /*    skip the psf header     */
  403.     fprintf (output_fp, "%%!PS-Adobe-\n");    /*    write a valid header    */
  404.     while (fgets (line, LONG_STR, input_fp) != NULL)
  405.     {    if (strncmp (line, "%%Page:", 7) == 0)
  406.             break;
  407.         fputs (line, output_fp);
  408.     }
  409. }
  410.  
  411. /****************************************************************************
  412. *    get_trailer ()                                                            *
  413. *    Read the trailer and pass it to the output.  Modify the page count to    *
  414. *    reflect the number of physical pages printed.                            *
  415. *    Remove any reference to the %Psf... lines.                                *
  416. ****************************************************************************/
  417.  
  418. get_trailer ()
  419. {
  420.     if (phys_page == 0  ||  (bookwork  &&  second_side))
  421.         fprintf (output_fp, "showpage pg restore\n");
  422.     if (alternate_tray == 2)
  423.         fprintf (output_fp, "%s\n", slots[0]);
  424.     fseek (input_fp, trailer_loc, 0);
  425.     while (fgets (line, LONG_STR, input_fp) != NULL)
  426.     {    if (strncmp (line, "%%Pages:", 8) == 0)
  427.             fprintf (output_fp, "%%%%Pages: %d\n", phys_page);
  428.         else if (strncmp (line, "%Psf", 4) != 0)
  429.             fputs (line, output_fp);
  430.     }
  431. }
  432.  
  433. /****************************************************************************
  434. *    display_page()                                                            *
  435. *    Send all ouput that belongs to a specific page.  For 8.5x5.5 books,        *
  436. *    generate the scale, etc that was omitted by psf.  Also enable the        *
  437. *    alternate tray if it to be used.                                        *
  438. ****************************************************************************/
  439.  
  440. display_page  (pgno, n)
  441. int pgno;
  442. int    n;
  443. {
  444.     fseek (input_fp, pg_loc[pgno], 0);
  445.     fgets (line, LONG_STR, input_fp);
  446.     if (n == 0)
  447.     {
  448.         if ((phys_page  &&  bookwork)  ||  need_showpage)
  449.             fprintf (output_fp, "showpage pg restore\n");
  450.  
  451.         if (alternate_tray == 1)
  452.         {    alternate_tray = 2;
  453.             fprintf (output_fp, "%s\n", slots[1]);
  454.         }
  455.         fprintf (output_fp, "%%%%Page: ? %d\n", ++phys_page);
  456.  
  457.         if ((bookwork  &&  max_frame == 2)  ||  pgno >= npage)
  458.         {    fprintf (output_fp, "/pg save def\n");
  459.         }
  460.         need_showpage = pgno >= npage;
  461.     }
  462.  
  463.     if (bookwork)
  464.     {    if (n == 0)
  465.         {
  466.             fprintf (output_fp, "90 rotate 0 %d translate\n", -real_width);
  467.             fprintf (output_fp, "%s", scale);
  468.         }
  469.         fprintf (output_fp, "%d %d translate\n", dx_home[n], dy_home[n]);
  470.     }
  471.  
  472.     if (pgno < npage)
  473.     {    while (fgets (line, LONG_STR, input_fp) != NULL)
  474.         {    if(strncmp (line, "%%", 2) == 0)
  475.                 break;
  476.             fputs (line, output_fp);
  477.         }
  478.     }
  479. }
  480.  
  481.  
  482. /****************************************************************************
  483. *    print_book()                                                            *
  484. *    print_book() is based on Tom Neff's (tneff@well.uucp) "book"             *
  485. *    for the HP LaserJet                                                     *
  486. *    Scan the text to ensure that the 8.5x.5.5 pages are constructed in        *
  487. *    such a way that a "book" is generated - simply staple in the middle    .    *
  488. ****************************************************************************/
  489.  
  490. print_book ()        
  491. {    int    done;
  492.  
  493.     nsheets = (npage+3)/4;
  494.     nhalves = nsheets*4;
  495.     phys_page = 0;
  496.  
  497.     if (side == 1 ||  side == 3)
  498.     {    for (rpage=0, lpage=nhalves-1;  rpage < lpage;  rpage+=2, lpage-=2)
  499.         {
  500.             display_page (lpage, 0);
  501.             display_page (rpage, 1);
  502.         }
  503.     }
  504.  
  505.     if (side == 3)
  506.         alternate_tray = 1;
  507.  
  508.     if ((side == 2  ||  side == 3)  &&  nhalves > 1)
  509.     {    second_side = 1;
  510.         if (reverse_order)
  511.         {    /* printer stacks face up */
  512.             for (rpage=nhalves-2, lpage=1;  lpage < nhalves/2;  
  513.                         rpage-=2, lpage+=2)
  514.             {
  515.                 display_page (lpage, 0);
  516.                 display_page (rpage, 1);
  517.             }
  518.         }
  519.         else
  520.         {    /*    printer stacks face down */
  521.             for (rpage=nhalves/2, lpage=rpage-1; lpage >= 0; 
  522.                         rpage+=2, lpage-=2)
  523.             {
  524.                 display_page (lpage, 0);
  525.                 display_page (rpage, 1);
  526.             }
  527.         }
  528.     }
  529.     if (need_showpage)
  530.         fprintf (output_fp, "showpage pg restore\n");
  531. }
  532.  
  533. /****************************************************************************
  534. *    print double()                                                            *
  535. *    print double sided pages.  first odd numbered, then even numbered.        *
  536. ****************************************************************************/
  537.  
  538. print_double ()
  539. {    int    apage;
  540.  
  541.     nsheets = (npage+1)/2;
  542.     phys_page = 0;
  543.  
  544.     if (side == 1  ||  side == 3)
  545.     {    for (apage = 0;  apage < nsheets;  apage++)
  546.         {    display_page (apage * 2, 0);
  547.         }
  548.     }
  549.  
  550.     if (side == 3)
  551.         alternate_tray = 1;
  552.  
  553.     if ((side == 2  ||  side == 3)  &&  npage > 1)
  554.     {    second_side = 1;
  555.         if (reverse_order)
  556.         {    /*    printer stacks face up */
  557.             for (apage = 0;  apage < nsheets;  apage++)
  558.             {    display_page (apage * 2 + 1, 0);
  559.             }
  560.         }
  561.         else
  562.         {    /* printer stacks face down */
  563.             for (apage = nsheets - 1;  apage >= 0;  apage--)
  564.             {    display_page (apage * 2 + 1, 0);
  565.             }
  566.         }
  567.         
  568.     }
  569.     if (need_showpage)
  570.         fprintf (output_fp, "showpage pg restore\n");
  571. }
  572.  
  573.  
  574. /****************************************************************************
  575. *    reverse_pages ()                                                        *
  576. *    normal print, reverse order of pages.                                    *
  577. ****************************************************************************/
  578.  
  579. reverse_pages ()
  580. {
  581.     int pgno;
  582.  
  583.     phys_page = 0;
  584.     for (pgno = npage-1;  pgno >= 0;  pgno--)
  585.         display_page (pgno, 0);
  586. }
  587.  
  588.  
  589. tscan (s, t)        /* search for string t in s */
  590. char     s[], t[];
  591. {
  592.     int    i, j, k;
  593.     for (i = 0;  s[i] != '\0';  i++)
  594.     {    for (j = i, k=0;  t[k] != '\0'  &&  s[j] == t[k];  j++, k++)
  595.             ;
  596.         if (t[k] == '\0')
  597.             return (i);
  598.     }
  599.     return (-1);
  600. }
  601. usage ()
  602. {
  603.     printf ("Usage:  psfdoub -n [-v] [-u f.def] file\n");
  604.     printf ("  where:         n = side number to print\n");
  605.     printf ("                -0 = not double sided (reverse print only)\n");
  606.     printf ("                -1 = print side 1 only\n");
  607.     printf ("                -2 = print side 2 only\n");
  608.     printf ("                -3 = print both sides in one pass\n");
  609.     printf ("                -v = reverse page order\n");
  610.     printf ("          -u f.def = use this .def file\n");
  611.     printf ("              file = print this file\n");
  612.     exit (0);
  613. }
  614.  
  615. void trim (s)                    /*    trim trailing blanks  and \n */
  616. char    *s;
  617. {    int many;
  618.  
  619.     for (many = strlen (s) - 1;  many >= 0;  many--)
  620.     {    if (isgraph (s[many]))
  621.             break;
  622.         else
  623.             s[many] = '\0';
  624.     }
  625. }
  626.  
  627.  
  628. /********************************************************
  629. *    catch ()                                            *
  630. *    Catch SIGINT from lpd                                *
  631. ********************************************************/
  632.  
  633. void catch (signo)
  634. int    signo;
  635. {
  636.         fprintf (output_fp, "%c", 0x04);
  637.         exit (0);
  638. }
  639. bad_file()
  640. {
  641.     fprintf (stderr, "Bad %s file\n", defref);
  642.     exit (1);
  643. }
  644.  
  645.