home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / LASER / PCLASER.ZIP / PCLASER.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1990-11-27  |  46.1 KB  |  1,314 lines

  1. {$A+,B-,D+,E+,F-,I+,L+,N-,O-,R-,S+,V+}
  2. {$M 16384,25000,655360}
  3.  
  4. { PCLASER.PAS
  5.   Utility to print ASCII text files to LaserJet Series II, IIp or II
  6.   either side-by-side with 4 66-line, 80-column pages per sheet of paper,
  7.   2 66-line, 170-column pages per sheet of paper, or in 5.5 x 8.5-inch
  8.   booklet form with 4 pages per sheet of paper.  This program combines
  9.   two of the PC Magazine utilities, the PCBOOK utility written by Jay Munro
  10.   and the LASERLST utility written by Michael Holmes and Bob Flanders.
  11.  
  12.   PCBook and LaserLst : Copyright 1989/1990 PC Magazine - Ziff Davis -
  13.                         Jay Munro, Michael Holmes and Bob Flanders
  14.   =====================================================================
  15.   LaserJet programming concepts employed:
  16.          Setting orientation & font style
  17.          Locating LaserJet cursor
  18.          LaserJet Macro setup and use
  19.   =====================================================================
  20.   General programming concepts
  21.          Building index arrays
  22.          Using files for printing
  23.   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  24.   This program was based on the PCBook utility originally written by Jay
  25.   Munro in QuickBASIC.  Since I had Turbo Pascal and not QuickBASIC, it
  26.   was necessary to translate the program into TP before I could make any
  27.   changes.  As far as I'm concerned, Jay, et. al. and ZD still own their
  28.   original copyrights.  The resulting TP code is smaller and likely faster
  29.   than the original QB code.  The code to produce output like in PCBook
  30.   and that as in LaserLst was so similar, it was far easier to combine the
  31.   programs into one and give the user the option of changing the format
  32.   from side-by-side printing to booklet format, as necessary.
  33.  
  34.   Changes made:
  35.     1.  Converted to Turbo Pascal.  While the TP source code is longer, the
  36.         compiled code is about 1/3 the size of the QuickBasic code.  Some
  37.         things were speeded up in the conversion.
  38.     2.  Modified the page header to show file creation date and time instead
  39.         of the current date.  I'd rather know the version date of the file
  40.         than the date I printed its contents.
  41.     3.  Page header is underlined.
  42.     4.  Multiple files may be specified with wildcards.  Each file is
  43.         completely printed - front and back - before starting the next file.
  44.     5.  Optionally print front or back sides only.  By combining this feature
  45.         with the alternate output file, you could make multiple copies of
  46.         a file by sending the front pages to one file, the back pages to
  47.         another file and then copying it to the printer as many times as
  48.         needed since all the printer escape sequences are in both files.
  49.     6.  Prompt for user-defined heading.
  50.     7.  Program modified to print side-by-side or in booklet form.
  51.     8.  The program now scans each command line parameter from left to right
  52.         and takes action accordingly.  The switches are now toggle their
  53.         option, and some of them are specified as defaults.  Specifying a
  54.         default switch the second time turns the option off.
  55.     9.  Combined LaserLst-type and PCBook-type formats into one program.
  56.    10.  Added the ability to print wide reports, i.e., > 80 column reports
  57.         with one page on the front of the sheet and the next page on the back.
  58.    11.  Added the ability to print a selected range of pages in the file.
  59.         This is useful when the software that generated the file put a
  60.         leading and/or trailing formfeeds in the file, causing blank pages
  61.         to be generated.  This also allows you to just print a selected
  62.         portion of a large file, assuming you don't need the whole thing.
  63.  
  64.   The TP version of PCBOOK doesn't implement all the error recovery that was
  65.   found in the QB version.  The main reason is that when a critical error
  66.   occurs, such as the printer being out of paper, there is no way to resume
  67.   where the program left off once the error condition is fixed.  The user
  68.   will have to put up with DOS's error handling unless they know of a way
  69.   to handle this.  Using an exit proc will tell you what error occurred and
  70.   the address of the line where the error occurred, but will not let you
  71.   resume execution -- at least I haven't figured out how, anyway....
  72.  
  73.   These changes were made by Bob White.  Much of the code is the TP trans-
  74.   lation of the QB code written by Jay Munro. }
  75.  
  76. { *************************************************************************** }
  77.  
  78. Program PCLASER;
  79.  
  80.   uses
  81.     Dos, Crt;
  82.  
  83.   const
  84.     Esc                     : Char = #27;   { Escape character }
  85.     CR                      : Char = #13;   { Carriage return character }
  86.     FF                      : Char = #12;   { Formfeed character }
  87.     LF                      : Char = #10;   { Linefeed character }
  88.     MaximumBufferSize       = 16384;        { Maximum buffer size }
  89.     MaximumPages            = 513;          { Maximum pages + 1 }
  90.     MaximumLineLength       = 180;          { The width of each page }
  91.     MaximumPageLength       = 66;           { Number of lines per page }
  92.     WideLineLength          = 170;          { For wide output }
  93.     NarrowLineLength        = 80;           { For narrow output or booklet }
  94.  
  95.   type
  96.     KeyType        = ( Escape, Carriage_Return, Other );
  97.     Flags          = record
  98.                        FileDate  : Boolean;
  99.                        DoHeader  : Boolean;
  100.                        FileTitle : Boolean;
  101.                        LineLen   : Integer;
  102.                        LineWrap  : Boolean;
  103.                        PgNumber  : Boolean;
  104.                        UserTitle : Boolean;
  105.                      end;
  106.  
  107.     BufType        = Array[1..MaximumBufferSize] of Char;
  108.     BufPtr         = ^BufType;
  109.     PtrArrayType   = Array[1..MaximumPages] of LongInt;
  110.     CommandPtr     = ^ComStr;
  111.     DateString     = String[17];
  112.     TitleType      = String[MaximumLineLength];
  113.  
  114.   var
  115.     Actual_Pages    : Integer;          { Actual pages in file }
  116.     AlternateFile   : Boolean;          { Allow output to alternate file }
  117.     Booklet         : Boolean;          { Booklet or side-by-side flag }
  118.     Buffer          : BufPtr;           { Pointer to the input buffer }
  119.     Commandline     : CommandPtr;       { Pointer to the DOS command line }
  120.     CreationDate    : DateString;       { The date the file was created }
  121.     DirInfo         : SearchRec;        { Buffer for FindFirst/FindNext }
  122.     FExt            : ExtStr;           { Used to get heading filename }
  123.     Filename        : PathStr;          { The individual filename }
  124.     FName           : NameStr;          { Used to get heading filename }
  125.     FPath           : DirStr;           { Used to get heading filename }
  126.     HeadingFilename : String[12];       { Filename to be used in heading }
  127.     InFile          : File;             { The input file }
  128.     I               : Integer;          { An index, used several times }
  129.     JustCount       : Boolean;          { Just count, optionally print }
  130.     OutFile         : Text;             { The output file }
  131.     OutputDest      : PathStr;          { The output destination, ie, LPT1 }
  132.     Page            : Integer;          { The number of pages in the file }
  133.     Parameter       : String;           { A command line parameter }
  134.     PathName        : PathStr;          { The user-supplied filename }
  135.     PC              : Flags;            { Various state flags }
  136.     PrintBack       : Boolean;          { Print the back side of the page? }
  137.     PrintFront      : Boolean;          { Print the front side of the page? }
  138.     PtrArray        : PtrArrayType;     { Array of page pointers }
  139.     Quit            : Boolean;          { True if escape pressed during print }
  140.     Selected_Pages  : Boolean;          { Print a range of pages }
  141.     Sheets          : Integer;          { Physical sheets of paper required }
  142.     Success         : Boolean;          { True if output file opened okay }
  143.     Temp            : PathStr;          { Buffer for alternate file name }
  144.     Title           : TitleType;        { User defined title in heading }
  145.     Tune            : Boolean;          { Do we beep or not? }
  146.     Wide            : Boolean;          { Printing 132-column file }
  147.  
  148. { *************************************************************************** }
  149.  
  150. { This function scans the input buffer to find the first occurrence of a
  151.   specific character.  This function was written in Turbo Assembler for
  152.   speed, although the buffer may be scanned with a loop and comparing each
  153.   character in the buffer to see if it's the character being searched for. }
  154.  
  155.   Function FindPos( var Buffer;
  156.                     Offset : Integer;
  157.                     MaxSize : Integer;
  158.                     Character : Char ) : Integer; External;
  159.  
  160.   {$L FINDPOS.OBJ}
  161.  
  162. { *************************************************************************** }
  163.  
  164. { Scan the command line, making sure the switches are preceeded by a blank.
  165.   This allows TP to break them out with the ParamCount and ParamStr routines. }
  166.  
  167.   Procedure Parse_Command_Line;
  168.  
  169.   var
  170.     I               : Integer;          { Index to command line characters }
  171.     Commandline     : CommandPtr;       { Pointer to the DOS command line }
  172.     Prev_Char       : Char;             { Previous character in command line }
  173.  
  174.   begin
  175.  
  176.     CommandLine := Ptr( PrefixSeg, $80 );
  177.     I := 1;
  178.     Prev_Char := ' ';
  179.  
  180.     Repeat
  181.       CommandLine^[I] := Upcase( CommandLine^[I] );
  182.       If (CommandLine^[I] = '/') and (Prev_Char <> ' ') then
  183.         begin
  184.           Insert( ' ', CommandLine^, I );
  185.           Inc( I );
  186.         end;
  187.       Prev_Char := CommandLine^[I];
  188.       Inc( I );
  189.     Until I > Length( CommandLine^ );
  190.  
  191.   end;
  192.  
  193. { *************************************************************************** }
  194.  
  195. { This procedure scans the input file and builds the array of pointers to
  196.   where each page will begin and end, which are returned in PTRARRAY.  The
  197.   array consists of byte pointers - the byte position in the file - of the
  198.   first character on each page.  When the program starts printing, it uses
  199.   SEEK to position to the appropriate character and reads everything up to
  200.   the start of the next page, and then prints everything it read. }
  201.  
  202.   Procedure BuildArray( var PtrArray : PtrArrayType;
  203.                         var PgCount  : Integer );
  204.  
  205.     var
  206.       Offset       : LongInt;
  207.       TotalSize    : LongInt;
  208.       FileLeft     : LongInt;
  209.       BufSize      : Integer;
  210.       BufUsed      : Integer;
  211.       LnCount      : Integer;
  212.       StPtr        : Integer;
  213.       TempLn       : Integer;
  214.       TempPg       : Integer;
  215.  
  216.     label
  217.       GetPage, PageCheck, PageBreak, EndBuild;
  218.  
  219.     begin
  220.       Offset   := 0;
  221.  
  222.       TotalSize := Filesize( InFile );           { Get the size of the file }
  223.       FileLeft  := TotalSize;
  224.  
  225.       If MemAvail < 2048 then
  226.         begin
  227.           Writeln( '** Less than 2K memory available - not enough to run **');
  228.           Halt;
  229.         end;
  230.  
  231. { Define the buffer size as either the 16K bytes (the currently-defined
  232.   maximum buffer size) or the available memory, whichever is larger, or
  233.   the file size, if it is less than 16K. }
  234.  
  235.       If TotalSize > MaximumBufferSize then
  236.         begin
  237.           If MemAvail > MaximumBufferSize then
  238.             BufSize := MaximumBufferSize
  239.            else
  240.             BufSize := MemAvail;
  241.         end
  242.        else
  243.         If TotalSize < MemAvail then
  244.           BufSize := TotalSize;
  245.  
  246.       GetMem( Buffer, BufSize );               { Allocate the input buffer }
  247.  
  248.       PgCount := 1;
  249.       PtrArray[ PgCount ] := 0;                { First page = start of file }
  250.       LnCount := 0;
  251.  
  252. GetPage:
  253.  
  254.       BufUsed := BufSize;
  255.       If FileLeft < BufSize then
  256.         BufUsed := FileLeft;
  257.  
  258.       BlockRead( InFile, Buffer^, BufUsed );     { Get a buffer full }
  259.  
  260.       StPtr := 1;
  261.       TempPg := 0;
  262.  
  263. PageCheck:
  264.  
  265. { Here, we're looking to see if a linefeed occurs before or after the next
  266.   formfeed.  For the sake of speed, the buffer is only scanned for formfeeds
  267.   whenever a new buffer is read or there was a formfeed in the buffer before.
  268.   The original QuickBasic code scanned for both a linefeed and a formfeed
  269.   each pass through - i.e., after each line.  If the buffer doesn't contain
  270.   a formfeed in it, the program wastes a lot of time scanning it for formfeeds
  271.   after the first line.  Checking it on the first pass after reading a new
  272.   buffer and subsequently only if a formfeed was found on the first pass
  273.   through saves quite a bit of time.... }
  274.  
  275.       TempLn := FindPos( Buffer^, StPtr-1, BufUsed, LF );
  276.  
  277.       If (StPtr = 1) or (TempPg <> 0 ) then
  278.         TempPg := FindPos( Buffer^, StPtr-1, BufUsed, FF );
  279.  
  280. { We found a formfeed in the input file. }
  281.  
  282.       If TempPg > 0 then
  283.         If ( TempPg < TempLn ) or ( TempLn = 0 ) then
  284.           begin
  285.             Inc( PgCount );
  286.             PtrArray[ PgCount ] := Offset + TempPg;
  287.             StPtr := TempPg + 1;
  288.             LnCount := 0;
  289.             If StPtr < BufUsed then Goto PageCheck;
  290.           end;
  291.  
  292. { There was no formfeed, but there was a linefeed.. }
  293.  
  294.       If TempLn > 0 then
  295.         begin
  296.  
  297.           If PC.LineWrap then
  298.             If ( TempLn - StPtr ) > PC.LineLen then
  299.               While ( TempLn - StPtr ) > PC.LineLen do
  300.                 begin
  301.                   Inc( LnCount );
  302.                   If LnCount = MaximumPageLength then Goto PageBreak;
  303.                   StPtr := StPtr + PC.LineLen;
  304.                 end;
  305.  
  306.           Inc( LnCount );
  307.  
  308. PageBreak:
  309.  
  310. { When there are no formfeeds in the file to make the pages break, use
  311.   MaximumPageLength as the maximum number of printed lines per page.
  312.   Currently, this is defined as 66 lines per page.  }
  313.  
  314.           If LnCount = MaximumPageLength then
  315.             begin
  316.               Inc( PgCount );
  317.               If PgCount = MaximumPages then
  318.                 begin
  319.                   Writeln('Too many pages - printing first ',MaximumPages-1);
  320.                   Goto EndBuild;
  321.                 end;
  322.               PtrArray[ PgCount ] := Offset + TempLn;
  323.               LnCount := 0;
  324.             end;
  325.  
  326.           StPtr := TempLn + 1;
  327.  
  328. { If there's more characters in the buffer, go scan them... }
  329.  
  330.           If StPtr <= BufUsed then Goto PageCheck;
  331.  
  332.         end;
  333.  
  334. { We've looked at this buffer - if there's more characters in the file, go
  335.   back and get the next buffer full. }
  336.  
  337.       Offset := Offset + BufUsed;
  338.       StPtr := 1;
  339.       FileLeft := TotalSize - Offset;
  340.  
  341.       If Offset < TotalSize then
  342.         Goto Getpage;
  343.  
  344. EndBuild:
  345.  
  346. { We've finished scanning the file.  Store the total size as the last page
  347.   size. }
  348.  
  349.       PtrArray[ PgCount+1 ] := TotalSize;
  350.       Freemem( Buffer, BufSize );                { Deallocate the buffer }
  351.  
  352.     end;
  353.  
  354. { *************************************************************************** }
  355.  
  356.   Procedure DoMacro( MacroNumber : String );
  357.     begin
  358.       Write( OutFile, Esc+'&f'+MacroNumber+'y2X'); { Execute the macro }
  359.     end;
  360.  
  361. { *************************************************************************** }
  362.  
  363.   Procedure StartMacro( MacroNumber : String );
  364.     begin
  365.       Write( OutFile, Esc+'&f'+MacroNumber+'Y');   {Define macro name}
  366.       Write( OutFile, Esc+'&f0X');                 {Macro starts now}
  367.     end;
  368.  
  369. { *************************************************************************** }
  370.  
  371.   Procedure EndMacro( MacroNumber : String );
  372.     begin
  373.       Write( OutFile, Esc+'&f'+MacroNumber+'y1X');  {End of macro command}
  374.       Write( OutFile, Esc+'&f'+MacroNumber+'y9X');  {Make it temp (10=perm)}
  375.     end;
  376.  
  377. { *************************************************************************** }
  378.  
  379.   Procedure Header( Page : Integer );
  380.     var
  381.       Heading      : String;
  382.       Temp         : String;
  383.       I            : Integer;
  384.  
  385.     begin
  386.       Heading[0] := Char( PC.LineLen );
  387.       FillChar( Heading[1], PC.LineLen, ' ');
  388.  
  389.       If PC.FileTitle then
  390.         begin
  391.           I := (PC.LineLen div 2) - (Length(HeadingFilename) div 2);
  392.           Move( HeadingFilename[1], Heading[I], Length( HeadingFilename ) );
  393.         end;
  394.  
  395.       If PC.UserTitle then
  396.         begin
  397.           If (Page mod 2) <> 0 then
  398.             I := 1                                  { Odd page, Left side }
  399.            else
  400.             I := PC.LineLen-Length(Title)+1;        { Even page, right side }
  401.           Move( Title[1], Heading[I], Length(Title) );
  402.         end;
  403.  
  404.       If PC.PgNumber then
  405.         begin
  406.           Str( Page, Temp );
  407.           Insert( 'Page ', Temp, 1 );
  408.           If (Page mod 2) <> 0 then
  409.             I := PC.LineLen - Length( Temp ) + 1    { Odd page, right side }
  410.            else
  411.             I := 1;                                 { Even page, left side }
  412.           Move( Temp[1], Heading[I], Length(Temp) );
  413.         end;
  414.  
  415.       If PC.FileDate then
  416.         begin
  417.           If (Page mod 2) <> 0 then
  418.             I := 1                                    { Odd page, Left side }
  419.            else
  420.             I := PC.LineLen-Length(CreationDate)+1;   { Even page, right side }
  421.           Move( CreationDate[1], Heading[I], Length(CreationDate) );
  422.         end;
  423.  
  424.       Writeln( OutFile, Esc+'&dD',Heading, Esc+'&d@' );
  425.       Writeln( OutFile );
  426.     end;
  427.  
  428. { *************************************************************************** }
  429.  
  430.   Procedure LJLocate( X, Y : Integer );
  431.     begin
  432.       Write( OutFile, Esc+'&a',Y,'r',X,'C');  { Move LaserJet cursor to X,Y }
  433.     end;
  434.  
  435. { *************************************************************************** }
  436.  
  437. { Set up the LaserJet for the LaserLst-type output where the first page is
  438.   to the left of the next page. }
  439.  
  440.   Procedure Side_by_Side_PrintSetup;
  441.     var
  442.       I : Integer;
  443.  
  444.     begin
  445.       Write( OutFile, Esc+'E' );              { Reset the LaserJet }
  446.       Write( OutFile, Esc+'&l1o5.15C');       { Select Landscape and }
  447.       Write( OutFile, Esc+'(s0p17H');         { Lineprinter pitch and font }
  448.       Write( OutFile, Esc+'&l0L');            { No pagefeed after 66 lines }
  449.       Write( OutFile, Esc+'(s-3B');           { Light stroke weight }
  450.  
  451.       If PC.LineWrap then
  452.         Write( OutFile, Esc+'&s0C');          { Wrap lines if selected }
  453.  
  454.       Write( OutFile, Esc+'&l6E');            { Top margin 6 lines }
  455.  
  456.       StartMacro( '1' );                      { Left side macro }
  457.         Write( OutFile, Esc+'9' );              { Reset left & right margins }
  458.         Write( OutFile, Esc+'&a5l85M');         { Left margin 5, right 85 }
  459.       EndMacro( '1' );                        { end of macro }
  460.  
  461.       StartMacro( '2' );                      { Right side macro }
  462.         Write( OutFile, Esc+'9' );              { Reset left & right margins }
  463.         Write( OutFile, Esc+'&a91l171M');       { Left margin 91, right 171 }
  464.       EndMacro( '2' );                        { end of macro }
  465.  
  466.       StartMacro( '3' );                      { Divider bar macro }
  467.         Write( OutFile, Esc+'9' );              { Reset the margins }
  468.         Write( OutFile, Esc+'&a88l90M');        { Left margin 88, right 90 }
  469.         I := 0;
  470.         If PC.DoHeader then                     { Row depends on heading }
  471.           I := 2;                               { Goto row 2 }
  472.         LJLocate( 88, I );                      { Goto row I, column 88 }
  473.         For I := 1 to MaximumPageLength do
  474.           Writeln( Outfile, '|' );              { Write out the vert. bars }
  475.       EndMacro( '3' );                        { end of macro }
  476.  
  477.     end;
  478.  
  479. { *************************************************************************** }
  480.  
  481. { Set up the LaserJet for the 2 pages per sheet format }
  482.  
  483.   Procedure Front_and_Back_PrintSetup;
  484.  
  485.     begin
  486.       Write( OutFile, Esc+'E' );              { Reset the LaserJet }
  487.       Write( OutFile, Esc+'&l1o5.15C');       { Select Landscape and }
  488.       Write( OutFile, Esc+'(s0p17H');         { Lineprinter pitch and font }
  489.       Write( OutFile, Esc+'&l0L');            { No pagefeed after 66 lines }
  490.       Write( OutFile, Esc+'(s-3B');           { Light stroke weight }
  491.  
  492.       If PC.LineWrap then
  493.         Write( OutFile, Esc+'&s0C');          { Wrap lines if selected }
  494.  
  495.       Write( OutFile, Esc+'&l6E');            { Top margin 2 lines }
  496.  
  497.       StartMacro( '1' );                      { Left side macro }
  498.         Write( OutFile, Esc+'9' );              { Reset left & right margins }
  499.         Write( OutFile, Esc+'&a5l191M');       { Left margin 10, right 191 }
  500.       EndMacro( '1' );                        { end of macro }
  501.  
  502.     end;
  503.  
  504. { *************************************************************************** }
  505.  
  506. { Set up the LaserJet for the PCBook format - booklet format with 4 pages
  507.   per sheet. }
  508.  
  509.   Procedure Booklet_PrintSetup;
  510.     begin
  511.       Write( OutFile, Esc+'E' );              { Reset the LaserJet }
  512.       Write( OutFile, Esc+'&l1o5.45C');       { Select Landscape and }
  513.       Write( OutFile, Esc+'(s0p16.66H');      { Lineprinter pitch and font }
  514.       Write( OutFile, Esc+'&l0L');            { No pagefeed after 66 lines }
  515.  
  516.       If PC.LineWrap then
  517.         Write( OutFile, Esc+'&s0C');          { Wrap lines if selected }
  518.  
  519.       Write( OutFile, Esc+'&l2E');            { Top margin 2 lines }
  520.  
  521.       StartMacro( '1' );                      { Left side macro }
  522.         Write( OutFile, Esc+'9' );              { Reset left & right margins }
  523.         Write( OutFile, Esc+'&a0l80M');         { Left margin 0, right 80 }
  524.       EndMacro( '1' );                        { end of macro }
  525.  
  526.       StartMacro( '2' );                      { Right side macro }
  527.         Write( OutFile, Esc+'9' );              { Reset left & right margins }
  528.         Write( OutFile, Esc+'&a95l175M');       { Left margin 95, right 175 }
  529.       EndMacro( '2' );                        { end of macro }
  530.  
  531.     end;
  532.  
  533. { *************************************************************************** }
  534.  
  535.   Procedure Beep;
  536.     begin
  537.       Write( #7 );                            { Beep! }
  538.     end;
  539.  
  540. { *************************************************************************** }
  541.  
  542.   Procedure PrintLogo;
  543.     var
  544.       I : Integer;
  545.     begin
  546.       ClrScr;
  547.       For I := 1 to 79 do Write('=');
  548.       Writeln;
  549.       Writeln('PCLaser - LaserJet Printing Utility');
  550.       Writeln('Copyright 1990 - Bob White   11/25/90');
  551.       Writeln('PCBook/LaserLst copyright 1989/1990 PC Magazine -  Ziff Davis');
  552.       For I := 1 to 79 do Write('=');
  553.       Writeln;
  554.     end;
  555.  
  556. { *************************************************************************** }
  557.  
  558.   Procedure Help;
  559.     begin
  560.       ClrScr;
  561.       Writeln('Usage: PCLASER [filename] [/A] [/B] [/BACK] [/C] [/D] [/F] ',
  562.               '[/FRONT]');
  563.       Writeln('                          [/H] [/L] [/P] [/R] [/S] [/T] [/W] ',
  564.               '[/2]');
  565.       Writeln;
  566.       Writeln('  /A     - Prompts for alternate output file');
  567.       Writeln('  /B     - Print in booklet format.  Also /BOOK');
  568.       Writeln('  /BACK  - Only print the back side of the page');
  569.       Writeln('  /C     - Pauses after physical page count');
  570.       Writeln('* /D     - Prints the file revision date in each page heading');
  571.       Writeln('* /F     - Prints the filename in each page heading');
  572.       Writeln('  /FRONT - Only print the front side of the page');
  573.       Writeln('  /H     - This message.  Also /? or ?');
  574.       Writeln('  /L     - Print lineprinter reports (2 pages per sheet)');
  575.       Writeln('* /P     - Prints the page numbers in each page heading');
  576.       Writeln('  /R     - Print a range of pages');
  577.       Writeln('  /S     - Turns sound on');
  578.       Writeln('  /T     - Prompts for a user-defined title');
  579.       Writeln('  /W     - Turns on line wrap');
  580.       Writeln('  /2     - Prints to LPT2 instead of LPT1');
  581.       Writeln;
  582.       Writeln('Options marked with "*" are enabled by default and are ');
  583.       Writeln('disabled by specifying the option on the command line.');
  584.       Halt;
  585.     end;
  586.  
  587. { *************************************************************************** }
  588.  
  589. { Get a keypress, returning whether or not it is a carriage return, escape,
  590.   or other key hit. }
  591.  
  592.   Function Press_A_Key : KeyType;
  593.  
  594.     var
  595.       Keystroke : Char;
  596.  
  597.     begin
  598.       Repeat until Keypressed;                   { Wait for a keypress }
  599.       Keystroke := ReadKey;                      { Get return code }
  600.  
  601.       Press_A_Key := Other;                      { Some other key was hit }
  602.  
  603.       If Keystroke = #0 then
  604.         Keystroke := ReadKey                     { ESC isn't extended key }
  605.        else
  606.         Case Keystroke of
  607.           #27 : Press_A_Key := Escape;
  608.           #13 : Press_A_Key := Carriage_Return;
  609.          end;
  610.     end;
  611.  
  612. { *************************************************************************** }
  613.  
  614. { Get the last revision date of the file and convert it to ASCII }
  615.  
  616.   Function GetFileDate : DateString;
  617.  
  618.     var
  619.       Created          : LongInt;
  620.       DT               : DateTime;
  621.       Temp             : String[10];
  622.       Result           : DateString;
  623.  
  624.     begin
  625.       GetFTime( InFile, Created );
  626.       UnPackTime( Created, DT );
  627.       With DT do
  628.         begin
  629.           Month := Month + 100;     { Add 100 so STR puts a zero in }
  630.           Day   := Day   + 100;     { when the value is less than 10 }
  631.           Hour  := Hour  + 100;
  632.           Min   := Min   + 100;
  633.  
  634.           Str( Month:4, Temp );
  635.           Result := Copy( Temp, 3, 2 ) + '/';
  636.           Str( Day:4, Temp );
  637.           Result := Result + Copy( Temp, 3, 2 ) + '/';
  638.           Str( Year:4, Temp );
  639.           Result := Result + Temp + '  ';
  640.  
  641.           Str( Hour:4, Temp );
  642.           Result := Result + Copy( Temp, 3, 2 ) + ':';
  643.           Str( Min:4, Temp );
  644.           Result := Result + Copy( Temp, 3, 2 );
  645.         end;
  646.       GetFileDate := Result;
  647.     end;
  648.  
  649. { *************************************************************************** }
  650.  
  651.   Procedure Print_Page_Info;
  652.     begin
  653.       If not Wide then
  654.         begin
  655.           If Page mod 4 <> 0 then Page := Page + ( 4 - (Page mod 4) );
  656.           Sheets := Page div 4;
  657.         end
  658.        else
  659.         begin
  660.           If Page mod 2 <> 0 then Inc( Page );
  661.           Sheets := Page div 2;
  662.         end;
  663.  
  664.       Writeln;
  665.       Writeln( Filename, ' contains ',Actual_Pages,' actual pages and');
  666.       Writeln( '  will require ', Sheets,' sheet(s) of paper to print.');
  667.       Writeln;
  668.     end;
  669.  
  670. { *************************************************************************** }
  671.  
  672.   Procedure Select_Pages_To_Print;
  673.  
  674.     var
  675.       Starting_Page          : Integer;
  676.       Ending_Page            : Integer;
  677.       Buf                    : String;
  678.       Temp                   : Integer;
  679.       Code                   : Integer;
  680.       I,J                    : Integer;
  681.  
  682.     begin
  683.       Starting_Page := -1;
  684.       Ending_Page   := -1;
  685.  
  686.       Repeat
  687.         Write('Enter starting page number (1-',Actual_Pages,')  [1]  >>');
  688.         Readln( Buf );
  689.         If Buf <> '' then
  690.           begin
  691.             Val( Buf, Temp, Code );
  692.             If (Code = 0) and (Temp >= 1) and (Temp <= Actual_Pages) then
  693.               Starting_Page := Temp;
  694.           end
  695.          else
  696.           Starting_Page := 1;
  697.       Until Starting_Page >= 1;
  698.  
  699.       Repeat
  700.         Write('Enter ending page number (',Starting_Page,'-',Actual_Pages,
  701.               ')  [',Actual_Pages,']  >>');
  702.         Readln( Buf );
  703.         If Buf <> '' then
  704.           begin
  705.             Val( Buf, Temp, Code );
  706.             If (Code = 0) and (Temp >= Starting_Page) and
  707.                (Temp <= Actual_Pages) then
  708.               Ending_Page := Temp;
  709.           end
  710.          else
  711.           Ending_Page := Actual_Pages;
  712.       Until Ending_Page >= Starting_Page;
  713.  
  714.       J := 1;
  715.       For I := Starting_Page to Ending_Page + 1 do
  716.         begin
  717.           PtrArray[J] := PtrArray[I];
  718.           Inc( J );
  719.         end;
  720.  
  721.       For I := J to Page do
  722.         PtrArray[I] := 0;
  723.  
  724.       Page := Ending_Page - Starting_Page + 1;
  725.       Actual_Pages := Page;
  726.  
  727.       Print_Page_Info;
  728.  
  729.     end;
  730.  
  731. { *************************************************************************** }
  732.  
  733. { Print the left page if we're printing 4 pages per sheet, or either the
  734.   front or back when printing 2 pages per sheet }
  735.  
  736.   Procedure Print_Left_Side( LeftMargin : Integer;
  737.                              LeftSide   : Integer );
  738.  
  739.     var
  740.       BufNeed         : Integer;        { Buffer size needed for current page }
  741.       MaxPrint        : Integer;        { Maximum bytes to print }
  742.  
  743.     begin
  744.       DoMacro( '1' );
  745.       LJLocate( LeftMargin, 0 );
  746.  
  747.       If PC.DoHeader then Header( LeftSide );
  748.  
  749.       If LeftSide <> 0 then
  750.         begin
  751.           BufNeed := PtrArray[LeftSide+1] - PtrArray[LeftSide];
  752.           GetMem( Buffer, BufNeed );
  753.           Seek( InFile, PtrArray[LeftSide] );
  754.           BlockRead( Infile, Buffer^, BufNeed );
  755.           MaxPrint := BufNeed;
  756.  
  757.           If Buffer^[BufNeed] = FF then Dec( MaxPrint );
  758.           For I := 1 to MaxPrint do
  759.             Write( OutFile, Buffer^[I] );
  760.           FreeMem( Buffer, BufNeed );
  761.         end;
  762.     end;
  763.  
  764. { *************************************************************************** }
  765.  
  766. { Print the right page if printing 4 pages per sheet.  This routine is not
  767.   used for front and back output. }
  768.  
  769.   Procedure Print_Right_Side( LeftMargin : Integer;
  770.                               RightSide  : Integer );
  771.  
  772.     var
  773.       BufNeed         : Integer;        { Buffer size needed for current page }
  774.       MaxPrint        : Integer;        { Maximum bytes to print }
  775.  
  776.     begin
  777.       If not Booklet then DoMacro( '3' );       { Draw vertical line }
  778.       DoMacro( '2' );                           { Reset the margins }
  779.       LJLocate( LeftMargin, 0 );
  780.  
  781.       If PC.DoHeader then Header( RightSide );
  782.  
  783.       BufNeed := PtrArray[RightSide+1] - PtrArray[RightSide];
  784.       GetMem( Buffer, BufNeed );
  785.       Seek( InFile, PtrArray[RightSide] );
  786.       BlockRead( Infile, Buffer^, BufNeed );
  787.       MaxPrint := BufNeed;
  788.  
  789.       If Buffer^[BufNeed] = FF then Dec( MaxPrint );
  790.       For I := 1 to MaxPrint do
  791.         Write( OutFile, Buffer^[I] );
  792.       FreeMem( Buffer, BufNeed );
  793.     end;
  794.  
  795. { *************************************************************************** }
  796.  
  797. { Prompt them to reinsert the paper and either press return or escape.  Any
  798.   other characters are ignored }
  799.  
  800.   Procedure ReInsert_Paper( var Quit : Boolean;
  801.                             Pass     : Integer );
  802.  
  803.     var
  804.       Key : KeyType;
  805.  
  806.     begin
  807.       If (Pass = 1) and PrintBack and PrintFront then
  808.         begin
  809.           If Tune then Beep;
  810.           Writeln;
  811.           Writeln('Put the paper back in the tray');
  812.           Writeln('  and press ENTER to continue,');
  813.           Writeln('  or press ESC to stop printing.');
  814.           Repeat
  815.             Key := Press_A_Key;
  816.             Quit := Key = Escape;
  817.           Until (Key = Carriage_Return) or Quit;
  818.           Writeln;
  819.         end;
  820.     end;
  821.  
  822. { *************************************************************************** }
  823.  
  824. { This code prints the LaserLst-type output where page 1 is on the left, page
  825.   2 is on the right, page 3 is behind page 2, and page 4 is behind page 1. }
  826.  
  827.   Procedure Side_By_Side_Print;
  828.     var
  829.       CurrentSheet    : Integer;          { Current sheet being printed }
  830.       Pass            : Integer;          { The current pass number, 1 or 2 }
  831.       LeftSide        : Integer;          { The left page index }
  832.       RightSide       : Integer;          { The right page index }
  833.       BookMark        : Integer;          { Bookmark set to halfway through }
  834.       NumberofPasses  : Integer;          { Number of passes on printer }
  835.  
  836.     begin
  837.  
  838.       NumberofPasses := 2;
  839.       If not PrintFront then NumberofPasses := 1;
  840.  
  841.       Pass := 0;
  842.  
  843.       Repeat
  844.  
  845.         Inc( Pass );
  846.  
  847.         Bookmark := Page div 4;
  848.         If Bookmark = 0 then Bookmark := 1;
  849.  
  850.         If ( (Pass=1) and PrintBack  ) or
  851.            ( (Pass=2) and PrintFront ) then
  852.           Writeln('Printing side ',Pass,' to ',OutputDest );
  853.  
  854.         If Pass = 1 then
  855.           CurrentSheet := Bookmark
  856.          else
  857.           CurrentSheet := 1;
  858.  
  859.         Repeat
  860.  
  861.           LeftSide := ((CurrentSheet-1)*4) + 1;
  862.           If Pass = 1 then
  863.             LeftSide := LeftSide + 2;
  864.           RightSide := LeftSide + 1;
  865.  
  866.           If (PtrArray[ RightSide+1 ] > 0) and ((PrintFront and (Pass = 2)) or
  867.              (PrintBack and (Pass = 1))) then
  868.                Print_Right_Side( 91, RightSide );
  869.  
  870.           If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 2)) or
  871.              (PrintBack and (Pass = 1))) then
  872.                Print_Left_Side( 5, LeftSide );
  873.  
  874.           If ((Pass = 2) and PrintFront) or ((Pass = 1) and PrintBack) then
  875.             Write( OutFile, FF );
  876.  
  877.           If Pass = 1 then
  878.             Dec( CurrentSheet )
  879.            else
  880.             Inc( CurrentSheet );
  881.  
  882.           Dec( BookMark );
  883.  
  884.         Until BookMark = 0;
  885.  
  886.         ReInsert_Paper( Quit, Pass );
  887.  
  888.       Until ( Pass = NumberofPasses ) or Quit;
  889.  
  890.     end;
  891. { *************************************************************************** }
  892.  
  893. { This code prints the lineprinter-style output, where page 1 is on the front
  894.   side of the sheet and page 2 is on the back. }
  895.  
  896.   Procedure Front_And_Back_Print;
  897.     var
  898.       CurrentSheet    : Integer;          { Current sheet being printed }
  899.       Pass            : Integer;          { The current pass number, 1 or 2 }
  900.       LeftSide        : Integer;          { The left page index }
  901.       BookMark        : Integer;          { Bookmark set to halfway through }
  902.       NumberofPasses  : Integer;          { Number of passes on printer }
  903.  
  904.     begin
  905.  
  906.       NumberofPasses := 2;
  907.       If not PrintFront then NumberofPasses := 1;
  908.  
  909.       Pass := 0;
  910.  
  911.       Repeat
  912.  
  913.         Inc( Pass );
  914.  
  915.         Bookmark := Page div 2;
  916.         If Bookmark = 0 then Bookmark := 1;
  917.  
  918.         If ( (Pass=1) and PrintBack  ) or
  919.            ( (Pass=2) and PrintFront ) then
  920.           Writeln('Printing side ',Pass,' to ',OutputDest );
  921.  
  922.         If Pass = 1 then
  923.           CurrentSheet := Bookmark
  924.          else
  925.           CurrentSheet := 1;
  926.  
  927.         Repeat
  928.  
  929.           LeftSide := ((CurrentSheet-1)*2) + 1;
  930.           If Pass = 1 then
  931.             LeftSide := LeftSide + 1;
  932.  
  933.           If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 2)) or
  934.              (PrintBack and (Pass = 1))) then
  935.                Print_Left_Side( 5, LeftSide );
  936.  
  937.           If ((Pass = 2) and PrintFront) or ((Pass = 1) and PrintBack) then
  938.             Write( OutFile, FF );
  939.  
  940.           If Pass = 1 then
  941.             Dec( CurrentSheet )
  942.            else
  943.             Inc( CurrentSheet );
  944.  
  945.           Dec( BookMark );
  946.  
  947.         Until BookMark = 0;
  948.  
  949.         ReInsert_Paper( Quit, Pass );
  950.  
  951.       Until ( Pass = NumberofPasses ) or Quit;
  952.  
  953.     end;
  954.  
  955. { *************************************************************************** }
  956.  
  957. { This code prints the PCBook-style output, where the output is created in
  958.   booklet form.  If the paper is folded or cut in half to create 8.5 x 5.5-
  959.   inch pages, the pages may be hole-punched and put in a binder and read like
  960.   a book. }
  961.  
  962.   Procedure Booklet_Print;
  963.     var
  964.       Pass            : Integer;          { The current pass number, 1 or 2 }
  965.       LeftSide        : Integer;          { The left page index }
  966.       RightSide       : Integer;          { The right page index }
  967.       BookMark        : Integer;          { Bookmark set to halfway through }
  968.       NumberofPasses  : Integer;          { Number of passes on printer }
  969.  
  970.     begin
  971.  
  972.       LeftSide := Page;
  973.       RightSide := 1;
  974.       NumberofPasses := 2;
  975.       If not PrintBack then NumberofPasses := 1;
  976.  
  977.       Pass := 0;
  978.  
  979.       Repeat
  980.  
  981.         Inc( Pass );
  982.  
  983.         Bookmark := Page div 4;
  984.         If Bookmark = 0 then Bookmark := 1;
  985.  
  986.         If ( (Pass=1) and PrintFront ) or
  987.            ( (Pass=2) and PrintBack   ) then
  988.           Writeln('Printing side ',Pass,' to ',OutputDest );
  989.  
  990.         Repeat
  991.           If (PtrArray[ RightSide+1 ] > 0) and ((PrintFront and (Pass = 1)) or
  992.              (PrintBack  and (Pass = 2))) then
  993.                Print_Right_Side( 95, RightSide );
  994.  
  995.           If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 1)) or
  996.              (PrintBack  and (Pass = 2))) then
  997.                Print_Left_Side( 0, LeftSide );
  998.  
  999.           If ( (Pass = 1) and PrintFront ) or
  1000.              ( (Pass = 2) and PrintBack  ) then
  1001.             Write( OutFile, FF );
  1002.  
  1003.           LeftSide := LeftSide - 2;
  1004.           RightSide := RightSide + 2;
  1005.           Dec( BookMark );
  1006.  
  1007.         Until BookMark = 0;
  1008.  
  1009.         ReInsert_Paper( Quit, Pass );
  1010.  
  1011.       Until ( Pass = NumberofPasses ) or Quit;
  1012.  
  1013.     end;
  1014.  
  1015. { *************************** Main Program ******************************* }
  1016.  
  1017.   begin
  1018.  
  1019.     Parse_Command_Line;                     { Fix switches if necessary }
  1020.  
  1021.     OutputDest     := 'LPT1';               { Output to printer }
  1022.     JustCount      := False;                { Don't pause after page count }
  1023.     Pathname       := '';                   { No filename specified yet }
  1024.     Tune           := False;                { No beeping allowed by default }
  1025.     AlternateFile  := False;                { Don't prompt for alternate file }
  1026.     PrintFront     := True;                 { Print the front sides }
  1027.     PrintBack      := True;                 { Print the back sides }
  1028.     Booklet        := False;                { Default is side-by-side }
  1029.     Wide           := False;                { Default is narrow pages }
  1030.     Selected_Pages := False;                { Print all, not just some }
  1031.  
  1032.     With PC do
  1033.       begin
  1034.         If not Wide then
  1035.           LineLen   := NarrowLineLength     { Set up the Narrow line length }
  1036.          else
  1037.           LineLen   := WideLineLength;      { Set up for Wide line length }
  1038.         LineWrap  := False;                 { Truncate lines at right margin }
  1039.         DoHeader  := True;                  { Print a header by default }
  1040.         FileTitle := True;                  { Print filename in header }
  1041.         PgNumber  := True;                  { Print page numbers in header }
  1042.         FileDate  := True;                  { Print modify date in header }
  1043.         UserTitle := False;                 { No user-defined title }
  1044.       end;
  1045.  
  1046.     PrintLogo;
  1047.  
  1048.     For I := 1 to ParamCount do
  1049.       begin
  1050.         Parameter := ParamStr(I);                { Get a parameter }
  1051.  
  1052.         If Parameter[1] <> '/' then              { Must be a file name }
  1053.           Pathname := ParamStr(I);
  1054.  
  1055.         If Parameter = '/A' then                 { Toggle prompt for other }
  1056.           AlternateFile := not AlternateFile;    { output destination }
  1057.  
  1058.         If Parameter = '/BACK' then              { Toggle back sides only }
  1059.           PrintFront := not PrintFront;
  1060.  
  1061.         If (Parameter = '/BOOK') or (Parameter = '/B') then
  1062.           Booklet := not Booklet;                { Toggle booklet format }
  1063.  
  1064.         If Parameter = '/C' then                 { Toggle pause after count }
  1065.           JustCount := not JustCount;
  1066.  
  1067.         If Parameter = '/D' then                 { Toggle the date and time }
  1068.           PC.FileDate := not PC.FileDate;        { the file was last written }
  1069.  
  1070.         If Parameter = '/F' then                 { Toggle the filename in the }
  1071.           PC.FileTitle := not PC.FileTitle;      { heading }
  1072.  
  1073.         If Parameter = '/FRONT' then             { Toggle front sides only }
  1074.           PrintBack := not PrintBack;
  1075.  
  1076.         If (Parameter = '/H') or (Parameter = '?' ) or
  1077.            (Parameter = '/?') then Help;         { Give them some help }
  1078.  
  1079.         If Parameter = '/L' then                 { Toggle line printer width }
  1080.           Wide := not Wide;
  1081.  
  1082.         If Parameter = '/P' then                 { Toggle the page numbers in }
  1083.           PC.PgNumber := not PC.PgNumber;        { the heading }
  1084.  
  1085.         If Parameter = '/R' then                 { Print a range of pages }
  1086.           Selected_Pages := not Selected_Pages;
  1087.  
  1088.         If Parameter = '/S' then                 { Toggle sounds }
  1089.           Tune := not Tune;
  1090.  
  1091.         If Parameter = '/T' then                 { Toggle alt. title prompt }
  1092.           PC.UserTitle := not PC.UserTitle;
  1093.  
  1094.         If Parameter = '/W' then                 { Toggle line wrap }
  1095.           PC.LineWrap := not PC.LineWrap;
  1096.  
  1097.         If Parameter = '/2' then                 { Toggle print to LPT2 }
  1098.           If OutputDest = 'LPT1' then
  1099.             OutputDest := 'LPT2'
  1100.            else
  1101.             OutputDest := 'LPT1';
  1102.  
  1103.       end;
  1104.  
  1105.     With PC do
  1106.       DoHeader := FileDate or FileTitle or PgNumber or UserTitle;
  1107.  
  1108.     If Wide then
  1109.       begin
  1110.         Booklet := False;
  1111.         PC.LineLen := WideLineLength;
  1112.       end
  1113.      else
  1114.       PC.LineLen := NarrowLineLength;
  1115.  
  1116.     If not PrintFront and not PrintBack then
  1117.       begin
  1118.         Writeln;
  1119.         Writeln('** Nothing to print **');
  1120.         If Tune then Beep;
  1121.         Halt;
  1122.       end;
  1123.  
  1124.     Repeat
  1125.       If Pathname = '' then
  1126.         begin
  1127.           If Tune then Beep;
  1128.           Writeln;
  1129.           Write('Enter file name to print: ');
  1130.           Readln( Pathname );
  1131.           If Pathname = '' then Halt;
  1132.         end;
  1133.  
  1134.       FindFirst( Pathname, Archive+Hidden+Readonly, DirInfo );
  1135.       If DosError <> 0 then
  1136.         begin
  1137.           If Tune then Beep;
  1138.           Writeln('** Error opening input file: ',Pathname,' **');
  1139.           Writeln;
  1140.           Writeln('Press any key to try again or ESC to quit.');
  1141.           Writeln;
  1142.  
  1143.           If Press_A_Key = Escape then
  1144.             Halt
  1145.            else
  1146.             Pathname := '';
  1147.         end;
  1148.     Until Pathname <> '';
  1149.  
  1150.     Success := False;
  1151.     Repeat
  1152.       If AlternateFile then
  1153.         begin
  1154.           Writeln;
  1155.           If Tune then Beep;
  1156.           Write('Enter the alternate output file: ');
  1157.           Readln( Temp );
  1158.           If Temp <> '' then OutputDest := Temp;
  1159.         end;
  1160.  
  1161.       Assign( OutFile, OutputDest );
  1162.       {$I-} ReWrite( OutFile ); {$I+}
  1163.  
  1164.       If IOResult = 0 then
  1165.         Success := True
  1166.        else
  1167.         begin
  1168.           If Tune then Beep;
  1169.           Writeln('** Cannot open output file: ',OutputDest,' **');
  1170.           Writeln;
  1171.           Writeln('Press any key to try again or ESC to quit.');
  1172.           Writeln;
  1173.  
  1174.           AlternateFile := True;  { Give them a chance to change dest. }
  1175.  
  1176.           If Press_A_Key = Escape then
  1177.             Halt
  1178.            else
  1179.             OutputDest := 'LPT1';
  1180.         end;
  1181.     Until Success;
  1182.  
  1183.     If PC.UserTitle then
  1184.       begin
  1185.         Writeln;
  1186.         If Tune then Beep;
  1187.         Writeln('Enter a title of up to ',PC.LineLen,' characters: ');
  1188.         Write(' >');
  1189.         Readln( Temp );
  1190.         If Temp <> '' then
  1191.           begin
  1192.             Title := Temp;
  1193.             With PC do
  1194.               begin
  1195.                 FileTitle := False;
  1196.                 FileDate  := False;
  1197.                 If Length( Title ) > ( PC.LineLen - 8 ) then
  1198.                   PgNumber := False;
  1199.                 If Length( Title ) > PC.LineLen then
  1200.                   Title[0] := Char( PC.LineLen );
  1201.               end;
  1202.           end;
  1203.       end;
  1204.  
  1205.     Quit := False;          { Gets set to TRUE if ESC pressed while printing }
  1206.  
  1207.     FindFirst( Pathname, Archive+Hidden+Readonly, DirInfo );
  1208.     If DosError <> 0 then
  1209.       begin
  1210.         Writeln('** Error opening input file: ',Pathname,' **');
  1211.         If Tune then Beep;
  1212.         Halt;
  1213.       end;
  1214.  
  1215.     FSplit( FExpand( PathName ), FPath, FName, FExt );
  1216.  
  1217.     While ( DosError = 0 ) and not Quit do
  1218.       begin
  1219.  
  1220.         FileName := FExpand( FPath+DirInfo.Name );
  1221.         Assign( InFile, Filename );
  1222.         {$I-} Reset( Infile, 1 ); {$I+}
  1223.  
  1224.         If IOResult = 0 then
  1225.           begin
  1226.  
  1227.             CreationDate := GetFileDate;
  1228.  
  1229.             FSplit( Filename, FPath, FName, FExt );
  1230.             HeadingFilename := FName+FExt;
  1231.  
  1232. { The pointer array (PTRARRAY) must be initialized to all zeros before
  1233.   scanning a particular file.  Zero means that page isn't printed. }
  1234.  
  1235.             FillChar( PtrArray, Sizeof(PtrArray), 0 );
  1236.  
  1237. { Scan the file, building an array of pointers to the bytes in the file
  1238.   where a new page starts. }
  1239.  
  1240.             BuildArray( PtrArray, Page );
  1241.             Actual_Pages := Page;
  1242.  
  1243. { Correct the number of pages to make the number of sheets come out right and
  1244.   tell the user how many sheets of paper are required. }
  1245.  
  1246.             Print_Page_Info;
  1247.  
  1248. { Allow the user to select a range of pages to print.  The number of pages
  1249.   and sheets required are corrected as necessary. }
  1250.  
  1251.             If Selected_Pages then
  1252.               Select_Pages_To_Print;
  1253.  
  1254. { If we're just counting, let them bail out instead of printing }
  1255.  
  1256.             If JustCount then
  1257.               begin
  1258.                 Writeln('Press any key to continue or ESC to exit');
  1259.                 Writeln;
  1260.  
  1261.                 If Press_A_Key = Escape then
  1262.                   begin
  1263.                     Close( InFile );
  1264.                     Write( OutFile, Esc+'E' );      { Reset the printer }
  1265.                     Close( OutFile );
  1266.                     Halt;
  1267.                   end;
  1268.               end;
  1269.  
  1270. { Set up the LaserJet and print in the selected format }
  1271.  
  1272.             If Booklet then
  1273.               begin
  1274.                 Booklet_PrintSetup;
  1275.                 Booklet_Print;
  1276.               end
  1277.              else
  1278.               If not Wide then
  1279.                 begin
  1280.                   Side_By_Side_PrintSetup;
  1281.                   Side_By_Side_Print;
  1282.                 end
  1283.                else
  1284.                 begin
  1285.                   Front_And_Back_PrintSetup;
  1286.                   Front_And_Back_Print;
  1287.                 end;
  1288.  
  1289.             Write( OutFile, Esc+'E' );
  1290.             Close( InFile );
  1291.  
  1292.           end;                            { If IOResult = 0 }
  1293.  
  1294. { Find the next file, if there is one and continue if the user hasn't
  1295.   pressed the escape key yet. }
  1296.  
  1297.         FindNext( DirInfo );
  1298.  
  1299.         If (DosError = 0) and not Quit then
  1300.           begin
  1301.             If Tune then Beep;
  1302.             Writeln;
  1303.             Writeln('Press any key to continue with the next file ',
  1304.                     'or ESC to exit.');
  1305.  
  1306.             If Press_A_Key = Escape then Halt;
  1307.           end;
  1308.  
  1309.       end;                                { While DosError = 0 }
  1310.  
  1311.     Close( OutFile );
  1312.  
  1313.   end.
  1314.