home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume12 / psf2 / part06 / psf.c
Encoding:
C/C++ Source or Header  |  1990-05-19  |  38.8 KB  |  1,469 lines

  1. /* ta=4 */
  2. /****************************************************************************
  3. *                     p s f . c        v2.0                                    *
  4. *                                                                            *
  5. *    Postscript filter                                                        *
  6. *                                                                            *
  7. *    Print text files to postscript printer.  Allow 1-up, 2-up and 4-up        *
  8. *    pages.  Provisions are made to allow font selection by imbedded            *
  9. *    escape sequences - to allow printing of man pages.  The escape sequence    *
  10. *    generated by "pnf" and "pmf" are compatible with psf.                    *
  11. *                                                                            *
  12. *    Copyright: 1989-Feb, Tony Field.       tony@ajfcal                        *
  13. *                                                                            *
  14. *    The orginal underline algorithm (/showunderline) was provided by        *
  15. *    Anders Thulin        mcvax!helios!ath@uunet.uucp                        *
  16. ****************************************************************************/
  17.  
  18. /*    NOTE:    tabstop=4    */
  19.  
  20. /*    Note:    if you want psf to ignore any text that is already in postscript
  21.             format, then possibly modify function "process_file()" to
  22.             do the detection and copy the input file to stdout.
  23.  
  24.             I haven't checked this out in detail, but it looks reasonable.
  25.             Maybe a command line option should be used to enable/disable
  26.             detection of postscript text (it is nice to be able to print
  27.             out postscript code)?
  28. */
  29.  
  30. /*    NOTES: re: -d option: double sided print.
  31.  
  32.     Double sided print requires two scans over the data.  The first
  33.     scan generates postscript output in normal (non-double sided) form.
  34.     A second scan examines the postscript and re-orders the output
  35.     to the printer.  The second pass is always done by the "psd" filter.
  36.     
  37.     Psf generates extra information to make it easy for psd to work.
  38.     It simply constructs pointers to each of the %%Page: beginning
  39.     in the print file.  (see function terminate_printer())  Psd
  40.     uses the pointers to "skip about" the file while it does the
  41.     actual page layout.
  42.     
  43.     If the target printer has two paper hoppers (i.e. #define HOPPER is
  44.     defined and "nslots > 2") then psf creates a temp file and system("psd
  45.     fname") is called to immediately generate the double sided output.
  46.     The user does not have to manually invoke psd.
  47.  
  48.     If HOPPER is not defined or nslots <= 1, psf simply creates an
  49.     appropriate output file and the user must manually invoke psd to
  50.     print the file.
  51.  
  52.     Double sided print is forced into this routine. It would have been
  53.     simple except for the fact that 2-up "book" format is supported.
  54.     The excuse for this strategy is, of course, to minimize the amount
  55.     of file processing overhead when double sided printing is done.
  56.     
  57.     If the double sided printing is for 8.5x5.5 inch paper printed
  58.     two-up, then psf carefully forgets (in function set_frame())
  59.     to put in page scale, rotation, and translation information.  
  60.     The psd filter reads the page layout and carefully re-inserts 
  61.     these when appropriate.  If 2-up "books" are made, each logical
  62.     page becomes a separate page on the output temp file.
  63. */
  64.  
  65. #include <stdio.h>
  66. #include <math.h>
  67. #include <time.h>
  68. #include "patchlevel.h"
  69. #include "psf.h"
  70.  
  71. /*    BINDIR is used to locate double sided printer "psd".
  72.     psd is called in function   output_book ()
  73.     You may wish to remove the reference to "BINDIR" in output_book().
  74. */
  75.  
  76. #ifndef BINDIR
  77. #define BINDIR "\0"
  78. #endif
  79.  
  80. /*    set up the mechanism for underline display */
  81.  
  82. #ifndef FONTINFO
  83. #define SHOWU(fp,ps)    fprintf (fp, ") %d showuline\n", ps)
  84. #else
  85. #define SHOWU(fp,ps)    fputs (") showunderline\n", fp)
  86. #endif
  87.  
  88. #define MAX_PAGES    500        /* max pages in a book                        */
  89. #define LONG_STR    1000    /* long buffer line                            */
  90.  
  91. #define    min(x,y)        ((x) < (y) ? (x) : (y))
  92. #define    max(x,y)        ((x) > (y) ? (x) : (y))
  93.  
  94. /* default font with and height - assumes Courier fixed pitch                */
  95.  
  96. #define NOMINAL_CWIDE    7.2        /* point width for Courier 12-point            */
  97. #define NOMINAL_POINTS    12        /* standard 12-point for printing            */
  98.  
  99. #define NORMAL        0x00        /* bitset for  print_attributes                */
  100. #define ITALICS        0x01
  101. #define BOLD        0x02
  102. #define UNDERLINE    0x04        /* must be 0x04.  underline is not a font    */
  103.  
  104. /* Paper physical dimensions.  Each paper size supported must be described.
  105.     If the paper print areas specified are incorrect, you must modify them.
  106.     The default paper sizes are coded into psf and are set for a NEC LC890
  107.     printer.  These defaults are overridden in the "psfprint.def" printer
  108.     definition file.
  109.  
  110.     All text work must preserve the physical margins and scale the 
  111.     drawing area to reflect the 1-up, 2-up or 4-up magnification.
  112.  
  113.  
  114.     "paper_name" is the name used on the command line with the -g option
  115.     to select the paper size:  eg   -g legal
  116.     
  117.     "paper_tray" is the command that is necessary to select the
  118.     specified paper size. For example, if the "legal" sized paper is in
  119.     the "alternate print tray", the postscript commands necessary to
  120.     switch paper tray and to select the legal size must be specified in
  121.     the "paper_tray" structure element. 
  122. */
  123.  
  124. typedef struct                     /*    measurement in point                    */
  125. {    char    paper_name[60];        /*    name of paper size (for command line)    */
  126.     char    paper_tray[200];    /*    postscript operator to select this tray    */
  127.     int        width;                /*    portrait point width of paper            */
  128.     int        height;                /*    portrait point height of paper            */
  129.     int        lx, ly, ux, uy;
  130.     int        left_marg;            /*    margin widths (unprintable area)        */
  131.     int        bot_marg;            /*            "                                */
  132.     int        right_marg;            /*            "                                */
  133.     int        top_marg;            /*            "                                */
  134.     int        x_size;            /*    generated by psf.                        */
  135.     int        y_size;            /*    size after correction for line count    */
  136.     int        n_lines;            /*            "                                */
  137.     int        n_chars;            /*            "                                */
  138. } measure;
  139.  
  140. measure    *p;        /*    working set of parameters  (points to something below)     */
  141.  
  142.                 /*    standard paper sizes in portrait layout (NEC LC890)        */
  143.                 /*    These are defaults and are overridden in psfprint.def.    */
  144.  
  145. measure    page_types[30] =
  146. {            {     "letter",
  147.                 "statusdict begin lettertray end",
  148.                   612,   792,    18,    15,   593,   777
  149.             },
  150.             {     "legal",
  151.                 "statusdict begin legaltray end",
  152.                   612,  1008,    18,    15,   593,   993
  153.             },
  154.             {    "a4",
  155.                 "statusdict begin a4tray end",
  156.                   595,   842,    18,    15,   578,   827
  157.             },
  158.             {    "b5",
  159.                 "statusdict begin b5tray end",
  160.                   516,   729,    18,    15,   497,   712
  161.             },
  162.             {    "",            /* end of paper list */
  163.                 "",
  164.                  0, 0,  0,  0, 0, 0, 0, 0, 0, 0 
  165.             }
  166. };
  167.  
  168. char    slots[4][100] = 
  169. {            "statusdict begin 1 setpapertray end",
  170.             "statusdict begin 2 setpapertray end",
  171.             "",
  172.             ""
  173. } ;
  174. int        nslots = 2;
  175.  
  176.  
  177. /* Current information about page.  Where are we, etc.  
  178. */
  179.  
  180. int        y_top_offset;            /*    offsets for each frame                    */
  181. int        x_left_offset;
  182. int        dx_home[4];                /*    page frame home (0,0) translations        */
  183. int        dy_home[4];
  184.  
  185. int        x,y;                    /* current x,y coordinate                    */
  186. double    scale_x, scale_y;        /* scale factors for 2-up, 4-up printing    */
  187. int        real_width;
  188.  
  189. long    *pg_loc;                /* double side print byte ptr to %%Page:    */
  190. int        npg_loc;                /* number of elements in pg_loc[]            */
  191.  
  192. int        book             = 0;    /* book format: double sided                */
  193. int        bookwork        = 0;    /* book format, 2-up print                    */
  194. int        lines_on_page     = 60;    /* user print lines on page                    */
  195. int        lines_total     = 0;    /* total number of lines for scale purposes    */
  196. int        chars_on_line     = 80;    /* default number of chars on line            */
  197. int        landscape         = 0;    /* 1 = landscape, 0 = portrait layout        */
  198. int        header            = 0;    /* 1 = print header at top of each page        */
  199. int        cross              = 0;    /* 1 = print cross on 4-up pages            */
  200. int        line_number        = 0;    /* current logical line number on page        */
  201. int        tab_size           = 8;    /* space translation for tabs.                */
  202. int        font_number     = 0;    /* one of the valid fonts in the printer    */
  203. int        point_size        = 12;    /* can be changed with the -p option        */
  204. int        x_user_offset     = 0;    /* offsets specified buy user                */
  205. int        y_user_offset     = 0;    /* points from physical page edge.            */
  206. int        set_paper_tray     = 0;    /* user has set paper tray selection        */
  207. int        set_line_count     = 0;    /*                print line count on page    */
  208. int        set_total_count    = 0;    /*                total line count on page    */
  209. int        set_point_size     = 0;    /*                point size                    */
  210. int        set_char_count     = 0;    /*                characters on a line        */
  211. int        set_paper_bin    = 0;    /*                paper bin (not page size)    */
  212. char    header_text[100];        /*                header line text            */
  213.  
  214. int        print_attribute = 0;    /* such as BOLD, UNDERLINE, ITALICS            */
  215. int        default_font_number;    /* set with -f option, or 0                    */
  216. int        default_point_size;        /* assumes value due to -p option            */
  217. int        y_coord            = 0;    /* current logical page y-coordinate, points*/
  218. int        x_coord            = 0;    /* current logical page x-coordinate, points*/
  219. int        page_number;            /* current page number for this file        */
  220. int        physical_page     = 0;    /* postscript physical page for multi-up    */
  221.  
  222.  
  223. char    fname[100];
  224. char    now[50];                /* time of day for page headers             */
  225.  
  226.  
  227. /*    to select a font, use 4 * font_number + print_attribute as index.
  228.     e.g.   If font_number = 1    for Helvetica,
  229.       and print_attribute = 0x02 for BOLD
  230.  
  231.     then the actual font selected is    fonts[4 * 1 + 2]
  232.                                         = Helvetica-Bold
  233.  
  234.     The various print attributes can be OR'ed together:
  235.             fonts [4 * 1 + ITALICS | BOLD] 
  236.  
  237.     The following are default fonts - and are overridden in psfprint.def.
  238. */
  239.       
  240. #define NFONTS      40            /*     4 variations * 9 font families  */
  241. char *fonts[NFONTS] =
  242. {
  243.     "Courier",                    "Courier-Oblique",            "Courier-Bold",             "Courier-BoldOblique",
  244.     "Helvetica",                 "Helvetica-Oblique",         "Helvetica-Bold",            "Helvetica-BoldOblique",
  245.     "Times-Roman",                 "Times-Italic",             "Times-Bold",                 "Times-BoldItalic",
  246.     "AvantGarde-Book",          "AvantGarde-BookOblique",   "AvantGarde-Demi",          "AvantGarde-DemiOblique",
  247.     "Bookman-Light",            "Bookman-LightItalic",      "Bookman-Demi",             "Bookman-DemiItalic",
  248.     "NewCenturySchlbk-Roman",   "NewCenturySchlbk-Italic",  "NewCenturySchlbk-Bold",    "NewCenturySchlbk-BoldItalic",
  249.     "Palatino-Roman",           "Palatino-Italic",          "Palatino-Bold",            "Palatino-BoldItalic",
  250.     "Helvetica-Narrow",         "Helvetica-Narrow-Oblique", "Helvetica-Narrow-Bold",    "Helvetica-Narrow-BoldOblique",
  251.     "Garamond-Light",            "Garamond-LightItalic",        "Garamond-Bold",            "Garamond-BoldItalic",
  252.     "ZapfChancery-MediumItalic","ZapfChancery-MediumItalic","ZapfChancery-MediumItalic","ZapfChancery-MediumItalic"
  253. } ;
  254.  
  255. int    fonts_used[NFONTS];
  256. int    fonts_have[NFONTS];
  257.  
  258. int    max_frame    = 1;        /* max number of frames in use */
  259. int    frame        = -1;        /* current frame in use */
  260.  
  261. FILE    *input_fp, *output_fp;
  262.  
  263. /*    input line and input line pointer */
  264. unsigned char    *c;
  265. unsigned char    line[LONG_STR + 1];
  266.  
  267. char    *pgmname;
  268.  
  269. char    *malloc();
  270.  
  271. main (argc, argv)
  272. int        argc;
  273. char    *argv[];
  274. {    int        c, i, j;
  275.     extern char *optarg;
  276.     extern int    optind;
  277.     FILE    *pdef;
  278.     
  279.     /*    see if there is a psfprint.def printer definition file.  If so,
  280.         use those parameters, rather than the hard-coded defaults.
  281.     */
  282.  
  283.     if ((pdef = fopen (PDEF, "r")) != NULL)
  284.     {    nslots = 0;
  285.         fgets (line, 100, pdef);
  286.         for (i = 0;  i < 28;  i++)
  287.         {    if (fgets (page_types[i].paper_name, 59, pdef) == NULL)
  288.                 break;
  289.             trim (page_types[i].paper_name);
  290.             if (strncmp (page_types[i].paper_name, "*fonts", 6) == 0)
  291.             {
  292.                 for (j = 0;  j < NFONTS;  j++)
  293.                     fonts_have[j] = 0;
  294.                 page_types[i].paper_name[0] = '\0';
  295.                 while (fgets (line, 90, pdef) != NULL)
  296.                 {    trim (line);
  297.                     if (*line == '*')
  298.                         break;
  299.                     for (j = 0;  j < NFONTS;  j++)
  300.                     {    if (comp (fonts[j], line) == 0)
  301.                         {    fonts_have[j] = 1;
  302.                             break;
  303.                         }
  304.                     }
  305.                 }
  306.                 if (strncmp (line, "*slots", 6) == 0)
  307.                 {    while (fgets (line, 90, pdef) != NULL)
  308.                     {    trim (line);
  309.                         if (strncmp (line, "*eof", 4) == 0)
  310.                             break;
  311.                         if (*line)
  312.                         {
  313.                             strcpy (slots[nslots], line);
  314.                             if (++nslots > 3)
  315.                                 break;
  316.                         }
  317.                     }
  318.                 }
  319.                 break;        /* end of file */
  320.             }
  321.             if (fgets (page_types[i].paper_tray, 199, pdef) == NULL)
  322.                 bad_file();
  323.             trim (page_types[i].paper_tray);
  324.             if (fgets (line, 100, pdef) == NULL)
  325.                 bad_file();
  326.             trim (line);
  327.             sscanf (line, "%d%d%d%d%d%d",
  328.                 &page_types[i].width,
  329.                 &page_types[i].height,
  330.                 &page_types[i].lx,
  331.                 &page_types[i].ly,
  332.                 &page_types[i].ux,
  333.                 &page_types[i].uy);
  334.  
  335.         }
  336.         page_types[i].paper_name[0] = '\0';
  337.         fclose (pdef);
  338.     }
  339.     else
  340.     {    for (i = 0;  i < NFONTS;  i++)
  341.             fonts_have[i] = 1;
  342.         fonts_have[8] = 0;
  343.     }
  344.  
  345.     for (i = 0;  page_types[i].paper_name[0];  i++)
  346.     {    page_types[i].left_marg  = page_types[i].lx;
  347.         page_types[i].bot_marg   = page_types[i].ly;
  348.         page_types[i].top_marg   = (page_types[i].height - 1) - page_types[i].uy;
  349.         page_types[i].right_marg = (page_types[i].width  - 1) - page_types[i].ux;
  350.  
  351.         page_types[i].x_size = page_types[i].ux - page_types[i].lx + 1;
  352.         page_types[i].y_size = page_types[i].uy - page_types[i].ly + 1;
  353.     }
  354.         
  355.     pgmname = argv[0];
  356.     p = &page_types[0];            /* default to letter size paper    */
  357.     *header_text = '\0';
  358.     scale_x = 1.0;
  359.     scale_y = 1.0;
  360.     if (strcmp (argv[1], "-") == 0  || strcmp (argv[1], "--") == 0)
  361.         usage();
  362.     while ((c = getopt(argc, argv, "124xhnwdi:m:b:c:g:H:l:L:f:t:p:-?")) != -1)
  363.     {    switch (c)
  364.         {
  365.         case '1':
  366.             max_frame = 1;
  367.             scale_x = 1.0;
  368.             scale_y = 1.0;
  369.             break;
  370.             
  371.         case '2':
  372.             landscape = 1;
  373.             max_frame = 2;
  374.             scale_x = 0.647;
  375.             scale_y = 0.772;
  376.             break;
  377.         
  378.         case '4':
  379.             max_frame = 4;
  380.             scale_x = 0.5;
  381.             scale_y = 0.5;
  382.             break;
  383.             
  384.         case 'b':
  385.             if ((set_paper_bin = atoi (optarg)) > nslots)
  386.             {    if (nslots = 0)
  387.                     fprintf (stderr, "%s: no alternate bins permitted for this printer\n", nslots);
  388.                 else
  389.                     fprintf (stderr, "%s: paper bin greater than %d\n", pgmname, nslots);
  390.                 exit (1);
  391.             }
  392.             break;
  393.  
  394.         case 'c':
  395.             chars_on_line = atoi (optarg);
  396.             set_char_count = 1;
  397.             break;
  398.  
  399.         case 'd':
  400.             book = 1;
  401.             break;
  402.                     
  403.         case 'f':
  404.             if (*optarg > '9')
  405.             {    for (i = 0;  i < NFONTS;  i += 4)
  406.                 {    if (compare (optarg, fonts[i]) == 0)
  407.                     {    font_number =  i / 4;
  408.                         break;
  409.                     }
  410.                 }
  411.                 if (i >= NFONTS)
  412.                     font_number = 0;
  413.             }
  414.             else
  415.             {
  416.                 font_number = atoi (optarg);
  417.                 if (font_number > (NFONTS / 4))
  418.                     font_number = 0;
  419.             }
  420.             break;
  421.  
  422.         case 'g':
  423.             p = NULL;
  424.             for (i = 0;  page_types[i].paper_name[0];  i++)
  425.             {    if (compare (optarg, page_types[i].paper_name) == 0)
  426.                 {    p = &page_types[i];
  427.                     break;
  428.                 }
  429.             }
  430.             if (p == NULL)
  431.                 usage ();
  432.             set_paper_tray = 1;
  433.             break;
  434.  
  435.         case 'l':
  436.             lines_on_page = atoi (optarg);
  437.             set_line_count = 1;
  438.             break;
  439.  
  440.         case 'L':
  441.             lines_total = atoi (optarg);
  442.             set_total_count = 1;
  443.             break;
  444.             
  445.         case 'h':
  446.             header = 1;
  447.             break;
  448.             
  449.         case 'H':
  450.             header = 2;
  451.             strcpy (header_text, optarg);
  452.             break;
  453.             
  454.         case 'i':
  455.             x_user_offset = atoi (optarg);
  456.             break;
  457.             
  458.         case 'm':
  459.             y_user_offset = atoi (optarg);
  460.             break;
  461.             
  462.         case 'n':
  463.             landscape = 0;
  464.             break;
  465.  
  466.         case 'p':
  467.             point_size = atoi (optarg);
  468.             set_point_size = 1;
  469.             break;
  470.             
  471.         case 't':
  472.             tab_size = atoi (optarg);
  473.             break;
  474.         
  475.         case 'w':
  476.             landscape = 1;
  477.             break;
  478.             
  479.         case 'x':
  480.             cross = 1;
  481.             break;
  482.  
  483.         default:    usage ();
  484.             break;
  485.         }
  486.     }
  487.  
  488.     if (font_number * 4 > NFONTS)
  489.     {    fprintf (stderr,"Font number invalid....\n");
  490.         usage ();
  491.     }
  492.     
  493.     if (header)
  494.         lines_on_page += 2;
  495.  
  496. #ifdef HOPPER
  497.     if (book  &&  nslots > 1)
  498.     {
  499.         if ((output_fp = fopen ("1psbook2.d34", "w")) == NULL)
  500.         {    fprintf (stderr, "%s: cannot create work file\n", pgmname);
  501.             exit (1);
  502.         }
  503.     }
  504.     else    
  505. #endif
  506.         output_fp = stdout;
  507.  
  508.     if (book)
  509.     {    if ((pg_loc = (long *) malloc (sizeof (long) * MAX_PAGES)) == NULL)
  510.         {    fprintf (stderr, "%s: cannot allocate enough memory\n", pgmname);
  511.             exit (1);
  512.         }
  513.         npg_loc = 0;
  514.     }
  515.  
  516.     for (i = 0;  i < NFONTS;  i++)
  517.         fonts_used[i] = 0;
  518.  
  519.     page_number = -1;
  520.     line_number = 32000;
  521.     default_point_size = point_size;
  522.     default_font_number = font_number;
  523.     bookwork = book  &&  landscape  &&  (max_frame == 2);
  524.     *fname = 0;    
  525.  
  526.     get_time (now);        
  527.     scale_factors ();
  528.     prologue (output_fp);
  529.     if (optind >=  argc)
  530.     {    if (header == 1)
  531.             header = 0;
  532.         start_file ();
  533.         input_fp = stdin;
  534.         process_file ();
  535.         terminate_file ();
  536.     }
  537.     else for ( ;  optind < argc;  optind++)
  538.     {    i = strlen (argv[optind]);
  539.         if (i > 38)
  540.             i -= 38;
  541.         else
  542.             i = 0;
  543.         strcpy (fname, argv[optind] + i);
  544.         if ((input_fp = fopen (argv[optind], "r")) == NULL)
  545.         {    fprintf (stderr, "Unknown file: %s\n", argv[optind]);
  546.             continue;
  547.         }
  548.         start_file ();
  549.         process_file ();
  550.         terminate_file ();
  551.         fclose (input_fp);
  552.     }
  553.     terminate_printer ();
  554.  
  555.     if (book)
  556.         output_book ();
  557.  
  558.     exit (0);
  559. }
  560.  
  561. /****************************************************************************
  562. *    scale_factors ()                                                        *
  563. *    Compute the x and y scale factors.  If the print is for landscape,        *
  564. *    adjust the paper size matrix (p->...) to reflect landscape rather        *
  565. *    than portrait.                                                            *
  566. ****************************************************************************/
  567.  
  568. /*    scale factors are calculated from:
  569.  
  570.     unprintable size  +  scale factor  *  print size  =  total paper size
  571.     
  572.                     total paper size - unprintable size
  573.     scale factor = --------------------------------------
  574.                             print size
  575. */
  576.  
  577. scale_factors ()
  578. {    int    wide;                /*    width needed for char count            */
  579.     int    high;                /*    points needed for line count        */
  580.     int    i;
  581.     double    char_width, scale;
  582.  
  583.     /*    determine default number of characters and lines based upon
  584.         Courier 12 point, 10 pitch font, portrait layout
  585.     */
  586.  
  587.     char_width = NOMINAL_CWIDE;    /* in points                        */
  588.     real_width = p->width;        /* for initial axis translate only    */
  589.  
  590.     p->n_chars = ceil ((double) p->x_size / NOMINAL_CWIDE);
  591.     p->n_lines = p->y_size / NOMINAL_POINTS;
  592.  
  593.     /*    set line count relative to portrait measure */
  594.  
  595.     if (set_total_count == 0)
  596.         lines_total = p->n_lines;
  597.  
  598.     if (set_line_count == 0)
  599.         lines_on_page = p->n_lines;
  600.  
  601.     if (lines_total < lines_on_page)
  602.     {    if (set_total_count)
  603.             lines_on_page = lines_total;
  604.         else
  605.             lines_total = lines_on_page;
  606.     }
  607.  
  608.     /*    if landscape, then switch the height and width dimensions      */
  609.     
  610.     if (landscape)
  611.     {
  612.         i = p->height;      p->height    = p->width;        p->width      = i;
  613.         i = p->left_marg;   p->left_marg = p->bot_marg;     p->bot_marg   = i;
  614.         i = p->top_marg;    p->top_marg  = p->right_marg;   p->right_marg = i;
  615.         i = p->lx;            p->lx        = p->ly;            p->ly          = i;
  616.         i = p->ux;            p->ux        = p->uy;            p->uy          = i;
  617.         i = p->x_size;        p->x_size    = p->y_size;        p->y_size      = i;
  618.         
  619.         if (max_frame == 1)
  620.         {    scale = (double) p->y_size / (double) p->x_size;
  621.             p->n_chars = ceil ((double) p->n_chars * scale * scale);
  622.         }
  623.     }
  624.     if (set_char_count == 0)
  625.         chars_on_line = p->n_chars;
  626.  
  627.     if (set_point_size)
  628.     {    scale = (double) point_size / (double) NOMINAL_POINTS;
  629.         lines_total = p->y_size / point_size;
  630.         if (set_char_count == 0)
  631.         {    chars_on_line /= scale;
  632.             char_width    *= scale;
  633.         }
  634.     }
  635.     else if (set_line_count  ||  set_total_count)
  636.     {
  637.         if (set_char_count == 0)
  638.         {    scale = (double) lines_total / (double) p->n_lines;
  639.             chars_on_line = ceil ((double) chars_on_line * scale);
  640.         }
  641.     }
  642.  
  643.     /*    Ideally, we wish to use a decender value of 0.5 line.
  644.         This is yieds a scale factor of 1.0 for Courier in default
  645.         portrait mode.  Hopefully, this is not a problem with
  646.         other fonts.
  647.     */
  648.     high = ceil ((double) point_size * ((double) lines_total + 0.51));
  649.     wide = ceil (chars_on_line * char_width);
  650.  
  651.     x_user_offset = max (0, x_user_offset - p->left_marg);
  652.     y_user_offset = max (0, y_user_offset - p->top_marg );
  653.  
  654.     switch (max_frame)
  655.     {
  656.     case 1:
  657.         scale_x = (double) (p->x_size) / (double) wide;
  658.         scale_y = (double) (p->y_size) / (double) high;
  659.         x_left_offset  = (int) ceil ((double) (p->left_marg + x_user_offset) / scale_x);
  660.         y_top_offset   = (int) ceil ((double) (p->top_marg  + y_user_offset) / scale_y);
  661.         dx_home[0] = 0;
  662.         dy_home[0] = 0;
  663.         p->height = ceil ((double) p->height / scale_y);
  664.         p->width  = ceil ((double) p->width / scale_x);
  665.         p->bot_marg = ceil ((double) p->bot_marg / scale_y);
  666.         break;
  667.     
  668.     case 2:
  669.         scale_x = (double) (p->width - 2 * p->left_marg - 2 * p->right_marg)
  670.                 / (double) (2 * wide);
  671.         scale_y = (double) (p->y_size) / (double) high;
  672.  
  673.         /*    point offsets for margins account for physical "forbidden" area */
  674.  
  675.         x_left_offset  = (int) ceil ((double) p->left_marg / scale_x);
  676.         y_top_offset   = (int) ceil ((double) p->top_marg / scale_y);
  677.         
  678.         /*    page origin translation vectors    */
  679.         
  680.         p->height = ceil ((double) p->height / scale_y);
  681.         p->width  = ceil ((double) p->width  / (scale_x * 2.0));
  682.         p->bot_marg = ceil ((double) p->bot_marg / scale_y);
  683.         dx_home[0] = 0;
  684.         dy_home[0] = 0;
  685.         dx_home[1] = p->width;
  686.         dy_home[1] = 0;
  687.         break;
  688.     
  689.     case 4:
  690.         scale_x = (double) (p->width - 2 * p->left_marg - 2 * p->right_marg)
  691.                 / (double) (2 * wide);
  692.         scale_y = (double) (p->height - 2 * p->top_marg - 2 * p->bot_marg)
  693.                 / (double) (2 * high);
  694.  
  695.         /*    point offsets for margins account for physical "forbidden" area */
  696.  
  697.         x_left_offset = (int) ceil ((double) p->left_marg / scale_x);
  698.         y_top_offset  = (int) ceil ((double) p->top_marg / scale_y);
  699.         
  700.         /*    page origin tranlsation vectors    */
  701.         
  702.         p->height = ceil ((double) p->height / (scale_y * 2.0));
  703.         p->width  = ceil ((double) p->width  / (scale_x * 2.0));
  704.         p->bot_marg = ceil ((double) p->bot_marg / scale_y);
  705.         dx_home[0] = 0;
  706.         dy_home[0] = p->height;
  707.         dx_home[1] = 0;
  708.         dy_home[1] = -p->height;
  709.         dx_home[2] = p->width;
  710.         dy_home[2] = p->height;
  711.         dx_home[3] = 0;
  712.         dy_home[3] = -p->height;
  713.         break;
  714.     
  715.     default: ;
  716.     }
  717.  
  718.     if (max_frame > 1)
  719.     {    x_left_offset += x_user_offset;
  720.         y_top_offset  += y_user_offset;
  721.     }
  722.     
  723. #ifdef DEBUG
  724.     printf ("%%!PS-Adobe-\n");
  725.     printf ("%% lines =%d/%d/%d  chars = %d/%d\n", lines_total, set_line_count,set_total_count, chars_on_line, set_char_count);
  726.     printf ("%% height     = %d / %d\n", p->height, high);
  727.     printf ("%% width      = %d / %d\n", p->width, wide);
  728.     printf ("%% (lx,ly)    = (%d,%d)\n", p->lx, p->ly);
  729.     printf ("%% (ux,uy)    = (%d,%d)\n", p->ux, p->uy);
  730.     printf ("%% left_marg  = %d\n", p->left_marg);
  731.     printf ("%% right_marg = %d\n", p->right_marg);
  732.     printf ("%% top_marg   = %d\n", p->top_marg);
  733.     printf ("%% bot_marg   = %d\n", p->bot_marg);
  734.     printf ("%% y_size     = %d\n", p->y_size);
  735.     printf ("%% x_size     = %d\n", p->x_size);
  736.     printf ("%% scale_x = %f   scale_y = %f\n", scale_x, scale_y);
  737.     printf ("%% offset (lx,ty) = (%d,%d)\n", x_left_offset,  y_top_offset);
  738.     printf ("%% home       = %d %d %d %d\n",dy_home[0], dy_home[1], dy_home[2],dy_home[3]);
  739. #endif
  740. }
  741.  
  742.  
  743. /****************************************************************************
  744. *    prologue ()                                                                *
  745. *    generate the require postscript-conformant prologue                        *
  746. ****************************************************************************/
  747.  
  748. prologue ()
  749. {    char    *getlogin();
  750.     int        i;
  751.  
  752.     if (book)
  753.         fprintf (output_fp, "%%Book file: psf-to-psd\n");
  754.     else
  755.         fprintf (output_fp, "%%!PS-Adobe-\n");
  756.     fprintf (output_fp, "%%%%Creator: %s\n", getlogin());
  757.     fprintf (output_fp, "%%%%CreationDate: %s\n", now);
  758.     fprintf (output_fp, "%%%%DocumentFonts: (atend)\n");
  759.     fprintf (output_fp, "%%%%Pages: (atend)\n");
  760.     fprintf (output_fp, "%%%%EndComments\n");
  761.     
  762. #ifndef FONTINFO
  763.     /*     The red book (pg 93) indicates that the FontInfo dictionary
  764.         "MAY" contain the /UnderlinePosition and /UnderlineThickness
  765.         This is the case for all Adobe fonts.  External non-Adobe fonts may
  766.         not have these values.
  767.         
  768.         usage:         (text to underline) <pointsize> showuline
  769.         where:        <pointsize> is current text point size.
  770.  
  771.         eg:            (text to underline) 12 showuline
  772.     */
  773.     fprintf (output_fp, "%s%s%s%s%s%s%s%s%s%s",
  774.             "/showuline {\n",
  775.             "    /CurPointSize exch def\n",
  776.             "    dup stringwidth pop\n",
  777.             "    gsave\n",
  778.             "    currentfont /FontInfo get dup\n",
  779.             "    /UnderlinePosition get CurPointSize mul 1000 div 0 exch rmoveto exch 0 rlineto\n",
  780.             "    /UnderlineThickness get CurPointSize mul 1000 div setlinewidth stroke\n",
  781.             "    grestore\n",
  782.             "    show\n",
  783.             "} def\n");
  784.  
  785. #else
  786.     /*    showunderline: without FontInfo:  underline is 2 points below base 
  787.         compliments of Anders Thulin
  788.                         mcvax!helios!ath@uunet.uucp (Anders Thulin)
  789.  
  790.         usage:        (text to underline) showunderline
  791.     */
  792.     fprintf (output_fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
  793.             "/showunderline {\n",
  794.             "  /str exch def\n",
  795.             "  /dy     0 def\n",
  796.             "  currentpoint\n",
  797.             "    str show\n",
  798.             "  moveto\n",
  799.             "  /dy -2 def\n",
  800.             "  currentpoint\n",
  801.             "  dy add\n",
  802.             "  moveto\n",
  803.             "  str stringwidth\n",
  804.             "  rlineto \n",
  805.             "  currentpoint\n",
  806.             "    stroke\n",
  807.             "  moveto\n",
  808.             "  currentpoint\n",
  809.             "  dy sub\n",
  810.             "  moveto\n",
  811.             "} def\n");
  812. #endif
  813.  
  814.     fprintf (output_fp, "%%%%EndProlog\n");
  815.  
  816.     if (set_paper_tray)
  817.         fprintf (output_fp, "%s\n", p->paper_tray);
  818.  
  819.     if (set_paper_bin)
  820.         fprintf (output_fp, "%s\n", slots[set_paper_bin - 1]);
  821. }
  822.  
  823. /****************************************************************************
  824. *    new_page ()                                                                *
  825. *    Generate a new page.  Send out required rotation,scale information        *
  826. *    This is the "prologue" to a page (not the end of the previous)            *
  827. ****************************************************************************/
  828.  
  829. new_page ()
  830. {
  831. }
  832.  
  833.  
  834. /****************************************************************************
  835. *    showpage ()                                                                *
  836. *    Generate a real "showpage" if we have really finished generating a        *
  837. *    physical page.  If we are processing 2 or 4 up, then generate             *
  838. *    coordinate "translates" if we really haven't finished all possible        *
  839. *    page frames of the page.                                                *
  840. ****************************************************************************/
  841.  
  842. showpage (end_of_file)
  843. int end_of_file;
  844. {
  845.     line_number = 0;
  846.  
  847.     if (++frame >= max_frame  ||  end_of_file)
  848.     {    if (bookwork == 0)                    /* psd will re-insert this */
  849.             fprintf (output_fp, "showpage pg restore\n");
  850.         frame = 0;
  851.     }
  852.     if (!end_of_file)
  853.         set_frame ();
  854. }
  855.  
  856. /****************************************************************************
  857. *    set_frame ()                                                            *
  858. *    Select the next logical frame in two-up or four-up mode.  If it is        *
  859. *    the first frame of a physical page, the generate the %%Page                *
  860. ****************************************************************************/
  861.  
  862. set_frame ()
  863. {
  864.     if (frame == 0  ||  bookwork)
  865.     {
  866.         if (book)        /*    mark byte position of %%Page: for psd  */
  867.         {    pg_loc[npg_loc++] = ftell (output_fp);
  868.         }
  869.         fprintf (output_fp, "%%%%Page: ? %d\n", ++physical_page);
  870.         if (bookwork == 0)                    /* psd will re-insert these */
  871.         {    fprintf (output_fp, "/pg save def\n");
  872.             if (landscape)
  873.                 fprintf (output_fp, "90 rotate 0 %d translate\n", -real_width);
  874.             fprintf (output_fp, "%.5f %.5f scale\n", scale_x, scale_y);
  875.         }
  876.         findfont();
  877.     }
  878.     set_y_coord ();
  879.  
  880.     if (max_frame > 1  &&  bookwork == 0)
  881.         fprintf (output_fp, "%d %d translate\n", dx_home[frame], dy_home[frame]);
  882.  
  883.     if (frame == 0  &&  cross)
  884.         draw_cross();
  885.  
  886. }
  887.  
  888.  
  889. /****************************************************************************
  890. *    set_y_coord                                                                *
  891. *    position next line to the top of a logical page.                        *
  892. *****************************************************************************/
  893.  
  894. set_y_coord ()
  895. {
  896.     y_coord = p->height - y_top_offset - point_size;
  897. }
  898.  
  899. /****************************************************************************
  900. *    put_top                                                                    *
  901. *    put a header line at the top of the page                                *
  902. *****************************************************************************/
  903.  
  904. put_top ()
  905. {
  906.     int    save_attr, save_point;
  907.     
  908.     save_attr = print_attribute;
  909.     save_point = point_size;
  910.     print_attribute = BOLD;
  911.     point_size = 12;
  912.     
  913.     findfont();
  914.     moveto (0, y_coord, 1);
  915.     if (header == 1)
  916.         fprintf (output_fp, "(%-40s %3d     %s)show\n", fname, page_number + 1, now);
  917.     else
  918.         fprintf (output_fp, "(%-40s %3d     %s)show\n", header_text, page_number + 1, now);
  919.     y_coord -= point_size * 2;
  920.     x_coord = 0;
  921.     print_attribute = save_attr;
  922.     point_size = save_point;
  923.     findfont();
  924. }
  925.  
  926. /****************************************************************************
  927. *    process_file()                                                            *
  928. *    Read the file, look for escape sequences, put text in postscript form    *
  929. ****************************************************************************/
  930.  
  931. process_file ()
  932. {
  933.     int        char_type, char_count, i, set_page, esc_type;
  934.     char    *strchr ();
  935.     int        previous_attribute;
  936.     int        lcount = 0;
  937.     
  938.     set_page = 0;
  939.     while (fgets (line, LONG_STR, input_fp) != NULL)
  940.     {
  941.         if (lcount++ == 0)
  942.         {    if ((i = tscan (line, "ta=")) >= 0)
  943.             {    tab_size = atoi (line + i + 3);
  944.             }
  945.             /*    we could also test here to see if the file is already
  946.                 in postscript format and simply copy out the file
  947.                 to stdout - however, we couldn't print postscript source.
  948.                 By choice, detection of postscript is left to "psdetect"
  949.                 in the back-end spooler.
  950.                
  951.                 e.g.   print postscript source with:
  952.                 
  953.                         psf thisfile.ps | lp
  954.                 
  955.                 will work even if psf is working in the print spooler.
  956.             */
  957.         }
  958.         if ((c = (unsigned char *) strchr (line, '\f')) != NULL)
  959.         {
  960.             if (c == line)
  961.             {    line_number = 32000;
  962.                 c = line + 1;
  963.             }
  964.             else
  965.             {    *c = 0;
  966.                 set_page = 1;
  967.                 c = line;
  968.             }
  969.         }
  970.         else
  971.             c = line;
  972.  
  973.         if (line_number >= lines_on_page * 10)
  974.         {    page_number++;
  975.             showpage (0);
  976.             line_number = 10;
  977.             if (header)
  978.             {
  979.                 put_top();
  980.                 line_number += 20;
  981.             }
  982.         }
  983.         else
  984.             line_number += 10;
  985.  
  986.         char_type = char_count = 0;
  987.  
  988.         /*    for empty lines, don't generate a real moveto - but to call
  989.             to ensure that check for page overflow is done.
  990.         */
  991.         if (*c == '\n')
  992.             moveto (x_coord, y_coord, 0);        /*    don't gen moveto    */
  993.         else
  994.             moveto (x_coord, y_coord, 1);        /*    do gen moveto        */
  995.  
  996.         while (*c  && *c != '\n')
  997.         {
  998.             if (char_type == 0)
  999.                 fputc ('(', output_fp);
  1000.                 
  1001.             switch ((int) *c)
  1002.             {
  1003.             case ESCAPE:
  1004.                 previous_attribute = print_attribute;
  1005.                 esc_type = *(++c);
  1006.                 if (escape_sequence (esc_type) == 0)
  1007.                 {
  1008.                     switch (esc_type)
  1009.                     {
  1010.                     case 'u':
  1011.                         SHOWU (output_fp, point_size);
  1012.                         break;
  1013.                     
  1014.  
  1015.                     default:
  1016.                         if (char_type  &&  (previous_attribute & UNDERLINE))
  1017.                             SHOWU (output_fp, point_size);
  1018. /*
  1019.                         else
  1020.                             if (c == line + 1  && (esc_type == '+'  || esc_type == '-'))
  1021.                                 ;
  1022. */
  1023.                         else
  1024.                             fputs (")show\n", output_fp);
  1025.  
  1026.                         if (esc_type == '+'  ||  esc_type == '-')
  1027.  
  1028.                         /*    check for +/- 1/2 line feed        */
  1029.                         
  1030.                         {
  1031.                             if (esc_type == '+')
  1032.                                 y_coord -= point_size / 2;
  1033.                             else
  1034.                                 y_coord += point_size / 2;
  1035.  
  1036.                             moveto (x_coord, y_coord, 1);
  1037.                             char_type = -1;
  1038.                             c++;
  1039.                             if (*c != '\n')
  1040.                                 fputc ('(', output_fp);
  1041.                             continue;
  1042.                         }
  1043.                         else
  1044.                             findfont (output_fp);
  1045.                     }
  1046.                     char_type = 0;
  1047.                 }
  1048.                 break;
  1049.                 
  1050.             default:
  1051.                 if (*c == '\t')
  1052.                 {
  1053.                     fputc (' ', output_fp);
  1054.                     while (++char_count % tab_size)
  1055.                         fputc (' ', output_fp);
  1056.                 }
  1057.                 else
  1058.                 {    if (strchr ("\r\b\\()", *c) != NULL)
  1059.                         fputc ('\\', output_fp);
  1060.                     fputc (*c, output_fp);
  1061.                     char_count++;
  1062.                 }
  1063.                 char_type = 1;
  1064.                 break;
  1065.             }
  1066.             c++;
  1067.         }
  1068.         if (char_type == 1)
  1069.         {    if (print_attribute & UNDERLINE)
  1070.                 SHOWU (output_fp, point_size);
  1071.             else
  1072.                 fputs (")show\n", output_fp);
  1073.         }
  1074.  
  1075.         y_coord -= point_size;
  1076.         x_coord = 0;
  1077.         if (set_page)
  1078.         {    line_number = 32000;
  1079.             set_page = 0;
  1080.         }
  1081.     }
  1082. }
  1083.  
  1084. /****************************************************************************
  1085. *    escape_sequence ()                                                        *
  1086. *    If an escape sequence (esc,char) is found, mark which type of font        *
  1087. ****************************************************************************/
  1088.  
  1089. int escape_sequence (which)
  1090. int    which;
  1091. {    unsigned char    s[10];
  1092.  
  1093.     switch (which)
  1094.     {
  1095.     case 'I':
  1096.         print_attribute |= ITALICS;
  1097.         break;
  1098.  
  1099.     case 'i':
  1100.         print_attribute &= ~ITALICS;
  1101.         break;
  1102.  
  1103.     case 'B':
  1104.         print_attribute |= BOLD;
  1105.         break;
  1106.  
  1107.     case 'b':
  1108.         print_attribute &= ~BOLD;
  1109.         break;
  1110.  
  1111.     case 'U':
  1112.         print_attribute |= UNDERLINE;
  1113.         break;
  1114.  
  1115.     case 'u':
  1116.         print_attribute &= ~UNDERLINE;
  1117.         break;
  1118.     
  1119.     case 'F':
  1120.         s[0] = *(++c);
  1121.         s[1] = '\0';
  1122.         font_number = atoi (s);        
  1123.         if (font_number > (NFONTS / 4))
  1124.             font_number = (NFONTS / 4) - 1;
  1125.         break;
  1126.     
  1127.     case 'f':
  1128.         font_number = default_font_number;
  1129.         break;
  1130.         
  1131.     case 'P':
  1132.         s[0] = *(++c);
  1133.         s[1] = *(++c);
  1134.         s[2] = '\0';
  1135.         point_size = atoi (s);
  1136.         break;
  1137.  
  1138.     case 'p':
  1139.         point_size = default_point_size;
  1140.         break;
  1141.  
  1142.     case '+':
  1143.     case '-':
  1144.         break;
  1145.     
  1146.     default:
  1147.         return (-1);
  1148.         ;
  1149.     }
  1150.     return (0);
  1151. }
  1152.  
  1153. /****************************************************************************
  1154. *    moveto ()                                                                *
  1155. *    Generate a postscript     x y moveto    statememt                        *
  1156. ****************************************************************************/
  1157.  
  1158. moveto (x, y, do_move)
  1159. int    x;
  1160. int    y;
  1161. int do_move;            /*    1 = gen moveto     0 = dont gen moveto    */
  1162. {
  1163.     /*    ensure that the current line can fit on the page - including the
  1164.         1/4 line needed for the decenders
  1165.     */
  1166.  
  1167.     if (line_number > lines_on_page * 10  ||  y < (p->bot_marg + point_size / 3))
  1168.     {
  1169.         showpage (0);
  1170.         if (header)
  1171.         {
  1172.             put_top();
  1173.             line_number += 20;
  1174.         }
  1175.         y = y_coord;
  1176.         x = x_coord;
  1177.     }
  1178.  
  1179.     if (do_move)
  1180.         fprintf (output_fp, "%d %d moveto\n", x + x_left_offset, y);
  1181. }
  1182.  
  1183. /****************************************************************************
  1184. *    findfont ()                                                                *
  1185. *    generate a findfont statement                                            *
  1186. ****************************************************************************/
  1187.  
  1188. findfont ()
  1189. {    int    this;
  1190.  
  1191.     /*    remove reference to UNDERLINE.  Underline is not a font.    */
  1192.     
  1193.     this = (font_number * 4) + (print_attribute & 0x03);
  1194.     fonts_used[this] = 1;
  1195.     fprintf (output_fp, "/%s findfont %d scalefont setfont\n", fonts[this], point_size);
  1196. }
  1197.  
  1198. /****************************************************************************
  1199. *    start_file ()                                                            *
  1200. *    Generate things that are appropriate for beginning of file processing    *
  1201. ****************************************************************************/
  1202.  
  1203. start_file ()
  1204. {
  1205.     line_number = 0;
  1206.     print_attribute = 0;
  1207.     page_number = 0;
  1208.     frame = -1;
  1209.     showpage (0);
  1210.     if (header)
  1211.     {
  1212.         put_top();
  1213.         line_number += 20;
  1214.     }
  1215. }
  1216.  
  1217. /****************************************************************************
  1218. *    terminate_file ()                                                        *
  1219. *    Generate things that are appropriate for end of file processing            *
  1220. ****************************************************************************/
  1221.  
  1222. terminate_file ()
  1223. {
  1224.     showpage (1);
  1225. }
  1226.  
  1227.  
  1228. /****************************************************************************
  1229. *    terminate_printer ()                                                    *
  1230. *    Generate things that are appropriate wrap-up after all files printed    *
  1231. *    For double sided printing (book == 1), generate byte offset info.        *
  1232. ****************************************************************************/
  1233.  
  1234. terminate_printer ()
  1235. {    int    i, used;
  1236.     long    psfptr;
  1237.     
  1238.     if (book)
  1239.     {    pg_loc[npg_loc++] = ftell (output_fp);
  1240.     }
  1241.     fprintf (output_fp, "%%%%Trailer\n");
  1242.     for (used = i = 0;  i < NFONTS;  i++)
  1243.     {    if (fonts_used[i])
  1244.         {    used = 1;
  1245.             break;
  1246.         }
  1247.     }
  1248.     if (used)
  1249.     {    fprintf (output_fp, "%%%%DocumentFonts:");
  1250.         for (i = 0;  i < NFONTS;  i ++)
  1251.         {    if (fonts_used[i])
  1252.                 fprintf (output_fp, " %s", fonts[i]);
  1253.         }
  1254.         fprintf (output_fp, "\n");
  1255.     }
  1256.             
  1257.     fprintf (output_fp, "%%%%Pages: %d\n", physical_page);
  1258.  
  1259.     if (book)            /*    print statistics for psd  */
  1260.     {
  1261.         psfptr = ftell (output_fp);
  1262.         fprintf (output_fp, "%%PsfScale: %.5f %.5f scale\n", scale_x, scale_y);
  1263.         fprintf (output_fp, "%%PsfMargin: %d %d %d %d %d\n", 
  1264.                         max_frame, landscape, real_width, p->height, p->width);
  1265.         for (i = 0;  i < 4;  i++)
  1266.             fprintf (output_fp, "%%PsfHome: %d %d %d\n",  i, dx_home[i], dy_home[i]);
  1267.         for (i = 0;  i < npg_loc-1;  i++)
  1268.             fprintf (output_fp, "%%PsfPg: %d %d\n",  i, pg_loc[i]);
  1269.         fprintf (output_fp, "%%PsfPg: 9999 %d\n", pg_loc[npg_loc-1]);
  1270.         fprintf (output_fp, "%%PsfPtr: %d\n", psfptr);
  1271.     }
  1272.     fprintf (output_fp, "%c", 0x04);        /* CTL/D = end job */
  1273. }
  1274.  
  1275. /****************************************************************************
  1276. *    draw_cross ()                                                            *
  1277. *    Draw horizontal and vertical separation lines between pages 4-up        *
  1278. ****************************************************************************/
  1279.  
  1280. draw_cross ()
  1281. {    int     p_w, p_h;
  1282.     
  1283.     if (max_frame == 4)
  1284.     {    p_w = p->width;
  1285.         p_h = p->height;
  1286.         fprintf (output_fp,"%d %d moveto\n", p_w, p_h);
  1287.         fprintf (output_fp,"%d %d lineto\n", p_w, -p_h);
  1288.         fprintf (output_fp,"%d %d moveto\n", 0, 0);
  1289.         fprintf (output_fp,"%d %d lineto\n", p_w * 2, 0);
  1290.         fprintf (output_fp,"%s\n", "stroke");
  1291.     }
  1292. }
  1293.  
  1294. /****************************************************************************
  1295. *    output_book ()                                                            *
  1296. *    Send file "double sided print" mode.  Used to make a "book".            *
  1297. *    Will pause the printer to ask for stack re-feed                            *
  1298. ****************************************************************************/
  1299.  
  1300. output_book ()
  1301. {
  1302. #ifdef HOPPER
  1303.     if (nslots > 1)
  1304.     {
  1305.         fflush (output_fp);
  1306.         fclose (output_fp);
  1307.         strcpy (line, BINDIR);
  1308.         if (*line)
  1309.             strcat (line, "/");
  1310.         strcat (line, "psd -3 1psbook2.d34");
  1311.         system (line);
  1312.         unlink ("1psbook2.d34");
  1313.     }
  1314. #endif
  1315. }
  1316.  
  1317. static char *usage_text[] =
  1318. {    "Usage: psf [-1|2|4] [-b n] [-c n] [-d] [-f n] [-g type ] [-h] [-H text]",
  1319.     "           [-i n]   [-l n] [-m n] [-n] [-p n] [-t n]     [-w] [-x] file...",
  1320.     "where:",
  1321.     "   -1|2|4  print 1,2,4 up (default=1)",
  1322.     "   -b n    paper bin n",
  1323.     "   -c n    print columns",
  1324.     "   -d      double sided",
  1325.     "   -f n    font number (def=0:Courier)",
  1326.     "   -g type letter legal a4 b5",
  1327.     "   -h      file name header",
  1328.     "   -H text text header",
  1329.     "   -i n    indent left margin points",
  1330.     "   -l n    print lines per page",
  1331.     "   -L n    lines per page",
  1332.     "   -m n    top margin points",
  1333.     "   -n      portrait (narrow) format",
  1334.     "   -p n    point size n",
  1335.     "   -t n    tabs to n (default=8)",
  1336.     "   -w      landscape (wide) format",
  1337.     "   -x      draw cross (4-up page)",
  1338.     "   file..  name of files (or stdin)",
  1339.     "   output: stdout",
  1340.     ""
  1341. } ;
  1342.     
  1343. usage ()
  1344. {    int        i, many, n, ff;
  1345.  
  1346.     for (i = 0;  i < 3; i++)
  1347.         fprintf (stderr, "%s\n", usage_text[i]);
  1348.  
  1349.     many = sizeof (usage_text)/sizeof (char *) - 3;
  1350.     
  1351.     for (i = 0;  i < many/2;  i++)
  1352.         fprintf (stderr, "%-38s %-38s\n", usage_text[i+3], usage_text[i+many/2+3]);
  1353.  
  1354.     fprintf (stderr,"Fonts selection with -f n (number or name)\n");
  1355.     many = 0;
  1356.     for (i = 0;  i < NFONTS/4;  i++)
  1357.     {    if (fonts_have[i*4])
  1358.         {    fprintf (stderr, "%2d %-18s", i, fonts[i*4]);
  1359.             many++;
  1360.             if ((ff = many % 3)  == 0)
  1361.                 fprintf (stderr, "\n");
  1362.         }
  1363.     }
  1364.     if (ff)
  1365.         fprintf (stderr, "\n");
  1366.  
  1367.     fprintf (stderr, "Paper type/size selection with -g type\n");
  1368.     many = 0;
  1369.     for (i = 0;  page_types[i].paper_name[0] != '\0';  i++)
  1370.     {    n = strlen (page_types[i].paper_name);
  1371.         if (many + n > 75)
  1372.         {    many = 0;
  1373.             fprintf (stderr,"\n");
  1374.             ff = 0;
  1375.         }
  1376.         else ff = 1;
  1377.         many += n + 3;
  1378.         fprintf (stderr,"   %s", page_types[i].paper_name);
  1379.     }    
  1380.     if (ff)
  1381.         fprintf (stderr, "\n");
  1382.     exit (0);
  1383. }
  1384.  
  1385. /************************************************
  1386. *        tscan (s,t)                                *
  1387. *        char    s[],t[];                        *
  1388. *                                                *
  1389. *    Index function as defined in K&R            *
  1390. *    Look for string t in s                        *
  1391. *                                                *
  1392. *    return -1 if t does not exits in s            *
  1393. *    else return array position of first            *
  1394. *    character match                                *
  1395. ************************************************/
  1396.  
  1397.  
  1398. tscan (s, t)
  1399. char     s[], t[];
  1400. {
  1401.     int    i, j, k;
  1402.     for (i = 0;  s[i] != '\0';  i++)
  1403.     {    for (j = i, k=0;  t[k] != '\0'  &&  s[j] == t[k];  j++, k++)
  1404.             ;
  1405.         if (t[k] == '\0')
  1406.             return (i);
  1407.     }
  1408.     return (-1);
  1409. }
  1410.  
  1411. get_time (t)
  1412. char    *t;
  1413. {
  1414.     long    n_time, time ();
  1415.     char    *x_time, *cc, *strchr();
  1416.     
  1417.     n_time = time (0);            /* get time */
  1418.     x_time = ctime (&n_time);    /* convert ascii */
  1419.     if ((cc = strchr (x_time, '\n')) != NULL)
  1420.         *cc = '\0';
  1421.     strcpy (t, x_time);
  1422. }
  1423.  
  1424. compare (a,b)
  1425. char    *a, *b;
  1426. {    int    aa, bb;
  1427.  
  1428.     while (*a  &&  *b)
  1429.     {    aa = *a++;
  1430.         bb = *b++;
  1431.         if (toupper (aa)  !=  toupper (bb))
  1432.             return (aa - bb);
  1433.     }
  1434.     return (0);
  1435. }
  1436.  
  1437. comp (a,b)
  1438. char    *a, *b;
  1439. {    int    aa, bb;
  1440.  
  1441.     while (*a  &&  *b)
  1442.     {    aa = *a++;
  1443.         bb = *b++;
  1444.         if (toupper (aa)  !=  toupper (bb))
  1445.             return (aa - bb);
  1446.     }
  1447.     if (*a == '\0'   &&  *b == '\n')
  1448.         return (0);
  1449.     return (*a - *b);
  1450. }
  1451.  
  1452. trim (s)
  1453. char    *s;
  1454. {
  1455.     while (*s)
  1456.     {    if (*s < ' ')
  1457.         {    *s = 0;
  1458.             break;
  1459.         }
  1460.         s++;
  1461.     }
  1462. }
  1463.  
  1464. bad_file()
  1465. {
  1466.     fprintf (stderr, "Bad %s file\n", PDEF);
  1467.     exit (1);
  1468. }
  1469.