home *** CD-ROM | disk | FTP | other *** search
- title LPTx : Line PrinTer Output Capture Routine
- page 60,132
- ;------------------------------------------------------------
- ;
- ; MAIN PROGRAM Version 6.00
- ;
- ; (C) Copyright 1987 by Mark DiVecchio, All Rights Reserved
- ;
- .xlist
- ;
- ;This program is released for use in non-commercial environments. I
- ;ask commercial users to register the program with a $25 copyright fee for
- ;each site (any number of users and computers) at which the program is used.
- ;
- ; DISCLAMER : this program tries to perform a function which is
- ; not supported by DOS. It will work sometime and will not work
- ; other times. That kind of explains why you don't see this type
- ; of program on the market.
- ; I have tested it under DOS 2.1 and DOS 3.1. Some users have
- ; reported trouble when running under DOS 3.x and for other users
- ; it works fine. USE AT YOUR OWN RISK.
- ;
- ; Mark C. DiVecchio
- ; 10435 Mountain Glen Terrace
- ; San Diego, CA 92131
- ; 619-566-6810
- ;------------------------------------------------------------
- ; Updates for Version 6.00 18 Mar 87
- ;
- ; Added use of Timer Interrupt and Idle interrupt to permit
- ; writing to disk
- ;
- ; Added a switch to inhibit the output of linefeed characters when
- ; capturing a file. Program strips linefeed character at the
- ; end of the line if you turn on this switch. The switch is -l on the
- ; command line when you open a capture file.
- ;
- ; This version does not use the PSP swapping of previous versions.
- ;
- ;------------------------------------------------------------
- ; Updates for Version 5.02 19 Nov 86
- ;
- ; Added -i inactivate option. Must be only option on command line :
- ; lptx -i
- ;
- ; This version adds a check for DOS interuupt 21h
- ; function 40h for standard printer device = 0004.
- ;
- ; This addition was suggested by Dale Letterman of Seattle.
- ;
- ; Assembled using MicroSoft MASM v 4.0
- ;
- ; Program is called and used in the same way as version 3.00
- ;
- ; I now enter DOS with interrupts disabled.
- ;
- ; Added a switch to inhibit the checking of the Critical Section Flag
- ; Add -x to the command line the first time that you run LPTx.
- ;
- ;------------------------------------------------------------
- ; Updates for Version 5.00 13 May 86
- ;
- ; This version also takes over the DOS interuupt 21h and specifically
- ; checks for function 5.
- ; If that is the call, LPTx captures the character if LPTx has been
- ; activated. If it is a DOS call, LPTx assumes that DOS wants LPT1 since
- ; there is no way for the DOS call to specify a line printer number.
- ;
- ; Uses undocumented DOS int 21h calls 50h and 51h.
- ; 50h Set new current Program Segment Prefix(PSP) from
- ; segment number in BX
- ; 51h Get current PSP into BX.
- ; These calls are used before any file is opened by the resident portion
- ; of LPTx. There is some concern that DOS puts information about open files
- ; into the current PSP. Before we open our spooler file, we want to set
- ; the current PSP to our PSP and then restore it after the file I/O
- ; is complete. This idea was expressed in PC Magazine May 13, 1986 on page
- ; 314 in an article by Charles Petzold.
- ;
- ;
- ; This version 5.0 does not obsolete versions 4.0 and 3.0. Those versions
- ; may work under some conditions where this one does not and vica versa.
- ;------------------------------------------------------------
- ; Updates for Version 4.01 5 May 86
- ;
- ; Had an error in the way LPTx detected if it was already in memory.
- ; This error existed from back in version 3.00 and may have been
- ; the cause of this program locking up the system the very first
- ; time it was called.
- ;------------------------------------------------------------
- ; Updates for Version 4.0 25 April 86
- ;
- ; Assembled using MicroSoft MASM v 4.0
- ;
- ; Program is called and used in the same way as version 3.00
- ;
- ; Modified the code to check if DOS was running when the print interrupt
- ; occurs. If so the print request is routed back to the regular line
- ; printer. This will limit the use of this capture program to user
- ; programs which do their own output without going to DOS.
- ;
- ; In turn, this guarantees that we do re-enter DOS.
- ;
- ; The trick of saving the DOS stack was dropped in this version and
- ; I have resorted to another trick which I garnered from the
- ; following message found on info-ibmpc. I use method number 2.
- ;
- ; This version 4.0 does not obsolete version 3.0. That version may
- ; work under some conditions where this one does not and vica versa.
- ; This one worked fine for me using DOS 2.1 and 123 version 1.A.
- ; Will not work with Shift PrtSc.
- ;
- comment *
- Date: Thu, 30 Jan 86 08:47:51 est
- Subject: File I/O from resident programs
- To: allegra!seismo!usc-isib.arpa!info-ibmpc
-
- Regarding opening up a file when you are terminate-and-stay-resident:
-
- Be very careful when you attempt this. Many an FAT has been eaten for
- lunch when I first tried doing it. Two ways that work like a charm:
-
- 1) Take over interrupt 0x28. This interrupt gets called by DOS
- while its waiting for a key to be hit. Whenever it does get
- called (your program should not be time critical, btw, as
- this routine is never called from CPU intensive tasks), it
- is safe to do with DOS what you will. (Except for certain
- interruptions, such as Search First and Search Next, which
- either you'll screw-up for the foreground task, or they'll
- screw-up for you.)
-
- 2) Get the Critical Section Flag by issuing an int 21, with ah=0x34.
- This returns a pointer to a flag in ES:BX. When this flag is
- NULL, and interrupts are on, it is safe to play DOS games.
- Unless you are the last program to take over the interrupt,
- don't trust the flag word: many "fine" programs like SideKick
- do not give you a true copy of the flag word on the stack, but
- rather give a simple "pushf" after interrupts are turned off.
- * ;end of comment
- ;
- ; More information from a message posted on USENIX:
- ;
- comment *
- From sdcsvax!ihnp4!timeinc!greenber Mon Jul 1 05:12:16 1985
- Date: 30 Jun 85 17:12:37 CDT (Sun)
- -----------------------------------------------------------
- INT 21 - Internal - Return CritSectFlag Pointer (MSDOS generic)
- REG AH = 34H
- On Return:
- ES:BX points to DOS "Critical Section Flag"
- When byte pointed to is zero, DOS is supposed to be
- safe to interrupt. NOT RELIABLE according to Chris
- Dunford.
- Examination of DOS 2.10 code in this area
- indicates that the byte immediately FOLLOWING this
- "Critical Section Flag" must be 00 to permit the
- PRINT.COM interrupt to be called. This suggests that
- checking the WORD pointed to, rather than the BYTE,
- might increase reliability of the test greatly.
- -----------------------------------------------------------
- INT 28 - Internal routine for MSDOS
- This interrupt is called from inside the "get input
- from keyboard" routine in DOS, if and only if it is safe to use
- INT 21 to access the disk at that time. It is used primarily by
- the PRINT.COM routines, but any number of other routines could
- be chained to it by saving the original vector, and calling it
- with a FAR call (or just JMPing to it) at the end of the new
- routine.
- Until PRINT.COM installs its own routine, this
- interrupt vector simply points to an IRET opcode.
- -----------------------------------------------------------
- * ;end of comment
- ;
- ;------------------------------------------------------------
- ; Updates for Version 3.0
- ;
- ; This version is fully compatible with IBM's PRINT command and
- ; hopefully most other print spoolers. I changed the method by which
- ; LPTx determines if a resident copy of itself is already in memory.
- ;
- ;------------------------------------------------------------
- ; This program intercepts the BIOS interrupt 17, the line printer
- ; interrupt. It will redirect the output of LPT1, LPT2, or LPT3 to a disk
- ; file. All three redirects may be active at the same time.
- ;
- ;
- ; Background:
- ;
- ; The basic problem with this type of program is that PC-DOS as written
- ; by Microsoft is not re-entrant. That means that if DOS is in control when
- ; the print interrupt occurs, you can not call DOS again to do some other
- ; function. Therefore, LPTx can not call DOS to write the captured print
- ; data to disk. Version 3.00 of LPTx tries to get around this by making
- ; PC-DOS re-entrant. Version 4.00 of LPTx gets around this by not ever
- ; trying to re-enter DOS.
- ;
- ;*******This Program Must be Converted to a .COM file before running ******
- ; Assemble with :
- ; masm lptx;
- ; link lptx;
- ; exe2bin lptx,lptx.com
- ; erase lptx.obj
- ; erase lptx.exe
- ;
- ;-----------------------------------------------------------------
- .list
- if1
- %out Pass 1 - Including Macros - v6.00
- ;
- .xlist
- ;-----------------------------------------------------------------
- ;
- ; Macros
- ;
- display macro msg
- mov DX,offset msg
- mov AH,DISPLAY_OUTPUT
- int DOS_CALL
- endm
- ;
- ; For the PC-AT:
- ; POPF macro described in the IBM Personal Computer
- ; Seminar Proceedings Volume 2, Number 4 September 1984
- ; QUOTE
- ; "If the system microprocessor executes a POPF instruction in either
- ; the real or the virtual address mode with CPL <= IOPL, then a
- ; pending maskable interrupt (the INTR pin active) may be improperly
- ; recognized after executing the POPF instruction even if maskable
- ; interrupts were disabled before the POPF instruction and the value
- ; popped had IF=0. If the interrupt is improperly recognized, the
- ; interrupt is still correctly executed. This errata has no effect
- ; when interrupts are enabled in either real or virtual address mode.
- ; The errata has no effect in the virtual address mode when
- ; CPL > IOPL."
- ;
- popff macro ;use POPFF instead of POPF
- local popem,skip
- ;simulate popping flags using IRET
- jmp short skip ;jump around iret
- popem:
- iret ;pop CS,IP,flags
- skip:
- push CS
- call popem ;call within segment
- ;program will continue here
- endm
-
- ;
- call_dos macro ;Enter DOS with interrupts disabled
- cli
- int DOS_CALL
- sti
- endm
- ;
- ;
- .list
- else
- %out Pass 2
- endif
- ;-----------------------------------------------------------------
- NULL equ 0
- OFF equ 0
- ON equ 1
- EMPTY equ 0
- BEL equ 7
- CR equ 13
- LF equ 10
- DOLLAR equ '$'
- COLON equ ':'
- BACKSLASH equ '\'
- BLANK equ ' '
- DASH equ '-'
- DOS_CALL equ 21h
- ;
- REQ equ 00B90h ;LPTx request flag
- ACK equ 0ABBBh ;LPTx acknowledge flag
- ;
- BUFSIZE equ 4096 ;size of DMA buffer
- DISPLAY_OUTPUT equ 9 ;for DOS call
- DEF_DRIVE equ 19h
- CREATE_FILE equ 3Ch
- OPEN_FILE equ 3Dh
- CLOSE_FILE equ 3Eh
- WRITE_FILE equ 40h
- DELETE_FILE equ 41h
- LSEEK_FILE equ 42h
- DEF_PATH equ 47h
- FIND_FILE equ 4Eh
- ;-----------------------------------------------------------------
- ;
- p_block struc
- ;
- ; data structure - these variables are used only in the
- ; memory resident copy of LPTx. BX is set to point to the offset of the
- ; allocation of this structure for the selected LPT
- ; NOTE : all of the labels in this structure are required as place
- ; holders even if not referenced. Used by the initialization calls
- ; later on.
- ;
- active db OFF ;ON = this LPTx is on, OFF = off
- handle dw NULL ;handle of disk file used by this LPT
- filen db 'a:\lptx' ; space for redirection disk file name
- pnum db BLANK
- db '.lst',NULL
- db ' '
- db ' '
- bufcntr dw EMPTY ;bytes used in DMA buffer for this LPT
- request db OFF ;ON indicates a write request is active
- ;for this LPT
- prt_status db 10h ;printer status for this LPT
- linefeed db ON ;ON = output a linefeed
- ;OFF = don't output a linefeed
- buffer db BUFSIZE dup(0) ;data buffer for this LPT
- ;
- p_block ends
- ;
- ;-----------------------------------------------------------------
- ;
- subttl Main Code
- page
- %out Assembling CODE Segment
- cseg segment para public 'CODE'
- assume CS:cseg,DS:nothing,SS:nothing
- org 100h
- lptx: jmp lptx_start
- ;
- ; What follows are three allocations of the Structure p_block
- ; One for each line printer that we can support.
- ; With this, all three line printers have DMA buffers and flag
- ; variables.
- ; BX is used to point to the offset of the allocation currently in use
- ; Line printer 1
- lpt1 p_block <,,,'1'>
- ; Line printer 2
- lpt2 p_block <,,,'2'>
- ; Line printer 3
- lpt3 p_block <,,,'3'>
- ;
- crit_flag db OFF ;set to ON if critical error occured
- off_crit dw 0 ;save old critical error address
- seg_crit dw 0
- ;
- csect_off dw 0 ;pointer to Critical Section flag
- csect_seg dw 0
- ; cs_switch can be cleared by the transient copy of LPTx
- cs_switch db ON ;enable check of Critical Section flag
- P_NORMAL equ 90h ;Printed selected and ready
- P_TIMEOUT equ 01h ;Time out
- save_psp dw 0 ;Save area for User's PSP Segment Address
- lptx_psp dw 0 ;Our PSP Segment Address
- byte_count dw 0 ;to save DOS byte count
- busy db OFF ;ON indicates write is taking place
- sound db OFF ;ON uses speaker to indicate progress of LPTx
- ; Old interrupt vector addresses
- old_08h dd 0 ;address of old int 08h routine
- old_17h dd 0 ;address of old int 17h routine
- old_21h dd 0 ;address of old int 21h routine
- old_28h dd 0 ;address of old int 28h routine
- ; New Stack for Interrupt 17h
- stk1_save dd 0 ;caller's stack EA
- db 128 dup('STACK ')
- stk1 equ this byte - 4
- ; New Stack for Interrupts 08h and 28h
- stk2_save dd 0 ;caller's stack EA
- db 128 dup('STACK ')
- stk2 equ this byte - 4
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 17h
- ;
- int_17h proc far
- sti ;interrupts on
- cmp AH,3 ;AH=3 for LPTx Function
- jne reg_call ;This is a regular print call
- jmp ret_ack ;This is an LPTx Call
- reg_call:
- push BX
- ; set up BX to point to the data area for the requested printer
- cmp DX,0 ;lpt1?
- jne chk_lpt2 ;no
- mov BX,offset lpt1 ;offset to LPT1
- jmp short bx_set
- chk_lpt2:
- cmp DX,1 ;lpt2?
- jne chk_lpt3 ;no
- mov BX,offset lpt2 ;offset to LPT2
- jmp short bx_set
- chk_lpt3:
- cmp DX,2 ;lpt3?
- jne ill_ptr ;no - bad printer number
- mov BX,offset lpt3 ;offset to LPT3
- bx_set:
- cmp CS:[BX].active,OFF ;are we active?
- je sleep17 ;no
- mov CS:[BX].prt_status,P_NORMAL ;signal ready status
- cmp AH,1 ;initialize call?
- je do_nix ;yes
- cmp AH,2 ;status call?
- je do_nix ;yes
- cmp AH,0 ;print call?
- jne do_nix ;no
-
- jmp prt_17 ;we are active
- do_nix: mov AH,CS:[BX].prt_status ;return print status
- rtn: pop BX
- iret
- ;
- ill_ptr:mov CS:[BX].prt_status,P_TIMEOUT ;time out status
- jmp do_nix
- ;
- ret_ack: ;return acknowledgement that I'm here
- ; note : Change REQ & ACK from version to version so two versions
- ; of LPTx don't get intermixed.
- cmp DX,REQ ;my flag to detect that LPTx is
- ;already loaded and alive.
- jne ret_nak ;return a NAK
- mov DX,ACK ;Memory resident LPTx answers with ACK
- push CS ;now set up ES to point to the resident
- pop ES ; data area
- ret_nak:
- iret ;return to calling program
- ;
- sleep17:pop BX ;restore BX before we go to sleep
- jmp dword ptr CS:old_17h ;jump immediate to original handler
- ;
- prt_17:
- push AX ; Start the print process.
- push BX ; Character is in AL.
- push CX
- push DX
- push DS
- push ES
- push SI
- push DI
- push BP
- ;
- push CS ; DS is used as the segment register
- pop DS ; for all data during the interrupt
- ;
- pushf
- cli
- mov SI,SS
- mov word ptr DS:stk1_save+2,SI ;save caller's stack pointer
- mov SI,SP
- mov word ptr DS:stk1_save,SI
- mov SI,CS
- mov SS,SI ;give me new bigger stack
- mov SI,offset stk1
- mov SP,SI
- popff
- mov DS:[BX].prt_status,P_NORMAL ;signal ready status
- ;prt_status is set before
- ;the call to prnt so that prnt
- ;can change it if the print to
- ;disk fails
- call prnt ;print the character
- ;
- pushf
- cli
- mov SI,word ptr DS:stk1_save
- mov SP,SI ;restore caller's stack pointer
- mov SI,word ptr DS:stk1_save+2
- mov SS,SI
- popff
-
- pop BP
- pop DI
- pop SI
- pop ES
- pop DS
- pop DX
- pop CX
- pop BX
- pop AX
- jmp do_nix
- int_17h endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 21h
- ;
- int_21h proc far
- sti ;interrupts on
- push BX
- cmp AH,5 ;is this a DOS printer call?
- je int_21h_5 ;yes
- cmp AH,40h ;is this a DOS write call?
- je int_21h_40 ;yes
- jmp sleep21 ;no - go on to real DOS
- ; DOS Function 40h - Write to File or Device. DS:DX contains the address
- ;of data to write. CX contains the byte count. Return AX = byte count.
- int_21h_40:
- cmp BX,0004 ;Standard Printer?
- jne sleep21 ;no - go on to real DOS
- ; set up BX to point to the data area for the requested printer
- ; Since we don't know what the standard printer device is, we
- ; use LPT1
- mov BX,offset lpt1 ;offset to LPT1
- cmp CS:[BX].active,OFF ;are we active?
- je sleep21 ;no
- push AX ;now do it
- push BX
- push CX
- push DX
- mov CS:byte_count,CX ;save byte count
- mov BX,DX
- ;DS:BX points to buffer, CX has byte count
- cmp CX,EMPTY ;check for zero byte count
- je prt_21_done
- loop21_40:
- mov AL,[BX] ;get a character
- mov AH,0 ;set up for call to interrupt 17h
- int 17h ;note : int17h returns a printer status
- ;in AH but DOS does not define a way
- ;to return that status
- inc BX
- loop loop21_40
- prt_21_done:
- pop DX
- pop CX
- pop BX
- pop AX
- mov AX,CS:byte_count;DOS returns byte count
- jmp exit21 ;to return it to the user.
- ;
- int_21h_5:
- ; DOS Function 5 Printer Output. The Character in DL is output to the
- ; standard printer device.
- ;
- ; set up BX to point to the data area for the requested printer
- ; Since we don't know what the standard printer device is, we
- ; use LPT1
- mov BX,offset lpt1 ;offset to LPT1
- cmp CS:[BX].active,OFF ;are we active?
- je sleep21 ;no
-
- push AX
- mov AH,0 ;set up for call to interrupt 17h
- mov AL,DL ;the character
- int 17h
- pop AX
- ;note : int17h returns a printer status
- ;in AH but DOS does not define a way
- ;to return it to the user.
- exit21: pop BX
- popff ;restore flags
- clc ;never an error from us
- ret ;return to caller (regular FAR return)
- ;
- sleep21:pop BX ;restore BX before we go to sleep
- jmp dword ptr CS:old_21h
- int_21h endp
- ;
- ;-----------------------------------------------------------------
- ;
- ; PRNT - Print a character in AL
- ;
- prnt proc near
- push DS
- cmp DS:[BX].active,OFF
- je prtext ;nothing there?
- push AX
- cmp DS:[BX].bufcntr,BUFSIZE/2 ;buffer half full?
- jne intadd ;no
- ;
- ; set write request but don't actually write anything out.
- ; we hope that the write can take place before the buffer fills up
- ;
- mov DS:[BX].request,ON
- cmp DS:sound,OFF ;sound on?
- je intadd ;no
- call horn ;sound horn to indicate buffer
- ; write request has been made
- ;
- intadd: pop AX
- cmp AL,LF ;is it a linefeed?
- jne intnolf ;no
- cmp DS:[BX].linefeed,OFF ;we are stripping linefeeds?
- je prtext ;yes
- intnolf:
- mov DI,BX ;offset of this printer's allocation
- add DI,offset buffer ;add in offset of buffer
- add DI,DS:[BX].bufcntr ;add in current byte count
- mov DS:[DI],AL ;stuff it
- inc DS:[BX].bufcntr
- cmp DS:[BX].bufcntr,BUFSIZE ;buffer overflow?
- jne prtext ;no
- mov DS:[BX].active,OFF ;yes, nothing to do but deactivate
- ; LPTx
- cmp DS:sound,OFF ;sound on?
- je prtext ;no
- call beep ;sound beep twice to indicate that
- call beep ;we have been deactivated
- prtext: pop DS
- ret ;done
- prnt endp
- ;-----------------------------------------------------------------
- ;
- ; Critical Error Handler
- ;
- crit_int proc far ;got critical error
- mov CS:crit_flag,ON ; set flag
- mov AL,0 ;tells DOS to ignore the
- iret ;error
- crit_int endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 08h - clock ticks
- ;
- ; This function is installed as a handler for hardware interrupt
- ; type 8. It first calls the previous int 08h handler to service
- ; the INTEL 8259 Programmable Interrupt Controller. Then it checks
- ; to see if any write requests are pending. If so, it calls do_save
- ; and flush to write the buffer to the disk. Note that int_08h
- ; checks the DOS critical section flag : do_save is called only if
- ; DOS is available.
- ;
- ; This function protects itself against secondary invocations by
- ; means of the global busy flag.
- ;
- int_08h proc far
- ; call original int 8h handler - ALWAYS
- pushf
- call dword ptr CS:old_08h
- ; now we can process if possible
- pushf
- cli
- cmp CS:busy,OFF ;can we process this?
- jne i08_exit ;no
- ; if DOS is in its critical section, we skip the write for now and
- ; hope that we can write before the buffer fills
- cmp CS:cs_switch,OFF ;is checking off?
- je no_cs ;yes, don't check the flag
- push DS ; check the critical section flag
- push SI
- lds SI,dword ptr CS:csect_off
- cmp byte ptr [SI],OFF
- pop SI
- pop DS
- jne i08_exit ;DOS in critical section
- ;this indicates that we cannot
- ;do any disk operations at this
- ;time
- no_cs:
- ; set busy flag
- mov CS:busy,ON
- call do_save
- mov CS:busy,OFF
- i08_exit:
- popff
- iret
- int_08h endp
- ;-----------------------------------------------------------------
- ;
- ; Interrupt handler for interrupt 28h - idle
- ;
- ; This function is installed as a handler for hardware interrupt
- ; type 28h. It first calls the previous int 28h handler. Then it checks
- ; to see if any write requests are pending. If so, it calls do_save
- ; and flush to write the buffer to the disk. It does not check the
- ; Critical Section Flag as int 28h handlers are allowed to perform
- ; DOS disk I/O but not keyboard I/O since most of the time int 28h
- ; is called by the keyboard I/O routines when they are waiting
- ; for a key press.
- ;
- ; This function protects itself against secondary invocations by
- ; means of the global busy flag.
- ;
- int_28h proc far
- ; call original int 28h handler - ALWAYS
- pushf
- call dword ptr CS:old_28h
- ; now we can process if possible
- pushf
- cli
- cmp CS:busy,OFF ;can we process this?
- jne i28_exit ;no
- ; set busy flag
- mov CS:busy,ON
- call do_save
- mov CS:busy,OFF
- i28_exit:
- popff
- iret
- int_28h endp
- ;------------------------------------------------------------
- ;
- ; Writes buffer to disk
- ;
- do_save proc near
- push AX ; Start the print process.
- push BX ; Character is in AL.
- push CX
- push DX
- push DS
- push ES
- push SI
- push DI
- push BP
- pushf
- sti ;interrupts on
- ;
- push CS ; DS is used as the segment register
- pop DS ; for all data during the interrupt
- ;
- pushf
- cli
- mov SI,SS
- mov word ptr DS:stk2_save+2,SI ;save caller's stack pointer
- mov SI,SP
- mov word ptr DS:stk2_save,SI
- mov SI,CS
- mov SS,SI ;give me new bigger stack
- mov SI,offset stk2
- mov SP,SI
- popff
- ;
- ; check to see if any write requests are active.
- ; we do not look at the active flag since the print redirection
- ; may have been inactivated by the time, we are able to write to
- ; the disk.
- ;
- ; set up BX to point to the data area for the requested printer
- mov BX,offset lpt1 ;offset to LPT1
- cmp DS:[BX].request,ON ;write LPT1 request?
- jne c28_lpt2 ;no
- call flush
- mov DS:[BX].request,OFF
- c28_lpt2:
- mov BX,offset lpt2 ;offset to LPT2
- cmp DS:[BX].request,ON ;write LPT2 request?
- jne c28_lpt3 ;no
- call flush
- mov DS:[BX].request,OFF
- c28_lpt3:
- mov BX,offset lpt3 ;offset to LPT3
- cmp DS:[BX].request,ON ;write LPT3 request?
- jne i28_done ;no
- call flush
- mov DS:[BX].request,OFF
- i28_done:
- pushf
- cli
- mov SI,word ptr DS:stk2_save
- mov SP,SI ;restore caller's stack pointer
- mov SI,word ptr DS:stk2_save+2
- mov SS,SI
- popff
- ;
- popff
- pop BP
- pop DI
- pop SI
- pop ES
- pop DS
- pop DX
- pop CX
- pop BX
- pop AX
- ret
- do_save endp
- ;
- ;------------------------------------------------------------
- ;
- ; FLUSH - Flush print buffer to disk file
- ;
- flush proc near
- cmp DS:[BX].bufcntr,EMPTY ;buffer empty?
- jne flush_buf ;no, write it to disk
- ret ;exit
- flush_buf:
- call disk_out
- ret
- flush endp
- ;------------------------------------------------------------
- ;
- ; DISK_OUT - write to disk
- ;
- disk_out proc near
- ;PSP
- ; push BX
- ; mov AH,51h ;get current PSP
- ; call_dos
- ; mov DS:save_psp,BX ;and save it
- ; mov BX,DS:lptx_psp ;get our PSP
- ; mov AH,50h
- ; call_dos ;set it into DOS
- ; pop BX
- ;
- push ES
- push DS
- mov AX,DS ;set up ES
- mov ES,AX
- push BX
- push ES
- mov AX,3524h ;get old critical error vector
- call_dos
- mov DS:off_crit,BX
- mov DS:seg_crit,ES
- mov DX,offset crit_int
- mov AX,2524h
- call_dos ;trap critical error vector
- mov DS:crit_flag,OFF ;clear critical error flag
- pop ES
- pop BX
- mov DX,BX ;open file
- add DX,offset filen ;filename
- mov AL,1 ;open for writing
- mov AH,open_FILE
- call_dos
- mov DS:[BX].handle,AX ;file handle
- jc disk_err ;error
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- push BX
- mov AH,lseek_FILE
- mov AL,2 ;end of file
- mov CX,0 ;offset 0
- mov DX,0
- mov BX,DS:[BX].handle
- call_dos
- pop BX
- jc disk_err ;some seek error
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- mov CX,DS:[BX].bufcntr ;buffer size
- mov DX,BX ;offset of structure allocation
- add DX,offset buffer ;add offset of buffer within the
- ; allocation
- push BX
- mov AH,write_FILE
- mov BX,DS:[BX].handle ;file handle
- call_dos ;buffer address is DS:DX
- pop BX
- jnc disk_ok
- cmp DS:crit_flag,ON ;critical error?
- je disk_err ;yes
- cmp AX,DS:[BX].bufcntr ;did DOS write it all?
- je disk_ok ;yes
- disk_err:
- call beep ;ring bell 4 times
- call beep
- call beep
- call beep
- mov DS:[BX].active,OFF ;turn us off
- mov DS:crit_flag,OFF ;clear error flag
- mov DS:[BX].prt_status,P_TIMEOUT ;signal time out error
- ;then try to close the file
- ;to save what we can
- jmp disk_close
- disk_ok:
- mov DS:[BX].bufcntr,EMPTY ;set buffer empty
- disk_close:
- push BX
- mov BX,DS:[BX].handle
- mov AH,close_FILE ;close the file
- call_dos
- pop BX
- disk_exit:
- pop DS
- pop ES
- push DS
- lds DX,dword ptr DS:off_crit
- mov AX,2524h ;restore critical error vector
- call_dos
- pop DS
- ; PSP
- ; push BX
- ; mov BX,DS:save_psp ;get user's PSP
- ; mov AH,50h
- ; call_dos ;set it back into DOS
- ; pop BX
- ;
- ret
- disk_out endp
- ;
- ;--------------------------------------------------------------
- ;
- ; Routine to sound the beeper
- ;
- note equ 0a98h ;2712 = 1193180. / 440Hz
- beep proc near
- push AX
- push BX
- push CX
- push DX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,note ;get note
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,07FFFh
- beep_lp:loop beep_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,03FFFh
- beep1_lp:loop beep1_lp
- pop DX
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- beep endp
- ;-------------------------------------------------------------------
- ;
- ; Routine to sound a key click
- ;
- key_clk equ 036h ;59 = 1193180. / 20,000Hz
- click proc near
- push AX
- push BX
- push CX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,key_clk ;get note
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,0FFh
- key_lp:loop key_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,0FFh
- key1_lp:loop key1_lp
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- click endp
- ;--------------------------------------------------------------
- ;
- ; Routine to honk the horn
- ;
- horn proc near
- push AX
- push BX
- push CX
- push DX
- mov AL,0b6h ;select tim 2,lsb,msb,binary
- out 43h,AL ;set up timer chip
- mov AX,2e9bh ;2712 = 1193180. / 100Hz
- out 42h,AL ;write timer 2 count: lsb...
- mov AL,AH
- out 42h,AL ;...and msb
- in AL,61h
- mov AH,AL ;save current port setting
- or AL,3
- out 61h,AL ;turn speaker on
- mov CX,07FFFh
- horn_lp:loop horn_lp
- mov AL,AH
- out 61h,AL ;restore port setting
- mov CX,03FFFh
- horn1_lp:loop horn1_lp
- pop DX
- pop CX
- pop BX
- pop AX
- ret ;return to caller
- horn endp
- ;--------------------------------------------------------------------
- end_res db 0
- ;
- ; This is the end of the memory resident portion of LPTx
- ;
- ;--------------------------------------------------------------------
- ;
- ; All of the following data is in the Code Segment
- ;
- mach_type db 0
- DOS_version db 0 ;Major Version Number
- db 0 ;Minor Version Number
- lfeed db ON ;linefeed enable switch
- drive db 0 ;default drive number 0=A etc.
- flag_27 db OFF ; 1=make this copy resident
- wrong_dos db 'DOS 2.0 or later required for LPTx',LF,CR,DOLLAR
- up_msg db 'LPTx - Line Printer Redirection Program - V6.00'
- db LF,CR,' Copyright 1987 Mark C. DiVecchio',LF,CR
- db DOLLAR
- lptx_resident db LF,CR,'Resident Portion of LPTx Loaded',LF,LF,CR
- db DOLLAR
- lptx_err_3 db 'Could not delete file',LF,CR,DOLLAR
- lptx_over db CR,LF,'File already exists. Do you want to overwrite '
- db 'it? (y or n) :',DOLLAR
- lptx_nc db 'File selection canceled',CR,LF,DOLLAR
- lptx_lf db 'Stripping Linefeed Characters',CR,LF,DOLLAR
- lptx_sd_on db 'Sound Enabled',CR,LF,DOLLAR
- lptx_cs_off db 'Critical Section Checking Disabled',CR,LF,DOLLAR
- lptx_del db 'File is being overwritten',LF,CR,DOLLAR
- lptx_cr db LF,CR,DOLLAR
- lptx_bad db 'Invalid Option',LF,CR
- db 'Calling sequence:',LF,CR
- db 'lptx [?] [-x] [-l] [-i] {-1,-2,-3} {-c -o <d:[pathname]filename>}'
- db LF,CR,DOLLAR
- lptx_on db LF,CR,'Redirection started. Disk file opened.'
- db LF,CR,DOLLAR
- lptx_off db LF,CR,'Redirection ended. Disk file closed.'
- db LF,CR,DOLLAR
- lptx_creat db 'Could not create the disk file',LF,CR,DOLLAR
- lptx_gone db LF,'LPTx - Resident portion inactivated',CR,LF,DOLLAR
- ; HELP screen
- help_msg db LF,CR,'Calling sequence : ',LF,LF,CR
- db 'LPTx [?] [-x] [-l] [-i] -p -f <[d:][\pathname\pathname]filename>'
- db LF,LF,CR
- db ' where p = printer number : 1, 2, or 3',LF,CR
- db ' f = function : o for open a print file'
- db LF,CR
- db ' c for close a print file'
- db LF,CR
- db ' drive letter & pathname are optional'
- db LF,CR
- db ' x = disable check of Critical Section Flag',
- db LF,CR
- db ' l = strip Linefeed characters from output',
- db LF,CR
- db ' i = inactivate LPTx',LF,CR
- db ' defaults : p = 1',LF,CR
- db ' f = o',LF,CR
- db DOLLAR
- ;
- stat_stat db CR,LF,'LPTx Status :',CR,LF,DOLLAR
- stat_lp db 'lpt'
- stat_ptr db ' : ',DOLLAR
- stat_off db ' not redirected',CR,LF,DOLLAR
- stat_dir db ' redirected to disk file '
- stat_fn db 60 dup (BLANK)
- ;
- yn_max db 2 ;max # of char
- yn_act db 0
- yn_in db 2 dup (0)
- ;
- ;--------------------------------------------------------------------
- ;
- ; This is the main routine which is executed each time that LPTx is
- ; called. In this routine, DS points to the data segment which is
- ; transient. ES points to the data segment which is permanently
- ; resident. ES:BX points to the data structure for the selected
- ; line printer, 1, 2, or 3.
- ; The offsets are the same for both. If this is the first
- ; time that LPTx is run, then ES=DS.
- ;
- lptx_start:
- push DS ;Save DS
- xor AX,AX ;clear AX for return IP
- push AX ;put 0 on stack
- ;
- ;to check for machine type look at
- ; F000:FFFE ; I don't use this currently
- ; = FF IBM PC
- ; = FE IBM XT or Portable
- ; = FD IBM PCjr
- ; = FC IBM PC AT
- ; = F9 IBM Convertible
- mov AX,0F000h
- mov ES,AX
- mov BX,0FFFEh
- mov CL,ES:[BX] ;get machine type
- mov mach_type,CL ;save machine type
- ;
- ;PSP
- mov lptx_psp,DS ;put away our PSP Segment address
- ;
- ; get the DOS version number
- ; returns zero for pre DOS 2.0 releases
- mov AH,30h
- int DOS_CALL ;call DOS
- mov word ptr DOS_version,AX
- ; Requires at least version 2.0 and may or may not work
- ; with versions above 2.1
- cmp DOS_version,2 ;is it DOS 2.+
- jge dos_ok ;yes
- display wrong_dos ;print error message
- mov AH,0
- int DOS_CALL ;terminate
- dos_ok: mov AH,def_drive ;get current default drive
- int DOS_CALL
- mov drive,AL ;save the drive number
- display up_msg ;print program ID
- mov flag_27,OFF ;to not make resident
- ; is a copy of LPTx already resident in memory?
- mov DX,REQ ;check if LPTx is already resident
- mov AH,3 ;get status - special call
- int 17h ;call int 17h - BIOS
- cmp DX,ACK ;my handler sets DX to ACK
- ;and sets ES
- je in_core ;LPTx is resident - ES loaded with
- ; segment address
- mov flag_27,ON ;to make this copy resident
- push CS
- pop ES ;set ES to CS for segment address
- mov AL,drive
- add AL,'a' ;make it a letter
- mov BX,offset lpt1
- mov ES:[BX].filen,AL ;put it into the filename
- mov BX,offset lpt2
- mov ES:[BX].filen,AL ;put it into the filename
- mov BX,offset lpt3
- mov ES:[BX].filen,AL ;put it into the filename
- ; ----------------------------------------------------
- in_core: ;ES is ok
- ; ES now points to resident data area
- ; set up ES:BX to point to default data structure
- mov BX,offset lpt1 ;offset - default to LPT1
- ;get options and file name
- ;scan input line for line printer number
- mov SI,81h ;starting offset
- mov CL,DS:80h ;length of input line
- mov CH,0
- cmp CX,0 ;nothing?
- jne inp_lp ;no
- jmp make_res ;yes, then just make LPTx resident
- ;if it isn't already
- inp_lp:
- cmp byte ptr DS:[SI],'?' ;a ? ?
- jne cont_scan ;no
- jmp help ;yes - go show help data
- cont_scan:
- cmp byte ptr DS:[SI],dash ;a dash ?
- je got_opt ;yes
- cmp byte ptr DS:[SI],CR ;a carriage return?
- je scan_done ;yes
- cmp byte ptr DS:[SI],BLANK ;a blank?
- je inp_ret ;yes
- jmp no_b ;assume that we got a file name
- ;without the -o option
- inp_ret:
- inc SI ;ignore blanks
- loop cont_scan ;continue to scan
- ;
- ; Scan of whole line is complete without a "-o", "-c" or filename
- scan_done:
- jmp make_res
- ;
- got_opt: ;we got an option
- inc SI ;to option
- cmp byte ptr DS:[SI],'1' ;LPT1?
- jne chk_2
- mov BX,offset lpt1 ;offset from ES
- jmp short inp_ret
- chk_2: cmp byte ptr DS:[SI],'2' ;LPT2?
- jne chk_3
- mov BX,offset lpt2 ;offset from ES
- jmp short inp_ret
- chk_3: cmp byte ptr DS:[SI],'3' ;LPT3?
- jne chk_fil
- mov BX,offset lpt3 ;offset from ES
- jmp short inp_ret
- chk_fil: ;is it file?
- cmp byte ptr DS:[SI],'o' ;open a file
- je file_op ;yes
- cmp byte ptr DS:[SI],'c' ;close a file
- je file_cl ;yes
- cmp byte ptr DS:[SI],'x' ;inhibit check for Critical Section?
- je cs_check_off ;yes
- cmp byte ptr DS:[SI],'l' ;linefeed switch ?
- je lf_off ;yes
- cmp byte ptr DS:[SI],'s' ;enable sound?
- je sound_on ;yes
- cmp byte ptr DS:[SI],'i' ;inactivate?
- jne bad_opt
- jmp inactivate
- bad_opt:
- display lptx_bad ;incorrect option
- jmp nor_ex
- ;
- ; [-x]
- ; turn OFF Critical Section check
- ;
- cs_check_off:
- mov ES:cs_switch,OFF
- display lptx_cs_off
- jmp inp_ret
- ;
- ;[-l]
- ; Turn linefeeds off in captured file
- ;
- lf_off: mov lfeed,OFF ;turn LFs off
- display lptx_lf
- jmp inp_ret ;continue the scan
- ;
- ; [-s]
- ; turn ON Sound
- ;
- sound_on:
- mov ES:sound,ON
- display lptx_sd_on
- jmp inp_ret
- ;
- ; [-c]
- ; close output file
- ;
- file_cl:cmp ES:[BX].active,ON ;are we active?
- jne no_close ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;redirection off message
- no_close:
- jmp nor_exit ;nothing to close so exit
- ;
- ; [-o]
- ; open a file for ouput
- ;
- file_op: ;get the file name
- inc SI ;to next chracter
- cmp byte ptr DS:[SI],BLANK ;a blank?
- jne no_b ;no
- inc SI ;skip over blank
- no_b:
- ; at this point, we have found a new file name. We close the old
- ; file if one was open
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;redirection off message
- no_cl: mov DI,BX ;base of structure
- add DI,offset filen ;add offset of destination
- push SI ;save pointer to file name
- ; search for a drive letter
- inc SI ;should point to a colon if
- ;one is there
- cmp byte ptr [SI],COLON ;?
- je got_drive ;yes
- get_drive:
- mov AL,drive ;get drive letter
- add AL,'a' ;make it a letter
- mov ES:[DI],AL ;put it in file name
- inc DI
- mov byte ptr ES:[DI],COLON ;put in a colon
- inc DI
- jmp path_search
- got_drive:
- pop SI ;move pointer back to start
- mov AL,[SI] ;get the given drive
- mov ES:[DI],AL ;move it
- sub AL,'a' ;make it a number
- mov drive,AL ;save the drive number
- inc SI
- inc DI
- mov byte ptr ES:[DI],COLON
- inc DI
- inc SI
- push SI ;save new start pointer
- path_search:
- ; now search for a backslash which says that a pathname was given
- bk_s_lp:cmp byte ptr [SI],BACKSLASH
- je got_path ;a path
- cmp byte ptr [SI],CR ;end of the file name?
- je get_path ;yes with no path
- inc SI
- jmp short bk_s_lp ;loop
- get_path:
- mov byte ptr ES:[DI],BACKSLASH ;create the path
- inc DI
- mov DL,drive ;the current drive
- inc DL ;bump it for DOS
- push DS
- push ES
- pop DS ;set up DS for DOS
- mov SI,DI ;set up SI for pathname
- mov AH,def_path ;get current directory
- int DOS_CALL ;path goes into DS:SI
- pop DS ;restore DS
- cmp byte ptr ES:[SI],NULL ;null path?
- je null_path ;yes - root directory
- path_lp: ;now find the end of the string
- cmp byte ptr ES:[SI],NULL ;null byte marks end of pathname
- je end_path ;now append the file name
- inc SI
- jmp short path_lp
- end_path:
- mov byte ptr ES:[SI],BACKSLASH
- inc SI
- null_path:
- mov DI,SI ;DI is destination
- got_path:
- pop SI ;restore source of filename
- ; pick up everything to next blank
- get_lp:
- mov AL,DS:[SI] ;character
- mov ES:[DI],AL ;put it away
- cmp AL,CR ;was it a Carriage Return?
- je end_line
- cmp AL,BLANK ;was it a space?
- je end_line
- inc SI
- inc DI
- jmp short get_lp ;no so get next character
- end_line:
- mov byte ptr ES:[DI],NULL ;zero out the CR or blank
- ;at the end of the filename
- ;it becomes an ASCIIZ string
- sub DI,BX ;now take out the base and
- cmp DI,offset filen ; make sure that we got something
- jne lptx_make ;file name was ok
- display lptx_creat ;could not understand the file name
- jmp nor_exit ;don't stay resident
- nor_ex: jmp nor_exit
-
- lptx_make:
- ; default DTA used by Find File is set by DOS to an offset of
- ; 80h into this program's Program Segment Prefix
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX
- add DX,offset filen ;file name
- mov AH,find_FILE
- mov CX,0 ;normal files only
- int DOS_CALL ;find first match
- pop DS
- jnc lptx_d ;file was found
- jmp lptx_create ;not there - which is ok
- ;file already exists
- lptx_d: display lptx_over
- mov DX,offset yn_max;input buffer
- mov AH,0AH
- int DOS_CALL
- cmp yn_act,0 ;anything typed?
- display lptx_cr
- je lptx_x ;no - exit
- cmp yn_in,'y' ;a yes?
- je lptx_d_yes ;yes
- cmp yn_in,'Y' ;a yes?
- je lptx_d_yes ;yes
- lptx_x: display lptx_nc
- jmp nor_exit ;all done if we can't overwrite
- ;see if we should abort the host
- lptx_d_yes:
- display lptx_del
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX
- add DX,offset filen ;file name
- mov AH,delete_FILE
- int DOS_CALL ;delete file
- pop DS
- jnc lptx_create ;ok its gone
- display lptx_err_3 ;can't delete it
- jmp nor_exit
- lptx_create: ; create the file
- push DS
- push ES
- pop DS ;uses DS:DX
- mov DX,BX ;base of this LPT's structure
- add DX,offset filen ;file name
- mov AH,create_FILE
- mov CX,0 ;normal files only
- int DOS_CALL ;find first match
- pop DS
- jnc creat_ok
- display lptx_creat ;could not create the file
- jmp nor_exit ;don't stay resident
- creat_ok: ;now close the file
- push BX
- mov BX,AX ;AX was loaded by the create file
- ; call
- mov AH,close_FILE ;close the file
- int DOS_CALL
- pop BX
- display lptx_on
- ; set the program up for writing
- mov ES:[BX].bufcntr,EMPTY ;set buffer empty
- mov ES:[BX].active,ON ;set us on
- mov AL,lfeed
- mov ES:[BX].linefeed,AL ;save linefeed switch
- make_res:
- cmp flag_27,ON ;make this one resident?
- je resident ;yes
- jmp nor_exit ;no
- ;
- resident:
- push ES
- push BX
- ; get old interrupt handler addressses
- mov AL,17h ;get current vector address for 17h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_17h,BX
- mov word ptr old_17h[2],ES ;save it for later use
-
- mov AL,DOS_CALL ;get current vector address for 21h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_21h,BX
- mov word ptr old_21h[2],ES ;save it for later use
-
- mov AL,08h ;get current vector address for 08h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_08h,BX
- mov word ptr old_08h[2],ES ;save it for later use
-
- mov AL,28h ;get current vector address for 28h
- mov AH,35h
- int DOS_CALL
- mov word ptr old_28h,BX
- mov word ptr old_28h[2],ES ;save it for later use
-
- ;
- ; Set LPTx up as the new int 17h interrupt handler
- mov AX,2517h ;set interrupt vector
- mov DX,offset int_17h ;BIOS printer
- int DOS_CALL
- ;
- ; Set LPTx up as the new int 21h interrupt handler
- ; mov AX,2521h ;set interrupt vector
- ; mov DX,offset int_21h ;DOS Functions
- ; int DOS_CALL
- ;
- ;
- ; Set LPTx up as the new int 08h interrupt handler
- mov AX,2508h ;set interrupt vector
- mov DX,offset int_08h ;Timer
- int DOS_CALL
- ;
- ;
- ; Set LPTx up as the new int 28h interrupt handler
- mov AX,2528h ;set interrupt vector
- mov DX,offset int_28h ;Idle
- int DOS_CALL
- ;
- mov AH,34h
- int DOS_CALL ;Call Special DOS interrupt
- ;returns pointer to critical
- ;section flag in ES:BX
- ;With DOS 2.1, this returns
- ;00EC:012D. I used the XRAY
- ;program to look at this
- ;byte while DOS was running.
- mov csect_seg,ES ;save the pointer
- mov csect_off,BX
- pop BX
- pop ES
- display lptx_resident ;resident loaded message
- call stat ;display status
- mov DX,offset end_res
- int 27h ;terminate but stay resident
- ;
- ; [?]
- ; HELP printer
- ;
- help: display help_msg ;display the HELP screen
- jmp short nor_exit
- ;
- ; Normal exit for transient copy of LPTx
- nor_exit:
- call stat ;display status
- bail_out:
- mov AH,0
- int DOS_CALL ;terminate
- ;
- ; [-i]
- ; unhook LPTx from interrupt vectors 08h, 17h, 21h, and 28h
- inactivate:
- ;
- cmp word ptr ES:old_17h,0 ;is it sill 0?
- je bail_out ;yes, we weren't installed yet
- ; flush all buffers
- mov BX,offset lpt1
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl1 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- ;
- no_cl1:
- mov BX,offset lpt2
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl2 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- ;
- no_cl2:
- mov BX,offset lpt3
- cmp ES:[BX].active,ON ;are we active?
- jne no_cl3 ;no
- mov AL,1AH ;CTRL-Z
- push DS
- push ES
- pop DS ;set DS to point to resident
- ;data segment
- call prnt ;print end of file mark
- call flush
- pop DS ;restore DS
- mov ES:[BX].active,OFF ;make us inactive
- display lptx_off ;capturing off message
- no_cl3:
- push DS
- mov DX,word ptr ES:old_17h ;original vector, offset
- mov AX,word ptr ES:old_17h[2];original vector, segment
- mov DS,AX
- mov AX,2517h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
- push DS
- mov DX,word ptr ES:old_21h ;original vector, offset
- mov AX,word ptr ES:old_21h[2];original vector, segment
- mov DS,AX
- mov AX,2521h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_08h ;original vector, offset
- mov AX,word ptr ES:old_08h[2];original vector, segment
- mov DS,AX
- mov AX,2508h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
-
- push DS
- mov DX,word ptr ES:old_28h ;original vector, offset
- mov AX,word ptr ES:old_28h[2];original vector, segment
- mov DS,AX
- mov AX,2528h ;set interrupt vector to DS:DX
- int DOS_CALL
- pop DS
-
- display lptx_gone ;inactivated
- jmp bail_out
- ;------------------------------------------------------------------------
- ;
- ; displays the status of each of the three line printers
- ;
- stat proc near
- ; display each LPTx with a message "not redirected"
- ; or redirected to <filename>
- push AX
- push BX
- push DX
- push SI
- push DI
- display stat_stat
- stat_1: mov BX,offset lpt1 ;first printer
- mov stat_ptr,'1'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_1_a ;yes
- display stat_off
- jmp short stat_2
- stat_1_a:
- mov SI,BX ;base
- add SI,offset filen ;offset
- mov DI,offset stat_fn
- stat_1_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_1_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_2:
- mov BX,offset lpt2 ;second printer
- mov stat_ptr,'2'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_2_a ;yes
- display stat_off
- jmp short stat_3
- stat_2_a:
- mov SI,BX ;base
- add SI,offset filen ;offset
- mov DI,offset stat_fn
- stat_2_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_2_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_3: mov BX,offset lpt3 ;third printer
- mov stat_ptr,'3'
- display stat_lp
- cmp ES:[BX].active,ON ;are we active?
- je stat_3_a ;yes
- display stat_off
- jmp short stat_done
- stat_3_a:
- mov SI,BX ;base
- add SI,offset filen ;offset
- mov DI,offset stat_fn
- stat_3_lp:
- mov AL,ES:[SI]
- mov [DI],AL
- inc SI
- inc DI
- cmp AL,NULL ;loop till a null byte is found
- jne stat_3_lp
- mov byte ptr [DI],CR
- inc DI
- mov byte ptr [DI],LF
- inc DI
- mov byte ptr [DI],DOLLAR
- display stat_dir ;display file name
- stat_done:
- pop DI
- pop SI
- pop DX
- pop BX
- pop AX
- ret
- stat endp
- ;
- cseg ends
- %out EOF
- end lptx