home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
extra
/
nyenhuis3.arc
/
MSSTER.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-14
|
35KB
|
1,192 lines
NAME msster
; File MSSTER.ASM
include mssdef.h
; Last edit 14 Jan 1990
public clscpt, defkey, clscpi, ploghnd, sloghnd, tloghnd
public dopar, shokey, cptchr, pktcpt, targ, replay, repflg
public kbdflg, shkadr, telnet, ttyact, write, dec2di
public cnvlin, katoi, decout, valout, atoi, cnvstr
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
data segment public 'data'
extrn flags:byte, trans:byte, portval:word, taklev:byte, takadr:word
extrn comand:byte, verident:byte, rdbuf:byte, errlev:byte
extrn dosnum:word, diskio: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,'$'
erms25 db cr,lf,'?Input must be numeric$'
erms22 db cr,lf,'?No open logging file$'
erms23 db cr,lf,'?Error writing session log, suspending capture.'
db cr,lf,'$'
erms24 db cr,lf,'?Error writing Packet log$'
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 'optional text, if any$'
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,' 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'
numlet equ $ - intclet ; number of entries
even
intcjmp dw intchb,intchc,intchf,intchh,intchl
dw intchm,intchp,intchq,intchr,intchs
dw intchu,intchn
pktbuf db cptsiz dup (?) ; packet logging buffer
pktbp dw pktbuf ; buffer pointer to next free byte
pktlft dw cptsiz ; number free bytes left
capbuf db cptsiz dup (?) ; session logging buffer
capbp dw capbuf ; buffer pointer to next free byte
caplft dw cptsiz ; number free bytes left
even
ploghnd dw -1 ; packet logging handle
sloghnd dw -1 ; session logging handle
tloghnd dw -1 ; transaction logging handle
clotab db 4
mkeyw 'All',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,' One of the following log files:'
db cr,lf,' ALL, Packets, Session, Transaction$'
writetab db 4 ; Write command log file types
mkeyw 'Packet',logpkt
mkeyw 'Screen',80h ; unused value, to say screen
mkeyw 'Session',logses
mkeyw 'Transaction',logtrn
wrtobj db 9 ; table of objects to be written
mkeyw 'ARGC',wrtargc ; Argument count
mkeyw 'COUNT',wrtcnt ; loop COUNT
mkeyw 'Date',wrtdate ; DOS date
mkeyw 'Errorlevel',wrterr ; Errorlevel
mkeyw 'INPUT-buffer',wrtinp ; Input command's circular buffer
mkeyw 'Path',wrtpath ; current DOS path
mkeyw 'Text',wrttxt ; text
mkeyw 'Time',wrttime ; DOS time of day
mkeyw 'Version',wrtver ; version of MS Kermit
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
ten dw 10 ; multiplier for setatoi
nbase dw ? ; currently active number base
numset db '0123456789ABCDEF' ; number conversion alphabet
temp dw 0
tmp db 0
data ends
code segment public 'code'
extrn comnd:near, outchr:near, stat0:near, iseof:near
extrn term:near, strlen:near, buflog:near
extrn beep:near, puthlp:near, getbaud:near, serhng:near
extrn serini:near,serrst:near, sendbr:near
extrn fpush:near, dumpscr:near, sendbl: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 teln2 ; nc = success
ret
teln2: mov ah,prstr
mov dx,offset crlf ; output a crlf
int dos
cmp flags.vtflg,0 ; emulating a terminal?
jne teln1 ; ne= yes, skip flashing message
call domsg ; Reassure user
teln1: call serini ; ensure port is inited now
mov al,0 ; 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
or al,lclecho
tel2: call getbaud ; pickup current baud rate for port
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
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
cmp al,0 ; was there a char from Term?
jne intch2 ; ne = 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 intchc ; to provide an exit
intch1: mov ah,coninq ; read keyboard, no echo
int dos ; get a char
cmp al,0 ; scan code indicator?
jne intch2 ; ne = no, ascii
mov ah,coninq ; read and discard scan code
int dos
jmp short intch1 ; try again
intch2: 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 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
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
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 intchsb ; wait for a space
intchq: test targ.flgs,capt ; 'Q' suspend logging. Logging active?
jz intchq1 ; z = no
and targ.flgs,not capt ; stop capturing
intchq1:jmp tem ; and resume
intchr: test flags.capflg,logses ; 'R' resume logging. Can we capture?
jz intchr1 ; z = no
test targ.flgs,capt ; already capturing?
jnz intchr1 ; yes, can't toggle back on then
or targ.flgs,capt ; else turn flag on
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: mov ah,0 ; '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 and the communications port and baud; rate being used
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 dosnum,200h ; 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
push di
mov di,capbp ; buffer pointer
mov byte ptr [di],al
inc capbp
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
cmp bx,0 ; 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
mov dx,offset capbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
jc cptdm2 ; carry set means error
mov capbp,offset capbuf
mov caplft,cptsiz ; init buffer ptr & chrs left
jmp short cptdm1
cptdm2: and flags.capflg,not logses ; so please stop capturing
and targ.flgs,not capt ; so please stop capturing
mov dx,offset erms23 ; tell user the bad news
mov ah,prstr
int dos
cptdm1: pop dx
pop cx
pop bx
pop ax
ret
cptdmp endp
pktcpt proc near ; packet log routine, char in al
push di
mov di,pktbp ; buffer pointer
mov [di],al ; store char in buffer
inc pktbp ; move pointer to next free byte
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
cmp bx,0 ; 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
mov dx,offset pktbuf ; the capture routine buffer
mov ah,write2 ; write with filehandle
int dos ; write out the block
jc pktdm2 ; carry set means error
mov pktbp,offset pktbuf
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
mov dx,offset clotab ; close table
mov bx,offset clohlp ; help
call comnd
jc clscp2 ; c = failure
mov tmp,bl
mov ah,cmeol
call comnd
jc clscp2 ; c = failure
mov bl,tmp
test flags.capflg,0FFH ; are any kinds active?
jz clscp1 ; z = no
cmp bl,logpkt+logses+logtrn ; close all?
je clscpi ; e = yes
cmp bl,logpkt ; just packet?
je clscp4
cmp bl,logses ; just session?
je clscp6
cmp bl,logtrn ; just session?
je clscp8
clscp1: mov dx,offset erms22 ; say none active
mov ah,prstr
int dos
clc
clscp2: ret
; CLSCPI called at Kermit exit
CLSCPI: call clscp4 ; close packet log
call clscp6 ; close session log
call clscp8 ; close transaction log
clc ; return success
ret
clscp4: push bx ; PACKET LOG
mov bx,ploghnd ; packet log handle
cmp bx,0 ; is it open?
jle clscp5 ; e = no
call pktdmp ; dump buffer
mov ah,close2
int dos
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
cmp bx,0 ; is it open?
jle clscp7 ; e = no
call cptdmp ; dump buffer
mov ah,close2
int dos
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
cmp bx,0 ; is it open?
jle clscp9 ; e = no
mov ah,close2
int dos
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
; 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)
cmp al,0 ; at end of string?
je cnvst4 ; e = 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
cmp al,0 ; end of text?
je katoi1a ; e = 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
cmp al,0 ; premature end?
je katoi1a ; e = 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
cmp al,0 ; premature end?
je katoix ; e = 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: cmp al,0 ; premature end?
je katoi8a ; e = 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
cmp dx,0 ; overflow?
jne katoix ; ne = yes, exit with error
jmp short katoi6 ; get more
katoi8: cmp bl,0 ; closing brace needed?
jne katoix ; ne = yes, but not found
katoi8a:dec si ; backup to reread terminator
katoi9: cmp bh,0 ; did we do any conversion?
je katoix ; e = 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 AX. Enter with string size in AH.
; Return carry set on failure, carry clear on success.
ATOI PROC NEAR
mov bx,0 ; high order of this stays 0
mov tmp,0 ; No input yet
mov cl,ah ; Number of chars of input
mov ch,0 ; size of string
mov ax,0 ; init sum
cld
atoi0: jcxz atoi4 ; Fail on no input
lodsb ; get an input char
dec cx ; count number remaining
cmp al,' ' ; leading space?
je atoi0 ; e = yes, skip it
cmp al,',' ; comma separator?
je atoi0 ; e = yes, skip it
dec si ; back up source pointer for reread below
inc cx ; and readjust byte counter
mov ax,0 ; clear sum
atoi1: push ax ; save sum
lodsb ; read a byte into al
mov bl,al ; put it into bl
pop ax ; regain sum
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
mul ten ; sum * 10. dx = high, ax = low
add ax,bx ; add current value
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
; corrupts ax, cx, and dx
mov cx,10
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
; WRITE {log} {object} {optional 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
jc write1 ; c = failure
mov tmp,bl ; save log file kind
mov ah,cmkey ; get kind of object to write
mov comand.cmkeep,1 ; keep Take/Macro open after this call
mov dx,offset wrtobj ; table of objects
xor bx,bx
call comnd
jc write1 ; c = failure
jmp bx ; do the routine to do the writing
write1: ret
write endp ; jmp rskp is success, ret is fail
; WRITE <log> ARGC
wrtargc proc near
xor ax,ax
mov di,offset rdbuf ; where to write the buffer
cmp taklev,0 ; in a Take/Macro?
je wrtarg1 ; e = no
mov bx,takadr ; current Take structure
mov ax,[bx].takargc ; get ARGC
wrtarg1:call dec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrtargc endp
; WRITE <log> COUNT
wrtcnt proc near
xor ax,ax
mov di,offset rdbuf ; where to write the buffer
cmp taklev,0 ; in a Take/Macro?
je wrtcnt1 ; e = no
mov bx,takadr ; current Take structure
mov ax,[bx].takctr ; get COUNT
wrtcnt1:call dec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrtcnt endp
; Write <log> DATE <optional text>
wrtdate proc near
mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd)
int dos
mov di,offset rdbuf
push cx ; save cx
push dx ; save dx
xor ah,ah
mov al,dh ; Months
cmp al,10 ; leading tens digit present?
jae wrtdat1 ; ae = yes
mov byte ptr [di],'0' ; insert leading 0
inc di
wrtdat1:call dec2di ; write decimal asciiz to buffer
mov byte ptr [di],'-'
inc di
pop dx ; recover dx
xor ah,ah
mov al,dl ; Days
cmp al,10 ; leading digit?
jae wrtdat2 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrtdat2:call dec2di ; write decimal asciiz to buffer
mov byte ptr [di],'-'
inc di
pop cx ; recover cx
mov ax,cx ; Year (omit century)
call dec2di ; write decimal asciiz to buffer
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrtdate endp
; WRITE <log> ERRORLEVEL
wrterr proc near
mov di,offset rdbuf ; where to write the buffer
mov al,errlev ; current Errorlevel
xor ah,ah
call dec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrterr endp
; Write <log> INPUT-buffer (no trailing text)
wrtinp proc near
mov ah,cmeol ; get a confirm
call comnd
jnc wrtin6 ; nc = success
ret ; failure
wrtin6: push es
call buflog ; get INPUT buffer pointers
mov bx,cx ; length of buffer (and max offset)
mov di,offset rdbuf ; where to write the buffer
mov byte ptr [di],'<' ; start with "<# unread chars>"
inc di
push cx
push dx
call dec2di ; ax has unread count, bufcnt
pop dx
pop cx
mov byte ptr [di],'>'
inc di
wrtin1: mov al,es:[si] ; extract a buffer char into al
inc si ; move pointer to next byte
test al,80h ; high bit set?
jz wrtin2 ; z = no
mov byte ptr [di],'~' ; yes, show a tilde
inc di
wrtin2: and al,7fh ; strip eighth bit
cmp al,' ' ; control code?
jae wrtin3 ; ae = no
mov byte ptr [di],'^' ; yes, show caret
inc di
or al,40h ; convert char to upper case letter
wrtin3: mov [di],al
inc di ; where to write next byte
cmp di,offset rdbuf+78 ; line full?
jb wrtin4 ; b = no, have more room
mov word ptr [di],0a0dh ; add cr/lf
mov byte ptr [di+2],0
push bx
push cx
push dx
push si
push es
call wrtcom ; dump what we have
pop es
pop si
pop dx
pop cx
pop bx
mov di,offset rdbuf ; reset to start of our local buffer
wrtin4: cmp si,bx ; beyond end of Input buffer?
jb wrtin5 ; b = not yet
xor si,si ; reset to start of INPUT-buf (wrap)
wrtin5: loop wrtin1
mov word ptr [di],0a0dh ; add cr/lf
mov byte ptr [di+2],0
pop es
jmp wrtcom ; write the last of INPUT buffer
wrtinp endp
; Write <log> PATH <optional text>
wrtpath proc near
mov si,offset rdbuf ; work buffer
mov ah,gcurdsk ; get current disk
int dos
add al,'A' ; make al = 0 == 'A'
mov [si],al
mov word ptr [si+1],'\:'
add si,3 ; end with a colon and backslash
mov ah,gcd ; get current directory (path really)
xor dl,dl ; use current drive
int dos ; get ds:si = asciiz path (no drive)
mov dx,si
call strlen
add si,cx
mov word ptr [si],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrtpath endp
; Write <log> TIME <optional text>
wrttime proc near
mov ah,gettim ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
int dos
mov di,offset rdbuf
push dx ; save dx
xor ah,ah
mov al,ch ; Hours
cmp al,10 ; leading digit?
jae wrttim1 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim1:push cx
call dec2di ; write decimal asciiz to buffer
pop cx
mov byte ptr [di],':'
inc di
xor ah,ah
mov al,cl ; Minutes
cmp al,10 ; leading digit?
jae wrttim2 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim2:call dec2di ; write decimal asciiz to buffer
mov byte ptr [di],':'
inc di
pop dx
push dx
xor ah,ah
mov al,dh ; Seconds
cmp al,10 ; leading digit?
jae wrttim3 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim3:call dec2di ; write decimal asciiz to buffer
mov byte ptr [di],'.'
inc di
pop dx
xor ah,ah
mov al,dl ; Hundredths of seconds
cmp al,10 ; leading digit?
jae wrttim4 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim4:call dec2di ; write decimal asciiz to buffer
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrttime endp
; Write <log> Version (no optional text)
wrtver proc near
mov si,offset verident ; MS Kermit version string in mssker
mov di,offset rdbuf
cld
wrtver1:lodsb
mov [di],al
inc di
cmp al,'$' ; end of string?
jne wrtver1 ; ne = no, continue copying
dec di
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
jmp wrttxt1 ; add any trailing text
wrtver endp
; Write <log> TEXT <optional text>
wrttxt proc near ; write string of text
mov comand.cmcr,1 ; bare cr's allowed without error
mov temp,offset rdbuf ; our buffer
wrttxt1:mov ah,cmline ; get string to be written
mov bx,temp ; where to put text
mov dx,offset rdbuf + 255 ; length rdbuf, end of buffer
sub dx,bx ; minus used part of buffer, yields
cmp dx,127 ; length remaining in buffer
jbe wrttxt2 ; be = regular buffer length
mov dl,127 ; cut back to that size
wrttxt2:mov comand.cmblen,dl ; length remaining in buffer
mov dx,offset msgtxt ; help
call comnd
mov si,temp ; start of text in buffer
mov di,si ; convert in-place, to asciiz
call cnvlin
jmp wrtcom ; finish in common write code
wrttxt endp
; Writes contents of buffer rdbuf (asciiz) to log file kind held in tmp
; and returns to command parser
wrtcom proc near ; common write code
mov ah,cmeol
call comnd
jnc wpkt0
ret ; c = failure
wpkt0: mov bl,tmp ; log file kind
cmp bl,logpkt ; Packet log?
jne wses1 ; ne = no
mov si,offset rdbuf
mov dx,si
call strlen
jcxz wpkt2 ; z = no chars to write
wpkt1: lodsb ; get byte to al
call pktcpt ; write to packet log
loop wpkt1
wpkt2: clc ; say success
ret
wses1: cmp bl,logses ; Session log?
jne wtrn1 ; ne = no
mov si,offset rdbuf
mov dx,si
call strlen
jcxz wses3 ; z = no chars to write
wses2: lodsb ; get byte to al
call cptchr ; write to log
loop wses2 ; do cx chars
wses3: clc ; say success
ret
wtrn1: cmp bl,logtrn ; Transaction log?
jne wtscn ; ne = no
mov bx,tloghnd ; file open?
cmp bx,0
jle wtrn2 ; le = no, forget it
mov dx,offset rdbuf
call strlen ; length to cx
jcxz wtrn2 ; z = nothing to write
mov ah,write2 ; write to file handle in bx
int dos
wtrn2: clc ; success
ret
wtscn: cmp bl,80h ; write screen?
jne wtscn1 ; ne = no
mov dx,offset rdbuf
call strlen ; length to cx
jcxz wtrn2 ; z = nothing to write
xor bx,bx ; handle is stdout
mov ah,write2 ; write to file handle in bx
int dos
wtscn1: clc
ret
wrtcom endp
code ends
end