home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msk230s1.zip
/
MSSKER.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-12
|
59KB
|
1,311 lines
NAME mssker
; File MSSKER.ASM
; Edit history:
; Last edit 7 Jan 1988
; 7 Jan 1988 Add es: seg override in parts of gcmdl procedure. [jrd]
; 1 Jan 1988 version 2.30
; 31 Dec 1987 Add DOS command line commands of "-f filespec" meaning replace
; name mskermit.ini with filespec as the init file, and "stay" meaning
; stay active after last command is finished.
; 21 Sept 1987 Add 'R' keyword for Receive short form. [jrd]
; 18 Aug 1987 Change CWD to CWDIR for MASM 4.5+ [jrd]
; 9 July 1987 Replace keyword CLRINP with keyword CLEAR. [jrd]
; 4 July 1987 Remove Clear and Local commands. Revise handling of Environment,
; allow very long PATH= strings, general cleanup.[jrd]
; 7 June 1987 Add error level values when returning to DOS. [jrd]
; 0 = success, 1= send failed, 2 = receive failed, 4 = REMOTE cmd failed.
; 24 March 1987 Add Disable and Enable server commands, req by Bill Catchings
; [jrd]
; 18 March 1987 Add Path not found to isfile knowledge. [jrd]
; 1 Oct 1986 Version 2.29a
; 30 August 86 Add DOS Critical Error handler replacement and redo Control
; Break handler to avoid aborting Kermit with the serial port interrupt
; running and these interrupts redirected to Kermit. [jrd]
; 14 July 86 Add entry points for Scripts. [jrd]
; [2.29] code frozen on 6 May 1986 [jrd]
;****************************** Version 2.30 *****************************
; KERMIT, Celtic for "free"
;
; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
; used by permission.
;
; Kermit-MS Program Version 2.30, 1 Jan 1988
; Kermit-MS Program Version 2.29, 26 May 1986, plus later revisions.
; Kermit-MS Program Version 2.27, December 6,1984
;
; Based on the Columbia University KERMIT Protocol.
;
; Copyright (C) 1982,1983,1984,1985,1986,1987,1988
; Trustees of Columbia University
;
; Daphne Tzoar, Jeff Damens
; Columbia University Center for Computing Activities
; 612 West 115th Street
; New York, NY 10025
;
; Joe R. Doupnik (version 2.29, 2.30)
; Dept of EE, and CASS
; Utah State University
; Logan, Utah 84322
;
; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
; Vace Kundakci, and Bernie Eiben for their help and contributions.
public prompt, dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
public takrd, takadr, taklev, filtst, drives, maxtry, imxtry
public netdone
include mssdef.h
env equ 2CH ; environment address in psp
cline equ 80H ; offset in psp of command line
CSTACK SEGMENT PARA STACK 'STACK' ; Renamed from STACK
dw 200 dup(0) ; Initialize stack to all zeros.
CSTACK ENDS
datas segment public 'datas'
extrn buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
extrn prmptr:word, inichk:byte, ttyact:byte
extrn machnam:byte, msfinal:byte, diskio:byte, decbuf:byte
versio label byte
verdef
db cr,lf,'$'
hlpmsg db 'Type ? for help',cr,lf,'$'
crlf db cr,lf,'$'
ermes1 db cr,lf,'?Unrecognized command$'
ermes2 db cr,lf,'?Unable to initialize memory$'
ermes3 db cr,lf,'?Not confirmed$'
ermes4 db cr,lf,'?Unable to change directory$'
erms30 db cr,lf,'Passed maximum nesting level for TAKE command$'
erms31 db cr,lf,'Take-file not found$'
erms34 db cr,lf,'This program requires DOS 2.0 or above$'
erms35 db cr,lf,'Must specify program name$'
erms37 db cr,lf,'Unable to execute program$'
tmsg5 db cr,lf,'[closing log file]',cr,lf,'$'
badnam db cr,lf,'?Protected or no such file(s).$'
filmsg db ' File specification with optional path name $'
pthmsg db ' Name of new working directory$'
tophlp db cr,lf
db ' Bye (to remote server) '
db ' Logout (to remote server)'
db cr,lf
db ' C or Connect (become a terminal) '
db ' Output text (for scripts)'
db cr,lf
db ' Clear (clear serial port buf) '
db ' Pause [seconds] (for scripts)'
db cr,lf
db ' Close (logging file) '
db ' Push (go to DOS)'
db cr,lf
db ' Comment (text is ignored) '
db ' Quit (leave Kermit)'
db cr,lf
db ' CWD (change dir &/or disk) '
db ' R or Receive (opt local filename)'
db cr,lf
db ' Define (a command macro) '
db ' Remote (prefix for commands)'
db cr,lf
db ' Delete (a file) '
db ' Run (a program)'
db cr,lf
db ' Directory '
db ' S or Send (local file new name)'
db cr,lf
db ' Disable (selected server commands)'
db ' Server (become a local server)'
db cr,lf
db ' Do (a macro) '
db ' Set (most things)'
db cr,lf
db ' Echo text (show line on screen) '
db ' Show (various definitions)'
db cr,lf
db ' Enable (selected server commands)'
db ' Space (left on current disk)'
db cr,lf
db ' Exit (leave Kermit) '
db ' Status (show main conditions)'
db cr,lf
db ' Finish (to remote server) '
db ' Stay (in Kermit after startup)'
db cr,lf
db ' Get (remote file opt new name)'
db ' Take (do a command file)'
db cr,lf
db ' Hangup (drop DTR, hangs up phone)'
db ' Transmit filespec [pmpt] (raw upload)'
db cr,lf
db ' Help (show this list) '
db ' Type (a file)'
db cr,lf
db ' Input [timeout] text (for scripts)'
db ' Version (show Kermit',27H,'s id)' ; 27H = single quote
db cr,lf
db ' Log (Packet or Session to file)'
db cr,lf,'$'
comtab db 43 ; COMND tables
mkeyw 'Bye',bye
mkeyw 'C',telnet
mkeyw 'Clear',scclr
mkeyw 'Close',clscpt
mkeyw 'Comment',rskp
mkeyw 'Connect',telnet
mkeyw 'CWD',cwdir
mkeyw 'Define',dodef
mkeyw 'Delete',delete
mkeyw 'Directory',direct
mkeyw 'Disable',srvdsa
mkeyw 'Do',docom
mkeyw 'Echo',scecho
mkeyw 'Enable',srvena
mkeyw 'Exit',exit
mkeyw 'Finish',finish
mkeyw 'Get',get
mkeyw 'H',help
mkeyw 'Hangup',dtrlow
mkeyw 'Help',help
mkeyw 'Input',scinp
mkeyw 'Log',setcpt
mkeyw 'Logout',logout
mkeyw 'Output',scout
mkeyw 'Pause',scpau
mkeyw 'Push',dopush
mkeyw 'Quit',exit
mkeyw 'R',read
mkeyw 'Receive',read
mkeyw 'Remote',remote
mkeyw 'Run',run
mkeyw 'S',send
mkeyw 'Send',send
mkeyw 'Server',server
mkeyw 'Set',setcom
mkeyw 'Show',showcmd
mkeyw 'Space',chkdsk
mkeyw 'Status',status
mkeyw 'Stay',rskp ; this command does nothing.
mkeyw 'Take',take
mkeyw 'Transmit',scxmit
mkeyw 'Type',typec
mkeyw 'Version',prvers
shotab db 5
mkeyw 'Key',shokey
mkeyw 'Macros',shomac
mkeyw 'Modem',shomodem
mkeyw 'Statistics',shosta
mkeyw 'Translation',shorx
; Program storage.
ssave dw ? ; Original SS when doing Command.com
in3ad dw 0,0 ; Original break interrupt addresses
ceadr dd 0 ; DOS Critical Error interrupt address
curdsk db 0 ; Current disk.
origd db 0 ; Original disk.
orgdir db 64 dup (?) ; original directory on original disk
drives db ? ; number of disk drives on system
taklev db 0 ; Take levels
takadr dw takstr-(size takinfo) ; Pointer into structure
takstr db (size takinfo) * maxtak dup(?)
psp dw ? ; segment of Program Segment Prefix
imxtry db defmxtry ; Retry limit for I packet send/rcv
maxtry db defmxtry ; Retry limit for data packet send/rcv
ininm2 db 'MSKERMIT.INI',0 ; init file name for 2.0
filtst filest <> ; file structure for procedure isfile
exearg dw ? ; segment addr of environment (filled in below)
dd 0 ; ptr to cmd line (filled in below)
dw 5ch,0,6ch,0 ; our def fcb's; segment filled in later
delcmd db ' del ',0 ; delete command
dircmd db ' dir ',0 ; directory command
chkdcmd db 'chkdsk.com',0 ; space command
typcmd db ' type ',0 ; type command
dosnum db ? ; dos version number
pthnam db 'PATH=' ; Path environment variable
pthlen equ $-pthnam ; length of that string
pthadr dw 0 ; offset of PATH= string
slashc db ' /c ' ; slashc Must directly preceed tmpbuf
tmpbuf db 65 dup (?) ; temp space for file names.
cmspnam db 'COMSPEC=' ; Environment variable
cmsplen equ $-cmspnam
cmspbuf db '\command.com',30 dup (0) ; default name plus additional space
eexit db cr,'exit',cr
leexit equ $-eexit
mfmsg db '?Not enough memory to run Kermit$'
mf7msg db '?Attempted to allocate a corrupted memory area$'
netdone dw 0 ; network closedown call pointer
errlev db 0 ; DOS errorlevel to be returned
datas ends ; End data segment
code segment public 'code'
extrn cmblnk:near, locate:near, logout:near
extrn bye:near, telnet:near, finish:near, comnd: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
extrn strcat:near, prtasz:near, shorx:near
extrn scout:near,scinp:near,scpau:near,scecho:near,scclr:near
extrn scxmit:near, srvdsa:near, srvena:near
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.
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:
mov ah,prstr
mov dx,offset machnam ; print machine name
int dos
mov ah,prstr ; Print the version header.
mov dx,offset versio
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 getbaud ; Get the baud rate.
call dodisk ; See how many disk drives we have.
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: 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
int dos
start3: 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
mov dx,prmptr ; get prompt
call prompt ; Prompt the user.
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
mov comand.cmcr,1 ; Allow bare CR's.
mov ah,cmkey
call comnd
jmp kermt2
mov comand.cmcr,0 ; Not anymore.
call bx ; Call the routine returned.
jmp kermt3
cmp flags.extflg,0 ; Check if the exit flag is set.
jne krmend ; If so jump to KRMEND.
jmp short kermt5 ; Do it again.
kermt2: mov dx,offset ermes1 ; Say Unrecognized Command
jmp short kermt4
kermt3: mov dx,offset ermes3 ; Say Not Confirmed.
kermt4: 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
mov bx,takadr ; structure of current Take
cmp byte ptr [bx].taktyp,0ffh ; type of Take (file or macro)
je kermt6 ; e = macro, do not try to close it
mov bx,word ptr [bx].takhnd ; Take file handle
mov ah,close2 ; DOS 2 file close
int dos ; close the Take file
kermt6: dec taklev ; readjust Take level
sub takadr,size takinfo ; readjust Take buffer
kermt7: mov flags.nmoflg,0 ; Reset filename override flag.
mov flags.getflg,0 ; May as well do this one.
jmp kermit ; get next command
krmend: call serrst ; Just in case the port wasn't reset
test flags.capflg,0FFH ; Logging active?
jz krmend1 ; z = no
mov dx,offset tmsg5
mov ah,prstr
int dos
call clscpi ; close log file
nop ; this skip returns...
nop
nop
krmend1: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
cmp netdone,0 ; does network cleanup pointer exist?
je krmend2 ; e = no, so ignore it
call netdone ; call the vector to shut network connection
krmend2:
mov ah,4cH ; terminate process
mov al,errlev ; return error level
int dos
ret
START ENDP
; change working directory
cwdir proc near
mov ah,cmfile
mov dx,offset tmpbuf
mov bx,offset pthmsg
call comnd
jmp r
mov dx,offset tmpbuf
mov ah,chdir
int dos
jnc cwd1
mov dx,offset ermes4
mov ah,prstr
int dos
jmp rskp
cwd1: mov bx,dx ; change of drives, if req'd
cmp byte ptr [bx+1],':' ; was a drive specified?
jne cwd3 ; ne = no
mov dl,[bx] ; get the drive letter
and dl,5FH ; make upper case
sub dl,'A' ; convert to A = 0, etc
mov ah,seldsk
int dos ; change disks
inc dl ; count A = 1 internally
mov curdsk,dl ; and store it
cwd3: jmp rskp
cwdir 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
mov flags.extflg,1 ; Set the exit flag.
jmp rskp ; Then return to system.
EXIT ENDP
; This is the 'HELP' command. It gives a list of the commands.
HELP PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
mov ah,prstr ; Print a string to the console.
mov dx,offset tophlp ; The address of the help message.
int dos
jmp rskp
HELP 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
; TAKE commands from a file, and allow a path name
TAKE PROC NEAR
cmp taklev,maxtak ; Hit our limit?
jl take1 ; Continue if still OK.
mov ah,prstr
mov dx,offset erms30 ; Complain.
int dos
ret
take1: mov di,takadr
add di,size takinfo
push di
mov ah,cmfile
lea dx,[di].takbuf ; convenient place to parse name into
mov bx,offset filmsg ; Help in case user types "?".
call comnd
pop di
ret
nop
pop di ; restore frame address
cmp ah,0
je take2 ; empty, complain.
push di ; keep it on stack.
lea si,[di].takbuf ; get buffer back
mov bl,ah ; length of thing parsed
mov bh,0
mov byte ptr [bx+si],0 ; make it asciz
mov ax,si ; point to name again
call spath ; is it around?
pop di ; need this back
jc take2 ; no, go complain
mov dx,ax ; point to name from spath
mov ah,open2 ; 2.0 open call
mov al,0 ; open for reading
int dos
jnc take3 ; open ok, keep going
take2: mov ah,prstr
mov dx,offset erms31
int dos
ret
take3: inc taklev
mov takadr,di
mov word ptr [di].takhnd,ax ; save file handle
mov byte ptr [di].taktyp,0feh ; mark as 2.0 file handle
mov bx,ax ; need descriptor here
mov ah,lseek
mov al,2
mov cx,0
mov dx,cx ; seek 0 bytes from end
int dos
mov [di].takcnt,ax
mov [di].takcnt+2,dx ; store length
mov ah,lseek
mov al,0
mov cx,0
mov dx,cx ; now seek back to beginning
int dos
cmp flags.takflg,0 ; echoing commands?
je take4 ; e = no
mov ah,prstr
mov dx,offset crlf
int dos
take4: call takrd ; Get a buffer full of data.
jmp rskp
TAKE ENDP
TAKRD PROC NEAR
push bx
push cx
push dx
mov bx,takadr
push bx ; save frame address
lea dx,[bx].takbuf ; buffer to read into
mov cx,dmasiz ; # of bytes to read
mov ah,readf2 ; 2.0 read call
mov bx,word ptr [bx].takhnd ; file handle is stored here
int dos
pop bx ; restore frame address
jnc takrd2 ; nc = successful read
mov ax,0 ; error, say zero bytes read
takrd2: mov [bx].takchl,al ; number of bytes read
lea ax,[bx].takbuf
mov [bx].takptr,ax
pop dx
pop cx
pop bx
ret
TAKRD 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
; put kermit.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
rdini1: push bx
call spath ; can we find it?
pop di
jc rdini6 ; no, forget it
mov dx,ax ; point to name
mov ah,open2 ; 2.0 open function
mov al,0 ; for reading...
int dos
jc rdini6 ; can't open, forget it
inc taklev ; bump take level
add takadr,size takinfo
mov di,takadr ; get current frame ptr
mov word ptr [di].takhnd,ax ; save file handle
mov byte ptr [di].taktyp,0feh ; mark as a handle
mov bx,ax ; move file ptr
mov ah,lseek
mov al,2
mov cx,0
mov dx,0 ; seek to end of file
int dos
mov [di].takcnt,ax ; copy file size
mov [di].takcnt+2,dx ; into structure
mov al,0
mov ah,lseek
mov cx,0
mov dx,0
int dos ; seek back to beginning
cmp flags.takflg,0 ; echo Take files?
je rdini3 ; e = no
mov ah,prstr
mov dx,offset crlf
int dos
rdini3: call takrd ; Get a buffer full of data.
rdini6: ret ; no init file, just return
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
inc taklev ; bump take level
add takadr,size takinfo ; address new take frame
mov bx,takadr
mov byte ptr [bx].taktyp,0ffh ; mark as a macro
mov [bx].takchl,0 ; chars remaining in macro
mov [bx].takcnt,0 ; and all chars in macro
lea di,[bx].takbuf ; point at text field of take buffer
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 ; ne = 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
mov di,offset 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
lea si,[bx].takbuf ; get address of text field
mov cx,di ; current end pointer, (save di)
sub cx,si ; current ptr minus start offset
mov [bx].takchl,cl ; count chars
mov [bx].takcnt,cx
cmp cx,0
jg gcmdl11 ; material at hand
dec taklev ; nothing to take
sub bx,size takinfo ; so reset Take info to say none
mov takadr,bx
jmp gcmdl14 ; and exit.
; 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
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
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].takchl,cl
add [bx].takcnt,cx
rep movsb ; copy it into the macro
gcmdl13:lea ax,[bx].takbuf ; update Take info
mov [bx].takptr,ax ; init buffer ptr
mov [bx].takcnt+2,0 ; clear high order
gcmdl14:pop es
ret
gcmdlin endp
; This routine prints the prompt and specifies the reparse address.
PROMPT PROC NEAR
mov comand.cmprmp,dx ; save the prompt
pop bx ; Get the return address.
mov comand.cmrprs,bx ; Save as addr to go to on reparse.
mov comand.cmostp,sp ; Save for later restoral.
push bx ; Put it on the stack again.
mov bx,offset comand.cmdbuf
mov comand.cmcptr,bx ; Initialize the command pointer.
mov comand.cmdptr,bx
mov ah,0
mov comand.cmaflg,ah ; Zero the flags.
mov comand.cmccnt,ah
mov comand.cmsflg,0FFH
cmp flags.takflg,0 ; look at Take flag
jne promp1 ; supposed to echo, skip this check
cmp taklev,0 ; inside a take file?
je promp1 ; no, keep going
ret ; yes, return
promp1: mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,comand.cmprmp
int dos
ret
PROMPT 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 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,cmtxt ; parse with cmtxt so we can have paths
mov bx,di ; where to place the file specs
mov dx,offset filmsg ; In case user wants help.
call comnd
jmp r
mov byte ptr [bx],0 ; plant terminator
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
int dos
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 (use Chkdsk.com)
mov ah,cmcfm
call comnd
jmp r
mov si,offset chkdcmd ; point to cmd
jmp crun ; and go execute it nicely
CHKDSK ENDP
; Get directory listing.
DIRECT PROC NEAR
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.
call comnd
jmp r
mov byte ptr [bx],0 ; plant terminator
mov si,offset tmpbuf
jmp crun ; join run cmd from there.
DIRECT ENDP
; the version command - print our version number
prvers proc near
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
int dos
jmp rskp
prvers endp
; the type command - type out a file
typec proc near
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.
call comnd
jmp r
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
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 filmsg ; In case user wants help.
call comnd
nop
nop
nop
cmp ah,0 ; byte count
jne run2 ; ne = have program name
mov ah,prstr ; else complain
mov dx,offset erms35
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
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.
jmp rskp ; ok, return
crun8: mov ah,prstr
mov dx,offset erms37
int dos
jmp rskp
CRUN ENDP
; the show command
showcmd proc near
mov ah,cmkey
mov dx,offset shotab
xor bx,bx ; no canned help
call comnd
jmp r
call bx ; call the handler
jmp r
jmp rskp ; and return
showcmd 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
; enter with ax/ ptr to file name. Searches path for given file,
; returns with ax/ ptr to whole name, or carry on if file isn't
; to be found.
SPATH proc near
mov bx,ax ; convenient place to keep this
call isfile ; does it exist as it is?
mov ax,bx ; if so, just return original name
jc spath0 ; c = nope, prepend path elements
ret
spath0: push es ; save es around work
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 ax,es:word ptr[env] ; pick up environment segment
mov es,ax
spath4: cmp byte ptr es:[si],0 ; end of PATH= string?
je spath9 ; e = yes, exit loop
mov di,offset tmpbuf ; 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 tmpbuf 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 tmpbuf
call isfile ; is it a file?
jc spath4 ; c = no, keep looking
pop es
ret ; return success (carry off)
spath9: pop es ; restore this
stc ; no file found
ret
spath endp
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
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).
cmp ax,7 ; corrupted memory (ax = 7)?
jne sbrkx1 ; ne = no.
mov dx,offset mf7msg ; corrupted memory found
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