dos_compilers/Borland Turbo Pascal v7/BIN/PRNFLTR.PAS
2024-07-02 08:21:37 -07:00

498 lines
13 KiB
Plaintext

{************************************************}
{ }
{ Printer output filter exammple }
{ Copyright (c) 1992 by Borland International }
{ }
{************************************************}
program PrinterOutputFilter;
{ Printer filters read input from the IDE by way of StdIn (by using Read
or ReadLn). It then converts the syntax highlight codes inserted into
the text into appropriate printer command codes. This converted text is
then output Lst (which defaults to LPT1).
The syntax highlight codes are in the form of <ESC>#, where '#' is an
ASCII digit from 1($31) to 8($38). The last code sent remains in effect
until another code is found. The following is a list of the codes and
what type of text they represent:
1 - Whitespace (space, tab)
2 - Comment
3 - Reserved word (begin, end, procedure, etc...)
4 - Identifier (Writeln, Reset, etc...)
5 - Symbol (;, :, ., etc...)
6 - String ('string', #32, #$30)
7 - Number (24, $56)
8 - Assembler (asm mov ax,5 end;)
The following printers are supported:
EPSON and compatibles
HP LaserJet II, III, IIP, IID, IIID, IIISi and compatibles
(Italics are available on IIIx, IIP)
ADOBE(R) PostScript(R)
ASCII (simply strips the highlight codes before sending to Lst)
Command line options:
/EPSON - Output EPSON printer codes
/HP - Output HP LaserJet codes
/PS - Output PostScript
/ASCII - Strip highlight codes (Default)
/Lxx - Lines per page (Default 55)
/Txx - Tabsize (Default 8)
/O[file] - Output to file or device (Default LPT1)
}
{$M 2048, 0, 0}
{$I-,S-,X+}
const
MaxAttributes = 8;
type
TPCharArray = array[0..16380] of PChar;
PPCharArray = ^TPCharArray;
PPrinterCodes = ^TPrinterCodes;
TPrinterCodes = record
{ Number of preamble strings in the Preamble array. }
PreambleCount: Byte;
{ Pointer to an array of PChars that define the preamble sequence for
this printer. Sent at the start of a print job. }
Preamble: PPCharArray;
{ Pointer to an array of PChars that define the code sequences for
changing the current attribute. }
CodeArray: PPCharArray;
{ Array of indexes into the CodeArray corresponing to attributes
supported for this printer. }
Attributes: array[0..MaxAttributes - 1] of Byte;
{ Codes sent at the start of a page. }
StartPage: PChar;
{ Codes sent at the end of a page. }
EndPage: PChar;
{ Codes sent at the end of a line. }
EndLine: PChar;
{ Codes sent at the end of the print job. }
Postamble: PChar;
end;
const
{ EPSON Printer code definition }
EpsonItalic = #27'4';
EpsonNoItalic = #27'5';
EpsonBold = #27'E';
EpsonNoBold = #27'F';
EpsonULine = #27'-'#1;
EpsonNoULine = #27'-'#0;
EpsonCodeArray: array[0..7] of PChar = (
EpsonBold,
EpsonNoBold,
EpsonItalic,
EpsonNoItalic,
EpsonULine,
EpsonNoULine,
EpsonBold + EpsonItalic,
EpsonNoBold + EpsonNoItalic);
EpsonCodes: TPrinterCodes = (
PreambleCount: 0;
Preamble: nil;
CodeArray: @EpsonCodeArray;
Attributes: (
0, { Whitespace }
2, { Comment }
1, { Reserved word }
0, { Identifier }
0, { Symbol }
4, { String }
0, { Number }
1); { Assembler }
StartPage: '';
EndPage: #12;
EndLine: #13#10;
Postamble: ''
);
{ HP LaserJet code definition }
HPInit = #27'E'#27'(10U'#27'&k0S'#27'(s3T';
HPItalic = #27'(s1S';
HPNoItalic = #27'(s0S';
HPBold = #27'(s3B';
HPNoBold = #27'(s0B';
HPULine = #27'&dD';
HPNoULine = #27'&d@';
HPCodeArray: array[0..7] of PChar = (
HPBold,
HPNoBold,
HPItalic,
HPNoItalic,
HPULine,
HPNoULine,
HPBold + HPItalic,
HPNoBold + HPNoItalic);
LaserJetPreamble: PChar = HPInit;
LaserJetCodes: TPrinterCodes = (
PreambleCount: 1;
Preamble: @LaserJetPreamble;
CodeArray: @HPCodeArray;
Attributes: (
0, { Whitespace }
2, { Comment }
1, { Reserved word }
0, { Identifier }
0, { Symbol }
4, { String }
0, { Number }
1); { Assembler }
StartPage: '';
EndPage: #12;
EndLine: #13#10;
Postamble: #12
);
{ Raw ASCII definition }
AsciiCodes: TPrinterCodes = (
PreambleCount: 0;
Preamble: nil;
CodeArray: nil;
Attributes: (
0, { Whitespace }
0, { Comment }
0, { Reserved word }
0, { Identifier }
0, { Symbol }
0, { String }
0, { Number }
0); { Assembler }
StartPage: '';
EndPage: #12;
EndLine: #13#10;
Postamble: ''
);
{ PostScript code definition }
PSPreamble0 = #4'%!PS-Adobe-3.0'#13#10+
'initgraphics'#13#10;
PSPreamble1 = '/fnr /Courier findfont 10 scalefont def'#13#10;
PSPreamble2 = '/fni /Courier-Oblique findfont 10 scalefont def'#13#10;
PSPreamble3 = '/fnb /Courier-Bold findfont 10 scalefont def'#13#10;
PSPreamble4 = '/fnbi /Courier-BoldOblique findfont 10 scalefont def'#13#10;
PSPreamble5 = '/newl {20 currentpoint exch pop 12 sub moveto} def'#13#10+
'/newp {20 765 moveto} def'#13#10+
'fnr setfont'#13#10;
PSNormal = 'fnr setfont'#13#10;
PSItalic = 'fni setfont'#13#10;
PSBold = 'fnb setfont'#13#10;
PSBoldItalic = 'fnbi setfont'#13#10;
PSCodeArray: array[0..5] of PChar = (
PSBold,
PSNormal,
PSItalic,
PSNormal,
PSBoldItalic,
PSNormal);
PSPreamble: array[0..5] of PChar = (
PSPreamble0,
PSPreamble1,
PSPreamble2,
PSPreamble3,
PSPreamble4,
PSPreamble5);
PSCodes: TPrinterCodes = (
PreambleCount: High(PSPreamble) - Low(PSPreamble) + 1;
Preamble: @PSPreamble;
CodeArray: @PSCodeArray;
Attributes: (
0, { Whitespace }
2, { Comment }
1, { Reserved word }
0, { Identifier }
0, { Symbol }
3, { String }
0, { Number }
1); { Assembler }
StartPage: 'newp'#13#10;
EndPage: 'showpage'#13#10;
EndLine: 'newl'#13#10;
Postamble: #4
);
{ Special case printer modes. This facilitates indicating a special case
printer such as PostScript }
pmNormal = $0001;
pmPostScript = $0002;
PrintMode: Word = pmNormal;
LinesPerPage: Word = 55;
ToFile: Boolean = False;
TabSize: Word = 8;
var
C, LineCount, TabCount: Integer;
Line, OutputLine: String;
InputBuffer: array[0..4095] of Char;
PrinterCodes: PPrinterCodes;
CurCode, NewCode: Byte;
AKey: Word;
Lst: Text;
procedure UpStr(var S: String);
var
I: Integer;
begin
for I := 1 to Length(S) do S[I] := UpCase(S[I]);
end;
{ Checks whether or not the Text file is a device. If so, it is forced to
"raw" mode }
procedure SetDeviceRaw(var T: Text); assembler;
asm
LES DI,T
MOV BX,WORD PTR ES:[DI]
MOV AX,4400H
INT 21H
TEST DX,0080H
JZ @@1
OR DL,20H
MOV DH,DH
MOV AX,4401H
INT 21H
@@1:
end;
{ Process the command line. If any new printers are to be supported, simply
add a command line switch here. }
procedure ProcessCommandLine;
var
Param: String;
I: Integer;
function ParamVal(var P: String; Default: Word): Word;
var
N, E: Integer;
begin
Delete(P, 1, 1);
Val(P, N, E);
if E = 0 then
ParamVal := N
else
ParamVal := Default;
end;
begin
PrinterCodes := @AsciiCodes;
for I := 1 to ParamCount do
begin
Param := ParamStr(I);
if (Length(Param) >= 2) and ((Param[1] = '/') or (Param[1] = '-')) then
begin
Delete(Param, 1, 1);
UpStr(Param);
if Param = 'EPSON' then
PrinterCodes := @EpsonCodes
else if Param = 'HP' then
PrinterCodes := @LaserJetCodes
else if Param = 'ASCII' then
PrinterCodes := @AsciiCodes
else if Param = 'PS' then
begin
PrinterCodes := @PSCodes;
PrintMode := pmPostScript;
end
else if Param[1] = 'L' then
LinesPerPage := ParamVal(Param, LinesPerPage)
else if Param[1] = 'T' then
TabSize := ParamVal(Param, TabSize)
else if Param[1] = 'O' then
begin
Delete(Param, 1, 1);
Assign(Lst, Param);
Rewrite(Lst);
ToFile := True;
SetDeviceRaw(Lst);
end;
end;
end;
if not ToFile then
begin
Assign(Lst, 'LPT1');
Rewrite(Lst);
SetDeviceRaw(Lst);
end;
end;
{ Flush the currently assembled string to the output }
procedure PurgeOutputBuf;
begin
if OutputLine = '' then Exit;
case PrintMode of
pmNormal: Write(Lst, OutputLine);
pmPostScript:
begin
Write(Lst, '(');
Write(Lst, OutputLine);
Write(Lst, ') show'#13#10);
end;
end;
OutputLine := '';
if IOResult <> 0 then Halt(1);
end;
{ Add the chracter to the output string. Process special case characters
and tabs, purging the output buffer when nessesary }
procedure AddToOutputBuf(AChar: Char);
var
I: Integer;
begin
case AChar of
'(',')','\':
begin
case PrintMode of
pmPostScript:
begin
if Length(OutputLine) > 253 then
PurgeOutputBuf;
Inc(OutputLine[0]);
OutputLine[Length(OutputLine)] := '\';
end;
end;
end;
#9:
begin
if Length(OutputLine) > (255 - TabSize) then
PurgeOutputBuf;
for I := 1 to TabSize - (TabCount mod TabSize) do
begin
Inc(OutputLine[0]);
OutputLine[Length(OutputLine)] := ' ';
end;
Inc(TabCount, TabSize - (TabCount mod TabSize));
Exit;
end;
end;
if Length(OutputLine) > 254 then
PurgeOutputBuf;
Inc(OutputLine[0]);
OutputLine[Length(OutputLine)] := AChar;
Inc(TabCount);
end;
{ End the current page and start a new one }
procedure NewPage(const PCodes: TPrinterCodes);
begin
PurgeOutputBuf;
Write(Lst, PCodes.EndPage);
Write(Lst, PCodes.StartPage);
LineCount := 0;
TabCount := 0;
end;
{ End the current line }
procedure NewLine(const PCodes: TPrinterCodes);
begin
PurgeOutputBuf;
Write(Lst, PCodes.EndLine);
Inc(LineCount);
TabCount := 0;
if LineCount > LinesPerPage then
NewPage(PCodes);
end;
{ Check for the presence of a keypressed and return it if available }
function GetKey(var Key: Word): Boolean; assembler;
asm
MOV AH,1
INT 16H
MOV AL,0
JE @@1
XOR AH,AH
INT 16H
LES DI,Key
MOV WORD PTR ES:[DI],AX
MOV AL,1
@@1:
end;
begin
SetTextBuf(Input, InputBuffer);
ProcessCommandLine;
LineCount := 0;
with PrinterCodes^ do
begin
if PreambleCount > 0 then
for C := 0 to PreambleCount - 1 do
Write(Lst, Preamble^[C]);
if IOResult <> 0 then Halt(1);
LineCount := 0;
CurCode := $FF;
TabCount := 0;
Write(Lst, StartPage);
Line := '';
while True do
begin
if (Line = '') and Eof then
begin
PurgeOutputBuf;
Break;
end;
ReadLn(Line);
if GetKey(AKey) and (AKey = $011B) then
Halt(1);
C := 1;
while C <= length(Line) do
begin
case Line[C] of
#27:
if (Line[C + 1] >= '1') and (Line[C + 1] <= '8') then
begin
NewCode := Attributes[Byte(Line[C + 1]) - $31];
if NewCode <> CurCode then
begin
PurgeOutputBuf;
if (CurCode > 0) and (CurCode < MaxAttributes) then
Write(Lst, CodeArray^[(CurCode - 1) * 2 + 1]);
if (NewCode > 0) and (NewCOde < MaxAttributes) then
Write(Lst, CodeArray^[(NewCode - 1) * 2]);
CurCode := NewCode;
end;
Inc(C);
end;
#12: NewPage(PrinterCodes^);
else
AddToOutputBuf(Line[C]);
end;
Inc(C);
end;
NewLine(PrinterCodes^);
end;
if LineCount > 0 then
Write(Lst, EndPage);
Write(Lst, Postamble);
end;
Close(Lst);
end.