home *** CD-ROM | disk | FTP | other *** search
- public prompt, dosnum, curdsk, swchar
- include msdefs.h
- ;******************** Version 2.26 **********************************
- ; KERMIT, Celtic for "free"
- ;
- ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
- ; used by permission.
- ;
- ; Kermit-MS Program Version 2.26, July 26, 1984
- ;
- ; Based on the Columbia University KERMIT Protocol.
- ;
- ; Copyright (C) 1982,1983,1984 Trustees of Columbia University
- ;
- ; Daphne Tzoar, Jeff Damens
- ; Columbia University Center for Computing Activities
- ; 612 West 115th Street
- ; New York, NY 10025
- ;
- ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
- ; Vace Kundakci, and Bernie Eiben for their help and contributions.
-
- makseg equ 26H
- deffcb equ 5cH
- setblk equ 4AH
- exec equ 4BH
- env equ 2CH ; environment address in psp
- terma equ 10 ; termination address in psp
- cline equ 80H ; offset in psp of command line
- namsiz equ 20 ; Bytes for file name and size.
- maxnam equ 10
- chmod equ 43H ; chmod call (used to test for file existence)
-
- STACK SEGMENT PARA STACK 'STACK'
- DW 100 DUP(0) ; Initialize stack to all zeros.
- STK EQU THIS WORD
- STACK ENDS
-
- datas segment public 'datas'
- extrn buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
- extrn fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
- extrn machnam:byte
- public takadr,taklev
-
- versio label byte
- verdef
- db cr,lf
- db 'Type ? for help',cr,lf
- db '$'
- tmp db ?,'$'
- crlf db cr,lf,'$'
- ermes1 db cr,lf,'?Unrecognized command$'
- ermes3 db cr,lf,'?Not confirmed$'
- erms30 db cr,lf,'Passed maximum nesting level for TAKE command$'
- erms31 db cr,lf,'Take file not found$'
- erms32 db cr,lf,'File(s) not found$'
- erms33 db cr,lf,'CHKDSK program not found on current disk$'
- erms34 db cr,lf,'This command works only for DOS 2.0 and above$'
- erms35 db cr,lf,'Must specify program name$'
- erms36 db cr,lf,'Could not free memory$'
- erms37 db cr,lf,'Unable to execute program$'
- infms1 db 'Really erase *.*? $'
- infms8 db cr,lf,'File(s) erased$'
- tmsg5 db cr,lf,'[closing log file]',cr,lf,'$' ; [jd]
- filhlp1 db ' Command file specification $'
- filhlp2 db ' File specification (possibly wild) $'
- filhlp3 db ' File spec (possibly wild) or confirm with carriage return$'
- filmsg db ' File specification with optional path name $'
- filwmsg db ' File specification (possibly wild) with optional path name $'
- chkfil db 0,'CHKDSK COM'
- chkflen equ $-chkfil
-
- tophlp db cr,lf
- db 'BYE',tab,tab
- db 'CLOSE',tab,tab
- db 'CONNECT',tab,tab
- db 'DEFINE',tab,tab
- db cr,lf
- db 'DELETE',tab,tab
- db 'DIRECTORY',tab
- db 'DO',tab,tab
- db 'EXIT',tab,tab
- db cr,lf
- db 'FINISH',tab,tab
- db 'GET',tab,tab
- db 'HELP',tab,tab
- db 'LOCAL',tab,tab
- db cr,lf
- db 'LOG',tab,tab
- db 'LOGOUT',tab,tab
- db 'PUSH',tab,tab
- db 'QUIT',tab,tab
- db cr,lf
- db 'RECEIVE',tab,tab
- db 'REMOTE',tab,tab
- db 'RUN',tab,tab
- db 'SEND',tab,tab
- db cr,lf
- db 'SERVER',tab,tab
- db 'SET',tab,tab
- db 'SHOW',tab,tab
- db 'SPACE',tab,tab
- db cr,lf
- db 'STATUS',tab,tab
- db 'TAKE'
- db '$'
-
- lochlp db cr,lf,'DELETE file'
- db cr,lf,'DIRECTORY [filespec]'
- db cr,lf,'SPACE remaining on current disk'
- db cr,lf,'RUN program'
- db cr,lf,'PUSH to command interpreter'
- db '$'
-
- ; COMND tables
-
- yestab db 2
- mkeyw 'NO',0
- mkeyw 'YES',1
-
- comtab db 27
- mkeyw 'BYE',bye
- mkeyw 'C',telnet
- mkeyw 'CLOSE',clscpt
- mkeyw 'CONNECT',telnet
- mkeyw 'DEFINE',dodef
- mkeyw 'DELETE',delete
- mkeyw 'DIRECTORY',direct
- mkeyw 'DO',docom
- mkeyw 'EXIT',exit
- mkeyw 'FINISH',finish
- mkeyw 'GET',get
- mkeyw 'HELP',help
- mkeyw 'LOCAL',lclcmd
- mkeyw 'LOG',setcpt
- mkeyw 'LOGOUT',logout
- mkeyw 'PUSH',dopush
- mkeyw 'QUIT',exit
- mkeyw 'RECEIVE',read
- mkeyw 'REMOTE',remote
- mkeyw 'RUN',run
- mkeyw 'SEND',send
- mkeyw 'SERVER',server
- mkeyw 'SET',setcom
- mkeyw 'SHOW',showcmd
- mkeyw 'SPACE',chkdsk
- mkeyw 'STATUS',status
- mkeyw 'TAKE',take
-
- loctab db 5
- mkeyw 'DELETE',delete
- mkeyw 'DIRECTORY',direct
- mkeyw 'PUSH',dopush
- mkeyw 'RUN',run
- mkeyw 'SPACE',chkdsk
-
- shotab db 2
- mkeyw 'KEY',shokey
- mkeyw 'MACRO',shomac
-
- ; Program storage.
-
- oldstk dw ? ; Storage for system stack.
- oldsts dw ? ; System stack segment.
- ssave dw ? ; Original SS when doing CHKDSK.
- siz dw ? ; Memory size.
- in3ad dd 0 ; Original break interrupt addresses. [25]
- curdsk db 0 ; Current disk.
- origd db 0 ; Original disk.
- fildat db 0 ; Manipulate file data/time creation.
- db 0
- taklev db 0 ; Take levels. [25t]
- takadr dw takstr-(size takinfo) ; Pointer into structure. [25t]
- temp dw 0
- temp1 dw ? ; Temporary storage.
- temp2 dw ?
- temp3 dw ?
- temp4 dw ?
- psp dw ?
- divst dw 0
- takstr db (size takinfo) * maxtak dup(?)
- ininam db 0,'MSKERMITINI' ; init file name, on default disk, 12 chars
- ininm2 db 'MSKERMIT.INI',0 ; init file name for 2.0
- nambuf db maxnam * namsiz dup (?)
- cmdnam db namsiz dup (?)
- exefcb db fcbsiz dup (?)
- exefcb2 db fcbsiz dup (?)
- exearg dw ? ; segment addr of environment (filled in below)
- dd 0 ; ptr to cmd line (filled in below)
- dd exefcb ; default fcb
- dd exefcb2 ; second default fcb
- dircmd db ' /c dir '
- dirclen equ $-dircmd
- dirnam db 50h dup (?)
- chkdcmd db 'chkdsk.com'
- chkdlen equ $-chkdcmd
- dosnum db ? ; dos version number
- pthnam db 'PATH='
- pthlen equ $-pthnam
- pthbuf db 100 dup (?) ; buffer for path definition.
- defpth db '\', 70 dup (?) ; buffer for default path
- cmspnam db 'COMSPEC='
- cmsplen equ $-cmspnam
- cmspbuf db '\command.com',0 ; default name
- db 30 dup (?) ; some additional space
- tfile db 100 dup (?) ; temp space for file names.
- eexit db cr,'exit',cr
- leexit equ $-eexit
- swchar db '\' ; default switch character.
- datas ends ; End data segment
-
- code segment public
- public takrd
- start proc far
- 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
- extrn clscpi:near, clscpt:near, getbaud:near
- extrn dodef:near, setcpt:near, docom:near
- extrn server:near, lclini:near, shokey:near, shomac:near
- assume cs:code,ds:datas,ss:stack,es:nothing
-
- push ds ; Save system data area.
- sub ax,ax ; Get a zero.
- push ax ; Put zero return addr on stack.
-
- mov ax,datas ; Initialize DS.
- mov ds,ax
- sub ax,ax
-
- mov oldstk,sp ; Save old stack pointer.
-
- mov ax,es:[2] ; In program segment prefix
- mov siz,ax ; Pick up memory size
- mov psp,es
-
- 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 getbaud ; Get the baud rate. [25]
- call dodisk ; See how many disk drives we have. [21a]
- 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 ah,dosver
- int dos
- mov dosnum,al ; remember dos version
- cmp al,0
- je start1 ; 1.1, keep going
- mov es,psp
- mov ax,es:[env] ; pick up environment address
- push ax
- call getpath ; get the path from the environment
- pop ax ; get environment back
- call getcsp ; get comspec from environment as well
- start1: call lclini ; do local initialization
- call gcmdlin ; read command line
- call rdinit ; read kermit init file
- call packlen ; Packet length in case do server comand.
- ; 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 itme.
- 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 kermit ; Do it again.
-
- kermt2: mov dx,offset ermes1 ; Give an error.
- jmp short kermt4
-
- kermt3: mov dx,offset ermes3 ; Give an error.
- kermt4: cmp flags.cxzflg,'C' ; some sort of abort?
- je kermit ; yes, don't print error message.
- mov ah,prstr
- int dos
- mov flags.droflg,0 ; Reset drive override flag.
- mov flags.nmoflg,0 ; Reset filename override flag.
- mov flags.getflg,0 ; May as well do this one.
- mov flags.cmrflg,0 ; This one too.
- jmp kermit
-
- krmend: call serrst ; Just in case the port wasn't reset. [21c]
- mov dl,origd ; Original disk drive.
- dec dl ; Want A == 0.
- mov ah,seldsk ; Reset original disk just in case.
- int dos
- mov sp,oldstk
- 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
- test flags.capflg,0FFH ; capturing?
- jz exit1 ; no, keep going
- mov dx,offset tmsg5
- mov ah,prstr
- int dos
- call clscpi
- nop ; this skip returns...
- nop
- nop
- exit1:
- 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
-
- lclcmd proc near
- mov ah,cmkey
- mov dx,offset loctab
- mov bx,offset lochlp
- call comnd
- jmp r
- call bx
- nop
- nop
- nop
- jmp rskp
- lclcmd endp
-
- ; Don't ignore ^C when in debug mode.
- SETINT PROC NEAR
- push ds ; Don't forget this. [25]
- mov ax,ds
- mov es,ax ; So can access our data area.
- mov ax,0
- mov ds,ax ; Access low core.
- mov ax,ds:[23H * 4] ; Address for interrupt 23H.
- mov cx,ds:[23H * 4 +2] ; CS value for it.
- mov word ptr es:in3ad,ax ; Remember original values.
- mov word ptr es:in3ad+2,cx
- mov ax,cs
- mov ds,ax ; Access code are.
- mov dx,offset intbrk
- mov al,23H ; On ^C, goto above address.
- mov ah,25H
- int dos
- pop ds
- ret
- SETINT ENDP
-
- ; take commands from a file, but allow a path name
- PTAKE PROC NEAR
- cmp taklev,maxtak ; Hit our limit?
- jl ptake1 ; Continue if still OK.
- mov ah,prstr
- mov dx,offset erms30 ; Complain.
- int dos
- ret
- ptake1: mov di,takadr
- add di,size takinfo
- push di
- mov ah,cmtxt
- lea bx,[di].takbuf ; convenient place to parse name into
- mov dx,offset filmsg ; Help in case user types "?".
- call comnd
- pop di
- ret
- nop
- pop di ; restore frame address
- 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 ptake2 ; 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 ptake3 ; open ok, keep going
- ptake2: mov ah,prstr
- mov dx,offset erms31
- int dos
- ret
- ptake3: inc taklev
- mov takadr,di
- mov word ptr [di].takfcb+1,ax ; save file descriptor
- mov byte ptr [di].takfcb,0feh ; mark as 2.0 file descriptor
- 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
- je ptake4
- mov ah,prstr
- mov dx,offset crlf
- int dos
- ptake4: call takrd ; Get a buffer full of data.
- jmp rskp
- PTAKE ENDP
-
-
- ; TAKE commands from a file. [25t]
-
- TAKE PROC NEAR
- cmp dosnum,0
- je take1
- jmp ptake ; use this for 2.0
- take1: cmp taklev,maxtak ; Hit our limit?
- jl take2 ; Continue if still OK.
- mov ah,prstr
- mov dx,offset erms30 ; Complain.
- int dos
- ret
- take2: mov bx,takadr
- add bx,size takinfo
- push bx
- lea dx,[bx].takfcb
- mov comand.cmcr,0 ; Filename must be specified.
- mov ah,cmifi
- mov bx,offset filhlp1
- call comnd
- pop bx
- ret ; Make sure this is three bytes long.
- nop
- pop bx
- mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
- mov ah,openf
- lea dx,[bx].takfcb
- int dos
- cmp al,0FFH ; File not found?
- jne take3
- mov ah,prstr
- mov dx,offset erms31
- int dos
- take3: inc taklev
- mov takadr,bx
- mov ax,word ptr [bx+16].takfcb
- mov [bx].takcnt,ax
- mov ax,word ptr [bx+18].takfcb
- mov [bx].takcnt+2,ax ; copy size into takinfo
- cmp flags.takflg,0
- je take4
- 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
- cmp byte ptr [bx].takfcb,0feh ; is it a 2.0 file handle?
- jne takrd1 ; no, handle differently
- 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].takfcb+1 ; file handle is stored here
- int dos
- pop bx ; restore frame address
- jmp takrd2 ; rejoin common exit
-
- takrd1: mov ah,setdma
- lea dx,[bx].takbuf
- int dos
- mov ah,readf
- lea dx,[bx].takfcb
- int dos
- mov ah,setdma
- lea dx,buff
- int dos
- takrd2: mov [bx].takchl,dmasiz
- lea ax,[bx].takbuf
- mov [bx].takptr,ax
- pop dx
- pop cx
- pop bx
- ret
-
- TAKRD ENDP
-
- ; copy the path into pthbuf
- ; enter with ax/ environment segment address
- ; works in 2.0 only.
- getpath proc near
- push es
- mov bx,ds
- mov es,bx ; address data segment
- mov bx,offset pthnam ; thing to find
- mov cx,pthlen ; length of it
- mov dx,offset pthbuf ; place to put it
- mov byte ptr pthbuf,0 ; initialize to null...
- call getenv ; get environment value
- pop es
- ret ; and return
- getpath endp
-
- ; copy the comspec into cmspbuf
- ; enter with ax/ environment segment address
- ; works in 2.0 only.
- getcsp proc near
- push es
- mov bx,ds
- mov es,bx ; address data segment
- mov bx,offset cmspnam ; thing to find
- mov cx,cmsplen ; length of it
- mov dx,offset cmspbuf ; place to put it
- call getenv ; get environment value
- pop es
- ret ; and return
- getcsp endp
-
- ; find a path variable. Enter with ax/ environment segment,
- ; bx/ variable to find (incl =), cx/ length of variable name,
- ; dx/ address to store value at.
- ; The buffer given in dx is unchanged if the variable isn't found
- getenv proc near
- push ds
- push es
- mov es,ax ; address segment
- mov di,0 ; offset in segment
- geten1: cmp es:byte ptr [di],0 ; end?
- je geten4 ; yes, forget it
- push cx ; save counter
- push di ; and offset
- mov si,bx
- repe cmpsb ; is it the one?
- 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
- mov si,di ; this is source
- mov di,dx ; destination as given
- mov ax,ds
- mov bx,es
- mov ds,bx
- mov es,ax ; exchange segment regs for copy
- geten3: lodsb ; get a byte
- stosb ; drop it off
- cmp al,0 ; end of string
- jne geten3 ; no, go on
- geten4: pop es
- pop ds ; restore registers
- 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 al,dosnum ; get dos version
- or al,al
- jne rdini4 ; post 2.0, use file handle instead...
- mov bx,takadr
- add bx,size takinfo ; bump take ptr, point to current take frame
- lea di,[bx].takfcb ; destination is fcb
- mov ax,ds
- mov es,ax ; destination segment = source segment
- mov si,offset ininam ; name of init file
- mov cx,12 ; 8 char name + 3 char ext + 1 char drive...
- rep movsb ; copy it in
- mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
- mov ah,openf
- lea dx,[bx].takfcb
- int dos
- cmp al,0FFH ; File not found?
- jne rdini1 ; no, keep going
- ret ; else just return, no init file
- rdini1: inc taklev ; bump take level
- mov takadr,bx ; save current take frame ptr
- mov ax,word ptr [bx+16].takfcb
- mov [bx].takcnt,ax
- mov ax,word ptr [bx+18].takfcb
- mov [bx].takcnt+2,ax ; copy size into takinfo
- rdini2: cmp flags.takflg,0
- je rdini3
- mov ah,prstr
- mov dx,offset crlf
- int dos
- rdini3: call takrd ; Get a buffer full of data.
- ret
-
- rdini4: mov ax,offset ininm2 ; name to try
- push bx
- call spath ; can we find it?
- pop di
- jc rdini6 ; no, forget it, go use 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
-
- rdini5: inc taklev ; bump take level
- add takadr,size takinfo
- mov di,takadr ; get current frame ptr
- mov word ptr [di].takfcb+1,ax ; save file handle
- mov byte ptr [di].takfcb,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
- jmp rdini2 ; go rejoin common exit
- rdini6: ret ; no init file, just return
- rdinit endp
-
- ; get command line into a macro buffer.
-
- gcmdlin proc near
- push ds
- push es
- cld
- mov es,psp ; address psp
- mov ch,0
- mov cl,es:[cline] ; length of cmd line
- mov di,cline+1 ; point to actual line
- mov al,' '
- jcxz gcmdl3 ; no command line, forget it.
- repe scasb ; skip over spaces
- je gcmdl3 ; all spaces, forget it
- mov si,di ; this is first non-space
- dec si ; pre-incremented...
- inc cx
- inc taklev ; bump take level
- add takadr,size takinfo ; address new take frame
- mov bx,takadr
- mov byte ptr [bx].takfcb,0ffh ; mark as a macro
- push cx ; save length
- push ds ; and segment
- lea di,[bx].takbuf ; into take buffer
- mov ax,ds
- mov ds,psp
- mov es,ax ; switch segments for copy
- gcmdl1: lodsb ; get a byte
- cmp al,',' ; comma?
- jne gcmdl2 ; no, keep going
- mov al,cr ; convert to cr
- gcmdl2: stosb ; deposit it
- loop gcmdl1 ; copy whole cmd
- pop ds ; restore segment
- mov si,offset eexit ; something to tack onto end
- mov cx,leexit ; length of it
- rep movsb ; copy it in
- pop cx ; restore len
- add cx,leexit ; count wnat we added
-
- lea ax,[bx].takbuf
- mov [bx].takptr,ax ; init buffer ptr
- mov [bx].takchl,cl ; chars remaining
- mov [bx].takcnt,cx ; and all chars
- mov [bx].takcnt+2,0 ; clear high order
- gcmdl3: pop es
- pop ds
- 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).
- DELETE PROC NEAR
- mov comand.cmcr,0 ; Filename must be specified.
- mov ah,cmifi ; Parse an input filespec.
- mov dx,offset fcb
- mov bx,offset filhlp2 ; Text of help message.
- call comnd
- jmp r ; Bad filename.
- mov ah,cmcfm ; Parse a confirm.
- call comnd
- jmp r
- cld
- mov di,offset fcb+1
- mov al,'?'
- mov cx,11 ; # of chars in a name
- repe scasb ; are they all ?'s?
- jne del1 ; no, skip message
- mov dx,offset infms1
- call prompt
- mov ah,cmkey
- mov dx,offset yestab
- mov bx,0
- call comnd
- jmp r
- push bx
- mov ah,cmcfm
- call comnd
- pop bx
- ret
- nop
- pop bx
- cmp bx,0
- jne del1
- jmp rskp
- del1: mov dx,offset fcb
- mov ah,sfirst ; See if any files match this specification.
- int dos
- cmp al,0FFH ; No matches?
- jne del2
- mov ah,prstr
- mov dx,offset erms32
- int dos
- jmp rskp
- del2: mov dx,offset fcb
- mov ah,delf ; Erase the file(s).
- int dos
- mov dx,offset infms8
- mov ah,prstr ; Say we did so.
- int dos
- jmp rskp
- DELETE ENDP
-
- CHKDSK PROC NEAR
- mov ah,cmcfm
- call comnd
- jmp r
- cmp dosnum,0
- je chkds1 ; yes, have to do it the hard way
- mov si,offset chkdcmd ; point to cmd
- mov cx,chkdlen ; and length
- jmp crun ; and go execute it nicely
- chkds1: push es
- mov ax,ds
- mov es,ax
- mov di,offset fcb
- mov si,offset chkfil
- mov cx,chkflen
- rep movsb
- mov dx,offset stk + 15 ; End of stack plus roundoff.
- mov cl,4
- shr dx,cl ; Divide to get segment.
- add dx,seg stack ; Get past the stack.
- mov es,dx ; remember where segment is.
- mov ah,makseg ; Create new PSP.
- int dos
- mov ax,siz ; Update machine size.
- mov es:2,ax
- mov es: byte ptr [deffcb],0 ; Blank default fcb.
- mov di,deffcb+1
- mov al,' ' ; Blank out fcb.
- mov cx,fcbsiz
- rep stosb
- mov word ptr es:[terma],offset term ; Termination address.
- mov es:[terma+2],cs
- mov ah,openf
- mov dx,offset fcb
- int dos
- inc al
- jnz chkok
- mov dx,offset erms33
- mov ah,prstr
- int dos
- jmp chkend
-
- chkok: mov byte ptr fcb+32,0 ; set current record field
- mov di,100h ; offset to copy into
- lp: mov dx,offset fcb
- mov ah,readf
- int dos
- push ax ; save status
- mov si,offset buff
- mov cx,dmasiz/2 ; Word size of DMA
- rep movsw ; copy into new segment...
- pop ax
- cmp al,1 ; End of file
- je dun
- cmp al,3 ; Done here too
- jne lp
- dun: mov ssave,sp ; Save stack pointer.
- mov ax,es
- mov word ptr cs:[doit+2],ax ; Set segment for CHKDSK.
- mov ds,ax
- mov ss,ax
- mov ax,0
- jmp cs: dword ptr [doit] ; Call CHKDSK.
- term: mov ax,seg datas ; Reset data area.
- mov ds,ax
- mov sp,ssave
- mov ax,seg stack
- mov ss,ax
- mov ah,setdma
- mov dx,offset buff
- int dos ; restore dma address!!
- chkend: pop es
- jmp rskp
- doit dd 100h
- CHKDSK ENDP
-
- ; Get directory listing.
- DIRECT PROC NEAR
- mov ah,dosver ; See what level of DOS we're at.
- int dos
- cmp al,0 ; Level 2.0 or above?
- jne dir4 ; Yes - get directory the easy way.
- mov comand.cmcr,1 ; Allow plain CR (so DIR == DIR *.*).
- mov ah,cmifi ; Get input file spec.
- mov dx,offset fcb ; Give the address for the FCB.
- mov bx,offset filhlp3
- call comnd
- jmp r
- mov ah,cmcfm ; Parse a confirm.
- call comnd
- jmp r
- mov comand.cmcr,0 ; Reset this.
- push es
- mov ax,ds
- mov es,ax
- mov temp1,0FFH
- mov di,offset nambuf
- dir0: call getfn ; Get a matching file name.
- cmp al,0FFH ; Retcode -- are we done?
- je dir1 ; Yes, just leave.
- call dumpit ; Print it or dump to buffer.
- jmp dir0
- dir1: pop es
- jmp rskp
-
- dir4: mov si,offset cmspbuf ; command processor
- mov di,offset dirnam
- dir5: lodsb ; get a byte
- or al,al
- jz dir6 ; stop on the null
- stosb ; otherwise copy it in
- jmp dir5 ; and keep going
- dir6: mov si,offset dircmd ; add directory command to it
- mov cx,dirclen
- rep movsb
- mov ah,cmtxt ; parse with cmtxt so we can have paths...
- mov bx,di ; next available byte
- mov dx,offset filwmsg ; In case user wants help.
- call comnd
- jmp r
- mov cl,ah
- mov ch,0 ; length of name
- sub di,offset dirnam ; compute # of bytes used
- add cx,di
- mov si,offset dirnam ; dir cmd
- jmp crun ; join run cmd from there.
- DIRECT ENDP
-
- getfn: cmp temp1,0FFH
- jne gtfn1
- mov ah,sfirst ; Any matches?
- mov dx,offset fcb
- int dos
- cmp al,0FFH ; Means no matches.
- je gtfn5
- call savfcb
- mov temp1,0
- jmp gtfn4
- gtfn1: cmp flags.wldflg,0FFH ; Wilcard seen?
- je gtfn2 ; Yes, get next file.
- mov al,0FFH ; No, set retcode.
- ret
- gtfn2: call rstfcb
- mov ah,snext
- mov dx,offset fcb
- int dos
- cmp al,0 ; Any more matches?
- je gtfn3 ; Yes keep going.
- mov al,0FFH ; OK return code.
- ret
- gtfn3: call savfcb
- gtfn4: push di
- mov si,offset buff ; Data is here.
- mov di,offset fcb ; Copy to here.
- mov cx,37
- repne movsb
- pop di
- call nicnam ; Make name nice for printing.
- mov al,0
- ret
- gtfn5: mov ah,prstr ; Don't print if a server.
- mov dx,offset erms32 ; Say no matches.
- int dos
- mov al,0FFH ; Failure return code.
- ret
-
- savfcb: push di
- mov si,offset fcb ; Data is here.
- mov di,offset cpfcb ; Copy to here.
- mov cx,37
- repne movsb
- pop di
- ret
-
- rstfcb: push di
- mov si,offset cpfcb ; Data is here.
- mov di,offset fcb ; Copy to here.
- mov cx,37
- repne movsb
- pop di
- ret
-
- nicnam: mov al,CR ; Add CRLF before print names
- stosb
- mov al,LF
- stosb
- mov cx,8
- mov si,offset fcb+1
- repne movsb ; Get the file name.
- mov al,' '
- stosb
- mov cx,3
- repne movsb
- mov al,tab
- stosb
- mov al,' '
- stosb
- mov ah,openf
- mov dx,offset fcb
- int dos
- mov bx,offset fcb+18 ; Get hi order word of file size.
- mov ax,[bx]
- mov dx,ax
- mov bx,offset fcb+16 ; Get lo order word.
- mov ax,[bx]
- call nout2x ; Get it in decimal.
- mov al,tab
- stosb
- mov al,' '
- stosb
- mov ah,0
- mov si,offset fcb+20
- lodsb
- mov fildat+1,al
- lodsb
- mov fildat,al ; Date field of fcb.
- mov cl,5
- shr fildat+1,cl
- and fildat,1
- mov cl,3
- shl fildat,cl
- mov al,fildat
- or al,fildat+1 ; Get the month field.
- cmp al,9
- jg nic0
- push ax
- mov al,' '
- stosb
- pop ax
- nic0: call nout2 ; Make it decimal.
- mov al,'-'
- stosb
- mov si,offset fcb+20 ; Get date field.
- lodsb
- and al,1FH
- cmp al,10 ; Only one digit?
- jge nic0x
- push ax
- mov al,'0' ; Make it two digits.
- stosb
- pop ax
- nic0x: call nout2 ; Make it decimal.
- mov al,'-'
- stosb
- mov si,offset fcb+21 ; Get the year field.
- lodsb
- shr al,1
- add al,80
- cmp al,100 ; At the year 2000 or above?
- js nic0y ; No, just go on.
- sub al,100 ; Go back to two digits.
- nic0y: cmp al,10 ; Only one digit?
- jge nic0z
- push ax
- mov al,'0' ; Make it two digits.
- stosb
- pop ax
- nic0z: call nout2 ; Make it decimal.
- mov al,tab
- stosb
- mov si,offset fcb+23 ; Get time field of fcb.
- lodsb
- mov cl,3 ; Get the hour field.
- shr al,cl
- mov tmp,'a' ; For AM.
- cmp al,12 ; Before noon?
- jl nic1
- mov tmp,'p' ; It's PM.
- je nic1 ; Don't change "12" to "0".
- sub al,12 ; Use a 12 hr. clock.
- nic1: cmp al,0 ; Just after midnight?
- jne nic1x
- add al,12 ; Make it "12" instead of "0".
- nic1x: cmp al,10 ; Pad with a space?
- jge nic2
- push ax
- mov al,' '
- stosb
- pop ax
- nic2: call nout2 ; Make it decimal.
- mov al,':' ; Separate hours and minutes.
- stosb
- mov si,offset fcb+23 ; Get the minutes field.
- lodsb
- and al,07
- mov cl,3
- shl al,cl
- mov ah,al
- mov si,offset fcb+22
- lodsb
- mov cl,5
- shr al,cl
- or al,ah
- mov ah,0
- cmp al,10 ; Would there be a leading zero.
- jge nic3
- push ax
- mov al,'0'
- stosb
- pop ax
- nic3: call nout2 ; Make it decimal.
- mov al,tmp ; Add 'a' (AM) or 'p' (PM).
- stosb
- mov ah,closf
- mov dx,offset fcb
- int dos
- ret
-
- ; For now, just print it.
- dumpit: mov al,'$'
- stosb
- mov ah,prstr
- mov dx,offset nambuf
- int dos
- mov di,offset nambuf
- ret
-
- ; push to an inferior command parser
- dopush proc near
- cmp dosnum,0 ; < 2.0 ?
- jne dopus1 ; no, go on
- mov dx,offset erms34
- mov ah,prstr
- int dos
- jmp rskp
- dopus1: mov ah,cmcfm
- call comnd
- jmp r
- mov si,offset cmspbuf ; name of parser
- push si ; save beginning
- sub cx,cx ; initial length
- dopus2: lodsb
- inc cx ; count this
- or al,al ; at end?
- jnz dopus2 ; no, keep going
- pop si ; restore cmd
- dec cx ; this is incremented one over
- jmp short crun ; go run it
- dopush endp
-
- ; crun - run an arbitrary program. Enter with si/address of whole
- ; cmd, cx/length of cmd.
- CRUN proc near
- push cx ; save length of cmd
- mov ax,ds
- mov es,ax ; address dest segment
- mov di,offset nambuf
- rep movsb ; copy command so we can mess with it
- pop cx
- mov si,offset nambuf ; point to command
- jmp short run3 ; and join run code
- CRUN ENDP
-
- RUN PROC NEAR
- cmp dosnum,0
- jne run1
- mov ah,prstr
- mov dx,offset erms34 ; Complain.
- int dos
- jmp rskp
- run1: mov ah,cmtxt ; Get program name.
- mov bx,offset nambuf ; Convenient buffer.
- mov dx,offset filmsg ; In case user wants help.
- call comnd
- nop
- nop
- nop
- cmp ah,0
- jne run2
- mov ah,prstr
- mov dx,offset erms35
- int dos
- jmp rskp
- run2: mov cl,ah
- mov ch,0
- mov si,offset nambuf
-
- ; alternate entry if cmd is already known. Source cmd ptr in si
- ; is trashed.
- run3: mov bx,cx
- mov byte ptr [si+bx],cr ; end string with a cr for dos.
- mov di,offset cmdnam
- mov ax,ds
- mov es,ax
- run4: lodsb
- cmp al,' '
- jne run5
- dec si ; back up over space
- jmp short run6 ; and exit loop
- run5: stosb
- loop run4
- run6: mov byte ptr [di],0 ; terminate string
- dec si ; point back a byte into argument
- mov [si],cl ; put length of argument here
- mov exearg+2,si ; pointer to argument string
- mov exearg+4,ds ; segment of same
- inc si ; pass length over
- mov al,1 ; scan leading separators
- mov di,offset exefcb ; parse into this fcb
- mov ah,prsfcb
- int dos ; go parse the fcb
- mov al,1 ; scan leading separators
- mov di,offset exefcb2 ; second fcb to fill
- mov ah,prsfcb
- int dos ; parse the fcb
- mov es,psp ; point to psp again
- mov ax,es:[env] ; get environment ptr
- mov exearg,ax ; put into argument block
- mov bx,offset stk + 15 ; end of pgm
- mov cl,4
- shr bx,cl ; compute # of paragraphs in last segment
- mov ax,seg stack ; end of kermit
- sub ax,psp ; minus beginning...
- add bx,ax ; # of paragraphs occupied
- mov ah,setblk
- int dos
- jc run7 ; nope...
- mov ax,ds
- mov es,ax ; put es segment back
- mov ax,offset cmdnam ; point to cmd name again
- call spath ; look for it
- jc run8 ; not found, go complain
- mov dx,ax ; point to command name
- mov al,0 ; load and execute...
- mov ah,exec
- mov bx,offset exearg ; and to arguments
- mov ssave,sp ; save stack ptr
- int dos ; go run the program
- mov ax,seg datas
- mov ds,ax ; reset data segment
- mov ax,seg stack
- mov ss,ax ; and stack segment
- mov sp,ssave ; restore stack ptr
- mov ah,setdma
- mov dx,offset buff
- pushf ; save flags
- int dos ; restore dma address!!
- popf ; recover flags
- jc run8 ; error, handle.
- jmp rskp ; ok, return
- run7: mov ah,prstr
- mov dx,offset erms36
- int dos
- jmp rskp
- run8: mov ah,prstr
- mov dx,offset erms37
- int dos
- jmp rskp
- RUN 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
-
- intbrk: cmp flags.debug,1 ; Debug mode?
- je intb1 ; Yes, then don't ignore the ^C.
- push ax
- push ds
- mov ax,seg datas
- 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
- intb1: jmp in3ad ; Original break interrupt address.
-
- ; Set the maximum data packet size. [21b]
-
- PACKLEN PROC NEAR
- mov ah,trans.spsiz ; Maximum send packet size.
- sub ah,4 ; Size minus control info.
- sub ah,trans.chklen ; And minus checksum chars.
- sub ah,2 ; Leave room at end: 2 for possible #X.
- cmp trans.ebquot,'N' ; Doing 8-bit quoting?
- je pack0 ; Nope so we've got our size.
- cmp trans.ebquot,'Y'
- je pack0 ; Not doing it in this case either.
- sub ah,1 ; Another 1 for 8th-bit quoting.
- pack0: mov trans.maxdat,ah ; Save max length for data field.
- ret
- PACKLEN ENDP
-
- NOUT2 PROC NEAR
- push ax
- push dx
- mov temp,10 ; Divide quotient by 10.
- cwd ; Convert word to doubleword.
- div temp ; AX <-- Quo, DX <-- Rem.
- cmp ax,0 ; Are we done?
- jz nout0 ; Yes.
- call nout2 ; If not, then recurse.
- nout0: add dl,'0' ; Make it printable.
- mov temp,ax
- mov al,dl
- stosb
- mov ax,temp
- pop dx
- pop ax
- ret ; We're done. [21c]
- NOUT2 ENDP
-
- NOUT2X PROC NEAR
- push ax
- push dx
- push cx
- mov temp,10 ; Divide quotient by 10.
- div temp ; AX <-- Quo, DX <-- Rem.
- mov cx,dx ; Remember the remainder.
- cmp ax,0 ; Are we done?
- jz nout0x ; Yes.
- mov dx,0
- call nout2 ; If not, then recurse.
- nout0x: add cl,'0' ; Make it printable.
- mov temp,ax
- mov al,cl
- stosb
- mov ax,temp
- pop cx
- pop dx
- pop ax
- ret ; We're done. [21c]
- NOUT2X ENDP
-
- SPATH proc near
- ; 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.
- push es
- mov bx,ds
- mov es,bx ; address data segment
- mov bx,ax ; convenient place to keep this
- mov si,ax
- mov di,offset tfile ; place to copy to
- mov dl,0 ; no '\' seen yet
- mov ah,swchar ; get switch character
- spath1: lodsb
- stosb
- cmp al,ah ; contain path characters?
- jne spath2 ; no, keep going
- 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 embedded, keep going
- pop es
- mov ax,offset tfile ; else...
- call isfile
- mov ax,offset tfile ; point to right thing...
- ret ; let isfile decide and return
- ; no path, keep going
- spath3: mov si,offset pthbuf ; path definition
- cmp byte ptr [si],0 ; empty path?
- jne spath4 ; no, keep going
- mov ah,gcd ; get current dir
- mov dl,0 ; for default drive
- mov si,offset defpth+1 ; place to put it
- int dos
- mov si,offset defpth ; point to the path
- spath4: cmp byte ptr [si],0 ; null, exit loop
- je spath9
- mov di,offset tfile ; place to put name
- spath5: lodsb ; get a byte
- 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 over it
- jmp short spath7 ; and break loop
- spath6: stosb ; else stick in dest string
- jmp spath5 ; and continue
- spath7: push si ; save this ptr
- mov si,bx ; this is user's file name
- mov al,swchar ; get switch character.
- cmp byte ptr [di-1],al ; does it end with switch char?
- je spath8 ; yes, don't put one in
- stosb ; else add one
- spath8: lodsb
- stosb
- or al,al
- jnz spath8 ; copy rest of name
- pop si ; restore pos in path def
- mov ax,offset tfile
- call isfile ; is it a file?
- jc spath4 ; no, keep looking
- mov ax,offset tfile
- pop es
- ret ; return success (carry off)
- spath9: pop es ; restore this
- mov ax,bx ; not found yet, get original path
- call isfile ; does it exist?
- ret ; return whatever isfile says.
- spath endp
-
-
- isfile proc near
- ; returns carry off if the file pointed to by ax exists
- mov dx,ax ; copy ptr
- mov al,0 ; don't change anything
- mov ah,chmod
- int dos
- ret ; dos sets carry
- isfile 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