home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / mssker.asm < prev    next >
Assembly Source File  |  1993-07-12  |  83KB  |  2,596 lines

  1.     NAME    mssker
  2. ; File MSSKER.ASM
  3.     include mssdef.h
  4. ; Edit history:
  5. ; 8 July 1993 version 3.13
  6. ; 6 Sept 1991 version 3.11
  7. ; Last edit 8 July 1993
  8. ;****************************** Version 3.10 ***************************** 
  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. ;    MS-DOS Kermit Program Version 3.13, 8 July 93
  15. ;    MS-DOS Kermit Program Version 3.12, Feb 1992
  16. ;    MS-DOS Kermit Program Version 3.11, 6 Sept 1991
  17. ;    MS-DOS Kermit Program Version 3.10, 2 March 1991
  18. ;    MS-DOS Kermit Program Version 3.02, development for 3.10, 1990-91
  19. ;    MS-DOS Kermit Program Version 3.01, 20 March 1990
  20. ;    MS-DOS Kermit Program Version 3.00, 16 Jan 1990 
  21. ;    Kermit-MS Program Version 2.32, 11 Dec 1988 
  22. ;    Kermit-MS Program Version 2.31, 1 July 1988
  23. ;       Kermit-MS Program Version 2.30, 1 Jan 1988
  24. ;    Kermit-MS Program Version 2.29, 26 May 1986, plus later revisions.
  25. ;       Kermit-MS Program Version 2.27, December 6,1984
  26. ;       Kermit-MS Program Version 2.26, July 27, 1984
  27. ;       PC-Kermit Program Version 1.20, November 4, 1983
  28. ;       PC-Kermit Program Version 1.0, 1982
  29. ;       Based on the Columbia University KERMIT Protocol.
  30. ;  Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  31. ;  City of New York.  Permission is granted to any individual or institution
  32. ;  to use this software as long as it is not sold for profit.  This copyright
  33. ;  notice must be retained.  This software may not be included in commercial
  34. ;  products without written permission of Columbia University.
  35. ;
  36. ;       Original Authors (versions 1.0 through 2.28):
  37. ;         Daphne Tzoar, Jeff Damens
  38. ;         Columbia University Center for Computing Activities
  39. ;         612 West 115th Street
  40. ;         New York, NY  10025
  41. ;
  42. ;       Present author (version 2.29, 2.30, 2.31, 2.32, 3.00, 3.01, 3.02,
  43. ;            3.10, 3.11, 3.12):
  44. ;         Joe R. Doupnik
  45. ;      Dept of EE, and CASS
  46. ;      Utah State University
  47. ;      Logan, UT  84322, USA
  48. ;      E-Mail: JRD@CC.USU.EDU (Internet), JRD@USU (BITNET)
  49. ; Special thanks to Christine Gianone, Frank da Cruz, Bill Catchings, 
  50. ; Bernie Eiben, Vace Kundakci, Terry Kennedy, Jack Bryans, and many many
  51. ; others for their help and contributions.
  52.  
  53.     public    dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
  54.     public    takrd, takadr, taklev, filtst, maxtry, dskspace, thsep, tdfmt
  55.     public    lclsusp, lclrest, lclexit, cwdir, kstatus, verident, cdsr
  56.     public    spath, patched, oldtak, getenv, psp, dosctty, patchid
  57.     public    tcptos, emsrbhandle, emsgshandle, apctrap
  58.  
  59. env    equ    2CH            ; environment address in psp
  60. cline    equ    80H            ; offset in psp of command line
  61. braceop    equ    7bh            ; opening curly brace
  62. bracecl    equ    7dh            ; closing curly brace
  63.  
  64. _STACK    SEGMENT                ; our stack
  65.     dw    1500 dup (0)        ; for TCP code
  66.     dw    200 dup(0)        ; for main Kermit code
  67. msfinal    label    word            ; top of stack
  68. _STACK    ENDS
  69.  
  70. data   segment
  71.     extrn    buff:byte, comand:byte, flags:byte, trans:byte,    prmptr:word
  72.     extrn    machnam:byte, decbuf:byte, rstate:byte, sstate:byte
  73.     extrn    mcctab:byte, rdbuf:byte
  74.  
  75. verident label    byte
  76.     verdef
  77. patchena db    '$patch level'
  78. patchid    db    ' 0 $'
  79. copyright db    cr,lf
  80.     db    'Copyright (C) Trustees of Columbia University 1982, 1993.'
  81.     db    cr,lf,'$'
  82. hlpmsg    db     cr,lf,'Type ? or HELP for help',cr,lf,'$'
  83. crlf    db      cr,lf,'$'
  84. ermes1    db    cr,lf,'?More parameters are needed$'
  85. ermes2    db    cr,lf,'?Unable to initialize memory$'
  86. ermes3  db      cr,lf,'?Command canceled$'
  87. ermes4    db    '?Unable to change directory',0            ; asciiz
  88. ermes5    db    cr,lf,'?Unable to complete initialization process$'
  89. ermes6    db    cr,lf,'Ignoring patch file.'
  90.     db    ' Version number mismatch.',cr,lf,'$'
  91. ermes7    db    cr,lf,'Patch file was not found',cr,lf,'$'
  92. ermes8    db    cr,lf,'Fatal error in patch file! Please remove PATCH '
  93.     db    'command.',cr,lf,'$'
  94. erms30    db    cr,lf,'?Passed maximum nesting level for TAKE command$'
  95. erms31    db    cr,lf,'?Cannot find Take-file: $'
  96. erms34    db    cr,lf,'This program requires DOS 2.0 or above$'
  97. erms37    db    cr,lf,'?Unable to execute command interpreter $'
  98. badnam    db    cr,lf,'?No such file(s)$'
  99. filmsg    db    ' Filename$'
  100. dskmsg    db    ' disk drive letter or Return$'
  101. pthmsg    db    ' Name of new working directory and/or disk$'
  102. runmsg    db    ' program name and command line$'
  103. pathlp    db    ' optional path for file mskermit.pch$'
  104. stophlp    db    'Status value to be returned  msg, nothing if no new value$'
  105. tophlp    db    cr,lf
  106.     db    '  Ask, Askq (read keybd to variable) '
  107.     db    '  Open Read/Write/Append file  scripts'
  108.     db    cr,lf
  109.     db    '  Bye      (logout remote server)    '
  110.     db    '  Output text     (for scripts)'
  111.     db    cr,lf
  112.     db      '  C or Connect  (become a terminal)  '
  113.     db    '  Pause [seconds], MPause [millisec]'
  114.     db    cr,lf
  115.     db    '  Clear   (Input, comms recv buffer) '
  116.     db    '  Pop, End (exit current macro/Take file)'
  117.     db    cr,lf
  118.     db    '  Close    (logging and script file) '
  119.     db    '  Push     (go to DOS, keep Kermit)'
  120.     db    cr,lf
  121.     db    '  CLS (clear screen at command level)'
  122.         db      '  Quit     (leave Kermit)'
  123.     db    cr,lf
  124.     db    '  CWD or CD  (change dir &/or disk)  '
  125.         db      '  R or Receive  (opt local filename)'
  126.     db    cr,lf
  127.     db    '  Decrement/Increment variable number'
  128.     db    '  Read (line from a file to variable)'
  129.     db    cr,lf
  130.     db    '  Define/Assign   (a command macro)  '
  131.     db    '  Reinput  (script Input, reread buffer)'
  132.     db    cr,lf
  133.     db    '  Delete   (a file)                  '
  134.     db    '  Remote   (prefix for commands)'
  135.     db    cr,lf
  136.     db    '  Directory (filepsec)               '
  137.     db    '  Replay   (file through term emulator)'
  138.     db    cr,lf
  139.     db    '  Disable  (selected server commands)'
  140.     db    '  Run      (a program)'
  141.     db    cr,lf
  142.     db    '  Echo text (show line on screen)    '
  143.         db      '  S or Send  local file   new name'
  144.     db    cr,lf         
  145.     db    '  Enable   (selected server commands)'
  146.     db    '  Server [timeout] (become a server)'
  147.     db    cr,lf
  148.     db      '  EXIT     (leave Kermit)            '
  149.         db      '  Set      (most things)'
  150.     db    cr,lf
  151.     db    '  Finish   (to remote server)        '
  152.     db    '  Show     (most things)'
  153.     db    cr,lf
  154.     db    '  Get      (remote file opt new name)'
  155.     db    '  Space    (free on current disk)'
  156.     db    cr,lf
  157.     db    '  GetOK    (get Yes, OK, No response)'
  158.     db    '  Stop     (exit all Take files & macros)'
  159.     db    cr,lf
  160.     db    '  Goto    (label, Take file or Macro)'
  161.     db    '  Take     (do a command file)'
  162.     db    cr,lf
  163.     db    '  Hangup   (drop DTR, hang up phone) '
  164.     db    '  Transmit filespec [prompt] (raw upload)'
  165.     db    cr,lf
  166.     db    '  If [not] <condition> <command>     '
  167.     db    '  Type     (a file)'
  168.     db    cr,lf
  169.     db    '  I or Input [timeout] text (scripts)'
  170.     db    '  Wait [timeout] on modem \cd \cts \dsr'
  171.     db    cr,lf
  172.     db    '  Log (Packet, Session, Transaction) '
  173.     db    '  Write  FILE or log file   text'
  174.     db    cr,lf
  175.     db    '  Mail     (file to host Mailer)     '
  176.     db    '$'
  177. data    ends
  178.  
  179. data1    segment
  180. qckhlp    db cr,lf
  181.     db '                    Introduction to MS-DOS Kermit',cr,lf
  182.     db 'o An MS-Kermit command is a line of words separated by spaces and'
  183.     db ' ending with',cr,lf,'  a carriage return <the Enter key>.'
  184.     db '  Example: SET SPEED 2400<Enter>',cr,lf
  185.     db 'o Most words can be abbreviated and can be completed by pressing'
  186.     db ' the Esc key.',cr,lf
  187.     db '  Example: SET SPE 24<Enter>  or even  SET SPE<Esc> 24<Esc>'
  188.     db '<Enter>',cr,lf
  189.     db 'o Help (detailed, specific): press the "?" key where a word would'
  190.     db ' appear.',cr,lf
  191.     db 'o Edit lines using the Backspace key to delete characters,'
  192.     db ' Control-W to delete',cr,lf
  193.     db '  words, and Control-U to delete the line.  Control-C cancels the'
  194.     db ' command.',cr,lf
  195.     db 'o Frequently used MS-Kermit commands:',cr,lf
  196.     db '  EXIT           Leave the Kermit program. QUIT does the same'
  197.     db ' thing.',cr,lf
  198.     db '  SET            PORT, PARITY, SPEED, TERMINAL and many other'
  199.     db ' parameters.',cr,lf
  200.     db '  SHOW or STATUS Display groups of important parameters.'
  201.     db ' SHOW ? for categories.',cr,lf,lf
  202.     db '  CONNECT        Establish a terminal connection to a remote'
  203.     db ' system or a modem.',cr,lf
  204.     db '  Control-$'
  205. qckhlp1    db ' C    (Control-$'
  206. qckhlp2    db '  followed by "C")  Return to MS-Kermit> prompt.',cr,lf,lf
  207.     db '  SEND filename  Send the file(s) to Kermit on the other'
  208.     db ' computer.',cr,lf
  209.     db '  RECEIVE        Receive file(s), SEND them from Kermit on the'
  210.     db ' other computer.',cr,lf
  211.     db '  GET filename   Ask the remote Kermit server to send the file(s)'
  212.     db ' to us.',cr,lf
  213.     db '  FINISH         Shut down remote Kermit but stay logged into'
  214.     db ' remote system.',cr,lf
  215.     db '  BYE            FINISH and logout of remote system and exit'
  216.     db ' local Kermit.',cr,lf
  217.     db 'o Common startup sequence: SET SPEED 9600, CONNECT, login, start'
  218.     db ' remote Kermit,',cr,lf
  219.     db '  put it into Server mode, escape back with Control-$'
  220. qckhlp3    db ' C, transfer'
  221.     db ' files with',cr,lf
  222.     db '  SEND x.txt, GET b.txt, BYE.'
  223.     db cr,lf
  224.     db ' - more -  Press the space bar for more information$'
  225. qckhlp4 db cr,lf
  226.     db ' DOCUMENTATION'
  227.     db cr,lf,lf
  228.     db ' MS-DOS Kermit is fully documentated in:'
  229.     db cr,lf, ' Christine M. Gianone, "Using MS-DOS Kermit", Second'
  230.     db ' Edition,'
  231.     db cr,lf,'   Digital Press, Bedford, MA, 1992, 345 pages:'
  232.     db cr,lf,' USA Order Number: EY-H893E-DP'
  233.     db cr,lf,' USA Digital Press ISBN: 1-55558-082-3'
  234.     db cr,lf,' USA Prentice Hall ISBN: 0-13-952276-X'
  235.     db cr,lf,' International Edition Order Number: EY-H893E-DI'
  236.     db cr,lf,' International Prentice Hall ISBN: 0-13-953043-6'
  237.     db cr,lf,' Available in computer bookstores or directly from Digital'
  238.     db ' Press.'
  239.     db cr,lf,' In the USA, call Digital Press toll-free 1-800-344-4825'
  240.     db ' to order;'
  241.     db cr,lf,'   major credit cards accepted. Overseas, order through'
  242.     db ' your bookstore or'
  243.     db cr,lf,'   your local Digital Equipment Corporation branch.'
  244.     db cr,lf,lf,' For additional information, contact:'
  245.     db cr,lf,'   Kermit Development and Distribution'
  246.     db cr,lf,'   Columbia University Academic Information Systems'
  247.     db cr,lf,'   612 West 115th Street'
  248.     db cr,lf,'   New York, NY  10025  USA'
  249.     db cr,lf,'   Telephone: (USA) 212 854-3703'
  250.     db cr,lf
  251.     db cr,lf,' New features are documented in KERMIT.UPD (MSKERM.UPD)'
  252.     db cr,lf,' For hints and tips, please read KERMIT.BWR (MSKERM.BWR)'
  253.     db cr,lf,' - more -  Press the space bar for a functional summary'
  254.     db ' of Kermit commands. $'
  255.  
  256. qckhlp5    db    cr,lf,lf,lf,lf,lf,lf,lf
  257.     db ' MS-DOS Kermit commands, a functional summary:'
  258.     db    cr,lf
  259.     db    cr,lf,' Local file management:         '
  260.     db    'Kermit program management:'
  261.     db    cr,lf,'   DIR    (list files)          '
  262.     db    '  EXIT     (from Kermit, return to DOS)'
  263.     db    cr,lf,'   CD     (change directory)    '
  264.     db    '  QUIT     (same as EXIT)'
  265.     db    cr,lf,'   DELETE (delete files)        '      
  266.     db    '  TAKE     (execute Kermit commands from file)'
  267.     db    cr,lf,'   RUN    (a DOS command)       '
  268.     db    '  CLS      (clear screen)'
  269.     db    cr,lf,'   TYPE   (display a file)      '
  270.     db    '  PUSH     (enter DOS, EXIT returns to Kermit)'
  271.     db    cr,lf,'   SPACE  (show disk space)     '
  272.     db    '  Ctrl-C   (interrupt a command)'
  273.     db    cr,lf
  274.     db    cr,lf,' Communication settings:        '
  275.     db    'Terminal emulation:'
  276.     db    cr,lf,'   SET PORT, SET SPEED          '
  277.     db    '  CONNECT  (begin terminal emulation)'
  278.     db    cr,lf,'   SET PARITY                   '
  279.     db    '  HANGUP   (close connection)'
  280.     db    cr,lf,'   SET FLOW-CONTROL             '
  281.     db    '  Alt-X    (return to MS-Kermit> prompt)'
  282.     db    cr,lf,'   SET LOCAL-ECHO               '
  283.     db    '  SET KEY  (key mapping)'
  284.     db    cr,lf,'   SET ? to see others          '
  285.     db    '  SET TERMINAL TYPE, BYTESIZE, other parameters'
  286.     db    cr,lf,'   SHOW COMMUNICATIONS, MODEM   '
  287.     db    '  SHOW TERMINAL, SHOW KEY'
  288.     db    cr,lf,lf,' - more -$'
  289. qckhlp6    db    cr,'          '
  290.     db    cr,lf,' File transfer settings:        '
  291.     db    cr,lf,'   SET FILE CHARACTER-SET name  '  
  292.     db    '  SET TRANSFER CHARACTER-SET'
  293.     db    cr,lf,'   SET FILE TYPE TEXT, BINARY   '  
  294.     db    '  SET SEND or RECEIVE parameters'
  295.     db    cr,lf,'   SET FILE ? to see others     '  
  296.     db    '  SET WINDOWS (sliding windows)'
  297.     db    cr,lf,'   SHOW FILE                    '  
  298.     db    '  SHOW PROTOCOL, SHOW STATISTICS'
  299.     db    cr,lf
  300.     db    cr,lf,' Kermit file transfer:           '
  301.     db    'ASCII file transfer:'
  302.     db    cr,lf,'   SEND files (to RECEIVE)      '
  303.     db    '  LOG SESSION, CLOSE SESSION (download)'
  304.     db    cr,lf,'   RECEIVE    (from SEND)       '
  305.     db    '  TRANSMIT (upload)'
  306.     db    cr,lf,'   MAIL files (to RECEIVE)      '
  307.     db    '  SET TRANSMIT parameters'
  308.     db    cr,lf,lf,' - more - $'
  309. qckhlp7    db    cr,'          '
  310.     db    cr,lf,' Using a Kermit server:         '
  311.     db    'Being a kermit server:'
  312.     db    cr,lf,'   GET files    (from server)   '
  313.     db    '  SET SERVER TIMEOUT or LOGIN'
  314.     db    cr,lf,'   SEND or MAIL   (to server)   '
  315.     db    '  ENABLE or DISABLE features'
  316.     db    cr,lf,'   REMOTE command (to server)   '
  317.     db    '  SERVER'
  318.     db    cr,lf,'   FINISH, LOGOUT, BYE          '
  319.     db    '  SHOW SERVER'
  320.     db    cr,lf
  321.     db    cr,lf,' Script programming commands:   '
  322.     db    cr,lf,'   INPUT, REINPUT secs text     '
  323.     db    '  :label, GOTO label'
  324.     db    cr,lf,'   OUTPUT text                  '
  325.     db    '  IF [ NOT ] condition command'
  326.     db    cr,lf,'   DECREMENT or INCREMENT variable number'
  327.     db    cr,lf,'   ASK or ASKQ variable prompt  '
  328.     db    '  OPEN READ (or WRITE or APPEND) file'
  329.     db    cr,lf,'   DEFINE variable or macro     '
  330.     db    '  READ variable-name'
  331.     db    cr,lf,'   ASSIGN variable or macro     '
  332.     db    '  WRITE file-designator text'
  333.     db    cr,lf,'   [ DO ] macro arguments       '
  334.     db    '  CLOSE READ or WRITE file or logfile'
  335.     db    cr,lf,'   ECHO text                    '
  336.     db    '  END or POP from macro or file'
  337.     db    cr,lf,'   PAUSE time                   '
  338.     db    '  STOP all macros and command files'
  339.     db    cr,lf,'   WAIT time modem-signals      '
  340.     db    '  WRITE file-designator text'
  341.     db    cr,lf,'   SHOW SCRIPTS, SHOW MACROS    '
  342.     db    '  SHOW VARIABLES'
  343.     db    cr,lf,lf
  344.     db ' Use "?" within comands for help on what fits that word.',lf,'$'
  345. kpath    db    65 dup (0)        ; Kermit's path to Kermit files
  346. data1    ends
  347.  
  348. data    segment
  349.  
  350. comtab  db    71            ; COMND tables
  351.     mkeyw    'Asg',assign        ; synonym
  352.     mkeyw    'Ask',ask
  353.     mkeyw    'Askq',askq
  354.     mkeyw    'Assign',assign
  355.     mkeyw    'Bye',bye
  356.     mkeyw    'C',telnet
  357.     mkeyw    'CD',cwdir
  358.     mkeyw    'Clear',scclr
  359.     mkeyw    'Close',clscpt
  360.     mkeyw    'Comment',comnt
  361.     mkeyw    'Connect',telnet
  362.     mkeyw    'CLS',cls
  363.     mkeyw    'CWD',cwdir
  364.     mkeyw    'Define',dodef
  365.     mkeyw    'Decrement',decvar
  366.     mkeyw    'Delete',delete
  367.     mkeyw    'Directory',direct
  368.     mkeyw    'Disable',srvdsa
  369.     mkeyw    'Do',docom
  370.     mkeyw    'Echo',scecho
  371.     mkeyw    'Enable',srvena
  372.     mkeyw    'End',popcmd
  373.     mkeyw    'Exit',exit
  374.     mkeyw    'Finish',finish
  375.     mkeyw    'Get',get
  376.     mkeyw    'G',get            ; hidden synomym for Get
  377.     mkeyw    'Ge',get        ; ditto
  378.     mkeyw    'Getok',getok
  379.     mkeyw    'goto',sgoto
  380.     mkeyw    'H',help
  381.     mkeyw    'Hangup',dtrlow
  382.     mkeyw    'Help',help
  383.     mkeyw    'If',ifcmd
  384.     mkeyw    'I',scinp
  385.     mkeyw    'Increment',incvar
  386.     mkeyw    'Input',scinp
  387. ;;;    mkeyw    'Load',load
  388.     mkeyw    'Log',setcpt
  389.     mkeyw    'Mail',mail
  390.     mkeyw    'Mpause',scmpause
  391.     mkeyw    'Open',vfopen
  392.     mkeyw    'O',scout        ; hidden synomym for OUTPUT
  393.     mkeyw    'Output',scout
  394.     mkeyw    'Pause',scpau
  395.     mkeyw    'Pop',popcmd
  396.     mkeyw    'Push',dopush
  397.     mkeyw    'Quit',exit
  398.     mkeyw    'R',read
  399.     mkeyw    'Read',vfread
  400.     mkeyw    'Receive',read
  401.     mkeyw    'Reinput',screinp
  402.     mkeyw    'Remote',remote
  403.     mkeyw    'Replay',replay
  404.     mkeyw    'Run',run
  405.     mkeyw    'S',send
  406.     mkeyw    'Send',send
  407.     mkeyw    'Server',server
  408.     mkeyw    'Set',setcom
  409.     mkeyw    'Show',showcmd
  410.     mkeyw    'Space',chkdsk
  411.     mkeyw    'Statistics',shosta
  412.     mkeyw    'Stay',stay
  413.     mkeyw    'Stop',takeqit
  414.     mkeyw    'Take',take
  415.     mkeyw    'Transmit',scxmit
  416.     mkeyw    'xmit',scxmit        ; hidden synonym
  417.     mkeyw    'Type',typec
  418.     mkeyw    'Version',prvers
  419.     mkeyw    'Wait',scwait
  420.     mkeyw    'Write',write
  421.     mkeyw    ':',comnt        ; script labels, do not react
  422.     mkeyw    'Patch',patch
  423.  
  424. shotab    db    17            ; SHOW keyword
  425.     mkeyw    'Communications',shcom
  426.     mkeyw    'Control-prefixing',cntlsho
  427.     mkeyw    'File',shfile
  428.     mkeyw    'Key',shokey
  429.     mkeyw    'Logging',shlog
  430.     mkeyw    'Macros',shomac
  431.     mkeyw    'Memory',shmem
  432.     mkeyw    'Modem',shomodem
  433.     mkeyw    'Protocol',shpro
  434.     mkeyw    'Scripts',shscpt
  435.     mkeyw    'Server',shserv
  436.     mkeyw    'Sessions',sesdisp    ; TCP/IP
  437.     mkeyw    'Statistics',shosta
  438.     mkeyw    'Status',status
  439.     mkeyw    'Terminal',shterm
  440.     mkeyw    'Translation',shorx
  441.     mkeyw    'Variables',shovar
  442.                     ; Kermit initing from Environment
  443. nulprmpt db    0            ; null prompt
  444. initab    db    8            ; Environment phrase dispatch table
  445.     mkeyw    'INPUT-buffer-length',setinpbuf ; Script INPUT buffer length
  446.     mkeyw    'Rollback',setrollb    ; number of Terminal rollback screens
  447.     mkeyw    'Width',setwidth    ; columns in rollback buffer, def=80
  448.     mkeyw    'COM1',com1port
  449.     mkeyw    'COM2',com2port
  450.     mkeyw    'COM3',com3port
  451.     mkeyw    'COM4',com4port
  452.     mkeyw    'Path',mkkpath
  453.  
  454. patched    db    1        ; 1 = enable patching; 0 = disable or done
  455.  
  456.     even
  457. lclsusp    dw    0        ; address of routine to call when going to DOS
  458. lclrest    dw    0        ; address of routine to call when returning
  459. lclexit    dw    0        ; address of routine to call when exiting
  460. tcptos    dw    0        ; top of stack for TCP code
  461. ssave    dd    0        ; Original SS:SP when doing Command.com
  462. in3ad    dw    0,0        ; Original break interrupt addresses
  463. ceadr    dd    0        ; DOS Critical Error interrupt address
  464. orgcbrk    db    0        ; original Control-Break Check state
  465. psp    dw    0        ; segment of Program Segment Prefix
  466. exearg    dw    0        ; segment addr of environment (filled in below)
  467.     dd    0        ; ptr to cmd line (filled in below)
  468.     dw    5ch,0,6ch,0    ; our def fcb's; segment filled in later
  469. emsrbhandle dw    -1        ; EMS rollback handle, -1 means invalid
  470. emsgshandle dw    -1        ; EMS graphics handle, -1 means invalid
  471. dosnum    dw    0        ; dos version number, major=low, minor=high
  472. dosctty    db    0        ; !=0 if DOS attempts using our comms line
  473. curdsk    db    0        ; Current disk
  474. origd    db    0        ; Original disk
  475. orgdir    db    64 dup (0)    ; original directory on original disk
  476. taklev    db    0        ; Take levels
  477. oldtak    db    0        ; Take level at start of command parse
  478. takadr    dw    takstr-(size takinfo) ; Pointer into structure
  479. takstr    db    (size takinfo) * maxtak dup(?)
  480. cmdlinetake db    0        ; non-zero if have DOS command line cmds
  481. filtst    filest    <>        ; file structure for procedure isfile
  482. maxtry    db    defmxtry    ; Retry limit for data packet send/rcv
  483. ininm2    db    'MSKERMIT.INI',0 ; init file name
  484. ptchnam    db    'MSR313.PCH',0    ; main patch file name (Version dependent)
  485. ptchnam2 db    'MSKERMIT.PCH',0 ; alternate patch file name
  486. delcmd    db    ' del ',0    ; delete command
  487. dircmd    db    ' dir ',0    ; directory command
  488. typcmd    db    ' type ',0    ; type command
  489. kerenv    db    'KERMIT=',0,0    ; Kermit= environment variable, + 2 nulls
  490. pthnam    db    'PATH='        ; Path environment variable
  491. pthlen    equ    $-pthnam    ;  length of that string
  492. pthadr    dw    0        ; offset of PATH= string
  493.  
  494. slashc    db    ' /c '        ; slashc Must directly preceed tmpbuf
  495. tmpbuf    db    128 dup (0)    ; temp space for file names and comments
  496. cmspnam    db    'COMSPEC='    ; Environment variable
  497. cmsplen    equ    $-cmspnam
  498. cmspbuf    db    '\command.com',30 dup (0) ; default name plus additional space
  499. shellnam db    'SHELL='    ; Environment variable
  500. shellen    equ    $-shellnam
  501. shellbuf db    40 dup (0)    ; buffer for name
  502. eexit    db    cr,'exit',cr
  503. leexit    equ    $-eexit
  504. onexit    db    7,0,'ON_EXIT'    ; <length>on_exit macro name
  505. onexlen    equ    $-onexit-2    ; length of name
  506. mfmsg    db    '?Not enough memory to run Kermit$'
  507. mf7msg    db    '?Attempted to allocate a corrupted memory area$'
  508. spcmsg    db    ' bytes available on drive '
  509. spcmsg1    db    ' :',cr,lf,0
  510. spcmsg2    db    cr,lf,' Drive '
  511. spcmsg3    db    ' : is not ready',0
  512. errlev    db    0        ; DOS errorlevel to be returned
  513. kstatus    dw    0        ; command execution status (0 = success)
  514. thsep    db    0        ; thousands separator
  515. tdfmt    db    0        ; date/time format code
  516. totpar    dw    0
  517. apctrap    db    0        ; disable command if done via APC
  518. temp    dw    0
  519.  
  520. segstr    db    'ABCDEFG'    ; segment "names" for patcher
  521. lsegstr    equ    $-segstr
  522.     even
  523. segtab    dw    code        ; segment values for patcher
  524.     dw    code1
  525.     dw    code2
  526.     dw    data
  527.     dw    data1
  528.     dw    _TEXT
  529.     dw    dgroup
  530. data   ends
  531.  
  532. code    segment
  533.     extrn    mail:near, load:near, shovar:near
  534.     extrn    bye:near, telnet:near, finish:near, comnd:near, prompt:near
  535.     extrn    read:near, remote:near, send:near, status:near, get:near
  536.     extrn    serrst:near, setcom:near, dtrlow:near, cmblnk:near
  537.     extrn    clscpi:near, clscpt:near, scpini:near, setrollb:near
  538.     extrn    dodef:near, setcpt:near, docom:near, shomodem:near
  539.     extrn    server:near, lclini:near, shokey:near, shomac:near, shosta:near
  540.     extrn    strlen:near, strcpy:near, shserv:near, initibm:near
  541.     extrn    strcat:near, prtasz:near, shorx:near, lnout:near, lnouts:near
  542.     extrn    scout:near,scinp:near,scpau:near,scecho:near,scclr:near
  543.     extrn    scxmit:near, scwait:near, srvdsa:near, srvena:near
  544.     extrn    shcom:near, shlog:near, shpro:near, shterm:near, shscpt:near
  545.     extrn    shfile:near, takopen:near, takclos:near, ask:near, askq:near
  546.     extrn    assign:near, sgoto:near, screinp:near, ifcmd:near, write:near
  547.     extrn    setinpbuf:near, shmem:near, replay:near, atoi:near
  548.     extrn    katoi:near, com1port:near, com2port:near, com3port:near
  549.     extrn    com4port:near, popcmd:near, mprompt:near, locate:near
  550.     extrn    vfopen:near, vfread:near, decvar:near, incvar:near
  551.     extrn    fparse:near, setwidth:near, cnvlin:near, scmpause:near
  552.     extrn    sesdisp:near, getok:near, cntlsho:near
  553.  
  554.         assume  cs:code, ds:data, ss:_stack, es:nothing
  555.  
  556. START    PROC    FAR
  557.     mov    ax,data            ; initialize DS
  558.         mov    ds,ax
  559.     mov    psp,es            ; remember psp address
  560.     mov    ah,dosver        ; get DOS version number (word)
  561.     int    dos
  562.     xchg    ah,al            ; major version to ah
  563.     mov    dosnum,ax        ; remember dos version
  564.     cmp    ax,200h            ; earlier than DOS 2.0?
  565.     jge    start1            ; ge = no
  566.     mov    ah,prstr
  567.     mov    dx,offset erms34    ; complain
  568.     int    dos
  569.     push    psp            ; set up exit for DOS 1
  570.     xor    ax,ax            ; and the IP
  571.     push    ax            ; make return addr of psp:0 for DOS 1
  572.     ret                ; and return far to exit now
  573. start1:
  574.     call    memini            ; initialize our memory usage
  575.     mov    ah,setdma        ; set disk transfer address
  576.     mov    dx,offset buff
  577.     int    dos
  578.     call    far ptr setint        ; ^C, DOS critical error interrupts
  579.     mov    ah,gcurdsk        ; get current disk
  580.     int    dos
  581.     inc    al            ; make 1 == A (not zero)
  582.     mov    curdsk,al
  583.     mov    origd,al        ; remember original disk we started on
  584.     mov    si,offset orgdir     ; place for directory path w/o drive code
  585.     add    al,'A'-1        ; make al alphabetic disk drive again
  586.     mov    [si],al            ; put it into original path descriptor
  587.     inc    si
  588.     mov    byte ptr [si],':'    ; add drive specifier too
  589.     inc    si
  590.     mov    byte ptr [si],'\'    ; add root indicator as well
  591.     inc    si
  592.     mov    ah,gcd            ; get current directory (path really)
  593.     xor    dl,dl            ; use current drive
  594.     int    dos
  595.     call    getpath            ; get the path from the environment
  596.     call    gettsep            ; get thousands separator, t/date code
  597.     mov    ah,gswitch
  598.     xor    al,al            ; pick up switch character
  599.     int    dos
  600.     mov    slashc+1,dl
  601.     and    maxtry,3fh        ; limit # packet retries
  602.     call    getcsp            ; get comspec from environment
  603.     call    getssp            ; get shellspec from environment
  604.     call    getparm            ; read "KERMIT=" Environment line
  605.     jc    start1b            ; c = fatal error
  606.     xor    cl,cl            ; counter, starts at 0
  607. start1a:mov    bx,offset kerenv+6    ; append "<digit>="  to "KERMIT"
  608.     mov    [bx],cl            ; binary digit
  609.     inc    cl
  610.     add    byte ptr [bx],'0'    ; to ascii
  611.     mov    byte ptr [bx+1],'='    ; append equals sign
  612.     call    getparm            ; read "KERMITn=" Environment line
  613.     jc    start1b            ; c = fatal error
  614.     cmp    cl,9            ; done all digits?
  615.     jbe    start1a            ; be = no
  616.                     ;
  617.     call    scpini            ; initialize script routines
  618.     jc    start1b            ; c = fatal error
  619.     call    lclini            ; do local initialization
  620.     cmp    flags.extflg,0        ; exit now?
  621.     je    start2            ; e = no
  622. start1b:mov    ah,prstr        ; announce our premature exit
  623.     mov    dx,offset ermes5    ; can't complete initialization
  624.     int    dos
  625.     jmp    krmend            ; quit immediately
  626. start2:    mov    word ptr comand.cmrprs,offset krmend ; offset of reparse addr
  627.     mov    ax,cs            ; our current code segment
  628.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  629.     mov    comand.cmostp,sp    ; save for reparse too
  630.     call    gcmdlin            ; read command line
  631.     cmp    taklev,0        ; in a Take file?
  632.     jne    start3            ; ne = yes, skip help msg
  633.     mov    ah,prstr
  634.     mov    dx,offset machnam    ; display machine name
  635.     int    dos
  636.         mov    dx,offset verident    ; display version header
  637.         int    dos
  638.     mov    dx,offset copyright    ; display copyright notice
  639.     int    dos
  640.     mov    dx,offset hlpmsg
  641.     int    dos
  642. start3:    mov    patchena,' '        ; let patch level show
  643.     call    serrst            ; reset serial port (if active)
  644.     call    initibm            ; define IBM macro
  645.     call    rdinit            ; read kermit init file
  646.  
  647.  ; This is the main KERMIT loop.  It prompts for and gets the users commands
  648.  
  649. kermit:    mov    ax,ds
  650.     mov    es,ax            ; convenient safety measure
  651.     mov    dx,prmptr        ; get prompt string address
  652.     call    mprompt              ; set master reparse address to here
  653.     cmp    flags.cxzflg,'C'    ; did someone want out?
  654.     jne    kermt9            ; ne = no
  655. kermt8:    cmp    taklev,0        ; are we in a Take file?
  656.     je    kermt9            ; e = no, ignore the signal
  657.     call    takclos            ; close take file, release buffer
  658.     jmp    short kermt8        ; close any other take files
  659. kermt9:    mov    flags.cxzflg,0        ; reset each time
  660.     and    flags.remflg,not dserver ; turn off server mode bit
  661.     cmp    dosctty,0        ; is DOS using our comms line?
  662.     je    kermt1            ; e = no
  663.     and    flags.remflg,not(dquiet+dregular+dserial)
  664.     or    flags.remflg,dquiet    ; set display to quiet mode
  665.     call    serrst            ; close port so CTTY can run
  666. kermt1:    mov    dx,offset comtab
  667.     mov    bx,offset tophlp
  668.     cmp    flags.extflg,0        ; exit flag set?
  669.     jne    krmend            ; ne = yes, jump to KRMEND
  670.     mov    comand.cmcr,1        ; allow bare CR's
  671.         mov    ah,cmkey
  672.     mov    comand.impdo,1        ; allow implied "DO macro"
  673.     call    comnd
  674.     jc    kermt3            ; c = failure
  675.     mov    comand.impdo,0        ; only on initial keyword, not here
  676.     mov    comand.cmcr,0        ; no more bare CR's
  677.     call    bx                  ; call the routine returned in BX
  678.     jc    kermt3            ; c = failure
  679.     cmp    flags.extflg,0        ; exit flag set?
  680.     jne    krmend            ; ne = yes, jump to KRMEND
  681.     jmp    short kermt5        ; do idle loop cleanup
  682.  
  683. kermt3:    cmp    flags.cxzflg,'C'    ; got here via Control-C?
  684.     jne    kermt7            ; ne = no
  685.     cmp    flags.extflg,0        ; exit flag set?
  686.     jne    kermt5            ; ne = yes, skip msg, do cleanup
  687.     mov    dx,offset ermes3    ; say command not executed
  688.     mov    ah,prstr        ; print    the error message in dx
  689.     int    dos
  690. kermt5:    cmp    flags.cxzflg,'C'    ; user Control-C abort?
  691.     jne    kermt7            ; ne = no, do normal operations
  692.     cmp    taklev,0        ; in a Take file?
  693.     je    kermt7            ; e = no        
  694.     call    takclos            ; close take file, release buffer
  695.     jmp    short kermt5        ; close any other take files
  696. kermt7:    cmp    flags.extflg,0        ; exit flag set?
  697.     jne    krmend            ; ne = yes, exit
  698.     jmp    kermit            ; e = no, get next command
  699.  
  700. krmend:    mov    flags.cxzflg,0        ; reset each time
  701.     mov    flags.extflg,0
  702.     call    far ptr exmacro        ; find on_exit macro
  703.     jc    krmend2            ; c = not found
  704.                     ; perform ON_EXIT macro
  705. krmend1:cmp    taklev,0        ; finished with macros?
  706.     je    krmend2            ; e = yes
  707.     mov    dx,prmptr        ; get prompt string address
  708.     call    mprompt              ; set master reparse address to here
  709.     mov    flags.cxzflg,0        ; reset each time
  710.     and    flags.remflg,not dserver ; turn off server mode bit
  711.     mov    dx,offset comtab    ; keyword table
  712.     xor    bx,bx            ; no help
  713.         mov    ah,cmkey
  714.     mov    comand.impdo,1        ; allow implied "DO macro"
  715.     mov    comand.cmcr,1        ; allow bare CR's
  716.     call    comnd
  717.     jc    krmend2            ; c = failure
  718.     mov    comand.impdo,0        ; only on initial keyword, not here
  719.     call    bx            ; call the routine returned in BX
  720.     jnc    krmend1            ; nc = success, keep doing commands
  721.                     ; end of ON_EXIT macro processing
  722. krmend2:cmp    taklev,0        ; in a Take file?
  723.     je    krmend3            ; e = no        
  724.     call    takclos            ; close take file, release buffer
  725.     jmp    short krmend2        ; close any other take files
  726. krmend3:mov    bx,lclexit        ; addr of sys dependent exit routine
  727.     or    bx,bx            ; sys dependent routines want service?
  728.     jz    krmend4            ; z = no
  729.     call    bx            ; call it
  730.     jnc    krmend4            ; nc = close
  731.     jmp    kermit            ; c = do not close
  732. krmend4:call    serrst            ; just in case the port wasn't reset
  733.     call    clscpi            ; close log files
  734.     call    far ptr emsclose    ; close and return EMS memory
  735.     mov    dl,origd        ; original disk drive
  736.     dec    dl            ; want A == 0
  737.     mov    ah,seldsk        ; reset original disk just in case
  738.     int    dos
  739.     mov    dx,offset orgdir    ; restore original directory
  740.     mov    ah,chdir
  741.     int    dos
  742.     push    ds            ; save ds around these DOS calls
  743.     mov    ax,cs            ; compose full address of ^C routine
  744.     mov    ds,ax            ; segment is the code segment
  745.     mov    dx,offset in3ad        ; restore Control-C interrupt vector
  746.     mov    al,23H            ; interrupt 23H
  747.     mov    ah,setintv        ; set interrupt vector
  748.     int    dos            ; ah, that's better
  749.     mov    dx,offset ceadr        ; DOS's Critical Error handler
  750.     mov    al,24h            ; interrupt 24h
  751.     mov    ah,setintv        ; do replacement (put it back)
  752.     int    dos
  753.     pop    ds
  754.     call    cbrestore        ; restore state of Control-Break Chk
  755.     mov    ah,4cH            ; terminate process
  756.     mov    al,errlev        ; return error level
  757.     int    dos
  758.     ret
  759. START    ENDP
  760.  
  761. ; This is the 'EXIT' command.  It leaves KERMIT and returns to DOS
  762.  
  763. EXIT    PROC    NEAR
  764.     mov    ah,cmeol
  765.     call    comnd            ; get a confirm
  766.     jc    exit1            ; c = failure
  767.     mov    flags.extflg,1        ; set the exit-Kermit flag
  768. exit1:    ret
  769. EXIT    ENDP
  770. code    ends
  771.  
  772. code1    segment
  773.     assume    cs:code1
  774. exmacro    proc    far            ; perform on_exit() macro
  775.     push    bx
  776.     push    cx
  777.     push    si
  778.     mov    bx,offset mcctab    ; table of macro names
  779.     mov    cl,[bx]            ; number of names in table
  780.     xor    ch,ch
  781.     jcxz    exmacx            ; z = empty table, do nothing
  782.     inc    bx            ; point to length of first name
  783. exmac2:    mov    ax,[bx]            ; length of this name
  784.     cmp    ax,onexlen        ; length same as desired keyword?
  785.     jne    exmac3            ; ne = no, search again
  786.     mov    si,bx
  787.     add    si,2            ; point at first char of name
  788.     push    cx            ; save name counter
  789.     push    di            ; save reg
  790.     mov    cx,onexlen        ; length of name
  791.     mov    di,offset onexit+2    ; point at desired macro name text
  792.     push    es            ; save reg
  793.     push    ds
  794.     pop    es            ; make es use data segment
  795.     cld
  796.     repe    cmpsb            ; match strings
  797.     pop    es            ; need current si below
  798.     pop    di
  799.     pop    cx            ; recover saved regs
  800.     jne    exmac3            ; ne = no match
  801.     mov    onexit+2,0        ; change name to be invisible
  802.     mov    byte ptr [bx+2],0    ; change macro table name too
  803.     jmp    short exmac4        ; e = matched
  804. exmac3:    add    bx,ax            ; step to next name, add name length
  805.     add    bx,4            ; + count and def word ptr
  806.     loop    exmac2            ; try next name
  807. exmacx:    pop    si            ; no macro, fail
  808.     pop    cx
  809.     pop    bx
  810.     stc                ; say failure
  811.     ret
  812.  
  813. exmac4:    cmp    taklev,maxtak        ; room in Take level?
  814.     jge    exmacx            ; ge = no, exit with no action
  815.     inc    taklev            ; increment take level
  816.     add    takadr,size takinfo    ; make a new Take entry/macro
  817.     mov    bx,takadr        ; point to current macro structure
  818.     mov    ax,ds            ; text is in our data seg
  819.     mov    [bx].takbuf,ax        ; seg of definition string struc
  820.     mov    [bx].takptr,offset onexit+2 ; where to read next command char
  821.     mov    [bx].takcnt,onexlen    ; number of chars in definition
  822.     mov    [bx].takargc,0        ; store macro argument count
  823.     mov    [bx].taktyp,0ffh    ; flag as a macro
  824.     pop    si
  825.     pop    cx
  826.     pop    bx
  827.     clc                ; say success
  828.     ret
  829. exmacro    endp
  830.  
  831. ; Close and return EMS memory, uses emsrbhandle and emsgshandle
  832. emsclose proc    far
  833.     mov    ah,45h            ; release handle and memory
  834.     mov    dx,emsrbhandle        ; handle
  835.     or    dx,dx            ; is handle valid (not -1)?
  836.     jl    emsclose1        ; l = no
  837.     int    67h            ; ems interrupt
  838. emsclose1:mov    emsrbhandle,-1
  839.     mov    ah,45h            ; release handle and memory
  840.     mov    dx,emsgshandle        ; handle
  841.     or    dx,dx            ; is handle valid (not -1)?
  842.     jl    emsclose2        ; l = no
  843.     int    67h            ; ems interrupt
  844. emsclose2:mov    emsgshandle,-1
  845.     ret
  846. emsclose endp
  847. code1    ends
  848.  
  849. code    segment
  850.     assume    cs:code
  851. ; TAKE commands    from a file, and allow a path name
  852. TAKE    PROC    NEAR
  853.     mov    kstatus,kssuc        ; global status, success
  854.     cmp    taklev,maxtak        ; at the limit?
  855.     jl    take1            ; l = no
  856.     mov    ah,prstr
  857.     mov    dx,offset erms30    ; complain
  858.     int    dos
  859.     stc                ; failure
  860.     ret
  861. take1:    mov    dx,offset tmpbuf    ; work buffer
  862.     mov    tmpbuf,0
  863.     mov    bx,offset filmsg    ; Help in case user types "?"
  864.     mov    comand.cmkeep,1        ; keep file open
  865.     mov    ah,cmword        ; get file name
  866.     call    comnd
  867.     jc    take1a            ; c = failure
  868.     mov    ah,cmeol
  869.     call    comnd
  870.     jc    take1a            ; c = failure
  871.     mov    ax,offset tmpbuf    ; point to name again
  872.     cmp    tmpbuf,0        ; empty filespec?
  873.     jne    take2            ; ne = no
  874.     mov    ah,prstr
  875.     mov    dx,offset ermes1    ; say more parameters needed
  876.     int    dos
  877.     stc
  878. take1a:    ret
  879.                     ; TAKE2: enter with ax=filename ptr
  880. TAKE2:    call    spath            ; is it around?
  881.     jc    take3            ; no, go complain
  882.     mov    dx,ax            ; point to name from spath
  883.     mov    ah,open2        ; open file
  884.     xor    al,al            ; 0 = open for reading
  885.     cmp    dosnum,300h        ; at or above DOS 3?
  886.     jb    take2a            ; b = no, so no shared access
  887.     or    al,40h            ; open for reading, deny none
  888. take2a:    int    dos
  889.     jnc    take4            ; nc = opened ok, keep going
  890.     mov    ax,dx            ; recover filename pointer
  891. take3:    push    ax
  892.     mov    ah,prstr
  893.     mov    dx,offset erms31
  894.     int    dos
  895.     pop    ax
  896.     mov    dx,ax            ; asciiz file name
  897.     call    prtasz            ; display it
  898.     mov    kstatus,kstake        ; status, Take failed
  899.     clc                ; we've done all error displays
  900.     ret
  901.                     ; TAKE4: enter with ax=filename ptr
  902. TAKE4:    call    takopen            ; open take buffer in macro space
  903.     jc    take6            ; c = failure
  904.     push    bx
  905.     mov    bx,takadr        ; get current frame ptr
  906.     mov    [bx].takhnd,ax        ; save file handle
  907.     mov    [bx].taktyp,0feh     ; mark as 2.0 file handle
  908.     pop    bx
  909.     cmp    flags.takflg,0        ; echoing Take files?
  910.     je    take5            ; e = no
  911.     mov    ah,prstr
  912.     mov    dx,offset crlf
  913.     int    dos
  914. take5:    call    takrd            ; get a buffer full of data
  915.     clc                ; success
  916. take6:    ret
  917. TAKE    ENDP
  918.  
  919. TAKRD    PROC    NEAR
  920.     push    ax
  921.     push    bx
  922.     push    cx    
  923.     push    dx
  924.     mov    bx,takadr
  925.     cmp    [bx].taktyp,0feh    ; get type of take (file?)
  926.     jne    takrd1            ; ne = no, do not read from disk
  927.     mov    cx,tbufsiz-2        ; # of bytes to read
  928.     mov    ax,[bx].takbuf        ; segment of Take buffer
  929.     push    bx            ; save frame address
  930.     mov    bx,[bx].takhnd        ; file handle is stored here
  931.     push    ds            ; save ds
  932.     mov    ds,ax            ; set ds to Take buffer segment
  933.     mov    dx,2            ; ds:dx = buffer, skip count word
  934.     mov    ah,readf2        ; read file
  935.     int    dos
  936.     pop    ds
  937.     pop    bx            ; restore frame address
  938.     jnc    takrd2            ; nc = successful read
  939. takrd1:    xor    ax,ax            ; error, say zero bytes read
  940. takrd2:    mov    [bx].takcnt,ax        ; number of bytes read
  941.     mov    [bx].takptr,2        ; offset of first new character
  942.     pop    dx
  943.     pop    cx
  944.     pop    bx
  945.     pop    ax
  946.     ret
  947. TAKRD    ENDP
  948.  
  949. ; TAKE-QUIT  (STOP)  Exit all Take files immediately but gracefully
  950.  
  951. TAKEQIT PROC    NEAR
  952.     xor    ax,ax
  953.     mov    errlev,al        ; return value in ERRORLEVEL
  954.     mov    kstatus,ax        ; and in STATUS
  955.     mov    ah,cmline        ; get optional error value and msg
  956.     mov    bx,offset rdbuf+1
  957.     mov    rdbuf,'\'        ; in case the user did not specify
  958.     mov    dx,offset stophlp    ; help on numerical argument
  959.     mov    comand.cmcr,1        ; bare c/r's allowed
  960.     call    comnd
  961.     mov    comand.cmcr,0        ; restore normal state
  962.     jc    takqit3            ; c = failure
  963.     mov    ah,cmeol        ; confirm
  964.     call    comnd
  965.     jc    takqit3
  966.     mov    si,offset rdbuf
  967.     cmp    byte ptr [si+1],'\'    ; user specified?
  968.     jne    takqit1            ; ne = no, use ours
  969.     inc    si            ; yes, use theirs
  970. takqit1:call    katoi            ; convert to number in ax
  971.     jc    takqit2            ; c = not a number
  972.     mov    errlev,al        ; return value in ERRORLEVEL
  973.     mov    kstatus,ax        ; and in STATUS
  974. takqit4:lodsb                ; read a msg char
  975.     or    al,al            ; null terminator?
  976.     jz    takqit2            ; z = empty string
  977.     cmp    al,' '            ; leading white space?
  978.     je    takqit4            ; be = leading white space
  979.     dec    si            ; backup to non-white char
  980.     mov    di,si            ; msg pointer, convert in-place
  981.     call    cnvlin            ; convert braces and numbers
  982.     mov    dx,offset crlf
  983.     mov    ah,prstr
  984.     int    dos
  985.     mov    dx,si            ; message pointer
  986.     call    prtasz
  987. takqit2:xor    ch,ch
  988.     mov    cl,taklev        ; number of Take levels active
  989.     jcxz    takqit3            ; z = none
  990.     cmp    cmdlinetake,cl        ; have DOS level command line?
  991.     jae    takqit3            ; ae = yes, don't close it here
  992.     call    takclos            ; close current Take file
  993.     jmp    short takqit2        ; repeat until all are closed
  994. takqit3:clc                ; success
  995.     ret
  996. TAKEQIT    ENDP
  997.  
  998. ; put mskermit.ini onto take stack if it exists.  Just like
  999. ; the take command, except it doesn't read a filename
  1000.  
  1001. rdinit    proc    near            ; read Kermit init file
  1002.     mov    ax,offset ininm2    ; default name to try
  1003.     cmp    decbuf,0        ; alternate init file given?
  1004.     je    rdini1            ; ne = no
  1005.     mov    ax,offset decbuf    ; yes, use it
  1006.     call    take2            ; let Take do error msgs
  1007.     clc                ; force success
  1008.     ret
  1009. rdini1:    call    spath            ; is it around?
  1010.     jc    rdini2            ; no, ignore file
  1011.     mov    dx,ax            ; point to name from spath
  1012.     mov    ah,open2        ; open file
  1013.     xor    al,al            ; 0 = open for reading
  1014.     cmp    dosnum,300h        ; at or above DOS 3?
  1015.     jb    rdini1a            ; b = no, so no shared access
  1016.     or    al,40h            ; open for reading, deny none
  1017. rdini1a:int    dos
  1018.     jc    rdini2            ; c = no ini file found, ignore
  1019.     call    take4            ; use TAKE command to complete work
  1020.     clc                ; ignore errors
  1021. rdini2:    ret
  1022. rdinit    endp
  1023.  
  1024. ; Patcher.  Patch file, MSRxxx.PCH or MSKERMIT.PCH has the following format:
  1025.  
  1026. ; 301 \Xxxxx    Text to display upon successful patch load
  1027. ; ;301 for V3.01.  For xxxx, see below
  1028. ; ; optional comment lines may appear anywhere after the 1st
  1029. ; ; xxxx in 1st line = total paragraphs in memory image.  Use \X if hex.
  1030. ; DS:xxxx xx xx        ; optional comment.  DS (or CS) are case insensitive
  1031. ; CS:xxxx xx xx xx    ; locations must be 4 hex chars, contents must be 2
  1032. ;
  1033. ; The 1st xx is the original value of the 1st byte @seg:offset for comparison.
  1034. ; A 00 value says don't compare.  Subsequent xx's are replacement bytes.
  1035. ; CS & DS lines may be intermixed.  AS & BS segments may be used when some
  1036. ; external module sets words aseg & bseg to a seg-base.
  1037. ; This mechanism expects file msscmd.obj to be linked first.
  1038.  
  1039. PATCH    proc
  1040.     mov    dx,offset rdbuf        ; optional path prefix
  1041.     mov    rdbuf,0
  1042.     mov    bx,offset pathlp
  1043.     mov    ah,cmword
  1044.     call    comnd
  1045.     jc    patch1
  1046.     mov    ah,cmeol
  1047.     call    comnd
  1048.     jc    patch1
  1049.     xor    ax,ax
  1050.     xchg    al,patched        ; clear and test patched
  1051.     test    al,al
  1052.     jz    patch1            ; z = disabled or done
  1053.     xchg    ah,flags.takflg        ; clear take flag, don't echo patches
  1054.     mov    byte ptr temp,ah    ; but save it
  1055.     call    ptchr
  1056.     mov    al,byte ptr temp    ; restore take flag
  1057.     mov    flags.takflg,al
  1058.     jc    patch2            ; c = NG
  1059. patch1:    ret
  1060.  
  1061. patch2:    mov    dx,offset ermes8    ; Fatal error
  1062.     mov    ah,prstr
  1063.     int    dos
  1064.     jmp    krmend            ; force exit
  1065.  
  1066. ptchr:    mov    dx,offset rdbuf        ; optional path
  1067.     call    strlen            ; get length, if any
  1068.     jcxz    ptchr1            ; z = nothing
  1069.     mov    si,dx
  1070.     add    si,cx
  1071.     cmp    byte ptr [si-1],'\'    ; ends with path specifier?
  1072.     je    ptchr1            ; e = yes
  1073.     cmp    byte ptr [si-1],':'    ; or a drive specifier?
  1074.     je    ptchr1            ; e = yes
  1075.     mov    word ptr [si],'\'+0    ; add '\' + null
  1076. ptchr1:    mov    di,offset rdbuf+66    ; path goes here
  1077.     mov    si,offset rdbuf+140    ; filename goes here, discard
  1078.     mov    byte ptr [di],0        ; clear
  1079.     call    fparse            ; split optional path
  1080.     mov    si,offset ptchnam    ; add name of patch file
  1081.     push    di
  1082.     call    strcat
  1083.     mov    ax,di            ; setup filename pointer for rdini1
  1084.     call    rdini1        ; let rdini try to find it & do take stuff
  1085.     pop    di
  1086.     jnc    ptch1            ; nc = file msrxxx.pch was found
  1087.     mov    si,offset ptchnam2    ; try alternate name
  1088.     mov    byte ptr [di],0        ; insert terminator
  1089.     call    strcat            
  1090.     mov    ax,di            ; setup filename pointer for rdini1
  1091.     call    rdini1        ; let rdini try to find it & do take stuff
  1092.     jnc    ptch1            ; nc = file msrxxx.pch was found
  1093.     mov    dx,offset ermes7    ; say file not found
  1094.     mov    ah,prstr
  1095.     int    dos
  1096.     clc
  1097.     ret
  1098.  
  1099. ptch1:    mov    al,taklev        ; remember initial take level
  1100.     mov    tmpbuf,al        ; when it changes it is EOF & done
  1101.     mov    comand.cmcr,1        ; bare cr's ok, to prevent prserr @EOF
  1102.     call    ptchrl            ; read 1st line's 1st 'word'
  1103.     jc    ptch2            ; c = trouble
  1104.     jz    ptch3            ; z = EOF
  1105.     mov    si,offset tmpbuf+1
  1106.     xchg    ah,al            ; line length to ah for atoi
  1107.     xor    al,al
  1108.     call    atoi            ; convert version string to integer
  1109.     jc    ptch2            ; c = bad number, or none
  1110.     cmp    ax,version        ; does it match this version?
  1111.     je    ptch4            ; e = yes
  1112. ptch2:    mov    al,tmpbuf        ; if take level has changed,
  1113.     xor    al,taklev        ;  we're already out of patch file
  1114.     jnz    ptch3            ; nz = change in take level
  1115.     call    takclos            ; close patch file
  1116. ptch3:    mov    dx,offset ermes6
  1117.     mov    ah,prstr        ; issue warning msg
  1118.     int    dos
  1119.     clc
  1120.     ret
  1121.  
  1122. ptch4:    mov    dx,offset tmpbuf+1
  1123.     call    ptchrw            ; read 2nd "word", 1st line
  1124.     jc    ptch2            ; c = NG
  1125.     mov    si,offset tmpbuf+1
  1126.     call    katoi            ; convert 2nd "magic number"
  1127.     jc    ptch2            ; c = NG
  1128.     cmp    ax,totpar    ; is it the total paragraphs memini computed?
  1129.     jne    ptch2            ; ne = no
  1130.     mov    bx,offset buff    ; place to stash 1st lines patch/version msg
  1131.     xor    dx,dx
  1132.     mov    ah,cmline        ; read it
  1133.     call    comnd
  1134.  
  1135. ptch5:    call    ptchrl            ; read CS:xxxx or DS:xxxx
  1136.     jc    ptch6
  1137.     jz    ptch7            ; z = EOF
  1138.     cmp    ax,7            ; were 7 chars read?
  1139.     jne    ptch6            ; ne = no
  1140.     mov    si,offset tmpbuf+1
  1141.     and    word ptr[si],not 2020h    ; convert to upper case
  1142.     cld
  1143.     lodsb                ; get the seg char
  1144.     cmp    word ptr[si],':S'     ; S:, actually
  1145.     je    ptch8            ; e = ok
  1146. ptch6:    stc                ; error exit
  1147.     ret
  1148.  
  1149. ptch7:    mov    ah,prstr
  1150.         mov    dx,offset verident    ; display version header
  1151.         int    dos
  1152.     clc
  1153.     ret
  1154.  
  1155. ptch8:    push    ds
  1156.     pop    es
  1157.     mov    di,offset segstr
  1158.     mov    cx,lsegstr        ; search for seg char in segstr
  1159.     repne    scasb
  1160.     jne    ptch6            ; ne = not found
  1161.     sub    di,offset segstr+1    ; distance spanned
  1162.     shl    di,1            ; make a word index
  1163.     mov    bx,segtab[di]        ; bx = seg-base
  1164.     or    bx,bx            ; seg-base = 0, disabled for patching
  1165.     jz    ptch6            ; z = 0, no patching
  1166.     mov    word ptr[si],'X\'     ; put '\X' in front of hex for katoi
  1167.     call    katoi            ; convert location
  1168.     jc    ptch6            ; c= NG
  1169.     push    bx            ; save seg being patched
  1170.     push    ax            ; save location being patched
  1171.     mov    tmpbuf+64,0        ; clear replacement byte count
  1172. ptch9:    mov    dx,offset tmpbuf+4
  1173.     call    ptchrw            ; read replacement byte follwing '\X'
  1174.     jnc    ptch11            ; nc = OK
  1175. ptch10:    pop    ax            ; clean stack & error return
  1176.     pop    bx
  1177.     stc
  1178.     ret
  1179.  
  1180. ptch11:    or    ax,ax            ; EOL?
  1181.     jnz    ptch13            ; nz = no
  1182.     mov    si,offset tmpbuf+64
  1183.     cld
  1184.     lodsb                ; replacement byte count
  1185.     cmp    al,2            ; gotta be at least 2
  1186.     jb    ptch10            ; b = too few
  1187.     xor    ch,ch
  1188.     mov    cl,al            ; replacement count
  1189.     pop    di            ; patch location
  1190.     pop    es            ; patch segment
  1191.     lodsb                ; al = comparison byte
  1192.     or    al,al            ; key value to ignore comparison?
  1193.     jz    ptch12            ; z = 0, yes
  1194.     cmp    byte ptr es:[di],al     ; do read check on memory image
  1195.     jne    ptch6            ; ne = no match, fail now
  1196. ptch12:    dec    cx            ; adjust for comparison byte
  1197.     rep    movsb            ; make patch
  1198.     jmp    ptch5            ; loop to read next line
  1199.  
  1200. ptch13:    cmp    al,2            ; 2 chars req'd for replacement byte
  1201.     jne    ptch10            ; ne = bad
  1202.     mov    si,offset tmpbuf+2    ; convert it
  1203.     call    katoi
  1204.     jc    ptch10            ; c = bad number or none
  1205.     mov    si,offset tmpbuf+64    ; --> replacement byte counted string
  1206.     inc    byte ptr[si]        ; bump count
  1207.     mov    bl,[si]
  1208.     xor    bh,bh
  1209.     mov    byte ptr[si+bx],al    ; stash replacement byte
  1210.     jmp    short ptch9        ; loop for next byte
  1211.  
  1212. ptchrl:    mov    dx,offset crlf        ; read 1st word, next line to tmpbuf+1
  1213.     call    prompt
  1214.     mov    dx,offset tmpbuf+1
  1215.     call    ptchrw
  1216.     jc    ptchrb            ; c = NG
  1217.     mov    dl,tmpbuf
  1218.     xor    dl,taklev
  1219.     jz    ptchra            ; z = not EOF
  1220.     xor    ax,ax            ; set z flag for EOF
  1221.     ret
  1222.  
  1223. ptchra:    or    ax,ax            ; empty or comment line?
  1224.     jz    ptchrl            ; z = empty or comment, ignore
  1225. ptchrb:    ret
  1226.  
  1227. ptchrw:    mov    ah,cmword
  1228.     mov    comand.cmper,1    ; prohibit substitution variable expansion
  1229.     xor    bx,bx            ; 'help' ptr
  1230.     call    comnd            ; line length is in ax
  1231.     ret
  1232. PATCH    endp
  1233.  
  1234. ; Get command line into a Take macro buffer. Allow "-f filspec" to override
  1235. ; normal mskermit.ini initialization filespec, allow command "stay" to
  1236. ; suppress automatic exit to DOS at end of command line execution. [jrd]
  1237.  
  1238. gcmdlin    proc    near
  1239.     mov    cmdlinetake,0        ; flag for DOS command line Take
  1240.     mov    word ptr decbuf,0    ; storage for new init filename
  1241.     push    es
  1242.     cld
  1243.     mov    es,psp            ; address psp
  1244.     xor    ch,ch
  1245.     mov    cl,es:byte ptr[cline]    ; length of cmd line from DOS
  1246.     jcxz    gcmdl1            ; z = empty line
  1247.     mov    si,cline+1        ; point to actual line
  1248. gcmdl0:    cmp    byte ptr es:[si],' '    ; skip over leading whitespace
  1249.     ja    gcmdl2            ; a = non-whitespace
  1250.     inc    si
  1251.     loop    gcmdl0            ; fall through on all whitespace
  1252. gcmdl1:    jmp    gcmdl14            ; common exit jump point
  1253. gcmdl2:    inc    cx            ; include DOS's c/r
  1254.     call    takopen            ; open take buffer in macro space
  1255.     mov    bx,takadr
  1256.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  1257.     mov    [bx].takcnt,0        ; length of text
  1258.     mov    es,[bx].takbuf        ; segment of buffer, from takopen
  1259.     mov    di,2            ; skip count word
  1260.     push    psp
  1261.     pop    ds            ; DS = PSP
  1262.     xor    dx,dx            ; clear brace count
  1263. gcmdl3:    or    cx,cx            ; anything left?
  1264.     jle    gcmdl10            ; le = no
  1265.     lodsb                ; get a byte from PSP's command line
  1266.     dec    cx            ; one less char in input string
  1267.     cmp    al,','            ; comma?
  1268.     jne    gcmdl4            ; no, keep going
  1269.     or    dx,dx            ; inside braces?
  1270.     jnz    gcmdl9            ; nz = yes, retain embedded commas
  1271.     mov    al,cr            ; convert to cr
  1272.     jmp    short gcmdl9        ; store it
  1273. gcmdl4:    call    bracechk        ; check for curly braces
  1274.     jc    gcmdl9            ; c = found and counted brace
  1275.     or    dx,dx            ; outside braces?
  1276.     jnz    gcmdl9            ; nz = no, ignore flag
  1277.     cmp    al,'-'            ; starting a flag?
  1278.     jne    gcmdl9            ; ne = no
  1279.     mov    ah,[si]            ; get flag letter
  1280.     or    ah,20h            ; convert to lower case
  1281.     cmp    ah,'f'            ; 'f' for init file replacement?
  1282.     jne    gcmdl9            ; ne = no
  1283.     inc    si            ; accept flag letter
  1284.     dec    cx
  1285. gcmdl5:    or    cx,cx            ; anything to read?
  1286.     jle    gcmdl10            ; le = exhausted supply
  1287.     lodsb                ; get filespec char from psp
  1288.     dec    cx            ; one less char in source buffer
  1289.     cmp    al,' '            ; in whitespace?
  1290.     jbe    gcmdl5            ; be = yes, scan it off
  1291.     dec    si            ; backup to real text
  1292.     inc    cx
  1293.                     ; copy filspec to buffer decbuf
  1294.     push    es            ; save current destination pointer
  1295.     push    di            ;  which is in es:di (Take buffer)
  1296.     mov    di,data            ; set es:di to regular decbuf
  1297.     mov    es,di
  1298.     lea    di,decbuf        ; where filespec part goes
  1299.     mov    word ptr es:[di],0    ; plant safety terminator
  1300. gcmdl6:    lodsb                ; get filespec char
  1301.     dec    cx            ; one less available
  1302.     cmp    al,' '            ; in printables?
  1303.     jbe    gcmdl7            ; be = no, all done
  1304.     cmp    al,','            ; comma command separator?
  1305.     je    gcmdl7            ; e = yes, all done
  1306.     stosb                ; store filespec char
  1307.     or    cx,cx            ; any chars left?
  1308.     jg    short gcmdl6        ; g = yes
  1309. gcmdl7:    mov    byte ptr es:[di],0    ; end filespec on a null
  1310.     pop    di            ; recover destination pointer es:di
  1311.     pop    es
  1312. gcmdl8:    or    cx,cx            ; strip trailing whitespace
  1313.     jle    gcmdl10            ; le = nothing left
  1314.     lodsb
  1315.     dec    cx
  1316.     cmp    al,' '            ; white space?
  1317.     jbe    gcmdl8            ; be = yes, strip it
  1318.     cmp    al,','            ; at next command?
  1319.     je    gcmdl10            ; e = yes, skip our own comma
  1320.     dec    si            ; back up to reread the char
  1321.     inc    cx
  1322.     jmp    gcmdl3            ; read more command text
  1323.                     ; end of flag analysis
  1324. gcmdl9:    stosb                ; deposit most recent char
  1325. gcmdl10:or    cx,cx            ; anything left to read?
  1326.     jg    gcmdl3            ; g = yes, loop
  1327.                     ;
  1328.     mov    ax,data            ; restore segment registers
  1329.     mov    ds,ax
  1330.     mov    si,[bx].takbuf        ; get segment of Take buffer
  1331.     mov    es,si
  1332.     mov    si,2            ; skip count word
  1333.     mov    cx,di            ; current end pointer, (save di)
  1334.     sub    cx,si            ; current ptr minus start offset
  1335.     mov    [bx].takcnt,cx        ; chars in buffer so far
  1336.     mov    es:word ptr [0],cx    ; store count word
  1337.     xor    dx,dx            ; brace count
  1338.     or    cx,cx
  1339.     jg    gcmdl11            ; g = material at hand
  1340.     call    takclos            ; empty take file
  1341.     jmp    short gcmdl14        ; finish up
  1342.                     ; scan for command "stay"
  1343. gcmdl11:mov    ax,es:[si]        ; get 2 bytes, cx and si are set above
  1344.     inc    si            ; increment by only one char
  1345.     dec    cx
  1346.     call    bracechk        ; check for braces
  1347.     jc    gcmdl12            ; c = brace found
  1348.     cmp    al,' '            ; separator?
  1349.     jbe    gcmdl12            ; be = yes, keep looking
  1350.     cmp    al,','             ; comma separator?
  1351.     je    gcmdl12            ; e = yes
  1352.     or    dx,dx            ; within braces?
  1353.     jnz    gcmdl12            ; nz = yes, skip STAY search
  1354.     or    ax,2020h        ; convert to lower case
  1355.     cmp    ax,'ts'            ; first two letters of stay
  1356.     jne    gcmdl12            ; ne = no match
  1357.     mov    ax,es:[si+1]        ; next two letters (stay vs status)
  1358.     or    ax,2020h        ; convert to lower case
  1359.     cmp    ax,'ya'            ; same as our pattern?
  1360.     jne    gcmdl12            ; ne = no match
  1361.     add    si,3            ; char after "stay"
  1362.     sub    cx,3
  1363.                     ; check for separator or end of macro
  1364.     cmp    byte ptr es:[si],' '    ; next char is a separator?
  1365.     jbe    gcmdl13            ; be = yes, found correct match
  1366.     cmp    byte ptr es:[si],','    ; or comma separator?
  1367.     je    gcmdl13            ; e = yes
  1368.     or    cx,cx            ; at end of macro?
  1369.     jle    gcmdl13            ; yes, consider current match correct
  1370. gcmdl12:or    cx,cx            ; done yet? ("stay" not found)
  1371.     jg    gcmdl11            ; g = not yet, look some more
  1372.     mov    cmdlinetake,1        ; remember doing DOS cmd line Take
  1373.     mov    si,offset eexit        ; append command "exit"
  1374.     mov    cx,leexit        ; length of string "exit"
  1375.     add    [bx].takcnt,cx
  1376.     rep    movsb            ; copy it into the Take buffer
  1377. gcmdl13:mov    [bx].takptr,2        ; init buffer ptr
  1378.     mov    cx,[bx].takcnt        ; count of bytes in buffer
  1379.     mov    es:[0],cx        ; count of bytes in Take buffer
  1380. gcmdl14:pop    es
  1381.     ret
  1382. gcmdlin    endp
  1383.  
  1384. ; Curly brace checker. Examine (and preserve) char in AL. Count up/down
  1385. ; braces in dx because DS is unknown here
  1386. bracechk proc    near
  1387.     cmp    al,braceop        ; opening brace?
  1388.     jne    bracech1        ; ne = no
  1389.     inc    dx            ; count up braces
  1390.     stc                ; say brace seen
  1391.     ret
  1392. bracech1:cmp    al,bracecl        ; closing brace
  1393.     jne    bracech3        ; ne = no
  1394.     sub    dx,1            ; count down with sign
  1395.     jns    bracech2        ; ns = no underflow
  1396.     xor    dx,dx            ; don't go below zero
  1397. bracech2:stc                ; say brace detected
  1398.     ret
  1399. bracech3:clc                ; say brace not found
  1400.     ret
  1401. bracechk endp
  1402.  
  1403. ; Enter with ax pointing to file name.  Searches path for given file,
  1404. ; returns with ax pointing to whole name, or carry set if file can't be found.
  1405. SPATH    proc    near
  1406.     call    isfile            ; does it exist as it is?
  1407.     jc    spath0            ; c = no, prepend path elements
  1408.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1409.     jnz    spath0            ; nz = yes, not desired file
  1410.     clc
  1411.     ret
  1412. spath0:    push    es            ; save es around work
  1413.     push    bx
  1414.     push    si
  1415.     push    di
  1416.     mov    bx,ax            ; save filename pointer in bx
  1417.     mov    si,ax
  1418.     xor    dl,dl            ; no '\' seen yet
  1419.     cld
  1420. spath1:    lodsb
  1421.     cmp    al,2fh            ; contains fwd slash path characters?
  1422.     je    spath1a
  1423.     cmp    al,5ch            ; or backslash?
  1424.     jne    spath2            ; no, keep going
  1425. spath1a:mov    dl,1            ; remember we've seen them
  1426. spath2:    or    al,al
  1427.     jnz    spath1            ; copy name in
  1428.     or    dl,dl            ; look at flag
  1429.     jz    spath3            ; no path, keep looking
  1430.     jmp    short spath9        ; embedded path, fail
  1431.  
  1432. spath3:    call    skpath            ; search kermit's path
  1433.     jnc    spath8a            ; nc = located file
  1434.     mov    si,pthadr        ; offset of PATH= string in environment
  1435.     mov    es,psp
  1436.     mov    di,es:word ptr[env]    ; pick up environment segment
  1437.     mov    es,di
  1438. spath4:    cmp    byte ptr es:[si],0    ; end of PATH= string?
  1439.     je    spath9            ; e = yes, exit loop
  1440.     mov    di,offset decbuf+64    ; place to put name
  1441. spath5:    mov    al,byte ptr es:[si]    ; get a byte from environment string
  1442.     inc    si
  1443.     cmp    al,';'            ; end of this part?
  1444.     je    spath7            ; yes, break loop
  1445.     or    al,al            ; maybe end of string?
  1446.     jnz    spath6            ; nz = no, keep going
  1447.     dec    si            ; back up to null for later rereading
  1448.     jmp    short spath7        ; and break loop
  1449. spath6:    mov    byte ptr [di],al    ; else stick in dest string
  1450.     inc    di
  1451.     jmp    short spath5        ; and continue
  1452. spath7:    push    si            ; save this ptr
  1453.     mov    si,bx            ; this is user's file name
  1454.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  1455.     je    spath8            ; yes, don't put one in
  1456.     cmp    byte ptr [di-1],5ch    ; how about this one?
  1457.     je    spath8            ; yes, don't put it in
  1458.     mov    byte ptr [di],5ch    ; else add one
  1459.     inc    di
  1460. spath8:    lodsb                ; get filename character
  1461.     mov    byte ptr [di],al    ; copy filename char to output buffer
  1462.     inc    di
  1463.     or    al,al            ; end of string?
  1464.     jnz    spath8            ; nz = no, copy rest of name
  1465.     pop    si            ; restore postion in path string
  1466.     mov    ax,offset decbuf+64
  1467.     call    isfile            ; is it a file?
  1468.     jc    spath4            ; c = no, keep looking
  1469.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1470.     jnz    spath4            ; nz = yes
  1471. spath8a:pop    di
  1472.     pop    si
  1473.     pop    bx
  1474.     pop    es
  1475.     clc
  1476.     ret                ; return success (carry clear)
  1477. spath9:    mov    ax,bx            ; restore original filename pointer
  1478.     pop    di            ; restore regs
  1479.     pop    si
  1480.     pop    bx
  1481.     pop    es
  1482.     stc                ; no file found
  1483.     ret
  1484. spath    endp
  1485.  
  1486. ; Search Kermit's path for file. Return carry clear if found, else carry set.
  1487. ; Worker for spath above.
  1488. skpath    proc    near
  1489.     mov    si,seg kpath        ; Kermit's path
  1490.     mov    es,si
  1491.     mov    si,offset kpath
  1492.     mov    di,offset decbuf+64    ; place to put name
  1493. skpath1:mov    al,es:[si]        ; get a byte from string
  1494.     inc    si
  1495.     cmp    al,';'            ; end of this part?
  1496.     je    skpath3            ; yes, break loop
  1497.     or    al,al            ; maybe end of string?
  1498.     jnz    skpath2            ; nz = no, keep going
  1499.     dec    si            ; back up to null for later rereading
  1500.     jmp    short skpath3        ; and break loop
  1501. skpath2:mov    byte ptr [di],al    ; else stick in dest string
  1502.     inc    di
  1503.     jmp    short skpath1        ; and continue
  1504. skpath3:cld
  1505.     mov    si,bx            ; this is user's file name
  1506.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  1507.     je    skpath4            ; yes, don't put one in
  1508.     cmp    byte ptr [di-1],5ch    ; how about this one?
  1509.     je    skpath4            ; yes, don't put it in
  1510.     mov    byte ptr [di],5ch    ; else add one
  1511.     inc    di
  1512. skpath4:lodsb                ; get filename character
  1513.     mov    byte ptr [di],al    ; copy filename char to output buffer
  1514.     inc    di
  1515.     or    al,al            ; end of string?
  1516.     jnz    skpath4            ; nz = no, copy rest of name
  1517.     mov    ax,offset decbuf+64
  1518.     push    bx
  1519.     call    isfile            ; is it a file?
  1520.     pop    bx
  1521.     jnc    skpath5            ; nc = yes
  1522.     ret
  1523. skpath5:test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1524.     jnz    skpath6            ; nz = yes
  1525.     clc                ; report file found (AX as offset)
  1526.     ret
  1527. skpath6:stc                ; report failure
  1528.     ret
  1529. skpath    endp
  1530.  
  1531. ; Put Kermit's Enviroment Path indicator into string kpath
  1532. mkkpath    proc    near            
  1533.     mov    dx,offset rdbuf
  1534.     mov    word ptr rdbuf,0
  1535.     xor    bx,bx
  1536.     mov    ah,cmword        ; get port address number
  1537.     call    comnd
  1538.     jnc    mkkpath1        ; nc = success
  1539.     ret
  1540. mkkpath1:mov    cx,ax            ; get string length
  1541.     push    si
  1542.     push    di
  1543.     push    es
  1544.     mov    si,offset rdbuf        ; source
  1545.     mov    di,seg kpath        ; storage spot
  1546.     mov    es,di
  1547.     mov    di,offset kpath
  1548.     cld
  1549.     rep    movsb            ; copy
  1550.     mov    byte ptr es:[di],0    ; terminate
  1551.     pop    es
  1552.     pop    di
  1553.     pop    si
  1554.     ret
  1555. mkkpath    endp
  1556.  
  1557. ; Put offset of PATH= string in pthadr
  1558. getpath    proc    near
  1559.     push    bx
  1560.     push    cx
  1561.     push    dx
  1562.     mov    bx,offset pthnam    ; thing    to find
  1563.     mov    cx,pthlen        ; length of it
  1564.     mov    pthadr,0        ; init offset to zero
  1565.     call    getenv            ; get environment value
  1566.     mov    pthadr,dx
  1567.     pop    dx
  1568.     pop    cx
  1569.     pop    bx
  1570.     ret
  1571. getpath    endp
  1572.  
  1573. ; getcsp: copy COMSPEC= environment string into cmspbuf
  1574. ; getssp: copy SHELL=   environment string into shellbuf
  1575. getcsp    proc    near
  1576.     mov    bx,offset cmspnam    ; find COMSPEC=
  1577.     mov    cx,cmsplen        ; it's length
  1578.     mov    di,offset cmspbuf    ; where to store string
  1579.     jmp    short getccom        ; do common worker
  1580.  
  1581. getssp:    mov    bx,offset shellnam    ; find SHELL=
  1582.     mov    cx,shellen        ; it's length
  1583.     mov    di,offset shellbuf    ; where to store string
  1584.     
  1585. getccom:push    es
  1586.     call    getenv            ; get environment offset into dx
  1587.     mov    si,dx            ; address of COMSPEC= string
  1588.     mov    es,psp
  1589.     mov    bx,es:word ptr[env]    ; pick up environment address
  1590.     mov    es,bx
  1591.     push    ds            ; save ds
  1592.     push    ds            ; make ds point to environment seg
  1593.     push    es            ; make es point to data segment
  1594.     pop    ds
  1595.     pop    es
  1596.     cld
  1597. getcs1:    lodsb                ; get a byte from environment
  1598.     cmp    al,' '            ; space or less?
  1599.     jg    getcs2            ; g = no, keep copying
  1600.     xor    al,al            ; terminate string on spaces etc
  1601. getcs2:    stosb                ; store it in destination
  1602.     or    al,al            ; at end of string yet?
  1603.     jnz    getcs1            ; nz = no, keep copying
  1604.     pop    ds            ; recover ds
  1605.     pop    es
  1606.     ret
  1607. getcsp    endp
  1608.  
  1609. ; Get Kermit parameters from the Environment. Parameters are commands like
  1610. ; regular commands except they do not appear in the SET main table and are
  1611. ; separated from one another by semicolons. They appear after KERMIT=.
  1612. ; Do not allow Take/Macros to be created by any of these commands.
  1613. ; On fatal error exits with carry set and flags.extflg = 1
  1614. getparm    proc    near
  1615.     push    ax
  1616.     push    bx
  1617.     push    cx
  1618.     push    dx
  1619.     push    si
  1620.     push    di
  1621.     push    es
  1622.     mov    es,psp            ; segment of our PSP
  1623.     mov    ax,es:word ptr[env]    ; pick up environment address
  1624.     mov    es,ax
  1625.     mov    bx,offset kerenv    ; Environment word to find, asciiz
  1626.     mov    dx,bx
  1627.     call    strlen            ; length of its string to cx
  1628.     call    getenv            ; return dx = offset in environment
  1629.     jnc    getpar1            ; nc = success
  1630.     jmp    getpar9            ; c = not found
  1631. getpar1:push    ds            ; save regular DS
  1632.     push    dx            ; push Environment offset, then seg
  1633.     push    es
  1634.     call    takopen            ; open Take buffer in macro space
  1635.     jnc    getpar2            ; nc = success
  1636.     mov    flags.extflg,1        ; say exit now
  1637.     pop    es            ; clean stack
  1638.     pop    dx
  1639.     pop    ds
  1640.     jmp    getparx            ; exit with fatal error
  1641.  
  1642. getpar2:mov    bx,takadr        ; bx = Take data structure
  1643.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  1644.     mov    [bx].takcnt,0        ; length of text
  1645.     mov    es,[bx].takbuf        ; ES = segment of buffer, from takopen
  1646.     mov    di,2            ; skip count word field for es:di
  1647.     pop    ds            ; pop Environment segment (was in ES)
  1648.     pop    si            ;  and seg, DS:SI is now Environment
  1649.     xor    cx,cx            ; line length counter
  1650. getpar3:lodsb                ; read an Environment character
  1651.     or    al,al            ; null (EOL)?
  1652.     jz    getpar5            ; z = yes, stop here
  1653.     cmp    al,';'            ; semicolon separator?
  1654.     jne    getpar4            ; ne = no
  1655.     mov    al,CR            ; replace semicolon with carriage ret
  1656. getpar4:stosb                ; store char in Take buffer
  1657.     inc    cx            ; count line length
  1658.     jmp    short getpar3        ; get more text, until a null
  1659.  
  1660. getpar5:mov    al,CR            ; terminate line, regardless
  1661.     stosb
  1662.     inc    cx            ; count terminator
  1663.     pop    ds            ; restore regular DS
  1664.     mov    [bx].takcnt,cx        ; chars in Take/macro buffer
  1665.     mov    es:[0],cx        ; store count byte
  1666.     mov    [bx].takptr,2        ; init buffer read ptr to first char
  1667.     jcxz    getpar8            ; z = nothing left, exit
  1668.                     ; parse each item as a command
  1669. getpar6:mov    comand.cmquiet,1    ; no screen display
  1670.     mov    dx,offset nulprmpt    ; set null prompt
  1671.     call    prompt
  1672.     cmp    flags.extflg,0        ; exit flag set?
  1673.     jne    getpar8            ; ne = yes, exit this routine now
  1674.     mov    dx,offset initab    ; table of initialization routines
  1675.     xor    bx,bx            ; no explict help text
  1676.     mov    comand.cmcr,1        ; allow bare CR's
  1677.     mov    comand.impdo,0        ; do not search Macro table
  1678.         mov    ah,cmkey        ; match a keyword
  1679.     call    comnd
  1680.     jc    getpar7            ; c = failure
  1681.     mov    comand.cmcr,0        ; no more bare CR's
  1682.     call    bx            ; call the routine returned in BX
  1683.                     ; ignore failures (carry bit set)
  1684. getpar7:cmp    taklev,0        ; finished Take file?
  1685.     je    getpar8            ; e = yes
  1686.     cmp    flags.extflg,0        ; exit flag set?
  1687.     je    getpar6            ; e = no, finish all commands
  1688.  
  1689. getpar8:call    takclos            ; close our take file, if open
  1690. getpar9:mov    flags.extflg,0        ; do not leave this flag set
  1691.     clc                ; clear for success
  1692. getparx:mov    comand.cmquiet,0    ; regular screen echoing
  1693.     pop    es
  1694.     pop    di
  1695.     pop    si
  1696.     pop    dx
  1697.     pop    cx
  1698.     pop    bx
  1699.     pop    ax
  1700.     ret
  1701. getparm    endp
  1702.  
  1703. ; Locate string variable in Environment
  1704. ; bx = variable to find (usually including =), cx = length of variable name.
  1705. ; Returns dx = offset within Environment of char following the name and
  1706. ; carry clear, else carry set and dx unchanged.
  1707. getenv    proc    near
  1708.     push    ax
  1709.     push    cx
  1710.     push    si
  1711.     push    di
  1712.     push    es
  1713.     mov    es,psp
  1714.     mov    ax,es:word ptr[env]    ; pick up environment address
  1715.     mov    es,ax
  1716.     xor    di,di            ; start at offset 0 in segment
  1717. geten1:    cmp    es:byte ptr [di],0    ; end of environment?
  1718.     je    geten3            ; yes, forget it
  1719.     push    cx            ; save counter
  1720.     push    di            ; and offset
  1721.     mov    si,bx
  1722.     cld
  1723.     repe    cmpsb            ; search for name
  1724.     pop    di
  1725.     pop    cx            ; restore these
  1726.     je    geten2            ; found it, break loop
  1727. getenv5:push    cx            ; preserve again
  1728.     mov    cx,0ffffh        ; bogus length
  1729.     xor    al,al            ; 0 = marker to look for
  1730.     repne    scasb            ; search for it
  1731.     pop    cx            ; restore length
  1732.     jmp    short geten1        ; loop thru rest of environment
  1733. geten2:    add    di,cx            ; skip to definition
  1734. geten6:    mov    si,bx            ; name
  1735.     add    si,cx            ; length
  1736.     cmp    byte ptr [si-1],'='    ; caller wanted '=' as last char?
  1737.     je    geten7            ; e = yes, and we found it
  1738.     mov    al,es:[di]        ; get next char
  1739.     cmp    al,'='            ; at the equals sign?
  1740.     je    geten7            ; e = yes
  1741.     inc    di            ; point at next char
  1742.     cmp    al,' '            ; white space?
  1743.     jbe    geten6            ; be = yes, skip over this
  1744.     dec    di            ; backup
  1745.     jmp    short getenv5        ; not a match, keep looking
  1746. geten7:    mov    dx,di            ; store offset of string
  1747.     clc                ; carry clear for success
  1748.     jmp    short geten4
  1749. geten3:    stc                ; carry set for failure
  1750. geten4:    pop    es
  1751.     pop    di
  1752.     pop    si
  1753.     pop    cx
  1754.     pop    ax
  1755.     ret
  1756. getenv    endp
  1757.  
  1758. ; Get thousands separator from DOS Country Information
  1759. gettsep    proc    near
  1760.     mov    ah,38h            ; Get Country Information
  1761.     mov    dx,offset tmpbuf    ; temp buffer
  1762.     int    dos
  1763.     mov    bx,7            ; assume DOS 3+ position in buffer
  1764.     cmp    byte ptr dosnum+1,3    ; DOS 3 or above?
  1765.     jae    gettse1            ; ae = yes
  1766.     mov    bx,4            ; for DOS 2.1
  1767.     cmp    dosnum,210h        ; earlier than version 2.1?
  1768.     jae    gettse1            ; ae = no
  1769.     mov    al,','            ; use comma for old DOS's
  1770. gettse1:mov    al,tmpbuf[bx]        ; get thousands separator char
  1771.     mov    thsep,al        ; save it
  1772.     mov    al,tmpbuf        ; get time/date format code
  1773.     mov    tdfmt,al        ; save it
  1774.     ret
  1775. gettsep    endp
  1776.  
  1777. STAY    PROC    NEAR
  1778.     clc
  1779.     ret
  1780. STAY    ENDP
  1781.  
  1782. CLS    proc    near            ; Clear command level screen
  1783.     mov    ah,cmeol        ; get a confirmation
  1784.     call    comnd
  1785.     jc    cls1            ; c = failure
  1786.     call    cmblnk            ; blank the screen
  1787.     call    locate            ; put cursor at home position
  1788. cls1:    ret
  1789. CLS    endp
  1790.  
  1791. COMNT    PROC    NEAR            ; COMMENT command
  1792.     mov    ah,cmline
  1793.     mov    bx,offset tmpbuf
  1794.     xor    dx,dx
  1795.     call    comnd
  1796.     jc    comnt1
  1797.     mov    ah,cmeol
  1798.     call    comnd
  1799. comnt1:    ret
  1800. COMNT    ENDP
  1801.  
  1802. ; change working directory
  1803. cwdir    proc    near
  1804.     mov    kstatus,kssuc        ; global status
  1805.     mov    ah,cmword
  1806.     mov    dx,offset tmpbuf
  1807.     mov    bx,offset pthmsg
  1808.     mov    word ptr tmpbuf,0
  1809.     call    comnd            ; get drive/dir spec, if any
  1810.     mov    ah,cmeol
  1811.     call    comnd
  1812.     jnc    cwd1
  1813.     ret                ; c = failure
  1814. cwd1:    mov    si,offset tmpbuf    ; cdsr wants drive/path ptr in si
  1815.     call    cdsr            ; common CD sub-routine
  1816.     jnc    cwd2            ; nc = success
  1817.     mov    kstatus,ksgen        ; global status for unsuccess
  1818. cwd2:    cmp    taklev,0        ; in a Take file or macro?
  1819.     je    cwd3            ; e = no, do echo
  1820.     cmp    flags.takflg,0        ; ok to echo?
  1821.     je    cwd4            ; e = no
  1822. cwd3:    push    dx
  1823.     mov    dx,offset crlf        ; msgs from cdsr don't include this
  1824.     mov    ah,prstr        ; so let's do it now
  1825.     int    dos
  1826.     pop    dx
  1827.     call    prtasz            ; output current drive/path or err msg
  1828. cwd4:    clc
  1829.     ret
  1830. cwdir    endp
  1831.  
  1832. ; CDSR processes both CD & REM CD.  Entered with si --> drive/path, it returns
  1833. ; dx --> ASCIIZ current drive/path, w/carry clear, if successful, or error msg
  1834. ; w/carry set, if not.
  1835. CDSR    PROC
  1836.     mov    kstatus,kssuc        ; global status
  1837.     xor    cx,cx            ; 0 for default drive, if none
  1838.     cmp    byte ptr[si],ch        ; any drive/path?
  1839.     je    cdsr4            ; e = no, format current drive/path
  1840.     cmp    byte ptr[si+1],':'    ; is drive specified?
  1841.     jne    cdsr1            ; ne = no
  1842.     mov    cl,[si]            ; drive letter
  1843.     cmp    byte ptr[si+2],ch    ; any path?
  1844.     jne    cdsr1            ; ne = yes
  1845.     mov    word ptr[si+2],'.'    ; append dot+null as path to kludge DOS
  1846. cdsr1:    call    dskspace        ; test for drive, spec'd by cl, ready
  1847.     jnc    cdsr2            ; nc = ready
  1848.     mov    spcmsg3,cl        ; insert drive letter ret'd by dskspace
  1849.     mov    dx,offset spcmsg2+2    ; in err msg.  dx --> msg w/o cr,lf
  1850.     mov    kstatus,ksgen        ; global status
  1851.     ret                ; carry is set
  1852.  
  1853. cdsr2:    mov    dx,si            ; where chdir wants it
  1854.     mov    ah,chdir
  1855.     int    dos
  1856.     jnc    cdsr3            ; nc = success
  1857.     mov    dx,offset ermes4    ; ret carry set, dx --> err msg
  1858.     ret
  1859.  
  1860. cdsr3:    mov    dl,cl            ; uc drive letter ret'd by dskspace
  1861.     sub    dl,'A'            ; A = 0 for seldsk
  1862.     mov    ah,seldsk
  1863.     int    dos
  1864.     inc    dl            ; A = 1 for curdsk
  1865.     mov    curdsk,dl
  1866. cdsr4:    push    si            ; use caller's buffer for cur dr/path
  1867.     mov    ax,':@'            ; al = 'A' - 1, ah = ':'
  1868.     add    al,curdsk        ; al = drive letter
  1869.     mov    [si],ax            ; stash drive:
  1870.     inc    si
  1871.     inc    si
  1872.     mov    byte ptr[si],'\'    ; add \
  1873.     inc    si
  1874.     mov    ah,gcd            ; gcd fills in path as ASCIIZ
  1875.     xor    dl,dl            ; use current drive
  1876.     int    dos
  1877.     pop    dx            ; return caller's buffer pointer in dx
  1878.     clc
  1879.     ret
  1880. CDSR    ENDP
  1881.  
  1882. ; Erase specified file(s). Add protection of ignore hidden, subdir, volume
  1883. ; label and system files. 9 Jan 86 [jrd]
  1884. DELETE    PROC    NEAR            ; includes paths and "?*" wildcards
  1885.     mov    kstatus,kssuc        ; global status
  1886.     mov    si,offset delcmd    ; del command
  1887.     mov    di,offset tmpbuf
  1888.     call    strcpy
  1889.     mov    dx,offset tmpbuf
  1890.     call    strlen            ; get its length
  1891.     add    di,cx            ; point at terminator
  1892.     mov    temp,di            ; remember starting spot
  1893.     mov    ah,cmline        ; get a line
  1894.     mov    bx,di            ; where to place the file spec
  1895.     mov    dx,offset filmsg    ; help message
  1896.     call    comnd
  1897.     jc    delet0            ; c = failure
  1898.     push    ax
  1899.     mov    ah,cmeol
  1900.     call    comnd
  1901.     pop    ax
  1902.     jc    delet0
  1903.     cmp    apctrap,0        ; disable from APC
  1904.     jne    delet0            ; ne = yes
  1905.     or    ax,ax            ; anything given?
  1906.     jnz    delet1            ; nz = yes
  1907.     mov    ah,prstr
  1908.     mov    dx,offset ermes1    ; say need something
  1909.     int    dos
  1910.     clc                ; say success
  1911. delet0:    mov    kstatus,ksgen        ; global status
  1912.     ret
  1913.  
  1914. delet1:    mov    di,temp            ; start of filespec
  1915.     xor    cl,cl            ; disk drive letter
  1916.     cmp    byte ptr [di+1],':'    ; drive specified?
  1917.     jne    delet2            ; ne = no
  1918.     mov    cl,[di]            ; get drive letter
  1919. delet2:    call    dskspace        ; compute space, get letter into CL
  1920.     jnc    delet3            ; nc = success
  1921.     mov    spcmsg3,cl        ; put drive letter in msg
  1922.     mov    dx,offset spcmsg2    ; error message
  1923.     call    prtasz
  1924.     mov    kstatus,ksgen        ; global status
  1925.     clc
  1926.     ret                ; and ignore this command
  1927. delet3:    mov    si,offset tmpbuf    ; del cmd
  1928.     jmp    crun            ; join run cmd from there
  1929. DELETE    ENDP
  1930.  
  1931. ; Space <optional drive letter>
  1932.  
  1933. CHKDSK    PROC    NEAR            ; Space command
  1934.     mov    kstatus,kssuc        ; global status
  1935.     mov    dx,offset tmpbuf    ; buffer
  1936.     mov    tmpbuf,0        ; init to null
  1937.     mov    bx,offset dskmsg    ; help message
  1938.     mov    ah,cmword        ; get optional drive letter
  1939.     call    comnd            ; ignore errors
  1940.     mov    ah,cmeol
  1941.     call    comnd
  1942.     jnc    chkdsk1            ; nc = success
  1943.     ret                ; failure
  1944. chkdsk1:mov    cl,tmpbuf        ; set drive letter
  1945.     call    dskspace        ; compute space, get letter into CL
  1946.     jnc    chkdsk2            ; nc = success
  1947.     and    cl,5fh            ; to upper case
  1948.     mov    spcmsg3,cl        ; insert drive letter
  1949.     mov    dx,offset spcmsg2    ; say drive not ready
  1950.     call    prtasz
  1951.     mov    kstatus,ksgen        ; global status
  1952.     clc
  1953.     ret
  1954.     
  1955. chkdsk2:mov    spcmsg1,cl        ; insert drive letter
  1956.     mov    di,offset tmpbuf    ; work space for lnout
  1957.     mov    word ptr[di],0a0dh    ; cr/lf
  1958.     mov    word ptr[di+2],'  '    ; add two spaces
  1959.     add    di,4
  1960.     call    lnouts            ; use thousands separator
  1961.     mov    si,offset spcmsg
  1962.     call    strcat            ; add text to end of message
  1963.     mov    dx,offset tmpbuf
  1964.     call    prtasz            ; print asciiz string
  1965.     clc
  1966.     ret
  1967. CHKDSK    ENDP
  1968.  
  1969. ; Compute disk free space (bytes) into long word dx:ax.
  1970. ; Enter with disk LETTER in CL (use null if current disk).
  1971. ; Returns uppercase drive letter in CL.
  1972. ; Returns carry set if drive access error. Changes AX, DX.
  1973.  
  1974. DSKSPACE PROC    NEAR
  1975.     mov    dl,cl            ; desired disk letter, or null
  1976.     or    dl,dl            ; use current disk?
  1977.     jnz    dskspa1            ; nz = no
  1978.     mov    ah,gcurdsk        ; get current disk
  1979.     int    dos
  1980.     add    al,'A'            ; make 0 ==> A
  1981.     mov    dl,al
  1982. dskspa1:and    dl,5fh            ; convert to upper case
  1983.     mov    cl,dl            ; return upper case drive letter in CL
  1984.     sub    dl,'A'-1        ; 'A' is 1, etc
  1985.     push    bx
  1986.     push    cx
  1987.     mov    ah,36h            ; get disk free space, bx=sect/cluster
  1988.     int    dos            ; dx:ax=sectors, cx=bytes/sector
  1989.     cmp    ax,0ffffh        ; error response?
  1990.     jne    dskspa2            ; ne = no
  1991.     pop    cx
  1992.     pop    bx
  1993.     stc                ; return error
  1994.     ret
  1995. dskspa2:mul    bx            ; sectors/cluster * clusters = sectors
  1996.     mov    bx,dx            ; save high word of sectors (> 64K)
  1997.     mul    cx            ; bytes = sectors * bytes/sector
  1998.     push    ax            ; save low word of bytes
  1999.     mov    ax,bx            ; recall sectors high word
  2000.     mov    bx,dx            ; save current bytes high word
  2001.     mul    cx            ; high word sectors * bytes/sector
  2002.     add    ax,bx            ; new high bytes + old high bytes
  2003.     mov    dx,ax            ; store high word in dx
  2004.     pop    ax            ; space is in dx:ax as a long word
  2005.     pop    cx
  2006.     pop    bx
  2007.     clc
  2008.     ret
  2009. DSKSPACE ENDP
  2010.  
  2011. ; Get directory    listing
  2012. DIRECT    PROC    NEAR
  2013.     mov    kstatus,kssuc        ; global status
  2014.     mov    si,offset dircmd    ; dir command
  2015.     mov    di,offset tmpbuf
  2016.     call    strcpy
  2017.     mov    dx,offset tmpbuf
  2018.     call    strlen            ; get its length
  2019.     add    di,cx            ; point at terminator
  2020.     mov    temp,cx            ; remember length
  2021.     mov    ah,cmline        ; parse with cmline to allow switches
  2022.     mov    bx,di            ; next available byte
  2023.     mov    dx,offset filmsg    ; help message 
  2024.     call    comnd
  2025.     jnc    direct1            ; nc = success
  2026. direct0:mov    kstatus,ksgen        ; global status
  2027.     ret                ; failure
  2028. direct1:mov    ah,cmeol
  2029.     call    comnd
  2030.     jc    direct0
  2031.     mov    word ptr [bx],0        ; plant terminator
  2032.     mov    cl,curdsk        ; current drive number ('A'=1)
  2033.     add    cl,'A'-1        ; make a letter
  2034.     mov    si,offset tmpbuf
  2035.     push    si
  2036.     add    si,temp            ; user's text after ' dir '
  2037.     cmp    byte ptr [si+1],':'    ; drive specified?
  2038.     jne    direct2            ; ne = no, use current drive
  2039.     mov    cl,[si]            ; get drive letter from buffer
  2040. direct2:call    dskspace        ; check for drive ready
  2041.     pop    si
  2042.     jnc    direct3            ; nc = drive ready
  2043.     mov    spcmsg3,cl        ; insert letter
  2044.     mov    dx,offset spcmsg2    ; say drive is not ready
  2045.     call    prtasz
  2046.     mov    kstatus,ksgen        ; global status
  2047.     stc
  2048.     ret
  2049. direct3:jmp    crun            ; join run cmd from there
  2050. DIRECT    ENDP
  2051.  
  2052. ; This is the 'HELP' command.  It gives a list of the commands
  2053.  
  2054. HELP    PROC    NEAR
  2055.     mov    kstatus,kssuc        ; global status
  2056.     mov    ah,cmeol
  2057.     call    comnd            ; get a confirm
  2058.     jnc    help1            ; nc = success
  2059.     ret                ; failure
  2060.  
  2061. help1:    push    ds            ; changing data segments!
  2062.     push    es
  2063.     mov    ax,ds
  2064.     mov    es,ax            ; for escchr
  2065.     mov    ax,data1        ; new data segment
  2066.     mov    ds,ax
  2067.     ; warning
  2068.     assume    ds:data1
  2069.     mov    ah,prstr        ; show Quick help summary screen
  2070.     mov    dx,offset qckhlp
  2071.     int    dos
  2072.     mov    ah,conout
  2073.     mov    dl,es:trans.escchr    ; get Kermit escape character
  2074.     add    dl,40h            ; convert to printable
  2075.     push    dx            ; save it for repeats below
  2076.     int    dos
  2077.     mov    ah,prstr
  2078.     mov    dx,offset qckhlp1    ; more help text
  2079.     int    dos
  2080.     mov    ah,conout
  2081.     pop    dx
  2082.     push    dx
  2083.     int    dos
  2084.     mov    ah,prstr
  2085.     mov    dx,offset qckhlp2    ; more help text
  2086.     int    dos
  2087.     pop    dx            ; recover current escape char
  2088.     mov    ah,conout
  2089.     int    dos
  2090.     mov    ah,prstr
  2091.     mov    dx,offset qckhlp3    ; end of help message
  2092.     int    dos
  2093.     mov    ah,coninq        ; get a keystroke, quietly
  2094.     int    dos
  2095.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  2096.     je    helpend            ; e = yes, quit now
  2097.     cmp    al,3
  2098.     je    helpend
  2099.     cmp    al,' '            ; space bar?
  2100.     je    help2            ; ne = no, skip second screen
  2101.     jmp    short helpend        ; switch data segments
  2102.  
  2103. help2:    mov    ah,prstr
  2104.     mov    dx,offset qckhlp4    ; more of help message
  2105.     int    dos
  2106.     mov    ah,coninq        ; get a keystroke, quietly
  2107.     int    dos
  2108.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  2109.     je    helpend            ; e = yes, quit now
  2110.     cmp    al,3
  2111.     je    helpend
  2112.     cmp    al,' '            ; space bar?
  2113.     je    help3            ; ne = no, skip second screen
  2114.     jmp    short helpend        ; switch data segments
  2115.  
  2116. help3:    mov    ah,prstr        ; show second Quick help summary
  2117.     mov    dx,offset qckhlp5
  2118.     int    dos
  2119.     mov    ah,coninq
  2120.     int    dos
  2121.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  2122.     je    helpend            ; e = yes, quit now
  2123.     cmp    al,3
  2124.     je    helpend
  2125.     cmp    al,'?'            ; query mark?
  2126.     je    helpquery        ; e = yes do main query help
  2127.     mov    ah,prstr
  2128.     mov    dx,offset qckhlp6
  2129.     int    dos
  2130.     mov    ah,coninq
  2131.     int    dos
  2132.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  2133.     je    helpend            ; e = yes, quit now
  2134.     cmp    al,3
  2135.     je    helpend
  2136.     cmp    al,'?'            ; query mark?
  2137.     je    helpquery        ; e = yes do main query help
  2138.     mov    ah,prstr
  2139.     mov    dx,offset qckhlp7
  2140.     int    dos
  2141. helpend:pop    es
  2142.     pop    ds            ; restore regular data seg data
  2143.     ; warning
  2144.     assume    ds:data
  2145.     clc
  2146.     ret
  2147. helpquery:
  2148.     pop    es
  2149.     pop    ds            ; restore regular data seg data
  2150.     ; warning
  2151.     assume    ds:data
  2152.     mov    ah,prstr        ; show help summary screen
  2153.     mov    dx,offset crlf        ; a few blank lines
  2154.     int    dos
  2155.     int    dos
  2156.     int    dos
  2157.     mov    dx,offset tophlp    ; show usual cryptic help
  2158.     int    dos
  2159. helpx:    clc
  2160.     ret
  2161. HELP    ENDP
  2162.  
  2163. ; the version command - print our version number
  2164. prvers    proc    near
  2165.     mov    kstatus,kssuc        ; global status
  2166.     mov    ah,cmeol
  2167.     call    comnd
  2168.     jc    prvers1            ; c = failure
  2169.     mov    ah,prstr
  2170.     mov    dx,offset crlf
  2171.     int    dos
  2172.     mov    ah,prstr
  2173.     mov    dx,offset machnam    ; display machine name
  2174.     int    dos
  2175.     mov    ah,prstr        ; display the version header
  2176.     mov    dx,offset verident
  2177.     int    dos
  2178.     clc
  2179. prvers1:ret
  2180. prvers    endp
  2181.  
  2182. ; SHOW command dispatcher
  2183. showcmd    proc    near
  2184.     mov    ah,cmkey
  2185.     mov    dx,offset shotab
  2186.     xor    bx,bx            ; no canned help
  2187.     call    comnd
  2188.     jc    showc1            ; c = failure
  2189.     jmp    bx            ; execute the handler
  2190. showc1:    ret                ; failure
  2191. showcmd    endp
  2192.  
  2193. ; the type command - type out a file
  2194. typec    proc    near
  2195.     mov    kstatus,kssuc        ; global status
  2196.     mov    si,offset typcmd    ; type command
  2197.     mov    di,offset tmpbuf
  2198.     call    strcpy
  2199.     mov    dx,offset tmpbuf
  2200.     call    strlen            ; get its length
  2201.     add    di,cx            ; point at terminator
  2202.     mov    temp,di            ; save place for later
  2203.     mov    ah,cmline        ; parse with cmline, allows | more
  2204.     mov    bx,di            ; next available byte
  2205.     mov    dx,offset filmsg    ; In case user wants help
  2206.     call    comnd
  2207.     jc    typec1            ; c = failure
  2208.     push    ax
  2209.     mov    ah,cmeol
  2210.     call    comnd
  2211.     pop    ax
  2212.     jc    typec1
  2213.     or    ax,ax            ; any text given?
  2214.     jnz    typec2            ; nz = yes
  2215.     mov    ah,prstr
  2216.     mov    dx,offset ermes1    ; say need more info
  2217.     int    dos
  2218.     mov    kstatus,ksgen        ; global status
  2219.     clc
  2220. typec1:    ret
  2221. typec2:    mov    byte ptr [bx],0        ; plant terminator
  2222.     mov    si,temp            ; start of filespec
  2223.     xor    cl,cl            ; say local drive
  2224.     cmp    byte ptr [si+1],':'    ; drive given?
  2225.     jne    typec3            ; ne = no
  2226.     mov    cl,[si]            ; get drive letter
  2227. typec3:    call    dskspace        ; check for drive ready
  2228.     jnc    typec4
  2229.     mov    spcmsg3,cl        ; put drive letter in msg
  2230.     mov    dx,offset spcmsg2    ; error message
  2231.     call    prtasz
  2232.     mov    kstatus,ksgen        ; global status
  2233.     clc
  2234.     ret                ; and ignore this command
  2235. typec4:    mov    si,offset tmpbuf
  2236.     jmp    short crun        ; join run cmd from there
  2237. typec    endp
  2238.  
  2239. ; PUSH to DOS (run another copy of Command.com or equiv)
  2240. ; entry fpush (fast push...) pushes without waiting for a confirm
  2241. dopush    proc    near
  2242.     mov    ah,cmeol
  2243.     call    comnd
  2244.     jnc    fpush            ; nc = success
  2245.     ret                ; failure
  2246. fpush:    mov    si,offset tmpbuf    ; a dummy buffer
  2247.     mov    byte ptr [si],0        ; plant terminator
  2248.     mov    dx,offset cmspbuf    ; always use command.com
  2249.     cmp    shellbuf,0        ; SHELL= present?
  2250.     je    crun4            ; e = no, use COMSPEC= name
  2251.     mov    dx,offset shellbuf    ; use SHELL= name
  2252.     jmp    short crun4        ; go run it
  2253.     stc
  2254.     ret
  2255. dopush    endp
  2256.  
  2257. ; Run a program from within Kermit
  2258. RUN    PROC    NEAR
  2259.     mov    ah,cmline        ; get program name and any arguments
  2260.     mov    bx,offset tmpbuf    ; place for user's text
  2261.     mov    dx,offset runmsg    ; In case user wants help
  2262.     call    comnd
  2263.     jnc    run1            ; nc = success
  2264.     ret                ; failure
  2265. run1:    cmp    apctrap,0        ; disable from APC
  2266.     je    run1a            ; e = no
  2267.     stc                ; yes, fail
  2268.     ret
  2269. run1a:    or    ax,ax            ; byte count
  2270.     jnz    run2            ; nz = have program name
  2271.     mov    ah,prstr        ; else complain
  2272.     mov    dx,offset ermes1    ; need more info
  2273.     int    dos
  2274.     clc
  2275.     ret
  2276. run2:    mov    si,offset tmpbuf    ; source of text
  2277.     mov    di,si
  2278.     call    cnvlin
  2279.     jmp    short crun
  2280. RUN    ENDP
  2281.  
  2282. ; crun - run an arbitrary program.    Rewritten by [jrd]
  2283. ; Enter with ordinary asciiz command in si (such as Dir *.asm)
  2284. ; Append a c/r and a null terminator and then ask command.com to do it
  2285. ; Set errlev with DOS errorlevel from subprocess.
  2286. CRUN    proc    near
  2287.     mov    ah,prstr        ; output crlf before executing comnd
  2288.     mov    dx,offset crlf        ; [lba]
  2289.     int    dos
  2290.     mov    di,offset tmpbuf    ; where to put full command line text
  2291.     cmp    si,di            ; same place?
  2292.     je    crun1            ; e = yes, don't copy ourself
  2293.     call    strcpy            ; si holds source text
  2294. crun1:    mov    si,offset slashc    ; DOS command begins with slashc area
  2295.     mov    dx,offset slashc+1    ; si points to /c part of command line
  2296.     call    strlen            ; get its length into cx
  2297.     push    bx
  2298.     mov    bx,dx
  2299.     add    bx,cx
  2300.     mov    byte ptr [bx],cr    ; end string with a c/r for dos
  2301.     inc    cx            ; count the c/r
  2302.     mov    byte ptr [bx+1],0    ; and terminate
  2303.     pop    bx
  2304.     mov    [si],cl            ; put length of argument here
  2305.     mov    dx,offset cmspbuf    ; always use command.com
  2306. crun4:    mov    exearg+2,si        ; pointer to argument string
  2307.     mov    exearg+4,ds        ; segment of same
  2308.     cmp    lclsusp,0        ; sys dependent routine to call
  2309.     je    crun5            ; e = none
  2310.     mov    bx,lclsusp        ; address to call
  2311.     push    dx            ; preserve name in dx
  2312.     call    bx            ; call sys dependent suspend routine
  2313.     pop    dx
  2314. crun5:    push    dx            ; preserve name in dx
  2315.     call    serrst            ; reset serial port (if active)
  2316.     call    cbrestore        ; restore state of Control-Break Chk
  2317.     pop    dx
  2318.     mov    es,psp            ; point to psp again
  2319.     mov    exearg+8,es        ; segment of psp, use our def fcb's
  2320.     mov    exearg+12,es        ; segment of psp, ditto, for fcb 2
  2321.     mov    ax,es:word ptr [env]    ; get environment ptr
  2322.     mov    exearg,ax        ; put into argument block
  2323.     mov    ax,ds
  2324.     mov    es,ax            ; put es segment back
  2325.     mov    bx,offset exearg    ; es:bx points to exec parameter block
  2326.     mov    ax,ss            ; save ss:sp
  2327.     mov    word ptr ssave+2,ax
  2328.     mov    word ptr ssave,sp
  2329.     xor    al,al            ; 0 = load and execute (DX has name)
  2330.     mov    ah,exec
  2331.     int    dos            ; go run command.com
  2332.     mov    bx,data            ; restore segment registers
  2333.     mov    ds,bx            ; reset data segment
  2334.     mov    es,bx            ; and extra segment
  2335.     cli
  2336.     mov    bx,word ptr ssave+2
  2337.     mov    ss,bx            ; and stack segment
  2338.     mov    sp,word ptr ssave    ; restore stack ptr
  2339.     sti
  2340.     jnc    crun9            ; nc = no error
  2341.     mov    ah,prstr        ; failure, complain
  2342.     mov    dx,offset erms37
  2343.     int    dos
  2344.     mov    dx,offset cmspbuf    ; path\name of command.com
  2345.     call    prtasz            ; asciiz
  2346.     mov    kstatus,ksgen        ; global status
  2347. crun9:    mov    ah,setdma        ; restore dma buffer pointer
  2348.     mov    dx,offset buff
  2349.     int    dos            ; restore dma address!!
  2350.     call    cboff            ; turn off DOS BREAK check
  2351.     cmp    lclrest,0        ; sys dependent routine to call?
  2352.     je    crun10            ; e = none
  2353.     mov    bx,lclrest        ; get routine's address
  2354.     call    bx            ; call sys dependent restore routine
  2355. crun10:    clc
  2356.     ret
  2357. CRUN    ENDP
  2358. code    ends
  2359.  
  2360. code1    segment
  2361.     assume    cs:code1 
  2362. ; Replace Int 23h and Int 24h with our own handlers
  2363. ; Revised to ask DOS for original interrupt vector contents, as suggested by
  2364. ; Jack Bryans. 9 Jan 1986 jrd
  2365. ; Modified again 30 August 1986 [jrd]
  2366. SETINT    PROC    FAR
  2367.     push    es            ; save registers
  2368.     mov    al,23H            ; desired interrupt vector (^C)
  2369.     mov    ah,getintv        ; Int 21H, function 35H = Get Vector
  2370.     int    dos            ; get vector in es:bx
  2371.     mov    in3ad,bx        ; save offset of original vector
  2372.     mov    in3ad+2,es        ;   and its segment
  2373.     mov    al,24h            ; DOS critical error, Int 24h
  2374.     mov    ah,getintv
  2375.     int    dos
  2376.     mov    word ptr ceadr,bx    ; DOS's Critical Error handler, offset
  2377.     mov    word ptr ceadr+2,es    ;  and segment address
  2378.     push    ds            ; save ds around next DOS calls
  2379.     mov    ax,seg intbrk        ; compose full address of ^C routine
  2380.     mov    ds,ax            ; segment is the code segment
  2381.     mov    dx,offset intbrk    ;   and offset is intbrk
  2382.     mov    al,23H            ; on ^C, goto intbrk
  2383.     mov    ah,setintv        ; set interrupt address from ds:dx
  2384.     int    dos
  2385.     mov    dx,offset dosce        ; replacement Critical Error handler
  2386.     mov    al,24h            ; interrupt 24h
  2387.     mov    ah,setintv        ; replace it
  2388.     int    dos
  2389.     pop    ds
  2390.     mov    ax,3300h        ; get state of Control-Break Check
  2391.     int    dos
  2392.     mov    orgcbrk,dl        ; save state here
  2393.     pop    es
  2394.     ret
  2395. SETINT    ENDP
  2396.  
  2397. ; Control Break, Interrupt 23h replacement
  2398. ; Always return with a Continue (vs Abort) condition since Kermit will cope
  2399. ; with failures. [jrd]
  2400. intbrk:    push ax
  2401.     push    ds    
  2402.     mov    ax,data            ; get Kermit's data segment
  2403.     mov    ds,ax
  2404.     mov    flags.cxzflg,'C'    ; say we saw a ^C
  2405.     mov    rstate,'E'
  2406.     mov    sstate,'E'
  2407.     pop    ds
  2408.     pop    ax
  2409.     iret               ; return to caller in a Continue condition
  2410.  
  2411. ; Kermit's DOS Critical Error Handler, Int 24h. [jrd]
  2412. ; Needed to avoid aborting Kermit with the serial port interrupt active and
  2413. ; the Control Break interrupt redirected. See the DOS Tech Ref Manual for
  2414. ; a start on this material; it is neither complete nor entirely accurate
  2415. ; The stack is the Kermit's stack, the data segment is unknown, interrupts
  2416. ; are off, and the code segment is Kermit's. Note: some implementations of
  2417. ; MS DOS may leave us in DOS's stack. Called by a DOS Int 21h function
  2418. dosce:    test    ah,80h        ; block device (disk drive)?
  2419.     jnz    dosce1        ; nz = no; serial device, memory, etc
  2420.     mov    al,3        ; tell DOS to Fail the Int 21h call
  2421.     iret            ; return to DOS
  2422. dosce1:    add    sp,6        ; pop IP, CS, Flags regs, from DOS's Int 24h
  2423.     pop    ax        ; restore original callers regs existing
  2424.     pop    bx        ;  just before doing Int 21h call
  2425.     pop    cx
  2426.     pop    dx
  2427.     pop    si
  2428.     pop    di
  2429.     pop    bp
  2430.     pop    ds
  2431.     pop    es        
  2432.     mov    al,0ffh        ; signal failure (usually) the DOS 1.x way
  2433.     push    bp        ; Kermit's IP, CS, and Flags are on the stack
  2434.     mov    bp,sp        ;  all ready for an iret, but first a word ..
  2435.     or    word ptr[bp+8],1 ; set carry bit, signals failure DOS 2+ way
  2436.     pop    bp        ; this avoids seeing the Interrupt flag bit
  2437.     iret            ; return to user, simulate return from Int 21h
  2438. code1    ends
  2439.  
  2440. code    segment
  2441.     assume    cs:code
  2442.  
  2443. ; Set DOS' Control-Break Check to off
  2444. cboff    proc    near
  2445.     mov    ax,3301h        ; set Control-Break Chk state
  2446.     xor    dl,dl            ; set state to off
  2447.     int    dos
  2448.     ret
  2449. cboff    endp
  2450.  
  2451. ; Restore DOS's Control-Break Check to startup value
  2452. cbrestore proc    near
  2453.     push    dx
  2454.     mov    ax,3301h        ; set Control-Break Chk state
  2455.     mov    dl,orgcbrk        ; restore state to startup value
  2456.     int    dos
  2457.     pop    dx
  2458.     ret
  2459. cbrestore endp
  2460.  
  2461. ISFILE    PROC    NEAR
  2462. ; Enter with ds:ax pointing at asciiz filename string
  2463. ; Returns carry set if the file pointed to by ax does not exist, else reset
  2464. ; Returns status byte, fstat, with DOS status and high bit set if major error
  2465. ; Does a search-for-first to permit paths and wild cards
  2466. ; Examines All kinds of files (ordinary, subdirs, vol labels, system,
  2467. ;  and hidden). Upgraded to All kinds on 27 Dec 1985. Revised 30 Aug 86 [jrd]
  2468. ; All registers are preserved
  2469.     push    bx
  2470.     push    ax
  2471.     mov    bx,ax
  2472.     mov    ax,[bx]
  2473.     and    ax,not 2020h        ; to upper
  2474.     cmp    ax,'UN'            ; look for DOS 5 NUL
  2475.     jne    isfil4            ; ne = mismatch
  2476.     mov    ax,[bx+2]
  2477.     and    al,not 20h
  2478.     cmp    ax,'L'+0
  2479.     jne    isfil4            ; ne = mismatch
  2480.     pop    ax
  2481.     pop    bx
  2482.     clc                ; say success
  2483.     ret
  2484. isfil4:    pop    ax
  2485.     pop    bx
  2486.     push    dx            ; save regs
  2487.     push    cx
  2488.     push    ax
  2489.     mov    byte ptr filtst.dta+21,0 ; clear old attribute bits
  2490.     mov    byte ptr filtst.fname,0    ; clear any old filenames
  2491.     mov    filtst.fstat,0        ; clear status byte
  2492.     mov     cx,3fH            ; look at all kinds of files
  2493.     mov    dx,offset filtst.dta    ; own own temporary dta
  2494.     mov    ah,setdma        ; set to new dta
  2495.     int    dos
  2496.     pop    dx            ; get ax (filename string ptr)
  2497.     push    dx            ; save it again
  2498.     mov    ah,first2        ; search for first
  2499.     int    dos
  2500.     pushf                ; save flags
  2501.     mov    dx,offset buff        ; reset dma
  2502.     mov    ah,setdma
  2503.     int    dos
  2504.     popf                ; recover flags
  2505.     jnc    isfil1            ; nc = file found
  2506.     mov    filtst.fstat,al        ; record DOS status
  2507.     cmp    al,2            ; just "File Not Found"?
  2508.     je    isfil2            ; e = yes
  2509.     cmp    al,3            ; "Path not found"?
  2510.     je    isfil2            ; e = yes
  2511.     cmp    al,18            ; "No more files"?
  2512.     je    isfil2            ; e = yes
  2513.     or    filtst.fstat,80h    ; set high bit for more serious error
  2514.     jmp    short isfil2    
  2515. isfil1:    cmp    byte ptr filtst.fname,0    ; did DOS fill in a name?
  2516.     je    isfil2            ; z = no
  2517.     clc
  2518.     jmp    short isfil3
  2519. isfil2:    stc                ; else set carry flag bit
  2520. isfil3:    pop    ax
  2521.     pop    cx
  2522.     pop    dx
  2523.     ret                ; DOS sets carry if file not found
  2524. ISFILE    ENDP
  2525.  
  2526. ; initialize memory usage by returning to DOS anything past the end of kermit
  2527. memini    proc    near
  2528.     push    es
  2529.     mov    bx,_TEXT
  2530.     sub    bx,psp
  2531.     mov    totpar,bx        ; save for patcher's magic number
  2532.     mov    es,psp            ; address psp segment again
  2533.     mov    bx,offset msfinal + 15    ; end of pgm + roundup
  2534.     mov    cl,4
  2535.     shr    bx,cl            ; compute # of paragraphs in last seg
  2536.     mov    ax,_STACK        ; last segment
  2537.     sub    ax,psp            ; minus beginning
  2538.     add    bx,ax            ; # of paragraphs occupied
  2539.     mov    ah,setblk
  2540.     int    dos
  2541.     pop    es
  2542.     jnc    memin1
  2543.     mov    dx,offset ermes2
  2544.     mov    ah,prstr
  2545.     int    dos            ; complain
  2546.     jmp    krmend            ; exit Kermit now
  2547. memin1:    pop    dx            ; save return address here
  2548.     mov    ax,_STACK        ; move SS down to DGROUP, adj SP
  2549.     sub    ax,DGROUP        ; paragraphs to move
  2550.     mov    cl,4            ; convert to bytes
  2551.     shl    ax,cl
  2552.     mov    bx,SP            ; current SP offset
  2553.     add    bx,ax            ; new SP, same memory cell
  2554.     mov    ax,bx
  2555.     sub    ax,400            ; top 400 bytes = Kermit
  2556.     mov    tcptos,ax        ; report this as TCP's top of stack
  2557.     mov    ax,DGROUP        ; new SS
  2558.     cli
  2559.     mov    SS,ax
  2560.     mov    SP,bx            ; whew!
  2561.     sti
  2562.     push    dx            ; push return address
  2563.     clc
  2564.     ret
  2565. memini    endp
  2566.  
  2567. ; Allocate memory.  Passed a memory size in ax, allocates that many
  2568. ; bytes (actually rounds up to a paragraph) and returns its SEGMENT in ax
  2569. ; The memory is NOT initialized.  Written by [jrd] to allow memory to
  2570. ; be allocated anywhere in the 1MB address space
  2571. sbrk    proc    near            ; K & R, please forgive us
  2572.     mov    bx,ax            ; bytes wanted
  2573.     add    bx,15            ; round up
  2574.     mov    cl,4
  2575.     shr    bx,cl            ; convert to # of paragraphs
  2576.     mov    cx,bx            ; remember quantity wanted
  2577.     mov    ah,alloc        ; DOS memory allocator
  2578.     int    dos
  2579.     jc    sbrkx            ; c = fatal
  2580.     cmp    cx,bx            ; paragraphs wanted vs delivered
  2581.     jb    sbrkx            ; b = not enough, fatal error
  2582.     ret                ; and return segment in ax
  2583. sbrkx:    mov    dx,offset mfmsg        ; assume not enough memory (ax = 8)
  2584.     cmp    ax,7            ; corrupted memory (ax = 7)?
  2585.     jne    sbrkx1            ; ne = no
  2586.     mov    dx,offset mf7msg    ; corrupted memory found
  2587. sbrkx1:    mov    ah,prstr
  2588.     int    dos
  2589.     jmp    krmend            ; exit Kermit now
  2590. sbrk    endp
  2591. code     ends
  2592.     end    start
  2593.