home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSSKER.ASM < prev    next >
Assembly Source File  |  1993-05-14  |  78KB  |  2,440 lines

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