home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D+,E+,F-,I+,L+,N-,O-,R-,S+,V+}
- {$M 16384,25000,655360}
-
- { PCLASER.PAS
- Utility to print ASCII text files to LaserJet Series II, IIp or II
- either side-by-side with 4 66-line, 80-column pages per sheet of paper,
- 2 66-line, 170-column pages per sheet of paper, or in 5.5 x 8.5-inch
- booklet form with 4 pages per sheet of paper. This program combines
- two of the PC Magazine utilities, the PCBOOK utility written by Jay Munro
- and the LASERLST utility written by Michael Holmes and Bob Flanders.
-
- PCBook and LaserLst : Copyright 1989/1990 PC Magazine - Ziff Davis -
- Jay Munro, Michael Holmes and Bob Flanders
- =====================================================================
- LaserJet programming concepts employed:
- Setting orientation & font style
- Locating LaserJet cursor
- LaserJet Macro setup and use
- =====================================================================
- General programming concepts
- Building index arrays
- Using files for printing
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- This program was based on the PCBook utility originally written by Jay
- Munro in QuickBASIC. Since I had Turbo Pascal and not QuickBASIC, it
- was necessary to translate the program into TP before I could make any
- changes. As far as I'm concerned, Jay, et. al. and ZD still own their
- original copyrights. The resulting TP code is smaller and likely faster
- than the original QB code. The code to produce output like in PCBook
- and that as in LaserLst was so similar, it was far easier to combine the
- programs into one and give the user the option of changing the format
- from side-by-side printing to booklet format, as necessary.
-
- Changes made:
- 1. Converted to Turbo Pascal. While the TP source code is longer, the
- compiled code is about 1/3 the size of the QuickBasic code. Some
- things were speeded up in the conversion.
- 2. Modified the page header to show file creation date and time instead
- of the current date. I'd rather know the version date of the file
- than the date I printed its contents.
- 3. Page header is underlined.
- 4. Multiple files may be specified with wildcards. Each file is
- completely printed - front and back - before starting the next file.
- 5. Optionally print front or back sides only. By combining this feature
- with the alternate output file, you could make multiple copies of
- a file by sending the front pages to one file, the back pages to
- another file and then copying it to the printer as many times as
- needed since all the printer escape sequences are in both files.
- 6. Prompt for user-defined heading.
- 7. Program modified to print side-by-side or in booklet form.
- 8. The program now scans each command line parameter from left to right
- and takes action accordingly. The switches are now toggle their
- option, and some of them are specified as defaults. Specifying a
- default switch the second time turns the option off.
- 9. Combined LaserLst-type and PCBook-type formats into one program.
- 10. Added the ability to print wide reports, i.e., > 80 column reports
- with one page on the front of the sheet and the next page on the back.
- 11. Added the ability to print a selected range of pages in the file.
- This is useful when the software that generated the file put a
- leading and/or trailing formfeeds in the file, causing blank pages
- to be generated. This also allows you to just print a selected
- portion of a large file, assuming you don't need the whole thing.
-
- The TP version of PCBOOK doesn't implement all the error recovery that was
- found in the QB version. The main reason is that when a critical error
- occurs, such as the printer being out of paper, there is no way to resume
- where the program left off once the error condition is fixed. The user
- will have to put up with DOS's error handling unless they know of a way
- to handle this. Using an exit proc will tell you what error occurred and
- the address of the line where the error occurred, but will not let you
- resume execution -- at least I haven't figured out how, anyway....
-
- These changes were made by Bob White. Much of the code is the TP trans-
- lation of the QB code written by Jay Munro. }
-
- { *************************************************************************** }
-
- Program PCLASER;
-
- uses
- Dos, Crt;
-
- const
- Esc : Char = #27; { Escape character }
- CR : Char = #13; { Carriage return character }
- FF : Char = #12; { Formfeed character }
- LF : Char = #10; { Linefeed character }
- MaximumBufferSize = 16384; { Maximum buffer size }
- MaximumPages = 513; { Maximum pages + 1 }
- MaximumLineLength = 180; { The width of each page }
- MaximumPageLength = 66; { Number of lines per page }
- WideLineLength = 170; { For wide output }
- NarrowLineLength = 80; { For narrow output or booklet }
-
- type
- KeyType = ( Escape, Carriage_Return, Other );
- Flags = record
- FileDate : Boolean;
- DoHeader : Boolean;
- FileTitle : Boolean;
- LineLen : Integer;
- LineWrap : Boolean;
- PgNumber : Boolean;
- UserTitle : Boolean;
- end;
-
- BufType = Array[1..MaximumBufferSize] of Char;
- BufPtr = ^BufType;
- PtrArrayType = Array[1..MaximumPages] of LongInt;
- CommandPtr = ^ComStr;
- DateString = String[17];
- TitleType = String[MaximumLineLength];
-
- var
- Actual_Pages : Integer; { Actual pages in file }
- AlternateFile : Boolean; { Allow output to alternate file }
- Booklet : Boolean; { Booklet or side-by-side flag }
- Buffer : BufPtr; { Pointer to the input buffer }
- Commandline : CommandPtr; { Pointer to the DOS command line }
- CreationDate : DateString; { The date the file was created }
- DirInfo : SearchRec; { Buffer for FindFirst/FindNext }
- FExt : ExtStr; { Used to get heading filename }
- Filename : PathStr; { The individual filename }
- FName : NameStr; { Used to get heading filename }
- FPath : DirStr; { Used to get heading filename }
- HeadingFilename : String[12]; { Filename to be used in heading }
- InFile : File; { The input file }
- I : Integer; { An index, used several times }
- JustCount : Boolean; { Just count, optionally print }
- OutFile : Text; { The output file }
- OutputDest : PathStr; { The output destination, ie, LPT1 }
- Page : Integer; { The number of pages in the file }
- Parameter : String; { A command line parameter }
- PathName : PathStr; { The user-supplied filename }
- PC : Flags; { Various state flags }
- PrintBack : Boolean; { Print the back side of the page? }
- PrintFront : Boolean; { Print the front side of the page? }
- PtrArray : PtrArrayType; { Array of page pointers }
- Quit : Boolean; { True if escape pressed during print }
- Selected_Pages : Boolean; { Print a range of pages }
- Sheets : Integer; { Physical sheets of paper required }
- Success : Boolean; { True if output file opened okay }
- Temp : PathStr; { Buffer for alternate file name }
- Title : TitleType; { User defined title in heading }
- Tune : Boolean; { Do we beep or not? }
- Wide : Boolean; { Printing 132-column file }
-
- { *************************************************************************** }
-
- { This function scans the input buffer to find the first occurrence of a
- specific character. This function was written in Turbo Assembler for
- speed, although the buffer may be scanned with a loop and comparing each
- character in the buffer to see if it's the character being searched for. }
-
- Function FindPos( var Buffer;
- Offset : Integer;
- MaxSize : Integer;
- Character : Char ) : Integer; External;
-
- {$L FINDPOS.OBJ}
-
- { *************************************************************************** }
-
- { Scan the command line, making sure the switches are preceeded by a blank.
- This allows TP to break them out with the ParamCount and ParamStr routines. }
-
- Procedure Parse_Command_Line;
-
- var
- I : Integer; { Index to command line characters }
- Commandline : CommandPtr; { Pointer to the DOS command line }
- Prev_Char : Char; { Previous character in command line }
-
- begin
-
- CommandLine := Ptr( PrefixSeg, $80 );
- I := 1;
- Prev_Char := ' ';
-
- Repeat
- CommandLine^[I] := Upcase( CommandLine^[I] );
- If (CommandLine^[I] = '/') and (Prev_Char <> ' ') then
- begin
- Insert( ' ', CommandLine^, I );
- Inc( I );
- end;
- Prev_Char := CommandLine^[I];
- Inc( I );
- Until I > Length( CommandLine^ );
-
- end;
-
- { *************************************************************************** }
-
- { This procedure scans the input file and builds the array of pointers to
- where each page will begin and end, which are returned in PTRARRAY. The
- array consists of byte pointers - the byte position in the file - of the
- first character on each page. When the program starts printing, it uses
- SEEK to position to the appropriate character and reads everything up to
- the start of the next page, and then prints everything it read. }
-
- Procedure BuildArray( var PtrArray : PtrArrayType;
- var PgCount : Integer );
-
- var
- Offset : LongInt;
- TotalSize : LongInt;
- FileLeft : LongInt;
- BufSize : Integer;
- BufUsed : Integer;
- LnCount : Integer;
- StPtr : Integer;
- TempLn : Integer;
- TempPg : Integer;
-
- label
- GetPage, PageCheck, PageBreak, EndBuild;
-
- begin
- Offset := 0;
-
- TotalSize := Filesize( InFile ); { Get the size of the file }
- FileLeft := TotalSize;
-
- If MemAvail < 2048 then
- begin
- Writeln( '** Less than 2K memory available - not enough to run **');
- Halt;
- end;
-
- { Define the buffer size as either the 16K bytes (the currently-defined
- maximum buffer size) or the available memory, whichever is larger, or
- the file size, if it is less than 16K. }
-
- If TotalSize > MaximumBufferSize then
- begin
- If MemAvail > MaximumBufferSize then
- BufSize := MaximumBufferSize
- else
- BufSize := MemAvail;
- end
- else
- If TotalSize < MemAvail then
- BufSize := TotalSize;
-
- GetMem( Buffer, BufSize ); { Allocate the input buffer }
-
- PgCount := 1;
- PtrArray[ PgCount ] := 0; { First page = start of file }
- LnCount := 0;
-
- GetPage:
-
- BufUsed := BufSize;
- If FileLeft < BufSize then
- BufUsed := FileLeft;
-
- BlockRead( InFile, Buffer^, BufUsed ); { Get a buffer full }
-
- StPtr := 1;
- TempPg := 0;
-
- PageCheck:
-
- { Here, we're looking to see if a linefeed occurs before or after the next
- formfeed. For the sake of speed, the buffer is only scanned for formfeeds
- whenever a new buffer is read or there was a formfeed in the buffer before.
- The original QuickBasic code scanned for both a linefeed and a formfeed
- each pass through - i.e., after each line. If the buffer doesn't contain
- a formfeed in it, the program wastes a lot of time scanning it for formfeeds
- after the first line. Checking it on the first pass after reading a new
- buffer and subsequently only if a formfeed was found on the first pass
- through saves quite a bit of time.... }
-
- TempLn := FindPos( Buffer^, StPtr-1, BufUsed, LF );
-
- If (StPtr = 1) or (TempPg <> 0 ) then
- TempPg := FindPos( Buffer^, StPtr-1, BufUsed, FF );
-
- { We found a formfeed in the input file. }
-
- If TempPg > 0 then
- If ( TempPg < TempLn ) or ( TempLn = 0 ) then
- begin
- Inc( PgCount );
- PtrArray[ PgCount ] := Offset + TempPg;
- StPtr := TempPg + 1;
- LnCount := 0;
- If StPtr < BufUsed then Goto PageCheck;
- end;
-
- { There was no formfeed, but there was a linefeed.. }
-
- If TempLn > 0 then
- begin
-
- If PC.LineWrap then
- If ( TempLn - StPtr ) > PC.LineLen then
- While ( TempLn - StPtr ) > PC.LineLen do
- begin
- Inc( LnCount );
- If LnCount = MaximumPageLength then Goto PageBreak;
- StPtr := StPtr + PC.LineLen;
- end;
-
- Inc( LnCount );
-
- PageBreak:
-
- { When there are no formfeeds in the file to make the pages break, use
- MaximumPageLength as the maximum number of printed lines per page.
- Currently, this is defined as 66 lines per page. }
-
- If LnCount = MaximumPageLength then
- begin
- Inc( PgCount );
- If PgCount = MaximumPages then
- begin
- Writeln('Too many pages - printing first ',MaximumPages-1);
- Goto EndBuild;
- end;
- PtrArray[ PgCount ] := Offset + TempLn;
- LnCount := 0;
- end;
-
- StPtr := TempLn + 1;
-
- { If there's more characters in the buffer, go scan them... }
-
- If StPtr <= BufUsed then Goto PageCheck;
-
- end;
-
- { We've looked at this buffer - if there's more characters in the file, go
- back and get the next buffer full. }
-
- Offset := Offset + BufUsed;
- StPtr := 1;
- FileLeft := TotalSize - Offset;
-
- If Offset < TotalSize then
- Goto Getpage;
-
- EndBuild:
-
- { We've finished scanning the file. Store the total size as the last page
- size. }
-
- PtrArray[ PgCount+1 ] := TotalSize;
- Freemem( Buffer, BufSize ); { Deallocate the buffer }
-
- end;
-
- { *************************************************************************** }
-
- Procedure DoMacro( MacroNumber : String );
- begin
- Write( OutFile, Esc+'&f'+MacroNumber+'y2X'); { Execute the macro }
- end;
-
- { *************************************************************************** }
-
- Procedure StartMacro( MacroNumber : String );
- begin
- Write( OutFile, Esc+'&f'+MacroNumber+'Y'); {Define macro name}
- Write( OutFile, Esc+'&f0X'); {Macro starts now}
- end;
-
- { *************************************************************************** }
-
- Procedure EndMacro( MacroNumber : String );
- begin
- Write( OutFile, Esc+'&f'+MacroNumber+'y1X'); {End of macro command}
- Write( OutFile, Esc+'&f'+MacroNumber+'y9X'); {Make it temp (10=perm)}
- end;
-
- { *************************************************************************** }
-
- Procedure Header( Page : Integer );
- var
- Heading : String;
- Temp : String;
- I : Integer;
-
- begin
- Heading[0] := Char( PC.LineLen );
- FillChar( Heading[1], PC.LineLen, ' ');
-
- If PC.FileTitle then
- begin
- I := (PC.LineLen div 2) - (Length(HeadingFilename) div 2);
- Move( HeadingFilename[1], Heading[I], Length( HeadingFilename ) );
- end;
-
- If PC.UserTitle then
- begin
- If (Page mod 2) <> 0 then
- I := 1 { Odd page, Left side }
- else
- I := PC.LineLen-Length(Title)+1; { Even page, right side }
- Move( Title[1], Heading[I], Length(Title) );
- end;
-
- If PC.PgNumber then
- begin
- Str( Page, Temp );
- Insert( 'Page ', Temp, 1 );
- If (Page mod 2) <> 0 then
- I := PC.LineLen - Length( Temp ) + 1 { Odd page, right side }
- else
- I := 1; { Even page, left side }
- Move( Temp[1], Heading[I], Length(Temp) );
- end;
-
- If PC.FileDate then
- begin
- If (Page mod 2) <> 0 then
- I := 1 { Odd page, Left side }
- else
- I := PC.LineLen-Length(CreationDate)+1; { Even page, right side }
- Move( CreationDate[1], Heading[I], Length(CreationDate) );
- end;
-
- Writeln( OutFile, Esc+'&dD',Heading, Esc+'&d@' );
- Writeln( OutFile );
- end;
-
- { *************************************************************************** }
-
- Procedure LJLocate( X, Y : Integer );
- begin
- Write( OutFile, Esc+'&a',Y,'r',X,'C'); { Move LaserJet cursor to X,Y }
- end;
-
- { *************************************************************************** }
-
- { Set up the LaserJet for the LaserLst-type output where the first page is
- to the left of the next page. }
-
- Procedure Side_by_Side_PrintSetup;
- var
- I : Integer;
-
- begin
- Write( OutFile, Esc+'E' ); { Reset the LaserJet }
- Write( OutFile, Esc+'&l1o5.15C'); { Select Landscape and }
- Write( OutFile, Esc+'(s0p17H'); { Lineprinter pitch and font }
- Write( OutFile, Esc+'&l0L'); { No pagefeed after 66 lines }
- Write( OutFile, Esc+'(s-3B'); { Light stroke weight }
-
- If PC.LineWrap then
- Write( OutFile, Esc+'&s0C'); { Wrap lines if selected }
-
- Write( OutFile, Esc+'&l6E'); { Top margin 6 lines }
-
- StartMacro( '1' ); { Left side macro }
- Write( OutFile, Esc+'9' ); { Reset left & right margins }
- Write( OutFile, Esc+'&a5l85M'); { Left margin 5, right 85 }
- EndMacro( '1' ); { end of macro }
-
- StartMacro( '2' ); { Right side macro }
- Write( OutFile, Esc+'9' ); { Reset left & right margins }
- Write( OutFile, Esc+'&a91l171M'); { Left margin 91, right 171 }
- EndMacro( '2' ); { end of macro }
-
- StartMacro( '3' ); { Divider bar macro }
- Write( OutFile, Esc+'9' ); { Reset the margins }
- Write( OutFile, Esc+'&a88l90M'); { Left margin 88, right 90 }
- I := 0;
- If PC.DoHeader then { Row depends on heading }
- I := 2; { Goto row 2 }
- LJLocate( 88, I ); { Goto row I, column 88 }
- For I := 1 to MaximumPageLength do
- Writeln( Outfile, '|' ); { Write out the vert. bars }
- EndMacro( '3' ); { end of macro }
-
- end;
-
- { *************************************************************************** }
-
- { Set up the LaserJet for the 2 pages per sheet format }
-
- Procedure Front_and_Back_PrintSetup;
-
- begin
- Write( OutFile, Esc+'E' ); { Reset the LaserJet }
- Write( OutFile, Esc+'&l1o5.15C'); { Select Landscape and }
- Write( OutFile, Esc+'(s0p17H'); { Lineprinter pitch and font }
- Write( OutFile, Esc+'&l0L'); { No pagefeed after 66 lines }
- Write( OutFile, Esc+'(s-3B'); { Light stroke weight }
-
- If PC.LineWrap then
- Write( OutFile, Esc+'&s0C'); { Wrap lines if selected }
-
- Write( OutFile, Esc+'&l6E'); { Top margin 2 lines }
-
- StartMacro( '1' ); { Left side macro }
- Write( OutFile, Esc+'9' ); { Reset left & right margins }
- Write( OutFile, Esc+'&a5l191M'); { Left margin 10, right 191 }
- EndMacro( '1' ); { end of macro }
-
- end;
-
- { *************************************************************************** }
-
- { Set up the LaserJet for the PCBook format - booklet format with 4 pages
- per sheet. }
-
- Procedure Booklet_PrintSetup;
- begin
- Write( OutFile, Esc+'E' ); { Reset the LaserJet }
- Write( OutFile, Esc+'&l1o5.45C'); { Select Landscape and }
- Write( OutFile, Esc+'(s0p16.66H'); { Lineprinter pitch and font }
- Write( OutFile, Esc+'&l0L'); { No pagefeed after 66 lines }
-
- If PC.LineWrap then
- Write( OutFile, Esc+'&s0C'); { Wrap lines if selected }
-
- Write( OutFile, Esc+'&l2E'); { Top margin 2 lines }
-
- StartMacro( '1' ); { Left side macro }
- Write( OutFile, Esc+'9' ); { Reset left & right margins }
- Write( OutFile, Esc+'&a0l80M'); { Left margin 0, right 80 }
- EndMacro( '1' ); { end of macro }
-
- StartMacro( '2' ); { Right side macro }
- Write( OutFile, Esc+'9' ); { Reset left & right margins }
- Write( OutFile, Esc+'&a95l175M'); { Left margin 95, right 175 }
- EndMacro( '2' ); { end of macro }
-
- end;
-
- { *************************************************************************** }
-
- Procedure Beep;
- begin
- Write( #7 ); { Beep! }
- end;
-
- { *************************************************************************** }
-
- Procedure PrintLogo;
- var
- I : Integer;
- begin
- ClrScr;
- For I := 1 to 79 do Write('=');
- Writeln;
- Writeln('PCLaser - LaserJet Printing Utility');
- Writeln('Copyright 1990 - Bob White 11/25/90');
- Writeln('PCBook/LaserLst copyright 1989/1990 PC Magazine - Ziff Davis');
- For I := 1 to 79 do Write('=');
- Writeln;
- end;
-
- { *************************************************************************** }
-
- Procedure Help;
- begin
- ClrScr;
- Writeln('Usage: PCLASER [filename] [/A] [/B] [/BACK] [/C] [/D] [/F] ',
- '[/FRONT]');
- Writeln(' [/H] [/L] [/P] [/R] [/S] [/T] [/W] ',
- '[/2]');
- Writeln;
- Writeln(' /A - Prompts for alternate output file');
- Writeln(' /B - Print in booklet format. Also /BOOK');
- Writeln(' /BACK - Only print the back side of the page');
- Writeln(' /C - Pauses after physical page count');
- Writeln('* /D - Prints the file revision date in each page heading');
- Writeln('* /F - Prints the filename in each page heading');
- Writeln(' /FRONT - Only print the front side of the page');
- Writeln(' /H - This message. Also /? or ?');
- Writeln(' /L - Print lineprinter reports (2 pages per sheet)');
- Writeln('* /P - Prints the page numbers in each page heading');
- Writeln(' /R - Print a range of pages');
- Writeln(' /S - Turns sound on');
- Writeln(' /T - Prompts for a user-defined title');
- Writeln(' /W - Turns on line wrap');
- Writeln(' /2 - Prints to LPT2 instead of LPT1');
- Writeln;
- Writeln('Options marked with "*" are enabled by default and are ');
- Writeln('disabled by specifying the option on the command line.');
- Halt;
- end;
-
- { *************************************************************************** }
-
- { Get a keypress, returning whether or not it is a carriage return, escape,
- or other key hit. }
-
- Function Press_A_Key : KeyType;
-
- var
- Keystroke : Char;
-
- begin
- Repeat until Keypressed; { Wait for a keypress }
- Keystroke := ReadKey; { Get return code }
-
- Press_A_Key := Other; { Some other key was hit }
-
- If Keystroke = #0 then
- Keystroke := ReadKey { ESC isn't extended key }
- else
- Case Keystroke of
- #27 : Press_A_Key := Escape;
- #13 : Press_A_Key := Carriage_Return;
- end;
- end;
-
- { *************************************************************************** }
-
- { Get the last revision date of the file and convert it to ASCII }
-
- Function GetFileDate : DateString;
-
- var
- Created : LongInt;
- DT : DateTime;
- Temp : String[10];
- Result : DateString;
-
- begin
- GetFTime( InFile, Created );
- UnPackTime( Created, DT );
- With DT do
- begin
- Month := Month + 100; { Add 100 so STR puts a zero in }
- Day := Day + 100; { when the value is less than 10 }
- Hour := Hour + 100;
- Min := Min + 100;
-
- Str( Month:4, Temp );
- Result := Copy( Temp, 3, 2 ) + '/';
- Str( Day:4, Temp );
- Result := Result + Copy( Temp, 3, 2 ) + '/';
- Str( Year:4, Temp );
- Result := Result + Temp + ' ';
-
- Str( Hour:4, Temp );
- Result := Result + Copy( Temp, 3, 2 ) + ':';
- Str( Min:4, Temp );
- Result := Result + Copy( Temp, 3, 2 );
- end;
- GetFileDate := Result;
- end;
-
- { *************************************************************************** }
-
- Procedure Print_Page_Info;
- begin
- If not Wide then
- begin
- If Page mod 4 <> 0 then Page := Page + ( 4 - (Page mod 4) );
- Sheets := Page div 4;
- end
- else
- begin
- If Page mod 2 <> 0 then Inc( Page );
- Sheets := Page div 2;
- end;
-
- Writeln;
- Writeln( Filename, ' contains ',Actual_Pages,' actual pages and');
- Writeln( ' will require ', Sheets,' sheet(s) of paper to print.');
- Writeln;
- end;
-
- { *************************************************************************** }
-
- Procedure Select_Pages_To_Print;
-
- var
- Starting_Page : Integer;
- Ending_Page : Integer;
- Buf : String;
- Temp : Integer;
- Code : Integer;
- I,J : Integer;
-
- begin
- Starting_Page := -1;
- Ending_Page := -1;
-
- Repeat
- Write('Enter starting page number (1-',Actual_Pages,') [1] >>');
- Readln( Buf );
- If Buf <> '' then
- begin
- Val( Buf, Temp, Code );
- If (Code = 0) and (Temp >= 1) and (Temp <= Actual_Pages) then
- Starting_Page := Temp;
- end
- else
- Starting_Page := 1;
- Until Starting_Page >= 1;
-
- Repeat
- Write('Enter ending page number (',Starting_Page,'-',Actual_Pages,
- ') [',Actual_Pages,'] >>');
- Readln( Buf );
- If Buf <> '' then
- begin
- Val( Buf, Temp, Code );
- If (Code = 0) and (Temp >= Starting_Page) and
- (Temp <= Actual_Pages) then
- Ending_Page := Temp;
- end
- else
- Ending_Page := Actual_Pages;
- Until Ending_Page >= Starting_Page;
-
- J := 1;
- For I := Starting_Page to Ending_Page + 1 do
- begin
- PtrArray[J] := PtrArray[I];
- Inc( J );
- end;
-
- For I := J to Page do
- PtrArray[I] := 0;
-
- Page := Ending_Page - Starting_Page + 1;
- Actual_Pages := Page;
-
- Print_Page_Info;
-
- end;
-
- { *************************************************************************** }
-
- { Print the left page if we're printing 4 pages per sheet, or either the
- front or back when printing 2 pages per sheet }
-
- Procedure Print_Left_Side( LeftMargin : Integer;
- LeftSide : Integer );
-
- var
- BufNeed : Integer; { Buffer size needed for current page }
- MaxPrint : Integer; { Maximum bytes to print }
-
- begin
- DoMacro( '1' );
- LJLocate( LeftMargin, 0 );
-
- If PC.DoHeader then Header( LeftSide );
-
- If LeftSide <> 0 then
- begin
- BufNeed := PtrArray[LeftSide+1] - PtrArray[LeftSide];
- GetMem( Buffer, BufNeed );
- Seek( InFile, PtrArray[LeftSide] );
- BlockRead( Infile, Buffer^, BufNeed );
- MaxPrint := BufNeed;
-
- If Buffer^[BufNeed] = FF then Dec( MaxPrint );
- For I := 1 to MaxPrint do
- Write( OutFile, Buffer^[I] );
- FreeMem( Buffer, BufNeed );
- end;
- end;
-
- { *************************************************************************** }
-
- { Print the right page if printing 4 pages per sheet. This routine is not
- used for front and back output. }
-
- Procedure Print_Right_Side( LeftMargin : Integer;
- RightSide : Integer );
-
- var
- BufNeed : Integer; { Buffer size needed for current page }
- MaxPrint : Integer; { Maximum bytes to print }
-
- begin
- If not Booklet then DoMacro( '3' ); { Draw vertical line }
- DoMacro( '2' ); { Reset the margins }
- LJLocate( LeftMargin, 0 );
-
- If PC.DoHeader then Header( RightSide );
-
- BufNeed := PtrArray[RightSide+1] - PtrArray[RightSide];
- GetMem( Buffer, BufNeed );
- Seek( InFile, PtrArray[RightSide] );
- BlockRead( Infile, Buffer^, BufNeed );
- MaxPrint := BufNeed;
-
- If Buffer^[BufNeed] = FF then Dec( MaxPrint );
- For I := 1 to MaxPrint do
- Write( OutFile, Buffer^[I] );
- FreeMem( Buffer, BufNeed );
- end;
-
- { *************************************************************************** }
-
- { Prompt them to reinsert the paper and either press return or escape. Any
- other characters are ignored }
-
- Procedure ReInsert_Paper( var Quit : Boolean;
- Pass : Integer );
-
- var
- Key : KeyType;
-
- begin
- If (Pass = 1) and PrintBack and PrintFront then
- begin
- If Tune then Beep;
- Writeln;
- Writeln('Put the paper back in the tray');
- Writeln(' and press ENTER to continue,');
- Writeln(' or press ESC to stop printing.');
- Repeat
- Key := Press_A_Key;
- Quit := Key = Escape;
- Until (Key = Carriage_Return) or Quit;
- Writeln;
- end;
- end;
-
- { *************************************************************************** }
-
- { This code prints the LaserLst-type output where page 1 is on the left, page
- 2 is on the right, page 3 is behind page 2, and page 4 is behind page 1. }
-
- Procedure Side_By_Side_Print;
- var
- CurrentSheet : Integer; { Current sheet being printed }
- Pass : Integer; { The current pass number, 1 or 2 }
- LeftSide : Integer; { The left page index }
- RightSide : Integer; { The right page index }
- BookMark : Integer; { Bookmark set to halfway through }
- NumberofPasses : Integer; { Number of passes on printer }
-
- begin
-
- NumberofPasses := 2;
- If not PrintFront then NumberofPasses := 1;
-
- Pass := 0;
-
- Repeat
-
- Inc( Pass );
-
- Bookmark := Page div 4;
- If Bookmark = 0 then Bookmark := 1;
-
- If ( (Pass=1) and PrintBack ) or
- ( (Pass=2) and PrintFront ) then
- Writeln('Printing side ',Pass,' to ',OutputDest );
-
- If Pass = 1 then
- CurrentSheet := Bookmark
- else
- CurrentSheet := 1;
-
- Repeat
-
- LeftSide := ((CurrentSheet-1)*4) + 1;
- If Pass = 1 then
- LeftSide := LeftSide + 2;
- RightSide := LeftSide + 1;
-
- If (PtrArray[ RightSide+1 ] > 0) and ((PrintFront and (Pass = 2)) or
- (PrintBack and (Pass = 1))) then
- Print_Right_Side( 91, RightSide );
-
- If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 2)) or
- (PrintBack and (Pass = 1))) then
- Print_Left_Side( 5, LeftSide );
-
- If ((Pass = 2) and PrintFront) or ((Pass = 1) and PrintBack) then
- Write( OutFile, FF );
-
- If Pass = 1 then
- Dec( CurrentSheet )
- else
- Inc( CurrentSheet );
-
- Dec( BookMark );
-
- Until BookMark = 0;
-
- ReInsert_Paper( Quit, Pass );
-
- Until ( Pass = NumberofPasses ) or Quit;
-
- end;
- { *************************************************************************** }
-
- { This code prints the lineprinter-style output, where page 1 is on the front
- side of the sheet and page 2 is on the back. }
-
- Procedure Front_And_Back_Print;
- var
- CurrentSheet : Integer; { Current sheet being printed }
- Pass : Integer; { The current pass number, 1 or 2 }
- LeftSide : Integer; { The left page index }
- BookMark : Integer; { Bookmark set to halfway through }
- NumberofPasses : Integer; { Number of passes on printer }
-
- begin
-
- NumberofPasses := 2;
- If not PrintFront then NumberofPasses := 1;
-
- Pass := 0;
-
- Repeat
-
- Inc( Pass );
-
- Bookmark := Page div 2;
- If Bookmark = 0 then Bookmark := 1;
-
- If ( (Pass=1) and PrintBack ) or
- ( (Pass=2) and PrintFront ) then
- Writeln('Printing side ',Pass,' to ',OutputDest );
-
- If Pass = 1 then
- CurrentSheet := Bookmark
- else
- CurrentSheet := 1;
-
- Repeat
-
- LeftSide := ((CurrentSheet-1)*2) + 1;
- If Pass = 1 then
- LeftSide := LeftSide + 1;
-
- If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 2)) or
- (PrintBack and (Pass = 1))) then
- Print_Left_Side( 5, LeftSide );
-
- If ((Pass = 2) and PrintFront) or ((Pass = 1) and PrintBack) then
- Write( OutFile, FF );
-
- If Pass = 1 then
- Dec( CurrentSheet )
- else
- Inc( CurrentSheet );
-
- Dec( BookMark );
-
- Until BookMark = 0;
-
- ReInsert_Paper( Quit, Pass );
-
- Until ( Pass = NumberofPasses ) or Quit;
-
- end;
-
- { *************************************************************************** }
-
- { This code prints the PCBook-style output, where the output is created in
- booklet form. If the paper is folded or cut in half to create 8.5 x 5.5-
- inch pages, the pages may be hole-punched and put in a binder and read like
- a book. }
-
- Procedure Booklet_Print;
- var
- Pass : Integer; { The current pass number, 1 or 2 }
- LeftSide : Integer; { The left page index }
- RightSide : Integer; { The right page index }
- BookMark : Integer; { Bookmark set to halfway through }
- NumberofPasses : Integer; { Number of passes on printer }
-
- begin
-
- LeftSide := Page;
- RightSide := 1;
- NumberofPasses := 2;
- If not PrintBack then NumberofPasses := 1;
-
- Pass := 0;
-
- Repeat
-
- Inc( Pass );
-
- Bookmark := Page div 4;
- If Bookmark = 0 then Bookmark := 1;
-
- If ( (Pass=1) and PrintFront ) or
- ( (Pass=2) and PrintBack ) then
- Writeln('Printing side ',Pass,' to ',OutputDest );
-
- Repeat
- If (PtrArray[ RightSide+1 ] > 0) and ((PrintFront and (Pass = 1)) or
- (PrintBack and (Pass = 2))) then
- Print_Right_Side( 95, RightSide );
-
- If (PtrArray[LeftSide+1] <> 0) and ((PrintFront and (Pass = 1)) or
- (PrintBack and (Pass = 2))) then
- Print_Left_Side( 0, LeftSide );
-
- If ( (Pass = 1) and PrintFront ) or
- ( (Pass = 2) and PrintBack ) then
- Write( OutFile, FF );
-
- LeftSide := LeftSide - 2;
- RightSide := RightSide + 2;
- Dec( BookMark );
-
- Until BookMark = 0;
-
- ReInsert_Paper( Quit, Pass );
-
- Until ( Pass = NumberofPasses ) or Quit;
-
- end;
-
- { *************************** Main Program ******************************* }
-
- begin
-
- Parse_Command_Line; { Fix switches if necessary }
-
- OutputDest := 'LPT1'; { Output to printer }
- JustCount := False; { Don't pause after page count }
- Pathname := ''; { No filename specified yet }
- Tune := False; { No beeping allowed by default }
- AlternateFile := False; { Don't prompt for alternate file }
- PrintFront := True; { Print the front sides }
- PrintBack := True; { Print the back sides }
- Booklet := False; { Default is side-by-side }
- Wide := False; { Default is narrow pages }
- Selected_Pages := False; { Print all, not just some }
-
- With PC do
- begin
- If not Wide then
- LineLen := NarrowLineLength { Set up the Narrow line length }
- else
- LineLen := WideLineLength; { Set up for Wide line length }
- LineWrap := False; { Truncate lines at right margin }
- DoHeader := True; { Print a header by default }
- FileTitle := True; { Print filename in header }
- PgNumber := True; { Print page numbers in header }
- FileDate := True; { Print modify date in header }
- UserTitle := False; { No user-defined title }
- end;
-
- PrintLogo;
-
- For I := 1 to ParamCount do
- begin
- Parameter := ParamStr(I); { Get a parameter }
-
- If Parameter[1] <> '/' then { Must be a file name }
- Pathname := ParamStr(I);
-
- If Parameter = '/A' then { Toggle prompt for other }
- AlternateFile := not AlternateFile; { output destination }
-
- If Parameter = '/BACK' then { Toggle back sides only }
- PrintFront := not PrintFront;
-
- If (Parameter = '/BOOK') or (Parameter = '/B') then
- Booklet := not Booklet; { Toggle booklet format }
-
- If Parameter = '/C' then { Toggle pause after count }
- JustCount := not JustCount;
-
- If Parameter = '/D' then { Toggle the date and time }
- PC.FileDate := not PC.FileDate; { the file was last written }
-
- If Parameter = '/F' then { Toggle the filename in the }
- PC.FileTitle := not PC.FileTitle; { heading }
-
- If Parameter = '/FRONT' then { Toggle front sides only }
- PrintBack := not PrintBack;
-
- If (Parameter = '/H') or (Parameter = '?' ) or
- (Parameter = '/?') then Help; { Give them some help }
-
- If Parameter = '/L' then { Toggle line printer width }
- Wide := not Wide;
-
- If Parameter = '/P' then { Toggle the page numbers in }
- PC.PgNumber := not PC.PgNumber; { the heading }
-
- If Parameter = '/R' then { Print a range of pages }
- Selected_Pages := not Selected_Pages;
-
- If Parameter = '/S' then { Toggle sounds }
- Tune := not Tune;
-
- If Parameter = '/T' then { Toggle alt. title prompt }
- PC.UserTitle := not PC.UserTitle;
-
- If Parameter = '/W' then { Toggle line wrap }
- PC.LineWrap := not PC.LineWrap;
-
- If Parameter = '/2' then { Toggle print to LPT2 }
- If OutputDest = 'LPT1' then
- OutputDest := 'LPT2'
- else
- OutputDest := 'LPT1';
-
- end;
-
- With PC do
- DoHeader := FileDate or FileTitle or PgNumber or UserTitle;
-
- If Wide then
- begin
- Booklet := False;
- PC.LineLen := WideLineLength;
- end
- else
- PC.LineLen := NarrowLineLength;
-
- If not PrintFront and not PrintBack then
- begin
- Writeln;
- Writeln('** Nothing to print **');
- If Tune then Beep;
- Halt;
- end;
-
- Repeat
- If Pathname = '' then
- begin
- If Tune then Beep;
- Writeln;
- Write('Enter file name to print: ');
- Readln( Pathname );
- If Pathname = '' then Halt;
- end;
-
- FindFirst( Pathname, Archive+Hidden+Readonly, DirInfo );
- If DosError <> 0 then
- begin
- If Tune then Beep;
- Writeln('** Error opening input file: ',Pathname,' **');
- Writeln;
- Writeln('Press any key to try again or ESC to quit.');
- Writeln;
-
- If Press_A_Key = Escape then
- Halt
- else
- Pathname := '';
- end;
- Until Pathname <> '';
-
- Success := False;
- Repeat
- If AlternateFile then
- begin
- Writeln;
- If Tune then Beep;
- Write('Enter the alternate output file: ');
- Readln( Temp );
- If Temp <> '' then OutputDest := Temp;
- end;
-
- Assign( OutFile, OutputDest );
- {$I-} ReWrite( OutFile ); {$I+}
-
- If IOResult = 0 then
- Success := True
- else
- begin
- If Tune then Beep;
- Writeln('** Cannot open output file: ',OutputDest,' **');
- Writeln;
- Writeln('Press any key to try again or ESC to quit.');
- Writeln;
-
- AlternateFile := True; { Give them a chance to change dest. }
-
- If Press_A_Key = Escape then
- Halt
- else
- OutputDest := 'LPT1';
- end;
- Until Success;
-
- If PC.UserTitle then
- begin
- Writeln;
- If Tune then Beep;
- Writeln('Enter a title of up to ',PC.LineLen,' characters: ');
- Write(' >');
- Readln( Temp );
- If Temp <> '' then
- begin
- Title := Temp;
- With PC do
- begin
- FileTitle := False;
- FileDate := False;
- If Length( Title ) > ( PC.LineLen - 8 ) then
- PgNumber := False;
- If Length( Title ) > PC.LineLen then
- Title[0] := Char( PC.LineLen );
- end;
- end;
- end;
-
- Quit := False; { Gets set to TRUE if ESC pressed while printing }
-
- FindFirst( Pathname, Archive+Hidden+Readonly, DirInfo );
- If DosError <> 0 then
- begin
- Writeln('** Error opening input file: ',Pathname,' **');
- If Tune then Beep;
- Halt;
- end;
-
- FSplit( FExpand( PathName ), FPath, FName, FExt );
-
- While ( DosError = 0 ) and not Quit do
- begin
-
- FileName := FExpand( FPath+DirInfo.Name );
- Assign( InFile, Filename );
- {$I-} Reset( Infile, 1 ); {$I+}
-
- If IOResult = 0 then
- begin
-
- CreationDate := GetFileDate;
-
- FSplit( Filename, FPath, FName, FExt );
- HeadingFilename := FName+FExt;
-
- { The pointer array (PTRARRAY) must be initialized to all zeros before
- scanning a particular file. Zero means that page isn't printed. }
-
- FillChar( PtrArray, Sizeof(PtrArray), 0 );
-
- { Scan the file, building an array of pointers to the bytes in the file
- where a new page starts. }
-
- BuildArray( PtrArray, Page );
- Actual_Pages := Page;
-
- { Correct the number of pages to make the number of sheets come out right and
- tell the user how many sheets of paper are required. }
-
- Print_Page_Info;
-
- { Allow the user to select a range of pages to print. The number of pages
- and sheets required are corrected as necessary. }
-
- If Selected_Pages then
- Select_Pages_To_Print;
-
- { If we're just counting, let them bail out instead of printing }
-
- If JustCount then
- begin
- Writeln('Press any key to continue or ESC to exit');
- Writeln;
-
- If Press_A_Key = Escape then
- begin
- Close( InFile );
- Write( OutFile, Esc+'E' ); { Reset the printer }
- Close( OutFile );
- Halt;
- end;
- end;
-
- { Set up the LaserJet and print in the selected format }
-
- If Booklet then
- begin
- Booklet_PrintSetup;
- Booklet_Print;
- end
- else
- If not Wide then
- begin
- Side_By_Side_PrintSetup;
- Side_By_Side_Print;
- end
- else
- begin
- Front_And_Back_PrintSetup;
- Front_And_Back_Print;
- end;
-
- Write( OutFile, Esc+'E' );
- Close( InFile );
-
- end; { If IOResult = 0 }
-
- { Find the next file, if there is one and continue if the user hasn't
- pressed the escape key yet. }
-
- FindNext( DirInfo );
-
- If (DosError = 0) and not Quit then
- begin
- If Tune then Beep;
- Writeln;
- Writeln('Press any key to continue with the next file ',
- 'or ESC to exit.');
-
- If Press_A_Key = Escape then Halt;
- end;
-
- end; { While DosError = 0 }
-
- Close( OutFile );
-
- end.