[Back to PRINTING SWAG index]  [Back to Main SWAG index]  [Original]

{$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.

[Back to PRINTING SWAG index]  [Back to Main SWAG index]  [Original]