home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
bin
/
mskermit
/
msvv90sea.exe
/
V9KERMSC.EXE
/
MSSTER.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-07-03
|
45KB
|
1,566 lines
NAME msster
; File MSSTER.ASM
include mssdef.h
; Copyright (C) 1985, 1993, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or institution
; to use this software as long as it is not sold for profit. This copyright
; notice must be retained. This software may not be included in commercial
; products without written permission of Columbia University.
;
; Edit history
; 27 August 1992 version 3.13
; 6 Sept 1991 version 3.11
; Last edit 22 Feb 1992
public clscpt, defkey, clscpi, ploghnd, sloghnd, tloghnd
public dopar, shokey, cptchr, pktcpt, targ, replay, repflg
public kbdflg, shkadr, telnet, ttyact, write, dec2di, caplft
public cnvlin, katoi, decout, valout, atoi, cnvstr
public pntchr, pntflsh, pntchk, prnhand, prnopen
public vfopen, vfread
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
data segment
extrn flags:byte, trans:byte, diskio:byte, portval:word
extrn rdbuf:byte, dosnum:word, filtst:byte, prnname:byte
extrn comand:byte, kstatus:word, flowon:byte, flowoff:byte
targ termarg <0,1,cptchr,0,parnon>
crlf db cr,lf,'$'
tmsg1 db cr,lf,'(Connecting to host, type $'
tmsg3 db ' C to return to PC)',cr,lf,cr,lf,cr,lf,'$'
erms21 db cr,lf,'?Cannot start the connection.$'
erms25 db cr,lf,'?Input must be numeric$'
erms22 db cr,lf,'?No open logging file$'
erms23 db '*** Error writing session log, suspending capture ***$'
erms24 db cr,lf,'?Error writing Packet log$'
erms26 db ' *** PRINTER IS NOT READY *** press R to retry'
db ' or D to discard printing: $'
esctl db 'Control-$'
repflg db 0 ; REPLAY or SET TERM REPLAY filespec flag
rephlp db 'name of file to playback$'
reperr db cr,lf,'?File not found$' ; for REPLAY command
msgtxt db 'text to be written$'
vfophlp db 'Filename$'
vfopbad db cr,lf,'?Cannot open file $' ; filename follows
vfclbad db cr,lf,'?Cannot close file$'
vfoptwice db cr,lf,'?File is already open$'
vfnofile db cr,lf,'?File is not open$'
vfrbad db cr,lf,'?Error while reading file$'
vfwbad db cr,lf,'?Error while writing file$'
vfrdbad db cr,lf,'?more parameters are needed$'
vfrdmsg db 'name of variable into which to read a line from file$'
vfrhandle dw -1 ; READ FILE handle (-1 = invalid)
vfwhandle dw -1 ; WRITE FILE handle
opntab db 3 ; OPEN FILE table
mkeyw 'Read',1
mkeyw 'Write',2
mkeyw 'Append',3
inthlp db cr,lf,' ? This message F Dump screen to file'
db cr,lf,' C Close the connection P Push to DOS'
db cr,lf,' S Status of the connection Q Quit logging'
db cr,lf,' M Toggle mode line R Resume logging'
db cr,lf,' B Send a Break 0 Send a null'
db cr,lf,' L Send a long 1.8 s Break H Hangup phone'
db cr,lf,' A Send Telnet "Are You There" I Send Telnet'
db ' "Interrupt Process"'
db cr,lf,' Typing the escape character will send it to the host'
db 0 ; this short-form obscures less screen area [jrd]
intprm db 'Command> $'
intclet db 'B','C','F','H','L' ; single letter commands
db 'M','P','Q','R','S' ; must parallel dispatch table intcjmp
db '?','0','A','I'
numlet equ $ - intclet ; number of entries
even
intcjmp dw intchb,intchc,intchf,intchh,intchl
dw intchm,intchp,intchq,intchr,intchs
dw intchu,intchn,intayt,inttip
prnhand dw 4 ; printer file handle (4 = DOS default)
even
ploghnd dw -1 ; packet logging handle
sloghnd dw -1 ; session logging handle
tloghnd dw -1 ; transaction logging handle
clotab db 6
mkeyw 'READ-FILE',4001h
mkeyw 'WRITE-FILE',4002h
mkeyw 'All-logs',logpkt+logses+logtrn
mkeyw 'Packets',logpkt
mkeyw 'Session',logses
mkeyw 'Transaction',logtrn
clseslog db cr,lf,' Closing Session log$'
clpktlog db cr,lf,' Closing Packet log$'
cltrnlog db cr,lf,' Closing Transaction log$'
clohlp db cr,lf,' READ-FILE or WRITE-FILE, or the following log files:'
db cr,lf,' All-logs, Packets, Session, Transaction$'
writetab db 5 ; Write command log file types
mkeyw 'FILE',4002h ; FILE
mkeyw 'Packet',logpkt
mkeyw 'Screen',80h ; unused value, to say screen
mkeyw 'Session',logses
mkeyw 'Transaction',logtrn
sttmsg db cr,lf,'Press space to continue ...$'
kbdflg db 0 ; non-zero means char here from Term
ttyact db 0 ; Connect mode active, if non-zero
shkadr dw 0 ; offset of replacement Show Key cmd
nbase dw 10 ; currently active number base
numset db '0123456789ABCDEF' ; number conversion alphabet
temp dw 0
tmp db 0
pktlft dw cptsiz ; number free bytes left
caplft dw cptsiz ; number free bytes left
data ends
data1 segment
pktbuf db cptsiz dup (0) ; packet logging buffer
pktbp dw pktbuf ; buffer pointer to next free byte
capbuf db cptsiz dup (0) ; session logging buffer
capbp dw capbuf ; buffer pointer to next free byte
prnbuf db cptsiz dup (0) ; printer buffer
pntptr dw prnbuf ; pointer to next free byte
data1 ends
code segment
extrn comnd:near, outchr:near, stat0:near, iseof:near
extrn term:near, strlen:near, pcwait:near, isfile:near
extrn beep:near, puthlp:near, serhng:near
extrn serini:near, serrst:near, sendbr:near, putmod:near
extrn fpush:near, dumpscr:near, sendbl:near, prtasz:near
extrn trnmod:near, dodecom:near
assume cs:code, ds:data, es:nothing
; the show key command
shokey proc near
cmp shkadr,0 ; keyboard translator present?
je shokey1 ; e = no, use regular routines
mov bx,shkadr ; get offset of replacement routine
jmp bx ; and execute it rather than us
shokey1:clc
ret
shokey endp
; enter with ax/scan code to define, si/ pointer to definition, cx/ length
; of definition. Defines it in definition table. Obsolete.
defkey proc near
ret
defkey endp
; This is the CONNECT command
TELNET PROC NEAR
mov ah,cmeol
call comnd ; get a confirm
jnc teln1 ; nc = success
ret
teln1: call serini ; ensure port is inited now
jnc teln1a ; nc = success
test flags.remflg,dquiet ; quiet display mode?
jnz teln1b ; nz = yes. Don't write to screen
mov dx,offset erms21 ; say cannot start connection
mov ah,prstr
int dos
teln1b: or kstatus,ksgen ; general command failure
ret
teln1a: cmp flags.vtflg,0 ; emulating a terminal?
jne teln2 ; ne= yes, no wait necessary
mov ah,prstr
mov dx,offset crlf ; output a crlf
int dos
call domsg ; reassure user
mov ax,2000 ; two seconds
call pcwait ; pause
teln2: xor al,al ; initial flags
mov ttyact,1 ; say telnet is active
cmp flags.vtflg,0 ; emulating a terminal?
je teln3 ; e = no, say mode line is to be off
cmp flags.modflg,0 ; mode line enabled?
jne tel010 ; ne = yes
teln3: or al,modoff ; no, make sure it stays off
tel010: test flags.debug,logses ; debug mode?
jz tel0 ; z = no, keep going
or al,trnctl ; yes, show control chars
tel0: cmp flags.vtflg,0 ; emulating a terminal?
je tel1 ; e = no
or al,emheath ; say emulating some kind of terminal
tel1: mov bx,portval
cmp [bx].ecoflg,0 ; echoing?
jz tel2 ; z = no
or al,lclecho ; turn on local echo
tel2: mov targ.flgs,al ; store flags
mov ah,flags.comflg ; COMs port identifier
mov targ.prt,ah ; Port 1 or 2, etc
mov ah,[bx].parflg ; parity flag
mov targ.parity,ah
mov ax,[bx].baud ; baud rate identifier
mov targ.baudb,al
xor ah,ah
test flags.capflg,logses ; select session logging flag bit
jz tel3 ; z = no logging
mov ah,capt ; set capture flag
tel3: or targ.flgs,ah
jmp short tem1
TEM: call serini ; init serial port
jnc tem1 ; nc = success
mov ttyact,0 ; say we are no longer active
clc
ret ; and exit Connect mode
tem1: mov dx,offset crlf ; give user an indication that we are
mov ah,prstr ; entering terminal mode
int dos
mov ax,offset targ ; point to terminal arguments
call term ; call the main Terminal procedure
mov al,kbdflg ; get the char from Term, if any
mov kbdflg,0 ; clear the flag
or al,al ; was there a char from Term?
jnz intch2 ; nz = yes, else ask for one from kbd
intchar:call iseof ; stdin at eof?
jnc intch1 ; nc = not eof, get more
mov al,'C' ; use C when file is empty
jmp short intchc ; to provide an exit
intch1: mov ah,0ch ; clear Bios keyboard buffer and do
mov al,coninq ; read keyboard, no echo
int dos ; get a char
or al,al ; scan code indicator?
jnz intch2 ; nz = no, ascii
mov ah,coninq ; read and discard scan code
int dos
jmp short intch1 ; try again
intch2: mov flags.cxzflg,0 ; prevent Control-C carryover
cmp al,' ' ; space?
je tem ; e = yes, ignore it
cmp al,cr ; check ^M (cr) against plain ascii M
je tem ; exit on cr
cmp al,trans.escchr ; is it the escape char?
jne intch3 ; ne = no
mov ah,al
call outchr
jmp short tem ; return, we are done here
intch3: push es
push ds
pop es
mov di,offset intclet ; command letters
mov cx,numlet ; quantity of them
cmp al,' ' ; control code?
jae intch3a ; ae = no
or al,40H ; convert control chars to printable
intch3a:cmp al,96 ; lower case?
jb intch3b ; b = no
and al,not (20h) ; move to upper case
intch3b:cld
repne scasb ; find the matching letter
pop es
jne intch4 ; ne = not found, beep and get another
dec di ; back up to letter
sub di,offset intclet ; get letter number
shl di,1 ; make it a word index
jmp intcjmp[di] ; dispatch to it
intch4: call beep ; say illegal character
jmp intchar
intayt: mov ah,255 ; 'I' Telnet Are You There
call outchr ; send IAC (255) AYT (246)
mov ah,246
call outchr
jmp tem
intchb: call sendbr ; 'B' send a break
jmp tem ; And return
intchc: mov ttyact,0 ; 'C' say we are no longer active
clc ; and exit Connect mode
ret
intchf: call dumpscr ; 'F' dump screen, use msy routine
jmp tem ; and return
intchh: call serhng ; 'H' hangup phone
call serrst ; turn off port
jmp tem
intchl: call sendbl ; 'L' send a long break
jmp tem
inttip: mov ah,255 ; 'I' Telnet Interrrupt Process
call outchr ; send IAC (255) IP (244)
mov ah,244
call outchr
jmp tem
intchm: cmp flags.modflg,1 ; 'M' toggle mode line, enabled?
jne intchma ; ne = no, leave it alone
xor targ.flgs,modoff ; enabled, toggle its state
intchma:jmp tem ; and reconnect
intchp: call fpush ; 'P' push to DOS
mov dx,offset sttmsg ; say we have returned
mov ah,prstr
int dos
jmp short intchsb ; wait for a space
intchq: and targ.flgs,not capt ; 'Q' suspend session logging
jmp tem ; and resume
intchr: test flags.capflg,logses ; 'R' resume logging. Can we capture?
jz intchr1 ; z = no
or targ.flgs,capt ; turn on session logging flag
intchr1:jmp tem ; and resume
intchs: call stat0 ; 'S' status, call stat0
mov dx,offset sttmsg
mov ah,prstr
int dos
intchsa:call iseof ; is stdin at eof?
jnc intchsb ; nc = not eof, get more
jmp tem ; resume if EOF
intchsb:mov ah,coninq ; console input, no echo
int dos
cmp al,' ' ; space?
jne intchsa
jmp tem
intchu: mov ax,offset inthlp ; '?' get help message
call puthlp ; write help msg
mov dx,offset intprm
mov ah,prstr ; Print it
int dos
jmp intchar ; Get another char
intchn: xor ah,ah ; '0' send a null
call outchr
jmp tem
TELNET ENDP
; Reassure user about connection to the host. Tell him what escape sequence
; to use to return
DOMSG PROC NEAR
mov ah,prstr
mov dx,offset tmsg1
int dos
call escprt
mov ah,prstr
mov dx,offset tmsg3
int dos
ret
DOMSG ENDP
; print the escape character in readable format.
ESCPRT PROC NEAR
mov dl,trans.escchr
cmp dl,' '
jge escpr2
push dx
mov ah,prstr
mov dx,offset esctl
int dos
pop dx
add dl,040H ; Make it printable
escpr2: mov ah,conout
int dos
ret
ESCPRT ENDP
; Set parity for character in Register AL
dopar: push bx
mov bx,portval
mov bl,[bx].parflg ; get parity flag byte
cmp bl,parnon ; No parity?
je parret ; Just return
and al,07FH ; Strip parity. Same as Space parity
cmp bl,parspc ; Space parity?
je parret ; e = yes, then we are done here
cmp bl,parevn ; Even parity?
jne dopar0 ; ne = no
or al,al
jpe parret ; pe = even parity now
xor al,080H ; Make it even parity
jmp short parret
dopar0: cmp bl,parmrk ; Mark parity?
jne dopar1 ; ne = no
or al,080H ; Turn on the parity bit
jmp short parret
dopar1: cmp bl,parodd ; Odd parity?
or al,al
jpo parret ; Already odd, leave it
xor al,080H ; Make it odd parity
parret: pop bx
ret
; REPLAY filespec through terminal emulator
replay proc near
mov dx,offset rdbuf ; place for filename
mov bx,offset rephlp ; help
mov repflg,0 ; clear the replay active flag
mov ah,cmword ; get filename
call comnd
jc replay2 ; c = failure
mov ah,cmeol ; get an EOL confirm
call comnd
jc replay2 ; c = failure
mov ah,open2 ; open file
xor al,al ; open readonly
cmp byte ptr dosnum+1,2 ; above DOS 2?
jna replay1 ; na = no, so no shared access
mov al,0+40h ; open readonly, deny none
replay1:mov dx,offset rdbuf ; asciiz filename
int dos
jnc replay3 ; nc = success
mov ah,prstr
mov dx,offset reperr ; Cannot open that file
int dos
clc
replay2:ret
replay3:mov diskio.handle,ax ; file handle
mov repflg,1 ; set replay flag
call telnet ; enter Connect mode
mov bx,diskio.handle
mov ah,close2 ; close the file
int dos
mov repflg,0 ; clear the flag
clc
ret
replay endp
cptchr proc near ; session capture routine, char in al
test flags.capflg,logses ; session logging active now?
jz cptch1 ; z = no
push di
push es
mov di,data1 ; seg of capbp and capbuf
mov es,di
cld
mov di,es:capbp ; buffer pointer
stosb
inc es:capbp
pop es
pop di
dec caplft ; decrement chars remaining
jg cptch1 ; more room, forget this part
call cptdmp ; dump the info
cptch1: ret
cptchr endp
cptdmp proc near ; empty the capture buffer
push ax
push bx
push cx
push dx
mov bx,sloghnd ; get file handle
or bx,bx ; is file open?
jle cptdm1 ; le = no, skip it
mov cx,cptsiz ; original buffer size
sub cx,caplft ; minus number remaining
jl cptdm2 ; means error
jcxz cptdm1 ; z = nothing to do
push ds
mov dx,data1 ; seg of capbuf
mov ds,dx
mov dx,offset capbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
pop ds
jc cptdm2 ; carry set means error
cmp ax,cx ; wrote all?
jne cptdm2 ; no, an error
push es
mov dx,data1 ; seg of capbuf and capbp
mov es,dx
mov es:capbp,offset capbuf
pop es
mov caplft,cptsiz ; init buffer ptr & chrs left
clc
jmp short cptdm1
cptdm2: and targ.flgs,not capt ; so please stop capturing
and flags.capflg,not logses ; deselect session logging flag bit
mov dx,offset erms23 ; tell user the bad news
call putmod ; write on mode line
stc
cptdm1: pop dx
pop cx
pop bx
pop ax
ret
cptdmp endp
pktcpt proc near ; packet log routine, char in al
test flags.capflg,logpkt ; logging packets now?
jz pktcp1 ; z = no
push di
push es
mov di,data1 ; seg of pktbuf and pktbp
mov es,di
mov di,es:pktbp ; buffer pointer
cld
stosb ; store char in buffer
inc es:pktbp ; move pointer to next free byte
pop es
pop di
dec pktlft ; decrement chars remaining
jg pktcp1 ; g = more room, forget this part
call pktdmp ; dump the info
pktcp1: ret
pktcpt endp
pktdmp proc near ; empty the capture buffer
push ax
push bx
push cx
push dx
mov bx,ploghnd ; get file handle
or bx,bx ; is file open?
jle cptdm1 ; le = no, skip it
mov cx,cptsiz ; original buffer size
sub cx,pktlft ; minus number remaining
jl pktdm2 ; l means error
jcxz pktdm1 ; z = nothing to do
push ds
mov dx,data1 ; seg of pktbuf
mov ds,dx
mov dx,offset pktbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
pop ds
jc pktdm2 ; carry set means error
cmp ax,cx ; wrote all?
jne pktdm2 ; ne = no, error
push es
mov dx,data1 ; seg of pktbuf
mov es,dx
mov es:pktbp,offset pktbuf
pop es
mov pktlft,cptsiz ; init buffer ptr & chrs left
jmp short pktdm1
pktdm2: and flags.capflg,not logpkt ; so please stop capturing
mov dx,offset erms24 ; tell user the bad news
mov ah,prstr
int dos
call clscp4 ; close the packet log
pktdm1: pop dx
pop cx
pop bx
pop ax
ret
pktdmp endp
; CLOSE command
clscpt proc near
mov ah,cmkey ; get kind of file to close
mov dx,offset clotab ; close table
mov bx,offset clohlp ; help
call comnd
jc clscp2 ; c = failure
mov temp,bx
mov ah,cmeol
call comnd
jc clscp2 ; c = failure
mov kstatus,kssuc ; success status thus far
mov bx,temp
cmp bh,40h ; READ-FILE or WRITE-FILE?
jne clscp0 ; ne = no
mov ax,bx
jmp vfclose ; close FILE, pass kind in AX
clscp0: cmp bx,logpkt+logses+logtrn ; close all?
je clscpi ; e = yes
cmp bx,logpkt ; just packet?
je clscp4
cmp bx,logses ; just session?
je clscp6
cmp bx,logtrn ; just session?
jne clscp1 ; ne = no
jmp clscp8
clscp1: mov dx,offset erms22 ; say none active
mov ah,prstr
int dos
clc
ret
clscp2: mov kstatus,ksgen ; general cmd failure status
stc
ret
; CLSCPI called at Kermit exit
CLSCPI: mov bx,portval
mov [bx].flowc,0 ; set no flow control so no sending it
call pntflsh ; flush PRN buffer
call clscp4 ; close packet log
call clscp6 ; close session log
call clscp8 ; close transaction log
mov al,2 ; close WRITE FILE log
call vfclose
clc ; return success
ret
clscp4: push bx ; PACKET LOG
mov bx,ploghnd ; packet log handle
or bx,bx ; is it open?
jle clscp5 ; e = no
call pktdmp ; dump buffer
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp5 ; e = no
mov ah,prstr
mov dx,offset clpktlog ; tell what we are doing
int dos
clscp5: mov ploghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logpkt ; say this log is closed
ret
clscp6: push bx ; SESSION LOG
mov bx,sloghnd ; session log handle
or bx,bx ; is it open?
jle clscp7 ; e = no
call cptdmp ; dump buffer
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp7 ; e = no
mov ah,prstr
mov dx,offset clseslog ; tell what we are doing
int dos
clscp7: mov sloghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logses ; say this log is closed
ret
clscp8: push bx ; TRANSACTION LOG
mov bx,tloghnd ; transaction log handle
or bx,bx ; is it open?
jle clscp9 ; e = no
mov ah,close2
int dos
cmp flags.takflg,0 ; ok to echo?
je clscp9 ; e = no
mov ah,prstr
mov dx,offset cltrnlog ; tell what we are doing
int dos
clscp9: mov tloghnd,-1 ; say handle is invalid
pop bx
and flags.capflg,not logtrn ; say this log is closed
ret
clscpt endp
; Print on PRN the char in register al. On success return with C bit clear.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntchr proc near
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
cmp es:pntptr,offset prnbuf+cptsiz ; buffer full yet?
pop ax
pop es
jb pntchr1 ; b = no
call pntflsh ; flush buffer now
jnc pntchr1 ; nc = success
ret ; c = fail, discard char
pntchr1:push es
push bx
mov bx,data1 ; segment of pntptr and prnbuf
mov es,bx
mov bx,es:pntptr ; pointer to next open slot
mov es:[bx],al ; store the character
inc bx ; update pointer
mov es:pntptr,bx ; save pointer
pop bx
pop es
clc ; clear carry bit
ret
pntchr endp
; Flush printer buffer. Return carry clear if success.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntflsh proc near
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
cmp es:pntptr,offset prnbuf ; any text in buffer?
pop ax
pop es
ja pntfls1 ; a = yes
clc
ret ; else nothing to do
pntfls1:cmp prnhand,0 ; is printer handle valid?
jg pntfls2 ; g = yes
push es
push ax
mov ax,data1 ; segment of pntptr and prnbuf
mov es,ax
mov es:pntptr,offset prnbuf
pop ax
pop es
clc ; omit printing, quietly
ret
pntfls2:push ax
push bx
push cx
push dx
push si
push di
push es
mov ah,flowoff ; get flow control char
or ah,ah ; flow control active?
jz pntfls3 ; z = no, not using xoff
call outchr ; output xoff (ah), no echo
pntfls3:mov bx,prnhand ; file handle for DOS printer PRN
push DS ; about to change DS
mov dx,data1 ; segment of prnbuf
mov ds,dx ; set DS
mov dx,offset prnbuf ; start of buffer
mov cx,ds:pntptr
sub cx,dx ; cx = current byte count
pntfls4:push cx
push dx
mov cx,1
mov ah,write2
int dos ; write buffer to printer
pop dx
pop cx
jc pntfls5 ; c = call failed
cmp ax,1 ; did we write it?
jne pntfls5 ; ne = no, dos critical error
inc dx ; point to next char
loop pntfls4
mov ds:pntptr,offset prnbuf ; reset buffer pointer
pop DS ; restore DS
clc ; declare success
jmp pntfls11
pntfls5:mov si,dx ; address of next char to be printed
mov di,offset prnbuf ; start of buffer
sub dx,di ; dx now = number successful prints
mov cx,ds:pntptr
sub cx,si ; count of chars to be printed
jle pntfls6
mov ax,ds
mov es,ax
cld
rep movsb ; copy unwritten to start of buffer
pntfls6:sub ds:pntptr,dx ; move back printer pointer by ok's
pop DS ; restore DS
pntfls7:mov dx,offset erms26 ; printer not ready, get user action
call putmod ; write new mode line
call beep ; make a noise
mov ah,0ch ; clear DOS typeahead buffer
mov al,1 ; read from DOS buffer
int dos
or al,al ; Special key?
jnz pntfls8 ; nz = no, consume
mov al,1 ; consume scan code
int dos
jmp short pntfls7 ; try again
pntfls8:and al,not 20h ; lower to upper case quickie
cmp al,'R' ; Retry?
jne pntfls8a ; ne = no
call trnmod ; toggle mode line
call trnmod ; back to same state as before
jmp pntfls3 ; go retry
pntfls8a:cmp al,'D' ; Discard printing?
jne pntfls7 ; ne = no, try again
mov bx,prnhand
cmp bx,4 ; stdin/stdout/stderr/stdaux/stdprn?
jbe pntfls9 ; be = yes, always available
mov ah,close2 ; close this file
int dos
pntfls9:mov bx,offset prnname ; name of printer file
mov word ptr [bx],'UN' ; set to NUL<0>
mov word ptr [bx+2],'L'+0
push es
mov ax,data1 ; seg for pntptr
mov es,ax
mov es:pntptr,offset prnbuf ; reset pointer
pop es
mov prnhand,-1 ; declare handle invalid
pntfls10:call trnmod ; toggle mode line
call trnmod ; back to same state as before
stc ; declare failure
pntfls11:pushf
mov ah,flowon
or ah,ah ; flow control active?
jz pntfls12 ; z = no, not using xon
call outchr ; output xon (al), no echo
pntfls12:popf
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret ; nc = success
pntflsh endp
; Check for PRN (DOS's printer) being ready. If ready, return with C clear
; Otherwise, write Not Ready msg on mode line and return with C bit set.
; N.B. DOS Critical Error will occur here if PRN is not ready. [jrd]
pntchk proc near
push dx
push cx
push ax
mov cx,10 ; ten retries before declaring error
cmp prnhand,0 ; printer handle valid?
jle pntchk2 ; le = no, invalid
pntchk0:push bx
mov bx,prnhand ; file handle
mov ah,ioctl ; get printer status, via DOS
mov al,7 ; status for output
int dos
pop bx
jc pntchk1 ; c = call failed
cmp al,0ffh ; code for Ready?
je pntchk3 ; e = yes, assume printer is ready
pntchk1:push cx ; save counter, just in case
mov ax,100 ; wait 100 millisec
call pcwait
pop cx
loop pntchk0 ; and try a few more times
; get here when printer is not ready
pntchk2:pop ax
pop cx
pop dx
stc ; say printer not ready
ret
pntchk3:pop ax
pop cx
pop dx
clc ; say printer is ready
ret
pntchk endp
prnopen proc near
push ax
push bx
push cx
push dx
mov prnhand,4 ; preset default handle
mov dx,offset prnname ; name of disk file, from mssset
mov ax,dx ; where isfile wants name ptr
call isfile ; what kind of file is this?
jc prnop3 ; c = no such file, create it
test byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
jnz prnop2 ; nz = no
mov al,1 ; writing
mov ah,open2 ; open existing file
int dos
jc prnop2 ; c = failure
mov prnhand,ax ; save file handle
mov bx,ax ; handle for DOS
mov ah,ioctl
mov al,0 ; get info
int dos
or dl,20h ; turn on binary mode
xor dh,dh
mov ah,ioctl
mov al,1 ; set info
int dos
mov cx,0ffffh ; setup file pointer
mov dx,-1 ; and offset
mov al,2 ; move to eof minus one byte
mov ah,lseek ; seek the end
int dos
pop dx
pop cx
pop bx
pop ax
clc
ret
prnop2: stc
ret
prnop3: test filtst.fstat,80h ; access problem?
jnz prnop2 ; nz = yes
mov ah,creat2 ; file did not exist
mov cx,20h ; attributes, archive bit
int dos
mov prnhand,ax ; save file handle
pop dx
pop cx
pop bx
pop ax
ret ; may have carry set
prnopen endp
; worker: copy line from si to di, first removing trailing spaces, second
; parsing out curly braced strings, then third converting \{b##} in strings
; to binary numbers. Returns carry set if error; else carry clear, with byte
; count in cx. Braces are optional but must occur in pairs.
; Items which cannot be converted to legal numbers are copied verbatium
; to the output string (ex: \{c} is copied as \{c} but \{x0d} is hex 0dh).
cnvlin proc near
push ax
push si ; source ptr
push di ; destination ptr
push es ; end of save regs
push ds ; move ds into es
pop es ; use data segment for es:di
call cnvstr ; trim trailing, parse curly braces
xor cx,cx ; initialize returned byte count
cnvln1: cmp byte ptr [si],0 ; at end of string?
je cnvln2 ; e = yes, exit
call katoi ; read char, convert ascii to binary
cld
stosb ; save the char
inc cx ; and count it
or ah,ah ; is returned number > 255?
jz cnvln1 ; z = no, do more chars
push ax
stosb ; save high order byte next
pop ax
inc cx
jmp short cnvln1 ; do more chars
cnvln2: mov byte ptr [di],0 ; plant terminator
clc ; clear c bit, success
pop es ; restore regs
pop di ; destination ptr
pop si ; source ptr
pop ax
ret
cnvlin endp
; Convert string by first remove trailing spaces and then removing surrounding
; curly brace delimiter pair. Converts text in place.
; Enter with source ptr in si.
; Preserves all registers, uses byte tmp. 9 Oct 1987 [jrd]
;
cnvstr proc near
push ax
push cx
push dx
push si ; save start of source string
push di
push es
; 1. Trim trailing spaces
mov dx,si ; source address
call strlen ; get current length to cx
jcxz cnvst4 ; z = nothing there
mov di,si ; set di to source address
add di,cx ; start at end of string
dec di ; ignore terminator
mov al,spc ; scan while spaces
push ds
pop es ; set es to data segment
std ; search backward
repe scasb ; scan off trailing spaces
mov byte ptr [di+2],0 ; terminate string after last text
cld
mov di,si ; set destination address to source
; 2. Parse off curly brace delimiters
cmp byte ptr [si],braceop ; opening brace?
jne cnvst4 ; ne = no, ignore brace-matching code
inc si ; skip opening brace
mov dl,braceop ; opening brace (we count them up)
mov dh,bracecl ; closing brace (we count them down)
mov tmp,1 ; we are at brace level 1
cnvst1: cld ; search forward
lodsb ; read a string char
stosb ; store char (skips opening brace)
or al,al ; at end of string?
jz cnvst4 ; z = yes, we are done
cmp al,dl ; an opening brace?
jne cnvst2 ; ne = no
inc tmp ; yes, increment brace level
jmp short cnvst1 ; and continue scanning
cnvst2: cmp al,dh ; closing brace?
jne cnvst1 ; ne = no, continue scanning
dec tmp ; yes, decrement brace level
cmp byte ptr [si],0 ; have we just read the last char?
jne cnvst3 ; no, continue scanning
mov tmp,0 ; yes, this is the closing brace
cnvst3: cmp tmp,0 ; at level 0?
jne cnvst1 ; ne = no, #opening > #closing braces
mov byte ptr [di-1],0 ; plant terminator on closing brace
cnvst4: pop es ; recover original registers
pop di
pop si
pop dx
pop cx
pop ax
ret
cnvstr endp
; Convert ascii strings of the form "\{bnnn}" to a binary word in ax.
; The braces are optional but must occur in pairs. Numeric base indicator "b"
; is O or o or X or x or D or d or missing, for octal, hex, or decimal (def).
; Enter with si pointing at "\".
; Returns binary value in ax with carry clear and si to right of "}" or at
; terminating non-numeric char if successful; otherwise, a failure,
; return carry set with si = entry value + 1 and first read char in al.
katoi proc near
cld
lodsb ; get first char
xor ah,ah ; clear high order field
push cx ; save working reg
push si ; save entry si+1
push bx
push ax ; save read char
or al,al ; end of text?
jz katoi1a ; z = yes, exit failure
cmp al,'\' ; escape char?
je katoi1b ; e = yes
katoi1a:jmp katoix ; common jump point to exit failure
katoi1b:lodsb ; get next char, maybe brace
or al,al ; premature end?
jz katoi1a ; z = yes, exit failure
xor bx,bx ; no conv yet, assume no opening brace
cmp al,braceop ; opening brace?
jne katoi2 ; ne = no, have number or base
mov bl,bracecl ; remember a closing brace is needed
lodsb ; get number base, if any
katoi2: xor cx,cx ; temporary place for binary value
mov nbase,10 ; assume decimal numbers
or al,al ; premature end?
jz katoix ; z = yes, exit failure
cmp al,'a' ; lower case?
jb katoi3 ; b = no
cmp al,'z' ; in range of lower case?
ja katoi3 ; a = no
and al,5fh ; map to upper case
katoi3: cmp al,'O' ; octal?
jne katoi4 ; ne = no
mov nbase,8 ; set number base
jmp short katoi6
katoi4: cmp al,'X' ; hex?
jne katoi5 ; ne = no
mov nbase,16
jmp short katoi6
katoi5: cmp al,'D' ; decimal?
jne katoi7 ; ne = no base char, assume decimal
mov nbase,10
katoi6: lodsb ; get a digit
katoi7: or al,al ; premature end?
jz katoi8a ; z = yes, use it as a normal end
cmp al,bl ; closing brace?
je katoi9 ; e = yes
call cnvdig ; convert ascii to binary digit
jc katoi8 ; c = cannot convert
inc bh ; say we did a successful conversion
xor ah,ah ; clear high order value
push ax ; save this byte's value
xchg ax,cx ; put binary summation in ax
mul nbase ; scale up current sum
xchg ax,cx ; put binary back in cx
pop ax ; recover binary digit
add cx,ax ; form running sum
jc katoix ; c = overflow error, exit
or dx,dx ; overflow?
jnz katoix ; nz = yes, exit with error
jmp short katoi6 ; get more
katoi8: or bl,bl ; closing brace needed?
jnz katoix ; nz = yes, but not found
katoi8a:dec si ; backup to reread terminator
katoi9: or bh,bh ; did we do any conversion?
jz katoix ; z = no, exit failure
pop ax ; throw away old saved ax
pop bx ; restore bx
pop ax ; throw away starting si, keep current
mov ax,cx ; return final value in ax
pop cx ; restore old cx
clc ; clear carry for success
ret
katoix: pop ax ; restore first read al
pop bx
pop si ; restore start value + 1
pop cx ; restore old cx
stc ; set carry for failure
ret
katoi endp
cnvdig proc near ; convert ascii code in al to binary
push cx ; return carry set if cannot
push es ; nbase has numeric base
push di
push ax
cmp al,'a' ; lower case?
jb cnvdig1 ; b = no
cmp al,'f' ; highest hex digit
ja cnvdigx ; a = illegal symbol
sub al,'a'-'A' ; convert 'a' to 'f' to upper case
cnvdig1:mov di,offset numset ; set of legal number symbols
mov cx,nbase ; number of legal symbols in this base
cmp cx,cx ; preset z flag
push ds
pop es ; point es at data segment
cld ; scan forward
repne scasb ; find character in set
jne cnvdigx ; ne = not found
inc cx ; offset auto-dec of repne scasb above
sub cx,nbase ; counted off minus length
neg cx ; two's complement = final value
pop ax ; saved ax
mov ax,cx ; return binary in al
clc ; c clear for success
jmp short cnvdixx ; exit
cnvdigx:stc ; c set for failure
pop ax
cnvdixx:pop di
pop es
pop cx
ret
cnvdig endp
decout proc near ; display decimal number in ax
push ax
push cx
push dx
mov cx,10 ; set the numeric base
call valout ; convert and output value
pop dx
pop cx
pop ax
ret
decout endp
valout proc near ; output number in ax using base in cx
; corrupts ax and dx
xor dx,dx ; clear high word of numerator
div cx ; (ax / cx), remainder = dx, quotient = ax
push dx ; save remainder for outputting later
or ax,ax ; any quotient left?
jz valout1 ; z = no
call valout ; yes, recurse
valout1:pop dx ; get remainder
add dl,'0' ; make digit printable
cmp dl,'9' ; above 9?
jbe valout2 ; be = no
add dl,'A'-1-'9' ; use 'A'--'F' for values above 9
valout2:mov ah,conout
int dos
ret
valout endp
; Convert input in buffer pointed to by SI to real number which is returned
; in DX:AX. Enter with string size in AH.
; Return carry set on failure, carry clear on success.
ATOI PROC NEAR
xor bx,bx ; high order of this stays 0
mov tmp,bl ; no input yet
mov cl,ah ; number of chars of input
xor ch,ch ; size of string
xor ax,ax ; init sum
xor dx,dx ; high order part of sum
cld
atoi0: jcxz atoi4 ; Fail on no input
mov bl,[si] ; get an input char
inc si
dec cx ; count number remaining
cmp bl,' ' ; leading space?
je atoi0 ; e = yes, skip it
cmp bl,',' ; comma separator?
je atoi0 ; e = yes, skip it
dec si ; back up source pointer for reread below
inc cx ; and readjust byte counter
atoi1: mov bl,[si] ; get a new char
inc si
cmp bl,'9' ; check range for '0' to '9'
ja atoi2 ; above '9'
cmp bl,'0'
jb atoi2 ; below '0'
sub bl,'0' ; take away ascii bias
push bx ; save digit and high null
shl ax,1
rcl dx,1 ; current sum * 2
push dx
push ax ; save it
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1 ; times * 4 more
pop bx ; low * 2
add bx,ax
mov ax,bx ; low order * 10
pop bx
adc bx,dx
mov dx,bx ; high order * 10
pop bx ; new digit and high null
add ax,bx ; plus new digit
adc dx,0
mov tmp,1 ; say have sum being computed
loop atoi1
inc si ; inc for dec below
atoi2: dec si ; point at terminator
cmp tmp,0 ; were any digits discovered?
je atoi4 ; e = no, fail
clc ; success
ret
atoi4: mov dx,offset erms25 ; Input must be numeric
stc ; failure
ret
ATOI ENDP
; Write binary number in AX as decimal asciiz to buffer pointer DI.
dec2di proc near ; output number in ax using base in cx
push ax
push cx
push dx
mov cx,10
call dec2di1 ; recursive worker
pop dx
pop cx
pop ax
ret
dec2di1:xor dx,dx ; clear high word of numerator
div cx ; (ax / cx), remainder = dx, quotient = ax
push dx ; save remainder for outputting later
or ax,ax ; any quotient left?
jz dec2di2 ; z = no
call dec2di1 ; yes, recurse
dec2di2:pop dx ; get remainder
add dl,'0' ; make digit printable
mov [di],dl ; store char in buffer
inc di
mov byte ptr[di],0 ; add terminator
ret
dec2di endp
; OPEN { READ | WRITE | APPEND } filespec
vfopen proc near
mov ah,cmkey ; get READ/WRITE/APPEND keyword
mov dx,offset opntab ; keyword table
xor bx,bx ; help
call comnd
jc vfopen1 ; c = failed
mov temp,bx
mov ah,cmword ; read filespec
mov dx,offset rdbuf ; buffer for filename
mov bx,offset vfophlp ; help
call comnd
jc vfopen1 ; c = failed
mov ah,cmeol ; get end of line confirmation
call comnd
jnc vfopen2
mov kstatus,ksgen ; general cmd failure status
vfopen1:ret ; error return, carry set
vfopen2:mov kstatus,kssuc ; assume success status
mov dx,offset rdbuf ; filename, asiiz
mov bx,temp ; kind of open
cmp bx,1 ; open for reading?
jne vfopen4 ; ne = no
; OPEN READ
cmp vfrhandle,0 ; is it open now?
jge vfopen8 ; ge = yes, complain
mov ah,open2 ; file open
xor al,al ; 0 = open readonly
cmp dosnum,300h ; at or above DOS 3?
jb vfopen3 ; b = no, so no shared access
or al,40h ; open readonly, deny none
vfopen3:int dos
jc vfopen9 ; c = failed to open the file
mov vfrhandle,ax ; save file handle
clc
ret
; OPEN WRITE or APPEND
vfopen4:cmp vfwhandle,0 ; is it open now?
jge vfopen8 ; ge = yes, complain
mov ax,dx ; filename for isfile
call isfile ; check for read-only/system/vol-label/dir
jc vfopen7 ; c = file does not exist
test byte ptr filtst.dta+21,1fh ; the no-no file attributes
jnz vfopen9 ; nz = do not write over one of these
vfopen5:test filtst.fstat,80h ; access problem?
jnz vfopen9 ; nz = yes, quit here
test byte ptr filtst.dta+21,1bh ; r/o, hidden, volume label?
jnz vfopen9 ; we won't touch these
mov ah,open2 ; open existing file (usually a device)
mov al,1+1 ; open for writing
int dos
jc vfopen9 ; carry set means can't open
mov vfwhandle,ax ; remember file handle
mov bx,ax ; file handle for lseek
xor cx,cx
xor dx,dx ; cx:dx = displacment
xor al,al ; 0 means from start of file
cmp temp,2 ; WRITE? means from start of file
je vfopen6 ; e = yes, else APPEND
mov al,2 ; move to eof
vfopen6:mov ah,lseek ; seek the place
int dos
clc
ret
vfopen7:cmp temp,1 ; READ?
je vfopen9 ; e = yes, should not be here
mov ah,creat2 ; create file
xor cx,cx ; 0 = attributes bits
int dos
jc vfopen9 ; c = failed
mov vfwhandle,ax ; save file handle
clc ; carry clear for success
ret
vfopen8:mov dx,offset vfoptwice ; trying to reopen a file
mov ah,prstr
int dos
mov kstatus,kstake ; Take file failure status
stc
ret
vfopen9:mov dx,offset vfopbad ; can't open, complain
mov ah,prstr
int dos
mov dx,offset rdbuf ; filename
call prtasz
mov kstatus,kstake ; Take file failure status
stc
ret
vfopen endp
; CLOSE {READ-FILE | WRITE-FILE}
vfclose proc near
mov tmp,al ; remember kind (1=READ, 2=WRITE)
mov bx,vfrhandle ; READ FILE handle
cmp al,1 ; READ-FILE?
je vfclos1 ; e = yes
cmp al,2 ; WRITE-FILE?
jne vfclos3 ; ne = no, a mistake
mov bx,vfwhandle ; write handle
or bx,bx
jl vfclos3 ; l = invalid handle
mov dx,offset rdbuf
xor cx,cx ; zero length
push bx ; save handle
mov ah,write2 ; set file high water mark
int dos
pop bx
vfclos1:or bx,bx
jl vfclos3 ; l = invalid handle
mov kstatus,kssuc ; success status thus far
mov ah,close2 ; close file
int dos
jc vfclos4 ; c = error
cmp tmp,1 ; READ?
jne vfclos2 ; ne = no, WRITE
mov vfrhandle,-1 ; declare READ handle to be invalid
clc
ret
vfclos2:mov vfwhandle,-1 ; declare WRITE handle to be invalid
clc
ret
vfclos4:mov ah,prstr
mov dx,offset vfclbad ; complain
int dos
vfclos3:mov kstatus,ksgen ; general cmd failure status
stc
ret
vfclose endp
; READ-FILE variable name
vfread proc near
mov comand.cmper,1 ; do not react to '\%' in macro name
mov ah,cmword
mov dx,offset rdbuf+2 ; buffer for macro name
mov word ptr rdbuf,0
mov bx,offset vfrdmsg
call comnd ; get macro name
jnc vfread1 ; nc = success
mov kstatus,ksgen ; general cmd failure status
ret ; failure
vfread1:or ax,ax ; null entry?
jnz vfread2 ; nz = no
mov dx,offset vfrdbad ; more parameters needed
mov ah,prstr
int dos
mov kstatus,ksgen ; general cmd failure status
stc
ret
vfread2:push ax
mov ah,cmeol ; get command confirmation
call comnd
pop ax ; ax is variable length
jc vfreadx ; c = failed
mov cx,cmdblen ; length of rdbuf
sub cx,ax ; minus macro name
dec cx ; minus space separator
mov temp,0 ; leading whitespace and comment flgs
mov di,offset rdbuf+2 ; destination buffer
add di,ax ; plus variable name
mov byte ptr [di],' ' ; space separator
inc di ; put definition here
mov bx,vfrhandle ; READ FILE handle
or bx,bx ; check for valid handle
jge vfread3 ; ge = valid
mov ah,prstr
mov dx,offset vfnofile ; say no file
int dos
vfreadx:mov kstatus,ksgen ; general cmd failure status
stc ; failure return
ret
vfread3:push cx ; read from file
mov kstatus,kssuc ; assume success status
mov cx,1 ; read 1 char
mov dx,di ; place here
mov byte ptr [di],0 ; insert terminator
mov ah,readf2
int dos
pop cx
jc vfreadx ; c = read failure
or ax,ax ; count of bytes read
jz vfread9 ; z means end of file
mov al,[di] ; get the character
cmp flags.takflg,0 ; echo Take files?
je vfread3a ; e = no
push ax
mov ah,conout
mov dl,al ; echo character
int dos
pop ax
vfread3a:cmp al,CR ; CR?
je vfread7 ; e = yes, ignore it
cmp al,LF ; LF?
je vfread8 ; e = yes, exit
cmp al,';' ; start of comment?
jne vfread4 ; ne = no
mov byte ptr temp+1,1 ; say comment has started
vfread4:cmp byte ptr temp+1,0 ; seen comment semicolon yet?
jne vfread7 ; ne = yes, do not store comment
cmp byte ptr temp,0 ; seen non-spacing char yet?
jne vfread6 ; ne = yes
cmp al,' ' ; is this a space?
je vfread7 ; e = yes, skip it
cmp al,TAB ; or a tab?
je vfread7 ; e = yes, skip it
mov byte ptr temp,1 ; say have seen non-spacing char
vfread6:inc di ; next storage cell
vfread7:loop vfread3 ; loop til end of line
vfread8:cmp byte ptr [di-1],'-' ; last printable is line-continuation?
jne vfread10 ; ne = no, use this line as-is
dec di ; point to hyphen
mov cx,offset rdbuf+cmdblen ; end of rdbuf
sub cx,di ; minus where we are now
jle vfread10 ; le = no space remaining
mov temp,0 ; leading whitespace and comment flgs
jmp vfread3 ; read another line
vfread9:mov kstatus,ksgen ; EOF, general command failure status
vfread10:cmp flags.takflg,0 ; echo Take files?
je vfread11 ; e = no
mov ah,prstr
mov dx,offset crlf ; for last displayed line
int dos
vfread11:mov byte ptr [di],0 ; insert final terminator
mov dx,offset rdbuf+2 ; start counting from here
push kstatus ; preserve status from above work
call strlen ; cx becomes length
call dodecom ; create the variable
pop kstatus ; recover reading status
jc vfread12 ; c = failure
ret
vfread12:mov kstatus,ksgen ; general command failure status
mov ah,prstr
mov dx,offset vfrbad ; say error while reading
int dos
stc
ret
vfread endp
; WRITE {FILE or log} text
Write proc near
mov ah,cmkey ; get kind of log file
mov dx,offset writetab ; table of possibilities
xor bx,bx ; help, when we get there
call comnd
jnc write1 ; nc = success
mov kstatus,ksgen ; general cmd failure status
ret
write1: mov temp,bx ; save log file kind
mov ah,cmline ; get string to be written
mov bx,offset rdbuf ; where to put text
mov dx,offset msgtxt ; help
call comnd
mov ah,cmeol
call comnd
jnc wpkt0
mov kstatus,ksgen ; general cmd failure status
ret ; c = failure
wpkt0: mov kstatus,kssuc ; success status thus far
mov si,offset rdbuf ; start of text in buffer
mov di,si ; convert in-place, to asciiz
call cnvlin
mov bx,temp ; log file kind
mov si,offset rdbuf
mov dx,si
call strlen
jcxz wpkt2 ; z = no chars to write
cmp bx,logpkt ; Packet log?
jne wses1 ; ne = no
wpkt1: lodsb ; get byte to al
call pktcpt ; write to packet log
loop wpkt1
wpkt2: clc ; say success
ret
wses1: cmp bx,logses ; Session log?
jne wtrn1 ; ne = no
wses2: lodsb ; get byte to al
call cptchr ; write to log
loop wses2 ; do cx chars
clc ; say success
ret
wtrn1: cmp bx,logtrn ; Transaction log?
jne wtrn2 ; ne = no
mov bx,tloghnd ; file handle
jmp short wtrn4
wtrn2: cmp bx,80h ; WRITE SCREEN?
jne wtrn3 ; ne = no
xor bx,bx ; handle is stdout
jmp short wtrn4
wtrn3: cmp bx,4002h ; WRITE FILE?
jne wtrn5 ; ne = no, forget this
mov bx,vfwhandle ; handle
wtrn4: or bx,bx ; is handle valid?
jl wtrn5 ; l = no
mov ah,write2 ; write to file handle in bx
int dos
jc wtrn4a ; c = failure
ret
wtrn4a: mov ah,prstr
mov dx,offset vfwbad ; say error while writing
int dos
mov kstatus,ksgen
stc
ret
wtrn5: mov kstatus,ksgen ; general cmd failure status
mov ah,prstr
mov dx,offset vfnofile ; say no file
int dos
stc
ret
write endp
code ends
end