home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis3.arc / MSSKER.ASM < prev    next >
Assembly Source File  |  1990-01-17  |  61KB  |  1,933 lines

  1.     NAME    mssker
  2. ; File MSSKER.ASM
  3.     include mssdef.h
  4. ; Edit history:
  5. ; Last edit 16 Jan 1990
  6. ; 16 June Add SHELL= support for PUSH as suggested by Mike Brown, Purdue
  7. ;  University Computing Center.
  8. ;****************************** Version 3.00 ***************************** 
  9. ; KERMIT, Celtic for "free" 
  10. ;
  11. ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
  12. ; used by permission.
  13. ;
  14. ;    Kermit-MS Program Version 3.00, 16 Jan 1990 
  15. ;    Kermit-MS Program Version 2.32, 11 Dec 1988 
  16. ;    Kermit-MS Program Version 2.31, 1 July 1988
  17. ;       Kermit-MS Program Version 2.30, 1 Jan 1988
  18. ;    Kermit-MS Program Version 2.29, 26 May 1986, plus later revisions.
  19. ;       Kermit-MS Program Version 2.27, December 6,1984
  20. ;       Based on the Columbia University KERMIT Protocol.
  21. ;       Copyright (C) 1982,1983,1984,1985,1986,1987,1988, 1989, 1990
  22. ;                 Trustees of Columbia University
  23. ;
  24. ;       Daphne Tzoar, Jeff Damens
  25. ;       Columbia University Center for Computing Activities
  26. ;       612 West 115th Street
  27. ;       New York, NY  10025
  28. ;
  29. ;    Joe R. Doupnik (version 2.29, 2.30, 2.31, 2.32, 3.00)
  30. ;    Dept of EE, and CASS
  31. ;    Utah State University
  32. ;    Logan, Utah 84322
  33. ;    jrd@cc.usu.Bitnet
  34. ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
  35. ; Vace Kundakci, Bernie Eiben and many many others for their help and
  36. ; contributions.
  37.  
  38.     public    dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
  39.     public    takrd, takadr, taklev, filtst, maxtry, dskspace, thsep
  40.     public    lclsusp, lclrest, lclexit, cwdir, kstatus, verident, cdsr
  41.     public    spath, patched
  42.  
  43. env    equ    2CH            ; environment address in psp
  44. cline    equ    80H            ; offset in psp of command line
  45.  
  46. STACK    SEGMENT    PARA STACK 'STACK'    ; our stack
  47.     dw    200 dup(0)        ; initialize stack to all zeros
  48. msfinal    label    word            ; top of stack
  49. STACK    ENDS
  50.  
  51. data   segment public 'data'
  52.     extrn    buff:byte, comand:byte, flags:byte, trans:byte,    prmptr:word
  53.     extrn    machnam:byte, decbuf:byte, rstate:byte, sstate:byte
  54.  
  55. verident label    byte
  56.     verdef
  57.     db    '$'
  58. copyright db    cr,lf
  59.     db    'Copyright (C) Trustees of Columbia University 1982, 1990.'
  60.     db    cr,lf,'$'
  61. hlpmsg    db     cr,lf,'Type ? or HELP for help',cr,lf,'$'
  62. crlf    db      cr,lf,'$'
  63. ermes1    db    cr,lf,'?More parameters are needed$'
  64. ermes2    db    cr,lf,'?Unable to initialize memory$'
  65. ermes3  db      cr,lf,'?Command canceled$'
  66. ermes4    db    '?Unable to change directory',0            ; asciiz
  67. ermes5    db    cr,lf,'?Unable to complete initialization process$'
  68. ermes6    db    cr,lf,'Ignoring patch file MSKERMIT.PCH. '
  69.     db    'Version number mismatch.',cr,lf,'$'
  70. ermes7    db    cr,lf,'Patch file MSKERMIT.PCH was not found',cr,lf,'$'
  71. ermes8    db    cr,lf,'Fatal error in MSKERMIT.PCH! Please remove PATCH '
  72.     db    'command.',cr,lf,'$'
  73. erms30    db    cr,lf,'?Passed maximum nesting level for TAKE command$'
  74. erms31    db    cr,lf,'?Cannot find Take-file: $'
  75. erms34    db    cr,lf,'This program requires DOS 2.0 or above$'
  76. erms37    db    cr,lf,'?Unable to execute program$'
  77. badnam    db    cr,lf,'?No such file(s)$'
  78. filmsg    db    ' Filename$'
  79. dskmsg    db    ' disk drive letter or Return$'
  80. pthmsg    db    ' Name of new working directory and/or disk$'
  81. runmsg    db    ' program name and command line$'
  82. tophlp    db    cr,lf
  83.     db    '  Ask, Askq (read keybd to variable) '
  84.     db    '  Output text     (for scripts)'
  85.     db    cr,lf
  86.     db    '  Bye      (logout remote server)    '
  87.     db    '  Pause [seconds] (for scripts)'
  88.     db    cr,lf
  89.     db      '  C or Connect  (become a terminal)  '
  90.     db    '  Pop   (exit current Take file or macro)'
  91.     db    cr,lf
  92.     db    '  Clear    (clear serial port buffer)'
  93.     db    '  Push     (go to DOS, keep Kermit)'
  94.     db    cr,lf
  95.     db    '  Close    (logging file)            '
  96.         db      '  Quit     (leave Kermit)'
  97.     db    cr,lf
  98.     db    '  CWD or CD  (change dir &/or disk)  '
  99.         db      '  R or Receive  (opt local filename)'
  100.     db    cr,lf
  101.     db    '  Define/Assign   (a command macro)  '
  102.     db    '  Reinput  (script Input, reread buffer)'
  103.     db    cr,lf
  104.     db    '  Delete   (a file)                  '
  105.     db    '  Remote   (prefix for commands)'
  106.     db    cr,lf
  107.     db    '  Directory                          '
  108.     db    '  Replay   (file through term emulator)'
  109.     db    cr,lf
  110.     db    '  Disable  (selected server commands)'
  111.     db    '  Run      (a program)'
  112.     db    cr,lf
  113.     db    '  Do       (a macro)                 '
  114.         db      '  S or Send  local file   new name'
  115.     db    cr,lf
  116.     db    '  Echo text (show line on screen)    '
  117.     db    '  Server [timeout] (become a server)'
  118.     db    cr,lf
  119.     db    '  Enable   (selected server commands)'
  120.         db      '  Set      (most things)'
  121.     db    cr,lf         
  122.     db      '  EXIT     (leave Kermit)            '
  123.     db    '  Show     (most things)'
  124.     db    cr,lf
  125.     db    '  Finish   (to remote server)        '
  126.     db    '  Space    (free on current disk)'
  127.     db    cr,lf
  128.     db    '  Get      (remote file opt new name)'
  129.         db      '  Status   (show main conditions)'
  130.     db    cr,lf
  131.     db    '  Goto    (label, Take file or Macro)'
  132.     db    '  Stop     (exit all Take files & macros)'
  133.     db    cr,lf
  134.     db    '  Hangup   (drop DTR, hang up phone) '
  135.     db    '  Take     (do a command file)'
  136.     db    cr,lf
  137.     db    '  If [not] <condition> <command>     '
  138.     db    '  Transmit filespec [prompt] (raw upload)'
  139.     db    cr,lf
  140.     db    '  I or Input [timeout] text (scripts)'
  141.     db    '  Type     (a file)'
  142.     db    cr,lf
  143.     db    '  Log (Packet, Session, Transaction) '
  144.     db    '  Wait [timeout] on modem \cd \cts \dsr'
  145.     db    cr,lf
  146.     db    '  Logout   (remote server)           '
  147.     db    '  Write    <to log file> <object type>'
  148.     db    cr,lf
  149.     db    '  Mail     (file to host Mailer)'
  150.     db    cr,lf
  151.     db    '  Type HELP for an Introduction, use "?" within commands for'
  152.     db    ' specific help.$'
  153. ;;;    db    '  Load filespec (file translate tbl) '
  154. ;;;    db    '  Version  (show Kermit''s id)'
  155.  
  156.  
  157. qckhlp    db cr,lf
  158.     db '                    Introduction to MS-DOS Kermit',cr,lf
  159.     db 'o An MS-Kermit command is a line of words separated by spaces and'
  160.     db ' ending with',cr,lf,'  a carriage return <the Enter key>.'
  161.     db '  Example: SET SPEED 2400<Enter>',cr,lf
  162.     db 'o Most words can be abbreviated and can be completed by pressing'
  163.     db ' the Esc key.',cr,lf
  164.     db '  Example: SET SPE 24<Enter>  or even  SET SPE<Esc> 24<Esc>'
  165.     db '<Enter>',cr,lf
  166.     db 'o Help (detailed, specific): press the "?" key where a word would'
  167.     db ' appear.',cr,lf
  168.     db 'o Edit lines using the Backspace key to delete characters,'
  169.     db ' Control-W to delete',cr,lf
  170.     db '  words, and Control-U to delete the line.  Control-C cancels the'
  171.     db ' command.',cr,lf
  172.     db 'o Frequently used MS-Kermit commands:',cr,lf
  173.     db '  EXIT           Leave the Kermit program. QUIT does the same'
  174.     db ' thing.',cr,lf
  175.     db '  SET            PORT, PARITY, SPEED, TERMINAL and many other'
  176.     db ' parameters.',cr,lf
  177.     db '  SHOW or STATUS Display groups of important parameters.'
  178.     db ' SHOW ? for categories.',cr,lf,lf
  179.     db '  CONNECT        Establish a terminal connection to a remote'
  180.     db ' system or a modem.',cr,lf
  181.     db '  Control-$'
  182. qckhlp1    db ' C    (Control-$'
  183. qckhlp2    db '  followed by "C")  Return to MS-Kermit> prompt.',cr,lf,lf
  184.     db '  SEND filename  Send the file(s) to Kermit on the other'
  185.     db ' computer).',cr,lf
  186.     db '  RECEIVE        Receive file(s), SEND them from Kermit on the'
  187.     db ' other computer.',cr,lf
  188.     db '  GET filename   Ask the remote Kermit server to send the file(s)'
  189.     db ' to us.',cr,lf
  190.     db '  FINISH         Shut down remote Kermit but stay logged into'
  191.     db ' remote system.',cr,lf
  192.     db '  BYE            FINISH and logout of remote system and exit'
  193.     db ' local Kermit.',cr,lf
  194.     db 'o Common startup sequence: SET SPEED 9600, CONNECT, login, start'
  195.     db ' remote Kermit,',cr,lf
  196.     db '  put it into Server mode, escape back with Control-$'
  197. qckhlp3    db ' C, transfer'
  198.     db ' files with',cr,lf
  199.     db '  SEND x.txt, GET b.txt, BYE. Read more about it in "Using MS-DOS'
  200.     db ' Kermit".'
  201.     db cr,lf
  202.     db 'Press the "?" key for a summary of Kermit commands, or space for'
  203.         db ' prompt.$'
  204.  
  205. comtab  db    59            ; COMND tables
  206.     mkeyw    'Ask',ask
  207.     mkeyw    'Askq',askq
  208.     mkeyw    'Assign',assign
  209.     mkeyw    'Bye',bye
  210.     mkeyw    'C',telnet
  211.     mkeyw    'CD',cwdir
  212.     mkeyw    'Clear',scclr
  213.     mkeyw    'Close',clscpt
  214.     mkeyw    'Comment',comnt
  215.     mkeyw    'Connect',telnet
  216.     mkeyw    'CWD',cwdir
  217.     mkeyw    'Define',dodef
  218.     mkeyw    'Delete',delete
  219.     mkeyw    'Directory',direct
  220.     mkeyw    'Disable',srvdsa
  221.     mkeyw    'Do',docom
  222.     mkeyw    'Echo',scecho
  223.     mkeyw    'Enable',srvena
  224.     mkeyw    'Exit',exit
  225.     mkeyw    'Finish',finish
  226.     mkeyw    'Get',get
  227.     mkeyw    'goto',goto
  228.     mkeyw    'H',help
  229.     mkeyw    'Hangup',dtrlow
  230.     mkeyw    'Help',help
  231.     mkeyw    'If',ifcmd
  232.     mkeyw    'I',scinp
  233.     mkeyw    'Input',scinp
  234. ;;;    mkeyw    'Load',load
  235.     mkeyw    'Log',setcpt
  236.     mkeyw    'Logout',logout
  237.     mkeyw    'Mail',mail
  238.     mkeyw    'Output',scout
  239.     mkeyw    'Pause',scpau
  240.     mkeyw    'Pop',takclos
  241.     mkeyw    'Push',dopush
  242.     mkeyw    'Quit',exit
  243.     mkeyw    'R',read
  244.     mkeyw    'Receive',read
  245.     mkeyw    'Reinput',screinp
  246.     mkeyw    'Remote',remote
  247.     mkeyw    'Replay',replay
  248.     mkeyw    'Run',run
  249.     mkeyw    'S',send
  250.     mkeyw    'Send',send
  251.     mkeyw    'Server',server
  252.     mkeyw    'Set',setcom
  253.     mkeyw    'Show',showcmd
  254.     mkeyw    'Space',chkdsk
  255.     mkeyw    'Status',status
  256.     mkeyw    'Stay',stay
  257.     mkeyw    'Stop',takeqit
  258.     mkeyw    'Take',take
  259.     mkeyw    'Transmit',scxmit
  260.     mkeyw    'Type',typec
  261.     mkeyw    'Version',prvers
  262.     mkeyw    'Wait',scwait
  263.     mkeyw    'Write',write
  264.     mkeyw    ':',comnt        ; script labels, do not react
  265.     mkeyw    'Patch',patch
  266.  
  267. shotab    db    13            ; SHOW keyword
  268.     mkeyw    'Communications',shcom
  269.     mkeyw    'File',shfile
  270.     mkeyw    'Key',shokey
  271.     mkeyw    'Logging',shlog
  272.     mkeyw    'Macros',shomac
  273.     mkeyw    'Memory',shmem
  274.     mkeyw    'Modem',shomodem
  275.     mkeyw    'Protocol',shpro
  276.     mkeyw    'Scripts',shscpt
  277.     mkeyw    'Server',shserv
  278.     mkeyw    'Statistics',shosta
  279.     mkeyw    'Terminal',shterm
  280.     mkeyw    'Translation',shorx
  281.                     ; Kermit initing from Environment
  282. nulprmpt db    0            ; null prompt
  283. initab    db    2            ; Environment phrase dispatch table
  284.     mkeyw    'INPUT-buffer-length',setinpbuf ; Script INPUT buffer length
  285.     mkeyw    'Rollback',setrollb    ; number of Terminal rollback screens
  286. patched    db    1        ; 1 = enable patching; 0 = disable or done
  287.  
  288.     even
  289. lclsusp    dw    0        ; address of routine to call when going to DOS
  290. lclrest    dw    0        ; address of routine to call when returning
  291. lclexit    dw    0        ; address of routine to call when exiting
  292. ssave    dw    0        ; Original SS when doing Command.com
  293. in3ad    dw    0,0        ; Original break interrupt addresses
  294. ceadr    dd    0        ; DOS Critical Error interrupt address
  295. orgcbrk    db    0        ; original Control-Break Check state
  296. psp    dw    0        ; segment of Program Segment Prefix
  297. exearg    dw    0        ; segment addr of environment (filled in below)
  298.     dd    0        ; ptr to cmd line (filled in below)
  299.     dw    5ch,0,6ch,0    ; our def fcb's; segment filled in later
  300. dosnum    dw    0        ; dos version number, major=low, minor=high
  301. curdsk    db    0        ; Current disk
  302. origd    db    0        ; Original disk
  303. orgdir    db    64 dup (0)    ; original directory on original disk
  304. taklev    db    0        ; Take levels
  305. takadr    dw    takstr-(size takinfo) ; Pointer into structure
  306. takstr    db    (size takinfo) * maxtak dup(?)
  307. filtst    filest    <>        ; file structure for procedure isfile
  308. maxtry    db    defmxtry    ; Retry limit for data packet send/rcv
  309. ininm2    db    'MSKERMIT.INI',0 ; init file name for 2.0
  310. ptchnam    db    'MSKERMIT.PCH',0 ; patch file name
  311. delcmd    db    ' del ',0    ; delete command
  312. dircmd    db    ' dir ',0    ; directory command
  313. typcmd    db    ' type ',0    ; type command
  314. kerenv    db    'KERMIT=',0,0    ; Kermit= environment variable, + 2 nulls
  315. pthnam    db    'PATH='        ; Path environment variable
  316. pthlen    equ    $-pthnam    ;  length of that string
  317. pthadr    dw    0        ; offset of PATH= string
  318.  
  319. slashc    db    ' /c '        ; slashc Must directly preceed tmpbuf
  320. tmpbuf    db    128 dup (0)    ; temp space for file names and comments
  321. cmspnam    db    'COMSPEC='    ; Environment variable
  322. cmsplen    equ    $-cmspnam
  323. cmspbuf    db    '\command.com',30 dup (0) ; default name plus additional space
  324. shellnam db    'SHELL='    ; Environment variable
  325. shellen    equ    $-shellnam
  326. shellbuf db    40 dup (0)    ; buffer for name
  327. eexit    db    cr,'exit',cr
  328. leexit    equ    $-eexit
  329. mfmsg    db    '?Not enough memory to run Kermit$'
  330. mf7msg    db    '?Attempted to allocate a corrupted memory area$'
  331. spcmsg    db    ' bytes available on drive '
  332. spcmsg1    db    ' :',cr,lf,0
  333. spcmsg2    db    cr,lf,' Drive '
  334. spcmsg3    db    ' : is not ready',0
  335. errlev    db    0        ; DOS errorlevel to be returned
  336. kstatus    dw    0        ; command execution status (0 = success)
  337. thsep    db    0        ; thousands separator
  338. totpar    dw    0
  339. temp    dw    0
  340. data   ends
  341.  
  342. code    segment    public 'code' 
  343.     extrn    logout:near, mail:near, load:near
  344.     extrn    bye:near, telnet:near, finish:near, comnd:near, prompt:near
  345.     extrn    read:near, remote:near, send:near, status:near, get:near
  346.     extrn    serrst:near, setcom:near, dtrlow:near
  347.     extrn    clscpi:near, clscpt:near, scpini:near, setrollb:near
  348.     extrn    dodef:near, setcpt:near, docom:near, shomodem:near
  349.     extrn    server:near, lclini:near, shokey:near, shomac:near, shosta:near
  350.     extrn    strlen:near, strcpy:near, shserv:near, initibm:near
  351.     extrn    strcat:near, prtasz:near, shorx:near, lnout:near, lnouts:near
  352.     extrn    scout:near,scinp:near,scpau:near,scecho:near,scclr:near
  353.     extrn    scxmit:near, scwait:near, srvdsa:near, srvena:near
  354.     extrn    shcom:near, shlog:near, shpro:near, shterm:near, shscpt:near
  355.     extrn    shfile:near, takopen:near, takclos:near, ask:near, askq:near
  356.     extrn    assign:near, goto:near, screinp:near, ifcmd:near, write:near
  357.     extrn    setinpbuf:near, shmem:near, replay:near, atoi:near
  358.     extrn    katoi:near
  359.  
  360.         assume  cs:code, ds:data, ss:stack, es:nothing
  361.  
  362. START    PROC    FAR
  363.     mov    ax,data            ; initialize DS
  364.         mov    ds,ax
  365.     mov    psp,es            ; remember psp address
  366.  
  367.     mov    ah,dosver        ; get DOS version number (word)
  368.     int    dos
  369.     xchg    ah,al            ; major version to ah
  370.     mov    dosnum,ax        ; remember dos version
  371.     cmp    ax,200h            ; earlier than DOS 2.0?
  372.     jge    start1            ; ge = no
  373.     mov    ah,prstr
  374.     mov    dx,offset erms34    ; complain
  375.     int    dos
  376.     push    psp            ; set up exit for DOS 1
  377.     xor    ax,ax            ; and the IP
  378.     push    ax            ; make return addr of psp:0 for DOS 1
  379.     ret                ; and return far to exit now
  380. start1:    mov    ah,setdma        ; set disk transfer address
  381.     mov    dx,offset buff
  382.     int    dos
  383.  
  384.     call    setint            ; ^C, DOS critical error interrupts
  385.     mov    ah,gcurdsk        ; get current disk
  386.     int    dos
  387.     inc    al            ; make 1 == A (not zero)
  388.     mov    curdsk,al
  389.     mov    origd,al        ; remember original disk we started on
  390.     mov    si,offset orgdir     ; place for directory path w/o drive code
  391.     add    al,'A'-1        ; make al alphabetic disk drive again
  392.     mov    [si],al            ; put it into original path descriptor
  393.     inc    si
  394.     mov    byte ptr [si],':'    ; add drive specifier too
  395.     inc    si
  396.     mov    byte ptr [si],'\'    ; add root indicator as well
  397.     inc    si
  398.     mov    ah,gcd            ; get current directory (path really)
  399.     xor    dl,dl            ; use current drive
  400.     int    dos
  401.     call    getpath            ; get the path from the environment
  402.     call    gettsep            ; get thousands separator
  403.     mov    ah,gswitch
  404.     xor    al,al            ; pick up switch character
  405.     int    dos
  406.     mov    slashc+1,dl
  407.     and    maxtry,3fh        ; limit # packet retries
  408.     call    getcsp            ; get comspec from environment
  409.     call    getssp            ; get shellspec from environment
  410.     call    memini            ; initialize our memory usage
  411.     call    getparm            ; read "KERMIT=" Environment line
  412.     jc    start1b            ; c = fatal error
  413.     xor    cl,cl            ; counter, starts at 0
  414. start1a:mov    bx,offset kerenv+6    ; append "<digit>="  to "KERMIT"
  415.     mov    [bx],cl            ; binary digit
  416.     inc    cl
  417.     add    byte ptr [bx],'0'    ; to ascii
  418.     mov    byte ptr [bx+1],'='    ; append equals sign
  419.     call    getparm            ; read "KERMITn=" Environment line
  420.     jc    start1b            ; c = fatal error
  421.     cmp    cl,9            ; done all digits?
  422.     jbe    start1a            ; be = no
  423.                     ;
  424.     call    scpini            ; initialize script routines
  425.     jc    start1b            ; c = fatal error
  426.     call    lclini            ; do local initialization
  427.     cmp    flags.extflg,0        ; exit now?
  428.     je    start2            ; e = no
  429. start1b:mov    ah,prstr        ; announce our premature exit
  430.     mov    dx,offset ermes5    ; can't complete initialization
  431.     int    dos
  432.     jmp    krmend            ; quit immediately
  433. start2:    mov    comand.cmrprs,offset krmend ; address to go to on reparse
  434.     mov    comand.cmostp,sp    ; save for reparse too
  435.     call    gcmdlin            ; read command line
  436.     cmp    taklev,0        ; in a Take file?
  437.     jne    start3            ; ne = yes, skip help msg
  438.     mov    ah,prstr
  439.     mov    dx,offset machnam    ; display machine name
  440.     int    dos
  441.         mov    dx,offset verident    ; display version header
  442.         int    dos
  443.     mov    dx,offset copyright    ; display copyright notice
  444.     int    dos
  445.     mov    dx,offset hlpmsg
  446.     int    dos
  447. start3:    mov    flags.chrset,437    ; find default global char set
  448.     cmp    dosnum,0300h+30        ; DOS version 3.30 or higher?
  449.     jb    start4            ; b = no, no Code Pages
  450.     mov    ax,6601h        ; get global Code Page
  451.     int    dos            ; bx=active Code Page, dx=boot CP
  452.     mov    flags.chrset,bx        ; setup default SET FILE CHAR SET
  453. start4:    call    serrst            ; reset serial port (if active)
  454.     call    initibm            ; define IBM macro
  455.     call    rdinit            ; read kermit init file
  456.  
  457.  ; This is the main KERMIT loop.  It prompts for and gets the users commands
  458.  
  459. kermit:    mov    ax,ds
  460.     mov    es,ax            ; convenient safety measure
  461.     cmp    taklev,0        ; keep port open between script cmds
  462.     jne    kermt1            ; ne = in Take or Macro
  463.     call    serrst            ; reset serial port for CTTY DOS use
  464. kermt1:    mov    dx,prmptr        ; get prompt
  465.     call    prompt              ; prompt user, set reparse address
  466.     mov    flags.cxzflg,0        ; reset each time
  467.     and    flags.remflg,not dserver ; turn off server mode bit
  468.     mov    dx,offset comtab
  469.     mov    bx,offset tophlp
  470.     cmp    flags.extflg,0        ; exit flag set?
  471.     jne    krmend            ; ne = yes, jump to KRMEND
  472.     mov    comand.cmcr,1        ; allow bare CR's
  473.         mov    ah,cmkey
  474.     mov    comand.impdo,1        ; allow implied "DO macro"
  475.     call    comnd
  476.     jc    kermt3            ; c = failure
  477.     mov    comand.impdo,0        ; only on initial keyword, not here
  478.     mov    comand.cmcr,0        ; no more bare CR's
  479.     call    bx                  ; call the routine returned in BX
  480.     jc    kermt3            ; c = failure
  481.     cmp    flags.extflg,0        ; exit flag set?
  482.     jne    krmend            ; ne = yes, jump to KRMEND
  483.     jmp    short kermt5        ; do idle loop cleanup
  484.  
  485. kermt3:    cmp    flags.cxzflg,'C'    ; got here via Control-C?
  486.     jne    kermt7            ; ne = no
  487.     cmp    flags.extflg,0        ; exit flag set?
  488.     jne    kermt5            ; ne = yes, skip msg, do cleanup
  489.     mov    dx,offset ermes3    ; say command not executed
  490.     mov    ah,prstr        ; print    the error message in dx
  491.     int    dos
  492. kermt5:    cmp    flags.cxzflg,'C'    ; user Control-C abort?
  493.     jne    kermt7            ; ne = no, do normal operations
  494.     cmp    taklev,0        ; in a Take file?
  495.     je    kermt7            ; e = no        
  496.     call    takclos            ; close take file, release buffer
  497.     jmp    kermt5            ; close any other take files
  498. kermt7:    cmp    flags.extflg,0        ; exit flag set?
  499.     jne    krmend            ; ne = yes, Exit now
  500.     jmp    kermit            ; get next command
  501.  
  502. krmend: call    serrst            ; just in case the port wasn't reset
  503.     test    flags.capflg,0FFH    ; Logging active?
  504.     jz    krmend2            ; z = no
  505.     call    clscpi            ; close log files
  506. krmend2:cmp    lclexit,0        ; sys dependent routines want service?
  507.     je    krmend3            ; e = no
  508.     mov    bx,lclexit        ; addr of sys dependent exit routine
  509.     call    bx            ; call it
  510. krmend3:mov    dl,origd        ; original disk drive
  511.     dec    dl            ; want A == 0
  512.     mov    ah,seldsk        ; reset original disk just in case
  513.     int    dos
  514.     mov    dx,offset orgdir    ; restore original directory
  515.     mov    ah,chdir
  516.     int    dos
  517.     mov    dx,offset in3ad        ; restore Control-C interrupt vector
  518.     mov    al,23H            ; interrupt 23H
  519.     mov    ah,25H            ; set interrupt vector
  520.     int    dos            ; ah, that's better
  521.     mov    dx,offset ceadr        ; DOS's Critical Error handler
  522.     mov    al,24h            ; interrupt 24h
  523.     mov    ah,25h            ; do replacement (put it back)
  524.     int    dos
  525.     call    cbrestore        ; restore state of Control-Break Chk
  526.     mov    ah,4cH            ; terminate process
  527.     mov    al,errlev        ; return error level
  528.     int    dos
  529.     ret
  530. START    ENDP
  531.  
  532. ; This is the 'EXIT' command.  It leaves KERMIT and returns to DOS
  533.  
  534. EXIT    PROC    NEAR
  535.     mov    ah,cmeol
  536.     call    comnd            ; get a confirm
  537.     jc    exit1            ; c = failure
  538.     mov    flags.extflg,1        ; set the exit-Kermit flag
  539. exit1:    ret
  540. EXIT    ENDP
  541.  
  542. ; TAKE commands    from a file, and allow a path name
  543. TAKE    PROC    NEAR
  544.     mov    kstatus,0        ; global status, success
  545.     cmp    taklev,maxtak        ; at the limit?
  546.     jl    take1            ; l = no
  547.     mov    ah,prstr
  548.     mov    dx,offset erms30    ; complain
  549.     int    dos
  550.     stc                ; failure
  551.     ret
  552. take1:    mov    dx,offset tmpbuf    ; work buffer
  553.     mov    tmpbuf,0
  554.     mov    bx,offset filmsg    ; Help in case user types "?"
  555.     mov    ah,cmword        ; get file name
  556.     call    comnd
  557.     jc    take1a            ; c = failure
  558.     mov    ah,cmeol
  559.     call    comnd
  560.     jc    take1a            ; c = failure
  561.     mov    ax,offset tmpbuf    ; point to name again
  562.     cmp    tmpbuf,0        ; empty filespec?
  563.     jne    take2            ; ne = no
  564.     mov    ah,prstr
  565.     mov    dx,offset ermes1    ; say more parameters needed
  566.     int    dos
  567.     stc
  568. take1a:    ret
  569.                     ; TAKE2: enter with ax=filename ptr
  570. TAKE2:    call    spath            ; is it around?
  571.     jc    take3            ; no, go complain
  572.     mov    dx,ax            ; point to name from spath
  573.     mov    ah,open2        ; open file
  574.     xor    al,al            ; 0 = open for reading
  575.     cmp    dosnum,300h        ; at or above DOS 3?
  576.     jb    take2a            ; b = no, so no shared access
  577.     or    al,40h            ; open for reading, deny none
  578. take2a:    int    dos
  579.     jnc    take4            ; nc = opened ok, keep going
  580.     mov    ax,dx            ; recover filename pointer
  581. take3:    push    ax
  582.     mov    ah,prstr
  583.     mov    dx,offset erms31
  584.     int    dos
  585.     pop    ax
  586.     mov    dx,ax            ; asciiz file name
  587.     call    prtasz            ; display it
  588.     mov    kstatus,8        ; global status
  589.     clc                ; we've done all error displays
  590.     ret
  591.                     ; TAKE4: enter with ax=filename ptr
  592. TAKE4:    call    takopen            ; open take buffer in macro space
  593.     jc    take6            ; c = failure
  594.     push    bx
  595.     mov    bx,takadr        ; get current frame ptr
  596.     mov    [bx].takhnd,ax        ; save file handle
  597.     mov    [bx].taktyp,0feh     ; mark as 2.0 file handle
  598.     pop    bx
  599.     cmp    flags.takflg,0        ; echoing Take files?
  600.     je    take5            ; e = no
  601.     mov    ah,prstr
  602.     mov    dx,offset crlf
  603.     int    dos
  604. take5:    call    takrd            ; get a buffer full of data
  605.     clc                ; success
  606. take6:    ret
  607. TAKE    ENDP
  608.  
  609. TAKRD    PROC    NEAR
  610.     push    ax
  611.     push    bx
  612.     push    cx    
  613.     push    dx
  614.     mov    bx,takadr
  615.     cmp    [bx].taktyp,0feh    ; get type of take (file?)
  616.     jne    takrd1            ; ne = no, do not read from disk
  617.     mov    cx,tbufsiz-1        ; # of bytes to read
  618.     mov    ax,[bx].takbuf        ; segment of Take buffer
  619.     push    bx            ; save frame address
  620.     mov    bx,[bx].takhnd        ; file handle is stored here
  621.     push    ds            ; save ds
  622.     mov    ds,ax            ; set ds to Take buffer segment
  623.     mov    dx,1            ; ds:dx = buffer, skip count byte
  624.     mov    ah,readf2        ; read file
  625.     int    dos
  626.     pop    ds
  627.     pop    bx            ; restore frame address
  628.     jnc    takrd2            ; nc = successful read
  629. takrd1:    xor    ax,ax            ; error, say zero bytes read
  630. takrd2:    mov    [bx].takcnt,ax        ; number of bytes read
  631.     mov    [bx].takptr,1        ; offset of first new character
  632.     pop    dx
  633.     pop    cx
  634.     pop    bx
  635.     pop    ax
  636.     ret
  637. TAKRD    ENDP
  638.  
  639. ; TAKE-QUIT  (STOP)  Exit all Take files immediately but gracefully
  640.  
  641. TAKEQIT PROC    NEAR
  642.     mov    ah,cmeol
  643.     call    comnd
  644.     jnc    takqit1            ; nc = success
  645.     ret
  646. takqit1:xor    ch,ch
  647.     mov    cl,taklev        ; number of Take levels active
  648.     jcxz    takqit2            ; z = none
  649.     call    takclos            ; close current Take file
  650.     jmp    short takqit1        ; repeat until all are closed
  651. takqit2:clc                ; success
  652.     ret
  653. TAKEQIT    ENDP
  654.  
  655. ; put mskermit.ini onto take stack if it exists.  Just like
  656. ; the take command, except it doesn't read a filename
  657.  
  658. rdinit    proc    near            ; read kermit init file..
  659.     mov    ax,offset ininm2    ; default name to try
  660.     cmp    decbuf,0        ; alternate init file given?
  661.     je    rdini1            ; ne = no
  662.     mov    ax,offset decbuf    ; yes, use it
  663.     call    take2            ; let Take do error msgs
  664.     clc                ; force success
  665.     ret
  666. rdini1:    call    spath            ; is it around?
  667.     jc    rdini2            ; no, ignore file
  668.     mov    dx,ax            ; point to name from spath
  669.     mov    ah,open2        ; open file
  670.     xor    al,al            ; 0 = open for reading
  671.     cmp    dosnum,300h        ; at or above DOS 3?
  672.     jb    rdini1a            ; b = no, so no shared access
  673.     or    al,40h            ; open for reading, deny none
  674. rdini1a:int    dos
  675.     jc    rdini2            ; c = no ini file found, ignore
  676.     call    take4            ; use TAKE command to complete work
  677.     clc                ; ignore errors
  678. rdini2:    ret
  679. rdinit    endp
  680.  
  681.  
  682.  
  683.  
  684.  
  685. ; Patcher.  Patch file, MSKERMIT.PCH has the following format:
  686.  
  687. ; 300 \Xxxxx    ; optional comment.  300 for V3.00.  For xxxx, see below
  688. ; ; optional comment lines may appear anywhere after the 1st
  689. ; ; xxxx in 1st line total paragraphs in memory image.  Use \X if hex.
  690. ; DS:xxxx xx xx        ; optional comment.  DS (or CS) are case insensitive
  691. ; CS:xxxx xx xx xx    ; locations must be 4 hex chars, contents must be 2
  692.  
  693. ; CS & DS lines may be intermixed.
  694. ; This mechanism expects file msscmd.obj to be linked first.
  695.  
  696. PATCH    proc
  697.     mov    ah,cmeol    ; confirm please
  698.     call    comnd
  699.     jc    ptch2        ; c = no confirm
  700.     xor    ax,ax
  701.     xchg    al,patched    ; clear and test patched
  702.     test    al,al
  703.     jnz    ptch2        ; z = disabled or done
  704.     xchg    ah,flags.takflg    ; clear take flag -- don't echo patches
  705.     mov    byte ptr temp,ah; but save it
  706.     call    ptchr
  707.     mov    al,byte ptr temp; restore take flag
  708.     mov    flags.takflg,al
  709.     jnc    ptch2        ; nc = OK
  710.     mov    dx,offset ermes8; Fatal error
  711.     mov    ah,prstr
  712.     int    dos
  713.     jmp    krmend        ; force exit
  714.  
  715. ptchr:    mov    ax,offset ptchnam ; point to name of patch file
  716.     call    rdini1        ; let rdini try to find it & do take stuff
  717.     jnc    ptch15        ; nc = file mskermit.pch was found
  718.     mov    dx,offset ermes7 ; say file not found
  719.     mov    ah,prstr
  720.     int    dos
  721.     clc
  722.     ret
  723. ptch15:    mov    al,taklev    ; remember initial take level
  724.     mov    tmpbuf,al    ; when it changes, it's EOF & we're done
  725.     mov    comand.cmcr,1    ; bare cr's ok, to prevent prserr @EOF
  726.     mov    dx,offset tmpbuf+1 ; where to read
  727.     call    ptchrl        ; read 1st 'word'
  728.     jc    ptch0        ; c = trubble
  729.     mov    si,offset tmpbuf+1
  730.     call    atoi        ; convert version string to integer
  731.     jc    ptch0        ; c = bad number, or none
  732.     cmp    ax,version    ; does it match this version?
  733.     je    ptch3        ; e = yes
  734. ptch0:    mov    al,tmpbuf    ; if take level has changed,
  735.     xor    al,taklev    ;  we're already out of patch file
  736.     jnz    ptch1        ; nz = change in take level
  737.     call    takclos        ; close patch file
  738. ptch1:    mov    dx,offset ermes6
  739.     mov    ah,prstr    ; issue warning msg
  740.     int    dos
  741.     clc
  742. ptch2:    ret
  743.  
  744. ptch3:    mov    dx,offset tmpbuf+1
  745.     call    ptchrw        ; read 2nd "word", 1st line
  746.     jc    ptch0        ; c = NG
  747.     mov    si,offset tmpbuf+1
  748.     call    katoi        ; convert 2nd "magic number"
  749.     jc    ptch0        ; c = NG
  750.     cmp    ax,totpar    ; is it the total paragraphs memini computed?
  751.     jne    ptch0        ; ne = no
  752.  
  753. ptch4:    mov    dx,offset tmpbuf+1
  754.     call    ptchrl        ; read CS:xxxx or DS:xxxx
  755.     jc    ptch2
  756.     mov    si,offset tmpbuf
  757.     cld
  758.     lodsb            ; initial take level
  759.     xor    al,taklev    ; if unequal, it's EOF (clears carry)
  760.     jnz    ptch2        ; nz = EOF, we're done
  761.     test    ah,ah        ; empty (possibly ;comment) line?
  762.     jz    ptch4        ; z = yes; ignore it
  763.     mov    tmpbuf+64,al    ; clear replacement byte count
  764.     cmp    ah,7        ; were 7 chars read?
  765.     jne    ptch5        ; ne = no
  766.     and    word ptr[si],not 2020h ; convert to upper case
  767.     lodsb            ; get the 'C' or 'D'
  768.     cmp    word ptr[si],':S' ; S:, actually
  769.     je    ptch6        ; e = ok
  770. ptch5:    stc            ; error exit
  771.     ret
  772.  
  773. ptch6:    mov    bx,cs        ; assume CS
  774.     cmp    al,'C'
  775.     je    ptch7        ; e = good guess
  776.     cmp    al,'D'
  777.     jne    ptch5        ; ne = neither CS or DS
  778.     mov    bx,ds        ; modify assumption
  779.  
  780. ptch7:    mov    word ptr[si],'X\' ; put '\X' in front of hex for katoi
  781.     call    katoi        ; convert location
  782.     jc    ptch2        ; c= NG
  783.     push    bx        ; save seg being patched
  784.     push    ax        ; save location being patched
  785. ptch8:    mov    dx,offset tmpbuf+4
  786.     call    ptchrw        ; read replacement byte follwing '\X'
  787.     jnc    ptch10        ; nc = OK
  788. ptch9:    pop    ax        ; clean stack & error return
  789.     pop    ax
  790.     stc
  791.     ret
  792.  
  793. ptch10:    test    ah,ah        ; EOL?
  794.     jnz    ptch11        ; nz = no
  795.     mov    si,offset tmpbuf+64
  796.     cld
  797.     lodsb            ; replacement byte count
  798.     cmp    ah,al        ; were there any?
  799.     je    ptch9        ; e = no
  800.     mov    cx,ax        ; replacement count
  801.     pop    di        ; patch location
  802.     pop    es        ; patch segment
  803.     rep    movsb        ; make patch
  804.     jmp    ptch4        ; loop to read next line
  805.  
  806. ptch11:    cmp    ah,2        ; 2 chars req'd for replacement byte
  807.     jne    ptch9        ; ne = bad
  808.     mov    si,offset tmpbuf+2 ; convert it
  809.     call    katoi
  810.     jc    ptch9        ; c = bad number or none
  811.     mov    si,offset tmpbuf+64    ; --> replacement byte counted string
  812.     inc    byte ptr[si]    ; bump count
  813.     mov    bl,[si]
  814.     xor    bh,bh
  815.     mov    byte ptr[si+bx],al ; stash replacement byte
  816.     jmp    ptch8        ; loop for next byte
  817.  
  818. ptchrl:    mov    bp,dx
  819.     mov    dx,offset crlf
  820.     call    prompt
  821.     mov    dx,bp
  822. ptchrw:    mov    ah,cmword
  823.     mov    comand.cmper,1    ; prohibit substitution variable expansion
  824.     xor    bx,bx        ; 'help' ptr
  825.     call    comnd
  826.     ret
  827. PATCH    endp    
  828.  
  829. ; Get command line into a Take macro buffer. Allow "-f filspec" to override
  830. ; normal mskermit.ini initialization filespec, allow command "stay" to
  831. ; suppress automatic exit to DOS at end of command line execution. [jrd]
  832.  
  833. gcmdlin    proc    near
  834.     mov    word ptr decbuf,0    ; storage for new init filename
  835.     push    es
  836.     cld
  837.     mov    es,psp            ; address psp
  838.     xor    ch,ch
  839.     mov    cl,es:byte ptr[cline]    ; length of cmd line from DOS
  840.     jcxz    gcmdl1            ; z = empty line
  841.     mov    si,cline+1        ; point to actual line
  842. gcmdl0:    cmp    byte ptr es:[si],' '    ; skip over leading whitespace
  843.     ja    gcmdl2            ; a = non-whitespace
  844.     inc    si
  845.     loop    gcmdl0            ; fall through on all whitespace
  846. gcmdl1:    jmp    gcmdl14            ; common exit jump point
  847. gcmdl2:    inc    cx            ; include DOS's c/r
  848.     call    takopen            ; open take buffer in macro space
  849.     mov    bx,takadr
  850.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  851.     mov    [bx].takcnt,0        ; length of text
  852.     mov    es,[bx].takbuf        ; segment of buffer, from takopen
  853.     mov    di,1            ; skip count byte
  854.     push    psp
  855.     pop    ds            ; DS = PSP
  856. gcmdl3:    cmp    cx,0            ; anything left?
  857.     jle    gcmdl10            ; le = no
  858.     lodsb                ; get a byte from PSP's command line
  859.     dec    cx            ; one less char in input string
  860.     cmp    al,','            ; comma?
  861.     jne    gcmdl4            ; no, keep going
  862.     mov    al,cr            ; convert to cr
  863.     jmp    short gcmdl9        ; store it
  864. gcmdl4:    cmp    al,'-'            ; starting a flag?
  865.     jne    gcmdl9            ; ne = no
  866.     mov    ah,[si]            ; get flag letter
  867.     or    ah,20h            ; convert to lower case
  868.     cmp    ah,'f'            ; 'f' for init file replacement?
  869.     jne    gcmdl9            ; ne = no
  870.     inc    si            ; accept flag letter
  871.     dec    cx
  872. gcmdl5:    cmp    cx,0            ; anything to read?
  873.     jle    gcmdl10            ; le = exhausted supply
  874.     lodsb                ; get filespec char from psp
  875.     dec    cx            ; one less char in source buffer
  876.     cmp    al,' '            ; in whitespace?
  877.     jbe    gcmdl5            ; be = yes, scan it off
  878.     dec    si            ; backup to real text
  879.     inc    cx
  880.                     ; copy filspec to buffer decbuf
  881.     push    es            ; save current destination pointer
  882.     push    di            ;  which is in es:di (Take buffer)
  883.     mov    di,data            ; set es:di to regular decbuf
  884.     mov    es,di
  885.     lea    di,decbuf        ; where filespec part goes
  886.     mov    word ptr es:[di],0    ; plant safety terminator
  887. gcmdl6:    lodsb                ; get filespec char
  888.     dec    cx            ; one less available
  889.     cmp    al,' '            ; in printables?
  890.     jbe    gcmdl7            ; be = no, all done
  891.     cmp    al,','            ; comma command separator?
  892.     je    gcmdl7            ; e = yes, all done
  893.     stosb                ; store filespec char
  894.     cmp    cx,0            ; any chars left?
  895.     jg    short gcmdl6        ; g = yes
  896. gcmdl7:    mov    byte ptr es:[di],0    ; end filespec on a null
  897.     pop    di            ; recover destination pointer es:di
  898.     pop    es
  899. gcmdl8:    cmp    cx,0            ; strip trailing whitespace
  900.     jle    gcmdl10            ; le = nothing left
  901.     lodsb
  902.     dec    cx
  903.     cmp    al,' '            ; white space?
  904.     jbe    gcmdl8            ; be = yes, strip it
  905.     cmp    al,','            ; at next command?
  906.     je    gcmdl10            ; e = yes, skip our own comma
  907.     dec    si            ; back up to reread the char
  908.     inc    cx
  909.     jmp    gcmdl3            ; read more command text
  910.                     ; end of flag analysis
  911. gcmdl9:    stosb                ; deposit most recent char
  912. gcmdl10:cmp    cx,0            ; anything left to read?
  913.     jg    gcmdl3            ; g = yes, loop
  914.                     ;
  915.     mov    ax,data            ; restore segment registers
  916.     mov    ds,ax
  917.     mov    si,[bx].takbuf        ; get segment of Take buffer
  918.     mov    es,si
  919.     mov    si,1            ; skip count byte
  920.     mov    cx,di            ; current end pointer, (save di)
  921.     sub    cx,si            ; current ptr minus start offset
  922.     mov    [bx].takcnt,cx        ; chars in buffer so far
  923.     mov    es:byte ptr [0],cl    ; store count byte
  924.     cmp    cx,0
  925.     jg    gcmdl11            ; material at hand
  926.     call    takclos            ; empty take file
  927.     jmp    gcmdl14            ; finish up
  928.                     ; scan for command "stay"
  929. gcmdl11:mov    al,es:[si]        ; get a byte, cx and si are set above
  930.     inc    si
  931.     dec    cx
  932.     cmp    al,' '            ; separator?
  933.     jbe    gcmdl12            ; be = yes, keep looking
  934.     cmp    al,','             ; comma separator?
  935.     je    gcmdl12            ; e = yes
  936.     mov    ah,al            ; get first byte
  937.     mov    al,es:[si]        ; second byte after separator
  938.     inc    si
  939.     dec    cx
  940.     or    ax,2020h        ; convert to lower case
  941.     cmp    ax,'st'            ; first two letters of stay
  942.     jne    gcmdl12            ; ne = no match
  943.     mov    ax,es:[si]        ; next two letters (stay vs status)
  944.     add    si,2
  945.     sub    cx,2
  946.     or    ax,2020h        ; convert to lower case
  947.     cmp    ax,'ya'            ; same as our pattern?
  948.     jne    gcmdl12            ; ne = no match
  949.                     ; check for separator or end of macro
  950.     cmp    cx,0            ; at end of macro?
  951.     jle    gcmdl13            ; yes, consider current match correct
  952.     cmp    byte ptr es:[si],' '    ; next char is a separator?
  953.     jbe    gcmdl13            ; be = yes, found correct match
  954.     cmp    byte ptr es:[si],','    ; or comma separator?
  955.     je    gcmdl13            ; e = yes
  956. gcmdl12:cmp    cx,0            ; done yet? ("stay" not found)
  957.     jg    gcmdl11            ; g = not yet, look some more
  958.     mov    si,offset eexit        ; append command "exit"
  959.     mov    cx,leexit        ; length of string "exit"
  960.     add    [bx].takcnt,cx
  961.     rep    movsb            ; copy it into the Take buffer
  962. gcmdl13:mov    [bx].takptr,1        ; init buffer ptr
  963.     mov    cx,[bx].takcnt        ; count of bytes in buffer
  964.     mov    es:byte ptr [0],cl    ; count of bytes in Take buffer
  965. gcmdl14:pop    es
  966.     ret
  967. gcmdlin    endp
  968.  
  969. ; Enter with ax pointing to file name.  Searches path for given file,
  970. ; returns with ax pointing to whole name, or carry set if file can't be found.
  971. SPATH    proc    near
  972.     call    isfile            ; does it exist as it is?
  973.     jc    spath0            ; c = no, prepend path elements
  974.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  975.     jnz    spath0            ; nz = yes, not desired file
  976.     clc
  977.     ret
  978. spath0:    push    es            ; save es around work
  979.     push    bx
  980.     push    si
  981.     push    di
  982.     mov    bx,ax            ; save filename pointer in bx
  983.     mov    si,ax
  984.     xor    dl,dl            ; no '\' seen yet
  985.     cld
  986. spath1:    lodsb
  987.     cmp    al,2fh            ; contains fwd slash path characters?
  988.     je    spath1a
  989.     cmp    al,5ch            ; or backslash?
  990.     jne    spath2            ; no, keep going
  991. spath1a:mov    dl,1            ; remember we've seen them
  992. spath2:    or    al,al
  993.     jnz    spath1            ; copy name in
  994.     or    dl,dl            ; look at flag
  995.     jz    spath3            ; no path, keep looking
  996.     jmp    short spath9        ; embedded path, fail
  997.  
  998. spath3:    mov    si,pthadr        ; offset of PATH= string in environment
  999.     mov    es,psp
  1000.     mov    di,es:word ptr[env]    ; pick up environment segment
  1001.     mov    es,di
  1002. spath4:    cmp    byte ptr es:[si],0    ; end of PATH= string?
  1003.     je    spath9            ; e = yes, exit loop
  1004.     mov    di,offset decbuf+64    ; place to put name
  1005. spath5:    mov    al,byte ptr es:[si]    ; get a byte from environment string
  1006.     inc    si
  1007.     cmp    al,';'            ; end of this part?
  1008.     je    spath7            ; yes, break loop
  1009.     or    al,al            ; maybe end of string?
  1010.     jnz    spath6            ; nz = no, keep going
  1011.     dec    si            ; back up to null for later rereading
  1012.     jmp    short spath7        ; and break loop
  1013. spath6:    mov    byte ptr [di],al    ; else stick in dest string
  1014.     inc    di
  1015.     jmp    spath5            ; and continue
  1016. spath7:    push    si            ; save this ptr
  1017.     mov    si,bx            ; this is user's file name
  1018.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  1019.     je    spath8            ; yes, don't put one in
  1020.     cmp    byte ptr [di-1],5ch    ; how about this one?
  1021.     je    spath8            ; yes, don't put it in
  1022.     mov    byte ptr [di],5ch    ; else add one
  1023.     inc    di
  1024. spath8:    lodsb                ; get filename character
  1025.     mov    byte ptr [di],al    ; copy filename char to output buffer
  1026.     inc    di
  1027.     or    al,al            ; end of string?
  1028.     jnz    spath8            ; nz = no, copy rest of name
  1029.     pop    si            ; restore postion in path string
  1030.     mov    ax,offset decbuf+64
  1031.     call    isfile            ; is it a file?
  1032.     jc    spath4            ; c = no, keep looking
  1033.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1034.     jnz    spath4            ; nz = yes
  1035.     pop    di
  1036.     pop    si
  1037.     pop    bx
  1038.     pop    es
  1039.     clc
  1040.     ret                ; return success (carry clear)
  1041. spath9:    mov    ax,bx            ; restore original filename pointer
  1042.     pop    di            ; restore regs
  1043.     pop    si
  1044.     pop    bx
  1045.     pop    es
  1046.     stc                ; no file found
  1047.     ret
  1048. spath    endp
  1049.  
  1050. ; Put offset of PATH= string in pthadr
  1051. getpath    proc    near
  1052.     push    bx
  1053.     push    cx
  1054.     push    dx
  1055.     mov    bx,offset pthnam    ; thing    to find
  1056.     mov    cx,pthlen        ; length of it
  1057.     mov    pthadr,0        ; init offset to zero
  1058.     call    getenv            ; get environment value
  1059.     mov    pthadr,dx
  1060.     pop    dx
  1061.     pop    cx
  1062.     pop    bx
  1063.     ret
  1064. getpath    endp
  1065.  
  1066. ; getcsp: copy COMSPEC= environment string into cmspbuf
  1067. ; getssp: copy SHELL=   environment string into shellbuf
  1068. getcsp    proc    near
  1069.     mov    bx,offset cmspnam    ; find COMSPEC=
  1070.     mov    cx,cmsplen        ; it's length
  1071.     mov    di,offset cmspbuf    ; where to store string
  1072.     jmp    short getccom        ; do common worker
  1073.  
  1074. getssp:    mov    bx,offset shellnam    ; find SHELL=
  1075.     mov    cx,shellen        ; it's length
  1076.     mov    di,offset shellbuf    ; where to store string
  1077.     
  1078. getccom:push    es
  1079.     call    getenv            ; get environment offset into dx
  1080.     mov    si,dx            ; address of COMSPEC= string
  1081.     mov    es,psp
  1082.     mov    bx,es:word ptr[env]    ; pick up environment address
  1083.     mov    es,bx
  1084.     push    ds            ; save ds
  1085.     push    ds            ; make ds point to environment seg
  1086.     push    es            ; make es point to data segment
  1087.     pop    ds
  1088.     pop    es
  1089.     cld
  1090. getcs1:    lodsb                ; get a byte from environment
  1091.     cmp    al,' '            ; space or less?
  1092.     jg    getcs2            ; g = no, keep copying
  1093.     xor    al,al            ; terminate string on spaces etc
  1094. getcs2:    stosb                ; store it in destination
  1095.     or    al,al            ; at end of string yet?
  1096.     jnz    getcs1            ; nz = no, keep copying
  1097.     pop    ds            ; recover ds
  1098.     pop    es
  1099.     ret
  1100. getcsp    endp
  1101.  
  1102. ; Get Kermit parameters from the Environment. Parameters are commands like
  1103. ; regular commands except they do not appear in the SET main table and are
  1104. ; separated from one another by semicolons. They appear after KERMIT=.
  1105. ; Do not allow Take/Macros to be created by any of these commands.
  1106. ; On fatal error exits with carry set and flags.extflg = 1
  1107. getparm    proc    near
  1108.     push    ax
  1109.     push    bx
  1110.     push    cx
  1111.     push    dx
  1112.     push    si
  1113.     push    di
  1114.     push    es
  1115.     mov    es,psp            ; segment of our PSP
  1116.     mov    ax,es:word ptr[env]    ; pick up environment address
  1117.     mov    es,ax
  1118.     mov    bx,offset kerenv    ; Environment word to find, asciiz
  1119.     mov    dx,bx
  1120.     call    strlen            ; length of its string to cx
  1121.     call    getenv            ; return dx = offset in environment
  1122.     jnc    getpar1            ; nc = success
  1123.     jmp    getpar9            ; c = not found
  1124. getpar1:PUSH    DS            ; save regular DS
  1125.     push    dx            ; push Environment offset, then seg
  1126.     push    es
  1127.     call    takopen            ; open Take buffer in macro space
  1128.     jnc    getpar2            ; nc = success
  1129.     mov    flags.extflg,1        ; say exit now
  1130.     pop    es            ; clean stack
  1131.     pop    dx
  1132.     pop    ds
  1133.     jmp    getparx            ; exit with fatal error
  1134.  
  1135. getpar2:mov    bx,takadr        ; bx = Take data structure
  1136.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  1137.     mov    [bx].takcnt,0        ; length of text
  1138.     mov    es,[bx].takbuf        ; ES = segment of buffer, from takopen
  1139.     mov    di,1            ; skip count byte field for es:di
  1140.     pop    DS            ; pop Environment segment (was in ES)
  1141.     pop    si            ;  and seg, DS:SI is now Environment
  1142.     xor    cx,cx            ; line length counter
  1143. getpar3:lodsb                ; read an Environment character
  1144.     or    al,al            ; null (EOL)?
  1145.     jz    getpar5            ; z = yes, stop here
  1146.     cmp    al,';'            ; semicolon separator?
  1147.     jne    getpar4            ; ne = no
  1148.     mov    al,CR            ; replace semicolon with carriage ret
  1149. getpar4:stosb                ; store char in Take buffer
  1150.     inc    cx            ; count line length
  1151.     jmp    short getpar3        ; get more text, until a null
  1152.  
  1153. getpar5:mov    al,CR            ; terminate line, regardless
  1154.     stosb
  1155.     inc    cx            ; count terminator
  1156.     POP    DS            ; restore regular DS
  1157.     mov    [bx].takcnt,cx        ; chars in Take/macro buffer
  1158.     mov    es:byte ptr [0],cl    ; store count byte
  1159.     mov    [bx].takptr,1        ; init buffer read ptr to first char
  1160.     jcxz    getpar8            ; z = nothing left, exit
  1161.                     ; parse each item as a command
  1162. getpar6:mov    comand.cmquiet,1    ; no screen display
  1163.     mov    dx,offset nulprmpt    ; set null prompt
  1164.     call    prompt
  1165.     cmp    flags.extflg,0        ; exit flag set?
  1166.     jne    getpar8            ; ne = yes, exit this routine now
  1167.     mov    dx,offset initab    ; table of initialization routines
  1168.     xor    bx,bx            ; no explict help text
  1169.     mov    comand.cmcr,1        ; allow bare CR's
  1170.     mov    comand.impdo,0        ; do not search Macro table
  1171.         mov    ah,cmkey        ; match a keyword
  1172.     call    comnd
  1173.     jc    getpar7            ; c = failure
  1174.     mov    comand.cmcr,0        ; no more bare CR's
  1175.     call    bx            ; call the routine returned in BX
  1176.                     ; ignore failures (carry bit set)
  1177. getpar7:cmp    taklev,0        ; finished Take file?
  1178.     je    getpar8            ; e = yes
  1179.     cmp    flags.extflg,0        ; exit flag set?
  1180.     je    getpar6            ; e = no, finish all commands
  1181.  
  1182. getpar8:call    takclos            ; close our take file, if open
  1183. getpar9:mov    flags.extflg,0        ; do not leave this flag set
  1184.     clc                ; clear for success
  1185. getparx:mov    comand.cmquiet,0    ; regular screen echoing
  1186.     pop    es
  1187.     pop    di
  1188.     pop    si
  1189.     pop    dx
  1190.     pop    cx
  1191.     pop    bx
  1192.     pop    ax
  1193.     ret
  1194. getparm    endp
  1195.  
  1196. ; Locate string variable in Environment
  1197. ; bx = variable to find (usually including =), cx = length of variable name.
  1198. ; Returns dx = offset within Environment of char following the name and
  1199. ; carry clear, else carry set and dx unchanged.
  1200. getenv    proc    near
  1201.     push    ax
  1202.     push    cx
  1203.     push    si
  1204.     push    di
  1205.     push    es
  1206.     mov    es,psp
  1207.     mov    ax,es:word ptr[env]    ; pick up environment address
  1208.     mov    es,ax
  1209.     xor    di,di            ; start at offset 0 in segment
  1210. geten1:    cmp    es:byte ptr [di],0    ; end of environment?
  1211.     je    geten3            ; yes, forget it
  1212.     push    cx            ; save counter
  1213.     push    di            ; and offset
  1214.     mov    si,bx
  1215.     cld
  1216.     repe    cmpsb            ; search for name
  1217.     pop    di
  1218.     pop    cx            ; restore these
  1219.     je    geten2            ; found it, break loop
  1220.     push    cx            ; preserve again
  1221.     mov    cx,0ffffh        ; bogus length
  1222.     xor    al,al            ; 0 = marker to look for
  1223.     repne    scasb            ; search for it
  1224.     pop    cx            ; restore length
  1225.     jmp    geten1            ; loop thru rest of environment
  1226. geten2:    add    di,cx            ; skip to definition
  1227.     mov    dx,di            ; store offset of string
  1228.     clc                ; carry clear for success
  1229.     jmp    short geten4
  1230. geten3:    stc                ; carry set for failure
  1231. geten4:    pop    es
  1232.     pop    di
  1233.     pop    si
  1234.     pop    cx
  1235.     pop    ax
  1236.     ret
  1237. getenv    endp
  1238.  
  1239. ; Get thousands separator from DOS Country Information
  1240. gettsep    proc    near
  1241.     mov    ah,38h            ; Get Country Information
  1242.     mov    dx,offset tmpbuf    ; temp buffer
  1243.     int    dos
  1244.     mov    bx,7            ; assume DOS 3+ position in buffer
  1245.     cmp    byte ptr dosnum+1,3    ; DOS 3 or above?
  1246.     jae    gettse1            ; ae = yes
  1247.     mov    bx,4            ; for DOS 2.1
  1248.     cmp    dosnum,210h        ; earlier than version 2.1?
  1249.     jae    gettse1            ; ae = no
  1250.     mov    al,','            ; use comma for old DOS's
  1251. gettse1:mov    al,tmpbuf[bx]        ; get thousands separator char
  1252.     mov    thsep,al        ; save it
  1253.     ret
  1254. gettsep    endp
  1255.  
  1256. STAY    PROC    NEAR
  1257.     clc
  1258.     ret
  1259. STAY    ENDP
  1260.  
  1261. COMNT    PROC    NEAR            ; COMMENT command
  1262.     mov    ah,cmline
  1263.     mov    bx,offset tmpbuf
  1264.     xor    dx,dx
  1265.     call    comnd
  1266.     ret
  1267. COMNT    ENDP
  1268.  
  1269. ; change working directory
  1270. cwdir    proc    near
  1271.     mov    kstatus,0        ; global status
  1272.     mov    ah,cmword
  1273.     mov    dx,offset tmpbuf
  1274.     mov    bx,offset pthmsg
  1275.     mov    word ptr tmpbuf,0
  1276.     call    comnd            ; get drive/dir spec, if any
  1277.     mov    ah,cmeol
  1278.     call    comnd
  1279.     jnc    cwd1
  1280.     ret                ; c = failure
  1281. cwd1:    mov    dx,offset crlf        ; msgs from cdsr don't include this
  1282.     mov    ah,prstr        ; so let's do it now
  1283.     int    dos
  1284.     mov    si,offset tmpbuf    ; cdsr wants drive/path ptr in si
  1285.     call    cdsr            ; common CD sub-routine
  1286.     jnc    cwd2            ; nc = success
  1287.     mov    kstatus,8        ; global status for unsuccess
  1288. cwd2:    call    prtasz            ; output current drive/path or err msg
  1289.     clc
  1290.     ret
  1291. cwdir    endp
  1292.  
  1293. ; CDSR processes both CD & REM CD.  Entered with si --> drive/path, it returns
  1294. ; dx --> ASCIIZ current drive/path, w/carry clear, if successful, or error msg
  1295. ; w/carry set, if not.
  1296. CDSR    PROC
  1297.     xor    cx,cx            ; 0 for default drive, if none
  1298.     cmp    byte ptr[si],ch        ; any drive/path?
  1299.     je    cdsr4            ; e = no, just format current drive/path
  1300.     cmp    byte ptr[si+1],':'    ; is drive specified?
  1301.     jne    cdsr1            ; ne = no
  1302.     mov    cl,[si]            ; drive letter
  1303.     cmp    byte ptr[si+2],ch    ; any path?
  1304.     jne    cdsr1            ; ne = yes
  1305.     mov    word ptr[si+2],'.'    ; append dot+null as path to kludge DOS
  1306. cdsr1:    call    dskspace        ; test for drive, spec'd by cl, ready
  1307.     jnc    cdsr2            ; nc = ready
  1308.     mov    spcmsg3,cl        ; insert drive letter ret'd by dskspace
  1309.     mov    dx,offset spcmsg2+2    ; in err msg.  dx --> msg w/o cr,lf
  1310.     ret                ; carry is set
  1311.  
  1312. cdsr2:    mov    dx,si            ; where chdir wants it
  1313.     mov    ah,chdir
  1314.     int    dos
  1315.     jnc    cdsr3            ; nc = success
  1316.     mov    dx,offset ermes4    ; ret carry set, dx --> err msg
  1317.     ret
  1318.  
  1319. cdsr3:    mov    dl,cl            ; uc drive letter ret'd by dskspace
  1320.     sub    dl,'A'            ; A = 0 for seldsk
  1321.     mov    ah,seldsk
  1322.     int    dos
  1323.     inc    dl            ; A = 1 for curdsk
  1324.     mov    curdsk,dl
  1325. cdsr4:    push    si            ; use caller's buffer for cur dr/path
  1326.     mov    ax,':@'            ; al = 'A' - 1, ah = ':'
  1327.     add    al,curdsk        ; al = drive letter
  1328.     mov    [si],ax            ; stash drive:
  1329.     inc    si
  1330.     inc    si
  1331.     mov    byte ptr[si],'\'    ; add \
  1332.     inc    si
  1333.     mov    ah,gcd            ; gcd fills in path as ASCIIZ
  1334.     xor    dl,dl            ; use current drive
  1335.     int    dos
  1336.     pop    dx            ; return caller's buffer pointer in dx
  1337.     clc
  1338.     ret
  1339. CDSR    ENDP
  1340.  
  1341. ; Erase specified file(s). Add protection of ignore hidden, subdir, volume
  1342. ; label and system files. 9 Jan 86 [jrd]
  1343. DELETE    PROC    NEAR            ; includes paths and "?*" wildcards
  1344.     mov    kstatus,0        ; global status
  1345.     mov    si,offset delcmd    ; del command
  1346.     mov    di,offset tmpbuf
  1347.     call    strcpy
  1348.     mov    dx,offset tmpbuf
  1349.     call    strlen            ; get its length
  1350.     add    di,cx            ; point at terminator
  1351.     mov    temp,di            ; remember starting spot
  1352.     mov    ah,cmline        ; get a line
  1353.     mov    bx,di            ; where to place the file spec
  1354.     mov    dx,offset filmsg    ; help message
  1355.     call    comnd
  1356.     jc    delet0            ; c = failure
  1357.     or    ah,ah            ; anything given?
  1358.     jnz    delet1            ; nz = yes
  1359.     mov    ah,prstr
  1360.     mov    dx,offset ermes1    ; say need something
  1361.     int    dos
  1362.     clc                ; say success
  1363. delet0:    ret
  1364.  
  1365. delet1:    mov    di,temp            ; start of filespec
  1366.     xor    cl,cl            ; disk drive letter
  1367.     cmp    byte ptr [di+1],':'    ; drive specified?
  1368.     jne    delet2            ; ne = no
  1369.     mov    cl,[di]            ; get drive letter
  1370. delet2:    call    dskspace        ; compute space, get letter into CL
  1371.     jnc    delet3            ; nc = success
  1372.     mov    spcmsg3,cl        ; put drive letter in msg
  1373.     mov    dx,offset spcmsg2    ; error message
  1374.     call    prtasz
  1375.     mov    kstatus,8        ; global status
  1376.     clc
  1377.     ret                ; and ignore this command
  1378. delet3:    mov    si,offset tmpbuf    ; del cmd
  1379.     jmp    crun            ; join run cmd from there
  1380. DELETE    ENDP
  1381.  
  1382. ; Space <optional drive letter>
  1383.  
  1384. CHKDSK    PROC    NEAR            ; Space command
  1385.     mov    kstatus,0        ; global status
  1386.     mov    dx,offset tmpbuf    ; buffer
  1387.     mov    tmpbuf,0        ; init to null
  1388.     mov    bx,offset dskmsg    ; help message
  1389.     mov    ah,cmword        ; get optional drive letter
  1390.     call    comnd            ; ignore errors
  1391.     mov    ah,cmeol
  1392.     call    comnd
  1393.     jnc    chkdsk1            ; nc = success
  1394.     ret                ; failure
  1395. chkdsk1:mov    cl,tmpbuf        ; set drive letter
  1396.     call    dskspace        ; compute space, get letter into CL
  1397.     jnc    chkdsk2            ; nc = success
  1398.     and    cl,5fh            ; to upper case
  1399.     mov    spcmsg3,cl        ; insert drive letter
  1400.     mov    dx,offset spcmsg2    ; say drive not ready
  1401.     call    prtasz
  1402.     mov    kstatus,8        ; global status
  1403.     clc
  1404.     ret
  1405.     
  1406. chkdsk2:mov    spcmsg1,cl        ; insert drive letter
  1407.     mov    di,offset tmpbuf    ; work space for lnout
  1408.     mov    word ptr[di],0a0dh    ; cr/lf
  1409.     mov    word ptr[di+2],'  '    ; add two spaces
  1410.     add    di,4
  1411.     call    lnouts            ; use thousands separator
  1412.     mov    si,offset spcmsg
  1413.     call    strcat            ; add text to end of message
  1414.     mov    dx,offset tmpbuf
  1415.     call    prtasz            ; print asciiz string
  1416.     clc
  1417.     ret
  1418. CHKDSK    ENDP
  1419.  
  1420. ; Compute disk free space (bytes) into long word dx:ax.
  1421. ; Enter with disk LETTER in CL (use null if current disk).
  1422. ; Returns uppercase drive letter in CL.
  1423. ; Returns carry set if drive access error. Changes AX, DX.
  1424.  
  1425. DSKSPACE PROC    NEAR
  1426.     mov    dl,cl            ; desired disk letter, or null
  1427.     or    dl,dl            ; use current disk?
  1428.     jnz    dskspa1            ; nz = no
  1429.     mov    ah,gcurdsk        ; get current disk
  1430.     int    dos
  1431.     add    al,'A'            ; make 0 ==> A
  1432.     mov    dl,al
  1433. dskspa1:and    dl,5fh            ; convert to upper case
  1434.     mov    cl,dl            ; return upper case drive letter in CL
  1435.     sub    dl,'A'-1        ; 'A' is 1, etc
  1436.     push    bx
  1437.     push    cx
  1438.     mov    ah,36h            ; get disk free space, bx=sect/cluster
  1439.     int    dos            ; dx:ax=sectors, cx=bytes/sector
  1440.     cmp    ax,0ffffh        ; error response?
  1441.     jne    dskspa2            ; ne = no
  1442.     pop    cx
  1443.     pop    bx
  1444.     stc                ; return error
  1445.     ret
  1446. dskspa2:mul    bx            ; sectors/cluster * clusters = sectors
  1447.     mov    bx,dx            ; save high word of sectors (> 64K)
  1448.     mul    cx            ; bytes = sectors * bytes/sector
  1449.     push    ax            ; save low word of bytes
  1450.     mov    ax,bx            ; recall sectors high word
  1451.     mov    bx,dx            ; save current bytes high word
  1452.     mul    cx            ; high word sectors * bytes/sector
  1453.     add    ax,bx            ; new high bytes + old high bytes
  1454.     mov    dx,ax            ; store high word in dx
  1455.     pop    ax            ; space is in dx:ax as a long word
  1456.     pop    cx
  1457.     pop    bx
  1458.     clc
  1459.     ret
  1460. DSKSPACE ENDP
  1461.  
  1462. ; Get directory    listing
  1463. DIRECT    PROC    NEAR
  1464.     mov    kstatus,0        ; global status
  1465.     mov    si,offset dircmd    ; dir command
  1466.     mov    di,offset tmpbuf
  1467.     call    strcpy
  1468.     mov    dx,offset tmpbuf
  1469.     call    strlen            ; get its length
  1470.     add    di,cx            ; point at terminator
  1471.     mov    temp,cx            ; remember length
  1472.     mov    ah,cmline        ; parse with cmline to allow switches
  1473.     mov    bx,di            ; next available byte
  1474.     mov    dx,offset filmsg    ; help message 
  1475.     call    comnd
  1476.     jnc    direct1            ; nc = success
  1477.     ret                ; failure
  1478. direct1:mov    word ptr [bx],0        ; plant terminator
  1479.     mov    cl,curdsk        ; current drive number ('A'=1)
  1480.     add    cl,'A'-1        ; make a letter
  1481.     mov    si,offset tmpbuf
  1482.     push    si
  1483.     add    si,temp            ; user's text after ' dir '
  1484.     cmp    byte ptr [si+1],':'    ; drive specified?
  1485.     jne    direct2            ; ne = no, use current drive
  1486.     mov    cl,[si]            ; get drive letter from buffer
  1487. direct2:call    dskspace        ; check for drive ready
  1488.     pop    si
  1489.     jnc    direct3            ; nc = drive ready
  1490.     mov    spcmsg3,cl        ; insert letter
  1491.     mov    dx,offset spcmsg2    ; say drive is not ready
  1492.     call    prtasz
  1493.     stc
  1494.     ret
  1495. direct3:jmp    crun            ; join run cmd from there
  1496. DIRECT    ENDP
  1497.  
  1498. ; This is the 'HELP' command.  It gives a list of the commands
  1499.  
  1500. HELP    PROC    NEAR
  1501.     mov    kstatus,0        ; global status
  1502.     mov    ah,cmeol
  1503.     call    comnd            ; get a confirm
  1504.     jnc    help1            ; nc = success
  1505.     ret                ; failure
  1506. help1:    mov    ah,prstr        ; show Quick help summary screen
  1507.     mov    dx,offset qckhlp
  1508.     int    dos
  1509.     mov    ah,conout
  1510.     mov    dl,trans.escchr        ; get Kermit escape character
  1511.     add    dl,40h            ; convert to printable
  1512.     push    dx            ; save it for repeats below
  1513.     int    dos
  1514.     mov    ah,prstr
  1515.     mov    dx,offset qckhlp1    ; more help text
  1516.     int    dos
  1517.     mov    ah,conout
  1518.     pop    dx
  1519.     push    dx
  1520.     int    dos
  1521.     mov    ah,prstr
  1522.     mov    dx,offset qckhlp2    ; more help text
  1523.     int    dos
  1524.     pop    dx            ; recover current escape char
  1525.     mov    ah,conout
  1526.     int    dos
  1527.     mov    ah,prstr
  1528.     mov    dx,offset qckhlp3    ; end of help message
  1529.     int    dos
  1530.     mov    ah,coninq        ; get a keystroke, quietly
  1531.     int    dos
  1532.     cmp    al,'?'            ; query mark?
  1533.     jne    helpx            ; ne = no, skip second screen
  1534.     mov    ah,prstr        ; show help summary screen
  1535.     mov    dx,offset crlf        ; a few blank lines
  1536.     int    dos
  1537.     int    dos
  1538.     int    dos
  1539.     mov    dx,offset tophlp    ; show usual cryptic help
  1540.     int    dos
  1541. helpx:    clc
  1542.     ret
  1543. HELP    ENDP
  1544.  
  1545. ; the version command - print our version number
  1546. prvers    proc    near
  1547.     mov    kstatus,0        ; global status
  1548.     mov    ah,cmeol
  1549.     call    comnd
  1550.     jc    prvers1            ; c = failure
  1551.     mov    ah,prstr
  1552.     mov    dx,offset crlf
  1553.     int    dos
  1554.     mov    ah,prstr
  1555.     mov    dx,offset machnam    ; display machine name
  1556.     int    dos
  1557.     mov    ah,prstr        ; display the version header
  1558.     mov    dx,offset verident
  1559.     int    dos
  1560.     clc
  1561. prvers1:ret
  1562. prvers    endp
  1563.  
  1564. ; the show command
  1565. showcmd    proc    near
  1566.     mov    kstatus,0        ; global status
  1567.     mov    ah,cmkey
  1568.     mov    dx,offset shotab
  1569.     xor    bx,bx            ; no canned help
  1570.     call    comnd
  1571.     jc    showc1            ; c = failure
  1572.     jmp    bx            ; execute the handler
  1573. showc1:    ret                ; failure
  1574. showcmd    endp
  1575.  
  1576. ; the type command - type out a file
  1577. typec    proc    near
  1578.     mov    kstatus,0        ; global status
  1579.     mov    si,offset typcmd    ; type command
  1580.     mov    di,offset tmpbuf
  1581.     call    strcpy
  1582.     mov    dx,offset tmpbuf
  1583.     call    strlen            ; get its length
  1584.     add    di,cx            ; point at terminator
  1585.     mov    temp,di            ; save place for later
  1586.     mov    ah,cmline        ; parse with cmline so we can have paths
  1587.     mov    bx,di            ; next available byte
  1588.     mov    dx,offset filmsg    ; In case user wants help
  1589.     call    comnd
  1590.     jc    typec1            ; c = failure
  1591.     or    ah,ah            ; any text given?
  1592.     jnz    typec2            ; nz = yes
  1593.     mov    ah,prstr
  1594.     mov    dx,offset ermes1    ; say need more info
  1595.     int    dos
  1596.     clc
  1597. typec1:    ret
  1598. typec2:    mov    byte ptr [bx],0        ; plant terminator
  1599.     mov    si,temp            ; start of filespec
  1600.     xor    cl,cl            ; say local drive
  1601.     cmp    byte ptr [si+1],':'    ; drive given?
  1602.     jne    typec3            ; ne = no
  1603.     mov    cl,[si]            ; get drive letter
  1604. typec3:    call    dskspace        ; check for drive ready
  1605.     jnc    typec4
  1606.     mov    spcmsg3,cl        ; put drive letter in msg
  1607.     mov    dx,offset spcmsg2    ; error message
  1608.     call    prtasz
  1609.     mov    kstatus,8        ; global status
  1610.     clc
  1611.     ret                ; and ignore this command
  1612. typec4:    mov    si,offset tmpbuf
  1613.     jmp    short crun        ; join run cmd from there
  1614. typec    endp
  1615.  
  1616. ; PUSH to DOS (run another copy of Command.com or equiv)
  1617. ; entry fpush (fast push...) pushes without waiting for a confirm
  1618. dopush    proc    near
  1619.     mov    ah,cmeol
  1620.     call    comnd
  1621.     jnc    fpush            ; nc = success
  1622.     ret                ; failure
  1623. fpush:    mov    si,offset tmpbuf    ; a dummy buffer
  1624.     mov    byte ptr [si],0        ; plant terminator
  1625.     mov    dx,offset cmspbuf    ; always use command.com
  1626.     cmp    shellbuf,0        ; SHELL= present?
  1627.     je    crun4            ; e = no, use COMSPEC= name
  1628.     mov    dx,offset shellbuf    ; use SHELL= name
  1629.     jmp    short crun4        ; go run it
  1630. dopush    endp
  1631.  
  1632. ; Run a program from within Kermit
  1633. RUN    PROC    NEAR
  1634.     mov    ah,cmline        ; get program name and any arguments
  1635.     mov    bx,offset tmpbuf    ; place for user's text
  1636.     mov    dx,offset runmsg    ; In case user wants help
  1637.     call    comnd
  1638.     jnc    run1            ; nc = success
  1639.     ret                ; failure
  1640. run1:    or    ah,ah            ; byte count
  1641.     jnz    run2            ; nz = have program name
  1642.     mov    ah,prstr        ; else complain
  1643.     mov    dx,offset ermes1    ; need more info
  1644.     int    dos
  1645.     clc
  1646.     ret
  1647. run2:    mov    si,offset tmpbuf    ; source of text
  1648.     jmp    short crun
  1649. RUN    ENDP
  1650.  
  1651. ; crun - run an arbitrary program.    Rewritten by [jrd]
  1652. ; Enter with ordinary asciiz command in si (such as Dir *.asm)
  1653. ; Append a c/r and a null terminator and then ask command.com to do it
  1654. ; Set errlev with DOS errorlevel from subprocess.
  1655. CRUN    proc    near
  1656.     mov    ah,prstr        ; output crlf before executing comnd
  1657.     mov    dx,offset crlf        ; [lba]
  1658.     int    dos
  1659.     mov    di,offset tmpbuf    ; where to put full command line text
  1660.     cmp    si,di            ; same place?
  1661.     je    crun1            ; e = yes, don't copy ourself
  1662.     call    strcpy            ; si holds source text
  1663. crun1:    mov    si,offset slashc    ; DOS command begins with slashc area
  1664.     mov    dx,offset slashc+1    ; si points to /c part of command line
  1665.     call    strlen            ; get its length into cx
  1666.     push    bx
  1667.     mov    bx,dx
  1668.     add    bx,cx
  1669.     mov    byte ptr [bx],cr    ; end string with a c/r for dos
  1670.     inc    cx            ; count the c/r
  1671.     mov    byte ptr [bx+1],0    ; and terminate
  1672.     pop    bx
  1673.     mov    [si],cl            ; put length of argument here
  1674.     mov    dx,offset cmspbuf    ; always use command.com
  1675. crun4:    mov    exearg+2,si        ; pointer to argument string
  1676.     mov    exearg+4,ds        ; segment of same
  1677.     cmp    lclsusp,0        ; sys dependent routine to call
  1678.     je    crun5            ; e = none
  1679.     mov    bx,lclsusp        ; address to call
  1680.     push    dx            ; preserve name in dx
  1681.     call    bx            ; call sys dependent suspend routine
  1682.     pop    dx
  1683. crun5:    push    dx            ; preserve name in dx
  1684.     call    serrst            ; reset serial port (if active)
  1685.     call    cbrestore        ; restore state of Control-Break Chk
  1686.     pop    dx
  1687.     mov    es,psp            ; point to psp again
  1688.     mov    exearg+8,es        ; segment of psp, use our def fcb's
  1689.     mov    exearg+12,es        ; segment of psp, ditto, for fcb 2
  1690.     mov    ax,es:word ptr [env]    ; get environment ptr
  1691.     mov    exearg,ax        ; put into argument block
  1692.     mov    ax,ds
  1693.     mov    es,ax            ; put es segment back
  1694.     mov    bx,offset exearg    ; es:bx points to exec parameter block
  1695.     xor    al,al            ; 0 = load and execute (DX has name)
  1696.     mov    ah,exec
  1697.     mov    ssave,sp        ; save stack ptr
  1698.     int    dos            ; go run the program
  1699.     mov    ax,data            ; restore segment registers
  1700.     mov    ds,ax            ; reset data segment
  1701.     mov    es,ax            ; and extra segment
  1702.     mov    ax,stack
  1703.     mov    ss,ax            ; and stack segment
  1704.     mov    sp,ssave        ; restore stack ptr
  1705.     pushf                ; save    flags
  1706.     mov    ah,setdma
  1707.     mov    dx,offset buff
  1708.     int    dos            ; restore dma address!!
  1709.     cmp    flags.chrset,1        ; user-defined table in use?
  1710.     je    crun6            ; e = yes
  1711.     mov    flags.chrset,437    ; find default global char set
  1712.     cmp    dosnum,0300h+30        ; DOS version 3.30 or higher?
  1713.     jb    crun6            ; b = no, no Code Pages
  1714.     mov    ax,6601h        ; get global Code Page
  1715.     int    dos            ; bx=active Code Page, dx=boot CP
  1716.     mov    flags.chrset,bx        ; setup default SET FILE CHAR SET
  1717. crun6:    call    cboff            ; turn off DOS BREAK check
  1718.     popf                ; recover flags
  1719.     jc    crun8            ; c = error, handle
  1720.     cmp    lclrest,0        ; sys dependent routine to call
  1721.     je    crun9            ; e = none
  1722.     mov    bx,lclrest        ; get routine's address
  1723.     call    bx            ; call sys dependent restore routine
  1724. crun9:    mov    ah,4dh            ; get subprocess return status
  1725.     int    dos
  1726.     mov    errlev,al        ; DOS errorlevel
  1727.     clc
  1728.     ret
  1729. crun8:    mov    ah,prstr
  1730.     mov    dx,offset erms37
  1731.     int    dos
  1732.     mov    kstatus,8        ; global status
  1733.     clc
  1734.     ret
  1735. CRUN    ENDP
  1736.  
  1737. ; Replace Int 23h and Int 24h with our own handlers
  1738. ; Revised to ask DOS for original interrupt vector contents, as suggested by
  1739. ; Jack Bryans. 9 Jan 1986 jrd
  1740. ; Modified again 30 August 1986 [jrd]
  1741. SETINT    PROC    NEAR
  1742.     push    es            ; save registers
  1743.     mov    al,23H            ; desired interrupt vector (^C)
  1744.     mov    ah,35H            ; Int 21H, function 35H = Get Vector
  1745.     int    dos            ; get vector in es:bx
  1746.     mov    in3ad,bx        ; save offset of original vector
  1747.     mov    in3ad+2,es        ;   and its segment
  1748.     mov    al,24h            ; DOS critical error, Int 24h
  1749.     mov    ah,35h
  1750.     int    dos
  1751.     mov    word ptr ceadr,bx    ; DOS's Critical Error handler, offset
  1752.     mov    word ptr ceadr+2,es    ;  and segment address
  1753.     push    ds            ; save ds around next DOS call
  1754.     mov    ax,cs            ; compose full address of ^C routine
  1755.     mov    ds,ax            ; segment is the code segment
  1756.     mov    dx,offset intbrk    ;   and offset is intbrk
  1757.     mov    al,23H            ; on ^C, goto intbrk
  1758.     mov    ah,25H            ; set interrupt address from ds:dx
  1759.     int    dos
  1760.     mov    dx,offset dosce        ; replacement Critical Error handler
  1761.     mov    al,24h            ; interrupt 24h
  1762.     mov    ah,25h            ; replace it
  1763.     int    dos
  1764.     pop    ds
  1765.     mov    ax,3300h        ; get state of Control-Break Check
  1766.     int    dos
  1767.     mov    orgcbrk,dl        ; save state here
  1768.     pop    es
  1769.     ret
  1770. SETINT    ENDP
  1771.  
  1772. ; Control Break, Interrupt 23h replacement
  1773. ; Always return with a Continue (vs Abort) condition since Kermit will cope
  1774. ; with failures. [jrd]
  1775. intbrk:    push ax
  1776.     push    ds    
  1777.     mov    ax,data            ; get Kermit's data segment
  1778.     mov    ds,ax
  1779.     mov    flags.cxzflg,'C'    ; say we saw a ^C
  1780.     mov    rstate,'E'
  1781.     mov    sstate,'E'
  1782.     pop    ds
  1783.     pop    ax
  1784.     iret               ; return to caller in a Continue condition
  1785.  
  1786. ; Set DOS' Control-Break Check to off
  1787. cboff    proc    near
  1788.     mov    ax,3301h        ; set Control-Break Chk state
  1789.     xor    dl,dl            ; set state to off
  1790.     int    dos
  1791.     ret
  1792. cboff    endp
  1793.  
  1794. ; Restore DOS's Control-Break Check to startup value
  1795. cbrestore proc    near
  1796.     push    dx
  1797.     mov    ax,3301h        ; set Control-Break Chk state
  1798.     mov    dl,orgcbrk        ; restore state to startup value
  1799.     int    dos
  1800.     pop    dx
  1801.     ret
  1802. cbrestore endp
  1803.  
  1804. ; Kermit's DOS Critical Error Handler, Int 24h. [jrd]
  1805. ; Needed to avoid aborting Kermit with the serial port interrupt active and
  1806. ; the Control Break interrupt redirected. See the DOS Tech Ref Manual for
  1807. ; a start on this material; it is neither complete nor entirely accurate
  1808. ; The stack is the Kermit's stack, the data segment is unknown, interrupts
  1809. ; are off, and the code segment is Kermit's. Note: some implementations of
  1810. ; MS DOS may leave us in DOS's stack. Called by a DOS Int 21h function
  1811. dosce:    test    ah,80h        ; block device (disk drive)?
  1812.     jnz    dosce1        ; nz = no; serial device, memory, etc
  1813.     mov    al,3        ; tell DOS to Fail the Int 21h call
  1814.     iret            ; return to DOS
  1815. dosce1:    add    sp,6        ; pop IP, CS, Flags regs, from DOS's Int 24h
  1816.     pop    ax        ; restore original callers regs existing
  1817.     pop    bx        ;  just before doing Int 21h call
  1818.     pop    cx
  1819.     pop    dx
  1820.     pop    si
  1821.     pop    di
  1822.     pop    bp
  1823.     pop    ds
  1824.     pop    es        
  1825.     mov    al,0ffh        ; signal failure (usually) the DOS 1.x way
  1826.     push    bp        ; Kermit's IP, CS, and Flags are on the stack
  1827.     mov    bp,sp        ;  all ready for an iret, but first a word ..
  1828.     or    word ptr[bp+8],1 ; set carry bit, signals failure DOS 2+ way
  1829.     pop    bp        ; this avoids seeing the Interrupt flag bit
  1830.     iret            ; return to user, simulate return from Int 21h
  1831.  
  1832. ISFILE    PROC    NEAR
  1833. ; Enter with ds:ax pointing at asciiz filename string
  1834. ; Returns carry set if the file pointed to by ax does not exist, else reset
  1835. ; Returns status byte, fstat, with DOS status and high bit set if major error
  1836. ; Does a search-for-first to permit paths and wild cards
  1837. ; Examines All kinds of files (ordinary, subdirs, vol labels, system,
  1838. ;  and hidden). Upgraded to All kinds on 27 Dec 1985. Revised 30 Aug 86 [jrd]
  1839. ; All registers are preserved
  1840.  
  1841.     push    dx            ; save regs
  1842.     push    cx
  1843.     push    ax
  1844.     mov    byte ptr filtst.dta+21,0 ; clear old attribute bits
  1845.     mov    byte ptr filtst.fname,0    ; clear any old filenames
  1846.     mov    filtst.fstat,0        ; clear status byte
  1847.     mov     cx,3fH            ; look at all kinds of files
  1848.     mov    dx,offset filtst.dta    ; own own temporary dta
  1849.     mov    ah,setdma        ; set to new dta
  1850.     int    dos
  1851.     pop    dx            ; get ax (filename string ptr)
  1852.     push    dx            ; save it again
  1853.     mov    ah,first2        ; search for first
  1854.     int    dos
  1855.     pushf                ; save flags
  1856.     mov    dx,offset buff        ; reset dma
  1857.     mov    ah,setdma
  1858.     int    dos
  1859.     popf                ; recover flags
  1860.     jnc    isfil1            ; nc = file found
  1861.     mov    filtst.fstat,al        ; record DOS status
  1862.     cmp    al,2            ; just "File Not Found"?
  1863.     je    isfil2            ; e = yes
  1864.     cmp    al,3            ; "Path not found"?
  1865.     je    isfil2            ; e = yes
  1866.     cmp    al,18            ; "No more files"?
  1867.     je    isfil2            ; e = yes
  1868.     or    filtst.fstat,80h    ; set high bit for more serious error
  1869.     jmp    short isfil2    
  1870. isfil1:    cmp    byte ptr filtst.fname,0    ; did DOS fill in a name?
  1871.     je    isfil2            ; z = no
  1872.     clc
  1873.     jmp    short isfil3
  1874. isfil2:    stc                ; else set carry flag bit
  1875. isfil3:    pop    ax
  1876.     pop    cx
  1877.     pop    dx
  1878.     ret                ; DOS sets carry if file not found
  1879. ISFILE    ENDP
  1880.  
  1881. ; initialize memory usage by returning to DOS anything past the end of kermit
  1882. memini    proc    near
  1883.     push    es
  1884.     mov    es,psp            ; address psp segment again
  1885.     mov    bx,offset msfinal + 15    ; end of pgm + roundup
  1886.     mov    cl,4
  1887.     shr    bx,cl            ; compute # of paragraphs in last seg
  1888.     mov    ax,stack        ; last segment
  1889.     sub    ax,psp            ; minus beginning
  1890.     add    bx,ax            ; # of paragraphs occupied
  1891.     mov    totpar,bx        ; save for patcher's magic number
  1892.     mov    ah,setblk
  1893.     int    dos
  1894.     jc    memin1
  1895.     pop    es
  1896.     ret
  1897. memin1:    pop    es
  1898.     mov    dx,offset ermes2
  1899.     mov    ah,prstr
  1900.     int    dos            ; complain
  1901.     jmp    krmend            ; exit Kermit now
  1902. memini    endp
  1903.  
  1904. ; Allocate memory.  Passed a memory size in ax, allocates that many
  1905. ; bytes (actually rounds up to a paragraph) and returns its SEGMENT in ax
  1906. ; The memory is NOT initialized.  Written by [jrd] to allow memory to
  1907. ; be allocated anywhere in the 1MB address space
  1908. sbrk    proc    near            ; K & R, please forgive us
  1909.     mov    bx,ax            ; bytes wanted
  1910.     add    bx,15            ; round up
  1911.     mov    cl,4
  1912.     shr    bx,cl            ; convert to # of paragraphs
  1913.     mov    cx,bx            ; remember quantity wanted
  1914.     mov    ah,alloc        ; DOS memory allocator
  1915.     int    dos
  1916.     jc    sbrkx            ; c = fatal
  1917.     cmp    cx,bx            ; paragraphs wanted vs delivered
  1918.     jb    sbrkx            ; b = not enough, fatal error
  1919.     ret                ; and return segment in ax
  1920. sbrkx:    mov    dx,offset mfmsg        ; assume not enough memory (ax = 8)
  1921.     cmp    ax,7            ; corrupted memory (ax = 7)?
  1922.     jne    sbrkx1            ; ne = no
  1923.     mov    dx,offset mf7msg    ; corrupted memory found
  1924. sbrkx1:    mov    ah,prstr
  1925.     int    dos
  1926.     jmp    krmend            ; exit Kermit now
  1927. sbrk    endp
  1928. code     ends
  1929.     end    start
  1930.