home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Multimedia & CD-ROM 3
/
mmcd03-jun1995-cd.iso
/
utils
/
various
/
utils-1
/
lpt2file.asm
< prev
next >
Wrap
Assembly Source File
|
1991-06-24
|
46KB
|
952 lines
;****************************************************************************
; LPT2FILE captures printer output to a file. Its syntax is
;
; LPT2FILE LPTn[:]=[[d:][path]filename] [/B=size] [/C]
;
; where LPTn specifies the printer output is to be rerouted from (LPT1,
; LPT2, or LPT3), "filename" specifies the name of the file, and "size"
; specifies the size of LPT2FILE's internal data buffer (in kilobytes).
; "Size" defaults to 4k; acceptable values range from 2k to 64k. Run
; without command line parameters, LPT2FILE displays which (if any)
; printer is redirected. Running it with /C cancels redirection.
;****************************************************************************
code segment
assume cs:code
org 100h
begin: jmp init
signature db 0,1,2,"LPT2FILE",2,1,0 ;Program signature
prog_id db ? ;Multiplex ID number
int08h dd ? ;Interrupt 08H vector
int13h dd ? ;Interrupt 13H vector
int17h dd ? ;Interrupt 17H vector
int21h dd ? ;Interrupt 21H vector
int25h dd ? ;Interrupt 25H vector
int26h dd ? ;Interrupt 26H vector
int28h dd ? ;Interrupt 28H vector
int2Fh dd ? ;Interrupt 2FH vector
errorflag dd ? ;Critical error flag address
intflags db 0 ;Disk interrupt flags
indos dd ? ;InDOS flag address
bufsize dw 4096 ;Internal buffer size
bufhalf dw 2048 ;Half buffer size
bufptr dw 0 ;Buffer pointer
bufseg dw ? ;Buffer segment
bytecount dw ? ;Number of bytes in buffer
counter db 91 ;Countdown timer
lptport db 0FEh,0 ;Redirected LPT port
filename db 128 dup (?) ;File specification
;****************************************************************************
; TIMER_INT handles interrupt 08H.
;****************************************************************************
timer_int proc far
pushf ;Push FLAGS
call cs:[int08h] ;Call previous handler
cli ;Disable interrupts
cmp cs:[counter],0 ;Branch if timer has
je timer1 ; already expired
dec cs:[counter] ;Decrement counter
jnz timer_exit ;Exit if not zero
cmp cs:[bufptr],0 ;Branch if there is data
jne timer1 ; in the buffer
mov cs:[counter],91 ;Reset the counter and exit
jmp short timer_exit ; if there's not
timer1: push di ;Save ES and DI
push es
cmp cs:[intflags],0 ;Branch if a disk interrupt
jne timer2 ; flag is set
les di,cs:[indos] ;Branch if the InDOS flag
cmp byte ptr es:[di],0 ; is set
jne timer2
les di,cs:[errorflag] ;Branch if the critical error
cmp byte ptr es:[di],0 ; flag is set
jne timer2
call flush ;Flush the output buffer
timer2: pop es ;Restore ES and DI
pop di
timer_exit: iret
timer_int endp
;****************************************************************************
; PRINTER_INT handles interrupt 17H.
;****************************************************************************
printer_int proc far
cmp cs:[lptport],0FFh ;Branch if redirection is
jne prn_check ; enabled
prn_bios: jmp cs:[int17h] ;Jump to BIOS handler
prn_check: cmp dx,word ptr cs:[lptport];Exit if this LPT port is not
jne prn_bios ; currently redirected
cmp ah,02h ;Exit if function code is
ja prn_bios ; greater than 02h
push di ;Save ES and DI
push es
;
; Process interrupt 17H, function 00H (transmit character to printer).
;
or ah,ah ;Branch if AH is not 0
jnz prn1
mov cs:[counter],91 ;Reset timer
mov di,cs:[bufptr] ;Point DI to buffer
cmp di,cs:[bufsize] ;Error if the buffer is
je prn_error ; full
mov es,cs:[bufseg] ;Point ES to buffer segment
mov es:[di],al ;Buffer the character
inc di ;Increment the buffer pointer
mov cs:[bufptr],di ;Store the new pointer
cmp di,cs:[bufhalf] ;Exit if the buffer is less
jb prn_exit ; than half full
prn_clear: cmp cs:[intflags],0 ;Branch if a disk interrupt
jne prn_exit ; flag is set
les di,cs:[indos] ;Branch if the InDOS flag
cmp byte ptr es:[di],0 ; is set
jne prn_exit
les di,cs:[errorflag] ;Branch if the critical error
cmp byte ptr es:[di],0 ; flag is set
jne prn_exit
call flush ;Flush the output buffer
jmp short prn_exit ;Then exit
;
; Process interrupt 17H, function 01H (initialize printer).
;
prn1: cmp ah,01h ;Branch if AH is not 1
jne prn2
cmp cs:[bufptr],0 ;Exit if the buffer
je prn_exit ; is empty
jmp prn_clear ;Flush it if it's not
;
; Process interrupt 17H, function 02H (get printer status).
;
prn2: mov di,cs:[bufptr] ;Get buffer pointer
cmp di,cs:[bufsize] ;Is the buffer full?
je prn_error ;Error if it is
prn_exit: mov ah,90h ;Return OK signal in AH
pop es ;Restore ES and DI
pop di
iret ;Return from interrupt
prn_error: mov ah,08h ;Return I/O error in AH
pop es ;Restore ES and DI
pop di
iret ;Return from interrupt
printer_int endp
;****************************************************************************
; DOS_INT handles interrupt 21H.
;****************************************************************************
dos_int proc near
pushf ;Save FLAGS
cmp cs:[bufptr],0 ;Exit if the buffer is
je dos_exit ; empty
push di
push es
cmp cs:[intflags],0 ;Branch if a disk interrupt
jne dos_busy ; flag is set
les di,cs:[indos] ;Branch if the InDOS flag
cmp byte ptr es:[di],0 ; is set
jne dos_busy
les di,cs:[errorflag] ;Branch if the critical error
cmp byte ptr es:[di],0 ; flag is set
jne dos_busy
call flush ;Flush the buffer
dos_busy: pop es ;Restore registers
pop di
dos_exit: popf ;Restore FLAGS
jmp cs:[int21h] ;Exit to original handler
dos_int endp
;****************************************************************************
; DOSIDLE_INT handles interrupt 28H.
;****************************************************************************
dosidle_int proc far
pushf ;Push FLAGS
call cs:[int28h] ;Call previous handler
cli ;Disable interrupts
cmp cs:[bufptr],0 ;Exit if the buffer
je dosidle_exit ; is empty
cmp cs:[intflags],0 ;Branch if a disk interrupt
jne dosidle_exit ; flag is set
push di ;Save ES and DI
push es
les di,cs:[errorflag] ;Check the state of the
cmp byte ptr es:[di],0 ; critical error flag
pop es ;Restore ES and DI
pop di
jne dosidle_exit ;Exit if the flag is set
call flush ;Yes, then flush it
dosidle_exit: iret ;Return from interrupt
dosidle_int endp
;****************************************************************************
; DISK_INT handles interrupt 13H.
;****************************************************************************
disk_int proc far
pushf ;Save FLAGS
or cs:[intflags],02h ;Set disk flag
popf ;Retrieve FLAGS
pushf ;Push FLAGS
call cs:[int13h] ;Call previous handler
pushf ;Save FLAGS
and cs:[intflags],0FDh ;Clear disk flag
popf ;Retrieve FLAGS
ret 2 ;Return with FLAGS intact
disk_int endp
;****************************************************************************
; ABS_READ_INT handles interrupt 25H.
;****************************************************************************
abs_read_int proc far
pushf ;Save FLAGS
or cs:[intflags],04h ;Set disk flag
popf ;Retrieve FLAGS
call cs:[int25h] ;Call previous handler
pushf ;Save FLAGS
and cs:[intflags],0FBh ;Clear disk flag
popf ;Retrieve FLAGS
ret ;Return with FLAGS on stack
abs_read_int endp
;****************************************************************************
; ABS_WRITE_INT handles interrupt 26H.
;****************************************************************************
abs_write_int proc far
pushf ;Save FLAGS
or cs:[intflags],08h ;Set disk flag
popf ;Retrieve FLAGS
call cs:[int26h] ;Call previous handler
pushf ;Save FLAGS
and cs:[intflags],0F7h ;Clear disk flag
popf ;Retrieve FLAGS
ret ;Return with FLAGS on stack
abs_write_int endp
;****************************************************************************
; MPLEX_INT handles interrupt 2FH. If, on entry, AH is set to LPT2FILE's
; multiplex ID number, MPLEX_INT uses the value in AL as a function code.
; The functions supported are:
;
; 00H Returns FFH in AL to indicate the program is installed
; and returns the address of its signature in ES:DI.
;
; 01H Returns the number of the printer currently redirected
; (0, 1, or 2) in AL, or FFH if none are redirected. If AL
; contains 0, 1, or 2, then ES:DI holds the address of the
; name of the file output is redirected to.
;
; 02H Accepts the number of the printer to be redirected (0, 1,
; or 2) in BL and the address of a file name in DS:SI. FFH
; cancels redirection. This function causes the output
; buffer to be flushed.
;****************************************************************************
mplex_int proc far
pushf ;Save FLAGS register
cmp ah,cs:[prog_id] ;Branch if AH holds the
je mplex2 ; multiplex ID
popf ;Restore FLAGS
jmp cs:[int2Fh] ;Pass the interrupt on
;
; Function 00H verifies that the program is installed.
;
mplex2: popf ;Restore FLAGS
or al,al ;Branch if function code
jnz mplex3 ; is other than 00H
mov al,0FFh ;Set AL to FFH
push cs ;Point ES:DI to the program
pop es ; signature
mov di,offset signature
iret ;Return from interrupt
;
; Function 01H reports the status of redirection.
;
mplex3: cmp al,01h ;Branch if function code
jne mplex4 ; is other than 01H
mov al,cs:[lptport] ;Put printer number in AL
push cs ;Point ES to this segment
pop es
mov di,offset filename ;Point DI to file name
iret ;Return from interrupt
;
; Function 02H designates a new printer and file name for redirection.
;
mplex4: cmp cs:[bufptr],0 ;Branch if the output
je mplex5 ; buffer is empty
call flush ;Flush the buffer
mplex5: mov cs:[lptport],bl ;Store printer number
cmp bl,0FFh ;Branch if redirection
je mplex_exit ; cancelled
push es ;Save ES
push cs ;Point ES to this segment
pop es
mov di,offset filename ;Point DI to file name
cld ;Clear direction flag
mplex6: movsb ;Copy one character
cmp byte ptr [si-1],0 ;Was it a zero?
jne mplex6 ;No, then loop back
pop es ;Restore ES
mplex_exit: iret ;Return from interrupt
mplex_int endp
;****************************************************************************
; FLUSH flushes the output buffer.
;****************************************************************************
flush proc near
push ax ;Save registers
push bx
push cx
push dx
push ds
mov ax,cs ;Point DS to the code
mov ds,ax ; segment
assume ds:code
mov counter,91 ;Reset the counter
mov ax,bufptr ;Retrieve buffer pointer
mov bytecount,ax ;Save it for later
mov bufptr,0 ;Reset the pointer
sti ;Enable interrupts
call openfile ;Attempt to open the file
jc flush_exit ;Branch if it failed
mov bx,ax ;Transfer file handle to BX
mov ax,4202h ;Move the file pointer to
sub cx,cx ; the end of the file
mov dx,cx
int 21h
mov ah,40h ;Copy the output buffer
mov cx,bytecount ; to disk
sub dx,dx
mov ds,bufseg
assume ds:nothing
int 21h
mov ah,3Eh ;Close the file
int 21h
flush_exit: pop ds ;Restore registers and exit
pop dx
pop cx
pop bx
pop ax
ret
flush endp
;****************************************************************************
; OPENFILE attempts to open or create the file output is redirected to.
; On return, carry is clear if the attempt was successful and the file
; handle is in AX. Carry set means the attempt failed. On entry, DS
; must point to the code segment.
;****************************************************************************
openfile proc near
mov ax,3D01h ;Attempt to open the file
mov dx,offset filename ; for writing
int 21h
jnc opened ;Branch if it worked
mov ax,4301h ;Attempt to strip all the
sub cx,cx ; attributes off the file
mov dx,offset filename
int 21h
mov ax,3D01h ;Then attempt to open it
mov dx,offset filename ; for writing again
int 21h
jnc opened ;Branch if it worked
mov ah,3Ch ;Attempt to create the
sub cx,cx ; file from scratch
mov dx,offset filename
int 21h
jnc opened ;Branch if it worked
stc ;Set the carry flag and
ret ; exit
opened: clc ;Clear the carry flag and
ret ; exit
openfile endp
;****************************************************************************
; Data that will be discarded when the program becomes memory-resident.
;****************************************************************************
helpmsg db "Captures printer output to a file.",13,10,13,10
db "LPT2FILE [LPTn[:]=[[d:][path]filename]] [/B=size] "
db "[/C]",13,10,13,10
db " LPTn Specifies the LPT port number.",13,10
db " /B=size Specifies the internal buffer size in "
db "kilobytes (default=4k).",13,10
db " /C Cancels redirection.",13,10,13,10
db "Running LPT2FILE with no parameters displays the "
db "status of redirection.",13,10,"$"
errmsg1 db "Syntax: LPT2FILE [LPTn[:]=[[d:][path]filename]] "
db "[/B=size] [/C]",13,10,"$"
errmsg2 db "Requires DOS 3.0 or higher",13,10,"$"
errmsg3 db "Buffer size is fixed once the program is installed"
crlf db 13,10,"$"
errmsg4 db "Invalid buffer size (minimum=2, maximum=64)"
db 13,10,"$"
errmsg5 db "Invalid port number (must be LPT1, LPT2, or LPT3)"
db 13,10,"$"
errmsg6 db "File could not be opened",13,10,"$"
errmsg7 db "Program could not be installed",13,10,"$"
errmsg8 db "Not enough memory",13,10,"$"
msg1 db "LPT2FILE 1.0 installed",13,10,"$"
msg2 db "No printers are currently redirected",13,10,"$"
msg3 db "LPTn: is currently redirected to $"
installed db 0 ;0=Not installed
eoladdr dw 0 ;End of line address
;****************************************************************************
; INIT makes the program resident in memory.
;****************************************************************************
assume cs:code,ds:code
init proc near
cld ;Clear direction flag
mov si,81h ;Point SI to command line
call scanhelp ;Scan for "/?" switch
jnc checkver ;Branch if not found
mov ah,09h ;Display help text and exit
mov dx,offset helpmsg ; with ERRORLEVEL=0
int 21h
mov ax,4C00h
int 21h
;
; Check the DOS version and see if the program is already installed.
;
checkver: mov dx,offset errmsg2 ;Exit if DOS version
mov ah,30h ; is less than 3.0
int 21h
cmp al,3
jae checkprog
error: mov ah,09h ;Display error message and
int 21h ; exit with ERRORLEVEL=1
mov ax,4C01h
int 21h
checkprog: push es ;Save ES
call check_install ;See if a copy is installed
jnc reset ;Branch if not
mov installed,1 ;Set flag if it is
mov prog_id,ah ;Also store the ID number
reset: pop es ;Restore ES
;
; First capitalize everything on the command line.
;
parse: mov si,81h ;Point SI to command line
mov cl,[si-1] ;CL = Number of characters
sub ch,ch ;Convert byte to word in CX
jcxz parse3 ;Done if CX=0
parse1: cmp byte ptr [si],"a" ;Leave it if less than "a"
jb parse2
cmp byte ptr [si],"z" ;Leave it if greater than "z"
ja parse2
and byte ptr [si],0DFh ;Capitalize it
parse2: inc si ;Advance SI
loop parse1 ;Loop until done
parse2a: mov si,81h ;Reset SI
;
; Parse the command line for entries.
;
parse3: call findchar ;Find parameter
jnc parse3a ;Branch if not end of line
jmp done ;Exit the parsing loop
parse3a: cmp byte ptr [si],"/" ;Branch if the character
jne getportinfo ; is not a forward slash
;
; Process a /B switch.
;
inc si ;Advance SI
lodsb ;Get character
cmp al,"B" ;Branch if it's not a "B"
jne slashc
cmp installed,0 ;Error if /B entered with the
mov dx,offset errmsg3 ; program already installed
jne error
lodsb ;Get the next character
cmp al,"=" ;Error if not a "="
mov dx,offset errmsg1
jne error
call asc2bin ;Get the number after the "="
mov dx,offset errmsg4 ;Exit if error occurred in
jc error ; the conversion
cmp al,2 ;Error if less than 2
jb error
cmp al,64 ;Error if greater than 64
ja error
sub ah,ah ;Compute the buffer size
mov cl,10 ; in bytes by shifting
shl ax,cl ; AX left 10 bits
or ax,ax ;Branch if not equal to 0
jnz not_zero
dec ax ;Set AX to FFFFH
not_zero: mov bufsize,ax ;Record the buffer size
shr ax,1 ;Divide buffer size by 2
mov bufhalf,ax ;Record it
jmp parse3 ;Return to parsing loop
;
; Process a /C switch.
;
slashc: mov dx,offset errmsg1 ;Initialize error pointer
cmp al,"C" ;Error if it's not a "C"
jne error1
mov lptport,0FFh ;Cancel redirection
jmp parse3 ;Return to input loop
;
; Process an LPT port number.
;
getportinfo: mov dx,offset errmsg1 ;Initialize error pointer
mov di,offset errmsg1+8 ;Point DI to "LPT"
mov cx,3 ;Load CX with count
repe cmpsb ;Compare the strings
jne error1 ;Error if not equal
mov dx,offset errmsg5 ;Initialize error pointer
lodsb ;Get port number
cmp al,"1" ;Error if less than "1"
jb error1
cmp al,"3" ;Error if greater than "3"
ja error1
sub al,31h ;Convert to port number
mov lptport,al ;Save it
mov dx,offset errmsg1 ;Initialize error pointer
cmp byte ptr [si],":" ;Is next character a colon?
jne gpi3 ;No, then branch
cmp byte ptr [si],0Dh ;Error if end of line
je error1
inc si ;Skip colon
gpi3: lodsb ;Get next character
cmp al,"=" ;Error if it's not "="
jne error1
;
; Process the file name that goes with the port number.
;
push si ;Save string address
call finddelim ;Find end of file name
jc gpi4 ;Branch if end of line
mov eoladdr,si ;Save end of line address
gpi4: mov byte ptr [si],0 ;Convert to ASCIIZ string
pop si ;Retrieve string address
mov di,offset filename ;Point DI to file name buffer
mov ah,60h ;Turn it into a fully
int 21h ; qualified file name
jnc gpi5 ;Branch if no error
error2: mov dx,offset errmsg6 ;Exit on error
error1: jmp error
gpi5: call openfile ;Attempt to open the file
jc error2
mov bx,ax ;Close the file
mov ah,3Eh
int 21h
cmp eoladdr,0 ;Reached end of line?
je done ;Yes, then quit parsing
mov si,eoladdr ;Point SI to end of file name
inc si ;Advance past the zero byte
jmp parse3 ;Loop back for more
;
; Come here when parsing is done.
;
done: cmp installed,0 ;Branch if the program is
jne done1 ; already installed
cmp lptport,0FEh ;Port number equal to FEH?
jne install ;No, then go install
inc lptport ;Set port number to FFH
jmp short install ;Go install
done1: cmp lptport,0FEh ;Port number equal to FEH?
je done2 ;Yes, then we're done
mov ah,prog_id ;Send new printer number
mov al,02h ; and file name to an
mov bl,lptport ; installed copy of
mov si,offset filename ; the program
int 2Fh
done2: call showstatus ;Show redirection status
mov ax,4C00h ;Exit with ERRORLEVEL=0
int 21h
;
; Install the program.
;
install: call mplex_id ;Find a multiplex ID number
mov dx,offset errmsg7 ;Error if none available
jc error1
mov prog_id,ah ;Save the ID number
mov ah,34h ;Get and save the address of
int 21h ; the InDOS flag
mov word ptr indos,bx
mov word ptr indos[2],es
push ds ;Save DS
mov ax,5D06h ;Get and save the address of
int 21h ; the critical error flag
mov word ptr cs:[errorflag],si
mov word ptr cs:[errorflag+2],ds
pop ds ;Restore DS
mov dx,offset errmsg7 ;Error if function returned
jc error1 ; with carry set
mov ax,3508h ;Hook interrupt 08H
int 21h
mov word ptr int08h,bx
mov word ptr int08h[2],es
mov ax,2508h
mov dx,offset timer_int
int 21h
mov ax,3513h ;Hook interrupt 13H
int 21h
mov word ptr int13h,bx
mov word ptr int13h[2],es
mov ax,2513h
mov dx,offset disk_int
int 21h
mov ax,3517h ;Hook interrupt 17H
int 21h
mov word ptr int17h,bx
mov word ptr int17h[2],es
mov ax,2517h
mov dx,offset printer_int
int 21h
mov ax,3521h ;Hook interrupt 21H
int 21h
mov word ptr int21h,bx
mov word ptr int21h[2],es
mov ax,2521h
mov dx,offset dos_int
int 21h
mov ax,3525h ;Hook interrupt 25H
int 21h
mov word ptr int25h,bx
mov word ptr int25h[2],es
mov ax,2525h
mov dx,offset abs_read_int
int 21h
mov ax,3526h ;Hook interrupt 26H
int 21h
mov word ptr int26h,bx
mov word ptr int26h[2],es
mov ax,2526h
mov dx,offset abs_write_int
int 21h
mov ax,3528h ;Hook interrupt 28H
int 21h
mov word ptr int28h,bx
mov word ptr int28h[2],es
mov ax,2528h
mov dx,offset dosidle_int
int 21h
mov ax,352Fh ;Hook interrupt 2FH
int 21h
mov word ptr int2Fh,bx
mov word ptr int2Fh[2],es
mov ax,252Fh
mov dx,offset mplex_int
int 21h
mov ah,49h ;Get the segment address of
mov es,ds:[2Ch] ; the environment block
int 21h ; and free the segment
mov ah,4Ah ;Shrink the memory block
mov bx,(offset helpmsg - offset code + 15) shr 4
mov cx,cs ; the program is
mov es,cx ; loaded in
int 21h
mov ah,48h ;Request a new block of
mov bx,bufsize ; memory for the data
mov cl,4 ; buffer
shr bx,cl
inc bx
int 21h
mov dx,offset errmsg8 ;Error if there's not
jnc no_error ; enough memory
jmp error
no_error: mov bufseg,ax ;Save the segment address
mov ah,09h ;Display message verifying
mov dx,offset msg1 ; the installation
int 21h
call showstatus ;Show redirection status
mov ax,3100h ;Terminate with function 31H
mov dx,(offset helpmsg - offset code + 15)
int 21h
init endp
;****************************************************************************
; FINDCHAR advances SI to the next non-space or non-comma character.
; On return, carry set indicates EOL was encountered.
;****************************************************************************
findchar proc near
lodsb ;Get the next character
cmp al,20h ;Loop if space
je findchar
cmp al,2Ch ;Loop if comma
je findchar
dec si ;Point SI to the character
cmp al,0Dh ;Exit with carry set if end
je eol ; of line is reached
clc ;Clear carry and exit
ret
eol: stc ;Set carry and exit
ret
findchar endp
;****************************************************************************
; FINDDELIM advances SI to the next space or comma character. On return,
; carry set indicates EOL was encountered.
;****************************************************************************
finddelim proc near
lodsb ;Get the next character
cmp al,20h ;Exit if space
je fd_exit
cmp al,2Ch ;Exit if comma
je fd_exit
cmp al,0Dh ;Loop back for more if end
jne finddelim ; of line isn't reached
dec si ;Set carry and exit
stc
ret
fd_exit: dec si ;Clear carry and exit
clc
ret
finddelim endp
;****************************************************************************
; SCANHELP scans the command line for a /? switch. If found, carry returns
; set and SI contains its offset. If not found, carry returns clear.
;****************************************************************************
scanhelp proc near
push si ;Save SI
scanloop: lodsb ;Get a character
cmp al,0Dh ;Exit if end of line
je scan_exit
cmp al,"?" ;Loop if not "?"
jne scanloop
cmp byte ptr [si-2],"/" ;Loop if not "/"
jne scanloop
add sp,2 ;Clear the stack
sub si,2 ;Adjust SI
stc ;Set carry and exit
ret
scan_exit: pop si ;Restore SI
clc ;Clear carry and exit
ret
scanhelp endp
;****************************************************************************
; CHECK_INSTALL returns carry set if the program is already installed,
; carry clear if it's not. If carry returns set, AH holds the program's
; multiplex ID number.
;****************************************************************************
check_install proc near
mov ax,8000h ;Initialize AH and AL
mov cx,80h ;Initialize count
chinst1: push ax ;Save AX and CX
push cx
sub di,di ;Set ES and DI to 0
mov es,di
int 2Fh ;Interrupt 2Fh
cmp al,0FFh ;Nothing here if AL isn't
jne chinst2 ; equal to FFH
mov si,offset signature ;See if program signature
mov cx,14 ; appears at the address
repe cmpsb ; returned in ES:DI
jne chinst2 ;Branch if it does not
pop cx ;Clear the stack and exit
pop ax ; with carry set
stc
ret
chinst2: pop cx ;Retrieve AX and CX
pop ax
inc ah ;Next multiplex ID
loop chinst1 ;Loop until done
clc ;Exit with carry clear
ret
check_install endp
;****************************************************************************
; MPLEX_ID searches for an unused multiplex ID number. If one is found,
; it is returned in AH with carry clear. Carry set means no multiplex
; ID numbers are currently available.
;****************************************************************************
mplex_id proc near
mov ax,8000h ;Initialize AH and AL
mov cx,80h ;Initialize count
mxid1: push ax ;Save AX and CX
push cx
int 2Fh ;Interrupt 2Fh
or al,al ;Branch if AL=0
jz mxid2
pop cx ;Retrieve AX and CX
pop ax
inc ah ;Increment ID number
loop mxid1 ;Loop until done
stc ;Exit with carry set
ret
mxid2: pop cx ;Clear the stack and exit
pop ax ; with carry clear
clc
ret
mplex_id endp
;****************************************************************************
; ASC2BIN converts a decimal number entered in ASCII form into a binary
; value in AL. Carry set on return indicates that an error occurred in
; the conversion.
;****************************************************************************
asc2bin proc near
sub ax,ax ;Initialize registers
sub bh,bh
mov dl,10
a2b_loop: mov bl,[si] ;Get a character
inc si
cmp bl,20h ;Exit if space
je a2b_exit
cmp bl,2Ch ;Exit if comma
je a2b_exit
cmp bl,0Dh ;Exit if carriage return
je a2b_exit
cmp bl,"0" ;Error if character is not
jb a2b_error ; a number
cmp bl,"9"
ja a2b_error
mul dl ;Multiply the value in AL by
jc a2b_error ; 10 and exit on overflow
sub bl,30h ;ASCII => binary
add ax,bx ;Add latest value to AX
cmp ax,255 ;Error if sum > 255
jna a2b_loop ;Loop back for more
a2b_error: dec si ;Set carry and exit
stc
ret
a2b_exit: dec si ;Clear carry and exit
clc
ret
asc2bin endp
;****************************************************************************
; SHOWSTATUS displays the current status of printer redirection.
;****************************************************************************
showstatus proc near
cmp installed,0 ;See if program is installed
je show1 ;Branch if not
mov ah,prog_id ;Use the multiplex interrupt
mov al,01h ; (function 01H) to find out
int 2Fh ; what printer (if any) is
jmp short show2 ; redirected
show1: mov al,lptport ;Get printer number
mov bx,cs ;Point to ES to this segment
mov es,bx
mov di,offset filename ;Point DI to file name
show2: cmp al,0FFh ;Branch if a printer is
jne show3 ; currently redirected
mov ah,09h ;Display "No printers
mov dx,offset msg2 ; redirected" message
int 21h ; and exit
ret
show3: add al,31h ;Convert printer number to
mov msg3[3],al ; ASCII and store it
mov dx,offset msg3 ;Display printer name
mov ah,09h
int 21h
call dos_out ;Display file name too
mov ah,09h ;End the line
mov dx,offset crlf
int 21h
ret
showstatus endp
;****************************************************************************
; DOS_OUT displays the ASCIIZ string pointed to by ES:DI.
;****************************************************************************
dos_out proc near
mov dl,es:[di] ;Get a character
or dl,dl ;Exit if it's zero
jz out_exit
mov ah,02h ;Output it using DOS
int 21h ; function 02H
inc di ;Advance DI to next one
jmp dos_out ;Loop until done
out_exit: ret
dos_out endp
code ends
end begin