DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦d07d4e4d5⟧ TextFile

    Length: 68193 (0x10a61)
    Types: TextFile
    Names: »mssker.asm«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦71044c191⟧ »EurOpenD3/misc/kermit.ms-2.32.tar.Z« 
        └─⟦31f2d420d⟧ 
            └─⟦this⟧ »mssker.asm« 

TextFile

        NAME    mssker
; File MSSKER.ASM
; Edit history:
; Last edit 3 Dec 1988
; 21 Nov 1988 Version 2.32
; 12 Nov 1988 Modify disk space arithmetic for DOS 4 # sectors > 64K.
; 16 Sept 1988 Use active escape character in quickhelp display.
; 28 July 1988 Add ASK command.
; 1 July 1988 Version 2.31
; 7 June 1988 Support implied DO macro on failure to find initial keyword
; 15 May 1988 Add support for :label, let serial port run (nearly)
;  continuously to aid script commands, add global status kstatus.
; 20 April 1988 Add summary Help from Christine Gianone (Columbia Univ).
; 8 April 1988 Move Take disk file i/o buffers into Macro definition buffer.
; 3 April 1988 Store global words lclsusp, lclrest, lclexit for system
;  dependent routines to be called (if non-null) when Kermit suspends while
;  going to DOS, returns from suspension, and when finally exiting to DOS.
;  Tnx to suggestion by Rich Blanford.
; 29 March 1988 Add attribute Deny none (40h) to readonly file opens,
;  thanks to Paul Fox of AT&T.
; 27 Feb 1988 Add Wait command. Revise exit flag handling for stdin being
;  a file rather than a device (keyboard). [jrd]
; 23 Feb 1988 Add Mail command. [jrd]
; 17 Jan 1988 Do serial port reset just before requesting Kermit command
;  line rather than at end of each send/receive operation; this permits faster
;  responses to script driven requests on our server mode. [jrd]
; 7 Jan 1988 Add es: seg override in parts of gcmdl procedure. [jrd]
; 1 Jan 1988 version 2.30

;****************************** 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.31, 1 July 1988
;       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, 2.31)
;       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  dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
        public  takrd, takadr, taklev, filtst, drives, maxtry, imxtry
        public  lclsusp, lclrest, lclexit, cwdir, kstatus
        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
        db      'Copyright (C) Trustees of Columbia University 1982, 1988.'
        db      cr,lf,'$'
hlpmsg  db      'Type ? or HELP for help',cr,lf,'$'
crlf    db      cr,lf,'$'
ermes1  db      cr,lf,'?More parameters are needed$'
ermes2  db      cr,lf,'?Unable to initialize memory$'
ermes3  db      cr,lf,'?Command canceled$'
ermes4  db      cr,lf,'?Unable to change directory$'
erms30  db      cr,lf,'?Passed maximum nesting level for TAKE command$'
erms31  db      cr,lf,'?Cannot find Take-file: $'
erms34  db      cr,lf,'This program requires DOS 2.0 or above$'
erms37  db      cr,lf,'?Unable to execute program$'
badnam  db      cr,lf,'?Protected or no such file(s)$'
filmsg  db      ' Filename$'
pthmsg  db      ' Name of new working directory and/or disk$'
runmsg  db      ' program name and command line$'
tophlp  db      cr,lf
        db      '  Ask (get console input to variable)'
        db      '  Mail     (file to host Mailer)'
        db      cr,lf
        db      '  Bye      (logout remote server)    '
        db      '  Output text     (for scripts)'
        db      cr,lf
        db      '  C or Connect  (become a terminal)  '
        db      '  Pause [seconds] (for scripts)'
        db      cr,lf
        db      '  Clear    (clear serial port buffer)'
        db      '  Pop   (exit current Take file or macro)'
        db      cr,lf
        db      '  Close    (logging file)            '
        db      '  Push     (go to DOS, keep Kermit)'
        db      cr,lf
        db      '  Comment  (text is ignored)         '
        db      '  Quit     (leave Kermit)'
        db      cr,lf
        db      '  CWD or CD  (change dir &/or disk)  '
        db      '  R or Receive  (opt local filename)'
        db      cr,lf
        db      '  Define/Assign   (a command macro)  '
        db      '  Reinput  (script Input, reread buffer)'
        db      cr,lf
        db      '  Delete   (a file)                  '
        db      '  Remote   (prefix for commands)'
        db      cr,lf
        db      '  Directory                          '
        db      '  Run      (a program)'
        db      cr,lf
        db      '  Disable  (selected server commands)'
        db      '  S or Send (local file   new name)'
        db      cr,lf
        db      '  Do       (a macro)                 '
        db      '  Server [timeout] (become a server)'
        db      cr,lf
        db      '  Echo text (show line on screen)    '
        db      '  Set      (most things)'
        db      cr,lf
        db      '  Enable   (selected server commands)'
        db      '  Show     (most things)'
        db      cr,lf
        db      '  EXIT     (leave Kermit)            '
        db      '  Space    (free on current disk)'
        db      cr,lf
        db      '  Finish   (to remote server)        '
        db      '  Status   (show main conditions)'
        db      cr,lf
        db      '  Get      (remote file opt new name)'
        db      '  Stay     (in Kermit after startup)'
        db      cr,lf
        db      '  Goto    (label, Take file or Macro)'
        db      '  Stop   (exit all Take files & macros)'
        db      cr,lf
        db      '  Hangup   (drop DTR, hang up phone) '
        db      '  Take     (do a command file)'
        db      cr,lf
        db      '  If [not] <condition> <command>     '
        db      '  Transmit filespec [prompt] (raw upload)'
        db      cr,lf
        db      '  I or Input [timeout] text (scripts)'
        db      '  Type     (a file)'
        db      cr,lf
        db      '  Log (Packet, Session, Transaction) '
        db      '  Wait [timeout] on modem \cd \cts \dsr'
        db      cr,lf
        db      '  Logout   (remote server)           '
        db      '  Version  (show Kermit''s id)'
        db      cr,lf
        db      '  Type HELP for an Introduction, use "?" within commands for'
        db      ' specific help.$'

qckhlp  db cr,lf
        db '                          Introduction to Kermit',cr,lf
        db 'o A Kermit-MS command is a line of words separated by spaces and'
        db ' ending with',cr,lf,'  a carriage return <the Enter key>.'
        db '  Example: SET SPEED 2400<Enter>',cr,lf
        db 'o Most words can be abbreviated and can be completed by pressing'
        db ' the Esc key.',cr,lf
        db '  Example: SET SPE 24<Enter>  or even  SET SPE<Esc> 24<Esc>'
        db '<Enter>',cr,lf
        db 'o Help (detailed, specific): press the "?" key where a word would'
        db ' appear.',cr,lf
        db 'o Edit lines using the BackSpace key to delete characters,'
        db ' Control-W to delete',cr,lf
        db '  words, and Control-U to delete the line.  Control-C cancels the'
        db ' command.',cr,lf
        db 'o Frequently used Kermit-MS commands:',cr,lf
        db '  EXIT           Leave the Kermit program. QUIT does the same'
        db ' thing.',cr,lf
        db '  SET            PORT, PARITY, SPEED, TERMINAL and many other'
        db ' parameters.',cr,lf
        db '  SHOW or STATUS Display groups of important parameters.'
        db ' SHOW ? for categories.',cr,lf,lf
        db '  CONNECT        Establish a terminal connection to a remote'
        db ' system or a modem.',cr,lf
        db '  Control-$'
qckhlp1 db ' C    (Control $'
qckhlp2 db '  followed by "C")  Exit CONNECT mode.',cr,lf,lf
        db '  SEND filename  Send the file(s) to the remote system (to its'
        db ' Kermit).',cr,lf
        db '  GET filename   Ask the remote Kermit server to send the file(s)'
        db ' to us.',cr,lf
        db '  RECEIVE        Like GET but remote end chooses files to be sent'
        db ' here.',cr,lf
        db '  FINISH         Shut down remote Kermit but stay logged into'
        db ' remote system.',cr,lf
        db '  BYE            FINISH and logout of remote system and exit'
        db ' local Kermit.',cr,lf
        db 'o Common startup sequence: SET SPEED 9600, CONNECT, login, start'
        db ' remote Kermit,',cr,lf
        db '  put it into Server mode, escape back with Control-$'
qckhlp3 db ' C, transfer'
        db ' files with',cr,lf
        db '  SEND x.txt, GET b.txt, BYE. Read more about it in the Kermit-MS'
        db ' Users Manual.'
        db cr,lf
        db 'Press the "?" key for a summary of Kermit commands: $'

comtab  db      55                      ; COMND tables
        mkeyw   'Ask',ask
        mkeyw   'Assign',assign
        mkeyw   'Bye',bye
        mkeyw   'C',telnet
        mkeyw   'CD',cwdir
        mkeyw   'Clear',scclr
        mkeyw   'Close',clscpt
        mkeyw   'Comment',comnt
        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   'goto',goto
        mkeyw   'H',help
        mkeyw   'Hangup',dtrlow
        mkeyw   'Help',help
        mkeyw   'If',ifcmd
        mkeyw   'I',scinp
        mkeyw   'Input',scinp
        mkeyw   'Log',setcpt
        mkeyw   'Logout',logout
        mkeyw   'Mail',mail
        mkeyw   'Output',scout
        mkeyw   'Pause',scpau
        mkeyw   'Pop',takclos
        mkeyw   'Push',dopush
        mkeyw   'Quit',exit
        mkeyw   'R',read
        mkeyw   'Receive',read
        mkeyw   'Reinput',screinp
        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   'Stop',takeqit
        mkeyw   'Take',take
        mkeyw   'Transmit',scxmit
        mkeyw   'Type',typec
        mkeyw   'Version',prvers
        mkeyw   'Wait',scwait
        mkeyw   ':',comnt

shotab  db      12                      ; SHOW keyword
        mkeyw   'Communications',shcom
        mkeyw   'File',shfile
        mkeyw   'Key',shokey
        mkeyw   'Logging',shlog
        mkeyw   'Macros',shomac
        mkeyw   'Modem',shomodem
        mkeyw   'Protocol',shpro
        mkeyw   'Scripts',shscpt
        mkeyw   'Server',shserv
        mkeyw   'Statistics',shosta
        mkeyw   'Terminal',shterm
        mkeyw   'Translation',shorx

lclsusp dw      0               ; address of routine to call when going to DOS
lclrest dw      0               ; address of routine to call when returning
lclexit dw      0               ; address of routine to call when exiting
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
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      80h dup (?)     ; temp space for file names and comments
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$'
spcmsg  db      ' bytes available on disk',cr,lf,0
spcmsg2 db      ' Drive not ready',cr,lf,'$'
errlev  db      0               ; DOS errorlevel to be returned
kstatus dw      0               ; command execution status (0 = success)
temp    dw      0
datas   ends                    ; End data segment

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
        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: 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
        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    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
        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
        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
        int     dos
        ret
take1:  mov     dx,offset tmpbuf        ; work buffer
        mov     tmpbuf,0
        mov     bx,offset filmsg        ; Help in case user types "?"
        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
        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
        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
        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
        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
        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.
        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
        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
        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
        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
        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.
        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
        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
        int     dos
        mov     ah,conout
        pop     dx
        push    dx
        int     dos
        mov     ah,prstr
        mov     dx,offset qckhlp2       ; more help text
        int     dos
        pop     dx                      ; recover current escape char
        mov     ah,conout
        int     dos
        mov     ah,prstr
        mov     dx,offset qckhlp3       ; end of help message
        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
        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
        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.
        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
        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
        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
        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
        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
        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