Calling DOS from within Interrupt Handlers
Mark DiVecchio
mark at sdencore.UUCP
Tue May 28 02:22:18 AEST 1985
----------------------------------------------------
I have had a substantual number of requests for a copy of my
PC-DOS program which permits interrupt handlers to call other
DOS functions.
I post it here for your edification.
The documentation :-) is first, followed by the .ASM source.
LPTx : Line Printer Output Capture Routine
-------------------------------------------------------------
Version 3.0
(C) Copyright 1985 by Mark DiVecchio, All Rights Reserved
You may use and freely distribute this program for
non-commercial applications.
Mark C. DiVecchio
9067 Hillery Drive
San Diego, CA 92126
619-566-6810
-------------------------------------------------------------
Have you ever wanted to get some data from your screen into a
program? Have you ever wanted to grab onto some printer data and put it into
a disk file but the program you are using does not have that as a option?
Well here is the answer to your problem. This program will grab onto
anything sent out of a line printer port as long as the program uses the
standard BIOS INT 17h call. I have tried this with printscreen, with
printscreen in graphics mode (produces some mighty unusual output), with
SIDEWAYS, with the copy command to LPT1: etc, with my word processor
(FinalWord), with MASM (direct output to LPT1) with Wordstar, with 1-2-3 and
with the DOS '>' redirection command line option. It all seems to work.
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 redirections may be active at the same time.
LPTx requires DOS 2.0 or later.
Calling sequence:
lptx -1 -o <d:[pathname]filename>
where -1 means redirect LPT1, -2 means redirect LPT2, -3 means redirect
LPT3
This option must appear first
-o means start the redirection to file specified. If redirection
is already in progress for the selected line printer,
the old file will be closed first.
(If you do not specify -o but you do specify a line printer,
LPTx will use either the last file name that you gave when
you loaded LPTx or will use the file named LPTXy.LST which it
will create in the root directory on the default drive - where
y is 1, 2, or 3.)
It is not necessary that you specify the complete path name
for the file. LPTx will create the file in the default
directory if you don't specify a directory. LPTx will always
be able to find the file because it saves the complete path.
-c means close the file and send all further output directly to the
line printer.
If neither option is specified, LPTx just displays the program status.
note: -1, -2, and -3 are mutually exclusive
-o and -c are mutually exclusive
examples:
lptx Displays the program status
lptx ? Displays a HELP screen
lptx -1 redirects LPT1 output to file named
LPTX1.LST in the root directory
on the default drive or the last
named file.
lptx -o a:\able.xxx redirects LPT1 output to file named
or a:\able.xxx. Any open redirection
lptx a:\able.xxx disk file for LPT1 is closed.
lptx -2 b:xx.lst redirects LPT2 output to file named
XX.LST in the default directory
on drive B:. Any open redirection
disk file for LPT2 is closed.
lptx -3 d:\ab\cd\file.lst redirects LPT3 output to the file named
file.lst in the directory ab\cd on drive
d:.
lptx -c closes any disk files open for LPT1 and sends
or the output back to the line printer
lptx -1 -c If no redirection is taking place to LPT1,
this is a NOP. LPT2 and LPT3 are not
affected.
lptx -2 -c closes any disk file open for LPT2 and
sends the output back to line printer.
if no redirection is taking place to LPT2,
this is a NOP. LPT1 and LPT3 are not
affected.
By redirecting LPT2 or LPT3 to a disk file, you can in effect have 2
or 3 printers on your system. LPT1 can be your physical printer and you can
have LPT2 output going to disk. When you redirect LPT2 or LPT3, LPT1 works
normally.
If you are redirecting to a diskette file, do not remove the diskette
once the redirection starts. I recommend redirecting to a hard disk or a RAM
disk.
If LPTx encounters any kind of error during the redirection, it
terminates operation and sends output back to the line printer. It does not
display anything but beeps the speaker four times. This prevents your
currently running program from possibly getting destroyed. An error with
LPT1 redirection does not shut down LPT2 or LPT3 redirection.
LPTx captures the int 17h interrupt vector. Problems may occur with
print spoolers which also take over the int 17h vector. You can be sure that
LPTX works correctly by running LPTX after you have run your print spooler.
LPTX will be transparent to the print spooler but your print spooler may not
be transparent to LPTX. LPTX works fine with IBM's PRINT command.
LPTx also captures the int 24h critical error interrupt vector. This
is done only for the period that LPTx is using the disk. This prevents the
generation of funny error messages in the middle of other programs that you
may be running. (LPTx just beeps 4 times and clears itself out of way if a
disk error occurs).
This version of LPTx can redirect all three printers to three
different files with all 3 active at the same time.
LPTx uses about 7K of memory for the resident data buffers and
interrupt handler.
If you modify or find any bugs in this program, I would appreciate
it if you would drop me a line with the changes. Use the address above.
-------------Program Follows---------------------------
title LPTx : Line Printer Output Capture Routine
page 66,132
;-------------------------------------------------------------
;
; MAIN PROGRAM Version 3.0
;
; (C) Copyright 1985 by Mark DiVecchio, All Rights Reserved
;
; You may use and freely distribute this program for
; non-commercial applications.
;
; Mark C. DiVecchio
; 9067 Hillery Drive
; San Diego, CA 92126
; 619-566-6810
;-------------------------------------------------------------
; 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.
;
; This version (3.0) 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.
;
; Calling sequence:
; lptx -1 -o <d:[pathname]filename>
;
; where -1 means redirect LPT1, -2 means redirect LPT2, -3 means redirect
; LPT3
; This option must appear first
;
; -o means start the redirect to file speicfied. If rerouting
; is already in progress for the selected line printer,
; the old file will be closed first.
; (If you do not specify -o but you do specify a line printer,
; LPTx will use either the last file name that you gave when
; you loaded LPTx or will use the file named LPTX1.LST which it
; will create in the root directory
; on the default drive - where x is 1, 2, or 3.)
;
; It is not necessary that you specify the complete path name
; for the file. LPTx opens and closes the file each time that it
; writes out a block. If you change directories, LPTx will
; be able to find the file because it save the complete path.
;
; -c means close the file and send all furthur output directly to the
; line printer.
;
; if neither option is specified, LPTx just displays the program status.
;
; note: -1, -2, and -3 are mutually exclusive
; -o and -c are mutually exclusive
;
; examples:
;
; lptx Displays the program status
;
; lptx ? Displays a HELP screen
;
; lptx -1 routes LPT1 output to file named
; LPTX1.LST on the default drive or the last
; named file.
;
; lptx -o a:\able.xxx routes LPT1 output to file named
; or a:\able.xxx. Any open redirection
; lptx a:\able.xxx disk file for LPT1 is closed.
;
; lptx -2 b:xx.lst routes LPT2 output to file named
; XX.LST in the default directory
; on drive B:. Any open redirection
; disk file for LPT2 is closed.
;
; lptx -3 d:\ab\cd\file.lst redirects LPT3 output to the file named
; file.lst in the directory ab\cd on drive
; d:.
;
; lptx -c closes any disk files open for LPT1 and sends
; or the output back to the line printer
; lptx -1 -c If no rerouting is taking place to LPT1,
; this is a NOP. LPT2 and LPT3 are not
; affected.
;
; lptx -2 -c closes any disk file open for LPT2 and
; sends the output back to line printer.
; if no rerouting is taking place to LPT2,
; this is a NOP. LPT1 and LPT3 are not
; affected.
;
; By rerouting LPT2 or LPT3 to a disk file, you can in effect have 2 or 3
; printers on your system. LPT1 can be your physical printer and you can
; have LPT2 output going to disk. When you redirect LPT2 or LPT3, LPT1 works
; normally.
;
; If you are rerouting to a diskette file, do not remove the diskette
; once the rerouting starts. I recommend rerouting to a hard disk or
; a RAM disk.
;
; If LPTx encounters any kind of error during the rerouting, it terminates
; operation and sends output back to the line printer. It does not display
; anything but beeps the speaker four times. This prevents your currently
; running program from possibly getting destroyed.
; An error on LPT1 redirect does not shut down LPT2 or LPT3 redirect.
;
; LPTx captures the int 17h interrupt vector. It may not operate correctly
; with other routines what also intercept that vector.
;
; Problems may occur with print spoolers which also take over the int 17h
; vector. You can be sure that LPTX works correctly by running LPTX after
; you have run your print spooler. LPTX will be transparent to the print
; spooler but your print spooler may not be transparent to LPTX.
; LPTX works fine with IBM's PRINT command.
;
; LPTx also captures the int 24h critical error interrupt vector. This is
; done only for the period that LPTx is using the disk. This prevents
; the generation of funny error messages in the middle of other programs
; that you may be running. (LPTx justs beeps 4 times and clears itself
; out of way if a disk error occurs).
;
; This version of LPTx can redirect all three printers to three different
; files with all 3 active at the same time.
;
; LPTx uses about 7K of memory for the resident data buffers and
; interrupt handler.
;
; My thanks to Don D. Worth of UCLA/OAC for his program named SPOOL.
; He included the concept of the saving the DOS stack when the interrupt
; routine called DOS on its own. I stole the idea for this program.
;
; If you modify or find any bugs in this program, I would appreciate
; it if you would drop me a line with the changes. Use the address
; above.
;
if1
%out Pass 1
else
%out Pass 2
endif
;
;-----------------------------------------------------------------
null equ 0
off equ 0
on equ 1
empty equ 0
cr equ 13
lf equ 10
dollar equ '$'
colon equ ':'
backslash equ '\'
blank equ ' '
dash equ '-'
dos_call equ 21h
bufsize equ 200H ;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
;-----------------------------------------------------------------
;
; Macros
display macro msg
mov DX,offset msg
mov AH,display_output
int dos_call
endm
;
;-----------------------------------------------------------------
;
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
;
active db off ;1 = this LPTx is on, 0 = off
handle dw null ;handle of disk file used by this LPT
;
; space for redirection disk file name
;
filen db 'a:\lptx'
ptr db blank
db '.lst',null
db ' '
db ' '
;
sp_left dw empty ;bytes left in DMA buffer for this LPT
buffer db bufsize dup(?) ;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 l_start
id dw 03579h ;unique ID for this program
;
; What follows is 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'>
;
lptxe db 7,7,7,7,dollar ;ring bell four times
crit_flag db 0 ;set to one if critical error occured
off_crit dw 0 ;save old critical error address
seg_crit dw 0
;
dosstk db 0C80H dup(?) ;place to save INT 21H's stack
stksav dd 0 ;caller's stack EA
db 64 dup('STACK ')
stk equ this byte
;-----------------------------------------------------------------
;
; Interrupt handler
;
prt_int:
cmp DX,0F0Fh ;my flag to detect that LPTX is
;already loaded and alive.
jne reg_call ;This is a regular print call
jmp ret_ack
reg_call: ; set up BX
push BX
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 sleep ;no
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_it ;we are active
do_nix: mov AH,90h ;Ready Status
pop BX
iret
;
ill_ptr:mov AH,0
pop BX
iret ;return with error status
;
ret_ack: ;return acknowledgement that I'm here
mov DX,05555h
mov AX,0AAAAh
push CS ;now set up ES to point to the resident
pop ES ; data area
iret
;
sleep: pop BX ;restore BX before we go to sleep
db 0EAh ;jump immediate to next handler
oldint dd ;address of old int 17 routine
;-----------------------------------------------------------------
;
; Start the print process
;
prt_it: push AX
push BX
push CX
push DX
push DS
push ES
push SI
push DI
push BP
; DS is used as the segment register
; for all data during the interrupt
;
push CS
pop DS ;set up DS
;
cli
mov SI,SS
mov word ptr stksav+2,SI ;save caller's stack
mov SI,SP
mov word ptr stksav,SI
mov SI,CS
mov SS,SI ;give me new bigger stack
mov SI,offset stk
mov SP,SI
sti
call prnt ;print the character
;
cli
mov SI,word ptr stksav
mov SP,SI ;restore caller's stack
mov SI,word ptr stksav+2
mov SS,SI
sti
;
pop BP
pop DI
pop SI
pop ES
pop DS
pop DX
pop CX
pop BX
pop AX
jmp do_nix
;-----------------------------------------------------------------
;
; Critical Error Handler
;
crit_int: ;got critical error
mov CS:crit_flag,on ; set flag
mov AL,0 ;tells DOS to ignore the
iret ;error
;-----------------------------------------------------------------
;
; Print a character in AL
;
prnt proc near
cmp DS:[BX].active,off
je prtext ;nothing there?
push AX
cmp DS:[BX].sp_left,bufsize ;buffer full
jne intadd ;no
call flush ;yes, flush buffer
intadd: pop AX
mov DI,BX ;offset of this printer's allocation
add DI,offset buffer ;add in offset of buffer
add DI,DS:[BX].sp_left ;add in current byte count
mov DS:[DI],AL ;stuff it
inc DS:[BX].sp_left
prtext: ret ;done
prnt endp
;
; Flush print buffer to disk file
;
flush proc near
cmp DS:[BX].sp_left,empty ;buffer non-empty?
jne flush_buf ;empty, skip it
ret ;exit
flush_buf:
mov DS:[BX].sp_left,empty ;else, reset it
;
push ES
push DS
;
; Preserve a chunk of DOS 2.0 across int 21h
; See PC Technical reference manual page D-7 for hint.
; It comments that only DOS calls 0 - 12 can be safely made
; from an interrupt handler. "Use of any other call will
; destroy the DOS stack and will leave DOS in an
; unpredictable state." What we do here is save and restore
; 3200 bytes of the DOS stack and restore it later. We only
; do it for the DOS stack. If this was invoked by a user
; program, we won't save the DOS stack or the user stack.
; It is not necessary.
;
mov AX,word ptr DS:stksav+2 ;get callers stack segment
cmp AX,0100h ; is it DOS?
ja flusha ;no, don;t bother to save it
mov AX,DS ;copy to my segment
mov ES,AX
mov AX,word ptr DS:stksav+2 ;copying from caller's stack
mov DS,AX
mov SI,0 ;offset into DOS's stack
mov DI,offset dosstk
mov CX,0C80h ;length to save
cld
rep movsb ;copy DOS's stack
;
pop DS
push DS
;
flusha:
;
push AX ;save the character
push BX
push ES
mov AX,3524h ;get old critical error vector
int dos_call
mov DS:off_crit,BX
mov DS:seg_crit,ES
mov DX,offset crit_int
mov AX,2524h
int dos_call ;trap critical error vector
mov DS:crit_flag,off ;clear critical error flag
pop ES
pop BX
pop AX
; open file
mov DX,BX
add DX,offset filen ;filename
mov AL,1 ;open for writing
mov AH,open_file
int dos_call
mov DS:[BX].handle,AX ;file handle
jc flush_err ;error
cmp DS:crit_flag,on ;critical error?
je flush_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
int dos_call
pop BX
jc flush_err ;some seek error
cmp DS:crit_flag,on ;critical error?
je flush_err ;yes
;
mov CX,bufsize ;buffer length
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
int dos_call ;buffer address is DS:DX
pop BX
jnc flush_ok
cmp DS:crit_flag,on ;critical error?
je flush_err ;yes
cmp AX,bufsize ;did DOS write it all?
je flush_ok ;yes
;
flush_err:
display lptxe ;ring bell
mov DS:[BX].active,off ;turn us off
mov DS:crit_flag,off ;clear error flag
; ;then try to close the file
; ;to save what we can
flush_ok:
push BX
mov BX,DS:[BX].handle
mov AH,close_file ;close the file
int dos_call
pop BX
;
flush_exit:
pop DS
pop ES
;
push DS
lds DX,dword ptr DS:off_crit
mov AX,2524h ;restore critical error vector
int dos_call
pop DS
;
mov AX,word ptr DS:stksav+2 ;copying to DOS's workarea
cmp AX,100H
ja flushe ;must be DOS's segment
push ES
mov ES,AX
mov DI,0 ;restore data areas
mov SI,offset dosstk
mov CX,0C80H ;length to restore
cld
rep movsb ;copy DOS's stack
pop ES ;restore ES
;
flushe: ret
flush endp
;
end_res db 0
;
;
; This is the end of the memory resident portion of LPTx
;
;
;--------------------------------------------------------------------
;--------------------------------------------------------------------
;--------------------------------------------------------------------
;
; all following data is in the Code Segment
;
mach_type db 0
save_psp dw 0
DOS_version db 0 ;Major Version Number
db 0 ;Minor Version Number
drive db 0 ;default drive number 0=A etc.
flag_27 db 0 ; 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 - V3.00'
db lf,cr,' Copyright 1985 Mark C. DiVecchio',lf,cr
db dollar
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) :$'
lptx_nc db 'File selection canceled',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 {-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
;
; HELP screen
;
help_msg db lf,cr,'Calling sequence : ',lf,lf,cr
db 'LPTX -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 ' defaults : p = 1',lf,cr
db ' f = o',lf,cr,dollar
;
; messages for STAT proc
;
stat_stat db cr,lf,'LPTx Status :',cr,lf,dollar
stat_lp db 'lpt'
stat_ptr db ' : $'
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.
;
l_start:
sti ;interrupts on
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
; = FF IBM PC
; = FE IBM XT
; = FD IBM PCjr
; = FC IBM PC AT
;
mov AX,0F000h
mov ES,AX
mov BX,0FFFEh
mov CL,ES:[BX] ;get machine type
mov mach_type,CL ;save machine type
mov save_psp,DS ;segment address of PSP
;
; 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
;
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
;
; get old interrupt handler
;
mov flag_27,off ;to not make resident
mov AL,17h ;get current vector address
mov AH,35h
int dos_call
mov word ptr oldint,BX
mov word ptr oldint[2],ES ;save it for later use
;
; are we already resident in memory?
;
mov DX,0F0Fh ;check if LPTX is already resident
mov AX,2 ;get status
int 17h ;call int 17h - BIOS
cmp DX,5555h ;my handler sets DX to 5555h
;and sets ES
je in_core ;yes - ES has 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 nor_exit ;yes, then just display status
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 inp_lp ;continue to scan
;
; scan of whole line is complete, if options were not found, we
; use defaults : LPT1 and file LPTX1.LST on the default drive.
; note : at least one option must be specified
;
scan_done:
jmp lptx_make ;go create the file
;
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
display lptx_bad ;incorrect option
jmp nor_ex
;
file_cl: ;close the output file
cmp ES:[BX].active,on ;are we active?
jne no_close ;no
mov AL,1AH ;CTRL-Z
mov word ptr ES:stksav+2,AX ;do this so that prnt does
;not bother to save the DOS stack
push DS
push ES
pop DS ;set DS to point to resident
;data segment
call prnt ;print end of file mark
call flush ;flush out write buffer
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
file_op: ;open a file for output
;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
mov word ptr ES:stksav+2,AX ;do this so that prnt does
;not bother to save the DOS stack
push DS
push ES
pop DS ;set DS to point to resident
;data segment
call prnt ;print end of file mark
call flush ;flush out write buffer
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].sp_left,empty ;set buffer empty
mov ES:[BX].active,on ;set us on
;
cmp flag_27,on ;make this one resident?
jne nor_exit ;no
;
; Now set LPTX up as the new int 17h interrupt handler
;
mov AH,25h ;set interrupt vector
mov AL,17h ;BIOS printer
mov DX,offset prt_int
int dos_call
display 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
mov AH,0
int dos_call ;terminate
;------------------------------------------------------------------------
;
; 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>
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:
ret
stat endp
;
cseg ends
%out EOF
end lptx
;
;
;
;
;
; Good Luck
;
--
Mark C. DiVecchio
K3FWT
[ihnp4|akgua|decvax|dcdwest|ucbvax]sdcsvax!sdencore!mark
More information about the Comp.sources.unix
mailing list