home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / mssker.asm < prev    next >
Assembly Source File  |  2020-01-01  |  109KB  |  3,558 lines

  1.     NAME    mssker
  2. ; File MSSKER.ASM
  3.     include mssdef.h
  4. ; Edit history
  5. ; 18 Jan 1995 version 3.14
  6. ; Last edit
  7. ; 18 Jan 1995
  8. ;****************************** Version 3.14 ***************************** 
  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.15 beta, Sept 97
  15. ;    MS-DOS Kermit Program Version 3.14, 18 Jan 95
  16. ;    MS-DOS Kermit Program Version 3.13, 8 July 93
  17. ;    MS-DOS Kermit Program Version 3.12, Feb 1992
  18. ;    MS-DOS Kermit Program Version 3.11, 6 Sept 1991
  19. ;    MS-DOS Kermit Program Version 3.10, 2 March 1991
  20. ;    MS-DOS Kermit Program Version 3.02, development for 3.10, 1990-91
  21. ;    MS-DOS Kermit Program Version 3.01, 20 March 1990
  22. ;    MS-DOS Kermit Program Version 3.00, 16 Jan 1990 
  23. ;    Kermit-MS Program Version 2.32, 11 Dec 1988 
  24. ;    Kermit-MS Program Version 2.31, 1 July 1988
  25. ;       Kermit-MS Program Version 2.30, 1 Jan 1988
  26. ;    Kermit-MS Program Version 2.29, 26 May 1986, plus later revisions.
  27. ;       Kermit-MS Program Version 2.27, December 6,1984
  28. ;       Kermit-MS Program Version 2.26, July 27, 1984
  29. ;       PC-Kermit Program Version 1.20, November 4, 1983
  30. ;       PC-Kermit Program Version 1.0, 1982
  31. ;       Based on the Columbia University KERMIT Protocol.
  32. ;    Copyright (C) 1982, 1997, Trustees of Columbia University in the 
  33. ;    City of New York.  The MS-DOS Kermit software may not be, in whole 
  34. ;    or in part, licensed or sold for profit as a software product itself,
  35. ;    nor may it be included in or distributed with commercial products
  36. ;    or otherwise distributed by commercial concerns to their clients 
  37. ;    or customers without written permission of the Office of Kermit 
  38. ;    Development and Distribution, Columbia University.  This copyright 
  39. ;    notice must not be removed, altered, or obscured.
  40. ;
  41. ;       Original Authors (versions 1.0 through 2.28):
  42. ;         Daphne Tzoar, Jeff Damens
  43. ;         Columbia University Center for Computing Activities
  44. ;         612 West 115th Street
  45. ;         New York, NY  10025
  46. ;
  47. ;       Present author (version 2.29, 2.30, 2.31, 2.32, 3.00, 3.01, 3.02,
  48. ;            3.10, 3.11, 3.12, 3.13, 3.14):
  49. ;         Joe R. Doupnik
  50. ;      Dept of EE, and CASS
  51. ;      Utah State University
  52. ;      Logan, UT  84322, USA
  53. ;      E-Mail: JRD@CC.USU.EDU (Internet), JRD@USU (BITNET)
  54. ; Special thanks to Christine Gianone, Frank da Cruz, Bill Catchings, 
  55. ; Bernie Eiben, Vace Kundakci, Terry Kennedy, Jack Bryans, and many many
  56. ; others for their help and contributions.
  57.  
  58.     public    dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
  59.     public    takrd, takadr, taklev, filtst, maxtry, dskspace, thsep, tdfmt
  60.     public    lclsusp, lclrest, lclexit, cwdir, kstatus, verident, cdsr
  61.     public    spath, patched, getenv, psp, dosctty, patchid, retcmd
  62.     public    tcptos, emsrbhandle, emsgshandle, apctrap, cboff, cbrestore
  63.     public    startup, cmdfile, inidir, tmpbuf, malloc, dostemp
  64.     public    breakcmd, xms, xmsrhandle, xmsghandle, xmsep
  65.  
  66. env    equ    2CH            ; environment address in psp
  67. cline    equ    80H            ; offset in psp of command line
  68. braceop    equ    7bh            ; opening curly brace
  69. bracecl    equ    7dh            ; closing curly brace
  70.  
  71. _STACK    SEGMENT                ; our stack
  72.     dw    1500 dup (0)        ; for TCP code
  73.     dw    200 dup(0)        ; for main Kermit code
  74. msfinal    label    word            ; top of stack
  75. _STACK    ENDS
  76.  
  77. data   segment
  78.     extrn    buff:byte, comand:byte, flags:byte, trans:byte,    prmptr:word
  79.     extrn    machnam:byte, decbuf:byte, rstate:byte, sstate:byte
  80.     extrn    mcctab:byte, rdbuf:byte, takeerror:byte, macroerror:byte
  81.     extrn    dos_bottom:byte, domath_ptr:word, domath_cnt:word
  82.     extrn    domath_msg:word, oldifelse:byte, retbuf:byte
  83.  
  84. verident label    byte
  85.     verdef
  86. patchena db    '$patch level'
  87. patchid    db    ' 0 $'
  88. copyright db    cr,lf
  89.     db    'Copyright (C) Trustees of Columbia University 1982, 1997.'
  90.     db    cr,lf,'$'
  91. copyright2 db    cr,lf,lf
  92.  db ' Copyright (C) 1982, 1997, Trustees of Columbia University in the'
  93.  db    cr,lf
  94.  db ' City of New York.  The MS-DOS Kermit software may not be, in whole' 
  95.  db    cr,lf
  96.  db ' or in part, licensed or sold for profit as a software product itself,'
  97.  db    cr,lf
  98.  db ' nor may it be included in or distributed with commercial products'
  99.  db    cr,lf
  100.  db ' or otherwise distributed by commercial concerns to their clients'
  101.  db    cr,lf
  102.  db ' or customers without written permission of the Office of Kermit' 
  103.  db    cr,lf
  104.  db ' Development and Distribution, Columbia University.  This copyright' 
  105.  db    cr,lf
  106.  db ' notice must not be removed, altered, or obscured.'
  107.  db    cr,lf,'$'
  108.  
  109. hlpmsg    db     cr,lf,'Type ? or HELP for help',cr,lf,'$'
  110. crlf    db      cr,lf,'$'
  111. patpmt    db    0
  112. ermes1    db    cr,lf,'?More parameters are needed$'
  113. ermes2    db    cr,lf,'?Unable to initialize memory$'
  114. ermes3  db      cr,lf,'?Command canceled$'
  115. ermes4    db    '?Unable to change directory',0            ; asciiz
  116. ermes5    db    cr,lf,'?Unable to complete initialization process$'
  117. ermes6    db    cr,lf,'Ignoring patch file.'
  118.     db    ' Version number mismatch.',cr,lf,'$'
  119. ermes7    db    cr,lf,'Patch file was not found',cr,lf,'$'
  120. ermes8    db    cr,lf,'Fatal error in patch file! Please remove PATCH '
  121.     db    'command.',cr,lf,'$'
  122. erms30    db    cr,lf,'?Passed maximum nesting level for TAKE command$'
  123. erms31    db    cr,lf,'?Cannot find Take-file: $'
  124. erms34    db    cr,lf,'This program requires DOS 2.0 or above$'
  125. erms37    db    cr,lf,'?Unable to execute command interpreter $'
  126. erms38    db    cr,lf,' Not an 8250 UART at this COM port$'
  127. erms39    db    cr,lf,' UART tests ok$'
  128. badnam    db    cr,lf,'?No such file(s)$'
  129.  
  130. ifdef    no_graphics
  131. nographics db    '  No graphics$'
  132. endif    ; no_graphics
  133. ifdef    no_network
  134. nonet    db    '  No network$'
  135. else
  136. ifdef    no_tcp
  137. notcp    db    '  No tcp/ip$'
  138. endif    ; no_tcp
  139. endif    ; no_network
  140.  
  141. ifdef    no_terminal
  142. noterm    db    '  No terminal$'
  143. endif    ; no_terminal
  144.  
  145. msgif    db    cr,lf,' IF extensions are ',0
  146. msggraph db    cr,lf,' Graphics is ',0
  147. msgtcpip db    cr,lf,' TCP/IP is ',0
  148. msgnetwork db    cr,lf,' Network is ',0
  149. msgterm    db    cr,lf,' Terminal emulation is ',0
  150. msgnot    db    'not ',0
  151. msgavail db    'available$',0
  152. xms    xmsreq <>            ; XMS request block
  153. data    ends
  154.  
  155. data1    segment
  156. filmsg    db    ' Filename$'
  157. dskmsg    db    ' disk drive letter or Return$'
  158. pthmsg    db    ' Name of new working directory and/or disk$'
  159. runmsg    db    ' program name and command line$'
  160. pathlp    db    ' optional path for file mskermit.pch$'
  161. stophlp    db    ' Status value to be returned  msg, nothing if no new value$'
  162. setenvhlp db    ' name=string  phrase to be put into DOS master environment$'
  163.  
  164. tophlp    db    cr,lf
  165.     db    '  Ask, Askq (read keybd to variable) '
  166.     db    '  Pause [secs], MPause/Msleep [millisec]'
  167.     db    cr,lf
  168.     db    '  APC text  send App Prog Cmd to host'
  169.     db    '  Pop, End (exit current macro/Take file)'
  170.     db    cr,lf
  171.     db    '  Bye      (logout remote server)    '
  172.     db    '  Push     (go to DOS, keep Kermit)'
  173.     db    cr,lf
  174.     db      '  C or Connect  (become a terminal)  '
  175.         db      '  Quit     (leave Kermit)'
  176.     db    cr,lf
  177.     db    '  Check (graphics, tcp/ip, networks) '
  178.         db      '  R or Receive  (opt local filename)'
  179.     db    cr,lf
  180.     db    '  Clear   (Input, comms recv buffer) '
  181.     db    '  Read (line from a file to variable)'
  182.     db    cr,lf
  183.     db    '  Close    (logging and script file) '
  184.     db    '  Reget    (get rest of a partial file)'
  185.     db    cr,lf
  186.     db    '  CLS (clear screen at command level)'
  187.     db    '  Reinput  (script Input, reread buffer)'
  188.     db    cr,lf
  189.     db    '  CWD or CD  (change dir &/or disk)  '
  190.     db    '  Remote   (prefix for commands)'
  191.     db    cr,lf
  192.     db    '  Decrement/Increment variable number'
  193.     db    '  Replay   (file through term emulator)'
  194.     db    cr,lf
  195.     db    '  Define/Assign   (a command macro)  '
  196.     db    '  Reset    (clock)'
  197.     db    cr,lf
  198.     db    '  Delete   (a file)                  '
  199.     db    '  Retrieve (get files, delete source) '
  200.     db    cr,lf
  201.     db    '  Dial     (phone number)            '
  202.     db    '  Return text (from macro to \v(return))'
  203.     db    cr,lf         
  204.     db    '  Directory (filepsec)               '
  205.     db    '  Run      (a program)'
  206.     db    cr,lf
  207.     db    '  Disable  (selected server commands)'
  208.         db      '  S, Send, Resend, Psend  local new-name'
  209.     db    cr,lf
  210.     db    '  Echo text (show line on screen)    '
  211.     db    '  Server [timeout] (become a server)'
  212.     db    cr,lf
  213.     db    '  Else     (follows IF statment)     '
  214.         db      '  Set      (most things)'
  215.     db    cr,lf
  216.     db    '  Enable   (selected server commands)'
  217.     db    '  Setenv   name=string to DOS environment'
  218.     db    cr,lf
  219.     db      '  EXIT     (leave Kermit)            '
  220.     db    '  Show     (most things)'
  221.     db    cr,lf
  222.     db    '  Finish   (to remote server)        '
  223.     db    '  Sleep time  (wait, no comms echos)'
  224.     db    cr,lf
  225.     db    '  For var start stop step {commands} '
  226.     db    '  Space    (free on current disk)'
  227.     db    cr,lf
  228.     db    '  Get      (remote file opt new name)'
  229.     db    '  Stop     (exit all Take files & macros)'
  230.     db    cr,lf
  231.     db    '  Getc  (read 1 byte from kbd to var)'
  232.     db    '  Switch index {:label, cmds,...}'
  233.     db    cr,lf
  234.     db    '  GetOK    (get Yes, OK, No response)'
  235.     db    '  Take     (commands from a file)'
  236.     db    cr,lf
  237.     db    '  Goto    (label, Take file or Macro)'
  238.     db    '  Telnet host port  NEW or RESUME'
  239.     db    cr,lf
  240.     db    '  Hangup   (drop DTR, hang up phone) '
  241.     db    '  Test COM1 ... COM4 (check for UART)'
  242.     db    cr,lf
  243.     db    '  If [not] <condition> <command>     '
  244.     db    '  Transmit filespec [prompt] (raw upload)'
  245.     db    cr,lf
  246.     db    '  I or Input [timeout] text (scripts)'
  247.     db    '  Type     (a file)'
  248.     db    cr,lf
  249.     db    '  INTRO  introduction to Kermit      '
  250.     db    '  Version  (show version and copyright)'
  251.     db    cr,lf
  252.     db    '  Log (Packet, Session, Transaction) '
  253.     db    '  Wait [timeout] on modem \cd \cts \dsr'
  254.     db    cr,lf
  255.     db    '  Mail     (file to host Mailer)     '
  256.     db    '  While <condition> {commands}'
  257.     db    cr,lf
  258.     db    '  Minput   (Input with many patterns)'
  259.     db    '  Write  FILE or log file   text'
  260.     db    cr,lf
  261.     db    '  Move    (send files, delete source)'
  262.     db    '  Undefine  (macro or array element)'
  263.     db    cr,lf
  264.     db    '  Open Read/Write/Append file        '
  265.     db    '  Xecho string  (without leading cr/lf)'
  266.     db    cr,lf
  267.     db    '  Output text      (to comms channel)'
  268.     db    '  Xif <condition> {cmds} ELSE {cmds}'
  269.     db    '$'
  270.  
  271. qckhlp    db    cr,lf
  272.     db    'MS-DOS Kermit 3.15, 15 Sept 1997, Copyright (C) 1982, 1995,'
  273.     db    cr,lf
  274.     db    'Trustees of Columbia University in the City of New York.'
  275.     db    cr,lf,lf
  276.     db    'Important commands (type the command, then press the'
  277.     db    ' Enter key):'
  278.     db    cr,lf,lf
  279.     db    '  INTRO    - For an introduction to MS-DOS Kermit.'
  280.     db    cr,lf
  281.     db    '  VERSION  - For version and copyright information.'
  282.     db    cr,lf
  283.     db    '  EXIT     - To leave MS-DOS Kermit.'
  284.     db    cr,lf,lf
  285.  
  286.     db    'Press the question-mark (?) key for context-sensitive'
  287.     db    ' help'
  288.     db    cr,lf
  289.     db    '  at any point within a command.'
  290.     db    cr,lf,lf
  291.  
  292.     db    'DOCUMENTATION:'
  293.     db    cr,lf
  294.  
  295.     db    '  "Using MS-DOS Kermit" by Christine M. Gianone,'
  296.     db    cr,lf
  297.     db    '  Digital Press / Butterworth-Heinemann, 1992, ISBN'
  298.     db    ' 1-55558-082-3.'
  299.     db    cr,lf
  300.       db    '  Please purchase this manual - it shows you how to use'
  301.     db    ' the software,'
  302.     db    cr,lf
  303.     db    '  it answers your questions, and its sales support the'
  304.     db    ' Kermit effort.'
  305.     db    cr,lf
  306.     db    '  To order, call +1 212 854-3703 or +1 800 366-2665.'
  307.     db    cr,lf,lf
  308.     
  309.     db    'And see these files on your Kermit diskette for additional'
  310.     db    ' information:'
  311.     db    cr,lf
  312.  
  313.     db    '  KERMIT.UPD - New features and updates.'
  314.     db    cr,lf
  315.  
  316.     db    '  KERMIT.BWR - Hints and tips, troubleshooting information,'
  317.     db    ' etc.'
  318.     db    cr,lf
  319.     db    '  KERMIT.HLP - Concise descriptions of each command.'
  320.     db    cr,lf,'$'
  321.  
  322. ifndef    no_terminal
  323. intrhlp    db cr,lf
  324.     db '                    Introduction to MS-DOS Kermit',cr,lf
  325.     db 'o An MS-Kermit command is a line of words separated by spaces and'
  326.     db ' ending with',cr,lf,'  a carriage return <the Enter key>.'
  327.     db '  Example: SET SPEED 2400<Enter>',cr,lf
  328.     db 'o Most words can be abbreviated and can be completed by pressing'
  329.     db ' the Esc key.',cr,lf
  330.     db '  Example: SET SPE 24<Enter>  or even  SET SPE<Esc> 24<Esc>'
  331.     db '<Enter>',cr,lf
  332.     db 'o Help (detailed, specific): press the "?" key where a word would'
  333.     db ' appear.',cr,lf
  334.     db 'o Edit lines using the Backspace key to delete characters,'
  335.     db ' Control-W to delete',cr,lf
  336.     db '  words, and Control-U to delete the line.  Control-C cancels the'
  337.     db ' command.',cr,lf
  338.     db 'o Frequently used MS-Kermit commands:',cr,lf
  339.     db '  EXIT           Leave the Kermit program. QUIT does the same'
  340.     db ' thing.',cr,lf
  341.     db '  SET            PORT, PARITY, SPEED, TERMINAL and many other'
  342.     db ' parameters.',cr,lf
  343.     db '  SHOW           Display groups of important parameters.'
  344.     db ' SHOW ? for categories.',cr,lf,lf
  345.     db '  CONNECT        Establish a terminal connection to a remote'
  346.     db ' system or a modem.',cr,lf
  347.     db '  Control-'
  348.         ; labels where Connect mode escape printable goes (twice)
  349. intrhlp1 db '  C    (Control-'
  350. intrhlp2 db ' '
  351.     db '  followed by "C")  Return to MS-Kermit> prompt.',cr,lf,lf
  352.     db '  SEND filename  Send the file(s) to Kermit on the other'
  353.     db ' computer.',cr,lf
  354.     db '  RECEIVE        Receive file(s), SEND them from Kermit on the'
  355.     db ' other computer.',cr,lf
  356.     db '  GET filename   Ask the remote Kermit server to send the file(s)'
  357.     db ' to us.',cr,lf
  358.     db '  FINISH         Shut down remote Kermit but stay logged into'
  359.     db ' remote system.',cr,lf
  360.     db '  BYE            FINISH and logout of remote system and exit'
  361.     db ' local Kermit.',cr,lf
  362.     db 'o Common startup sequence: SET SPEED 9600, CONNECT, login, start'
  363.     db ' remote Kermit,',cr,lf
  364.     db '  put it into Server mode, escape back with Control-C, transfer'
  365.     db ' files with',cr,lf
  366.     db '  SEND x.txt, GET b.txt, BYE.'
  367.  
  368.     db    cr,lf,lf
  369.     db ' MS-DOS Kermit commands, a functional summary:'
  370.     db    cr,lf
  371.     db    cr,lf,' Local file management:         '
  372.     db    'Kermit program management:'
  373.     db    cr,lf,'   DIR    (list files)          '
  374.     db    '  EXIT     (from Kermit, return to DOS)'
  375.     db    cr,lf,'   CD     (change directory)    '
  376.     db    '  QUIT     (same as EXIT)'
  377.     db    cr,lf,'   DELETE (delete files)        '      
  378.     db    '  TAKE     (execute Kermit commands from file)'
  379.     db    cr,lf,'   RUN    (a DOS command)       '
  380.     db    '  CLS      (clear screen)'
  381.     db    cr,lf,'   TYPE   (display a file)      '
  382.     db    '  PUSH     (enter DOS, EXIT returns to Kermit)'
  383.     db    cr,lf,'   SPACE  (show disk space)     '
  384.     db    '  Ctrl-C   (interrupt a command)'
  385.     db    cr,lf
  386.     db    cr,lf,' Communication settings:        '
  387.     db    'Terminal emulation:'
  388.     db    cr,lf,'   SET PORT, SET SPEED          '
  389.     db    '  CONNECT  (begin terminal emulation)'
  390.     db    cr,lf,'   SET PARITY                   '
  391.     db    '  HANGUP   (close connection)'
  392.     db    cr,lf,'   SET FLOW-CONTROL             '
  393.     db    '  Alt-X    (return to MS-Kermit> prompt)'
  394.     db    cr,lf,'   SET LOCAL-ECHO               '
  395.     db    '  SET KEY  (key mapping)'
  396.     db    cr,lf,'   SET ? to see others          '
  397.     db    '  SET TERMINAL TYPE, BYTESIZE, other parameters'
  398.     db    cr,lf,'   SHOW COMMUNICATIONS, MODEM   '
  399.     db    '  SHOW TERMINAL, SHOW KEY'
  400.     db    cr,lf
  401.     db    cr,lf,' File transfer settings:        '
  402.     db    cr,lf,'   SET FILE CHARACTER-SET name  '
  403.     db    '  SET TRANSFER CHARACTER-SET'
  404.     db    cr,lf,'   SET FILE TYPE TEXT, BINARY   '
  405.     db    '  SET SEND or RECEIVE parameters'
  406.     db    cr,lf,'   SET FILE ? to see others     '
  407.     db    '  SET WINDOWS (sliding windows)'
  408.     db    cr,lf,'   SHOW FILE                    '
  409.     db    '  SHOW PROTOCOL, SHOW STATISTICS'
  410.     db    cr,lf,lf
  411.     db    cr,lf,' Kermit file transfer:           '
  412.     db    'ASCII file transfer:'
  413.     db    cr,lf,'   SEND files (to RECEIVE)      '
  414.     db    '  LOG SESSION, CLOSE SESSION (download)'
  415.     db    cr,lf,'   RECEIVE    (from SEND)       '
  416.     db    '  TRANSMIT (upload)'
  417.     db    cr,lf,'   MAIL files (to RECEIVE)      '
  418.     db    '  SET TRANSMIT parameters'
  419.     db    cr,lf
  420.     db    cr,lf,' Using a Kermit server:         '
  421.     db    'Being a kermit server:'
  422.     db    cr,lf,'   GET files    (from server)   '
  423.     db    '  SET SERVER TIMEOUT or LOGIN'
  424.     db    cr,lf,'   SEND or MAIL   (to server)   '
  425.     db    '  ENABLE or DISABLE features'
  426.     db    cr,lf,'   REMOTE command (to server)   '
  427.     db    '  SERVER'
  428.     db    cr,lf,'   FINISH, LOGOUT, BYE          '
  429.     db    '  SHOW SERVER'
  430.     db    cr,lf
  431.     db    cr,lf,' Script programming commands:   '
  432.     db    cr,lf,'   INPUT, REINPUT secs text     '
  433.     db    '  :label, GOTO label'
  434.     db    cr,lf,'   OUTPUT text                  '
  435.     db    '  IF [ NOT ] condition command'
  436.     db    cr,lf,'   DECREMENT or INCREMENT variable number'
  437.     db    cr,lf,'   ASK or ASKQ variable prompt  '
  438.     db    '  OPEN READ (or WRITE or APPEND) file'
  439.     db    cr,lf,'   DEFINE variable or macro     '
  440.     db    '  READ variable-name'
  441.     db    cr,lf,'   ASSIGN variable or macro     '
  442.     db    '  WRITE file-designator text'
  443.     db    cr,lf,'   [ DO ] macro arguments       '
  444.     db    '  CLOSE READ or WRITE file or logfile'
  445.     db    cr,lf,'   ECHO text                    '
  446.     db    '  END or POP from macro or file'
  447.     db    cr,lf,'   PAUSE time                   '
  448.     db    '  STOP all macros and command files'
  449.     db    cr,lf,'   SLEEP time  no comms sampling'
  450.     db    '  WRITE file-designator text'
  451.     db    cr,lf,'   WAIT time modem-signals      '
  452.     db    '  SHOW VARIABLES, SHOW SCRIPTS, SHOW MACROS'
  453.     db    cr,lf
  454.     db ' Use "?" within comands for help on what fits that word.$'
  455. endif    ;; ifndef no_terminal
  456.  
  457. kpath    db    64 dup (0)        ; Kermit's paths to Kermit files
  458. data1    ends
  459.  
  460. data    segment
  461.  
  462. comtab  db    106 - 1            ; COMND tables
  463.     mkeyw    'APC',scapc
  464.     mkeyw    'Asg',assign        ; synonym
  465.     mkeyw    'Ask',ask
  466.     mkeyw    'Askq',askq
  467.     mkeyw    '_assign',hide_assign    ; hidden, expand destination name
  468.     mkeyw    'Assign',assign
  469.     mkeyw    'Break',breakcmd
  470.     mkeyw    'Bye',bye
  471.     mkeyw    'C',telnet
  472.     mkeyw    'CD',cwdir
  473.     mkeyw    'Clear',scclr
  474.     mkeyw    'Close',clscpt
  475.     mkeyw    'Check',check
  476.     mkeyw    'Comment',comnt
  477.     mkeyw    'Connect',telnet
  478.     mkeyw    'Continue',continue
  479.     mkeyw    'CLS',cls
  480.     mkeyw    'CWD',cwdir
  481.     mkeyw    'Declare',declare
  482.     mkeyw    '_define',hide_define    ; hidden, expand destination name
  483.     mkeyw    'Define',dodef
  484.     mkeyw    'Dec',decvar        ; decrement vs declare resolver
  485.     mkeyw    'Decrement',decvar
  486.     mkeyw    'Delete',delete
  487.     mkeyw    'Dial',dial
  488.     mkeyw    'Directory',direct
  489.     mkeyw    'Disable',srvdsa
  490.     mkeyw    'Do',docom
  491.     mkeyw    'Echo',scecho
  492.     mkeyw    'Else',elsecmd
  493.     mkeyw    'Enable',srvena
  494.     mkeyw    'End',popcmd
  495.     mkeyw    'Exit',exit
  496.     mkeyw    'Finish',finish
  497.     mkeyw    '_forinc',_forinc    ; hidden, FOR statement incrementer
  498.     mkeyw    'For',forcmd
  499.     mkeyw    'Forward',sforward    ; hidden "Forward" goto
  500.     mkeyw    'Get',get
  501.     mkeyw    'G',get            ; hidden synomym for Get
  502.     mkeyw    'Ge',get        ; ditto
  503.     mkeyw    'Getc',getc
  504.     mkeyw    'Getok',getok
  505.     mkeyw    'goto',sgoto
  506.     mkeyw    'H',help
  507.     mkeyw    'Hangup',dtrlow
  508.     mkeyw    'Help',help
  509.     mkeyw    'If',ifcmd
  510.     mkeyw    'I',scinp
  511.     mkeyw    'Increment',incvar
  512.     mkeyw    'Input',scinp
  513.     mkeyw    'INTRO',intro
  514.     mkeyw    'Local',localmac
  515.     mkeyw    'Log',setcpt
  516.     mkeyw    'Mail',mail
  517.     mkeyw    'Minput',scminput
  518.     mkeyw    'Move',move
  519.     mkeyw    'Mpause',scmpause
  520.     mkeyw    'Msleep',scmpause
  521.     mkeyw    'Open',vfopen
  522.     mkeyw    'O',scout        ; hidden synomym for OUTPUT
  523.     mkeyw    'Output',scout
  524.     mkeyw    'Pause',scpau
  525.     mkeyw    'Pop',popcmd
  526.     mkeyw    'Psend',psend
  527.     mkeyw    'Push',dopush
  528.     mkeyw    'Quit',exit
  529.     mkeyw    'R',read
  530.     mkeyw    'Read',vfread
  531.     mkeyw    'Receive',read
  532.     mkeyw    'Reget',reget
  533.     mkeyw    'Reinput',screinp
  534.     mkeyw    'Remote',remote
  535.     mkeyw    'Replay',replay
  536.     mkeyw    'Resend',resend
  537.     mkeyw    'Reset',reset
  538.     mkeyw    'Retrieve',retrieve
  539.     mkeyw    'Return',retcmd
  540.     mkeyw    'Run',run
  541.     mkeyw    'S',send
  542.     mkeyw    'Send',send
  543.     mkeyw    'Server',server
  544.     mkeyw    'Set',setcom
  545.     mkeyw    'Setenv',setenv
  546.     mkeyw    'Show',showcmd
  547.     mkeyw    'Sleep',scsleep
  548.     mkeyw    'Space',chkdsk
  549.     mkeyw    'Statistics',shosta
  550.     mkeyw    'Stay',stay
  551.     mkeyw    'Stop',takeqit
  552.     mkeyw    'Switch',switch
  553.     mkeyw    'Take',take
  554.     mkeyw    'Test',testcom
  555.     mkeyw    'Transmit',scxmit
  556.     mkeyw    'xmit',scxmit        ; hidden synonym
  557.     mkeyw    'Type',typec
  558.     mkeyw    'Undefine',undefine
  559.     mkeyw    'Version',prvers
  560.     mkeyw    'Wait',scwait
  561.     mkeyw    'While',whilecmd
  562.     mkeyw    'Write',write
  563.     mkeyw    'Xecho',xecho
  564.     mkeyw    'XIF',xifcmd
  565.     mkeyw    ':',comnt        ; script labels, do not react
  566.     mkeyw    'Patch',patch
  567.     mkeyw    'Nopush',pushproc    ; must be hidden
  568.  
  569.  
  570. ifdef    no_network
  571. shotab    db    19 - 2            ; SHOW keyword
  572. else
  573. ifndef    no_tcp
  574. shotab    db    19            ; SHOW keyword
  575. else
  576. shotab    db    19 - 1            ; SHOW keyword
  577. endif    ; no_tcp
  578. endif    ; no_network
  579.     mkeyw    'array',sharray
  580.     mkeyw    'Communications',shcom
  581.     mkeyw    'Control-prefixing',cntlsho
  582.     mkeyw    'File',shfile
  583.     mkeyw    'Key',shokey
  584.     mkeyw    'Logging',shlog
  585.     mkeyw    'Macros',shomac
  586.     mkeyw    'Memory',shmem
  587.     mkeyw    'Modem',shomodem
  588. ifndef    no_network
  589.     mkeyw    'Network',shownet
  590. endif    ; no_network
  591.     mkeyw    'Protocol',shpro
  592.     mkeyw    'Scripts',shscpt
  593.     mkeyw    'Server',shserv
  594. ifndef    no_tcp
  595.     mkeyw    'Sessions',sesdisp    ; TCP/IP
  596. endif    ; no_tcp
  597.     mkeyw    'Statistics',shosta
  598.     mkeyw    'Status',status
  599.     mkeyw    'Terminal',shterm
  600.     mkeyw    'Translation',shorx
  601.     mkeyw    'Variables',shovar
  602.                     ; Kermit initing from Environment
  603. nulprmpt db    0,0,0            ; null prompt
  604. initab    db    8            ; Environment phrase dispatch table
  605.     mkeyw    'INPUT-buffer-length',setinpbuf ; Script INPUT buffer length
  606.     mkeyw    'Rollback',setrollb    ; number of Terminal rollback screens
  607.     mkeyw    'Width',setwidth    ; columns in rollback buffer, def=80
  608.     mkeyw    'COM1',com1port
  609.     mkeyw    'COM2',com2port
  610.     mkeyw    'COM3',com3port
  611.     mkeyw    'COM4',com4port
  612.     mkeyw    'Path',mkkpath
  613.  
  614. featab    db    5        ; Compiled-in feature list for CHECK cmd
  615.     mkeyw    'if',5
  616.     mkeyw    'graphics',1
  617.     mkeyw    'networks',3
  618.     mkeyw    'tcp',2
  619.     mkeyw    'terminals',4
  620.  
  621. chktab    db    4        ; table of comm ports for TEST
  622.     mkeyw    'COM1',1
  623.     mkeyw    'COM2',2
  624.     mkeyw    'COM3',3
  625.     mkeyw    'COM4',4
  626.  
  627. patched    db    1        ; 1 = enable patching; 0 = disable or done
  628.  
  629.     even
  630. lclsusp    dw    0        ; address of routine to call when going to DOS
  631. lclrest    dw    0        ; address of routine to call when returning
  632. lclexit    dw    0        ; address of routine to call when exiting
  633. tcptos    dw    0        ; top of stack for TCP code
  634. ssave    dd    0        ; Original SS:SP when doing Command.com
  635. in3ad    dw    0,0        ; Original break interrupt addresses
  636. ceadr    dd    0        ; DOS Critical Error interrupt address
  637. orgcbrk    db    0        ; original Control-Break Check state
  638. psp    dw    0        ; segment of Program Segment Prefix
  639. exearg    dw    0        ; segment addr of environment (filled in below)
  640.     dd    0        ; ptr to cmd line (filled in below)
  641.     dw    5ch,0,6ch,0    ; our def fcb's; segment filled in later
  642. emsrbhandle dw    -1        ; EMS rollback handle, -1 means invalid
  643. emsgshandle dw    -1        ; EMS graphics handle, -1 means invalid
  644. xmsrhandle dw    0        ; XMS rollback buffer handle, 0 = invalid
  645. xmsghandle dw    0        ; XMS graphics memory buffer handle
  646. xmsep    dd    0        ; XMS manager entry point, 0 = invalid
  647. dosnum    dw    0        ; dos version number, major=low, minor=high
  648. dosctty    db    0        ; !=0 if DOS attempts using our comms line
  649. curdsk    db    0        ; Current disk
  650. origd    db    0        ; Original disk
  651. orgdir    db    64 dup (0)    ; original directory on original disk
  652. startup    db    64 dup (0)    ; our startup directory
  653. cmdfile db    64 dup (0)    ; path and file of last TAKE
  654. inidir    db    64 dup (0)    ; mskermit.ini directory (ends on \)
  655. taklev    db    0        ; Take levels
  656. takadr    dw    takstr-(size takinfo) ; Pointer into structure
  657. takstr    db    (size takinfo) * maxtak dup(0)
  658. cmdlinetake db    0        ; non-zero if have DOS command line cmds
  659. filtst    filest    <>        ; file structure for procedure isfile
  660. maxtry    db    defmxtry    ; Retry limit for data packet send/rcv
  661. ininm2    db    'MSKERMIT.INI',0 ; init file name
  662.  
  663. ifdef    nls_portuguese
  664. ptchnam    db    'MSRP315.PCH',0    ; Portuguese
  665. else
  666. ifdef    no_terminal
  667. ifdef    no_network
  668. ptchnam    db    'MSRL315.PCH',0    ; MSK Lite
  669. else
  670. ptchnam    db    'MSRN315.PCH',0    ; MSK medium-lite
  671. endif
  672. else
  673.  
  674. ifdef    no_network
  675. ptchnam    db    'MSRM315.PCH',0    ; MSK medium
  676. else
  677. ptchnam    db    'MSR315.PCH',0    ; main patch file name (Version dependent)
  678. endif
  679. endif
  680. endif
  681.  
  682. ptchnam2 db    'MSKERMIT.PCH',0 ; alternate patch file name
  683. delcmd    db    ' del ',0    ; delete command
  684. dircmd    db    ' dir ',0    ; directory command
  685. typcmd    db    ' type ',0    ; type command
  686. kerenv    db    'KERMIT=',0,0    ; Kermit= environment variable, + 2 nulls
  687. pthnam    db    'PATH='        ; Path environment variable
  688. pthlen    equ    $-pthnam    ;  length of that string
  689. pthadr    dw    0        ; offset of PATH= string
  690. dostempname db    'TEMP='        ; DOS TEMP= enviroment string
  691. dostempnlen equ $ - dostempname ; string length
  692. dostemp db    ' > ',60 dup (0) ; " > " contents of TEMP=  "\$kermit$.tmp"
  693. tmpname db    '$kermit$.tmp',0 ;   path must start on dostemp+3
  694.  
  695. slashc    db    ' /c '        ; slashc Must directly preceed tmpbuf
  696. tmpbuf    db    128 dup (0)    ; temp space for file names and comments
  697. cmspnam    db    'COMSPEC='    ; Environment variable
  698. cmsplen    equ    $-cmspnam
  699. cmspbuf    db    '\command.com',30 dup (0) ; default name plus additional space
  700. shellnam db    'SHELL='    ; Environment variable
  701. shellen    equ    $-shellnam
  702. shellbuf db    40 dup (0)    ; buffer for name
  703. eexit    db    cr,'exit',cr
  704. leexit    equ    $-eexit
  705. onexit    db    8,0,'ON_EXIT',CR ; <length>on_exit macro name
  706. onexlen    equ    $-onexit-2     ; length of name
  707. mfmsg    db    '?Not enough memory to run Kermit$'
  708. mf7msg    db    '?Attempted to allocate a corrupted memory area$'
  709. spcmsg    db    ' bytes available on drive '
  710. spcmsg1    db    ' :',cr,lf,0
  711. spcmsg2    db    cr,lf,' Drive '
  712. spcmsg3    db    ' : is not ready',0
  713. moremsg    db    '... more, press a key to continue ...$'
  714. errlev    db    0        ; DOS errorlevel to be returned
  715. kstatus    dw    0        ; command execution status (0 = success)
  716. thsep    db    0        ; thousands separator
  717. tdfmt    db    0        ; date/time format code
  718. totpar    dw    0
  719. apctrap    db    0        ; disable command if done via APC
  720. pttemp    db    0        ; Patch temp variable
  721. temp    dw    0
  722. tempptr dw    0
  723. seekptr    dw    0,0        ; pointer for lseek in takeread
  724. nopush_flag db    0        ; nz = stops push/run, keep hidden
  725.  
  726. segstr    db    'ABCDEFG'    ; segment "names" for patcher
  727. lsegstr    equ    $-segstr
  728.     even
  729. segtab    dw    code        ; segment values for patcher
  730.     dw    code1
  731.     dw    code2
  732.     dw    data
  733.     dw    data1
  734.     dw    _TEXT
  735.     dw    dgroup
  736. data   ends
  737.  
  738. code1    segment
  739.     extrn    fparse:far, iseof:far, strlen:far, strcpy:far, prtscr:far
  740.     extrn    strcat:far, prtasz:far, domath:far, decout:far, poplevel:far
  741.     assume    cs:code1
  742. code1    ends
  743.  
  744. code    segment
  745.     extrn    reget:near, mail:near, shovar:near, scapc:near
  746.     extrn    bye:near, telnet:near, finish:near, comnd:near, prompt:near
  747.     extrn    read:near, remote:near, send:near, status:near, get:near
  748.     extrn    serrst:near, setcom:near, dtrlow:near, cmblnk:near, getc:near
  749.     extrn    clscpi:near, clscpt:near, scpini:near, setrollb:near
  750.     extrn    dodef:near, setcpt:near, docom:near, shomodem:near
  751.     extrn    server:near, lclini:near, shokey:near, shomac:near, shosta:near
  752.     extrn    shserv:near, initibm:near, forcmd:near, _forinc:near
  753.     extrn    shorx:near, lnout:near, lnouts:near, scminput:near
  754.     extrn    scout:near,scinp:near,scpau:near,scecho:near,scclr:near
  755.     extrn    scxmit:near, scwait:near, srvdsa:near, srvena:near
  756.     extrn    shcom:near, shlog:near, shpro:near, shterm:near, shscpt:near
  757.     extrn    shfile:near, takclos:far, ask:near, askq:near
  758.     extrn    assign:near, sgoto:near, screinp:near, ifcmd:near, write:near
  759.     extrn    setinpbuf:near, shmem:near, replay:near, xifcmd:near
  760.     extrn    com1port:near, com2port:near, com3port:near
  761.     extrn    com4port:near, popcmd:near, mprompt:near, locate:near
  762.     extrn    vfopen:near, vfread:near, decvar:near, incvar:near
  763.     extrn    setwidth:near, scmpause:near, whilecmd:near, reset:near
  764.     extrn    getok:near, cntlsho:near, shownet:near, ctlu:near
  765.     extrn    resend:near, psend:near, tstport:near, scsleep:near
  766.     extrn    takopen_file:far, takopen_macro:far, sforward:near
  767.     extrn    hide_assign:near, hide_define:near, dial:near, declare:near
  768.     extrn    sharray:near, localmac:near, switch:near, move:near
  769.     extrn    retrieve:near, undefine:near, xecho:near
  770. ifndef    no_tcp
  771.     extrn    sesdisp:near
  772. endif    ; no_tcp
  773.  
  774.         assume  cs:code, ds:data, ss:_stack, es:nothing
  775.  
  776. START    PROC    FAR
  777.     mov    ax,data            ; initialize DS
  778.         mov    ds,ax
  779.     mov    psp,es            ; remember psp address
  780.     mov    ah,dosver        ; get DOS version number (word)
  781.     int    dos
  782.     xchg    ah,al            ; major version to ah
  783.     mov    dosnum,ax        ; remember dos version
  784.     cmp    ax,200h            ; earlier than DOS 2.0?
  785.     jge    start1            ; ge = no
  786.     mov    ah,prstr
  787.     mov    dx,offset erms34    ; complain
  788.     int    dos
  789.     push    psp            ; set up exit for DOS 1
  790.     xor    ax,ax            ; and the IP
  791.     push    ax            ; make return addr of psp:0 for DOS 1
  792.     ret                ; and return far to exit now
  793. start1:    call    memini            ; initialize our memory usage
  794.     mov    ah,setdma        ; set disk transfer address
  795.     mov    dx,offset buff
  796.     int    dos
  797.     call    far ptr setint        ; ^C, DOS critical error interrupts
  798.     mov    ah,gcurdsk        ; get current disk
  799.     int    dos
  800.     inc    al            ; make 1 == A (not zero)
  801.     mov    curdsk,al
  802.     mov    origd,al        ; remember original disk we started on
  803.     mov    si,offset orgdir     ; place for directory path w/o drive code
  804.     add    al,'A'-1        ; make al alphabetic disk drive again
  805.     mov    [si],al            ; put it into original path descriptor
  806.     inc    si
  807.     mov    byte ptr [si],':'    ; add drive specifier too
  808.     inc    si
  809.     mov    byte ptr [si],'\'    ; add root indicator as well
  810.     inc    si
  811.     mov    ah,gcd            ; get current directory (path really)
  812.     xor    dl,dl            ; use current drive
  813.     int    dos
  814.     call    getpath            ; get the path from the environment
  815.     call    gettsep            ; get thousands separator, t/date code
  816.     mov    ah,gswitch
  817.     xor    al,al            ; pick up switch character
  818.     int    dos
  819.     mov    slashc+1,dl
  820.     and    maxtry,3fh        ; limit # packet retries
  821.     mov    bx,4            ; PRN handle for DOS
  822.     mov    ah,ioctl
  823.     mov    al,0            ; get info to 
  824.     int    dos
  825.     or    dl,20h            ; turn on binary mode
  826.     xor    dh,dh
  827.     mov    ah,ioctl
  828.     mov    al,1            ; set info
  829.     int    dos
  830.     call    getcsp            ; get comspec from environment
  831.     call    getssp            ; get shellspec from environment
  832.     call    getdostemp        ; get DOS TEMP= string
  833.     mov    dx,offset dostemp
  834.     call    strlen            ; length so far
  835.     cmp    cx,3            ; just ' > '?
  836.     je    start1c            ; e = yes, no TEMP= in environment
  837.     mov    bx,dx            ; string so far
  838.     add    bx,cx            ; last byte + 1
  839.     cmp    byte ptr [bx-1],'\'    ; ends on slash?
  840.     je    start1c            ; e = yes
  841.     mov    word ptr [bx],'\'+0    ; append slash and null terminator
  842. start1c:mov    di,dx            ; destination of dostemp
  843.     mov    si,offset tmpname    ; redirection filename
  844.     call    strcat            ; append
  845.  
  846.     call    getargv            ; get directory where we started
  847.     call    getparm            ; read "KERMIT=" Environment line
  848.     jc    start1b            ; c = fatal error
  849.     xor    cl,cl            ; counter, starts at 0
  850. start1a:mov    bx,offset kerenv+6    ; append "<digit>="  to "KERMIT"
  851.     mov    [bx],cl            ; binary digit
  852.     inc    cl
  853.     add    byte ptr [bx],'0'    ; to ascii
  854.     mov    byte ptr [bx+1],'='    ; append equals sign
  855.     call    getparm            ; read "KERMITn=" Environment line
  856.     jc    start1b            ; c = fatal error
  857.     cmp    cl,9            ; done all digits?
  858.     jbe    start1a            ; be = no
  859.     call    scpini            ; initialize script routines
  860.     jc    start1b            ; c = fatal error
  861.     call    lclini            ; do local initialization
  862.     cmp    flags.extflg,0        ; exit now?
  863.     je    start2            ; e = no
  864. start1b:mov    ah,prstr        ; announce our premature exit
  865.     mov    dx,offset ermes5    ; can't complete initialization
  866.     int    dos
  867.     jmp    krmend5            ; quit immediately
  868. start2:    mov    word ptr comand.cmrprs,offset krmend ; offset of reparse addr
  869.     mov    ax,cs            ; our current code segment
  870.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  871.     mov    comand.cmostp,sp    ; save for reparse too
  872.     call    gcmdlin            ; read command line
  873.     cmp    taklev,0        ; in a Take file?
  874.     jne    start3            ; ne = yes, skip help msg
  875.     mov    ah,prstr
  876.     mov    dx,offset machnam    ; display machine name
  877.     int    dos
  878.         mov    dx,offset verident    ; display version header
  879.         int    dos
  880.     mov    dx,offset copyright    ; display copyright notice
  881.     int    dos
  882. ifdef no_graphics
  883.     mov    dx,offset nographics
  884.     int    dos
  885. endif
  886. ifdef no_network
  887.     mov    dx,offset nonet
  888.     int    dos
  889. else
  890. ifdef no_tcp
  891.     mov    dx,offset notcp
  892.     int    dos
  893. endif
  894. endif
  895. ifdef    no_terminal
  896.     mov    dx,offset noterm
  897.     int    dos
  898. endif
  899. ifdef no_graphics + no_tcp + no_network
  900.     mov    dx,offset crlf
  901.     int    dos
  902. endif
  903.     mov    dx,offset hlpmsg
  904.     int    dos
  905. start3:    mov    patchena,' '        ; let patch level show
  906.     call    serrst            ; reset serial port (if active)
  907.     call    initibm            ; define IBM macro
  908.     call    rdinit            ; read kermit init file
  909.     push    es
  910.     mov    di,ds
  911.     mov    es,di
  912.     mov    di,offset inidir    ; remember path to mskermit.ini
  913.     mov    si,offset cmdfile    ; last Take file path+name
  914.     call    strcpy            ; copy whole string
  915.     mov    dx,di
  916.     call    strlen            ; length of complete path+filename
  917.     add    di,cx            ; last byte +1
  918.     mov    al,'\'            ; look for this separator
  919.     std
  920.     repne    scasb
  921.     cld
  922.     mov    byte ptr [di+2],0    ; terminate after separator
  923.     pop    es
  924.  
  925.  ; This is the main KERMIT loop.  It prompts for and gets the users commands
  926.  
  927. kermit:    mov    ax,ds
  928.     mov    es,ax            ; convenient safety measure
  929.     mov    dx,prmptr        ; get prompt string address
  930.     call    mprompt              ; set master reparse address to here
  931.     cmp    flags.cxzflg,'C'    ; did someone want out?
  932.     jne    kermt4            ; ne = no
  933. kermt2:    cmp    taklev,0        ; are we in a Take file?
  934.     je    kermt4            ; e = no, ignore the signal
  935.     call    takclos            ; close take file, release buffer
  936.     jmp    short kermt2        ; close any other take files
  937. kermt4:    mov    flags.cxzflg,0        ; reset each time
  938.     and    flags.remflg,not dserver ; turn off server mode bit
  939.     cmp    dosctty,0        ; is DOS using our comms line?
  940.     je    kermt1            ; e = no
  941.     and    flags.remflg,not(dquiet+dregular+dserial)
  942.     or    flags.remflg,dquiet    ; set display to quiet mode
  943.     call    serrst            ; close port so CTTY can run
  944. kermt1:    mov    dx,offset comtab
  945.     mov    bx,offset tophlp
  946.     cmp    flags.extflg,0        ; exit flag set?
  947.     jne    krmend            ; ne = yes, jump to KRMEND
  948.     mov    comand.cmcr,1        ; allow bare CR's
  949.         mov    ah,cmkey
  950.     mov    comand.impdo,1        ; allow implied "DO macro"
  951.     call    comnd
  952.     jc    kermt3            ; c = failure
  953.     mov    comand.impdo,0        ; only on initial keyword, not here
  954.     mov    comand.cmcr,0        ; no more bare CR's
  955.     push    bx
  956.     mov    bx,takadr
  957.     mov    al,taklev
  958.     mov    [bx].takinvoke,al    ; remember Take level of this cmd
  959.     pop    bx
  960.     call    bx                  ; call the routine returned in BX
  961.     jc    kermt3            ; c = failure
  962.     cmp    flags.extflg,0        ; exit flag set?
  963.     jne    krmend            ; ne = yes, jump to KRMEND
  964.     jmp    short kermt5        ; do idle loop cleanup
  965.  
  966. kermt3:    cmp    flags.cxzflg,'C'    ; got here via Control-C?
  967.     jne    kermt7            ; ne = no
  968.     cmp    flags.extflg,0        ; exit flag set?
  969.     jne    kermt5            ; ne = yes, skip msg, do cleanup
  970.     mov    dx,offset ermes3    ; say command not executed
  971.     mov    ah,prstr        ; print    the error message in dx
  972.     int    dos
  973. kermt5:    cmp    flags.cxzflg,'C'    ; user Control-C abort?
  974.     jne    kermt7            ; ne = no, do normal operations
  975.     cmp    taklev,0        ; in a Take file?
  976.     je    kermt7            ; e = no        
  977.     call    takclos            ; close take file, release buffer
  978.     jmp    short kermt5        ; close any other take files
  979. kermt7:    cmp    flags.extflg,0        ; exit flag set?
  980.     jne    krmend            ; ne = yes, exit
  981.     mov    bx,takadr
  982.     mov    al,[bx].takinvoke    ; take level at start of command parse
  983.     cmp    al,taklev        ; same?
  984.     jne    kermt10            ; ne = no, already closed
  985.     mov    al,[bx].taktyp        ; kind, file or macro
  986.     cmp    al,take_file        ; type of Take, file?
  987.     jne    kermt8            ; ne = no (macro)
  988.     cmp    takeerror,0        ; is Take Error off?
  989.     jne    kermt9            ; ne = no, close Take file
  990. kermt8:    cmp    al,take_macro        ; regular macro?
  991.     jne    kermt10            ; ne = no, leaves internal macro
  992.     cmp    macroerror,0        ; is Macro Error off?
  993.     je    kermt10            ; e = yes, error is not fatal
  994. kermt9:    call    takclos            ; close Take file or Macro
  995. kermt10:jmp    kermit            ; e = no, get next command
  996.  
  997. krmend:    mov    flags.cxzflg,0        ; reset each time
  998.     mov    flags.extflg,0
  999.     call    far ptr exmacro        ; find on_exit macro
  1000.     jc    krmend2            ; c = not found
  1001.                     ; perform ON_EXIT macro
  1002. krmend1:cmp    taklev,0        ; finished with macros?
  1003.     je    krmend2            ; e = yes
  1004.     mov    dx,prmptr        ; get prompt string address
  1005.     call    mprompt              ; set master reparse address to here
  1006.     cmp    taklev,0        ; still in on_exit?
  1007.     je    krmend2            ; e = no, exit to DOS
  1008.     mov    flags.cxzflg,0        ; reset each time
  1009.     and    flags.remflg,not dserver ; turn off server mode bit
  1010.     mov    dx,offset comtab    ; keyword table
  1011.     xor    bx,bx            ; no help
  1012.         mov    ah,cmkey
  1013.     mov    comand.impdo,1        ; allow implied "DO macro"
  1014.     mov    comand.cmcr,1        ; allow bare CR's
  1015.     call    comnd
  1016.     jc    krmend2            ; c = failure
  1017.     mov    comand.impdo,0        ; only on initial keyword, not here
  1018.     call    bx            ; call the routine returned in BX
  1019.     jnc    krmend1            ; nc = success, keep doing commands
  1020.                     ; end of ON_EXIT macro processing
  1021. krmend2:cmp    taklev,0        ; in a Take file?
  1022.     je    krmend3            ; e = no        
  1023.     call    takclos            ; close take file, release buffer
  1024.     jmp    short krmend2        ; close any other take files
  1025. krmend3:mov    bx,lclexit        ; addr of sys dependent exit routine
  1026.     or    bx,bx            ; sys dependent routines want service?
  1027.     jz    krmend4            ; z = no
  1028.     call    bx            ; call it
  1029.     jnc    krmend4            ; nc = close
  1030.     jmp    kermit            ; c = do not close
  1031. krmend4:call    serrst            ; just in case the port wasn't reset
  1032.     call    clscpi            ; close log files
  1033.     call    far ptr emsclose    ; close and return EMS memory
  1034.     mov    dl,origd        ; original disk drive
  1035.     dec    dl            ; want A == 0
  1036.     mov    ah,seldsk        ; reset original disk just in case
  1037.     int    dos
  1038.     mov    dx,offset orgdir    ; restore original directory
  1039.     mov    ah,chdir
  1040.     int    dos
  1041.     push    ds            ; save ds around these DOS calls
  1042.     mov    ax,cs            ; compose full address of ^C routine
  1043.     mov    ds,ax            ; segment is the code segment
  1044.     mov    dx,offset in3ad        ; restore Control-C interrupt vector
  1045.     mov    al,23H            ; interrupt 23H
  1046.     mov    ah,setintv        ; set interrupt vector
  1047.     int    dos            ; ah, that's better
  1048.     mov    dx,offset ceadr        ; DOS's Critical Error handler
  1049.     mov    al,24h            ; interrupt 24h
  1050.     mov    ah,setintv        ; do replacement (put it back)
  1051.     int    dos
  1052.     pop    ds
  1053.     call    cbrestore        ; restore state of Control-Break Chk
  1054. krmend5:mov    ah,4cH            ; terminate process
  1055.     mov    al,errlev        ; return error level
  1056.     int    dos
  1057.     ret
  1058. START    ENDP
  1059.  
  1060. ; This is the 'EXIT' command.  It leaves KERMIT and returns to DOS
  1061.  
  1062. EXIT    PROC    NEAR
  1063.     mov    ah,cmeol
  1064.     call    comnd            ; get a confirm
  1065.     jc    exit1            ; c = failure
  1066.     mov    flags.extflg,1        ; set the exit-Kermit flag
  1067. exit1:    cmp    taklev,0        ; in a Take file?
  1068.     je    exit2            ; e = no        
  1069.     call    takclos            ; close take file, release buffer
  1070.     jmp    short exit1        ; close any other take files
  1071. exit2:    clc
  1072.     ret
  1073. EXIT    ENDP
  1074.  
  1075. ; Resume For/While at the foot of the interation loop
  1076. CONTINUE proc    near
  1077.     mov    temp,1            ; marker for continue
  1078.     jmp    short break1
  1079. CONTINUE endp
  1080.  
  1081. ; Abandon current For/While statement
  1082. BREAKCMD proc    near
  1083.     mov    temp,0            ; marker for break
  1084.  
  1085. break1:    mov    al,taklev        ; Take level
  1086.     or    al,al            ; in take/macro?
  1087.     jz    breakx            ; z = no
  1088.     mov    bx,takadr
  1089. break2:    test    [bx].takattr,take_while ; is this a for/while/switch macro?
  1090.     jnz    break3            ; nz = yes
  1091.     sub    bx,size takinfo        ; work backward
  1092.     dec    al
  1093.     jnz    break2            ; nz = have some
  1094.     stc                ; carry set to say for/while not
  1095.     ret                ; found
  1096.  
  1097. break3:    cmp    temp,0            ; Break?
  1098.     jne    break4            ; ne = no, Continue
  1099.     push    ax            ; save found take level
  1100.     call    takclos            ; close for/while macro
  1101.     pop    ax
  1102.     mov    bx,takadr        ; new take level
  1103.     cmp    taklev,al        ; did all at that level and above?
  1104.     jae    break3            ; ae = no
  1105. breakx:    clc
  1106.     ret
  1107.                     ; Continue
  1108. break4:    inc    al            ; look above the for/while macro
  1109.     add    bx,size takinfo
  1110.     cmp    al,taklev        ; above the current macros?
  1111.     ja    breakx            ; a = yes, quit
  1112.     mov    [bx].takcnt,0        ; exhaust the macro to end reading
  1113.     jmp    short break4
  1114. BREAKCMD endp
  1115.  
  1116. ; Permit ELSE keyword right after failed IF statement
  1117. ELSECMD    proc    near
  1118.     cmp    oldifelse,0        ; ELSE permitted after failed IF?
  1119.     je    elsecmd1        ; e = no
  1120.     mov    oldifelse,0
  1121.     clc                ; let cmd parser read rest as cmd
  1122.     ret
  1123. elsecmd1:
  1124.     mov    ah,cmline        ; discard the line quietly
  1125.     mov    comand.cmblen,cmdblen    ; set line capacity (length of rdbuf)
  1126.     mov    bx,offset rdbuf
  1127.     xor    dx,dx            ; no help
  1128.     call    comnd
  1129.     clc
  1130.     ret
  1131. ELSECMD endp
  1132.  
  1133. ; RETURN string   string is placed in buffer retbuf
  1134. RETCMD    proc    near
  1135.     mov    ah,cmline
  1136.     mov    bx,offset retbuf+2    ; returned string
  1137.     mov    word ptr rdbuf,0
  1138.     xor    dx,dx
  1139.     call    comnd
  1140.     jnc    retcmd1
  1141.     ret
  1142. retcmd1:mov    word ptr retbuf,ax    ; <count word> <returned string>
  1143.     call    poplevel        ; do the pop
  1144.     ret
  1145. RETCMD    endp
  1146.  
  1147. ; NOPUSH
  1148. PUSHPROC PROC    NEAR
  1149.     mov    ah,cmeol
  1150.     call    comnd
  1151.     jc    pushp1            ; c = failure
  1152.     mov    nopush_flag,1        ; set nopush condition
  1153. pushp1:    ret
  1154. PUSHPROC ENDP
  1155.  
  1156. code    ends
  1157.  
  1158. code1    segment
  1159.     assume    cs:code1
  1160.  
  1161. exmacro    proc    far            ; perform on_exit() macro
  1162.     push    bx
  1163.     push    cx
  1164.     push    si
  1165.     mov    bx,offset mcctab    ; table of macro names
  1166.     mov    cl,[bx]            ; number of names in table
  1167.     xor    ch,ch
  1168.     jcxz    exmacx            ; z = empty table, do nothing
  1169.     inc    bx            ; point to length of first name
  1170. exmac2:    mov    ax,[bx]            ; length of this name
  1171.     cmp    ax,onexlen        ; length same as desired keyword?
  1172.     jne    exmac3            ; ne = no, search again
  1173.     mov    si,bx
  1174.     add    si,2            ; point at first char of name
  1175.     push    cx            ; save name counter
  1176.     push    di            ; save reg
  1177.     mov    cx,onexlen        ; length of name
  1178.     mov    di,offset onexit+2    ; point at desired macro name text
  1179.     push    es            ; save reg
  1180.     push    ds
  1181.     pop    es            ; make es use data segment
  1182.     cld
  1183.     repe    cmpsb            ; match strings
  1184.     pop    es            ; need current si below
  1185.     pop    di
  1186.     pop    cx            ; recover saved regs
  1187.     jne    exmac3            ; ne = no match
  1188.     mov    onexit+2,0        ; change name to be invisible
  1189.     mov    byte ptr [bx+2],0    ; change macro table name too
  1190.     jmp    short exmac4        ; e = matched
  1191. exmac3:    add    bx,ax            ; step to next name, add name length
  1192.     add    bx,4            ; + count and def word ptr
  1193.     loop    exmac2            ; try next name
  1194. exmacx:    pop    si            ; no macro, fail
  1195.     pop    cx
  1196.     pop    bx
  1197.     stc                ; say failure
  1198.     ret
  1199.  
  1200. exmac4:    call    takopen_macro        ; open a macro
  1201.     jc    exmacx            ; c = failed
  1202.     mov    bx,takadr        ; point to current macro structure
  1203.     mov    ax,ds            ; text is in our data seg
  1204.     mov    [bx].takbuf,ax        ; seg of definition string struc
  1205.     mov    [bx].takptr,offset onexit+2 ; where to read next command char
  1206.     mov    [bx].takcnt,onexlen    ; number of chars in definition
  1207.     mov    [bx].takargc,0        ; store macro argument count
  1208.     pop    si
  1209.     pop    cx
  1210.     pop    bx
  1211.     clc                ; say success
  1212.     ret
  1213. exmacro    endp
  1214.  
  1215. ; Close and return EMS memory, uses emsrbhandle and emsgshandle
  1216. emsclose proc    far
  1217.     mov    ah,45h            ; release handle and memory
  1218.     mov    dx,emsrbhandle        ; handle
  1219.     or    dx,dx            ; is handle valid (not -1)?
  1220.     jl    emsclose1        ; l = no
  1221.     int    67h            ; ems interrupt
  1222. emsclose1:mov    emsrbhandle,-1
  1223.     mov    ah,45h            ; release handle and memory
  1224.     mov    dx,emsgshandle        ; handle
  1225.     or    dx,dx            ; is handle valid (not -1)?
  1226.     jl    emsclose2        ; l = no
  1227.     int    67h            ; ems interrupt
  1228. emsclose2:mov    emsgshandle,-1
  1229.     cmp    xmsrhandle,0        ; XMS rollback handle, valid?
  1230.     je    emsclose3        ; e = no
  1231.     mov    dx,xmsrhandle
  1232.     mov    ah,0ah            ; XMS free block
  1233.     call    dword ptr xmsep        ; XMS manager entry point
  1234.     mov    xmsrhandle,0
  1235. emsclose3:cmp    xmsghandle,0        ; XMS graphics handle, valid?
  1236.     je    emsclose4        ; e = no
  1237.     mov    dx,xmsghandle
  1238.     mov    ah,0ah            ; XMS free block
  1239.     call    dword ptr xmsep        ; XMS manager entry point
  1240.     mov    xmsghandle,0
  1241. emsclose4:ret
  1242. emsclose endp
  1243. code1    ends
  1244.  
  1245. code    segment
  1246.     assume    cs:code
  1247.  
  1248. ; TAKE commands    from a file, and allow a path name
  1249. TAKE    PROC    NEAR
  1250.     mov    kstatus,kssuc        ; global status, success
  1251.     cmp    taklev,maxtak        ; at the limit?
  1252.     jl    take1            ; l = no
  1253.     mov    ah,prstr
  1254.     mov    dx,offset erms30    ; complain
  1255.     int    dos
  1256.     stc                ; failure
  1257.     ret
  1258. take1:    mov    bx,offset tmpbuf    ; work buffer
  1259.     mov    tmpbuf,0
  1260.     mov    dx,offset filmsg    ; Help in case user types "?"
  1261.     mov    ah,cmword        ; get file name
  1262.     call    comnd
  1263.     jc    take1a            ; c = failure
  1264.     mov    ah,cmeol
  1265.     call    comnd
  1266.     jc    take1a            ; c = failure
  1267.     mov    ax,offset tmpbuf    ; point to name again
  1268.     cmp    tmpbuf,0        ; empty filespec?
  1269.     jne    take2            ; ne = no
  1270.     mov    ah,prstr
  1271.     mov    dx,offset ermes1    ; say more parameters needed
  1272.     int    dos
  1273.     stc
  1274. take1a:    ret
  1275.                     ; TAKE2: enter with ax=filename ptr
  1276. TAKE2:    call    spath            ; is it around?
  1277.     jc    take3            ; no, go complain
  1278.     mov    dx,ax            ; point to name from spath
  1279.     mov    ah,open2        ; open file
  1280.     xor    al,al            ; 0 = open for reading
  1281.     cmp    dosnum,300h        ; at or above DOS 3?
  1282.     jb    take2a            ; b = no, so no shared access
  1283.     or    al,40h            ; open for reading, deny none
  1284. take2a:    push    dx
  1285.     int    dos
  1286.     pop    dx
  1287.     jnc    take4            ; nc = opened ok, keep going
  1288.     mov    ax,dx            ; recover filename pointer
  1289. take3:    push    ax
  1290.     mov    ah,prstr
  1291.     mov    dx,offset erms31
  1292.     int    dos
  1293.     pop    ax
  1294.     mov    dx,ax            ; asciiz file name
  1295.     call    prtasz            ; display it
  1296.     mov    cmdfile,0        ; clear latest cmd file info
  1297.     mov    kstatus,kstake        ; status, Take failed
  1298.     clc                ; we've done all error displays
  1299.     ret
  1300.                     ; TAKE4: enter with ax=filename ptr
  1301. TAKE4:    push    dx            ; save filename string
  1302.     push    ax            ; save pointer
  1303.     call    takopen_file        ; open take file
  1304.     pop    ax
  1305.     pop    dx
  1306.     jc    take6            ; c = failure
  1307.     call    save_cmdfile        ; save path+name of file from dx
  1308.     push    bx
  1309.     mov    bx,takadr        ; get current frame ptr
  1310.     mov    [bx].takhnd,ax        ; save file handle
  1311.     pop    bx
  1312.     cmp    flags.takflg,0        ; echoing Take files?
  1313.     je    take5            ; e = no
  1314.     mov    ah,prstr
  1315.     mov    dx,offset crlf
  1316.     int    dos
  1317. take5:    call    takrd            ; get a buffer full of data
  1318.     clc                ; success
  1319. take6:    ret
  1320. TAKE    ENDP
  1321.  
  1322. ; TAKE-QUIT  (STOP)  Exit all Take files immediately but gracefully
  1323.  
  1324. TAKEQIT PROC    NEAR
  1325.     xor    ax,ax
  1326.     mov    errlev,al        ; return value in ERRORLEVEL
  1327.     mov    kstatus,ax        ; and in STATUS
  1328.  
  1329.     mov    ah,cmword        ; get optional error value
  1330.     mov    bx,offset rdbuf
  1331.     mov    dx,offset stophlp    ; help on numerical argument
  1332.     mov    comand.cmcr,1        ; bare c/r's allowed
  1333.     call    comnd
  1334.     mov    comand.cmcr,0        ; restore normal state
  1335.     jc    takqit3            ; c = failure
  1336.  
  1337.     mov    ah,cmline        ; get optional error msg
  1338.     mov    bx,offset rdbuf+100
  1339.     mov    dx,offset stophlp    ; help on numerical argument
  1340.     mov    comand.cmcr,1        ; bare c/r's allowed
  1341.     mov    comand.cmdonum,1    ; \number conversion allowed
  1342.     call    comnd
  1343.     mov    comand.cmcr,0        ; restore normal state
  1344.     jc    takqit3            ; c = failure
  1345.     push    ax            ; save string count
  1346.     mov    ah,cmeol        ; confirm
  1347.     call    comnd
  1348.     pop    ax
  1349.     jc    takqit3
  1350.     mov    domath_ptr,offset rdbuf    ; string
  1351.     mov    domath_cnt,ax        ; string length
  1352.     call    domath            ; convert to number in dx:ax
  1353.     cmp    domath_cnt,0
  1354.     jne    takqit2            ; ne = did not convert whole word
  1355.     mov    errlev,al        ; return value in ERRORLEVEL
  1356.     mov    kstatus,ax        ; and in STATUS
  1357.     mov    si,offset rdbuf+100
  1358. takqit4:lodsb                ; read a msg char
  1359.     or    al,al            ; null terminator?
  1360.     jz    takqit2            ; z = empty string
  1361.     cmp    al,' '            ; leading white space?
  1362.     je    takqit4            ; be = leading white space
  1363.     dec    si            ; backup to non-white char
  1364.     mov    dx,offset crlf
  1365.     mov    ah,prstr
  1366.     int    dos
  1367.     mov    dx,si            ; message pointer
  1368.     call    prtasz
  1369. takqit2:xor    ch,ch
  1370.     mov    cl,taklev        ; number of Take levels active
  1371.     jcxz    takqit3            ; z = none
  1372.     cmp    cmdlinetake,cl        ; have DOS level command line?
  1373.     jae    takqit3            ; ae = yes, don't close it here
  1374.     call    takclos            ; close current Take file
  1375.     jmp    short takqit2        ; repeat until all are closed
  1376. takqit3:clc                ; success
  1377.     ret
  1378. TAKEQIT    ENDP
  1379.  
  1380. code    ends
  1381. code1    segment
  1382.     assume    cs:code1
  1383.  
  1384. TAKRD    PROC    FAR
  1385.     push    ax
  1386.     push    bx
  1387.     push    cx    
  1388.     push    dx
  1389.     push    di
  1390.     push    es
  1391.     push    temp
  1392.     mov    bx,takadr
  1393.     cmp    [bx].taktyp,take_file    ; get type of take (file?)
  1394.     je    takrd0            ; e = take file, not macro
  1395.     jmp    takrd30
  1396.  
  1397. takrd0:    xor    ax,ax
  1398.     mov    [bx].takcnt,ax        ; number of bytes to be read
  1399.     mov    [bx].takptr,ax        ; offset of first new character
  1400.     mov    temp,ax            ; prime the disk reader
  1401.     mov    tempptr,offset tmpbuf + 1
  1402.  
  1403. takrd1:    mov    ax,[bx].takbuf        ; segment of Take buffer
  1404.     mov    es,ax
  1405.     mov    cx,tbufsiz        ; # of bytes to examine
  1406.     xor    dx,dx            ; dl = 0 for store data (vs comments)
  1407.     xor    di,di            ; offset in buffer where data starts
  1408.  
  1409. takrd2:    call    takrworker        ; fill take buffer, return a byte
  1410.     jc    takrd30            ; c = failure
  1411.     add    word ptr [bx].takseek,1
  1412.     adc    word ptr [bx].takseek+2,0 ; seek distance, bytes
  1413.     mov    bx,takadr
  1414.     cmp    al,TAB            ; TAB?
  1415.     jne    takrd2a            ; ne = no
  1416.     mov    al,' '            ; convert to space
  1417. takrd2a:cmp    al,LF            ; line terminator?
  1418.     je    takrd2            ; e = yes, ignore it
  1419.     cmp    al,CR            ; internal line terminator?
  1420.     je    takrd5            ; e = yes, always write in buffer
  1421.     or    dl,dl            ; store data (vs discard comments)?
  1422.     jnz    takrd2            ; nz = no, discard, read comments
  1423.     cmp    al,';'            ; start of comment indicator?
  1424.     jne    takrd5            ; ne = no
  1425.     cmp    [bx].takcnt,0        ; bytes examined in buffer, so far
  1426.     je    takrd4            ; e = nothing, so no escape either
  1427.     mov    ah,byte ptr es:[di-1]    ; preceeding char
  1428.     cmp    ah,'\'            ; escaped?
  1429.     jne    takrd3            ; ne = no
  1430.     dec    di            ; overwrite '\' with ';'
  1431.     dec    [bx].takcnt
  1432.     dec    cx
  1433.     jmp    short takrd5
  1434.  
  1435. takrd3:    cmp    ah,' '            ; whitespace precedessor?
  1436.     je    takrd4            ; e = yes, ';' starts a comment
  1437.     cmp    ah,TAB            ; this kind too?
  1438.     jne    takrd5            ; ne = no, not a comment
  1439. takrd4:    mov    dl,1            ; say start discarding comments
  1440.     jmp    short takrd2        ; read more comments
  1441.  
  1442. takrd5:    cmp    al,' '            ; space
  1443.     jne    takrd6            ; ne = no
  1444.     cmp    [bx].takcnt,0        ; anything in line buffer yet?
  1445.     je    takrd7            ; e = no, omit leading space
  1446. takrd6:    inc    [bx].takcnt        ; bytes accepted into buffer so far
  1447.     stosb                ; store byte
  1448.     cmp    al,CR            ; ending on CR?
  1449.     jne    takrd7            ; ne = no
  1450.     or    dl,dl            ; processing comment?
  1451.     jnz    takrd30            ; nz = yes, CR ends comment line
  1452.     cmp    [bx].takcnt,1        ; more than just CR?
  1453.     jbe    takrd30            ; be = no
  1454.     cmp    byte ptr es:[di-2],'-'    ; hyphenated line?
  1455.     jne    takrd30            ; ne = no
  1456.     sub    [bx].takcnt,2        ; remove '-' and CR from buffer
  1457.     sub    di,2            ; back over both
  1458.     add    cx,2            ; add back capacity
  1459.     xor    dl,dl            ; end of comment
  1460. takrd7:    loop    takrd2
  1461.  
  1462. takrd30:mov    cx,[bx].takcnt        ; trim trailing spaces. line count
  1463.     cmp    cx,1
  1464.     jbe    takrd34            ; be = empty line or eof
  1465.     mov    di,cx
  1466.     dec    di            ; count of 1 is only es:[0]
  1467.     cmp    byte ptr es:[di-1],' '    ; ended on text?
  1468.     ja    takrd34            ; a = yes, do not trim
  1469.     xor    di,di            ; es:di(0) is buffer
  1470.     dec    cx            ; back over final CR
  1471.     jcxz    takrd34            ; z = only CR remained
  1472.     add    di,cx
  1473.     dec    di            ; look at last byte - 1
  1474.     mov    al,' '            ; scan for
  1475.     std
  1476.     repe    scasb
  1477.     cld
  1478.     jne    takrd32            ; ne = does not over decrement
  1479.     dec    di
  1480. takrd32:inc    di
  1481.     inc    di
  1482.     mov    byte ptr es:[di],CR    ; final CR goes here
  1483.     inc    di
  1484.     mov    [bx].takcnt,di        ; new count
  1485. takrd34:pop    temp
  1486.     pop    es
  1487.     pop    di
  1488.     pop    dx
  1489.     pop    cx
  1490.     pop    bx
  1491.     pop    ax
  1492.     ret
  1493. TAKRD    ENDP
  1494.  
  1495. ; Read one byte from disk file into al.
  1496. ; Return carry set if failure
  1497. takrworker proc    near
  1498.     push    bx
  1499.     push    cx
  1500.     push    dx
  1501.     push    es
  1502.     cmp    temp,0            ; bytes to be read from tmpbuf
  1503.     jne    takrwork1        ; ne = have things in the buffer
  1504.     mov    bx,takadr
  1505.     mov    dx,word ptr [bx].takseek
  1506.     mov    cx,word ptr [bx].takseek+2
  1507.     mov    bx,[bx].takhnd        ; bx = file handle
  1508.     mov    ah,lseek        ; seek
  1509.     mov    al,0            ; from start of file
  1510.     int    dos
  1511.     mov    temp,0            ; bytes remaining unread
  1512.     mov    cx,length tmpbuf - 1    ; # of bytes to read
  1513.     mov    dx,offset tmpbuf + 1    ; ds:dx = buffer, skip count word
  1514.     mov    tempptr,dx        ; where to read from tmpbuf next time
  1515.     mov    ah,readf2        ; read file
  1516.     int    dos
  1517.     jc    takrwork2        ; c = error, preserve ax
  1518.     mov    temp,ax            ; returned byte count
  1519.     or    ax,ax
  1520.     jz    takrwork2        ; z = nothing left
  1521.  
  1522. takrwork1:
  1523.     mov    bx,tempptr        ; where to read a byte
  1524.     mov    al,[bx]            ; read the byte
  1525.     inc    tempptr            ; where to read next time
  1526.     dec    temp            ; say another byte read
  1527.     clc
  1528.     jmp    short takrwork3        ; succeed
  1529.  
  1530. takrwork2:stc                ; fail
  1531. takrwork3:pop    es
  1532.     pop    dx
  1533.     pop    cx
  1534.     pop    bx
  1535.     ret
  1536. takrworker endp
  1537.  
  1538. code1    ends
  1539. code    segment
  1540.     assume    cs:code
  1541. ; put mskermit.ini onto take stack if it exists.  Just like
  1542. ; the take command, except it doesn't read a filename
  1543.  
  1544. rdinit    proc    near            ; read Kermit init file
  1545.     mov    ax,offset ininm2    ; default name to try
  1546.     cmp    decbuf,0        ; alternate init file given?
  1547.     je    rdini1            ; ne = no
  1548.     mov    ax,offset decbuf    ; yes, use it
  1549.     call    spath            ; is it around?
  1550.     jc    rdini2            ; c = no
  1551.     call    take2            ; let Take do error msgs
  1552.     clc                ; force success
  1553.     ret
  1554. rdini1:    call    spath            ; is it around?
  1555.     jc    rdini2            ; c = no, ignore file
  1556.     mov    dx,ax            ; point to name from spath
  1557.     mov    ah,open2        ; open file
  1558.     xor    al,al            ; 0 = open for reading
  1559.     cmp    dosnum,300h        ; at or above DOS 3?
  1560.     jb    rdini1a            ; b = no, so no shared access
  1561.     or    al,40h            ; open for reading, deny none
  1562. rdini1a:int    dos
  1563.     jc    rdini2            ; c = no ini file found, ignore
  1564.     call    take4            ; use TAKE command to complete work
  1565.     clc                ; ignore errors
  1566. rdini2:    ret
  1567. rdinit    endp
  1568.  
  1569. ; Patcher.  Patch file, MSRxxx.PCH or MSKERMIT.PCH has the following format:
  1570.  
  1571. ; 301 \Xxxxx    Text to display upon successful patch load
  1572. ; ;301 for V3.01.  For xxxx, see below
  1573. ; ; optional comment lines may appear anywhere after the 1st
  1574. ; ; xxxx in 1st line = total paragraphs in memory image.  Use \X if hex.
  1575. ; DS:xxxx xx xx        ; optional comment.  DS (or CS) are case insensitive
  1576. ; CS:xxxx xx xx xx    ; locations must be 4 hex chars, contents must be 2
  1577. ;
  1578. ; The 1st xx is the original value of the 1st byte @seg:offset for comparison.
  1579. ; A 00 value says don't compare.  Subsequent xx's are replacement bytes.
  1580. ; CS & DS lines may be intermixed.  AS & BS segments may be used when some
  1581. ; external module sets words aseg & bseg to a seg-base.
  1582. ; This mechanism expects file msscmd.obj to be linked first.
  1583.  
  1584. PATCH    proc
  1585.     mov    bx,offset rdbuf        ; optional path prefix
  1586.     mov    rdbuf,0
  1587.     mov    dx,offset pathlp
  1588.     mov    ah,cmword
  1589.     call    comnd
  1590.     jc    patch1
  1591.     mov    ah,cmeol
  1592.     call    comnd
  1593.     jc    patch1
  1594.     xor    ax,ax
  1595.     xchg    al,patched        ; clear and test patched
  1596.     test    al,al
  1597.     jz    patch1            ; z = disabled or done
  1598.     xchg    ah,flags.takflg        ; clear take flag, don't echo patches
  1599.     mov    byte ptr temp,ah    ; but save it
  1600.     call    ptchr
  1601.     mov    al,byte ptr temp    ; restore take flag
  1602.     mov    flags.takflg,al
  1603.     jc    patch2            ; c = NG
  1604. patch1:    ret
  1605.  
  1606. patch2:    mov    dx,offset ermes8    ; Fatal error
  1607.     mov    ah,prstr
  1608.     int    dos
  1609.     jmp    krmend            ; force exit
  1610.  
  1611. ptchr:    mov    dx,offset rdbuf        ; optional path
  1612.     call    strlen            ; get length, if any
  1613.     jcxz    ptchr1            ; z = nothing
  1614.     mov    si,dx
  1615.     add    si,cx
  1616.     cmp    byte ptr [si-1],'\'    ; ends with path specifier?
  1617.     je    ptchr1            ; e = yes
  1618.     cmp    byte ptr [si-1],':'    ; or a drive specifier?
  1619.     je    ptchr1            ; e = yes
  1620.     mov    word ptr [si],'\'+0    ; add '\' + null
  1621. ptchr1:    mov    di,offset rdbuf+66    ; path goes here
  1622.     mov    si,offset rdbuf+140    ; filename goes here, discard
  1623.     mov    byte ptr [di],0        ; clear
  1624.     call    fparse            ; split optional path
  1625.     mov    si,offset ptchnam    ; add name of patch file
  1626.     call    strcat
  1627.     mov    ax,di            ; setup filename pointer for rdini1
  1628.     call    rdini1        ; let rdini try to find it & do take stuff
  1629.     jnc    ptch1            ; nc = file msrxxx.pch was found
  1630.     mov    di,offset rdbuf+66    ; path goes here
  1631.     mov    si,offset rdbuf+140    ; filename goes here, discard
  1632.     mov    byte ptr [di],0        ; clear
  1633.     mov    dx,offset rdbuf        ; source string again
  1634.     call    fparse            ; split optional path
  1635.     mov    si,offset ptchnam2    ; try alternate name
  1636.     mov    byte ptr [di],0        ; insert terminator
  1637.     call    strcat            
  1638.     mov    ax,di            ; setup filename pointer for rdini1
  1639.     call    rdini1        ; let rdini try to find it & do take stuff
  1640.     jnc    ptch1            ; nc = file msrxxx.pch was found
  1641.     mov    dx,offset ermes7    ; say file not found
  1642.     mov    ah,prstr
  1643.     int    dos
  1644.     clc
  1645.     ret
  1646.  
  1647. ptch1:    mov    al,taklev        ; remember initial take level
  1648.     mov    pttemp,al        ; when it changes it is EOF & done
  1649.     mov    comand.cmkeep,1        ; keep Take open after eof
  1650.     mov    comand.cmcr,1        ; bare cr's ok, to prevent prserr @EOF
  1651.     call    ptchrl            ; read 1st line's 1st 'word'
  1652.     jc    ptch2            ; c = trouble
  1653.     jz    ptch3            ; z = EOF
  1654.     mov    si,offset tmpbuf+1
  1655.     mov    domath_cnt,4        ; length of field
  1656.     mov    domath_ptr,si
  1657.     mov    domath_msg,1        ; don't complain
  1658.     call    domath            ; convert number to binary
  1659.     cmp    domath_cnt,0
  1660.     jne    ptch2            ; ne = bad number, or none
  1661.     cmp    ax,version        ; does it match this version?
  1662.     je    ptch4            ; e = yes
  1663. ptch2:    mov    al,pttemp        ; if take level has changed,
  1664.     xor    al,taklev        ;  we're already out of patch file
  1665.     jnz    ptch3            ; nz = change in take level
  1666.     call    takclos            ; close patch file
  1667. ptch3:    mov    dx,offset ermes6
  1668.     mov    ah,prstr        ; issue warning msg
  1669.     int    dos
  1670.     clc
  1671.     ret
  1672.  
  1673. ptch4:    mov    dx,offset tmpbuf+1
  1674.     call    ptchrw            ; read 2nd "word", 1st line
  1675.     jc    ptch2            ; c = NG
  1676.     mov    si,offset tmpbuf+1
  1677.     mov    domath_cnt,6        ; arbitrary length
  1678.     mov    domath_ptr,si
  1679.     call    domath            ; convert 2nd "magic number"
  1680.     cmp    domath_cnt,0
  1681.     jne    ptch2            ; ne = bad number, or none
  1682.     cmp    ax,totpar    ; is it the total paragraphs memini computed?
  1683.     jne    ptch2            ; ne = no
  1684.     mov    bx,offset buff    ; place to stash 1st lines patch/version msg
  1685.     xor    dx,dx            ; help
  1686.     mov    ah,cmline        ; read it
  1687.     call    comnd
  1688.  
  1689. ptch5:    call    ptchrl            ; read CS:xxxx or DS:xxxx
  1690.     jc    ptch6
  1691.     jz    ptch7            ; z = EOF
  1692.     cmp    ax,7            ; were 7 chars read?
  1693.     jne    ptch6            ; ne = no
  1694.     mov    si,offset tmpbuf+1
  1695.     and    word ptr[si],not 2020h    ; convert to upper case
  1696.     cld
  1697.     lodsb                ; get the seg char
  1698.     cmp    word ptr[si],':S'     ; S:, actually
  1699.     je    ptch8            ; e = ok
  1700. ptch6:    stc                ; error exit
  1701.     ret
  1702.  
  1703. ptch7:    test    flags.remflg,dquiet    ; quiet display?
  1704.     jnz    ptch7a            ; nz = yes, skip msg
  1705.     mov    ah,prstr
  1706.         mov    dx,offset verident    ; display version header
  1707.         int    dos
  1708. ptch7a:    clc
  1709.     ret
  1710.  
  1711. ptch8:    push    ds
  1712.     pop    es
  1713.     mov    di,offset segstr
  1714.     mov    cx,lsegstr        ; search for seg char in segstr
  1715.     repne    scasb
  1716.     jne    ptch6            ; ne = not found
  1717.     sub    di,offset segstr+1    ; distance spanned
  1718.     shl    di,1            ; make a word index
  1719.     mov    bx,segtab[di]        ; bx = seg-base
  1720.     or    bx,bx            ; seg-base = 0, disabled for patching
  1721.     jz    ptch6            ; z = 0, no patching
  1722.     mov    word ptr[si],'X\'     ; put '\X' in front for hex
  1723.     mov    domath_cnt,16        ; arbitrary length
  1724.     mov    domath_ptr,si
  1725.     call    domath            ; convert number to binary
  1726.     cmp    domath_cnt,0
  1727.     jne    ptch6            ; ne = bad number, or none
  1728.     push    bx            ; save seg being patched
  1729.     push    ax            ; save location being patched
  1730.     mov    tmpbuf+64,0        ; clear replacement byte count
  1731. ptch9:    mov    dx,offset tmpbuf+4
  1732.     call    ptchrw            ; read replacement byte follwing '\X'
  1733.     jnc    ptch11            ; nc = OK
  1734. ptch10:    pop    ax            ; clean stack & error return
  1735.     pop    bx
  1736.     stc
  1737.     ret
  1738.  
  1739. ptch11:    or    ax,ax            ; EOL?
  1740.     jnz    ptch13            ; nz = no
  1741.     mov    si,offset tmpbuf+64
  1742.     cld
  1743.     lodsb                ; replacement byte count
  1744.     cmp    al,2            ; gotta be at least 2
  1745.     jb    ptch10            ; b = too few
  1746.     xor    ch,ch
  1747.     mov    cl,al            ; replacement count
  1748.     pop    di            ; patch location
  1749.     pop    es            ; patch segment
  1750.     lodsb                ; al = comparison byte
  1751.     or    al,al            ; key value to ignore comparison?
  1752.     jz    ptch12            ; z = 0, yes
  1753.     cmp    byte ptr es:[di],al     ; do read check on memory image
  1754.     jne    ptch6            ; ne = no match, fail now
  1755. ptch12:    dec    cx            ; adjust for comparison byte
  1756.     rep    movsb            ; make patch
  1757.     jmp    ptch5            ; loop to read next line
  1758.  
  1759. ptch13:    cmp    al,2            ; 2 chars req'd for replacement byte
  1760.     jne    ptch10            ; ne = bad
  1761.     mov    domath_ptr,offset tmpbuf+2; convert it
  1762.     mov    domath_cnt,16        ; arbitrary length
  1763.     call    domath            ; convert number to binary
  1764.     cmp    domath_cnt,0
  1765.     jne    ptch10            ; ne = bad number, or none
  1766.     mov    si,offset tmpbuf+64    ; --> replacement byte counted string
  1767.     inc    byte ptr[si]        ; bump count
  1768.     mov    bl,[si]
  1769.     xor    bh,bh
  1770.     mov    byte ptr[si+bx],al    ; stash replacement byte
  1771.     jmp    short ptch9        ; loop for next byte
  1772.  
  1773. ptchrl:    mov    dx,offset patpmt    ; read 1st word, next line to tmpbuf+1
  1774.     call    prompt
  1775.     mov    dx,offset tmpbuf+1
  1776.     call    ptchrw
  1777.     jc    ptchrb            ; c = NG
  1778.     push    dx
  1779.     mov    dl,pttemp        ; old Take level
  1780.     xor    dl,taklev        ; current Take level, changed
  1781.     pop    dx
  1782.     jz    ptchra            ; z = no, not EOF
  1783.     xor    ax,ax            ; set z flag for EOF
  1784.     ret
  1785.  
  1786. ptchra:    or    ax,ax            ; empty or comment line?
  1787.     jz    ptchrl            ; z = empty or comment, ignore
  1788. ptchrb:    ret
  1789.  
  1790. ptchrw:    push    dx
  1791.     mov    dl,pttemp        ; old Take level
  1792.     xor    dl,taklev        ; current Take level, changed?
  1793.     pop    dx
  1794.     jz    ptchrwa            ; z = no, not EOF
  1795.     xor    ax,ax            ; set z flag for EOF
  1796.     ret
  1797. ptchrwa:mov    ah,cmword
  1798.     mov    comand.cmper,1    ; prohibit substitution variable expansion
  1799.     xor    bx,bx            ; 'help' ptr
  1800.     xchg    bx,dx            ; order for comnd
  1801.     call    comnd            ; line length is in ax
  1802.     ret
  1803. PATCH    endp
  1804.  
  1805. ; Get command line into a Take macro buffer. Allow "-f filspec" to override
  1806. ; normal mskermit.ini initialization filespec, allow command "stay" to
  1807. ; suppress automatic exit to DOS at end of command line execution. [jrd]
  1808.  
  1809. gcmdlin    proc    near
  1810.     mov    cmdlinetake,0        ; flag for DOS command line Take
  1811.     mov    word ptr decbuf,0    ; storage for new init filename
  1812.     push    es
  1813.     cld
  1814.     mov    es,psp            ; address psp
  1815.     xor    ch,ch
  1816.     mov    cl,es:byte ptr[cline]    ; length of cmd line from DOS
  1817.     jcxz    gcmdl1            ; z = empty line
  1818.     mov    si,cline+1        ; point to actual line
  1819. gcmdl0:    cmp    byte ptr es:[si],' '    ; skip over leading whitespace
  1820.     ja    gcmdl2            ; a = non-whitespace
  1821.     inc    si
  1822.     loop    gcmdl0            ; fall through on all whitespace
  1823. gcmdl1:    jmp    gcmdl14            ; common exit jump point
  1824. gcmdl2:    inc    cx            ; include DOS's c/r
  1825.     call    takopen_macro        ; open take as macro
  1826.     mov    bx,takadr
  1827.     mov    ax,150            ; space needed: DOS line + ",stay"
  1828.     call    malloc            ; hope it works
  1829.     mov    [bx].takbuf,ax        ; memory segment
  1830.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  1831.     mov    es,ax            ; segment of buffer
  1832.         mov     di,2                    ; skip count word
  1833.     push    psp
  1834.  
  1835.     pop    DS            ; DS = PSP
  1836.     xor    dx,dx            ; clear brace count
  1837. gcmdl3:    or    cx,cx            ; anything left?
  1838.     jle    gcmdl10            ; le = no
  1839.     lodsb                ; get a byte from PSP's command line
  1840.     dec    cx            ; one less char in input string
  1841.     cmp    al,','            ; comma?
  1842.     jne    gcmdl4            ; no, keep going
  1843.     or    dx,dx            ; inside braces?
  1844.     jnz    gcmdl9            ; nz = yes, retain embedded commas
  1845.     mov    al,cr            ; convert to cr
  1846.     jmp    short gcmdl9        ; store it
  1847. gcmdl4:    call    bracechk        ; check for curly braces
  1848.     jc    gcmdl9            ; c = found and counted brace
  1849.     or    dx,dx            ; outside braces?
  1850.     jnz    gcmdl9            ; nz = no, ignore flag
  1851.     cmp    al,'-'            ; starting a flag?
  1852.     jne    gcmdl9            ; ne = no
  1853.     mov    ah,[si]            ; get flag letter
  1854.     or    ah,20h            ; convert to lower case
  1855.     cmp    ah,'f'            ; 'f' for init file replacement?
  1856.     jne    gcmdl9            ; ne = no
  1857.     inc    si            ; accept flag letter
  1858.     dec    cx
  1859. gcmdl5:    or    cx,cx            ; anything to read?
  1860.     jle    gcmdl10            ; le = exhausted supply
  1861.     lodsb                ; get filespec char from psp
  1862.     dec    cx            ; one less char in source buffer
  1863.     cmp    al,' '            ; in whitespace?
  1864.     jbe    gcmdl5            ; be = yes, scan it off
  1865.     dec    si            ; backup to real text
  1866.     inc    cx
  1867.                     ; copy filspec to buffer decbuf
  1868.     push    es            ; save current destination pointer
  1869.     push    di            ;  which is in es:di (Take buffer)
  1870.     mov    di,data            ; set es:di to regular decbuf
  1871.     mov    es,di
  1872.     lea    di,decbuf        ; where filespec part goes
  1873.     mov    word ptr es:[di],0    ; plant safety terminator
  1874. gcmdl6:    lodsb                ; get filespec char
  1875.     dec    cx            ; one less available
  1876.     cmp    al,' '            ; in printables?
  1877.     jbe    gcmdl7            ; be = no, all done
  1878.     cmp    al,','            ; comma command separator?
  1879.     je    gcmdl7            ; e = yes, all done
  1880.     stosb                ; store filespec char
  1881.     or    cx,cx            ; any chars left?
  1882.     jg    short gcmdl6        ; g = yes
  1883. gcmdl7:    mov    byte ptr es:[di],0    ; end filespec on a null
  1884.     pop    di            ; recover destination pointer es:di
  1885.     pop    es
  1886. gcmdl8:    or    cx,cx            ; strip trailing whitespace
  1887.     jle    gcmdl10            ; le = nothing left
  1888.     lodsb
  1889.     dec    cx
  1890.     cmp    al,' '            ; white space?
  1891.     jbe    gcmdl8            ; be = yes, strip it
  1892.     cmp    al,','            ; at next command?
  1893.     je    gcmdl10            ; e = yes, skip our own comma
  1894.     dec    si            ; back up to reread the char
  1895.     inc    cx
  1896.     jmp    gcmdl3            ; read more command text
  1897.                     ; end of flag analysis
  1898. gcmdl9:    stosb                ; deposit most recent char
  1899. gcmdl10:or    cx,cx            ; anything left to read?
  1900.     jg    gcmdl3            ; g = yes, loop
  1901.                     ;
  1902.     mov    ax,data            ; restore segment registers
  1903.     mov    DS,ax
  1904.     mov    si,[bx].takbuf        ; get segment of Take buffer
  1905.     mov    es,si
  1906.     mov    si,2            ; skip count word
  1907.     mov    cx,di            ; current end pointer, (save di)
  1908.     sub    cx,si            ; current ptr minus start offset
  1909.     mov    [bx].takcnt,cx        ; chars in buffer so far
  1910.         mov     es:word ptr [0],cx      ; store count word
  1911.     xor    dx,dx            ; brace count
  1912.     or    cx,cx
  1913.     jg    gcmdl11            ; g = material at hand
  1914.     call    takclos            ; empty take file
  1915.     jmp    short gcmdl14        ; finish up
  1916.                     ; scan for command "stay"
  1917. gcmdl11:mov    ax,es:[si]        ; get 2 bytes, cx and si are set above
  1918.     inc    si            ; increment by only one char
  1919.     dec    cx
  1920.     call    bracechk        ; check for braces
  1921.     jc    gcmdl12            ; c = brace found
  1922.     cmp    al,' '            ; separator?
  1923.     jbe    gcmdl12            ; be = yes, keep looking
  1924.     cmp    al,','             ; comma separator?
  1925.     je    gcmdl12            ; e = yes
  1926.     or    dx,dx            ; within braces?
  1927.     jnz    gcmdl12            ; nz = yes, skip STAY search
  1928.     or    ax,2020h        ; convert to lower case
  1929.     cmp    ax,'ts'            ; first two letters of stay
  1930.     jne    gcmdl12            ; ne = no match
  1931.     mov    ax,es:[si+1]        ; next two letters (stay vs status)
  1932.     or    ax,2020h        ; convert to lower case
  1933.     cmp    ax,'ya'            ; same as our pattern?
  1934.     jne    gcmdl12            ; ne = no match
  1935.     add    si,3            ; char after "stay"
  1936.     sub    cx,3
  1937.                     ; check for separator or end of macro
  1938.     cmp    byte ptr es:[si],' '    ; next char is a separator?
  1939.     jbe    gcmdl13            ; be = yes, found correct match
  1940.     cmp    byte ptr es:[si],','    ; or comma separator?
  1941.     je    gcmdl13            ; e = yes
  1942.     or    cx,cx            ; at end of macro?
  1943.     jle    gcmdl13            ; yes, consider current match correct
  1944. gcmdl12:or    cx,cx            ; done yet? ("stay" not found)
  1945.     jg    gcmdl11            ; g = not yet, look some more
  1946.     mov    cmdlinetake,1        ; remember doing DOS cmd line Take
  1947.     mov    si,offset eexit        ; append command "exit"
  1948.     mov    cx,leexit        ; length of string "exit"
  1949.     add    [bx].takcnt,cx
  1950.     rep    movsb            ; copy it into the Take buffer
  1951. gcmdl13:mov     [bx].takptr,2           ; init buffer ptr
  1952.         mov     cx,[bx].takcnt          ; count of bytes in buffer
  1953.         mov     es:[0],cx               ; count of bytes in Take buffer
  1954. gcmdl14:pop    es
  1955.     ret
  1956. gcmdlin    endp
  1957.  
  1958. ; Curly brace checker. Examine (and preserve) char in AL. Count up/down
  1959. ; braces in dx because DS is unknown here
  1960. bracechk proc    near
  1961.     cmp    al,braceop        ; opening brace?
  1962.     jne    bracech1        ; ne = no
  1963.     inc    dx            ; count up braces
  1964.     stc                ; say brace seen
  1965.     ret
  1966. bracech1:cmp    al,bracecl        ; closing brace
  1967.     jne    bracech3        ; ne = no
  1968.     sub    dx,1            ; count down with sign
  1969.     jns    bracech2        ; ns = no underflow
  1970.     xor    dx,dx            ; don't go below zero
  1971. bracech2:stc                ; say brace detected
  1972.     ret
  1973. bracech3:clc                ; say brace not found
  1974.     ret
  1975. bracechk endp
  1976.  
  1977. ; Enter with ax pointing to file name.  Searches path for given file,
  1978. ; returns with ax pointing to whole name, or carry set if file can't be found.
  1979. SPATH    proc    near
  1980.     call    isfile            ; does it exist as it is?
  1981.     jc    spath0            ; c = no, prepend path elements
  1982.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1983.     jnz    spath0            ; nz = yes, not desired file
  1984.     push    di
  1985.     mov    di,ax
  1986.     push    di
  1987.     push    ax
  1988.     mov    dx,di            ; get string length
  1989.     call    strlen
  1990.     cld
  1991.     push    es
  1992.     mov    ax,ds
  1993.     mov    es,ax
  1994.     mov    al,'\'            ; look for path separator
  1995.     repne    scasb            ; scan es:di for separator
  1996.     pop    es
  1997.     pop    ax
  1998.     pop    di
  1999.     je    spath14            ; e = found, use as-is
  2000.     cmp    byte ptr [di+1],':'    ; drive already given?
  2001.     jne    spath10            ; ne = no
  2002. spath14:pop    di
  2003.     clc
  2004.     ret                ; path stuff is already in ax
  2005.  
  2006. spath10:push    bx
  2007.     mov    bx,[di]
  2008.     and    bx,not 2020h        ; to upper
  2009.     cmp    bx,'UN'            ; look for DOS 5 NUL
  2010.     jne    spath11            ; ne = mismatch
  2011.     mov    bx,[di+2]
  2012.     and    bl,not 20h
  2013.     cmp    bx,'L'+0
  2014. spath11:pop    bx
  2015.     jne    spath12            ; ne = mismatch
  2016.     pop    di
  2017.     clc
  2018.     ret
  2019.  
  2020. spath12:push    ax
  2021.     mov    di,offset decbuf+64    ; where results will be returned
  2022.     mov    ah,gcurdsk        ; get current disk
  2023.     int    dos
  2024.     inc    al            ; make 1 == A (not zero)
  2025.     add    al,'A'-1        ; make al alphabetic disk drive again
  2026.     mov    [di],al            ; put it into original path descriptor
  2027.     inc    di
  2028.     mov    word ptr [di],'\:'    ; add drive specifier too
  2029.     add    di,2
  2030.     push    si
  2031.     mov    si,di
  2032.     mov    ah,gcd            ; get current directory (path really)
  2033.     xor    dl,dl            ; use current drive
  2034.     int    dos
  2035.     pop    si
  2036.     push     dx
  2037.     mov    dx,di            ; find end of string
  2038.     call    strlen
  2039.     pop    dx
  2040.     add    di,cx            ; step after path
  2041.     pop    ax
  2042.     push    si
  2043.     mov    dx,ax            ; this is user's file name
  2044.     mov    si,offset decbuf+200    ; filename goes here, temp
  2045.     push    di            ; preserve di from above
  2046.     mov    di,offset decbuf+220    ; far away, path, temp
  2047.     call    fparse            ; get filename to ds:si
  2048.     pop    di
  2049.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  2050.     je    spath13            ; yes, don't put one in
  2051.     cmp    byte ptr [di-1],5ch    ; how about this one?
  2052.     je    spath13            ; yes, don't put it in
  2053.     mov    byte ptr [di],5ch    ; else add one
  2054.     inc    di
  2055. spath13:lodsb                ; get filename character
  2056.     mov    byte ptr [di],al    ; copy filename char to output buffer
  2057.     inc    di
  2058.     or    al,al            ; end of string?
  2059.     jnz    spath13            ; nz = no, copy rest of name
  2060.     pop    si            ; restore postion in path string
  2061.     pop    di
  2062.     mov    ax,offset decbuf+64    ; return results in ax
  2063.     clc
  2064.     ret
  2065.  
  2066. spath0:    push    es            ; save es around work
  2067.     push    bx
  2068.     push    si
  2069.     push    di
  2070.     mov    bx,ax            ; save filename pointer in bx
  2071.     mov    si,ax
  2072.     xor    dl,dl            ; no '\' seen yet
  2073.     cld
  2074. spath1:    lodsb
  2075.     cmp    al,2fh            ; contains fwd slash path characters?
  2076.     je    spath1a
  2077.     cmp    al,5ch            ; or backslash?
  2078.     jne    spath2            ; ne = no, keep going
  2079. spath1a:mov    dl,1            ; remember we've seen them
  2080. spath2:    or    al,al
  2081.     jnz    spath1            ; copy name in
  2082.     or    dl,dl            ; look at flag
  2083.     jz    spath3            ; no path, keep looking
  2084.     jmp    short spath9        ; embedded path, fail
  2085.  
  2086. spath3:    call    skpath            ; search kermit's path
  2087.     jnc    spath8a            ; nc = located file
  2088.     mov    si,pthadr        ; offset of PATH= string in environment
  2089.     mov    es,psp
  2090.     mov    di,es:word ptr[env]    ; pick up environment segment
  2091.     mov    es,di
  2092. spath4:    cmp    byte ptr es:[si],0    ; end of PATH= string?
  2093.     je    spath9            ; e = yes, exit loop
  2094.     mov    di,offset decbuf+64    ; place to put name
  2095. spath5:    mov    al,byte ptr es:[si]    ; get a byte from environment string
  2096.     inc    si
  2097.     cmp    al,';'            ; end of this part?
  2098.     je    spath7            ; yes, break loop
  2099.     or    al,al            ; maybe end of string?
  2100.     jnz    spath6            ; nz = no, keep going
  2101.     dec    si            ; back up to null for later rereading
  2102.     jmp    short spath7        ; and break loop
  2103. spath6:    mov    byte ptr [di],al    ; else stick in dest string
  2104.     inc    di
  2105.     jmp    short spath5        ; and continue
  2106. spath7:    push    si            ; save this ptr
  2107.     mov    si,bx            ; this is user's file name
  2108.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  2109.     je    spath8            ; yes, don't put one in
  2110.     cmp    byte ptr [di-1],5ch    ; how about this one?
  2111.     je    spath8            ; yes, don't put it in
  2112.     mov    byte ptr [di],5ch    ; else add one
  2113.     inc    di
  2114. spath8:    lodsb                ; get filename character
  2115.     mov    byte ptr [di],al    ; copy filename char to output buffer
  2116.     inc    di
  2117.     or    al,al            ; end of string?
  2118.     jnz    spath8            ; nz = no, copy rest of name
  2119.     pop    si            ; restore postion in path string
  2120.     mov    ax,offset decbuf+64
  2121.     call    isfile            ; is it a file?
  2122.     jc    spath4            ; c = no, keep looking
  2123.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  2124.     jnz    spath4            ; nz = yes
  2125. spath8a:pop    di
  2126.     pop    si
  2127.     pop    bx
  2128.     pop    es
  2129.     clc
  2130.     ret                ; return success (carry clear)
  2131. spath9:    mov    ax,bx            ; restore original filename pointer
  2132.     pop    di            ; restore regs
  2133.     pop    si
  2134.     pop    bx
  2135.     pop    es
  2136.     stc                ; no file found
  2137.     ret
  2138. spath    endp
  2139.  
  2140. ; Search Kermit's path for file. Return carry clear if found, else carry set.
  2141. ; Worker for spath above.
  2142. skpath    proc    near
  2143.     mov    si,seg kpath        ; Kermit's path string
  2144.     mov    es,si
  2145.     mov    si,offset kpath
  2146.     mov    di,offset decbuf+64    ; place to put name
  2147. skpath1:mov    al,es:[si]        ; get a byte from string
  2148.     inc    si
  2149.     cmp    al,';'            ; end of this part?
  2150.     je    skpath3            ; yes, break loop
  2151.     or    al,al            ; maybe end of string?
  2152.     jnz    skpath2            ; nz = no, keep going
  2153.     dec    si            ; back up to null for later rereading
  2154.     jmp    short skpath3        ; and break loop
  2155. skpath2:mov    byte ptr [di],al    ; else stick in dest string
  2156.     inc    di
  2157.     jmp    short skpath1        ; and continue
  2158. skpath3:cld
  2159.     mov    si,bx            ; this is user's file name
  2160.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  2161.     je    skpath4            ; yes, don't put one in
  2162.     cmp    byte ptr [di-1],5ch    ; how about this one?
  2163.     je    skpath4            ; yes, don't put it in
  2164.     mov    byte ptr [di],5ch    ; else add one
  2165.     inc    di
  2166. skpath4:lodsb                ; get filename character
  2167.     mov    byte ptr [di],al    ; copy filename char to output buffer
  2168.     inc    di
  2169.     or    al,al            ; end of string?
  2170.     jnz    skpath4            ; nz = no, copy rest of name
  2171.     mov    ax,offset decbuf+64
  2172.     push    bx
  2173.     call    isfile            ; is it a file?
  2174.     pop    bx
  2175.     jnc    skpath5            ; nc = yes
  2176.     ret
  2177. skpath5:test    byte ptr filtst.dta+21,10H ; subdirectory name?
  2178.     jnz    skpath6            ; nz = yes
  2179.     clc                ; report file found (AX as offset)
  2180.     ret
  2181. skpath6:stc                ; report failure
  2182.     ret
  2183. skpath    endp
  2184.  
  2185. ; Put Kermit's Enviroment Path indicator into string kpath
  2186. mkkpath    proc    near
  2187.     mov    bx,offset rdbuf
  2188.     mov    word ptr rdbuf,0
  2189.     xor    dx,dx
  2190.     mov    comand.cmblen,64    ; 64 bytes max
  2191.     mov    ah,cmword        ; get a word, with semicolons
  2192.     call    comnd
  2193.     jnc    mkkpath1        ; nc = success
  2194.     ret
  2195. mkkpath1:mov    cx,ax            ; get string length
  2196.     push    si
  2197.     push    di
  2198.     push    es
  2199.     mov    si,offset rdbuf        ; source
  2200.     mov    di,seg kpath        ; storage spot
  2201.     mov    es,di
  2202.     mov    di,offset kpath
  2203.     cld
  2204.     rep    movsb            ; copy
  2205.     mov    word ptr es:[di],0    ; terminate
  2206.     pop    es
  2207.     pop    di
  2208.     pop    si
  2209.     ret
  2210. mkkpath    endp
  2211.  
  2212. ; Put offset of PATH= string in pthadr
  2213. getpath    proc    near
  2214.     push    bx
  2215.     push    cx
  2216.     push    dx
  2217.     mov    bx,offset pthnam    ; thing    to find
  2218.     mov    cx,pthlen        ; length of it
  2219.     mov    pthadr,0        ; init offset to zero
  2220.     call    getenv            ; get environment value
  2221.     mov    pthadr,dx
  2222.     pop    dx
  2223.     pop    cx
  2224.     pop    bx
  2225.     ret
  2226. getpath    endp
  2227.  
  2228. ; getcsp: copy COMSPEC= environment string into cmspbuf
  2229. ; getssp: copy SHELL=   environment string into shellbuf
  2230. ; getdostemp: copy TEMP= environment string into dostemp
  2231. getcsp    proc    near
  2232.     mov    bx,offset cmspnam    ; find COMSPEC=
  2233.     mov    cx,cmsplen        ; its length
  2234.     mov    di,offset cmspbuf    ; where to store string
  2235.     jmp    short getccom        ; do common worker
  2236.  
  2237. getssp:    mov    bx,offset shellnam    ; find SHELL=
  2238.     mov    cx,shellen        ; its length
  2239.     mov    di,offset shellbuf    ; where to store string
  2240.     jmp    short getccom        ; do common worker
  2241.  
  2242. getdostemp:mov    bx,offset dostempname    ; fine TEMP=
  2243.     mov    cx,dostempnlen        ; its length
  2244.     mov    di,offset dostemp+3    ; where to store string
  2245.  
  2246. getccom:push    es
  2247.     call    getenv            ; get environment offset into dx
  2248.     jc    getcs3            ; c = not found
  2249.     mov    si,dx            ; address of COMSPEC= string
  2250.     mov    es,psp
  2251.     mov    bx,es:word ptr[env]    ; pick up environment address
  2252.     mov    es,bx
  2253.     push    ds            ; save ds
  2254.     push    ds            ; make ds point to environment seg
  2255.     push    es            ; make es point to data segment
  2256.     pop    ds
  2257.     pop    es
  2258.     cld
  2259. getcs1:    lodsb                ; get a byte from environment
  2260.     cmp    al,' '            ; space or less?
  2261.     jg    getcs2            ; g = no, keep copying
  2262.     xor    al,al            ; terminate string on spaces etc
  2263. getcs2:    stosb                ; store it in destination
  2264.     or    al,al            ; at end of string yet?
  2265.     jnz    getcs1            ; nz = no, keep copying
  2266.     pop    ds            ; recover ds
  2267. getcs3:    pop    es
  2268.     ret
  2269. getcsp    endp
  2270.  
  2271. ; Get Kermit parameters from the Environment. Parameters are commands like
  2272. ; regular commands except they do not appear in the SET main table and are
  2273. ; separated from one another by semicolons. They appear after KERMIT=.
  2274. ; Do not allow Take/Macros to be created by any of these commands.
  2275. ; On fatal error exits with carry set and flags.extflg = 1
  2276. getparm    proc    near
  2277.     push    ax
  2278.     push    bx
  2279.     push    cx
  2280.     push    dx
  2281.     push    si
  2282.     push    di
  2283.     push    es
  2284.     mov    es,psp            ; segment of our PSP
  2285.     mov    ax,es:word ptr[env]    ; pick up environment address
  2286.     mov    es,ax
  2287.     mov    bx,offset kerenv    ; Environment word to find, asciiz
  2288.     mov    dx,bx
  2289.     call    strlen            ; length of its string to cx
  2290.     call    getenv            ; return dx = offset in environment
  2291.     jnc    getpar1            ; nc = success
  2292.     jmp    getpar9            ; c = not found
  2293. getpar1:push    ds            ; save regular DS
  2294.     push    dx            ; push Environment offset, then seg
  2295.     push    es
  2296.     call    takopen_macro        ; open Take buffer in macro space
  2297.     jnc    getpar2            ; nc = success
  2298. getpar1a:mov    flags.extflg,1        ; say exit now
  2299.     pop    es            ; clean stack
  2300.     pop    dx
  2301.     pop    ds
  2302.     jmp    getparx            ; exit with fatal error
  2303.  
  2304. getpar2:mov    ax,tbufsiz        ; take buffer size (bytes)
  2305.     call    malloc            ; get memory, seg returned in AX
  2306.     jc    getpar1a        ; c = failed
  2307.     mov    bx,takadr        ; bx = Take data structure
  2308.     mov    [bx].takbuf,ax        ; segment of memory
  2309.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  2310.     mov    es,ax            ; ES = segment of buffer
  2311.         mov     di,2                    ; skip count word field for es:di
  2312.     pop    ds            ; pop Environment segment (was in ES)
  2313.     pop    si            ;  and seg, DS:SI is now Environment
  2314.     xor    cx,cx            ; line length counter
  2315. getpar3:lodsb                ; read an Environment character
  2316.     or    al,al            ; null (EOL)?
  2317.     jz    getpar5            ; z = yes, stop here
  2318.     cmp    al,';'            ; semicolon separator?
  2319.     jne    getpar4            ; ne = no
  2320.     mov    al,CR            ; replace semicolon with carriage ret
  2321. getpar4:stosb                ; store char in Take buffer
  2322.     inc    cx            ; count line length
  2323.     jmp    short getpar3        ; get more text, until a null
  2324.  
  2325. getpar5:mov    al,CR            ; terminate line, regardless
  2326.     stosb
  2327.     inc    cx            ; count terminator
  2328.     pop    ds            ; restore regular DS
  2329.     mov    [bx].takcnt,cx        ; chars in Take/macro buffer
  2330.         mov     es:[0],cx               ; store count byte
  2331.         mov     [bx].takptr,2           ; init buffer read ptr to first char
  2332.     jcxz    getpar8            ; z = nothing left, exit
  2333.                     ; parse each item as a command
  2334. getpar6:mov    comand.cmquiet,1    ; no screen display
  2335.     mov    dx,offset nulprmpt    ; set null prompt
  2336.     call    prompt
  2337.     cmp    flags.extflg,0        ; exit flag set?
  2338.     jne    getpar8            ; ne = yes, exit this routine now
  2339.     mov    dx,offset initab    ; table of initialization routines
  2340.     xor    bx,bx            ; no explict help text
  2341.     mov    comand.cmcr,1        ; allow bare CR's
  2342.     mov    comand.impdo,0        ; do not search Macro table
  2343.         mov    ah,cmkey        ; match a keyword
  2344.     call    comnd
  2345.     jc    getpar7            ; c = failure
  2346.     mov    comand.cmcr,0        ; no more bare CR's
  2347.     call    bx            ; call the routine returned in BX
  2348.                     ; ignore failures (carry bit set)
  2349. getpar7:cmp    taklev,0        ; finished Take file?
  2350.     jle    getpar9            ; le = yes
  2351.     cmp    flags.extflg,0        ; exit flag set?
  2352.     je    getpar6            ; e = no, finish all commands
  2353.  
  2354. getpar8:call    takclos            ; close our take file, if open
  2355. getpar9:mov    flags.extflg,0        ; do not leave this flag set
  2356.     clc                ; clear for success
  2357. getparx:mov    comand.cmquiet,0    ; regular screen echoing
  2358.     pop    es
  2359.     pop    di
  2360.     pop    si
  2361.     pop    dx
  2362.     pop    cx
  2363.     pop    bx
  2364.     pop    ax
  2365.     ret
  2366. getparm    endp
  2367.  
  2368. ; Locate string variable in Environment
  2369. ; bx = variable to find (usually including =), cx = length of variable name.
  2370. ; Returns dx = offset within Environment of char following the name and
  2371. ; carry clear, else carry set and dx unchanged.
  2372. getenv    proc    near
  2373.     push    ax
  2374.     push    cx
  2375.     push    si
  2376.     push    di
  2377.     push    es
  2378.     mov    es,psp
  2379.     mov    ax,es:word ptr[env]    ; pick up environment address
  2380.     mov    es,ax
  2381.     xor    di,di            ; start at offset 0 in segment
  2382. geten1:    cmp    es:byte ptr [di],0    ; end of environment?
  2383.     je    geten3            ; yes, forget it
  2384.     push    cx            ; save counter
  2385.     push    di            ; and offset
  2386.     mov    si,bx
  2387.     cld
  2388.     repe    cmpsb            ; search for name
  2389.     pop    di
  2390.     pop    cx            ; restore these
  2391.     je    geten2            ; found it, break loop
  2392. getenv5:push    cx            ; preserve again
  2393.     mov    cx,0ffffh        ; bogus length
  2394.     xor    al,al            ; 0 = marker to look for
  2395.     repne    scasb            ; search for it
  2396.     pop    cx            ; restore length
  2397.     jmp    short geten1        ; loop thru rest of environment
  2398. geten2:    add    di,cx            ; skip to definition
  2399. geten6:    mov    si,bx            ; name
  2400.     add    si,cx            ; length
  2401.     cmp    byte ptr [si-1],'='    ; caller wanted '=' as last char?
  2402.     je    geten7            ; e = yes, and we found it
  2403.     mov    al,es:[di]        ; get next char
  2404.     cmp    al,'='            ; at the equals sign?
  2405.     je    geten7            ; e = yes
  2406.     inc    di            ; point at next char
  2407.     cmp    al,' '            ; white space?
  2408.     jbe    geten6            ; be = yes, skip over this
  2409.     dec    di            ; backup
  2410.     jmp    short getenv5        ; not a match, keep looking
  2411. geten7:    mov    dx,di            ; store offset of string
  2412.     clc                ; carry clear for success
  2413.     jmp    short geten4
  2414. geten3:    stc                ; carry set for failure
  2415. geten4:    pop    es
  2416.     pop    di
  2417.     pop    si
  2418.     pop    cx
  2419.     pop    ax
  2420.     ret
  2421. getenv    endp
  2422.  
  2423. ; SETENV
  2424. ; Put  "NAME=string" to the DOS master environment, uses undocumented Int 2Eh
  2425. setenv    proc    near
  2426.     mov    bx,offset decbuf+1    ; borrowed buffer
  2427.     mov    word ptr [bx],'ES'
  2428.     mov    word ptr [bx+2],' T'    ; preload "SET "
  2429.     add    bx,4            ; where rest of text goes
  2430.     mov    dx,offset setenvhlp    ; help
  2431.     mov    comand.cmblen,126 - 4    ; max buffer length
  2432.     mov    ah,cmline        ; get line of text
  2433.     call    comnd
  2434.     jnc    setenv1            ; nc = success
  2435.     ret                ; failure
  2436.  
  2437. setenv1:mov    bx,offset decbuf+1+4    ; look after "SET " 
  2438.     add    bx,ax            ; plus length of user string
  2439.     mov    word ptr [bx],CR    ; terminate in CR NUL
  2440.     sub    bx,offset decbuf    ; compute length
  2441.     mov    decbuf,bl        ; <count byte><text>CR
  2442.     mov    ah,getintv        ; does Int 2eh exist?
  2443.     mov    al,2eh
  2444.     int    dos
  2445.     jnc    setenv2            ; nc = call succeeded
  2446.     ret
  2447. setenv2:cmp    byte ptr es:[bx],0cfh    ; is an IRET?
  2448.     jne    setenv3            ; no, assume vector exists
  2449.     stc
  2450.     ret
  2451. setenv3:push    si
  2452.     push    di
  2453.     push    bp
  2454.     cli
  2455.     mov    ax,ss            ; save ss:sp
  2456.     mov    word ptr ssave+2,ax
  2457.     mov    word ptr ssave,sp
  2458.     sti
  2459.     cld
  2460.     mov    si,offset decbuf    ; string pointer to ds:si
  2461.     int    2eh            ; Command.com, do contents of ds:si
  2462.     mov    bx,data            ; restore segment registers
  2463.     mov    ds,bx            ; reset data segment
  2464.     mov    es,bx            ; and extra segment
  2465.     cli
  2466.     mov    bx,word ptr ssave+2
  2467.     mov    ss,bx            ; and stack segment
  2468.     mov    sp,word ptr ssave    ; restore stack ptr
  2469.     sti
  2470.     pop    bp
  2471.     pop    di
  2472.     pop    si
  2473.     clc
  2474.     ret
  2475. setenv    endp
  2476.  
  2477. ; Store drive:path\ of where Kermit was started into string startup
  2478. getargv    proc    near
  2479.     push    si
  2480.     push    di
  2481.     push    es
  2482.     mov    es,psp
  2483.     mov    ax,es:word ptr[env]    ; pick up environment address
  2484.     mov    es,ax
  2485.     xor    di,di            ; start at offset 0 in segment
  2486.     mov    cx,0ffffh        ; bogus length
  2487. getargv1:xor    al,al            ; 0 = marker to look for
  2488.     repne    scasb            ; search for it
  2489.     cmp    es:byte ptr [di],0    ; end of environment (double null)?
  2490.     jne    getargv1        ; ne = no
  2491.     inc    di            ; skip single null
  2492.     cmp    es:word ptr [di],1    ; marker for argv[0]?
  2493.     jne    getargv5        ; ne = no
  2494.     add    di,2            ; skip word
  2495.     mov    si,offset startup    ; startup string
  2496.     mov    cx,63            ; max length of wanted string
  2497. getargv2:mov    al,es:[di]        ; get char
  2498.     mov    [si],al            ; store in startup string
  2499.     inc    si
  2500.     inc    di
  2501.     or    al,al            ; null terminator?
  2502.     loopnz    getargv2        ; nz = no
  2503.                     ; trim off filename part
  2504.     mov    cx,si
  2505.     sub    cx,offset startup
  2506.     dec    si
  2507. getargv3:cmp    byte ptr [si],':'    ; back to drive terminator?
  2508.     jne    getargv3a        ; ne = no
  2509.     mov    byte ptr [si+1],'\'    ; make drive:\ syntax for root
  2510.     inc    si            ; move over separators
  2511.     jmp    short getargv4        ; done
  2512. getargv3a:cmp    byte ptr [si],'\'    ; or path separator?
  2513.     je    getargv4        ; e = yes
  2514.     dec    si            ; backup
  2515.     loop    getargv3
  2516.  
  2517. getargv4:mov    byte ptr [si+1],0    ; terminate string
  2518. getargv5:pop    es
  2519.     pop    di
  2520.     pop    si
  2521.     ret
  2522. getargv    endp
  2523.  
  2524. ; Get thousands separator from DOS Country Information
  2525. gettsep    proc    near
  2526.     mov    ah,38h            ; Get Country Information
  2527.     mov    dx,offset tmpbuf    ; temp buffer
  2528.     int    dos
  2529.     mov    bx,7            ; assume DOS 3+ position in buffer
  2530.     cmp    byte ptr dosnum+1,3    ; DOS 3 or above?
  2531.     jae    gettse1            ; ae = yes
  2532.     mov    bx,4            ; for DOS 2.1
  2533.     cmp    dosnum,210h        ; earlier than version 2.1?
  2534.     jae    gettse1            ; ae = no
  2535.     mov    al,','            ; use comma for old DOS's
  2536. gettse1:mov    al,tmpbuf[bx]        ; get thousands separator char
  2537.     mov    thsep,al        ; save it
  2538.     mov    al,tmpbuf        ; get time/date format code
  2539.     mov    tdfmt,al        ; save it
  2540.     ret
  2541. gettsep    endp
  2542.  
  2543. STAY    PROC    NEAR
  2544.     clc
  2545.     ret
  2546. STAY    ENDP
  2547.  
  2548. ; CHECK <build features>, returns success if feature is present
  2549. CHECK    proc    near
  2550.     mov    kstatus,kssuc        ; global status
  2551.     mov    ah,cmkey
  2552.     mov    dx,offset featab    ; feature table
  2553.     xor    bx,bx            ; table is help
  2554.     call    comnd
  2555.     jnc    check1            ; nc = success
  2556.     mov    kstatus,ksgen        ; general failure
  2557.     ret
  2558. check1:    push    bx
  2559.     mov    ah,cmeol
  2560.     call    comnd
  2561.     pop    bx
  2562.     jnc    check1a
  2563.     mov    kstatus,ksgen        ; general failure
  2564.     ret
  2565. check1a:mov    di,offset tmpbuf
  2566.     cmp    bx,1            ; graphics?
  2567.     jne    check2            ; ne = no
  2568.     mov    si,offset msggraph
  2569.     call    strcpy
  2570. ifdef    no_graphics
  2571.     mov    kstatus,ksgen
  2572.     mov    si,offset msgnot
  2573.     call    strcat
  2574. endif
  2575.     jmp    short check6
  2576.  
  2577. check2:    cmp    bx,2            ; tcp/ip?
  2578.     jne    check3            ; ne = no
  2579.     mov    si,offset msgtcpip
  2580.     call    strcpy
  2581. ifdef    no_tcp
  2582.     mov    kstatus,ksgen
  2583.     mov    si,offset msgnot
  2584.     call    strcat
  2585. endif
  2586.     jmp    short check6
  2587.  
  2588. check3:    cmp    bx,3            ; networks?
  2589.     jne    check4            ; ne = no
  2590.     mov    si,offset msgnetwork
  2591.     call    strcpy
  2592. ifdef    no_network
  2593.     mov    kstatus,ksgen
  2594.     mov    si,offset msgnot
  2595.     call    strcat
  2596. endif
  2597.     jmp    short check6
  2598.  
  2599. check4:    cmp    bx,4            ; terminals?
  2600.     jne    check5            ; ne = no
  2601.     mov    si,offset msgterm    ; terminals
  2602.     call    strcpy
  2603. ifdef    no_terminal
  2604.     mov    kstatus,ksgen
  2605.     mov    si,offset msgnot
  2606.     call    strcat
  2607. endif
  2608.     jmp    short check6
  2609.  
  2610. check5:    mov    si,offset msgif        ; IF statements
  2611.     call    strcpy
  2612.  
  2613. check6:    mov    si,offset msgavail
  2614.     call    strcat
  2615.     cmp    taklev,0        ; at top level?
  2616.     jne    checkx            ; ne = no, be quiet
  2617.     mov    dx,offset tmpbuf    ; show msg
  2618.     mov    ah,prstr
  2619.     int    dos
  2620. checkx:    ret                ; return status
  2621. CHECK    endp
  2622.  
  2623. TESTCOM    proc    near
  2624.     mov    kstatus,kssuc        ; global status
  2625.     mov    ah,cmkey
  2626.     mov    dx,offset chktab    ; check comm port table
  2627.     xor    bx,bx            ; table is help
  2628.     call    comnd
  2629.     jnc    testc1            ; nc = success
  2630.     mov    kstatus,ksgen        ; general failure
  2631.     ret
  2632. testc1:    mov    al,flags.comflg        ; save current comms port flag
  2633.     push    ax
  2634.     mov    flags.comflg,bl        ; port number, 1..4
  2635.     call    tstport            ; see if real UART, carry set if not
  2636.     pop    ax
  2637.     mov    flags.comflg,al        ; restore flag
  2638.     mov    dx,offset erms39    ; say UART
  2639.     jnc    testc2            ; nc = real UART
  2640.     mov    dx,offset erms38    ; say non-UART
  2641.     mov    kstatus,ksgen        ; set failure state for non-UART
  2642. testc2:    cmp    taklev,0        ; in a Take file or macro?
  2643.     je    testc3            ; e = no, display
  2644.     cmp    flags.takflg,0        ; Take echo off?
  2645.     je    testc4            ; e = yes, do not display
  2646. testc3:    mov    ah,prstr
  2647.     int    dos
  2648. testc4:    ret
  2649. TESTCOM endp
  2650.  
  2651. CLS    proc    near            ; Clear command level screen
  2652.     mov    ah,cmeol        ; get a confirmation
  2653.     call    comnd
  2654.     jc    cls1            ; c = failure
  2655.     call    cmblnk            ; blank the screen
  2656.     call    locate            ; put cursor at home position
  2657. cls1:    ret
  2658. CLS    endp
  2659.  
  2660. COMNT    PROC    NEAR            ; COMMENT command
  2661.     mov    ah,cmline
  2662.     mov    bx,offset tmpbuf
  2663.     xor    dx,dx            ; help
  2664.     call    comnd
  2665.     jc    comnt1
  2666.     mov    ah,cmeol
  2667.     call    comnd
  2668. comnt1:    ret
  2669. COMNT    ENDP
  2670.  
  2671. ; change working directory
  2672. cwdir    proc    near
  2673.     mov    kstatus,kssuc        ; global status
  2674.     mov    ah,cmword
  2675.     mov    bx,offset tmpbuf
  2676.     mov    dx,offset pthmsg
  2677.     mov    word ptr tmpbuf,0
  2678.     call    comnd            ; get drive/dir spec, if any
  2679.     mov    ah,cmeol
  2680.     call    comnd
  2681.     jnc    cwd1
  2682.     ret                ; c = failure
  2683. cwd1:    mov    si,offset tmpbuf    ; cdsr wants drive/path ptr in si
  2684.     call    cdsr            ; common CD sub-routine
  2685.     jnc    cwd2            ; nc = success
  2686.     mov    kstatus,ksgen        ; global status for unsuccess
  2687. cwd2:    cmp    taklev,0        ; in a Take file or macro?
  2688.     je    cwd3            ; e = no, do echo
  2689.     cmp    flags.takflg,0        ; ok to echo?
  2690.     je    cwd4            ; e = no
  2691. cwd3:    push    dx
  2692.     mov    dx,offset crlf        ; msgs from cdsr don't include this
  2693.     mov    ah,prstr        ; so let's do it now
  2694.     int    dos
  2695.     pop    dx
  2696.     call    prtasz            ; output current drive/path or err msg
  2697. cwd4:    clc
  2698.     ret
  2699. cwdir    endp
  2700.  
  2701. ; Erase specified file(s). Add protection of ignore hidden, subdir, volume
  2702. ; label and system files. 9 Jan 86 [jrd]
  2703. DELETE    PROC    NEAR            ; includes paths and "?*" wildcards
  2704.     mov    kstatus,kssuc        ; global status
  2705.     mov    si,offset delcmd    ; del command
  2706.     mov    di,offset tmpbuf
  2707.     call    strcpy
  2708.     mov    dx,offset tmpbuf
  2709.     call    strlen            ; get its length
  2710.     add    di,cx            ; point at terminator
  2711.     mov    temp,di            ; remember starting spot
  2712.     mov    ah,cmline        ; get a line
  2713.     mov    bx,di            ; where to place the file spec
  2714.     mov    dx,offset filmsg    ; help message
  2715.     call    comnd
  2716.     jc    delet0            ; c = failure
  2717.     push    ax
  2718.     mov    ah,cmeol
  2719.     call    comnd
  2720.     pop    ax
  2721.     jc    delet0
  2722.     cmp    apctrap,0        ; disable from APC
  2723.     jne    delet0            ; ne = yes
  2724.     or    ax,ax            ; anything given?
  2725.     jnz    delet1            ; nz = yes
  2726.     mov    ah,prstr
  2727.     mov    dx,offset ermes1    ; say need something
  2728.     int    dos
  2729.     clc                ; say success
  2730. delet0:    mov    kstatus,ksgen        ; global status
  2731.     ret
  2732.  
  2733. delet1:    mov    si,offset tmpbuf    ; source
  2734.     mov    di,temp            ; start of filespec
  2735.     xor    cl,cl            ; disk drive letter
  2736.     cmp    byte ptr [di+1],':'    ; drive specified?
  2737.     jne    delet2            ; ne = no
  2738.     mov    cl,[di]            ; get drive letter
  2739. delet2:    call    dskspace        ; compute space, get letter into CL
  2740.     jnc    delet3            ; nc = success
  2741.     mov    spcmsg3,cl        ; put drive letter in msg
  2742.     mov    dx,offset spcmsg2    ; error message
  2743.     call    prtasz
  2744.     mov    kstatus,ksgen        ; global status
  2745.     clc
  2746.     ret                ; and ignore this command
  2747. delet3:    mov    si,offset tmpbuf    ; del cmd
  2748.     jmp    crun            ; join run cmd from there
  2749. DELETE    ENDP
  2750.  
  2751. ; Space <optional drive letter>
  2752.  
  2753. CHKDSK    PROC    NEAR            ; Space command
  2754.     mov    kstatus,kssuc        ; global status
  2755.     mov    bx,offset tmpbuf    ; buffer
  2756.     mov    tmpbuf,0        ; init to null
  2757.     mov    dx,offset dskmsg    ; help message
  2758.     mov    ah,cmword        ; get optional drive letter
  2759.     call    comnd            ; ignore errors
  2760.     mov    ah,cmeol
  2761.     call    comnd
  2762.     jnc    chkdsk1            ; nc = success
  2763.     ret                ; failure
  2764. chkdsk1:mov    cl,tmpbuf        ; set drive letter
  2765.     call    dskspace        ; compute space, get letter into CL
  2766.     jnc    chkdsk2            ; nc = success
  2767.     and    cl,5fh            ; to upper case
  2768.     mov    spcmsg3,cl        ; insert drive letter
  2769.     mov    dx,offset spcmsg2    ; say drive not ready
  2770.     call    prtasz
  2771.     mov    kstatus,ksgen        ; global status
  2772.     clc
  2773.     ret
  2774.     
  2775. chkdsk2:mov    spcmsg1,cl        ; insert drive letter
  2776.     mov    di,offset tmpbuf    ; work space for lnout
  2777.     mov    word ptr[di],0a0dh    ; cr/lf
  2778.     mov    word ptr[di+2],'  '    ; add two spaces
  2779.     add    di,4
  2780.     call    lnouts            ; use thousands separator
  2781.     mov    si,offset spcmsg
  2782.     call    strcat            ; add text to end of message
  2783.     mov    dx,offset tmpbuf
  2784.     call    prtasz            ; print asciiz string
  2785.     clc
  2786.     ret
  2787. CHKDSK    ENDP
  2788.  
  2789.  
  2790. ; Get directory    listing
  2791. DIRECT    PROC    NEAR
  2792.     mov    kstatus,kssuc        ; global status
  2793.     mov    si,offset dircmd    ; dir command
  2794.     mov    di,offset tmpbuf
  2795.     call    strcpy
  2796.     mov    dx,offset tmpbuf
  2797.     call    strlen            ; get its length
  2798.     add    di,cx            ; point at terminator
  2799.     mov    temp,cx            ; remember length
  2800.     mov    ah,cmline        ; parse with cmline to allow switches
  2801.     mov    bx,di            ; next available byte
  2802.     mov    dx,offset filmsg    ; help message 
  2803.     call    comnd
  2804.     jnc    direct1            ; nc = success
  2805. direct0:mov    kstatus,ksgen        ; global status
  2806.     ret                ; failure
  2807. direct1:mov    ah,cmeol
  2808.     call    comnd
  2809.     jc    direct0
  2810.     mov    word ptr [bx],0        ; plant terminator
  2811.     mov    si,offset tmpbuf
  2812.     push    si
  2813.     add    si,temp            ; user's text after ' dir '
  2814.     mov    cl,curdsk        ; current drive number ('A'=1)
  2815.     add    cl,'A'-1        ; make a letter
  2816.     cmp    byte ptr [si+1],':'    ; drive specified?
  2817.     jne    direct2            ; ne = no, use current drive
  2818.     mov    cl,[si]            ; get drive letter from buffer
  2819. direct2:call    dskspace        ; check for drive ready
  2820.     pop    si
  2821.     jnc    direct3            ; nc = drive ready
  2822.     mov    spcmsg3,cl        ; insert letter
  2823.     mov    dx,offset spcmsg2    ; say drive is not ready
  2824.     call    prtasz
  2825.     mov    kstatus,ksgen        ; global status
  2826.     stc
  2827.     ret
  2828. direct3:jmp    crun            ; join run cmd from there
  2829. DIRECT    ENDP
  2830.  
  2831. ; This is the 'HELP' command.  It gives a list of the commands
  2832. ; And INTRO command
  2833. INTRO    proc    near
  2834.     mov    kstatus,kssuc        ; global status
  2835.     mov    ah,cmeol
  2836.     call    comnd            ; get a confirm
  2837.     jnc    intro1            ; nc = success
  2838.     ret                ; failure
  2839. intro1:
  2840. ifdef    no_terminal
  2841.     ret
  2842. else
  2843.     push    es
  2844.     mov    ax,seg intrhlp        ; all Intro text is in data1
  2845.     mov    es,ax
  2846.     mov    al,trans.escchr        ; Connect mode escape char
  2847.     cmp    al,' '            ; printable now?
  2848.     jae    intro2            ; ae = yes
  2849.     add    al,40h            ; make control visible
  2850. intro2:    mov    si,offset intrhlp1
  2851.     mov    es:[si],al
  2852.     mov    si,offset intrhlp2
  2853.     mov    es:[si],al
  2854.     mov    si,offset intrhlp    ; Intro text in seg data1
  2855.     xor    bx,bx            ; line counter
  2856.     cld
  2857.      jmp    short help2        ; common tail
  2858. endif    ; ifdef no_terminal
  2859. INTRO    endp
  2860.  
  2861. HELP    PROC    NEAR
  2862.     mov    kstatus,kssuc        ; global status
  2863.     mov    ah,cmeol
  2864.     call    comnd            ; get a confirm
  2865.     jnc    help1            ; nc = success
  2866.     ret                ; failure
  2867. help1:    mov    si,offset qckhlp    ; help text in seg data1
  2868.     xor    bx,bx            ; line counter
  2869.     push    es
  2870.     mov    ax,seg qckhlp        ; all help text is in data1
  2871.     mov    es,ax
  2872.     cld
  2873.  
  2874. HELP2:    mov    al,es:[si]        ; read a help msg byte
  2875.     inc    si
  2876.     cmp    al,'$'            ; end of message?
  2877.     je    help3            ; e = yes, stop
  2878.     mov    ah,conout
  2879.     mov    dl,al
  2880.     int    dos            ; display byte
  2881.     cmp    dl,LF            ; line break?
  2882.     jne    help2            ; ne = no
  2883.     inc    bl            ; count line
  2884.     cmp    bl,dos_bottom        ; (24) time for a more msg?
  2885.     jbe    help2            ; be = not yet
  2886.     xor    bl,bl            ; reset line count
  2887.     call    iseof            ; are we at EOF, such as from disk?
  2888.     jc    help2            ; c = yes, ignore more msg
  2889.     push    es
  2890.     push    si
  2891.     mov    ah,prstr
  2892.     mov    dx,offset moremsg    ; "... more..." msg
  2893.     int    dos
  2894.     pop    si
  2895.     pop    es
  2896.     mov    ah,coninq        ; read the char from file, not device
  2897.     int    dos
  2898.     cmp    al,3            ; a ^C?
  2899.     je    short help3        ; e = yes, stop the display
  2900.     cmp    al,'?'            ; query?
  2901.     je    helpquery        ; e = yes
  2902.     push    bx            ; save line counter
  2903.     push    es            ; and read pointer
  2904.     push    si
  2905.     call    ctlu            ; clear display's line, reuse it
  2906.     pop    si
  2907.     pop    es
  2908.     pop    bx
  2909.     jmp    short help2        ; continue
  2910. help3:    pop    es
  2911.     clc
  2912.     ret
  2913.  
  2914. helpquery:pop    es
  2915.     mov    ah,prstr        ; show help summary screen
  2916.     mov    dx,offset crlf        ; a few blank lines
  2917.     int    dos
  2918.     int    dos
  2919.     int    dos
  2920.     push    ds
  2921.     mov    dx,seg tophlp
  2922.     mov    ds,dx
  2923.     mov    dx,offset tophlp    ; show usual cryptic help
  2924.     int    dos
  2925.     pop    ds
  2926.     clc
  2927.     ret
  2928. HELP    ENDP
  2929.  
  2930. ; the version command - print our version number
  2931. prvers    proc    near
  2932.     mov    kstatus,kssuc        ; global status
  2933.     mov    ah,cmeol
  2934.     call    comnd
  2935.     jc    prvers1            ; c = failure
  2936.     mov    ah,prstr
  2937.     mov    dx,offset crlf
  2938.     int    dos
  2939.     mov    ah,prstr
  2940.     mov    dx,offset machnam    ; display machine name
  2941.     int    dos
  2942.     mov    ah,prstr        ; display the version header
  2943.     mov    dx,offset verident
  2944.     int    dos
  2945.     mov    ah,prstr
  2946.     mov    dx,offset copyright2    ; full copyright notice
  2947.     int    dos
  2948.     clc
  2949. prvers1:ret
  2950. prvers    endp
  2951.  
  2952. ; SHOW command dispatcher
  2953. showcmd    proc    near
  2954.     mov    ah,cmkey
  2955.     mov    dx,offset shotab
  2956.     xor    bx,bx            ; no canned help
  2957.     call    comnd
  2958.     jc    showc1            ; c = failure
  2959.     jmp    bx            ; execute the handler
  2960. showc1:    ret                ; failure
  2961. showcmd    endp
  2962.  
  2963. ; the type command - type out a file
  2964. typec    proc    near
  2965.     mov    kstatus,kssuc        ; global status
  2966.     mov    si,offset typcmd    ; type command
  2967.     mov    di,offset tmpbuf
  2968.     call    strcpy
  2969.     mov    dx,offset tmpbuf
  2970.     call    strlen            ; get its length
  2971.     add    di,cx            ; point at terminator
  2972.     mov    temp,di            ; save place for later
  2973.     mov    ah,cmline        ; parse with cmline, allows | more
  2974.     mov    bx,di            ; next available byte
  2975.     mov    dx,offset filmsg    ; In case user wants help
  2976.     call    comnd
  2977.     jc    typec1            ; c = failure
  2978.     push    ax
  2979.     mov    ah,cmeol
  2980.     call    comnd
  2981.     pop    ax
  2982.     jc    typec1
  2983.     or    ax,ax            ; any text given?
  2984.     jnz    typec2            ; nz = yes
  2985.     mov    ah,prstr
  2986.     mov    dx,offset ermes1    ; say need more info
  2987.     int    dos
  2988.     mov    kstatus,ksgen        ; global status
  2989.     clc
  2990. typec1:    ret
  2991. typec2:    mov    byte ptr [bx],0        ; plant terminator
  2992.     mov    si,temp            ; start of filespec
  2993.     xor    cl,cl            ; say local drive
  2994.     cmp    byte ptr [si+1],':'    ; drive given?
  2995.     jne    typec3            ; ne = no
  2996.     mov    cl,[si]            ; get drive letter
  2997. typec3:    call    dskspace        ; check for drive ready
  2998.     jnc    typec4
  2999.     mov    spcmsg3,cl        ; put drive letter in msg
  3000.     mov    dx,offset spcmsg2    ; error message
  3001.     call    prtasz
  3002.     mov    kstatus,ksgen        ; global status
  3003.     clc
  3004.     ret                ; and ignore this command
  3005. typec4:    mov    si,offset tmpbuf
  3006.     jmp    short crun        ; join run cmd from there
  3007. typec    endp
  3008.  
  3009. ; PUSH to DOS (run another copy of Command.com or equiv)
  3010. ; entry fpush (fast push...) pushes without waiting for a confirm
  3011. dopush    proc    near
  3012.     mov    ah,cmeol
  3013.     call    comnd
  3014.     jnc    fpush            ; nc = success
  3015.     ret                ; failure
  3016. fpush:    cmp    nopush_flag,0        ; pushing allowed?
  3017.     jne    fpush1            ; ne = no
  3018.     mov    si,offset tmpbuf    ; a dummy buffer
  3019.     mov    byte ptr [si],0        ; plant terminator
  3020.     mov    dx,offset cmspbuf    ; always use command.com
  3021.     cmp    shellbuf,0        ; SHELL= present?
  3022.     je    crun4            ; e = no, use COMSPEC= name
  3023.     mov    dx,offset shellbuf    ; use SHELL= name
  3024.     jmp    short crun4        ; go run it
  3025. fpush1:    stc                ; fail
  3026.     ret
  3027. dopush    endp
  3028.  
  3029. ; Run a program from within Kermit
  3030. RUN    PROC    NEAR
  3031.     mov    ah,cmline        ; get program name and any arguments
  3032.     mov    bx,offset tmpbuf    ; place for user's text
  3033.     mov    dx,offset runmsg    ; In case user wants help
  3034.     call    comnd
  3035.     jnc    run1            ; nc = success
  3036.     ret                ; failure
  3037. run1:    cmp    apctrap,0        ; disable from APC
  3038.     jne    run3            ; ne = yes, fail
  3039.     cmp    nopush_flag,0        ; pushing disabled?
  3040.     jne    run3            ; ne = yes, fail
  3041.     or    ax,ax            ; byte count
  3042.     jnz    run2            ; nz = have program name
  3043.     mov    ah,prstr        ; else complain
  3044.     mov    dx,offset ermes1    ; need more info
  3045.     int    dos
  3046.     clc
  3047.     ret
  3048. run2:    mov    si,offset tmpbuf    ; source of text
  3049.     jmp    short crun
  3050.  
  3051. run3:    stc                ; failure exit
  3052.     ret
  3053. RUN    ENDP
  3054.  
  3055. ; crun - run an arbitrary program.
  3056. ; Enter with ordinary ASCIIZ command in SI (such as Dir *.asm)
  3057. ; Append a c/r and a null terminator and then ask command.com to do it
  3058. ; Set errlev with DOS errorlevel from subprocess.
  3059. CRUN    proc    near
  3060.     mov    ah,prstr        ; output crlf before executing comnd
  3061.     mov    dx,offset crlf        ; [lba]
  3062.     int    dos
  3063.     mov    di,offset tmpbuf    ; where to put full command line text
  3064.     cmp    si,di            ; same place?
  3065.     je    crun1            ; e = yes, don't copy ourself
  3066.     call    strcpy            ; si holds source text
  3067. crun1:    mov    si,offset slashc    ; DOS command begins with slashc area
  3068.     mov    dx,offset slashc+1    ; si points to /c part of command line
  3069.     call    strlen            ; get its length into cx
  3070.     push    bx
  3071.     mov    bx,dx
  3072.     add    bx,cx
  3073.     mov    byte ptr [bx],cr    ; end string with a c/r for dos
  3074.     inc    cx            ; count the c/r
  3075.     mov    byte ptr [bx+1],0    ; and terminate
  3076.     pop    bx
  3077.     mov    [si],cl            ; put length of argument here
  3078.     mov    dx,offset cmspbuf    ; always use command.com
  3079. crun4:    mov    exearg+2,si        ; pointer to argument string
  3080.     mov    exearg+4,ds        ; segment of same
  3081.     cmp    lclsusp,0        ; sys dependent routine to call
  3082.     je    crun5            ; e = none
  3083.     mov    bx,lclsusp        ; address to call
  3084.     push    dx            ; preserve name in dx
  3085.     call    bx            ; call sys dependent suspend routine
  3086.     pop    dx
  3087. crun5:    push    dx            ; preserve name in dx
  3088.     call    serrst            ; reset serial port (if active)
  3089.     call    cbrestore        ; restore state of Control-Break Chk
  3090.     pop    dx
  3091.     mov    es,psp            ; point to psp again
  3092.     mov    exearg+8,es        ; segment of psp, use our def fcb's
  3093.     mov    exearg+12,es        ; segment of psp, ditto, for fcb 2
  3094.     mov    ax,es:word ptr [env]    ; get environment ptr
  3095.     mov    exearg,ax        ; put into argument block
  3096.     mov    ax,ds
  3097.     mov    es,ax            ; put es segment back
  3098.     mov    bx,offset exearg    ; es:bx points to exec parameter block
  3099.     mov    ax,ss            ; save ss:sp
  3100.     mov    word ptr ssave+2,ax
  3101.     mov    word ptr ssave,sp
  3102.     xor    al,al            ; 0 = load and execute (DX has name)
  3103.     mov    ah,exec
  3104.     int    dos            ; go run command.com
  3105.     mov    bx,data            ; restore segment registers
  3106.     mov    ds,bx            ; reset data segment
  3107.     mov    es,bx            ; and extra segment
  3108.     cli
  3109.     mov    bx,word ptr ssave+2
  3110.     mov    ss,bx            ; and stack segment
  3111.     mov    sp,word ptr ssave    ; restore stack ptr
  3112.     sti
  3113.     jnc    crun9            ; nc = no error
  3114.     mov    ah,prstr        ; failure, complain
  3115.     mov    dx,offset erms37
  3116.     int    dos
  3117.     mov    dx,offset cmspbuf    ; path\name of command.com
  3118.     call    prtasz            ; asciiz
  3119.     mov    kstatus,ksgen        ; global status
  3120. crun9:    mov    ah,setdma        ; restore dma buffer pointer
  3121.     mov    dx,offset buff
  3122.     int    dos            ; restore dma address!!
  3123.     call    cboff            ; turn off DOS BREAK check
  3124.     cmp    lclrest,0        ; sys dependent routine to call?
  3125.     je    crun10            ; e = none
  3126.     mov    bx,lclrest        ; get routine's address
  3127.     call    bx            ; call sys dependent restore routine
  3128. crun10:    clc
  3129.     ret
  3130. CRUN    ENDP
  3131. code    ends
  3132.  
  3133. code1    segment
  3134.     assume    cs:code1 
  3135.  
  3136. ; Write path and filename of current Take file to buffer cmdfile. 
  3137. ; Enter with current working filename offset in register dx.
  3138. save_cmdfile    proc far
  3139.     push    ax
  3140.     push    dx
  3141.     push    es
  3142.     mov    di,ds
  3143.     mov    es,di
  3144.     mov    di,offset cmdfile    ; destination
  3145.     mov    si,dx            ; source path
  3146.     mov    ax,[si]
  3147.     cmp    ah,':'            ; drive specified?
  3148.     jne    save_c1            ; ne = no
  3149.     and    al,not 20h        ; upper case the drive letter
  3150.     add    si,2            ; next byte to read
  3151.     jmp    short save_c2
  3152. save_c1:mov    al,curdsk        ; current drive letter
  3153.     add    al,'A'-1        ; number back to letter
  3154.     mov    ah,':'            ; and letter
  3155. save_c2:cld
  3156.     stosw                ; write to output
  3157.     xor    al,al
  3158.     mov    [di],al            ; terminate
  3159.     cmp    byte ptr [si],'\'    ; rooted path?
  3160.     je    save_c3            ; e = yes
  3161.     mov    al,'\'            ; get root indicator
  3162.     stosb                ; write to output
  3163.     mov    dl,cmdfile        ; get upper case drive letter
  3164.     sub    dl,'A'-1        ; A = 1
  3165.     push    si
  3166.     mov    si,di            ; gcd writes to si
  3167.     mov    ah,gcd            ; get current directory (path really)
  3168.     int    dos
  3169.     mov    dx,si
  3170.     call    strlen
  3171.     add    di,cx
  3172.     pop    si
  3173.     jcxz    save_c3            ; z = no directory, have \ already
  3174.     mov    al,'\'            ; path separator
  3175.     stosb
  3176.     mov    byte ptr [di],0        ; terminator
  3177. save_c3:call    strcpy            ; copy rest of string
  3178.     pop    es
  3179.     pop    dx
  3180.     pop    ax
  3181.     ret
  3182. save_cmdfile    endp
  3183.  
  3184. ; Replace Int 23h and Int 24h with our own handlers
  3185. ; Revised to ask DOS for original interrupt vector contents, as suggested by
  3186. ; Jack Bryans. 9 Jan 1986 jrd
  3187. ; Modified again 30 August 1986 [jrd]
  3188. SETINT    PROC    FAR
  3189.     push    es            ; save registers
  3190.     mov    al,23H            ; desired interrupt vector (^C)
  3191.     mov    ah,getintv        ; Int 21H, function 35H = Get Vector
  3192.     int    dos            ; get vector in es:bx
  3193.     mov    in3ad,bx        ; save offset of original vector
  3194.     mov    in3ad+2,es        ;   and its segment
  3195.     mov    al,24h            ; DOS critical error, Int 24h
  3196.     mov    ah,getintv
  3197.     int    dos
  3198.     mov    word ptr ceadr,bx    ; DOS's Critical Error handler, offset
  3199.     mov    word ptr ceadr+2,es    ;  and segment address
  3200.     push    ds            ; save ds around next DOS calls
  3201.     mov    ax,seg intbrk        ; compose full address of ^C routine
  3202.     mov    ds,ax            ; segment is the code segment
  3203.     mov    dx,offset intbrk    ;   and offset is intbrk
  3204.     mov    al,23H            ; on ^C, goto intbrk
  3205.     mov    ah,setintv        ; set interrupt address from ds:dx
  3206.     int    dos
  3207.     mov    dx,offset dosce        ; replacement Critical Error handler
  3208.     mov    al,24h            ; interrupt 24h
  3209.     mov    ah,setintv        ; replace it
  3210.     int    dos
  3211.     pop    ds
  3212.     mov    ax,3300h        ; get state of Control-Break Check
  3213.     int    dos
  3214.     mov    orgcbrk,dl        ; save state here
  3215.     pop    es
  3216.     ret
  3217. SETINT    ENDP
  3218.  
  3219. ; Control Break, Interrupt 23h replacement
  3220. ; Always return with a Continue (vs Abort) condition since Kermit will cope
  3221. ; with failures. [jrd]
  3222. intbrk:    push    ax
  3223.     push    ds    
  3224.     mov    ax,data            ; get Kermit's data segment
  3225.     mov    ds,ax
  3226.     mov    flags.cxzflg,'C'    ; say we saw a ^C
  3227.     mov    rstate,'E'
  3228.     mov    sstate,'E'
  3229.     pop    ds
  3230.     pop    ax
  3231.     iret               ; return to caller in a Continue condition
  3232.  
  3233. ; Kermit's DOS Critical Error Handler, Int 24h. [jrd]
  3234. ; Needed to avoid aborting Kermit with the serial port interrupt active and
  3235. ; the Control Break interrupt redirected. See the DOS Tech Ref Manual for
  3236. ; a start on this material; it is neither complete nor entirely accurate
  3237. ; The stack is the Kermit's stack, the data segment is unknown, interrupts
  3238. ; are off, and the code segment is Kermit's. Note: some implementations of
  3239. ; MS DOS may leave us in DOS's stack. Called by a DOS Int 21h function
  3240. dosce:    test    ah,80h        ; block device (disk drive)?
  3241.     jnz    dosce1        ; nz = no; serial device, memory, etc
  3242.     mov    al,3        ; tell DOS to Fail the Int 21h call
  3243.     iret            ; return to DOS
  3244. dosce1:    add    sp,6        ; pop IP, CS, Flags regs, from DOS's Int 24h
  3245.     pop    ax        ; restore original callers regs existing
  3246.     pop    bx        ;  just before doing Int 21h call
  3247.     pop    cx
  3248.     pop    dx
  3249.     pop    si
  3250.     pop    di
  3251.     pop    bp
  3252.     pop    ds
  3253.     pop    es        
  3254.     mov    al,0ffh        ; signal failure (usually) the DOS 1.x way
  3255.     push    bp        ; Kermit's IP, CS, and Flags are on the stack
  3256.     mov    bp,sp        ;  all ready for an iret, but first a word ..
  3257.     or    word ptr[bp+8],1 ; set carry bit, signals failure DOS 2+ way
  3258.     pop    bp        ; this avoids seeing the Interrupt flag bit
  3259.     iret            ; return to user, simulate return from Int 21h
  3260.  
  3261. ; Set DOS' Control-Break Check to off
  3262. cboff    proc    far
  3263.     push    ax
  3264.     push    dx
  3265.     mov    ax,3301h        ; set Control-Break Chk state
  3266.     xor    dl,dl            ; set state to off
  3267.     int    dos
  3268.     pop    dx
  3269.     pop    ax
  3270.     ret
  3271. cboff    endp
  3272.  
  3273. ; Restore DOS's Control-Break Check to startup value
  3274. cbrestore proc    far
  3275.     push    ax
  3276.     push    dx
  3277.     mov    ax,3301h        ; set Control-Break Chk state
  3278.     mov    dl,orgcbrk        ; restore state to startup value
  3279.     int    dos
  3280.     pop    dx
  3281.     pop    ax
  3282.     ret
  3283. cbrestore endp
  3284.  
  3285.  
  3286. ; CDSR processes both CD & REM CD.  Entered with si --> drive/path, it returns
  3287. ; dx --> ASCIIZ current drive/path, w/carry clear, if successful, or error msg
  3288. ; w/carry set, if not.
  3289. CDSR    PROC    FAR
  3290.     mov    kstatus,kssuc        ; global status
  3291.     xor    cx,cx            ; 0 for default drive, if none
  3292.     cmp    byte ptr[si],ch        ; any drive/path?
  3293.     je    cdsr4            ; e = no, format current drive/path
  3294.     cmp    byte ptr[si+1],':'    ; is drive specified?
  3295.     jne    cdsr1            ; ne = no
  3296.     mov    cl,[si]            ; drive letter
  3297. ;    cmp    byte ptr[si+2],ch    ; any path?
  3298. ;    jne    cdsr1            ; ne = yes
  3299. ;    mov    word ptr[si+2],'.'    ; append dot+null as path to kludge DOS
  3300. cdsr1:    call    dskspace        ; test for drive, spec'd by cl, ready
  3301.     jnc    cdsr2            ; nc = ready
  3302.     mov    spcmsg3,cl        ; insert drive letter ret'd by dskspace
  3303.     mov    dx,offset spcmsg2+2    ; in err msg.  dx --> msg w/o cr,lf
  3304.     mov    kstatus,ksgen        ; global status
  3305.     ret                ; carry is set
  3306.  
  3307. cdsr2:    push    cx            ; save drive letter part
  3308.     mov    dx,si
  3309. cdsr2a:    call    strlen
  3310.     mov    bx,cx            ; look at last char+1
  3311.     dec    bx            ; last byte
  3312.     cmp    cx,1            ; if any bytes
  3313.     jbe    cdsr2b            ; be = enough for 1 char
  3314.     cmp    byte ptr [si+bx],'\'    ; ends on backslash?
  3315.     jne    cdsr2b            ; ne = no
  3316.     cmp    byte ptr [si+bx-1],':'    ; ends as ":\"?
  3317.     je    cdsr2b            ; e = yes, leave intact for roots
  3318.     mov    byte ptr [si+bx],0    ; trim trailing backslash
  3319.     jmp    short cdsr2a        ; keep trimming
  3320. cdsr2b:    pop    cx            ; restore drive letter
  3321.     mov    dl,cl            ; uc drive letter ret'd by dskspace
  3322.     sub    dl,'A'            ; A = 0 for seldsk
  3323.     mov    ah,seldsk
  3324.     int    dos
  3325.     inc    dl            ; A = 1 for curdsk
  3326.     mov    curdsk,dl
  3327.     mov    dx,si            ; where chdir wants it
  3328.     cmp    byte ptr [si+1],':'    ; drive specified?
  3329.     jne    cdsr3            ; ne = no, just path
  3330.     add    dx,2            ; skip "drive:"
  3331.     cmp    byte ptr [si+2],0    ; any path?
  3332.     je    cdsr4            ; e = no
  3333. cdsr3:    mov    ah,chdir
  3334.     int    dos
  3335.     jnc    cdsr4            ; nc = success
  3336.     mov    dx,offset ermes4    ; ret carry set, dx --> err msg
  3337.     ret
  3338.  
  3339. cdsr4:    push    si            ; use caller's buffer for cur dr/path
  3340.     mov    ax,':@'            ; al = 'A' - 1, ah = ':'
  3341.     add    al,curdsk        ; al = drive letter
  3342.     mov    [si],ax            ; stash drive:
  3343.     inc    si
  3344.     inc    si
  3345.     mov    byte ptr[si],'\'    ; add \
  3346.     inc    si
  3347.     mov    ah,gcd            ; gcd fills in path as ASCIIZ
  3348.     xor    dl,dl            ; use current drive
  3349.     int    dos
  3350.     pop    dx            ; return caller's buffer pointer in dx
  3351.     clc
  3352.     ret
  3353. CDSR    ENDP
  3354. ; Compute disk free space (bytes) into long word dx:ax.
  3355. ; Enter with disk LETTER in CL (use null if current disk).
  3356. ; Returns uppercase drive letter in CL.
  3357. ; Returns carry set if drive access error. Changes AX, DX.
  3358.  
  3359. DSKSPACE PROC    FAR
  3360.     mov    dl,cl            ; desired disk letter, or null
  3361.     or    dl,dl            ; use current disk?
  3362.     jnz    dskspa1            ; nz = no
  3363.     mov    ah,gcurdsk        ; get current disk
  3364.     int    dos
  3365.     add    al,'A'            ; make 0 ==> A
  3366.     mov    dl,al
  3367. dskspa1:and    dl,5fh            ; convert to upper case
  3368.     mov    cl,dl            ; return upper case drive letter in CL
  3369.     sub    dl,'A'-1        ; 'A' is 1, etc
  3370.     push    bx
  3371.     push    cx
  3372.     mov    ah,36h            ; get disk free space, bx=sect/cluster
  3373.     int    dos            ; dx:ax=sectors, cx=bytes/sector
  3374.     cmp    ax,0ffffh        ; error response?
  3375.     jne    dskspa2            ; ne = no
  3376.     pop    cx
  3377.     pop    bx
  3378.     stc                ; return error
  3379.     ret
  3380. dskspa2:mul    bx            ; sectors/cluster * clusters = sectors
  3381.     mov    bx,dx            ; save high word of sectors (> 64K)
  3382.     mul    cx            ; bytes = sectors * bytes/sector
  3383.     push    ax            ; save low word of bytes
  3384.     mov    ax,bx            ; recall sectors high word
  3385.     mov    bx,dx            ; save current bytes high word
  3386.     mul    cx            ; high word sectors * bytes/sector
  3387.     add    ax,bx            ; new high bytes + old high bytes
  3388.     mov    dx,ax            ; store high word in dx
  3389.     pop    ax            ; space is in dx:ax as a long word
  3390.     pop    cx
  3391.     pop    bx
  3392.     clc
  3393.     ret
  3394. DSKSPACE ENDP
  3395.  
  3396. ; Enter with ds:ax pointing at asciiz filename string
  3397. ; Returns carry set if the file pointed to by ax does not exist, else reset
  3398. ; Returns status byte, fstat, with DOS status and high bit set if major error
  3399. ; Does a search-for-first to permit paths and wild cards
  3400. ; Examines All kinds of files (ordinary, subdirs, vol labels, system,
  3401. ;  and hidden). Upgraded to All kinds on 27 Dec 1985. Revised 30 Aug 86 [jrd]
  3402. ; All registers are preserved
  3403. ISFILE    PROC    FAR
  3404.     push    bx
  3405.     push    ax
  3406.     mov    bx,ax
  3407.     mov    ax,[bx]
  3408.     or    al,al            ; is string empty?
  3409.     jnz    isfil5            ; nz = no
  3410.     pop    ax
  3411.     pop    bx
  3412.     stc                ; return failure
  3413.     ret
  3414. isfil5:    and    ax,not 2020h        ; to upper
  3415.     cmp    ax,'UN'            ; look for DOS 5 NUL
  3416.     jne    isfil4            ; ne = mismatch
  3417.     mov    ax,[bx+2]
  3418.     and    al,not 20h
  3419.     cmp    ax,'L'+0
  3420.     jne    isfil4            ; ne = mismatch
  3421.     pop    ax
  3422.     pop    bx
  3423.     clc                ; say success
  3424.     ret
  3425. isfil4:    pop    ax
  3426.     pop    bx
  3427.     push    dx            ; save regs
  3428.     push    cx
  3429.     push    ax
  3430.     mov    byte ptr filtst.dta+21,0 ; clear old attribute bits
  3431.     mov    byte ptr filtst.fname,0    ; clear any old filenames
  3432.     mov    filtst.fstat,0        ; clear status byte
  3433.     mov     cx,3fH            ; look at all kinds of files
  3434.     mov    dx,offset filtst.dta    ; own own temporary dta
  3435.     mov    ah,setdma        ; set to new dta
  3436.     int    dos
  3437.     pop    dx            ; get ax (filename string ptr)
  3438.     push    dx            ; save it again
  3439.     mov    ah,first2        ; search for first
  3440.     int    dos
  3441.     pushf                ; save flags
  3442.     mov    dx,offset buff        ; reset dma
  3443.     mov    ah,setdma
  3444.     int    dos
  3445.     popf                ; recover flags
  3446.     jnc    isfil1            ; nc = file found
  3447.     mov    filtst.fstat,al        ; record DOS status
  3448.     cmp    al,2            ; just "File Not Found"?
  3449.     je    isfil2            ; e = yes
  3450.     cmp    al,3            ; "Path not found"?
  3451.     je    isfil2            ; e = yes
  3452.     cmp    al,18            ; "No more files"?
  3453.     je    isfil2            ; e = yes
  3454.     or    filtst.fstat,80h    ; set high bit for more serious error
  3455.     jmp    short isfil2    
  3456. isfil1:    cmp    byte ptr filtst.fname,0    ; did DOS fill in a name?
  3457.     je    isfil2            ; z = no
  3458.     clc
  3459.     jmp    short isfil3
  3460. isfil2:    stc                ; else set carry flag bit
  3461. isfil3:    pop    ax
  3462.     pop    cx
  3463.     pop    dx
  3464.     ret                ; DOS sets carry if file not found
  3465. ISFILE    ENDP
  3466.  
  3467.  
  3468. ; Allocate memory.  Passed a memory size in ax, allocates that many
  3469. ; bytes (actually rounds up to a paragraph) and returns its SEGMENT in ax
  3470. ; The memory is NOT initialized.  Written by [jrd] to allow memory to
  3471. ; be allocated anywhere in the 1MB address space
  3472. malloc    proc    far
  3473.     push    bx
  3474.     push    cx
  3475.     mov    bx,ax            ; bytes wanted
  3476.     add    bx,15            ; round up
  3477.     mov    cl,4
  3478.     shr    bx,cl            ; convert to # of paragraphs
  3479.     mov    cx,bx            ; remember quantity wanted
  3480.     mov    ah,alloc        ; DOS memory allocator
  3481.     int    dos
  3482.     jc    mallocx            ; c = fatal
  3483.     cmp    cx,bx            ; paragraphs wanted vs delivered
  3484.     jae    mallocx            ; ae = enough
  3485.     push    es
  3486.     mov    es,ax
  3487.     mov    ah,freemem        ; free the memory
  3488.     int    dos
  3489.     pop    es
  3490.     stc                ; fail
  3491. mallocx:pop    cx
  3492.     pop    bx
  3493.     ret                ; and return segment in ax
  3494. malloc    endp
  3495. code1    ends
  3496.  
  3497. code    segment
  3498.     assume    cs:code
  3499.  
  3500. ; initialize memory usage by returning to DOS anything past the end of kermit
  3501. memini    proc    near
  3502.     push    es
  3503.     mov    bx,_TEXT
  3504.     sub    bx,psp
  3505.     mov    totpar,bx        ; save for patcher's magic number
  3506.     mov    es,psp            ; address psp segment again
  3507.     mov    bx,offset msfinal + 15    ; end of pgm + roundup
  3508.     mov    cl,4
  3509.     shr    bx,cl            ; compute # of paragraphs in last seg
  3510.     mov    ax,_STACK        ; last segment
  3511.     sub    ax,psp            ; minus beginning
  3512.     add    bx,ax            ; # of paragraphs occupied
  3513.     mov    ah,setblk
  3514.     int    dos
  3515.     pop    es
  3516.     jnc    memin1
  3517.     mov    dx,offset ermes2
  3518.     mov    ah,prstr
  3519.     int    dos            ; complain
  3520.     jmp    krmend            ; exit Kermit now
  3521. memin1:    pop    dx            ; save return address here
  3522.     mov    ax,_STACK        ; move SS down to DGROUP, adj SP
  3523.     sub    ax,DGROUP        ; paragraphs to move
  3524.     mov    cl,4            ; convert to bytes
  3525.     shl    ax,cl
  3526.     mov    bx,SP            ; current SP offset
  3527.     add    bx,ax            ; new SP, same memory cell
  3528.     mov    ax,bx
  3529.     sub    ax,400            ; top 400 bytes = Kermit
  3530.     mov    tcptos,ax        ; report this as TCP's top of stack
  3531.     mov    ax,DGROUP        ; new SS
  3532.     cli
  3533.     mov    SS,ax
  3534.     mov    SP,bx            ; whew!
  3535.     sti
  3536.     push    dx            ; push return address
  3537.     clc
  3538.     ret
  3539. memini    endp
  3540.  
  3541. sbrk    proc    near            ; K & R, please forgive us
  3542.     call    malloc            ; allocate memory
  3543.     jc    sbrkx            ; c = failed
  3544.     ret                ; success
  3545. sbrkx:    mov    dx,offset mfmsg        ; assume not enough memory (ax = 8)
  3546.     cmp    ax,7            ; corrupted memory (ax = 7)?
  3547.     jne    sbrkx1            ; ne = no
  3548.     mov    dx,offset mf7msg    ; corrupted memory found
  3549. sbrkx1:    mov    ah,prstr
  3550.     int    dos
  3551.     jmp    krmend            ; exit Kermit now
  3552. sbrk    endp
  3553. code     ends
  3554.     end    start
  3555.