{$S-,R-,V-,I-,N-,B-,F-} {$IFNDEF Ver40} {Allow overlays} {$F+,O-,X+,A-} {$ENDIF} {$DEFINE AssignLstDevice} UNIT Printer; INTERFACE CONST fmClosed = $D7B0; { magic numbers for Turbo } fmInput = $D7B1; fmOutput = $D782; fmInOut = $D7B3; IO_Invalid = $FC; { invalid operation eg. attempt to write } { to a file opened in fmInput mode } LPTNames : ARRAY [0..2] OF STRING [4] = ('LPT1', 'LPT2', 'LPT3'); LPTPort : BYTE = 0; VAR Lst : TEXT; { for source compatability with TP3 } FUNCTION GetROMPrinterStatus (LPTNo : WORD) : BYTE; { status of LPTNo via ROM BIOS int 17h func 2h } INLINE ( $5A / { pop DX ; get printer number} $B4 / $02 / { mov AH,02 ; set AH for BIOS int 17h function 0} $CD / $17 / { int $17 ; do an int 17h} $86 / $E0); { xchg AL,AH ; put byte result in AL} FUNCTION DoInt17 (Ch : CHAR; LPTNo : WORD) : BYTE; { send a character to LPTNo via ROM BIOS int 17h func 0h } INLINE ( $5A / { pop DX ; get printer number} $58 / { pop AX ; get char} $B4 / $00 / { mov AH,00 ; set AH for BIOS int 17h function 0} $CD / $17 / { int $17 ; do an int 17h} $86 / $E0); { xchg AL,AH ; put byte result in AL} PROCEDURE AssignLst (VAR F : TEXT; LPTNumber : WORD); { like Turbo's assign, except associates Text variable with one of the LPTs } PROCEDURE OutputToFile (FName : STRING); {redirect printer output to file } FUNCTION PrinterStatus (LPTNum : BYTE) : BYTE; FUNCTION Printer_OK : BOOLEAN; PROCEDURE SelectPrinter (LPTNum : BYTE); PROCEDURE ResetPrinter; { only resets printer 0 } IMPLEMENTATION TYPE TextBuffer = ARRAY [0..127] OF CHAR; TextRec = RECORD Handle : WORD; Mode : WORD; BufSize : WORD; Private : WORD; BufPos : WORD; BufEnd : WORD; BufPtr : ^TextBuffer; OpenFunc : POINTER; InOutFunc : POINTER; FlushFunc : POINTER; CloseFunc : POINTER; { 16 byte user data area, I use 4 bytes } PrintMode : WORD; { not currently used} LPTNo : WORD; { LPT number in [0..2] } UserData : ARRAY [1..12] OF CHAR; Name : ARRAY [0..79] OF CHAR; Buffer : TextBuffer; END; CONST LPTFileopen : BOOLEAN = FALSE; VAR LPTExitSave : POINTER; PROCEDURE Out_Char (Ch : CHAR; LPTNo : WORD; VAR ErrorCode : INTEGER); { call macro to send char to LPTNo. If bit 4, the Printer Selected bit } { is not set upon return, it is assumed that an error has occurred. } BEGIN ErrorCode := DoInt17 (Ch, LPTNo); IF (ErrorCode AND $10) = $10 THEN { if bit 4 is set } ErrorCode := 0 { no error } { if bit 4 is not set, error is passed untouched and placed in IOResult } END; FUNCTION LstIgnore (VAR F : TextRec) : INTEGER; { A do nothing, no error routine } BEGIN LstIgnore := 0 { return 0 for IOResult } END; FUNCTION LstOutput (VAR F : TextRec) : INTEGER; { Send whatever has accumulated in the Buffer to int 17h } { If error occurs, return in IOResult. See Inside Turbo } { Pascal chapter of TP4 manual for more info on TFDD } VAR I : WORD; ErrorCode : INTEGER; BEGIN LstOutput := 0; WITH F DO BEGIN FOR I := 0 TO PRED (BufPos) DO BEGIN Out_Char (BufPtr^ [I], LPTNo, ErrorCode); { send each char to printer } IF ErrorCode <> 0 THEN BEGIN { if error } LstOutput := ErrorCode; { return errorcode in IOResult } EXIT { return from function } END END; BufPos := 0 END; END; PROCEDURE AssignLst (VAR F : TEXT; LPTNumber : WORD); { like Turbo's assign, except associates Text variable with one of the LPTs } BEGIN WITH TextRec (F) DO BEGIN Mode := fmClosed; BufSize := SIZEOF (Buffer); BufPtr := @Buffer; OpenFunc := @LstIgnore; { you don't open the BIOS printer functions } CloseFunc := @LstIgnore; { nor do you close them } InOutFunc := @LstOutput; { but you can Write to them } FlushFunc := @LstOutput; { and you can WriteLn to them } LPTNo := LPTNumber; { user selected printer num (in [0..2]) } MOVE (LPTNames [LPTNumber], Name, 4); { set name of device } BufPos := 0; { reset BufPos } END; END; PROCEDURE OutputToFile (FName : STRING); BEGIN ASSIGN (Lst, FName); REWRITE (Lst); LPTFileopen := TRUE; END; FUNCTION PrinterStatus (LPTNum : BYTE) : BYTE; VAR Status : BYTE; BEGIN Status := GetROMPrinterStatus (LPTNum); IF (Status AND $B8) = $90 THEN PrinterStatus := 0 {all's well} ELSE IF (Status AND $20) = $20 THEN PrinterStatus := 1 {no Paper} ELSE IF (Status AND $10) = $00 THEN PrinterStatus := 2 {off line} ELSE IF (Status AND $80) = $00 THEN PrinterStatus := 3 {busy} ELSE IF (Status AND $08) = $08 THEN PrinterStatus := 4; {undetermined error} END; FUNCTION Printer_OK : BOOLEAN; VAR Retry : BYTE; BEGIN Retry := 0; WHILE (PrinterStatus (LPTPort) <> 0) AND (Retry < 255) DO INC (Retry); Printer_OK := (PrinterStatus (LPTPort) = 0); END; {PrinterReady} PROCEDURE SelectPrinter (LPTNum : BYTE); BEGIN IF (LPTNum >= 0) AND (LPTNum <= 3) THEN LPTPort := LPTNum; AssignLst (Lst, LPTPort); { set up turbo 3 compatable Lst device } REWRITE (Lst); END; PROCEDURE ResetPrinter; VAR address : INTEGER ABSOLUTE $0040 : $0008; portno, DELAY : INTEGER; BEGIN portno := address + 2; Port [portno] := 232; FOR DELAY := 1 TO 2000 DO {nothing} ; Port [portno] := 236; END; {ResetPrinter} PROCEDURE LptExitHandler; FAR; BEGIN IF LPTFileopen THEN CLOSE (Lst); ExitProc := LPTExitSave; END; BEGIN LPTExitSave := ExitProc; ExitProc := @LptExitHandler; {$IFDEF AssignLstDevice} LPTPort := 0; AssignLst (Lst, LPTPort); { set up turbo 3 compatable Lst device } REWRITE (Lst); {$ENDIF} END.