home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
ccdos.tar.gz
/
ccdos.tar
/
ccsker.asm
< prev
next >
Wrap
Assembly Source File
|
1991-09-08
|
55KB
|
1,243 lines
NAME ccsker
; File CCSKER.ASM
;CHINESE
ifdef MSDOS
include mssker.dat
else
include ccsker.dat
endif
code segment public 'code'
extrn cmblnk:near, locate:near, logout:near, mail:near
extrn bye:near, telnet:near, finish:near, comnd:near, prompt:near
extrn read:near, remote:near, send:near, status:near, get:near
extrn dodisk:near, serrst:near, setcom:near, dtrlow:near
extrn clscpi:near, clscpt:near, getbaud:near
extrn dodef:near, setcpt:near, docom:near, shomodem:near
extrn server:near, lclini:near, shokey:near, shomac:near, shosta:near
extrn packlen:near, strlen:near, strcpy:near, shserv:near
extrn strcat:near, prtasz:near, shorx:near, lnout:near
extrn scout:near,scinp:near,scpau:near,scecho:near,scclr:near
extrn scxmit:near, scwait:near, srvdsa:near, srvena:near
extrn shcom:near, shlog:near, shpro:near, shterm:near, shscpt:near
extrn shfile:near, takopen:near, takclos:near, ask:near, assign:near
extrn goto:near, screinp:near, ifcmd:near, isdev:near
extrn chkos:near ; Jun. 1990
assume cs:code, ds:datas, ss:cstack, es:nothing
START PROC FAR
mov ax,datas ; Initialize DS
mov ds,ax
mov psp,es ; remember psp address
mov ah,dosver
int dos
mov dosnum,al ; remember dos version
cmp dosnum,2 ; earlier than DOS 2.0?
jge start1 ; ge = no
mov ah,prstr
; mov dx,offset erms34 ; Complain
mcmsg erms34, cerms34
int dos
mov ax,psp ; set up exit for DOS 1
push ax ; push the segment
mov ax,0 ; and the IP
push ax ; make return addr of psp:0 for DOS 1
ret ; and return far to exit now
start1:
call chkos ; check if MS-DOS or CC-DOS ? Jun.1990
mov ah,prstr
mov dx,offset machnam ; print machine name
int dos
mov ah,prstr ; Print the version header
; mov dx,offset versio
mcmsg versio, cversio
int dos
mov ah,setdma ; Set disk transfer address
mov dx,offset buff
int dos
call setint
mov ah,gcurdsk ; Get current disk
int dos
inc al ; We want 1 == A (not zero)
mov curdsk,al
mov origd,al ; Remember original disk we started on
mov si,offset orgdir ; place for directory path w/o drive code
add al,'A'-1 ; make al alphabetic disk drive again
mov [si],al ; put it into original path descriptor
inc si
mov byte ptr [si],':' ; add drive specifier too
inc si
mov byte ptr [si],'\' ; add root indicator as well
inc si
mov ah,gcd ; get current directory (path really)
xor dl,dl ; use current drive
int dos
call getpath ; get the path from the environment
call getcsp ; get comspec from environment
call memini ; init our memory usage
call lclini ; do local initialization
call packlen ; Packet length in case do server comand
mov ah,gswitch
mov al,0 ; pick up switch character
int dos
mov slashc+1,dl
mov al,maxtry ; limit # packet retries
and al,3fh ; 63 max
mov maxtry,al
shl al,1 ; times two. I packets get more tries
mov imxtry,al ; keep that much
add al,maxtry ; try three times
js start2 ; s = sign bit set, too large
mov imxtry,al ; imxtry = 3 * maxtry
start2: mov comand.cmrprs,offset krmend ; address to go to on reparse
mov comand.cmostp,sp ; Save for reparse too
call gcmdlin ; read command line
cmp taklev,0 ; in a Take file?
jne start3 ; ne = yes, skip help msg
mov ah,prstr
; mov dx,offset hlpmsg
mcmsg hlpmsg,chlpmsg
int dos
start3: call serrst ; reset serial port (if active)
call rdinit ; read kermit init file
; This is the main KERMIT loop. It prompts for and gets the users commands
kermit: mov ax,ds
mov es,ax ; make sure this addresses data segment
cmp taklev,0 ; keep port open between script cmds
jne kermt1 ; ne = in Take or Macro
call serrst ; reset serial port for CTTY DOS use
kermt1: mov dx,prmptr ; get prompt
call chkos ; check if MS-DOS or CC-DOS ? Jun.1990
call prompt ; Prompt the user, set reparse address
mov pack.state,0 ; Clear the state
mov flags.cxzflg,0 ; Reset each time
and flags.remflg,not dserver ; turn off server mode bit
mov ah,inichk ; Original or set checksum length
mov trans.chklen,ah ; Reset just in case
mov dx,offset comtab
; mov bx,offset tophlp
mcmsgb tophlp,ctophlp
cmp flags.extflg,0 ; Check if the exit flag is set
jne krmend ; If so jump to KRMEND
mov comand.cmcr,1 ; Allow bare CR's
mov ah,cmkey
mov comand.impdo,1 ; allow implied "DO macro"
call comnd
jmp kermt3
nop
mov comand.impdo,0 ; only on initial keyword, not here
mov comand.cmcr,0 ; no more bare CR's
call bx ; Call the routine returned
jmp kermt3
nop
cmp flags.extflg,0 ; Check if the exit flag is set
jne krmend ; If so jump to KRMEND
jmp short kermt5 ; Do it again
kermt3: mov kstatus,8 ; global status
cmp flags.cxzflg,'C' ; got here via Control-C?
jne kermt7 ; ne = no
kermt4: cmp flags.extflg,0 ; Check if the exit flag is set
jne kermt5 ; ne = yes, skip msg, do cleanup
; mov dx,offset ermes3 ; Say command not executed
mcmsg ermes3,cermes3
mov ah,prstr ; print the error message in dx
int dos
kermt5: cmp flags.cxzflg,'C' ; user Control-C abort?
jne kermt7 ; ne = no, do normal operations
cmp taklev,0 ; in a Take file?
je kermt7 ; e = no
call takclos ; close take file, release buffer
jmp kermt5 ; close any other take files
kermt7: mov flags.nmoflg,0 ; Reset filename override flag
mov flags.getflg,0 ; May as well do this one
cmp flags.extflg,0 ; Check if the exit flag is set
jne krmend ; ne = yes, Exit now
jmp kermit ; get next command
krmend: call serrst ; Just in case the port wasn't reset
test flags.capflg,0FFH ; Logging active?
jz krmend2 ; z = no
call clscpi ; close log files
nop ; this skip returns..
nop
nop
krmend2:cmp lclexit,0 ; sys dependent routines want service?
je krmend3 ; e = no
mov bx,lclexit ; addr of sys dependent exit routine
call bx ; call it
krmend3:mov dl,origd ; Original disk drive
dec dl ; Want A == 0
mov ah,seldsk ; Reset original disk just in case
int dos
mov dx,offset orgdir ; restore original directory
mov ah,chdir
int dos
mov dx,offset in3ad ; restore Control-C interrupt vector
mov al,23H ; interrupt 23H
mov ah,25H ; set interrupt vector
int dos ; ah, that's better
mov dx,offset ceadr ; DOS's Critical Error handler
mov al,24h ; interrupt 24h
mov ah,25h ; do replacement (put it back)
int dos
mov ah,4cH ; terminate process
mov al,errlev ; return error level
int dos
ret
START ENDP
; This is the 'EXIT' command. It leaves KERMIT and returns to DOS
EXIT PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm
jmp r
nop
mov flags.extflg,1 ; Set the exit flag
jmp rskp ; Then return to system
EXIT ENDP
; TAKE commands from a file, and allow a path name
TAKE PROC NEAR
mov kstatus,0 ; global status, success
cmp taklev,maxtak ; Hit our limit?
jl take1 ; Continue if still OK
mov ah,prstr
;mov dx,offset erms30 ; Complain
mcmsg erms30, cerms30
int dos
ret
take1: mov dx,offset tmpbuf ; work buffer
mov tmpbuf,0
; mov bx,offset filmsg ; Help in case user types "?"
mcmsgb filmsg,cfilmsg
mov ah,cmfile ; get file name
call comnd
jmp r
nop
mov ah,cmcfm
call comnd
jmp r
nop
mov ax,offset tmpbuf ; point to name again
cmp tmpbuf,0 ; empty filespec?
jne take2 ; ne = no
mov ah,prstr
; mov dx,offset ermes1 ; say more parameters needed
mcmsg ermes1,cermes1
int dos
jmp rskp
; TAKE2: enter with ax=filename ptr
TAKE2: call spath ; is it around?
jc take3 ; no, go complain
mov dx,ax ; point to name from spath
mov ah,open2 ; 2.0 open call
cmp dosnum,2 ; above DOS 2?
mov al,0 ; open for reading
jna take2a ; na = no, so no shared access
mov al,0+40h ; open for reading, deny none
take2a: int dos
jnc take4 ; nc = opened ok, keep going
mov ax,dx ; recover filename pointer
take3: push ax
mov ah,prstr
; mov dx,offset erms31
mcmsg erms31, cerms31
int dos
pop ax
mov dx,ax ; asciiz file name
call prtasz ; display it
mov kstatus,8 ; global status
jmp rskp ; we've done all error displays
; TAKE4: enter with ax=filename ptr
TAKE4: call takopen ; open take buffer in macro space
jc take6 ; c = failure
push bx
mov bx,takadr ; get current frame ptr
mov [bx].takhnd,ax ; save file handle
mov [bx].taktyp,0feh ; mark as 2.0 file handle
pop bx
cmp flags.takflg,0 ; echoing Take files?
je take5 ; e = no
mov ah,prstr
mov dx,offset crlf
int dos
take5: call takrd ; Get a buffer full of data
take6: jmp rskp
TAKE ENDP
TAKRD PROC NEAR
push ax
push bx
push cx
push dx
mov bx,takadr
cmp [bx].taktyp,0feh ; get type of take (file?)
jne takrd1 ; ne = no, do not read from disk
mov dx,[bx].takbuf ; address of buffer to read into
inc dx ; skip count byte in takbuf
mov cx,dmasiz ; # of bytes to read
push si
mov si,dx ; fill buffer with spaces for
takrd0: mov byte ptr [si],' ' ; Show Macro
inc si
loop takrd0
pop si
mov cx,dmasiz
push bx ; save frame address
mov bx,[bx].takhnd ; file handle is stored here
mov ah,readf2 ; 2.0 read call
int dos
pop bx ; restore frame address
jnc takrd2 ; nc = successful read
takrd1: mov ax,0 ; error, say zero bytes read
takrd2: mov [bx].takcnt,ax ; number of bytes read
mov ax,[bx].takbuf
inc ax ; skip count byte in takbuf
mov [bx].takptr,ax ; first new character
pop dx
pop cx
pop bx
pop ax
ret
TAKRD ENDP
; TAKE-QUIT Exit all Take files immediately but gracefully
TAKEQIT PROC NEAR
mov ah,cmcfm
call comnd
jmp r
nop
takqit1:mov ch,0
mov cl,taklev ; number of Take levels active
jcxz takqit2 ; z = none
call takclos ; close current Take file
jmp short takqit1 ; repeat until all are closed
takqit2:jmp rskp
TAKEQIT ENDP
; put mskermit.ini onto take stack if it exists. Just like
; the take command, except it doesn't read a filename
rdinit proc near ; read kermit init file..
mov ax,offset ininm2 ; default name to try
cmp decbuf,0 ; alternate init file given?
je rdini1 ; ne = no
mov ax,offset decbuf ; yes, use it
call take2 ; Let Take do error msgs
nop
nop
nop
ret
rdini1: call spath ; is it around?
jc rdini2 ; no, ignore file
mov dx,ax ; point to name from spath
mov ah,open2 ; 2.0 open call
mov al,0 ; open for reading
cmp dosnum,2 ; above DOS 2?
jna rdini1a ; na = no, so no shared access
mov al,0+40h ; open for reading, deny none
rdini1a:int dos
jc rdini2 ; c = no ini file found, ignore
call take4 ; use TAKE command to complete work
nop ; ignore errors
nop
nop
rdini2: ret
rdinit endp
; Get command line into a Take macro buffer. Allow "-f filspec" to override
; normal mskermit.ini initialization filespec, allow command "stay" to
; suppress automatic exit to DOS at end of command line execution. [jrd]
gcmdlin proc near
mov word ptr decbuf,0 ; storage for new init filename
push es
cld
mov es,psp ; address psp
mov ch,0
mov cl,es:byte ptr[cline] ; length of cmd line from DOS
jcxz gcmdl1 ; z = empty line
mov si,cline+1 ; point to actual line
gcmdl0: cmp byte ptr es:[si],' ' ; skip over leading whitespace
ja gcmdl2 ; a = non-whitespace
inc si
loop gcmdl0 ; fall through on all whitespace
gcmdl1: jmp gcmdl14 ; common exit jump point
gcmdl2: inc cx ; include DOS's c/r
call takopen ; open take buffer in macro space
mov bx,takadr
mov byte ptr [bx].taktyp,0ffh ; mark as a macro
mov [bx].takcnt,0 ; length of text
mov di,[bx].takbuf ; offset of buffer, from takopen
inc di ; skip count byte
mov ax,ds
mov dx,es ; swap ds and es
mov es,ax
mov ds,dx ; ds = PSP, es = datas
gcmdl3: cmp cx,0 ; anything left?
jbe gcmdl10 ; be = no
lodsb ; get a byte
dec cx ; one less char in input string
cmp al,',' ; comma?
jne gcmdl4 ; no, keep going
mov al,cr ; convert to cr
jmp gcmdl9 ; store it
gcmdl4: cmp al,'-' ; starting a flag?
jne gcmdl9 ; ne = no
mov ah,byte ptr[si] ; get flag letter
or ah,20h ; convert to lower case
cmp ah,'f' ; 'f' for init file replacement?
jne gcmdl9 ; ne = no
mov ah,byte ptr[si+1] ; need space or tab separator
cmp ah,' ' ; separator?
ja gcmdl9 ; a = no, not a flag
; strip out and analyze flag info
inc si ; point at separator
dec cx
gcmdl5: cmp cx,0 ; anything to read?
jle gcmdl10 ; le = exhausted supply
lodsb ; get filespec char from psp
dec cx ; one less char in source buffer
cmp al,' ' ; in whitespace?
jbe gcmdl5 ; be = yes, scan it off
dec si ; backup to real text
inc cx
; copy filspec to buffer decbuf
push di ; save current destination pointer
lea di,decbuf ; where filespec part goes
mov word ptr es:[di],0 ; plant safety terminator
gcmdl6: lodsb ; get filespec char
dec cx ; one less available
cmp cx,0 ; any chars left?
jle gcmdl7 ; le = no
cmp al,' ' ; in printables?
jbe gcmdl7 ; be = no, all done
cmp al,',' ; comma command separator?
je gcmdl7 ; e = yes, all done
stosb ; store filespec char
mov byte ptr es:[di],0 ; end filespec on a null
jmp short gcmdl6
gcmdl7: pop di ; recover macro register
dec si ; compensate for last read above
inc cx
gcmdl8: cmp cx,0 ; strip trailing whitespace
jbe gcmdl10 ; be = nothing left
lodsb
dec cx
cmp al,' ' ; white space?
jbe gcmdl8 ; be = yes, strip it
cmp al,',' ; at next command?
je gcmdl10 ; e = yes, skip our own comma
dec si ; back up to reread the char
inc cx
jmp gcmdl3 ; read more command text
; end of flag analysis
gcmdl9: stosb ; deposit most recent char
gcmdl10:cmp cx,0 ; anything left to read?
jg gcmdl3 ; g = yes, loop
;
mov ax,datas ; restore segment registers
mov ds,ax
mov es,ax ; return to ds=datas, es=datas
mov si,[bx].takbuf ; get address of text field
inc si ; skip count byte
mov cx,di ; current end pointer, (save di)
sub cx,si ; current ptr minus start offset
mov [bx].takcnt,cx
cmp cx,0
jg gcmdl11 ; material at hand
call takclos ; empty take file
jmp gcmdl14 ; finish up
; scan for command "stay"
gcmdl11:lodsb ; get a byte, cx and si are set above
dec cx
cmp al,' ' ; separator?
jbe gcmdl12 ; be = yes, keep looking
cmp al,',' ; comma separator?
je gcmdl12 ; e = yes
mov ah,al ; get first byte
lodsb ; second byte after separator
dec cx
or ax,2020h ; convert to lower case
cmp ax,'st' ; first two letters of stay
jne gcmdl12 ; ne = no match
lodsw ; next two letters (stay vs status)
sub cx,2
or ax,2020h ; convert to lower case
cmp ax,'ya' ; same as our pattern?
jne gcmdl12 ; ne = no match
; check for separator or end of macro
cmp cx,0 ; at end of macro?
jle gcmdl13 ; yes, consider current match correct
cmp byte ptr[si],' ' ; next char is a separator?
jbe gcmdl13 ; be = yes, found correct match
cmp byte ptr[si],',' ; or comma separator?
je gcmdl13 ; e = yes
gcmdl12:cmp cx,0 ; done yet? ("stay" not found)
jg gcmdl11 ; g = not yet, look some more
mov si,offset eexit ; append command "exit"
mov cx,leexit ; length of string "exit"
add [bx].takcnt,cx
rep movsb ; copy it into the macro
gcmdl13:mov ax,[bx].takbuf
inc ax ; skip count byte
mov [bx].takptr,ax ; init buffer ptr
gcmdl14:pop es
ret
gcmdlin endp
; Enter with ax pointing to file name. Searches path for given file,
; returns with ax pointing to whole name, or carry set if file can't be found.
SPATH proc near
call isfile ; does it exist as it is?
jc spath0 ; c = no, prepend path elements
test byte ptr filtst.dta+21,10H ; subdirectory name?
jnz spath0 ; nz = yes, not desired file
clc
ret
spath0: push es ; save es around work
push bx
push si
push di
mov bx,ax ; save filename pointer in bx
mov si,ax
mov dl,0 ; no '\' seen yet
cld
spath1: lodsb
cmp al,2fh ; contains fwd slash path characters?
je spath1a
cmp al,5ch ; or backslash?
jne spath2 ; no, keep going
spath1a:mov dl,1 ; remember we've seen them
spath2: or al,al
jnz spath1 ; copy name in
or dl,dl ; look at flag
jz spath3 ; no path, keep looking
jmp spath9 ; embedded path, fail
spath3: mov si,pthadr ; offset of PATH= string in environment
mov es,psp
mov di,es:word ptr[env] ; pick up environment segment
mov es,di
spath4: cmp byte ptr es:[si],0 ; end of PATH= string?
je spath9 ; e = yes, exit loop
mov di,offset decbuf+64 ; place to put name
spath5: mov al,byte ptr es:[si] ; get a byte from environment string
inc si
cmp al,';' ; end of this part?
je spath7 ; yes, break loop
cmp al,0 ; maybe end of string?
jne spath6 ; no, keep going
dec si ; back up to null for later rereading
jmp short spath7 ; and break loop
spath6: mov byte ptr [di],al ; else stick in dest string
inc di
jmp spath5 ; and continue
spath7: push si ; save this ptr
mov si,bx ; this is user's file name
cmp byte ptr [di-1],2fh ; does path end with switch char?
je spath8 ; yes, don't put one in
cmp byte ptr [di-1],5ch ; how about this one?
je spath8 ; yes, don't put it in
mov byte ptr [di],5ch ; else add one
inc di
spath8: lodsb ; get filename character
mov byte ptr [di],al ; copy filename char to output buffer
inc di
or al,al ; end of string?
jnz spath8 ; nz = no, copy rest of name
pop si ; restore postion in path string
mov ax,offset decbuf+64
call isfile ; is it a file?
jc spath4 ; c = no, keep looking
test byte ptr filtst.dta+21,10H ; subdirectory name?
jnz spath4 ; nz = yes
pop di
pop si
pop bx
pop es
clc
ret ; return success (carry clear)
spath9: mov ax,bx ; restore original filename pointer
pop di ; restore regs
pop si
pop bx
pop es
stc ; no file found
ret
spath endp
; Put offset of PATH= string in pthadr
getpath proc near
push bx
push cx
push dx
mov bx,offset pthnam ; thing to find
mov cx,pthlen ; length of it
mov pthadr,0 ; init offset to zero
call getenv ; get environment value
mov pthadr,dx
pop dx
pop cx
pop bx
ret ; and return
getpath endp
; copy COMSPEC= environment string into cmspbuf
getcsp proc near
push bx
push cx
push dx
push es
mov bx,offset cmspnam ; find COMSPEC=
mov cx,cmsplen ; it's length
call getenv ; get environment offset in dx
mov di,offset cmspbuf ; where to store string
mov si,dx ; address of COMSPEC= string
mov es,psp
mov bx,es:word ptr[env] ; pick up environment address
mov es,bx
push ds ; save ds
push ds ; make ds point to environment seg
push es ; make es point to datas segment
pop ds
pop es
cld
getcs1: lodsb ; get a byte from environment
cmp al,' ' ; space or less?
jg getcs2 ; g = no, keep copying
mov al,0 ; terminate string on spaces etc
getcs2: stosb ; store it in cmspbuf
or al,al ; at end of string yet?
jne getcs1 ; ne = no, keep copying
pop ds ; recover ds
pop es
pop dx
pop cx
pop bx
ret ; and return
getcsp endp
; Locate string variable in Environment
; bx/ variable to find (incl =), cx/ length of variable name,
; dx/ address to store value at
getenv proc near
push ax
push cx
push si
push di
push es
mov es,psp
mov ax,es:word ptr[env] ; pick up environment address
mov es,ax
mov di,0 ; start at this offset in segment
geten1: cmp es:byte ptr [di],0 ; end of environment?
je geten4 ; yes, forget it
push cx ; save counter
push di ; and offset
mov si,bx
cld
repe cmpsb ; search for name
pop di
pop cx ; restore these
je geten2 ; found it, break loop
push cx ; preserve again
mov cx,0ffffh ; bogus length
mov al,0 ; marker to look for
repne scasb ; search for it
pop cx ; restore length
jmp geten1 ; loop thru rest of environment
geten2: add di,cx ; skip to definition
geten4: mov dx,di ; store offset of string
pop es
pop di
pop si
pop cx
pop ax
ret ; and return
getenv endp
COMNT PROC NEAR ; COMMENT command
mov ah,cmtxt
mov bx,offset tmpbuf
mov dx,0
call comnd
jmp r
nop
jmp rskp
COMNT ENDP
; change working directory
cwdir proc near
mov kstatus,0 ; global status
mov ah,cmfile
mov dx,offset tmpbuf
; mov bx,offset pthmsg
mcmsgb pthmsg, cpthmsg
call comnd
jmp r
mov ah,cmcfm
call comnd
jmp r
cmp tmpbuf,0 ; anything given?
jne cwd1 ; ne = yes
mov ah,prstr
; mov dx,offset ermes1 ; say need more
mcmsg ermes1,cermes1
int dos
jmp rskp
cwd1: mov dl,curdsk ; remember present disk
mov byte ptr temp,dl
mov bx,offset tmpbuf ; change of drives, if req'd
cmp byte ptr [bx+1],':' ; was a drive specified?
jne cwd2 ; ne = no
mov dl,[bx] ; get the drive letter
add bx,2 ; skip drive colon
and dl,5FH ; make upper case
sub dl,'A' ; convert to A = 0, etc
mov ah,seldsk
int dos ; change disks
jc cwd3 ; c = failure
inc dl ; count A = 1 internally
mov curdsk,dl ; and store it
cwd2: cmp byte ptr [bx],0 ; anything left?
je cwd4 ; e = no
mov dx,bx ; get path string
mov ah,chdir ; DOS change directory
int dos
jnc cwd4 ; nc = success
;cwd3: mov dx,offset ermes4 ; failure
cwd3: mcmsg ermes4,cermes4
mov ah,prstr
int dos
mov dl,byte ptr temp ; get current disk
dec dl ; A = 0 for DOS
mov ah,seldsk ; restore it
int dos
mov kstatus,8 ; global status
cwd4: jmp rskp
cwdir endp
; Erase specified file(s). Add protection of ignore hidden, subdir, volume
; label and system files. 9 Jan 86 [jrd]
DELETE PROC NEAR ; revised for DOS 2.0, incl paths & ?* [jrd]
mov kstatus,0 ; global status
mov si,offset delcmd ; del command
mov di,offset tmpbuf
call strcpy
mov dx,offset tmpbuf
call strlen ; get its length
add di,cx ; point at terminator
mov ah,cmfile ; filespec
mov dx,di ; where to place the file specs
; mov bx,offset filmsg ; In case user wants help.
mcmsgb filmsg,cfilmsg
call comnd
jmp r
nop
mov temp,ax ; save byte count
mov ah,cmcfm
call comnd
jmp r
nop
cmp byte ptr temp+1,0 ; anything given?
jne delet1 ; ne = yes
mov ah,prstr
; mov dx,offset ermes1 ; say need something
mcmsg ermes1,cermes1
int dos
jmp rskp
delet1: mov dx,offset delcmd ; get length of prefix (del )
call strlen
mov ax,offset tmpbuf ; command line so far
add ax,cx ; bump address to filename field
call isfile ; and ask if file exists & what kind it is
jc delet2 ; c = no such file, complain
test byte ptr filtst.dta+21,1EH; attribute bits: is file protected?
jz delet3 ; z = no, go ahead
delet2: mov ah,prstr
; mov dx,offset badnam ; give error message
mcmsg badnam, cbadnam
int dos
mov kstatus,8 ; global status
jmp rskp ; and ignore this command
delet3: mov si,offset tmpbuf ; del cmd
jmp crun ; join run cmd from there
DELETE ENDP
CHKDSK PROC NEAR ; Space command
mov kstatus,0 ; global status
mov ah,cmcfm
call comnd
jmp r
mov ah,prstr
mov dx,offset crlf ; start of message
int dos
mov dl,0 ; use current drive
mov ah,36h ; get disk free space
int dos
cmp ax,0ffffh ; error response?
je chkdsk1 ; e = yes
mul bx ; sectors/cluster * clusters = sectors
mov bx,dx ; save high word of sectors (> 64K)
mul cx ; bytes = sectors * bytes/sector
push ax ; save low word of bytes
mov ax,bx ; recall sectors high word
mov bx,dx ; save current bytes high word
mul cx ; high word sectors * bytes/sector
add ax,bx ; new high bytes + old high bytes
mov dx,ax
pop ax
mov di,offset tmpbuf ; work space for lnout
mov word ptr[di],' ' ; start with two spaces
add di,2
call lnout
mov si,offset spcmsg
cmp isccdos,0 ; if in CCDOS ?
jz chkdsk0 ; z = No
mov si,offset cspcmsg
chkdsk0:call strcat ; add text to end of message
mov dx,offset tmpbuf
call prtasz ; print asciiz string
jmp rskp
chkdsk1:mov ah,prstr
; mov dx,offset spcmsg2 ; say drive not ready
mcmsg spcmsg2, cspcmsg2
int dos
mov kstatus,8 ; global status
jmp rskp
CHKDSK ENDP
; Get directory listing
DIRECT PROC NEAR
mov kstatus,0 ; global status
mov si,offset dircmd ; dir command
mov di,offset tmpbuf
call strcpy
mov dx,offset tmpbuf
call strlen ; get its length
add di,cx ; point at terminator
mov ah,cmtxt ; parse with cmtxt so we can have paths
mov bx,di ; next available byte
; mov dx,offset filmsg ; In case user wants help.
mcmsg filmsg, cfilmsg
call comnd
jmp r
mov byte ptr [bx],0 ; plant terminator
mov si,offset tmpbuf
jmp crun ; join run cmd from there
DIRECT ENDP
; This is the 'HELP' command. It gives a list of the commands
HELP PROC NEAR
mov kstatus,0 ; global status
mov ah,cmcfm
call comnd ; Get a confirm
jmp r
mov ah,prstr ; show Quick help summary screen
; mov dx,offset qckhlp
mcmsg qckhlp,cqckhlp
int dos
mov ah,conout
mov dl,trans.escchr ; get Kermit escape character
add dl,40h ; convert to printable
push dx ; save it for repeats below
int dos
mov ah,prstr
; mov dx,offset qckhlp1 ; more help text
mcmsg qckhlp1,cqckhlp1
int dos
mov ah,conout
pop dx
push dx
int dos
mov ah,prstr
; mov dx,offset qckhlp2 ; more help text
mcmsg qckhlp2,cqckhlp2
int dos
pop dx ; recover current escape char
mov ah,conout
int dos
mov ah,prstr
; mov dx,offset qckhlp3 ; end of help message
mcmsg qckhlp3,cqckhlp3
int dos
mov ah,coninq ; get a keystroke, quietly
int dos
cmp al,'?' ; query mark?
jne helpx ; ne = no, skip second screen
mov ah,prstr ; show help summary screen
mov dx,offset crlf ; a few blank lines
int dos
int dos
int dos
; mov dx,offset tophlp ; show usual cryptic help
mcmsg tophlp,ctophlp
int dos
helpx: jmp rskp
HELP ENDP
; the version command - print our version number
prvers proc near
mov kstatus,0 ; global status
mov ah,cmcfm
call comnd
jmp r
mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr
mov dx,offset machnam ; print machine name
int dos
mov ah,prstr ; Print the version header
; mov dx,offset versio
mcmsg versio, cversio
int dos
jmp rskp
prvers endp
; the show command
showcmd proc near
mov kstatus,0 ; global status
mov ah,cmkey
mov dx,offset shotab
xor bx,bx ; no canned help
call comnd
jmp r
jmp bx ; execute the handler
showcmd endp
; the type command - type out a file
typec proc near
mov kstatus,0 ; global status
mov si,offset typcmd ; type command
mov di,offset tmpbuf
call strcpy
mov dx,offset tmpbuf
call strlen ; get its length
add di,cx ; point at terminator
mov ah,cmtxt ; parse with cmtxt so we can have paths
mov bx,di ; next available byte
; mov dx,offset filmsg ; In case user wants help.
mcmsg filmsg, cfilmsg
call comnd
jmp r
cmp ah,0 ; any text given?
jne typec1 ; ne = yes
mov ah,prstr
; mov dx,offset ermes1 ; say need more info
mcmsg ermes1, cermes1
int dos
jmp rskp
typec1: mov byte ptr [bx],0 ; plant terminator
mov si,offset tmpbuf
jmp crun ; join run cmd from there
typec endp
; PUSH to DOS (run another copy of Command.com or equiv)
; entry fpush (fast push...) pushes without waiting for a confirm
; returns rskp
dopush proc near
dopus1: mov ah,cmcfm
call comnd
jmp r
nop
fpush: mov si,offset tmpbuf ; a dummy buffer
mov byte ptr [si],0 ; plant terminator
jmp short crun4 ; go run it
dopush endp
; Run a program from within Kermit
RUN PROC NEAR
mov ah,cmtxt ; Get program name and any arguments
mov bx,offset tmpbuf ; place for user's text
; mov dx,offset runmsg ; In case user wants help
mcmsg runmsg, crunmsg
call comnd
jmp r
nop
cmp ah,0 ; byte count
jne run2 ; ne = have program name
mov ah,prstr ; else complain
; mov dx,offset ermes1 ; need more info
mcmsg ermes1,cermes1
int dos
jmp rskp
run2: mov si,offset tmpbuf ; source of text
jmp crun
RUN ENDP
; crun - run an arbitrary program. Rewritten by [jrd]
; Enter with ordinary asciiz command in si (such as Dir *.asm)
; Append a c/r and a null terminator and then ask command.com to do it
CRUN proc near
mov ah,prstr ; output crlf before executing comnd. [lba]
mov dx,offset crlf ; [lba]
int dos ; display it. [lba]
mov di,offset tmpbuf ; where to put full command line text
cmp si,di ; same place?
je crun1 ; e = yes, don't copy ourself
call strcpy ; si holds source text
crun1: mov si,offset slashc ; DOS command begins with slashc area
mov dx,offset slashc+1 ; si points to /c part of command line
call strlen ; get its length into cx
push bx
mov bx,dx
add bx,cx
mov byte ptr [bx],cr ; end string with a c/r for dos
inc cx ; count the c/r
mov byte ptr [bx+1],0 ; and terminate
pop bx
mov [si],cl ; put length of argument here
crun4: mov exearg+2,si ; pointer to argument string
mov exearg+4,ds ; segment of same
cmp lclsusp,0 ; sys dependent routine to call
je crun5 ; e = none
mov bx,lclsusp ; address to call
call bx ; call sys dependent suspend routine
crun5: call serrst ; reset serial port (if active)
mov es,psp ; point to psp again
mov exearg+8,es ; segment of psp, use our def fcb's
mov exearg+12,es ; segment of psp, ditto, for fcb 2
mov ax,es:word ptr [env] ; get environment ptr
mov exearg,ax ; put into argument block
mov ax,ds
mov es,ax ; put es segment back
mov bx,offset exearg ; es:bx points to exec parameter block
mov dx,offset cmspbuf ; always use command.com
mov al,0 ; load and execute..
mov ah,exec
mov ssave,sp ; save stack ptr
int dos ; go run the program
mov ax,datas
mov ds,ax ; reset data segment
mov es,ax ; and extra segment
mov ax,cstack
mov ss,ax ; and stack segment
mov sp,ssave ; restore stack ptr
pushf ; save flags
mov ah,setdma
mov dx,offset buff
int dos ; restore dma address!!
popf ; recover flags
jc crun8 ; c = error, handle
cmp lclrest,0 ; sys dependent routine to call
je crun9 ; e = none
mov bx,lclrest ; get routine's address
call bx ; call sys dependent restore routine
crun9: jmp rskp ; ok, return
crun8: mov ah,prstr
; mov dx,offset erms37
mcmsg erms37,cerms37
int dos
mov kstatus,8 ; global status
jmp rskp
CRUN ENDP
; Replace Int 23h and Int 24h with our own handlers
; Revised to ask DOS for original interrupt vector contents, as suggested by
; Jack Bryans. 9 Jan 1986 jrd
; Modified again 30 August 1986 [jrd]
SETINT PROC NEAR
push es ; save registers
push bx
mov al,23H ; desired interrupt vector (^C)
mov ah,35H ; Int 21H, function 35H = Get Vector
int dos ; get vector in es:bx
mov in3ad,bx ; save offset address of original vector
mov in3ad+2,es ; and its segment
mov al,24h ; DOS critical error, Int 24h
mov ah,35h
int dos
mov word ptr ceadr,bx ; DOS's Critical Error handler, offset
mov word ptr ceadr+2,es ; and segment address
push ds ; save ds around next DOS call
mov ax,cs ; compose full address of ^C routine
mov ds,ax ; Offset is the code segment
mov dx,offset intbrk ; and main address is intbrk
mov al,23H ; On ^C, goto intbrk
mov ah,25H ; set interrupt address from ds:dx
int dos
mov dx,offset dosce ; replacement Critical Error handler
mov al,24h ; interrupt 24h
mov ah,25h ; replace it
int dos
pop ds
pop bx
pop es
ret
SETINT ENDP
; Control Break, Interrupt 23h replacement
; Always return with a Continue (vs Abort) condition since Kermit will cope
; with failures. [jrd]
intbrk: push ax
push ds
mov ax,datas ; get Kermit's data segment
mov ds,ax
mov flags.cxzflg,'C' ; Say we saw a ^C
mov pack.state,'A' ; Set the state to abort
pop ds
pop ax
iret ; return to caller in a Continue condition
; Kermit's DOS Critical Error Handler, Int 24h. [jrd]
; Needed to avoid aborting Kermit with the serial port interrupt active and
; the Control Break interrupt redirected. See the DOS Tech Ref Manual for
; a start on this material; it is neither complete nor entirely accurate
; The stack is the Kermit's stack, the data segment is unknown, interrupts
; are off, and the code segment is Kermit's. Note: some implementations of
; MS DOS may leave us in DOS's stack. Called by a DOS Int 21h function
dosce: test ah,80h ; block device (disk drive)?
jnz dosce1 ; nz = no; serial device, memory, etc
mov al,3 ; tell DOS to Fail the Int 21h call
iret ; return to DOS
dosce1: add sp,6 ; pop IP, CS, Flags regs, from DOS's Int 24h
pop ax ; restore original callers regs existing
pop bx ; just before doing Int 21h call
pop cx
pop dx
pop si
pop di
pop bp
pop ds
pop es
mov al,0ffh ; signal failure (usually) the DOS 1.x way
push ax ; Kermit's IP, CS, and Flags are on the stack
push bp ; all ready for an iret, but first a word ..
mov bp,sp
mov ax,ss:[bp+8] ; get Kermit's flags word
or ax,1 ; set the carry bit, signal failure DOS 2+ way
mov ss:[bp+8],ax ; store new flags back in the stack
pop bp ; this avoids seeing the Interrupt flag bit
pop ax
iret ; return to user, simulate return from Int 21h
ISFILE PROC NEAR
; Enter with ds:ax pointing at asciiz filename string
; Returns carry set if the file pointed to by ax does not exist, else reset
; Returns status byte, fstat, with DOS status and high bit set if major error
; Does a search-for-first to permit paths and wild cards
; Examines All kinds of files (ordinary, subdirs, vol labels, system,
; and hidden). Upgraded to All kinds on 27 Dec 1985. Revised 30 Aug 86 [jrd]
; All registers are preserved
push dx ; save regs
push cx
push ax
mov byte ptr filtst.dta+21,0 ; clear old attribute bits
mov byte ptr filtst.fname,0 ; clear any old filenames
mov filtst.fstat,0 ; clear status byte
mov cx,3fH ; look at all kinds of files
mov dx,offset filtst.dta ; own own temporary dta
mov ah,setdma ; set to new dta
int dos
pop dx ; get ax (filename string ptr)
push dx ; save it again
mov ah,first2 ; search for first
int dos
pushf ; save flags
mov dx,offset buff ; reset dma
mov ah,setdma
int dos
popf ; recover flags
jnc isfil1 ; nc = file found
mov filtst.fstat,al ; record DOS status
cmp al,2 ; just "File Not Found"?
je isfil2 ; e = yes
cmp al,3 ; "Path not found"?
je isfil2 ; e = yes
cmp al,18 ; "No more files"?
je isfil2 ; e = yes
or filtst.fstat,80h ; set high bit for more serious error
jmp isfil2
isfil1: cmp byte ptr filtst.fname,0 ; did DOS fill in a name?
jne isfil3 ; nz = yes
isfil2: stc ; else set carry flag bit
isfil3: pop ax
pop cx
pop dx
ret ; DOS sets carry if file not found
ISFILE ENDP
; initialize memory usage by returning to DOS anything past the end of kermit
memini proc near
push es
mov es,psp ; address psp segment again
mov bx,offset msfinal + 15 ; end of pgm + roundup
mov cl,4
shr bx,cl ; compute # of paragraphs in last seg
mov ax,datas ; last segment
sub ax,psp ; minus beginning
add bx,ax ; # of paragraphs occupied
mov ah,setblk
int dos
jc memin1
pop es
ret
memin1: pop es
; mov dx,offset ermes2
mcmsg ermes2,cermes2
mov ah,prstr
int dos ; complain
jmp krmend ; and just exit..
memini endp
; Allocate memory. Passed a memory size in ax, allocates that many
; bytes (actually rounds up to a paragraph) and returns its SEGMENT in ax
; The memory is NOT initialized. Written by [jrd] to allow memory to
; be allocated anywhere in the 1MB address space
sbrk proc near ; K & R, please forgive us
mov bx,ax ; bytes wanted
add bx,15 ; round up
mov cl,4
shr bx,cl ; convert to # of paragraphs
mov ah,alloc ; DOS memory allocator
int dos
jc sbrkx ; c = fatal
ret ; and return segment in ax
;sbrkx: mov dx,offset mfmsg ; assume not enough memory (ax = 8)
sbrkx: mcmsg mfmsg, cmfmsg
cmp ax,7 ; corrupted memory (ax = 7)?
jne sbrkx1 ; ne = no
; mov dx,offset mf7msg ; corrupted memory found
mcmsg mf7msg, cmf7msg
sbrkx1: mov ah,prstr
int dos
jmp krmend ; exit Kermit now
sbrk endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret
R PROC NEAR
ret
R ENDP
code ends ; End of code section
end start