home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msk316src.zip / MSSKER.ASM < prev    next >
Assembly Source File  |  2000-10-31  |  110KB  |  3,599 lines

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