home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msurmx.a86 < prev    next >
Text File  |  2020-01-01  |  66KB  |  1,337 lines

  1.         NAME    msurmx
  2. ; Apapted for RMX, by Jack Bryans, 9/1/87, from:
  3. ; Keyboard translator, by Joe R. Doupnik, Dec 1986
  4. ;  with contributions from David L. Knoell.
  5. ; For Generic keyboard reading (via DOS)
  6. ; edit history:
  7. ; Last edit 13 Oct 1987
  8.  
  9. $INCLUDE(MSSDEF.H86)
  10.  
  11.         public  keybd, msuinit
  12.  
  13. ; some definitions
  14.  
  15. maxkeys equ     128                     ; maximum number of key definitions
  16. maxstng equ     64                      ; maximum number of multi-char strings
  17. stbuflen equ    1000                    ; length of string buffer (bytes)
  18.  
  19. verb    equ     8000h                   ; dirlist flag: use verb action table
  20. strng   equ     4000h                   ; dirlist flag: use string action table
  21. scan    equ     100h                    ; keycode flag: code is scan not ascii
  22. braceop equ     7bh                     ; opening curly brace
  23. bracecl equ     7dh                     ; closing curly brace
  24.  
  25. datas   segment
  26.         extrn taklev:byte, comand:byte, intake:byte, flags:byte
  27.         extrn shkadr:word, stkadr:word, trans:byte
  28. ; system dependent references
  29.         extrn   ciptr:word, cifill:byte, cibuf1:word, cibuf2:word
  30.  
  31. ;;;     System Independent local storage
  32.  
  33. tranbuf db      132 dup (?)             ; 132 byte translator work buffer
  34. crlf    db      cr,lf,'$'
  35. dfhelp1 db      cr,lf,' Enter key',27h,'s identification as a character',cr,lf
  36.         db      '  or as its numerical equivalent \{b##} of ascii',cr,lf
  37.         db      '  or as its scan code \{b##}'
  38.         db      cr,lf,'  or as SCAN followed by its scan code',cr,lf
  39.         db      '    where b is O for octal, X for hex, or D for decimal'
  40.         db      ' (default).',cr,lf,'    Braces {} are optional.'
  41.         db      cr,lf,'    Follow the identification with the new definition.'
  42.         db      cr,lf,' or CLEAR to restore initial key settings.$'
  43. dfaskky db      cr,lf,' Push key to be defined: $'
  44. dfaskdf db      ' Enter new definition: $'
  45. verbbad db      cr,lf,' No such verb',cr,lf,'$'
  46. strbad  db      cr,lf,' Not enough space for new string',cr,lf,'$'
  47. keyfull db      cr,lf,' No more space to define keys',cr,lf,'$'
  48. dfkopps db      cr,lf,' Opps! That is Kermit',27h,'s Escape Char.'
  49.         db      ' Translation is not permitted.',cr,lf,'$'
  50. shkmsg1 db      cr,lf,'Push key to be shown (? shows all): $'
  51. shkmsg2 db      ' decimal is defined as',cr,lf,'$'
  52. shkmsg3 db      cr,lf,'... more, push any key to continue ...$'
  53. kwarnmsg db     cr,lf,' Notice: this form of Set Key is obsolete$'
  54.  
  55. ascmsg  db      ' Ascii char: $'
  56. scanmsg db      ' Scan Code $'
  57. strngmsg db     ' String: $'
  58. verbmsg db      ' Verb: $'
  59. noxmsg  db      ' Self, no translation.$'
  60. fremsg  db      cr,lf,' Free space: $'
  61. kyfrdef db      ' key and $'
  62. stfrdef db      ' string definitions, $'
  63. stfrspc db      ' string characters.',cr,lf,'$'
  64.                                         ; translation tables
  65. keylist dw      maxkeys dup (0)         ; 16 bit keycodes, paralled by dirlist
  66. dirlist dw      maxkeys dup (0)         ; director {v+s} + {index | new char}
  67. sptable dw      maxstng dup (0)         ; list of asciiz string offsets
  68. stbuf   dw      stbuflen dup (0)        ; buffer for strings
  69. strmax  dw      stbuf                   ; first free byte in stbuf
  70. listptr dw      ?                       ; item number for keylist and dirlist
  71. nkeys   dw      0                       ; number of actively defined keys
  72. keycode dw      ?                       ; ascii/scan code for key
  73. kbtemp  dw      ?                       ; scratch storage for translator
  74. brace   db      ?                       ; brace detected flag byte
  75. oldform db      0                       ; old form Set Key, if non-zero
  76. verblen dw      ?                       ; length of user's verb (work temp)
  77. kwcnt   dw      ?                       ; number of keywords (work temp)
  78. msutake db      ?                       ; if being run from take file or not
  79. twelve  dw      12d
  80.  
  81. ;;;     End System Independent Data Area
  82.  
  83. ;;;     System Dependent Data Area
  84. ;       edit dfhelp2 to include nice list of verbs for this system.
  85. dfhelp2 db      cr,lf,' Enter either \{Kverb}  for a Kermit action verb',cr,lf
  86.         db      ' or a replacement string  (single byte binary numbers are'
  87.         db      ' \{b##})',cr,lf,' or nothing at all to undefine a key.'
  88.         db      cr,lf,' Braces {} are optional, and strings maybe enclosed in'
  89.         db      ' them.',cr,lf,' Strings may not begin with the character'
  90.         db      ' combinations of  \k  or  \{k',cr,lf
  91.         db      '    (start with a { brace instead).',cr,lf,lf
  92.         db      ' Verbs are as follows:',cr,lf
  93.         db      ' Logoff (suspend logging), Logon (resume logging),'
  94.         db      ' Hangup, null (send a)',cr,lf
  95.         db      ' help, status, exit',cr,lf,'$'
  96.  
  97. kverbs  db      7                       ; number of table entries below
  98.         %mkeyw  (%('help'),cquery)      ; independent of ordering and case!
  99.         %mkeyw  (%('status'),cstatus)   ; mkeyw 'name',procedure entry point
  100.         %mkeyw  (%('exit'),cquit)
  101.         %mkeyw  (%('null'),snull)
  102.         %mkeyw  (%('Logoff'),klogof)
  103.         %mkeyw  (%('Logon'),klogon)
  104.         %mkeyw  (%('Hangup'),chang)
  105.  
  106. ; Initialization data.
  107. kbdinlst equ    this byte       ; Kermit IBM initialization time keyboard setup
  108.         dw      0               ; end of table marker
  109.  
  110. datas   ends
  111.  
  112. ;                       Documentation
  113. ;Translating a key:
  114. ;   The translator is called to obtain keyboard input; it sends characters to
  115. ; the serial port through standard controlled echo procedures or invokes
  116. ; named procedures. It returns carry clear when its operation is completed
  117. ; for normal actions and carry set when Connect mode must be exited. When
  118. ; Connect mode is exited the just read char should be passed in Kbdflg
  119. ; to msster.asm for invoking actions such as Status, send a break,
  120. ; quit connect mode; system dependent procedure Term is responsible for this.
  121. ;
  122. ;  Principal procedures are -
  123. ;       msuinit         Initializes keyboard translator in this file when
  124. ;                       Kermit first begins. Installs dfkey and shkey as the
  125. ;                       procedures used for Set Key and Show Key. Sys Indep.
  126. ;                       Called from msx or msy init procs. System Independent.
  127. ;       keybd           Performs the translation, outputs chars to the serial
  128. ;                       port or invokes a Kermit action routine. Sys Indep.
  129. ;       dfkey           Defines a key's translation. Reads command line
  130. ;                       via Kermit's command parser comnd. System Independent.
  131. ;       shkey           Shows translation of a key. Requests user to push
  132. ;                       selected key. System Independent.
  133. ;
  134. ;       kbdinit         optional. Initializes the translation tables when
  135. ;                       Kermit starts up. Called by msuinit. System Dependent.
  136. ;       getkey          Performs the keyboard read and returns results in
  137. ;                       a standardized system independent format. Sys Depend.
  138. ; Supporting system independent procedures are -
  139. ; shkfre (show string free space), tstkeyw (finds user's keyword in the verb
  140. ; table), insertst (insert string in buffer), remstr (delete string in buffer).
  141. ;
  142. ;    System dependent procedure Getkey reads a keycode.
  143. ; For any system, the canonical output form is the key's code in Keycode.
  144. ; Place the ascii code (or scan code if none) in byte Keycode and ancillary
  145. ; info (shift states plus marker bit for scan codes) in byte Keycode + 1.
  146. ;
  147. ;    Procedure Keybd calls Getkey for the Keycode, checks list of translatable
  148. ; keys Keylist, and then either sends an ascii string (one or more characters)
  149. ; or invokes a Kermit action verb. List Dirlist indicates what kind of
  150. ; translation to do. Keybd is system independent.
  151. ;
  152. ;    Keylist is a packed but unordered list of 16 bit keycodes which need
  153. ; translation. The lower order byte holds a key code (ascii char or scan code)
  154. ; while the high byte holds a scan code marker bit (0 if ascii code in low
  155. ; byte) plus any ancillary keyboard information such as Control/Shift/Alt/Meta
  156. ; keys being held down; these are of use in Show Key presentations.
  157. ;    Dirlist parallels Keylist to provide the kind of translation, verb or
  158. ; string, in the two highest bits with the other bits holding either
  159. ; a single new replacement character or the item number in lists of verbs
  160. ; or strings. If neither verb nor strng type bits are set in a dirlist
  161. ; word then the translation is a single new character held in the lower
  162. ; eight bits of that dirlist word.
  163. ;
  164. ;    The number of key translations is assembly constant Maxkeys (def 128).
  165. ;    The maximum number of strings is assembly constant Maxstngs (def 64).
  166. ;    The maximum number of verbs is 256 and is set by building table Kverbs.
  167. ;
  168. ;   For verbs, use the Item number from the Director table Dirlist to select
  169. ; a procedure offset from the structured list Kverbs and jump to that offset.
  170. ; Most verb procedures return carry clear to stay within Connect mode.
  171. ; Verbs requiring exiting Connect mode return carry set and may set byte
  172. ; Kbdflg to a char code which will be read by msster.asm for activating a
  173. ; transient Kermit action such as send a break (Kbdflg = 'b').
  174. ; Kbdflg is stored in msster.asm (as zero initially, meaning ignore it).
  175. ; Action verb procedures are normally located in a system dependent file.
  176. ;
  177. ;   For multi-char strings, use Item number from Director table Dirlist to
  178. ; select a pointer to a string. The list of string pointers is Sptable
  179. ; (string pointer table) which holds the offset in the data segment of the
  180. ; strings stored in buffer Stbuf. In stbuf strings are held as: one byte of
  181. ; length of following text and then the text itself (permits embedded nulls).
  182. ;  Use Chrout to send each string character, and finally return from Keybd
  183. ; with carry clear.
  184. ;
  185. ;   For single character replacements obtain the new character from the lower
  186. ; order byte of Director table Dirlist. If the character is Kermit's present
  187. ; escape character return from Keybd carry set to leave connect mode.
  188. ; Otherwise, send the character via Chrout and return from Keybd carry clear.
  189.  
  190. ; Keylist table format:
  191. ;    7 bits   1 bit   8 bits
  192. ; +----------+----+------------+ scan bit = 1 if key's code is non-ascii
  193. ; | aux info |scan| key's code | aux info = system dependent, used only to
  194. ; +----------+----+------------+            help identify key
  195. ;
  196. ; Dirlist table format            v s   meaning
  197. ;   1   1      14 bits            0 0   copy out one byte translation
  198. ; +---+---+--------------------+  1 0   copy out multi-char string number Item
  199. ; | v | s | item # or new char |  0 1   do action verb number Item
  200. ; +---+---+--------------------+  1 1   (not used)
  201. ;
  202. ; Table kverbs is organized by macro mkeyw as -
  203. ;       kverbs  db      number of table entries
  204. ;       (each entry is in the form below:)
  205. ;               db      number of bytes in verbname
  206. ;               db      'verbname'              variable length
  207. ;               db      '$'                     for printing
  208. ;               dw      value                   offset of procedure
  209. ;
  210. ;
  211. ;   Dfkey defines a key to be itself (undefines it) or a single replacement
  212. ; character or a character string or a Kermit action verb. Dfkey requires
  213. ; a command line so that it may be invoked by Take files but can be forced
  214. ; to prompt an interactive user to push a key. Syntax is discussed below.
  215. ; Note that redefined keys have their old definitions cleared so that
  216. ; old string space is reclaimed automatically.
  217. ;
  218. ;   Shkey displays a key's definition and the user is asked to push the
  219. ; selected key. The free space for strings is always shown afterward. See
  220. ; below for syntax.
  221. ;
  222. ;   Kbdinit is an optional routine called when Kermit starts up. It fills in
  223. ; the translation tables with desirable default values to save having to
  224. ; use long mskermit.ini files. The default values are stored in a structured
  225. ; table similar to (but not the same as) Dfkey's command lines; the keycode
  226. ; values are preset by hand to 16 bit numbers.
  227.  
  228. ;Defining a key:
  229. ; Command is SET KEY <key ident><whitespace><definition>
  230. ;
  231. ; <key ident> is
  232. ;               a single ordinary ascii char or
  233. ;               the numerical equivalent of an ascii char or
  234. ;               a Scan Code written as a number or
  235. ;               keyword SCAN followed by a number.
  236. ;               ?       Displays help message.
  237. ;       Numbers and Binary codes are of the form
  238. ;               \123    a decimal number
  239. ;               \o456   an octal number         base letters o, d, x can be
  240. ;               \d213   a decimal number        upper or lower case
  241. ;               \x0d    a hex number
  242. ;               \{b###} braces around above material following slash.
  243. ;
  244. ; <whitespace> is one or more spaces and or tabs.
  245. ;
  246. ; <definition> is
  247. ;       missing altogether which "undefines" a key.
  248. ;       \Kverb          for a Kermit action verb; upper or lower case K is ok
  249. ;       \{Kverb}        ditto. Verb is the name of an action verb.
  250. ;       text            a string with allowed embedded whitespace and embedded
  251. ;                       binary chars as above. This kind of string may not
  252. ;                       commence with sequences \K or \{K; use braces below.
  253. ;       {text}          string confined to material within but excluding
  254. ;                       the braces. Note, where the number of opening braces
  255. ;                       exceeds the number of closing braces the end of line
  256. ;                       terminates the string: {ab{}{{c}d ==> ab{}{{c}d
  257. ;                       but  {ab}{{c}d ==> ab.
  258. ;       ?               Displays help message and lists all action verbs.
  259. ;
  260. ;       If Set Key is given interactively, as opposed to within a Take
  261. ;       file, the system will prompt for inputs if none is on the command
  262. ;       line. The response to Push key to be defined cannot be edited.
  263. ;
  264. ;       Text which reduces to a single replacement character is put into a
  265. ;       table separate from the multi-character strings (maxstng of these).
  266. ;       A key may be translated into any single 8 bit code.
  267. ;
  268. ;       Comments can follow a Kermit action verb or a braced string; no
  269. ;       semicolon is required since all are stripped out by the Take file
  270. ;       reader before the defining text is seen by SET KEY.
  271. ;
  272. ;       The current Kermit escape character cannot be translated without
  273. ;       subtrafuge.
  274. ;
  275. ;       Examples:
  276. ;               Set Key q z
  277. ;                               makes key q send character z
  278. ;               Set Key \7 \27[0m
  279. ;                               makes key Control G send the four byte
  280. ;                               string  ESC [ 0 m
  281. ;               Set Key q
  282. ;                               undefines key q so it sends itself (q) again.
  283. ;               Set Key \2349 \kexit
  284. ;                               defines IBM Alt-X to invoke the leave connect
  285. ;                               mode verb "exit" (Kermit's escape-char ^] C).
  286. ;               Set Key \x0c Login \{x0d}myname\{x0d}mypass\x0d
  287. ;                               defines Control L to send the string
  288. ;                               Login <cr>myname<cr>mypass<cr>
  289. ;
  290. ; Alternative Set Key syntax for backward compatibility with previous versions
  291. ;       The same forms as above except the key identification number must
  292. ;       be decimal and must Not have a leading backslash. Example:
  293. ;       Set Key Scan 59 This is the F1 key
  294. ;
  295. ;       If the definition is omitted it may be placed on the following line;
  296. ;       if that line is also empty the key is undefined (defined as Self).
  297. ;       A warning message about obsolete syntax will be given followed by
  298. ;       the key's modern numerical value and new definition. Only "special"
  299. ;       keys (those not producing ascii codes) are compatible with this
  300. ;       translator.
  301. ;
  302. ;Showing a key:
  303. ; Command is SHOW KEY <cr>
  304. ; System prompts user to press a key and shows the definition plus the
  305. ; free space for strings. Query response results in showing all definitions.
  306. ;                       End Documentation
  307.  
  308. code    segment
  309.                 ; system independent external items
  310.         extrn   comnd:near, prompt:near                 ; in msscmd
  311.         extrn   strlen:near                             ; in mssfil
  312.         extrn   cnvlin:near, katoi:near, decout:near    ; in msster
  313.                 ; system dependent external items
  314.         extrn   dosint:near
  315.                 ; these are system dependent action verbs, in msxrmx
  316.         extrn   beep:near, chang:near, chrout:near, cstatus:near, cquit:near
  317.         extrn   cquery:near, klogon:near, klogof:near, snull:near
  318.  
  319. ; Begin system independent Keyboard Translator code
  320.  
  321. ; MSUINIT performs Kermit startup initialization for this file.
  322. ; Note, shkadr and stkadr are pointers tested by Set/Show Key calls. If they
  323. ; are not initialized here then the older Set/Show Key procedures are called.
  324. MSUINIT PROC                            ; call from msx/msy init code
  325.         call    kbdinit                 ; optional: init translator tables
  326.         mov     shkadr,offset shkey     ; declare keyboard translator present
  327.         mov     stkadr,offset dfkey     ; via Show and Set Key proc addresses
  328.         ret
  329. MSUINIT ENDP
  330.  
  331. ; Call Keybd to read a keyboard char (just returns carry clear if none) and
  332. ; 1) send the replacement string (or original char if not translated)
  333. ;    out the serial port, or
  334. ; 2) execute a Kermit action verb.
  335. ; Returns carry set if Connect mode is to be exited, else carry clear.
  336. ; Modifies registers ax and bx.
  337. KEYBD   PROC                            ; active translator
  338.         call    getkey                  ; read keyboard
  339.         jnc     keybd1                  ; nc = data available
  340.         clc                             ; else just return carry clear
  341.         ret
  342. keybd1: cmp     nkeys,0                 ; is number of keys defined = 0?
  343.         jz      keybd3                  ; z = none defined
  344.         push    di                      ; search keylist for this keycode
  345.         push    cx                      ; save some registers
  346.         push    es
  347.         mov     di,offset keylist       ; list of defined keycode words
  348.         mov     ax,keycode              ; present keycode
  349.         mov     cx,nkeys                ; number of words to examine
  350.         push    ds
  351.         pop     es                      ; make es:di point to datas segment
  352.         cld
  353.         repne   scasw                   ; find keycode in list
  354.         pop     es                      ; restore regs
  355.         pop     cx
  356.         je      keybd1b                 ; e = found, work with present di
  357.         pop     di                      ; restore original di
  358.         test    keycode,scan            ; is this a scan code?
  359.         jz      keybd3                  ; z = no, it's ascii, use al as char
  360.         call    beep                    ; say key is a dead one
  361.         clc
  362.         ret                             ; and exit with no action
  363.  
  364. keybd1b:sub     di,2                    ; correct for auto increment
  365.         sub     di,offset keylist       ; subtract start of list ==> listptr
  366.         mov     ax,dirlist[di]          ; ax = contents of director word
  367.         pop     di                      ; restore original di
  368.                                         ; dispatch on Director code
  369.         test    ax,verb                 ; verb only?
  370.         jnz     keyvb                   ; e = yes
  371.         test    ax,strng                ; multi-char string only?
  372.         jnz     keyst                   ; e = yes, else single char & no xlat.
  373.                                         ;
  374.                                         ; do single CHAR output (char in al)
  375. keybd3: cmp     al,trans.escchr         ; Kermit's escape char?
  376.         je      keybd3a                 ; e = yes, handle separately
  377.         call    chrout                  ; transmit the char
  378.         clc                             ; return success
  379.         ret
  380. keybd3a:stc                             ; set carry for jump to Quit
  381.         ret
  382.  
  383. keyvb:  and     ax,not(verb+strng)      ; VERB (ax=index, remove type bits)
  384.         mov     bx,offset kverbs        ; start of verb table
  385.         cmp     al,byte ptr [bx]        ; index > number of entries?
  386.         jae     keybdx                  ; ae = illegal, indices start at 0
  387.         inc     bx                      ; bx points to first entry
  388.         push    cx                      ; save reg
  389.         mov     cx,ax                   ; save the index in cx
  390.         inc     cx                      ; counter, indices start at 0
  391. keyvb1: mov     al,byte ptr [bx]        ; cnt value
  392.         xor     ah,ah
  393.         add     ax,4                    ; skip text and '?' and value word
  394.         add     bx,ax                   ; look at next slot
  395.         loop    keyvb1                  ; walk to correct slot
  396.         sub     bx,2                    ; backup to value field
  397.         pop     cx                      ; restore reg
  398.         mov     bx,[bx]                 ; get value field of this slot
  399.         cmp     bx,0                    ; jump address defined?
  400.         je      keybdx                  ; e = no, skip the action
  401.         jmp     bx                      ; perform the function
  402.  
  403. keyst:  and     ax,not(verb+strng)      ; STRING (ax=index, remove type bits)
  404.         shl     ax,1                    ; convert to word index
  405.         push    si                      ; save working reg
  406.         mov     si,ax                   ; word subscript in table
  407.         mov     si,sptable[si]          ; memory offset of selected string
  408.         cmp     si,0                    ; is there a string pointer present?
  409.         je      keyst3                  ; e = no, skip operation
  410.         cld                             ; scan forward
  411.         lodsb                           ; get string length byte
  412.         mov     cl,al
  413.         xor     ch,ch                   ; to cx for looping
  414.         jcxz    keybdx                  ; z = null length
  415. keyst2: lodsb                           ; get new string char into al
  416.         push    si                      ; save si and cx around call
  417.         push    cx
  418.         call    chrout                  ; send out the char in al
  419.         pop     cx                      ; recover regs
  420.         pop     si
  421.         loop    keyst2                  ; loop through whole string
  422. keyst3: pop     si                      ; restore reg
  423.  
  424. keybdx: clc                             ; return success
  425.         ret
  426. KEYBD   ENDP
  427.  
  428. ; SET KEY - define a key   (procedure dfkey)
  429. ; SET KEY <key ident><whitespace><new meaning>
  430. ; Call from Kermit level. Returns as ret if failure or as rskp if success.
  431. ;
  432. DFKEY   PROC                            ; define a key as a verb or a string
  433.         mov     keycode,0               ; clear keycode
  434.         mov     oldform,0               ; say no old form Set Key yet
  435.         mov     dx,offset tranbuf       ; our work space
  436.         mov     word ptr tranbuf,0      ; insert terminator
  437.         mov     bx,offset dfhelp1       ; first help message
  438.         mov     ah,cmfile               ; parse a word
  439.         call    comnd                   ; get key code or original ascii char
  440.          nop
  441.          nop
  442.          nop
  443.         mov     al,intake               ; reading from Take file indirectly
  444.         or      al,taklev               ; ditto, directly
  445.         mov     msutake,al              ; save here
  446.         or      ah,ah                   ; any text given?
  447.         jnz     dfkey12                 ; nz = yes, so don't consider prompts
  448.                                         ; interactive key request
  449.         cmp     intake,0                ; in a Take file?
  450.         je      dfkey10                 ; e = no, prompt for keystroke
  451.         jmp     dfkey0                  ;  else say bad syntax
  452. dfkey10:mov     ah,prstr
  453.         mov     dx,offset dfaskky       ; ask for key to be pressed
  454.         call    dosint
  455. dfkey11:call    getkey                  ; read key ident from keyboard
  456.         jc      dfkey11                 ; c = no response, wait for keystroke
  457.         mov     ah,prstr                ; display cr/lf
  458.         mov     dx,offset crlf
  459.         call    dosint
  460.         call    shkey0                  ; show current definition (in SHKEY)
  461.         jmp     dfkey1e                 ; prompt for and process definition
  462.  
  463. dfkey12:                                ; Look for word SCAN and ignore it
  464.         mov     dx,word ptr tranbuf     ; get first two characters
  465.         or      dx,2020h                ; map upper to lower case
  466.         cmp     dx,'cs'                 ; first two letters of word "scan"?
  467.         je      dfkey                   ; e = yes, skip the word
  468.         cmp     dx,'lc'                 ; first two letters of word "clear"?
  469.         je      dfkeyc                  ; e = yes, reinit keyboard
  470.         cmp     ah,1                    ; number of characters received
  471.         ja      dfkey1                  ; a = more than one, decode
  472.         mov     ah,byte ptr tranbuf     ; get the single char
  473.         mov     byte ptr keycode,ah     ; store as ascii keycode
  474.         jmp     dfkey1b                 ; go get definition
  475.  
  476. dfkey0: mov     dx,offset dfhelp1       ; say bad definition command
  477.         mov     ah,prstr
  478.         call    dosint
  479.         jmp     rskp
  480.  
  481. dfkeyc:                                 ; CLEAR key defs, restore startup defs
  482.         mov     cx,maxkeys              ; size of keycode tables
  483.         push    es                      ; save register
  484.         push    ds
  485.         pop     es                      ; make es point to datas segment
  486.         mov     ax,0                    ; null, value to be stored
  487.         mov     di,offset dirlist       ; director table
  488.         cld
  489.         rep     stosw                   ; clear it
  490.         mov     cx,maxkeys
  491.         mov     di,offset keylist       ; keycode table
  492.         rep     stosw                   ; clear it
  493.         mov     cx,maxstng
  494.         mov     di,offset sptable       ; string pointer table
  495.         rep     stosw                   ; clear it
  496.         pop     es                      ; recover register
  497.         mov     strmax,offset stbuf     ; clear string buffer
  498.         mov     stbuf,0                 ;
  499.         mov     nkeys,0                 ; clear number of defined keys
  500.         call    msuinit                 ; restore startup definitions
  501.         jmp     rskp
  502.                                         ; Multi-char key identification
  503. dfkey1: mov     si,offset tranbuf       ; point to key ident text
  504.         cmp     byte ptr [si],'0'       ; is first character numeric?
  505.         jb      dfkey1a                 ; b = no
  506.         cmp     byte ptr [si],'9'       ; in numbers?
  507.         ja      dfkey1a                 ; a = no
  508.         mov     keycode,scan            ; setup keycode for scan value
  509.         mov     dx,si                   ; get length of string in cx
  510.         call    strlen
  511.         push    ds
  512.         pop     es                      ; make es point to datas segment
  513.         push    si
  514.         add     si,cx                   ; point at string terminator
  515.         mov     di,si
  516.         inc     di                      ; place to store string (1 byte later)
  517.         inc     cx                      ; include null terminator
  518.         std                             ; work backward
  519.         rep     movsb                   ; move string one place later
  520.         cld
  521.         pop     si
  522.         mov     byte ptr [si],'\'       ; make ascii digits into \nnn form
  523.         mov     oldform,0ffh            ; set old form flag
  524.         mov     dx,offset kwarnmsg      ; tell user this is old form
  525.         mov     ah,prstr
  526.         call    dosint
  527. dfkey1a:call    katoi                   ; convert ascii number to binary in ax
  528.         jc      dfkey0                  ; c = no number converted
  529.         or      keycode,ax              ; store in keycode
  530.  
  531. dfkey1b:                                ; Get Definition proper
  532.         test    oldform,0ffh            ; old form Set Key active?
  533.         jz      dfkey1f                 ; z = no
  534.         mov     bx,offset tranbuf       ; get new definition on main cmd line
  535.         mov     word ptr [bx],0         ; insert terminator
  536.         mov     dx,offset dfhelp2       ; help for definition of key
  537.         mov     ah,cmtxt                ; read rest of line into tranbuf
  538.         call    comnd
  539.          nop                            ; allow null definitions
  540.          nop
  541.          nop
  542.         or      ah,ah                   ; char count zero?
  543.         jz      dfkey1e                 ; z = zero, prompt for definition
  544.         jmp     dfkey1g                 ; process definition
  545.  
  546. dfkey1e:mov     ah,prstr
  547.         mov     dx,offset crlf
  548.         call    dosint
  549.         mov     dx,offset dfaskdf       ; prompt for definition string
  550.         call    prompt                  ; Kermit prompt routine
  551.         mov     comand.cmcr,1           ; permit bare carriage returns
  552. dfkey1f:mov     bx,offset tranbuf       ; get new definition
  553.         mov     word ptr [bx],0         ; insert terminator
  554.         mov     dx,offset dfhelp2       ; help for definition of key
  555.         mov     ah,cmtxt                ; read rest of line into tranbuf
  556.         call    comnd
  557.          ret                            ; exit now on ^C from user
  558.          nop
  559.          nop
  560.         cmp     comand.cmcr,0           ; prompting for definition?
  561.         je      dfkey1g                 ; e = no, trim leading whitespace
  562.         mov     comand.cmcr,0           ; turn off allowance for bare c/r's
  563.         jmp     dfkey2                  ; interactive, allow leading whitespace
  564. dfkey1g:xchg    ah,al                   ; put byte count in al
  565.         xor     ah,ah                   ; clear high byte
  566.         mov     kbtemp,ax               ; and save count in kbtemp
  567.         mov     ah,cmcfm                ; get a confirm
  568.         call    comnd
  569.          ret                            ; none so declare parse error
  570.          nop
  571.          nop                            ; round out to three bytes
  572.         mov     cx,kbtemp               ; string length
  573.         jcxz    dfkey2                  ; z = empty string
  574.         push    si
  575.         push    di
  576.         mov     si,offset tranbuf       ; strip leading white space
  577. dfkey1c:cld                             ; work forward
  578.         lodsb                           ; read string char into al
  579.         dec     cx                      ; number of chars left to read
  580.         cmp     al,' '                  ; a space?
  581.         je      dfkey1c                 ; e = yes, keep going
  582.         cmp     al,tab                  ; tab?
  583.         je      dfkey1c                 ; e = yes, keep going
  584.         dec     si                      ; offset inc si in lodsb
  585.         add     cx,2                    ; include terminator, offset dec above
  586.         jcxz    dfkey1d                 ; z = nothing to move
  587.         mov     di,offset tranbuf       ; destination is start of buffer
  588.         push    ds
  589.         pop     es
  590.         cld
  591.         rep     movsb                   ; copy text part of string
  592. dfkey1d:pop     di
  593.         pop     si
  594.  
  595. dfkey2:                                 ; Examine translation
  596.         mov     al,trans.escchr         ; current escape char (port dependent)
  597.         cmp     al,byte ptr keycode     ; is this Kermit's escape char?
  598.         jne     dfkey2a                 ; ne = no
  599.         test    keycode,scan            ; see if scan code
  600.         jnz     dfkey2a                 ; nz = scan, so not ascii esc char
  601.         mov     dx,offset dfkopps       ; Opps! msg
  602.         mov     ah,prstr                ; complain and don't redefine
  603.         call    dosint
  604.         jmp     rskp
  605.  
  606. dfkey2a:push    di                      ; get a director code for this key
  607.         push    cx
  608.         mov     di,offset keylist       ; list of keycodes
  609.         mov     cx,nkeys                ; number currently defined
  610.         mov     ax,keycode              ; present keycode
  611.         jcxz    dfkey2b                 ; cx = 0 means none defined yet
  612.         cld
  613.         push    ds
  614.         pop     es
  615.         repne   scasw                   ; is current keycode in the list?
  616.         jne     dfkey2b                 ; ne = not in list
  617.         sub     di,2                    ; correct for auto increment
  618.         sub     di,offset keylist
  619.         mov     listptr,di              ; list pointer for existing definition
  620.         pop     cx
  621.         pop     di
  622.         jmp     dfkey3                  ; go process definition
  623.  
  624. dfkey2b:pop     cx                      ; key not currently defined so
  625.         pop     di                      ;  make a new director entry for it
  626.         mov     bx,nkeys                ; number of keys previously defined
  627.         cmp     bx,maxkeys              ; enough space?
  628.         jae     dfkey2c                 ; ae = no, complain
  629.         shl     bx,1                    ; count words
  630.         mov     listptr,bx              ; index into word list
  631.         mov     ax,keycode              ; get key's code
  632.         mov     keylist[bx],ax          ; store it in list of keycodes
  633.         mov     dirlist[bx],0           ; clear the new director entry
  634.         inc     nkeys                   ; new number of keys
  635.         jmp     dfkey3                  ; go process definition
  636.  
  637. dfkey2c:mov     dx,offset keyfull       ; say key space is full already
  638.         mov     ah,prstr
  639.         call    dosint
  640.         jmp     rskp                    ; tell parser we are happy
  641. ; listptr has element number in keylist or dirlist; keycode has key's code.
  642.  
  643. ; Parse new definition. First look for Kermit verbs as a line beginning
  644. ; as \K or \{K. Otherwise, consider the line to be a string.
  645. ; In any case, update the Director table for the new definition.
  646.  
  647. dfkey3: mov     brace,0                 ; assume not using braces
  648.         mov     si,offset tranbuf       ; start of definition text
  649.         cmp     byte ptr [si],'\'       ; starts with escape char?
  650.         jne     dfkey5                  ; ne = no, so we have a string
  651.         inc     si                      ; skip the backslash
  652.         cmp     byte ptr [si],braceop   ; starts with \{?
  653.         jne     dfkey3a                 ; ne = no
  654.         inc     si                      ; skip the opening brace
  655.         mov     brace,bracecl           ; expect closing brace
  656. dfkey3a:cmp     byte ptr [si],'K'       ; starts with \{K or \K?
  657.         je      dfkey3b                 ; e = yes
  658.         cmp     byte ptr [si],'k'       ; starts as \{k or \k?
  659.         jne     dfkey5                  ; ne = no, then it's a string
  660. dfkey3b:inc     si                      ; yes, skip the K too
  661.                                         ; Kermit action VERBS
  662.         push    si                      ; save verb name start address
  663. dfkey4a:cld
  664.         lodsb                           ; scan til closing brace or w/s or end
  665.         cmp     al,0                    ; premature end?
  666.         je      dfkey4b                 ; e = yes, accept without brace
  667.         cmp     al,brace                ; closing brace?
  668.         je      dfkey4b                 ; e = yes
  669.         cmp     al,spc                  ; white space or control char?
  670.         ja      short dfkey4a           ; a = no, so not at end yet
  671. dfkey4b:mov     byte ptr[si-1],0        ; insert null terminator
  672.         pop     si                      ; recover start address
  673.         call    tstkeyw                 ; find keyword, kw # returned in kbtemp
  674.         jc      dfkey4d                 ; c = no keyword found, complain
  675.         call    remstr                  ; clear old string, if string
  676.         mov     ax,kbtemp               ; save keyword number
  677.         and     ax,not(verb+strng)      ; clear verb / string field
  678.         or      ax,verb                 ; set verb ident
  679.         mov     si,listptr
  680.         mov     dirlist[si],ax          ; store info in Director table
  681.         jmp     dfkey7                  ; show results and return success
  682.  
  683. dfkey4d:mov     dx,offset verbbad       ; say no such verb
  684.         mov     ah,prstr
  685.         call    dosint
  686.         jmp     rskp
  687.  
  688. ; Here we are left with the definition string; si points to its start, and
  689. ; kbtemp holds its length (number of bytes). Null termination. If the string
  690. ; begins with an opening brace it terminates on a matching closing brace
  691. ; or the end of line, whichever occurs first. Trailing whitespace removed
  692. ; before examining braces.
  693. ; Null length strings mean define key as Self.
  694.                                         ; STRING definitions
  695. dfkey5: call    remstr                  ; first, clear old string, if any
  696.         mov     si,offset tranbuf       ; si=source, di=dest, convert in-place
  697.         mov     di,si
  698.         call    cnvlin                  ; convert numbers, cx gets line length
  699.         mov     si,offset tranbuf       ; provide address of new string
  700.         cmp     cx,1                    ; just zero or one byte to do?
  701.         jbe     dfkey6                  ; e = yes, do as a char
  702.         call    insertst                ; insert new string, returns reg cx.
  703.         jc      dfkey5h                 ; c = could not do insert
  704.         mov     si,listptr              ; cx has type and string number
  705.         mov     dirlist[si],cx          ; update Director table from insertst
  706.         jmp     dfkey7                  ; show results and return success
  707.  
  708. dfkey5h:mov     dx,offset strbad        ; display complaint
  709.         mov     ah,prstr
  710.         call    dosint
  711.         jmp     rskp
  712.  
  713.                 ; define SINGLE CHAR replacement or CLEAR a key definition.
  714.                 ; cx has char count 1 (normal) or 0 (to undefine the key).
  715. dfkey6: jcxz    dfkey6c                 ; z = cx= 0, clear definition
  716.         mov     al,byte ptr [si]        ; get first byte from definition
  717.         xor     ah,ah                   ; set the type bits to Char
  718.         mov     si,listptr
  719.         mov     dirlist[si],ax          ; store type and key's new code
  720.         jmp     dfkey7                  ; return success
  721.  
  722. dfkey6c:push    si                      ; clear a definition,
  723.         push    di                      ; listptr points to current def
  724.         mov     si,listptr              ; starting address to clear
  725.         add     si,offset dirlist
  726.         mov     di,si                   ; destination
  727.         add     si,2                    ; source is next word
  728.         mov     cx,nkeys                ; current number of keys defined
  729.         add     cx,cx                   ; double for listptr being words
  730.         sub     cx,listptr              ; cx = number of words to move
  731.         shr     cx,1                    ; convert to actual number of moves
  732.         jcxz    dfkey6d                 ; z = none, just remove last word
  733.         push    es
  734.         push    ds
  735.         pop     es                      ; make es:di point to datas segment
  736.         cld
  737.         push    cx                      ; save cx
  738.         rep     movsw                   ; move down higher list items
  739.         pop     cx
  740.         mov     si,listptr              ; do keylist too, same way
  741.         add     si,offset keylist
  742.         mov     di,si
  743.         add     si,2
  744.         rep     movsw
  745.         pop     es
  746. dfkey6d:mov     si,nkeys                ; clear old highest list element
  747.         shl     si,1                    ; address words
  748.         mov     dirlist[si],0           ; null the element
  749.         mov     keylist[si],0           ; null the element
  750.         dec     nkeys                   ; say one less key defined now
  751.         pop     di                      ; restore saved registers
  752.         pop     si
  753.  
  754. dfkey7: mov     ah,msutake              ; Finish up. In a Take file?
  755.         or      ah,taklev               ; or even directly
  756.         cmp     ah,0
  757.         je      dfkey7a                 ; e = no
  758.         cmp     flags.takflg,0          ; echo Take commands?
  759.         je      dfkey7b                 ; e = no
  760. dfkey7a:mov     ah,prstr                ; display cr/lf
  761.         mov     dx,offset crlf
  762.         call    dosint
  763.         call    shkey0                  ; show new definition (in SHKEY)
  764.         call    shkfre                  ; show free string space
  765. dfkey7b:jmp     rskp                    ; return success
  766. DFKEY   ENDP
  767.  
  768. ; SHOW KEY <cr> command. Call from Kermit level. Vectored here by SHOW
  769. ; command. Replaces obsolete procedure in msx---.
  770. ; Prompts for a key and shows that key's (or all if ? entered) keycode,
  771. ; definition, and the key definition free space remaining.
  772.  
  773. SHKEY   PROC                            ; Show key's definition command
  774.         mov     ah,cmcfm                ; get a confirm
  775.         call    comnd
  776.          nop                            ; ignore any additional text
  777.          nop
  778.          nop
  779.         push    bx
  780.         mov     dx,offset shkmsg1       ; ask for original key
  781.         mov     ah,prstr
  782.         call    dosint
  783. shky0:  call    getkey                  ; read keyboard, output to keycode
  784.         jc      shky0                   ; wait for a key (c = nothing there)
  785.         cmp     byte ptr keycode,'?'    ; query for all keys?
  786.         jne     shky0a                  ; ne = no, not a query
  787.         test    keycode,scan            ; is this a scan code, vs ascii query?
  788.         jz      shky0c                  ; z = no Scan, so it is a query
  789.  
  790. shky0a: mov     ah,prstr                ; show single key. Setup display
  791.         mov     dx,offset crlf
  792.         call    dosint
  793.         call    shkey0                  ; show just one key
  794. shky0b: call    shkfre                  ; show free string space
  795.         jmp     shkeyx                  ; exit
  796.  
  797. shky0c: mov     cx,nkeys                ; Show all keys. nkeys = number defined
  798.         jcxz    shky0b                  ; z = none to show
  799.         mov     si,offset keylist       ; list of definitions
  800.         push    si                      ; save pointer
  801. shky1:  pop     si                      ; recover pointer
  802.         cld
  803.         lodsw                           ; get a keycode
  804.         push    si                      ; save pointer
  805.         push    cx                      ; save counter
  806.         mov     keycode,ax              ; save new keycode
  807.         mov     ah,prstr
  808.         mov     dx,offset crlf
  809.         call    dosint
  810.         call    shkey0                  ; show this keycode
  811.  
  812.         pop     cx                      ; pause between screens, recover cntr
  813.         push    cx                      ; save it again
  814.         dec     cx                      ; number yet to be shown
  815.         jcxz    shky1b                  ; z = have now shown all of them
  816.         mov     ax,nkeys                ; number of defined keys
  817.         sub     ax,cx                   ; minus number yet to be displayed
  818.         xor     dx,dx                   ; clear extended numerator
  819.         div     twelve                  ; two lines per definition display
  820.         or      dx,dx                   ; remainder zero (12 defs shown)?
  821.         jnz     shky1b                  ; nz = no, not yet so keep going
  822.         mov     ah,prstr
  823.         mov     dx,offset shkmsg3       ; "push any key to continue" msg
  824.         call    dosint
  825. shky1a: call    getkey                  ; get any key
  826.         jc      shky1a                  ; c = nothing at keyboard yet, wait
  827. shky1b: pop     cx                      ; resume loop
  828.         loop    shky1
  829.         pop     si                      ; clean stack
  830.         call    shkfre                  ; show free string space
  831.         jmp     shkeyx                  ; exit
  832.  
  833.                 ; show key worker routine, called from above
  834.                                         ; SHKEY0 called by DFKEY just above
  835. SHKEY0: test    keycode,scan            ; scan code?
  836.         jz      shkey1                  ; z = no, regular ascii
  837.  
  838.                                         ; SCAN codes
  839.         mov     dx,offset scanmsg       ; say Scan Code:
  840.         mov     ah,prstr
  841.         call    dosint
  842.         mov     ah,conout
  843.         mov     dl,'\'                  ; add backslash before number
  844.         call    dosint
  845.         mov     ax,keycode              ; get key's code again
  846.         call    decout                  ; display 16 bit decimal keycode
  847.         jmp     shkey2                  ; go get definition
  848.  
  849. shkey1: mov     dx,offset ascmsg        ; say ASCII CHAR
  850.         mov     ah,prstr
  851.         call    dosint
  852.         mov     dl,byte ptr keycode     ; get ascii code (al part of input)
  853.         mov     ah,conout
  854.         cmp     dl,spc                  ; control code?
  855.         jae     shkey1a                 ; ae = no
  856.         push    dx                      ; save char
  857.         mov     dl,5eh                  ; show caret first
  858.         call    dosint
  859.         pop     dx
  860.         add     dl,'A'-1                ; ascii bias
  861. shkey1a:cmp     dl,del                  ; DEL?
  862.         jne     shkey1b                 ; ne = no
  863.         mov     dl,'D'                  ; spell out DEL
  864.         call    dosint
  865.         mov     dl,'E'
  866.         call    dosint
  867.         mov     dl,'L'
  868. shkey1b:call    dosint
  869.         mov     dl,spc                  ; add a couple of spaces
  870.         call    dosint
  871.         call    dosint
  872.         mov     dl,'\'                  ; add backslash before number
  873.         call    dosint
  874.         mov     ax,keycode              ; show 16 bit keycode in decimal
  875.         call    decout                  ; and go get definiton
  876.  
  877.                                         ; Display defintion
  878. shkey2: mov     dx,offset shkmsg2       ; intermediate part of reply
  879.         mov     ah,prstr                ; " is defined as "
  880.         call    dosint
  881.         push    di                      ; get a director code for this key
  882.         push    cx
  883.         mov     di,offset keylist       ; list of keycodes
  884.         mov     cx,nkeys                ; number currently defined
  885.         jcxz    shkey2a                 ; z = none
  886.         mov     ax,keycode              ; present keycode
  887.         push    ds
  888.         pop     es                      ; use datas segment for es:di
  889.         cld
  890.         repne   scasw                   ; is current keycode in the list?
  891.         jne     shkey2a                 ; ne = not in list
  892.         sub     di,2                    ; correct for auto increment
  893.         sub     di,offset keylist
  894.         mov     listptr,di              ; list pointer for existing definition
  895.         pop     cx
  896.         pop     di
  897.         jmp     shkey3                  ; go process definition
  898.  
  899. shkey2a:pop     cx
  900.         pop     di
  901.         mov     dx,offset noxmsg        ; say Self (no translation)
  902.         mov     ah,prstr
  903.         call    dosint
  904.         ret                             ; return to main show key loop
  905.  
  906. shkey3:                                 ; translations, get kind of.
  907.         mov     si,listptr
  908.         test    dirlist[si],verb        ; defined as verb?
  909.         jnz     shkey6                  ; nz = yes, go do that one
  910.         test    dirlist[si],strng       ; defined as string?
  911.         jz      shkey3a                 ; z = no
  912.         jmp     shkey8                  ; yes, do string display
  913. shkey3a:
  914.         mov     dx,offset ascmsg        ; CHAR. say 'Ascii char:'
  915.         mov     ah,prstr
  916.         call    dosint
  917.         mov     ax,dirlist [si]         ; get type and char
  918.         mov     dl,al                   ; put char here for display
  919.         push    ax                      ; save here too
  920.         mov     ah,conout
  921.         cmp     dl,spc                  ; control code?
  922.         jae     shkey4                  ; ae = no
  923.         push    dx
  924.         mov     dl,5eh                  ; show caret
  925.         call    dosint
  926.         pop     dx
  927.         add     dl,'A'-1                ; add ascii bias
  928. shkey4: cmp     dl,del                  ; DEL?
  929.         jne     shkey4a                 ; ne = no
  930.         mov     dl,'D'                  ; spell out DEL
  931.         call    dosint
  932.         mov     dl,'E'
  933.         call    dosint
  934.         mov     dl,'L'
  935. shkey4a:call    dosint
  936.         mov     dl,spc                  ; add a couple of spaces
  937.         mov     ah,conout
  938.         call    dosint
  939.         call    dosint
  940.         mov     dl,'\'                  ; add backslash before number
  941.         call    dosint
  942.         pop     ax                      ; recover char
  943.         xor     ah,ah                   ; clear high byte
  944.         call    decout                  ; show decimal value
  945.         ret                             ; return to main show key loop
  946.  
  947. shkey6: mov     ah,prstr                ; VERB
  948.         mov     dx,offset verbmsg       ; say 'verb'
  949.         call    dosint
  950.         mov     si,listptr              ; get verb index from director
  951.         mov     dx,dirlist[si]
  952.         and     dx,not(verb+strng)      ; remove type bits, leaves verb number
  953.         mov     bx,offset kverbs        ; table of verbs & actions
  954.         mov     al,byte ptr [bx]        ; number of keywords
  955.         xor     ah,ah
  956.         dec     ax
  957.         mov     kwcnt,ax                ; save number of last one here
  958.         cmp     dx,ax                   ; asking for more than we have?
  959.         ja      shkeyx                  ; a = yes, exit bad
  960.         inc     bx                      ; point to first slot
  961.         mov     cx,0                    ; current slot number
  962. shkey6b:cmp     cx,dx                   ; this slot?
  963.         je      shkey6c                 ; e = yes, print the text part
  964.         ja      shkeyx                  ; a = beyond, exit bad
  965.         mov     al,byte ptr [bx]        ; get cnt (keyword length)
  966.         xor     ah,ah
  967.         add     ax,4                    ; skip over '$' and two byte value
  968.         add     bx,ax                   ; bx = start of next keyword slot
  969.         inc     cx                      ; current keyword number
  970.         jmp     short shkey6b           ; try another
  971. shkey6c:inc     bx                      ; look at text field
  972.         mov     dx,bx                   ; offset for printing
  973.         mov     ah,prstr
  974.         call    dosint
  975.         mov     ah,conout
  976.         mov     dl,spc                  ; add a couple of spaces
  977.         call    dosint
  978.         call    dosint
  979.         mov     dl,'\'                  ; show verb name as \Kverb
  980.         call    dosint
  981.         mov     dl,'K'
  982.         call    dosint
  983.         mov     ah,prstr
  984.         mov     dx,bx                   ; show name part again
  985.         call    dosint
  986.         ret                             ; return to main show key loop
  987.  
  988. shkey8: mov     ah,prstr                ; STRING
  989.         mov     dx,offset strngmsg      ; say String:
  990.         call    dosint
  991.         mov     si,listptr              ; get index from director
  992.         mov     bx,dirlist[si]
  993.         and     bx,not(verb+strng)      ; remove type bits
  994.         shl     bx,1                    ; index words
  995.         mov     si,sptable[bx]          ; table of string offsets
  996.         mov     cl,byte ptr [si]        ; get string length byte
  997.         xor     ch,ch
  998.         inc     si                      ; point to string text
  999.         mov     ah,conout
  1000. shkey8a:cld
  1001.         lodsb                           ; get a byte
  1002.         cmp     al,spc                  ; control code?
  1003.         jae     shkey8b                 ; ae = no
  1004.         push    ax
  1005.         mov     dl,5eh                  ; show caret first
  1006.         call    dosint
  1007.         pop     ax
  1008.         add     al,40h                  ; convert to printable for display
  1009. shkey8b:mov     dl,al
  1010.         call    dosint                  ; display it
  1011.         loop    shkey8a                 ; do another
  1012.         ret                             ; return to main show key loop
  1013.  
  1014. shkeyx: pop     bx                      ; restore reg
  1015.         jmp     rskp                    ; return success
  1016. SHKEY   ENDP
  1017.  
  1018. ;;;     keyboard translator local support procedures, system independent
  1019.  
  1020. ; Tstkeyw checks text word pointed to by si against table of keywords (pointed
  1021. ; to by kverbs, made by mkeyw macro); returns in bx either action value or 0.
  1022. ; Returns in kbtemp the number of the keyword and carry clear, or if failure
  1023. ; returns kbtemp zero and carry set.
  1024. ; Keyword structure is:         db      cnt     (length of string 'word')
  1025. ;                               db      'word'  (keyword string)
  1026. ;                               db      '$'     (printing terminator)
  1027. ;                               dw      value   (value returned in bx)
  1028. ; Make these with macro mkeyw such as   mkeyw 'test',15   with the list of
  1029. ; such keywords headed by a byte giving the number of keywords in the list.
  1030. tstkeyw proc
  1031.         push    ax
  1032.         push    cx
  1033.         push    si
  1034.         mov     verblen,0               ; verblen will hold verb length
  1035.         push    si                      ; save user's verb pointer
  1036. tstkw1: cld
  1037.         lodsb                           ; get a verb character
  1038.         cmp     al,spc                  ; verbs are all non-spaces and above
  1039.         jbe     tstkw2                  ; be = done (space or control char)
  1040.         inc     verblen                 ; count verb length
  1041.         jmp     short tstkw1            ; printable char, look for more
  1042. tstkw2: pop     si                      ; pointer to verb
  1043.         mov     bx,offset kverbs        ; table of Kermit verb keywords
  1044.         mov     al,byte ptr [bx]        ; number of keywords
  1045.         xor     ah,ah
  1046.         mov     kwcnt,ax                ; save number of keywords here
  1047.         inc     bx                      ; point bx to first slot
  1048.         mov     kbtemp,0                ; remember which keyword
  1049.  
  1050. tstkw3:                                 ; match table keyword and text word
  1051.         mov     cx,verblen              ; length of user's verb
  1052.         cmp     byte ptr [bx],cl        ; compare length vs table keyword
  1053.         jne     tstkw4                  ; ne = not equal lengths, try another
  1054.         push    si                      ; lengths match, how about spelling?
  1055.         push    bx
  1056.         inc     bx                      ; point at start of keyword
  1057. tstkw3a:mov     ah,byte ptr [bx]        ; keyword char
  1058.         mov     al,byte ptr [si]        ; text char
  1059.         cmp     ah,'A'
  1060.         jb      tstkw3b                 ; b = control chars
  1061.         cmp     ah,'Z'
  1062.         ja      tstkw3b                 ; a = not upper case alpha
  1063.         add     ah,'a'-'A'              ; convert upper case to lower case
  1064. tstkw3b:cmp     al,'A'
  1065.         jb      tstkw3c
  1066.         cmp     al,'Z'
  1067.         ja      tstkw3c
  1068.         add     al,'a'-'A'              ; convert upper case to lower case
  1069. tstkw3c:cmp     al,ah                   ; test characters
  1070.         jne     tstkw3d                 ; ne = no match
  1071.         inc     si                      ; move to next char
  1072.         inc     bx
  1073.         loop    tstkw3a                 ; loop through entire length
  1074. tstkw3d:pop     bx
  1075.         pop     si
  1076.         jcxz    tstkw5                  ; z: cx = 0, exit with match;
  1077.                                         ;  else select next keyword
  1078. tstkw4: inc     kbtemp                  ; number of keyword to test next
  1079.         mov     cx,kbtemp
  1080.         cmp     cx,kwcnt                ; all done? Recall kbtemp starts at 0
  1081.         jae     tstkwx                  ;ae = exhausted search, unsuccessfully
  1082.         mov     al,byte ptr [bx]        ; cnt (keyword length from macro)
  1083.         xor     ah,ah
  1084.         add     ax,4                    ; skip over '$' and two byte value
  1085.         add     bx,ax                   ; bx = start of next keyword slot
  1086.         jmp     tstkw3                  ; do another comparison
  1087.  
  1088. tstkw5:                                 ; get action pointer
  1089.         mov     al,byte ptr [bx]        ; cnt (keyword length from macro)
  1090.         xor     ah,ah
  1091.         add     ax,2                    ; skip over '$'
  1092.         add     bx,ax                   ; now bx points to dispatch value
  1093.         mov     bx,[bx]                 ; bx holds dispatch value
  1094.         clc                             ; carry clear for success
  1095.         jmp     short tstkwxx           ; exit
  1096.         ret
  1097. tstkwx: xor     bx,bx                   ; exit when no match
  1098.         mov     kbtemp,bx               ; make verb number be zero too
  1099.         stc                             ; carry set for failure
  1100. tstkwxx:pop     si
  1101.         pop     cx
  1102.         pop     ax
  1103.         ret
  1104. tstkeyw endp
  1105.  
  1106. ; Insert asciiz string pointed to by si into string buffer stbuf.
  1107. ; Reg cx has string length upon entry.
  1108. ; Success: returns offset of first free byte (strmax) in string buffer stbuf,
  1109. ; cx = type and Index of new string, and carry clear.
  1110. ; Failure = carry set.
  1111. insertst proc
  1112.         push    bx
  1113.         push    dx
  1114.         push    si
  1115.         push    di
  1116.         push    kbtemp          ; save this variable too
  1117.         mov     dx,cx           ; save length of incoming string in dx
  1118.         mov     bx,offset sptable ; table of string offsets
  1119.         mov     kbtemp,0        ; slot number
  1120.         mov     cx,maxstng      ; number of entries, find an empty slot
  1121. insert1:cmp     word ptr[bx],0  ; slot empty?
  1122.         je      insert2         ; e = yes
  1123.         inc     kbtemp          ; remember slot number
  1124.         add     bx,2            ; look at next slot
  1125.         loop    insert1         ; keep looking
  1126.         jmp     short insert4   ; get here if no empty slots
  1127. insert2:                        ; see if stbuf has sufficient space
  1128.         mov     cx,dx           ; length of new string to cx
  1129.         mov     di,strmax       ; offset of first free byte in stbuf
  1130.         add     di,cx           ; di = address where this string would end
  1131.         cmp     di,offset stbuf+stbuflen ; beyond end of buffer?
  1132.         jae     insert4         ; ae = yes, not enough room
  1133.         mov     di,strmax       ; point to first free slot in stbuf
  1134.         mov     [bx],di         ; fill slot with address offset of buffer
  1135.         push    es
  1136.         push    ds
  1137.         pop     es              ; point es:di to datas segment
  1138.         cld
  1139.         mov     byte ptr [di],cl ; length of text for new string
  1140.         inc     di              ; move to next storage slot
  1141.         rep     movsb           ; copy string text
  1142.         pop     es
  1143.         mov     strmax,di       ; offset of next free byte
  1144.         mov     cx,kbtemp       ; return new slot number with Director Index
  1145.         and     cx,not(strng+verb) ; clear type bits
  1146.         or      cx,strng        ; say type is multi-char string
  1147.         clc                     ; say success
  1148.         jmp     short insertx   ; exit
  1149. insert4:stc                     ; say no-can-do
  1150. insertx:pop     kbtemp
  1151.         pop     di
  1152.         pop     si
  1153.         pop     dx
  1154.         pop     bx
  1155.         ret
  1156. insertst endp
  1157.  
  1158. ; Remove (delete) string. Enter with listptr preset for director entry.
  1159. ; Acts only on existing multi-char strings; recovers freed space.
  1160. ; All registers preserved.
  1161. remstr  proc
  1162.         push    si
  1163.         mov     si,listptr              ; list pointer
  1164.         test    dirlist[si],strng       ; multi-char string?
  1165.         pop     si
  1166.         jnz     remst1                  ; nz = a multi-char string
  1167.         ret                             ; else do nothing
  1168. remst1: push    ax
  1169.         push    bx
  1170.         push    cx
  1171.         push    dx
  1172.         push    si
  1173.         mov     si,listptr
  1174.         mov     ax,dirlist[si]          ; Director table entry
  1175.         and     ax,not(strng+verb) ; clear type bits, leave string's pointer
  1176.         mov     dirlist[si],0           ; clear Director table entry
  1177.         shl     ax,1                    ; index words not bytes
  1178.         mov     si,offset sptable       ; list of string offsets in stbuf
  1179.         add     si,ax                   ; plus index = current slot
  1180.         mov     bx,[si]                 ; get offset of string to be deleted
  1181.         mov     dx,bx                   ; save in dx for later
  1182.         mov     cl,byte ptr [bx]        ; get length byte
  1183.         xor     ch,ch                   ; get length of subject string
  1184.         inc     cx                      ; length byte too, cx has whole length
  1185.         sub     strmax,cx       ; count space to be freed (adj end-of-buf ptr)
  1186.         mov     word ptr [si],0 ; clear sptable of subject string address
  1187.         push    cx                      ; save length of purged string
  1188.         push    di                      ; save di
  1189.         push    si
  1190.         push    es                      ; save es
  1191.         push    ds
  1192.         pop     es              ; setup es:di to be ds:offset of string
  1193.         mov     di,dx           ; destination = start address of purged string
  1194.         mov     si,dx           ; source = start address of purged string
  1195.         add     si,cx           ;  plus string length of purged string.
  1196.         mov     cx,offset stbuf+stbuflen ; 1 + address of buffer end
  1197.         sub     cx,si                   ; 1 + number of bytes to move
  1198.         dec     cx                      ; number of bytes to move
  1199.         jcxz    remst2                  ; z = none
  1200.         cld                             ; direction is forward
  1201.         rep     movsb                   ; move down preserved strings
  1202. remst2: pop     es                      ; restore regs
  1203.         pop     di
  1204.         pop     si
  1205.         pop     ax              ; recover length of purged string (was in cx)
  1206.         mov     bx,offset sptable       ; string pointer table
  1207.         mov     cx,maxstng              ; max mumber of entries
  1208. remst4: cmp     [bx],dx         ; does this entry occur before purged string?
  1209.         jbe     remst5          ; be = before or equal, so leave it alone
  1210.         sub     [bx],ax         ; recompute address (remove old string space)
  1211. remst5: add     bx,2                    ; look at next list entry
  1212.         loop    remst4                  ; do all entries in sptable
  1213.         pop     si
  1214.         pop     dx
  1215.         pop     cx
  1216.         pop     bx
  1217.         pop     ax
  1218.         ret
  1219. remstr  endp
  1220.  
  1221. shkfre  proc                            ; show free key & string defs & space
  1222.         push    ax                      ; preserves all registers.
  1223.         push    bx
  1224.         push    cx
  1225.         push    dx
  1226.         push    kbtemp
  1227.         mov     dx,offset fremsg
  1228.         mov     ah,prstr
  1229.         call    dosint
  1230.         mov     ax,maxkeys              ; max number of key defs
  1231.         sub     ax,nkeys                ; number currently used
  1232.         call    decout                  ; show the value
  1233.         mov     ah,prstr
  1234.         mov     dx,offset kyfrdef       ; give key defs msg
  1235.         call    dosint
  1236.         mov     bx,offset sptable       ; table of string pointers
  1237.         mov     cx,maxstng              ; number of pointers
  1238.         mov     kbtemp,0                ; number free
  1239. shkfr1: cmp     word ptr [bx],0         ; slot empty?
  1240.         jne     shkfr2                  ; ne = no
  1241.         inc     kbtemp                  ; count free defs
  1242. shkfr2: add     bx,2                    ; look at next slot
  1243.         loop    shkfr1                  ; do all of them
  1244.         mov     ax,kbtemp               ; number of free defs
  1245.         call    decout                  ; display
  1246.         mov     dx,offset stfrdef       ; say free string defs
  1247.         mov     ah,prstr
  1248.         call    dosint
  1249.         mov     ax,offset stbuf+stbuflen ; 1 + last byte in stbuf
  1250.         sub     ax,strmax               ; offset of last free byte in stbuf
  1251.         call    decout
  1252.         mov     dx,offset stfrspc       ; give free space part of msg
  1253.         mov     ah,prstr
  1254.         call    dosint
  1255.         pop     kbtemp
  1256.         pop     dx
  1257.         pop     cx
  1258.         pop     bx
  1259.         pop     ax
  1260.         ret
  1261. shkfre  endp
  1262. ; Initialize the keyboard tables at Kermit startup time. Optional procedure.
  1263. ; Requires kbdinlst to be configured with mkeyw macro in the form
  1264. ;       mkeyw   'definition',keytype*256+keycode
  1265. ; keytype is 0 for scan codes and non-zero for ascii.
  1266. ; Returns normally.
  1267. kbdinit proc                            ; read keyword kbdinlst and setup
  1268.         push    ds                      ;  initial keyboard assignments.
  1269.         pop     es                      ; set es:di to datas segment
  1270.         mov     taklev,1                ; pretend that we are in Take file
  1271.         mov     si,offset kbdinlst      ; start of list of definitions
  1272. kbdini1:mov     cl,byte ptr [si]        ; cnt field (keyword length of macro)
  1273.         xor     ch,ch
  1274.         jcxz    kbdinix                 ; z = null cnt field = end of list
  1275.         inc     si                      ; look at text field
  1276.         mov     di,offset tranbuf       ; where defkey expects text
  1277.         cld
  1278.         rep     movsb                   ; copy cx chars to tranbuf
  1279.         mov     byte ptr [di],0         ; insert null terminator
  1280.         inc     si                      ; skip '$' field
  1281.         mov     ax,word ptr [si]        ; get value field
  1282.         mov     keycode,ax              ; set key ident value
  1283.         push    si
  1284.         call    dfkey2                  ; put dfkey to work
  1285.          nop
  1286.          nop
  1287.          nop
  1288.         pop     si
  1289.         add     si,2                    ; point to next entry
  1290.         jmp     kbdini1                 ; keep working
  1291. kbdinix:mov     taklev,0                ; reset Take file level
  1292.         ret
  1293. kbdinit endp
  1294. ;;;     End of System Independent Procedures
  1295.  
  1296. ;;;     Begin System Dependent Procedures
  1297.  
  1298. ; Read keyboard. System dependent.
  1299. ; Return carry set if nothing at keyboard.
  1300. ; If char present return carry clear with key's code in Keycode.
  1301. ; If key is ascii put that in the low byte of Keycode and clear bit Scan in
  1302. ; the high byte; otherwise, put the scan code in the lower byte and set bit
  1303. ; Scan in the high byte.
  1304. ; Bit Scan is set if key is not an ascii code.
  1305. ; Modifies register ax.
  1306. getkey  proc
  1307.         mov     si,ciptr                ; read 1 from keyboard
  1308.         lodsb
  1309.         cmp     al,cifill
  1310.         jne     GETKY1                  ; ne = got one
  1311.         stc                             ; no char, ret w/carry set
  1312.         ret
  1313. GETKY1: cmp     si,offset cibuf2 + cibufl
  1314.         jne     GETKY2
  1315.         mov     si,offset cibuf1
  1316. GETKY2: mov     ciptr,si
  1317.         xor     ah,ah
  1318.         cmp     al,80h                  ; if > 7fh,
  1319.         jb      GETKY3
  1320.         or      ax,scan                 ; set scan flag
  1321. GETKY3: mov     keycode,ax              ; ret w/carry clear = keycode's got one
  1322.         clc
  1323.         ret
  1324. getkey  endp
  1325.  
  1326. ; Jumping to this location is like retskp.  It assumes the instruction
  1327. ;   after the call is a jmp addr.
  1328.  
  1329. RSKP    PROC
  1330.         pop     bp
  1331.         add     bp,3
  1332.         jmp     bp
  1333. RSKP    ENDP
  1334.  
  1335. code    ends
  1336.         end
  1337.