home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ccdos / ccscmd.asm < prev    next >
Assembly Source File  |  2020-01-01  |  60KB  |  1,256 lines

  1.         NAME    ccscmd
  2. ; File CCSCMD.ASM
  3.  
  4. ;CHINESE
  5. ifdef   MSDOS
  6.         include msscmd.dat
  7. else
  8.         include ccscmd.dat
  9. endif
  10.  
  11. code    segment public 'code'
  12.         extrn   ctlu:near, cmblnk:near, clearl:near, locate:near, takrd:near
  13.         extrn   takclos:near, docom:near
  14.         assume  cs:code, ds:datas, es:nothing
  15.  
  16. ;       This routine parses the specified function in AH. Any additional
  17. ;       information is in DX and BX.
  18. ;       Returns rskp on success and ret on failure
  19.  
  20. COMND   PROC NEAR
  21.         mov     cmdstk,sp               ; save stack ptr for longjmp exit
  22.         mov     noparse,0               ; recognize semicolons in Take files
  23.         cmp     ah,cmcfm                ; Parse a confirm?
  24.         jne     cm2                     ; nz = no
  25.         jmp     cmcfrm                  ; get a confirm
  26. cm2:    cmp     ah,cmkey                ; Parse a keyword?
  27.         jne     cm3
  28.         jmp     cmkeyw                  ; Try and get one
  29. cm3:    cmp     ah,cmtxt                ; Parse arbitrary text
  30.         jne     cm4
  31.         jmp     cmtext
  32. cm4:    cmp     ah,cmfile               ; parse text surrounded by whitespace
  33.         jne     cm5
  34.         jmp     cmfil0
  35. cm5:    mov     ah,prstr                ; Else give error
  36. ;        mov     dx,offset cmer00        ; "?Program internal error"
  37.         mcmsg   cmer00,ccmer00
  38.  
  39.         int     dos
  40.         jmp     prserr
  41. COMND   ENDP
  42.  
  43. ; This routine parses a keyword from the table pointed at by DX, help text
  44. ; point to by BX. Format of the table is as follows (use macro mkeyw):
  45. ;       addr:   db      N         ; Where N is the # of entries in the table
  46. ;               db      M         ; M is the size of the keyword (excl '$')
  47. ;               db      'string$' ; String is the keyword
  48. ;               dw      value     ; Value is data to be returned
  49. ; Keywords may be in any order and in mixed case.
  50. ; Return is rskp for success and ret for failure.
  51.  
  52. ; comand.cmptab: pointer to keyword table (supplied by caller)
  53. ; comand.cmhlp: pointer to help message (supplied by caller)
  54. ; comand.cmsptr: pointer to current user word text
  55. ; comand.cmsiz: length of user text, excluding terminator
  56. ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
  57. ; comand.cmwhite: non-zero allows leading whitespace for cmtxt and cmfile,
  58. ;                 reset automatically at end of call
  59. ; comand.cmwptr: buffer write pointer to next free byte
  60. ; comand.cmrptr: buffer read pointer for next free byte
  61. ; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call
  62. ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
  63. ;                automatically at time of failure.
  64. cmkeyw  proc    near
  65.         mov     comand.cmsiz,0          ; user word length
  66.         mov     ax,comand.cmrptr        ; get command reading pointer
  67.         mov     comand.cmsptr,ax        ; set pointer for start of user word
  68.         mov     comand.cmhlp,bx         ; save the help pointer
  69.         mov     comand.cmptab,dx        ; save the beginning of keyword table
  70.         mov     bx,dx
  71.         cmp     byte ptr[bx],0          ; get number of entries in table
  72.         jne     cmky1
  73.         jmp     cmky7                   ; e = no keywords to check, error
  74. cmky1:  mov     comand.cmsflg,0ffh      ; skip leading spaces/tabs
  75.         call    cmgtch                  ; get char from the user into ah
  76.         jc      cmky3                   ; c = terminator
  77.         mov     dx,comand.cmrptr        ; next byte to read
  78.         dec     dx                      ; where we just read a char
  79.         mov     comand.cmsptr,dx        ; remember start of keyword
  80.         inc     comand.cmsiz            ; start counting user chars
  81. cmky2:  call    cmgtch                  ; read until terminator
  82.         jc      cmky3                   ; c = terminator
  83.         inc     comand.cmsiz            ; count user chars
  84.         jmp     short cmky2             ; no terminator yet
  85.  
  86. cmky3:  cmp     ah,'?'                  ; need help?
  87.         jne     cmky4                   ; ne = no
  88.         jmp     cmkyhlp                 ; do help and exit
  89. cmky4:  cmp     ah,escape               ; escape?
  90.         jne     cmky6                   ; ne = no
  91.         call    cmkyesc                 ; process escape
  92.         jc      cmky5                   ; c = failure (no unique keyword yet)
  93.         mov     comand.cmper,0          ; reset to variable recognition
  94.         mov     comand.cmkeep,0
  95.         mov     comand.impdo,0          ; clear flag to prevent loops
  96.         mov     comand.cmquiet,0        ; permit echoing again
  97.         jmp     rskp                    ; return successfully to user
  98.  
  99. cmky5:  cmp     comand.cmsiz,0          ; started a word yet?
  100.         je      cmky1                   ; e = no, ignore escape, keep looking
  101.         jmp     cmkyhlp                 ; ne = yes, show type of error
  102.  
  103. cmky6:  cmp     comand.cmsiz,0          ; length of user's text, empty?
  104.         je      cmky7                   ; e = yes, parse error
  105.         push    bx
  106.         mov     bx,comand.cmsptr        ; point at first user character
  107.         cmp     byte ptr[bx],':'        ; start of a label?
  108.         pop     bx
  109.         jne     cmky6a                  ; ne = no, return success
  110.         mov     comand.cmsiz,1          ; say just one byte
  111. cmky6a:
  112.         call    getkw                   ; get unique kw, point to it with bx
  113.         jc      cmky8                   ; c = not found
  114.         add     bl,[bx]                 ; add length of keyword text (CNT)
  115.         adc     bh,0
  116.         add     bx,2                    ; point at value field
  117.         mov     bx,[bx]                 ; bx = return value following keyword
  118.         mov     comand.cmper,0          ; reset to variable recognition
  119.         mov     comand.cmkeep,0
  120.         mov     comand.impdo,0          ; clear flag to prevent loops
  121.         mov     comand.cmquiet,0        ; permit echoing again
  122.         mov     errflag,0
  123.         jmp     rskp                    ; return successfully
  124.                                         ; all other terminators come here
  125. cmky7:  cmp     comand.cmsiz,0          ; empty table or empty user's text?
  126.         jne     cmky8                   ; ne = no
  127.         cmp     comand.cmcr,0           ; empty lines allowed?
  128.         jne     cmky10                  ; ne = yes, do not complain
  129.         push    dx
  130.         mov     ah,prstr
  131. ;        mov     dx,offset cmer01        ; command word expected
  132.         mcmsg   cmer01,ccmer01
  133.  
  134.         int     dos
  135.         pop     dx
  136.         mov     comand.cmquiet,0        ; permit echoing again
  137.         mov     comand.impdo,0          ; clear flag to prevent loops
  138.         ret                             ; do ret exit
  139.  
  140. cmky8:  cmp     comand.impdo,0          ; failed here, ok to try Macro table?
  141.         je      cmky8a                  ; e = no, use regular exit path
  142.         mov     comand.impdo,0          ; yes, but clear flag to prevent loops
  143.         mov     comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
  144.         mov     comand.cmquiet,1        ; suppress echoing of same keyword
  145.         mov     bx,offset docom         ; return DO as "found" keyword
  146.         jmp     rskp                    ; return success to invoke DO
  147.  
  148. cmky8a: mov     comand.cmquiet,0        ; permit echoing again
  149.         mov     errflag,1               ; say already doing error recovery
  150.         or      kstatus,1               ; global command status, failure
  151.         call    isdev                   ; reading pretyped lines?
  152.         jnc     cmky9                   ; nc = yes, consume rest of line
  153.         cmp     taklev,0                ; in a Take file?
  154.         jne     cmky9                   ; ne = yes
  155.         call    cmskw                   ; display offending keyword
  156.         dec     comand.cmrptr           ; interactive, backup to terminator
  157.         mov     bx,comand.cmrptr        ; look at it
  158.         cmp     byte ptr [bx],' '       ; got here on space terminator?
  159.         jne     cmky10                  ; ne = no, (cr,lf,ff) exit failure
  160.         mov     ah,prstr                ; start a fresh line
  161.         mov     dx,offset crlf
  162.         int     dos
  163.         call    bufreset                ; cut back buffer to just before term
  164.         jmp     repars                  ; reparse interactive lines
  165.  
  166. cmky9:  call    cmcfrm                  ; get formal end of command line
  167.          nop                            ;  to maintain illusion of typeahead
  168.          nop                            ;  and let user backspace to correct
  169.          nop                            ;  mistakes (we reparse everything)
  170.         call    cmskw                   ; display offending keyword
  171. cmky10: ret                             ; do ret exit
  172. cmkeyw  endp
  173.  
  174. ;;;;;; start support routines for keyword parsing.
  175.  
  176. cmkyesc proc    near                    ; deal with escape terminator
  177.         call    bufreset                ; reset buffer to end just before ESC
  178.         cmp     comand.cmsiz,0          ; user word length, empty?
  179.         jne     cmkye2                  ; ne = have user text, else complain
  180. cmkye1: call    esceoc                  ; do normal escape end-of-command
  181.         stc                             ; say failure to fill out word
  182.         ret
  183.                                         ; add unique keyword to buffer
  184. cmkye2: call    getkw                   ; is there a matching keyword?
  185.         jc      cmkye1                  ; c = ambiguous or not found
  186.         push    bx                      ; unique, bx points to structure
  187.         push    si
  188.         mov     cl,[bx]                 ; length of keyword
  189.         mov     ch,0
  190.         inc     bx                      ; point to first letter
  191.         mov     si,comand.cmwptr        ; where next char goes
  192.         mov     dx,comand.cmsiz         ; length of user word
  193.         add     bx,dx                   ; add chars known so far
  194.         sub     cx,dx                   ; calculate number yet to add
  195.         add     comand.cmsiz,cx
  196.         jcxz    cmkye4                  ; z = none
  197.         mov     ah,conout               ; display new char
  198. cmkye3: mov     al,[bx]                 ; get a keyword letter
  199.         inc     bx
  200.         call    tolowr                  ; lowercase
  201.         mov     [si],al                 ; store it
  202.         inc     si
  203.         mov     dl,al
  204.         int     dos                     ; display it
  205.         loop    cmkye3                  ; do all new chars
  206. cmkye4: mov     byte ptr[si],' '        ; insert space terminator in buffer
  207.         mov     dl,' '                  ; display it
  208.         mov     ah,conout
  209.         int     dos
  210.         inc     si
  211.         mov     comand.cmrptr,si        ; move token pointer after the space
  212.         mov     comand.cmwptr,si        ; next free slot is after the space
  213.         mov     comand.cmsflg,0ffh      ; set space-seen flag
  214.         pop     si
  215.         pop     bx                      ; bx = keyword structure
  216.         add     bl,[bx]                 ; add length of keyword text
  217.         adc     bh,0
  218.         add     bx,2                    ; point at value field
  219.         mov     bx,[bx]                 ; bx = return value following keyword
  220.         clc                             ; carry clear for success
  221.         ret
  222. cmkyesc endp
  223.  
  224. esceoc  proc    near                    ; do normal escape end-of-command
  225.         push    ax
  226.         push    dx
  227.         mov     ah,conout               ; ring the bell
  228.         mov     dl,bell
  229.         int     dos
  230.         pop     dx
  231.         pop     ax
  232.         call    bufreset                ; reset buffer
  233.         stc                             ; say error condition
  234.         ret
  235. esceoc  endp
  236.  
  237. ; Help. Question mark entered by user.  Display all the keywords that match
  238. ; user text. If text is null then use external help if available; otherwise,
  239. ; display all keywords in the table. Removes question mark from buffer and
  240. ; invokes reparse of command line to-date. User word starts at .cmsptr and
  241. ; is .cmsiz bytes long.
  242. cmkyhlp proc    near
  243.         mov     cx,0                    ; clear number of keyword (none yet)
  244.         cmp     comand.cmsiz,0          ; user text given?
  245.         jne     cmkyh1                  ; ne = yes, use matching keywords
  246.         cmp     comand.cmhlp,0          ; external help given?
  247.         jne     cmkyh6                  ; yes, use it instead of full table
  248. cmkyh1: mov     temp,0                  ; count # chars printed on this line
  249.         mov     bx,comand.cmptab        ; beginning of kw table
  250.         mov     ch,[bx]                 ; length of table
  251.         mov     cl,0                    ; no keywords or help displayed yet
  252.         inc     bx                      ; point at CNT field
  253. cmkyh2: cmp     comand.cmsiz,0          ; length of user word
  254.         je      cmkyh3                  ; e = null, use full table
  255.         call    cmpwrd                  ; compare keyword with user word
  256.         jc      cmkyh5                  ; c = no match, get another keyword
  257. cmkyh3: mov     al,[bx]                 ; length of table keyword
  258.         add     byte ptr temp,al        ; count chars printed so far
  259.         cmp     temp,76                 ; will this take us beyond column 78?
  260.         jbe     cmkyh4                  ; be = no, line has more room
  261.         mov     ah,prstr
  262.         mov     dx,offset crlf          ; break the line
  263.         int     dos
  264.         mov     temp,0                  ; and reset the count
  265. cmkyh4: cmp     cl,0                    ; any keywords found yet?
  266.         jne     cmkyh4a                 ; ne = yes
  267. ;        mov     dx,offset cmin01        ; start with One of the following: msg
  268.         mcmsg   cmin01,ccmin01
  269.         mov     ah,prstr
  270.         int     dos
  271.         inc     cl                      ; say one keyword has been found
  272. cmkyh4a:mov     dl,spc                  ; put two spaces before each keyword
  273.         mov     ah,conout
  274.         int     dos
  275.         int     dos
  276.         add     temp,2                  ; count output chars
  277.         mov     dx,bx                   ; get current keyword structure
  278.         inc     dx                      ;  text part
  279.         mov     ah,prstr
  280.         int     dos                     ; display it
  281. cmkyh5: dec     ch                      ; are we at end of table?
  282.         jle     cmkyh7                  ; le = yes, quit now
  283.         add     bl,[bx]                 ; next keyword, add CNT chars to bx
  284.         adc     bh,0
  285.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  286.         jmp     cmkyh2                  ; go examine this keyword
  287.  
  288. cmkyh6: mov     dx,comand.cmhlp         ; external help text
  289.         mov     ah,prstr
  290.         int     dos
  291.         inc     cl                      ; say gave help already
  292. cmkyh7: cmp     cl,0                    ; found any keywords?
  293.         jne     cmkyh9                  ; ne = yes
  294.         mov     cx,comand.cmsiz         ; length of word
  295.         cmp     cx,0
  296.         jg      cmkyh8                  ; g = something to show
  297.         push    dx
  298.         mov     ah,prstr
  299. ;        mov     dx,offset cmer01        ; command word expected
  300.         mcmsg   cmer01,ccmer01
  301.  
  302.         int     dos
  303.         pop     dx
  304.         jmp     prserr
  305. cmkyh8: mov     kwstat,0                ; set keyword not-found status
  306.         call    cmskw                   ; display offending keyword
  307. cmkyh9: mov     ah,prstr                ; start a fresh line
  308.         mov     dx,offset crlf
  309.         int     dos
  310.         call    bufreset                ; cut back buffer to just before '?'
  311.         jmp     repars
  312. cmkyhlp endp
  313.  
  314. ; See if keyword is ambiguous or not from what the user has typed in.
  315. ; Return carry set if word is ambiguous or not found, carry clear otherwise.
  316. ; Uses table pointed at by comand.cmptab, user text pointed at by
  317. ; comand.cmsptr and length in comand.cmsiz.
  318. cmambg  proc    near
  319.         push    bx
  320.         push    cx
  321.         push    dx
  322.         mov     dl,0                    ; count keyword matches so far
  323.         mov     bx,comand.cmptab        ; look at start of keyword table
  324.         mov     cl,[bx]                 ; get number of entries in table
  325.         mov     ch,0                    ; use cx as a counter
  326.         jcxz    cmamb8                  ; z = no table so always ambiguous
  327.         inc     bx                      ; look at CNT byte of keyword
  328. cmamb4: call    cmpwrd                  ; user vs table words, same?
  329.         jc      cmamb6                  ; c = no match
  330.         inc     dl                      ; count this as a match
  331.         cmp     dl,1                    ; more than one match?
  332.         ja      cmamb8                  ; a = yes, quit now
  333. cmamb6: add     bl,[bx]                 ; add CNT chars to bx
  334.         adc     bh,0
  335.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  336.         loop    cmamb4                  ; do rest of keyword table
  337. cmamb7: cmp     dl,1                    ; how many matches were found?
  338.         jne     cmamb8                  ; ne = none or more than 1: ambiguous
  339.         pop     dx                      ; restore main registers
  340.         pop     cx
  341.         pop     bx
  342.         clc
  343.         ret                             ; ret = not ambiguous
  344. cmamb8: pop     dx                      ; restore main registers
  345.         pop     cx
  346.         pop     bx
  347.         stc
  348.         ret                             ; return ambiguous or not found
  349. cmambg  endp
  350.  
  351. ; Compare user text with keyword, abbreviations are considered a match.
  352. ; Enter with bx pointing at keyword table CNT field for a keyword.
  353. ; Return carry clear if they match, set if they do not match. User text
  354. ; pointed at by comand.cmsptr and length is in comand.cmsiz.
  355. ; Registers preserved.
  356.  
  357. cmpwrd  proc    near
  358.         push    cx
  359.         mov     cx,comand.cmsiz         ; length of user's text
  360.         jcxz    cmpwrd2                 ; z: null user word matches no keyword
  361.         cmp     cl,[bx]                 ; user's text longer than keyword?
  362.         ja      cmpwrd2                 ; a = yes, no match
  363.         push    ax
  364.         push    bx
  365.         push    si
  366.         inc     bx                      ; point at table's keyword text
  367.         mov     si,comand.cmsptr        ; buffer ptr to user input
  368.         cld
  369. cmpwrd1:lodsb                           ; user text
  370.         mov     ah,[bx]                 ; keyword text
  371.         inc     bx                      ; next keyword letter
  372.         call    tolowr                  ; force lower case on both chars
  373.         cmp     ah,al                   ; same?
  374.         loope   cmpwrd1                 ; e = same so far
  375.         pop     si
  376.         pop     bx
  377.         pop     ax
  378.         jne     cmpwrd2                 ; ne = mismatch
  379.         pop     cx                      ; recover keyword counter
  380.         clc                             ; they match
  381.         ret
  382. cmpwrd2:pop     cx                      ; recover keyword counter
  383.         stc                             ; they do not match
  384.         ret
  385. cmpwrd  endp
  386.  
  387. ; Get pointer to keyword structure using user text. Uses keyword table
  388. ; pointed at by comand.cmptab and comand.cmsiz holding length
  389. ; of user's keyword (cmpwrd needs comand.cmsptr pointing at user's
  390. ; keyword and length of comand.cmsiz). Structure pointer returned in BX.
  391. ; Return carry clear for success and carry set for failure. Modifies BX.
  392. getkw   proc    near
  393.         push    cx
  394.         mov     kwstat,0                ; keyword status, set to not-found
  395.         cmp     comand.cmsiz,0          ; length of user word, empty?
  396.         je      getkw3                  ; e = yes, fail
  397.         mov     bx,comand.cmptab        ; table of keywords
  398.         mov     cl,[bx]                 ; number of keywords in table
  399.         mov     ch,0
  400.         jcxz    getkw3                  ; z = none, fail
  401.         inc     bx                      ; point to first
  402. getkw1: call    cmpwrd                  ; compare user vs table words
  403.         jc      getkw2                  ; c = failed to match word, try next
  404.         mov     kwstat,1                ; say found one keyword, maybe more
  405.         push    dx
  406.         mov     dx,comand.cmsiz         ; users word length
  407.         cmp     [bx],dl                 ; same length (end of keyword)?
  408.         pop     dx
  409.         je      getkw4                  ; e = yes, exact match. Done
  410.         call    cmambg                  ; ambiguous?
  411.         jnc     getkw4                  ; nc = unique, done, return with bx
  412.         mov     kwstat,2                ; say more than one such keyword
  413. getkw2: add     bl,[bx]                 ; next keyword, add CNT chars to bx
  414.         adc     bh,0
  415.         add     bx,4                    ; skip CNT, '$' and 16 bit value
  416.         loop    getkw1                  ; do all, exhaustion = failure
  417. getkw3: pop     cx
  418.         stc                             ; return failure
  419.         ret
  420. getkw4: pop     cx
  421.         clc                             ; return success
  422.         ret
  423. getkw   endp
  424.  
  425. ; show offending keyword message. Comand.cmsptr points to user word,
  426. ; comand.cmsiz has length. Modifies AX, CX, and DX.
  427. cmskw   proc    near
  428.         mov     ah,prstr                ; not one of the above terminators
  429. ;        mov     dx,offset cmer02        ; '?Word "'
  430.         mcmsg   cmer02,ccmer02
  431.  
  432.         int     dos
  433.         mov     cx,comand.cmsiz         ; length of word
  434.         jcxz    cmskw3                  ; z = null
  435.         mov     ah,conout
  436.         push    si
  437.         mov     si,comand.cmsptr        ; point to word
  438.         cld
  439. cmskw1: lodsb
  440.         cmp     al,' '                  ; control code?
  441.         jae     cmskw2                  ; ae = no
  442.         push    ax
  443.         mov     dl,5eh                  ; caret
  444.         int     dos
  445.         pop     ax
  446.         add     al,'A'-1                ; plus ascii bias
  447. cmskw2: mov     dl,al                   ; display chars in word
  448.         int     dos
  449.         loop    cmskw1
  450.         pop     si
  451. cmskw3:
  452. ;       mov     dx,offset cmer03        ; '" not usable here.'
  453.         mcmsg   cmer03,ccmer03
  454.  
  455.         cmp     kwstat,1                ; kywd status from getkw, not found?
  456.         jb      cmskw4                  ; b = not found, a = ambiguous
  457. ;        mov     dx,offset cmer04        ; '" ambiguous'
  458.         mcmsg   cmer04,ccmer04
  459.  
  460. cmskw4: mov     ah,prstr
  461.         int     dos
  462.         ret
  463. cmskw   endp
  464. ;;;;;;;;;; end of support routines for keyword parsing.
  465.  
  466. ; Parse arbitrary text up to a CR. Enter with BX = pointer to output buffer,
  467. ; DX pointing to help text. Produces asciiz string. Return updated pointer in
  468. ; BX and output size in AH. Leading spaces are omitted unless comand.cmwhite
  469. ; is non-zero (cleared upon exit). It does not need to be followed by the
  470. ; usual call to confirm the line. Byte comand.cmblen can be used to specify
  471. ; the length of the caller's buffer; cleared to zero by this command to
  472. ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
  473. cmtext  proc    near
  474.         mov     comand.cmptab,bx        ; save pointer to data buffer
  475.         mov     comand.cmhlp,dx         ; save the help message
  476.         mov     cx,0                    ; init the char count
  477.         cmp     comand.cmblen,0         ; length of user's buffer given?
  478.         jne     cmtxt0                  ; ne = yes
  479.         mov     comand.cmblen,127       ; else set 127 byte limit plus null
  480. cmtxt0: mov     comand.cmsflg,0ffh      ; skip initial spaces
  481.         cmp     comand.cmwhite,0        ; allow leading whitespace?
  482.         je      cmtxt1a                 ; e = no
  483. cmtxt1: mov     comand.cmsflg,0         ; get all spaces
  484. cmtxt1a:call    cmgtch                  ; get a char
  485.         jnc     cmtxt5                  ; nc = non-terminator, put in buffer
  486.         cmp     ah,' '                  ; space?
  487.         je      cmtxt5                  ; e = yes, record it
  488.         cmp     ah,escape               ; escape?
  489.         jne     cmtxt2                  ; ne = no
  490.         call    esceoc                  ; do normal escape end-of-command
  491.         jmp     cmtxt0                  ; try again
  492.  
  493. cmtxt2: cmp     ah,'?'                  ; asking a question?
  494.         je      cmtxt3                  ; e = yes
  495.         cmp     ah,cr                   ; formal carriage return?
  496.         je      cmtxt2a                 ; e = yes
  497.         inc     comand.cmrptr           ; accept char into buffer
  498.         jmp     cmtxt5                  ;  and record the char
  499. cmtxt2a:mov     ah,cl                   ; return count in AH
  500.         mov     bx,comand.cmptab        ; return updated pointer
  501.         mov     byte ptr[bx],0          ; put terminator into the buffer
  502.         mov     comand.cmwhite,0        ; clear leading whitespace flag
  503.         mov     comand.cmper,0          ; reset to variable recognition
  504.         mov     comand.cmblen,0         ; set user buffer length to unknown
  505.         mov     comand.cmkeep,0
  506.         jmp     rskp
  507.                                         ; Help processor
  508. cmtxt3: inc     comand.cmrptr           ; count the ?
  509.         cmp     cx,0                    ; Is "?" first char?
  510.         jne     cmtxt5                  ; ne = no, just add to buffer
  511.         dec     comand.cmrptr
  512.         mov     comand.cmsiz,0          ; no keyword for help
  513.         mov     comand.cmwhite,0        ; clear leading whitespace flag
  514.         cmp     comand.cmhlp,0          ; external help given?
  515.         jne     cmtxt3a                 ; ne = yes
  516. ;---------------------- Sept.20,1990 [zqf]
  517. ;        mov     comand.cmhlp,offset cmin00 ; confirm with c/r msg
  518.         push    dx
  519.         mcmsg   cmin00,ccmin00
  520.         mov     comand.cmhlp,dx
  521.         pop     dx
  522. ;---------------------- 
  523.         mov     comand.cmblen,0         ; set user buf length to unknown
  524. cmtxt3a:jmp     cmkyhlp                 ; do help process
  525.  
  526. cmtxt5: inc     cx                      ; increment the count
  527.         mov     bx,comand.cmptab        ; pointer into destination array
  528.         mov     [bx],ah                 ; put char into the buffer
  529.         inc     bx
  530.         mov     al,0
  531.         mov     [bx],al                 ; insert null terminator
  532.         mov     comand.cmptab,bx
  533.         cmp     ch,0                    ; overflowed into high byte?
  534.         jne     cmtxt6                  ; ne = yes
  535.         cmp     cl,comand.cmblen        ; buffer filled?
  536.         ja      cmtxt6                  ; a = yes, declare error
  537.         jb      cmtxt5a                 ; a = not filled yet
  538.         mov     ah,conout               ; notify user that the buffer is full
  539.         mov     dl,bell
  540.         int     dos
  541. cmtxt5a:jmp     cmtxt1
  542. cmtxt6: mov     ah,prstr
  543. ;        mov     dx,offset cmer09
  544.         mcmsg   cmer09,ccmer09
  545.  
  546.         int     dos
  547.         jmp     prserr                  ; declare parse error
  548. cmtext  endp
  549.  
  550.  
  551. ; Parse arbitrary text up to whitespace.  Enter with DX pointing to output
  552. ; buffer and BX pointing to help text. Produces asciiz string. Return updated
  553. ; pointer in DX and input size in AH. Skips leading whitespace unless
  554. ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit.
  555.  
  556. cmfil0  proc    near
  557.         mov     comand.cmptab,dx        ; save pointer to data buffer
  558.         mov     comand.cmhlp,bx         ; save the help message
  559.         mov     comand.cmsiz,0          ; init the char count
  560. cmfil0a:cmp     comand.cmwhite,0        ; allow leading whitespace?
  561.         jne     cmfil1                  ; ne = yes
  562.         mov     comand.cmsflg,0ffh      ; omit leading space
  563. cmfil1: call    cmgtch                  ; get a char
  564.         jc      cmfi1a                  ; c = terminator
  565.         jmp     cmfil5                  ; put char into the buffer
  566. cmfi1a: cmp     ah,escape               ; escape?
  567.         je      cmfi1b                  ; e = yes
  568.         jmp     cmfil2                  ; process other terminators
  569.  
  570. cmfi1b: call    esceoc                  ; do normal escape end-of-command
  571.         jmp     cmfil0a                 ; try again
  572. cmfil2: cmp     ah,'?'                  ; asking a question?
  573.         je      cmfil3                  ; e = yes
  574.         xchg    dx,bx                   ; re-interchange bx and dx
  575.         mov     comand.cmwhite,0        ; clear whitespace flag
  576.         mov     comand.cmper,0          ; reset to variable recognition
  577.         mov     comand.cmkeep,0
  578.         mov     bx,comand.cmptab        ; pointer into destination array
  579.         mov     byte ptr[bx],0          ; put null terminator into the buffer
  580.         inc     bx
  581.         mov     ah,byte ptr comand.cmsiz ; return count in AH
  582.         mov     dx,comand.cmptab        ; return updated pointer
  583.         xchg    dx,bx                   ; re-interchange bx and dx
  584.         mov     comand.cmwhite,0        ; clear whitespace flag
  585.         mov     comand.cmper,0          ; reset to variable recognition
  586.         mov     comand.cmkeep,0
  587.         jmp     rskp                    ; return success
  588.  
  589. cmfil3: inc     comand.cmrptr           ; count the ?
  590.         cmp     comand.cmsiz,0          ; Is "?" first char?
  591.         jne     cmfil5                  ; ne = no, just add to buffer
  592.         dec     comand.cmrptr
  593.         mov     comand.cmsiz,0
  594.         cmp     comand.cmhlp,0          ; external help given?
  595.         jne     cmfil3a                 ; ne = yes
  596. ; ------------------------Sept.20,1990 [zqf]
  597. ;        mov     comand.cmhlp,offset cmin00 ; confirm with c/r msg
  598.         push    dx
  599.         mcmsg   cmin00,ccmin00
  600.         mov     comand.cmhlp,dx
  601.         pop     dx
  602. ; ------------------------
  603. cmfil3a:jmp     cmkyhlp                 ; do help process
  604.  
  605. cmfil5: inc     comand.cmsiz            ; inrement the count
  606.         mov     bx,comand.cmptab        ; pointer into destination array
  607.         mov     [bx],ah                 ; put char into the buffer
  608.         inc     bx
  609.         mov     comand.cmptab,bx
  610.         jmp     cmfil1                  ; the end of cmfil0
  611. cmfil0  endp
  612.  
  613. ; This routine gets a confirm (CR) and displays any extra non-blank text.
  614. ; errflag non-zero means suppress "extra text" display in this routine
  615. ; because another routine is handling errors.
  616. cmcfrm  proc    near
  617.         mov     comand.cmper,1          ; do not react to \%x substitutions
  618. cmcfr1: mov     comand.cmsflg,0ffh      ; set space-seen flag (skip spaces)
  619.         call    cmgtch                  ; get a char
  620.         push    comand.cmrptr
  621.         pop     temp                    ; remember first non-space position
  622.         jc      cmcfr4                  ; c = terminator
  623.         dec     temp                    ; backup to text char
  624. cmcfr3: mov     comand.cmsflg,0ffh      ; set space-seen flag (skip spaces)
  625.         call    cmgtch
  626.         jnc     cmcfr3                  ; read until terminator
  627. cmcfr4: cmp     ah,' '
  628.         je      cmcfr3                  ; ignore ending on space
  629.         cmp     ah,escape               ; escape?
  630.         jne     cmcfr5                  ; ne = no
  631.         call    esceoc                  ; do standard end of cmd on escape
  632.         mov     ax,comand.cmrptr
  633.         cmp     ax,temp                 ; started text yet?
  634.         je      cmcfr1                  ; e = no
  635.         jmp     short cmcfr3            ; try again
  636. cmcfr5: cmp     ah,'?'                  ; curious?
  637.         jne     cmcfr6                  ; ne = no
  638. ;---------------------- Sept.20,1990 [zqf]
  639. ;        mov     comand.cmhlp,offset cmin00 ; msg Confirm with c/r
  640.         push    dx
  641.         mcmsg   cmin00,ccmin00
  642.         mov     comand.cmhlp,dx
  643.         pop     dx
  644. ;----------------------
  645.         mov     comand.cmsiz,0          ; no keyword
  646.         mov     errflag,0
  647.         jmp     cmkyhlp                 ; do help
  648. cmcfr6: cmp     ah,cr                   ; the confirmation char?
  649.         jne     cmcfr3                  ; ne = no
  650.         cmp     errflag,0               ; already doing one error?
  651.         jne     cmcfr7                  ; ne = yes, skip this one
  652.         mov     cx,comand.cmrptr        ; pointer to terminator
  653.         mov     dx,temp                 ; starting place
  654.         sub     cx,dx                   ; end minus starting point = length
  655.         cmp     cx,0                    ; string present?
  656.         jle     cmcfr7                  ; le = nothing to display
  657.         push    dx                      ; save source pointer
  658.         mov     ah,prstr
  659. ;        mov     dx,offset cmer07        ; ?Ignoring extras
  660.         mcmsg   cmer07,ccmer07
  661.  
  662.         int     dos
  663.         pop     dx
  664.         mov     bx,1                    ; stdout handle, cx=count, dx=src ptr
  665.         mov     ah,write2               ; allow embedded dollar signs
  666.         int     dos
  667.         mov     ah,prstr
  668.         mov     dx,offset cmer08        ; trailer msg
  669.         int     dos
  670. cmcfr7: mov     errflag,0
  671.         mov     comand.cmper,0          ; reset to variable recognition
  672.         mov     comand.cmkeep,0
  673.         jmp     rskp                    ; return confirmed
  674. cmcfrm  endp
  675.  
  676. ;;; Routines to get and edit incoming text.
  677.  
  678. ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
  679. ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
  680. ; then treat '\%' as literal characters. If no matching parameter exists
  681. ; just remove '\%x'. Returns carry clear if nothing done, else carry set and
  682. ; new text already placed in user's buffer. comand.cmwptr and comand.cmcnt
  683. ; are updated. Uses depth-first recursion algorithm. All registers preserved.
  684. subst   proc    near
  685.         cmp     comand.cmper,0          ; should we recognize '\%'?
  686.         jne     subst2                  ; ne = no, treat as literals
  687.         cmp     ah,'\'                  ; is it the first char of the pattern?
  688.         jne     subst1                  ; ne = no, try next
  689.         mov     subcnt,1                ; say first is matched
  690.         jmp     short subst2            ; exit successfully
  691. subst1: cmp     subcnt,1                ; first char matched already?
  692.         ja      subst3                  ; a = first two have been matched
  693.         jb      subst2                  ; b = none yet
  694.         inc     subcnt                  ; assume a match follows
  695.         cmp     ah,'%'                  ; second match char, same?
  696.         je      subst2                  ; e = yes
  697.         mov     subcnt,0                ; mismatch, clear match counter
  698. subst2: clc                             ; carry clear = no substitution done
  699.         ret
  700. subst3: mov     subcnt,0                ; clear match counter
  701.         cmp     ah,'0'                  ; third char is '0' or above?
  702.         jb      subst2                  ; b = out of range, no match
  703.         push    bx                      ; save working regs
  704.         push    cx
  705.         sub     comand.cmrptr,3         ; reread commands where backslash was
  706.         call    bufreset                ; reset buffer to this point
  707.         push    comand.cmptab           ; save current keyword parsing parms
  708.         push    comand.cmsptr
  709.         push    comand.cmsiz
  710.         mov     bx,comand.cmrptr        ; points at backslash
  711.         mov     comand.cmsptr,bx        ; direct keyword routine to it
  712.         mov     comand.cmsiz,3          ; three bytes (\%x) of user text
  713.         mov     comand.cmptab,offset mcctab ; use Macro table for new text
  714.         call    getkw                   ; get ptr, bx, to matching keyword
  715.         pop     comand.cmsiz            ; restore borrowed keyword parameters
  716.         pop     comand.cmsptr
  717.         pop     comand.cmptab
  718.         jc      substx                  ; c = not found, keep after pops
  719.         mov     cl,byte ptr[bx]         ; length of found word
  720.         add     cl,2                    ; plus count field and '$'
  721.         mov     ch,0
  722.         add     bx,cx                   ; point to 16 bit value (string ptr)
  723.         mov     bx,[bx]                 ; point to string structure
  724.         mov     cl,[bx]                 ; length of string (ch=0 from above)
  725.         inc     bx                      ; skip length byte, bx=string address
  726.         jcxz    substx                  ; z = nothing left to transfer
  727.         cld
  728. subst4: mov     ah,[bx]                 ; get a char
  729.         inc     bx
  730.         push    di                      ; assume di is used by other routines
  731.         mov     di,comand.cmrptr
  732.         mov     [di],ah                 ; store char (without es:di)
  733.         inc     di
  734.         mov     comand.cmwptr,di        ; where to store next char
  735.         mov     comand.cmrptr,di        ; move read pointer too
  736.         cmp     di,offset comand.cmdbuf+size cmdbuf ; reached max buffer size?
  737.         pop     di
  738.         jae     subst6                  ; ae = yes, no more room
  739.         cmp     sp,20*2                 ; still some stack space?
  740.         jle     subst6                  ; le = insufficient room
  741.         call    SUBST                   ; rescan what we stored (recursion)
  742.         jnc     subst5                  ; nc = no substitution, so no kbd test
  743.         push    ax                      ; break out of loops with Control-C
  744.         push    dx
  745.         mov     ah,constat              ; check console status for Control-C
  746.         int     dos                     ;  our control-break handler sees it
  747.         pop     dx                      ;  and cmgetc reads it
  748.         pop     ax
  749. subst5: loop    subst4
  750. substx: pop     cx
  751.         pop     bx
  752.         stc                             ; set carry to say have stored chars
  753.         ret
  754. subst6: mov     ah,prstr
  755. ;        mov     dx,offset stkmsg        ; out of work space msg
  756.         mcmsg   stkmsg,cstkmsg
  757.  
  758.         int     dos
  759.         jmp     prserr                  ; and declare parse error
  760. subst   endp
  761.  
  762. ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
  763. ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
  764. ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
  765. ; and indirect stdin files (\; means literal semicolon). Return char in AL.
  766. CMGETC  proc    near                    ; Basic raw character reader
  767.         mov     ah,taklev               ; get current Take level
  768.         mov     intake,ah               ; remember here for later callers
  769. cmget01:cmp     prevch,0                ; left over char yet to be exported?
  770.         je      cmget02                 ; e = no
  771.         mov     al,prevch               ; get old char
  772.         mov     prevch,0                ; clear storage
  773.         jmp     cmget6                  ; analyze it
  774. cmget02:cmp     taklev,0                ; in a Take file?
  775.         jne     cmget1                  ; ne = yes, do Take reader section
  776.         call    isdev                   ; is stdin a device or a file?
  777.         jnc     cmget20                 ; nc = file (redirection of stdin)
  778.         jmp     cmget10                 ; c = device, do separately
  779.  
  780. cmget20:call    iseof                   ; see if file is empty
  781.         jc      cmget21                 ; c = EOF on disk file
  782.         mov     ah,coninq               ; read the char from file, not device
  783.         int     dos
  784.         cmp     al,cr                   ; is it a cr?
  785.         je      cmget01                 ; yes, ignore and read next char
  786.         cmp     al,ctlz                 ; Control-Z?
  787.         je      cmget21                 ; e = yes, same as EOF here
  788.         cmp     al,lf                   ; LF's end lines from disk files
  789.         jne     cmget23                 ; ne = not LF, pass along as is
  790.         mov     al,cr                   ; make LF a CR for this parser
  791.         call    iseof                   ; see if this is the last char in file
  792.         jnc     cmget23                 ; nc = not EOF, process new CR
  793. cmget21:mov     flags.extflg,1          ; EOF on disk file, set exit flag
  794. cmget23:jmp     short cmget6            ; do echoing and return
  795.  
  796. cmget1: push    bx                      ; read from Take file
  797.         mov     bx,takadr
  798.         cmp     [bx].takcnt,0           ; bytes remaining in Take buffer
  799.         jne     cmget4                  ; ne = not empty
  800.         cmp     [bx].taktyp,0feh        ; type of Take (file?)
  801.         jne     cmget3                  ; ne = no (macro)
  802.         call    takrd                   ; read another buffer
  803.         cmp     [bx].takcnt,0           ; anything in the file?
  804.         jne     cmget4                  ; ne = yes
  805. cmget3: pop     bx                      ; clear stack
  806.         jmp     cmget5                  ; close take file
  807.  
  808. cmget4: push    si
  809.         mov     si,[bx].takptr          ; read a char from Take buffer
  810.         cld
  811.         lodsb
  812.         mov     [bx].takptr,si          ; move buffer pointer
  813.         pop     si
  814.         dec     [bx].takcnt             ; decrease number of bytes remaining
  815.         pop     bx
  816.         cmp     al,ctlz                 ; Control-Z?
  817.         jne     cmget6                  ; ne = no
  818. cmget5: cmp     comand.cmkeep,0         ; keep Take/macro open after eof?
  819.         jne     cmget5a                 ; ne = yes
  820.         call    takclos                 ; close take file
  821. cmget5a:mov     al,cr                   ; report cr as last char
  822.         mov     noparse,0               ; and say end of comment
  823.                                         ; start common code
  824. cmget6: cmp     al,lf                   ; line feed?
  825.         jne     cmget8                  ; ne = no
  826.         jmp     cmget01                 ; yes, ignore and read another char
  827.                                         ; handle comments (echo but not parse)
  828. cmget8: cmp     noparse,0               ; parsing?
  829.         jne     cmget9                  ; ne = yes, do echo and no parse
  830.         cmp     prevch,0                ; have previous char to analyze?
  831.         jne     cmget8c                 ; ne = yes
  832.         cmp     al,'\'                  ; start of '\;'?
  833.         jne     cmget8a                 ; ne = no
  834.         mov     prevch,al               ; yes, maybe. save '\' til later
  835.         jmp     cmget02                 ; read next char
  836. cmget8a:cmp     al,';'                  ; possible start of comment?
  837.         jne     cmget8e                 ; no, export al
  838.         mov     al,' '                  ; replace ';' with space for comment
  839.         jmp     cmget9                  ; go start a comment
  840.  
  841. cmget8c:cmp     al,';'                  ; end of '\;'?
  842.         je      cmget8d                 ; e = yes, omit leading backslash
  843.         xchg    prevch,al               ; no, save new, recover old '\'
  844.         jmp     short cmget8e           ; export '\'
  845. cmget8d:mov     prevch,0                ; clear old '\'
  846. cmget8e:jmp     cmget12                 ; do parsing
  847.         mov     prevch,0                ; clear previous char
  848.         jmp     cmget02                 ; get next char
  849.  
  850.                                         ; echo comment
  851. cmget9: cmp     flags.takflg,0          ; echoing take files?
  852.         je      cmget9a                 ; e = no
  853.         push    ax
  854.         push    dx
  855.         mov     ah,conout               ; echo current char
  856.         mov     dl,al
  857.         int     dos
  858.         pop     dx
  859.         pop     ax
  860. cmget9a:mov     noparse,0               ; cr ends comment
  861.         cmp     al,cr                   ; end of comment?
  862.         je      cmget13                 ; e = yes, export cr
  863.         mov     noparse,1               ; still in comment
  864.         jmp     cmget01                 ; read more chars
  865.  
  866.                                         ; read from tty device
  867. cmget10:mov     ah,coninq               ; Get a char from device, not file
  868.         int     dos                     ;  with no echoing
  869.         or      al,al
  870.         jnz     cmget12                 ; ignore null bytes of special keys
  871.         int     dos                     ; read and discard scan code byte
  872.         jmp     cmget10                 ; try again
  873.  
  874. cmget12:cmp     al,'C'and 1Fh           ; Control-C?
  875.         je      cmget14                 ; e = yes
  876.         cmp     al,TAB                  ; tab is replaced by space
  877.         jne     cmget13                 ; ne = not tab
  878.         mov     al,' '
  879. cmget13:ret                             ; normal exit, char is in AL
  880.  
  881. cmget14:mov     ah,prstr                ; Control-C handler
  882.         push    dx
  883.         mov     dx,offset ctcmsg        ; show Control-C
  884.         int     dos
  885.         pop     dx
  886.         mov     prevch,0
  887.         mov     flags.cxzflg,'C'        ; tell others the news
  888.         mov     sp,cmdstk               ; restore command entry stack pointer
  889.         ret                             ;  and fail immediately (a longjmp)
  890. cmgetc  endp
  891.  
  892. ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
  893. ; comand.cmbuf. Set read pointer comand.cmrptr to next free buffer byte if
  894. ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
  895. ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
  896. ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
  897. ; Return char in AH.
  898. CMINBF  proc    near                    ; Buffer reader, final editor
  899.         push    di
  900.         mov     di,comand.cmwptr
  901.         cmp     di,offset comand.cmdbuf+size cmdbuf-3 ; max buffer size - 3
  902.         pop     di
  903.         jb      cminb1                  ; b = not full
  904.         mov     ah,conout               ; almost full, notify user
  905.         push    dx
  906.         mov     dl,bell
  907.         int     dos
  908.         mov     dx,offset comand.cmdbuf+size cmdbuf
  909.         cmp     comand.cmrptr,dx        ; max buffer size?
  910.         pop     dx
  911.         jb      cminb1                  ; b = more room
  912.         mov     ah,prstr
  913.         push    dx
  914. ;        mov     dx,offset cmer09        ; command too long
  915.         mcmsg   cmer09,ccmer09
  916.         int     dos
  917.         pop     dx
  918.         jmp     prserr                  ; overflow = parse error
  919.  
  920. cminb1: push    bx
  921.         mov     bx,comand.cmrptr
  922.         mov     ah,[bx]                 ; get current command char while here
  923.         cmp     bx,comand.cmwptr        ; do we need to read more?
  924.         pop     bx                      ; no if cmrptr < cmwptr
  925.         jb      cminb2                  ; b: cmrptr < cmwptr (have extra here)
  926.         call    cmgetc                  ; no readahead, read another into al
  927.         mov     ah,al                   ; keep char in 'ah'
  928.         push    bx
  929.         mov     bx,comand.cmwptr        ; Get the pointer into the buffer
  930.         mov     [bx],ah                 ; Put it in the buffer
  931.         inc     bx
  932.         mov     comand.cmwptr,bx        ; inc write pointer
  933.         pop     bx
  934.                                         ; Char to be delivered is in ah
  935. cminb2: cmp     ah,'W' and 1fh          ; Is it a ^W?
  936.         jne     cminb3
  937.         call    cntrlw                  ; Kill the previous word
  938.         jnc     cminbf                  ; nc = no change, get another char
  939.         jmp     repars                  ; need a new command scan (cleans stk)
  940.  
  941. cminb3: cmp     ah,'U' and 1fh          ; Is it a ^U?
  942.         jne     cminb3a                 ; ne = no
  943.         mov     comand.cmwptr,offset comand.cmdbuf ;reset buffer write pointer
  944.         jmp     repars                  ; Go start over (cleans stack)
  945.                                         ; BS and DEL
  946. cminb3a:cmp     ah,DEL                  ; Delete code?
  947.         je      cminb3b                 ; e = yes
  948.         cmp     ah,BS                   ; Backspace (a delete operator)?
  949.         jne     cminb4                  ; ne = no
  950. cminb3b:call    bufdel                  ; delete char from buffer
  951.         jc      cminb3c                 ; c = did erasure
  952.         jmp     cminbf                  ; no erasure, ignore BS, get more
  953. cminb3c:jmp     repars                  ; could have deleted previous token
  954.  
  955. cminb4: push    bx                      ; look for hyphen or \hyphen
  956.         cmp     ah,cr                   ; check for hyphen line continuation
  957.         jne     cminb4b                 ; ne = not end of line
  958.         mov     bx,comand.cmwptr        ; Get the pointer into the buffer
  959.         cmp     bx,offset comand.cmdbuf-2 ; do we have a previous char?
  960.         jb      cminb4b                 ; b = no
  961.         cmp     byte ptr[bx-2],'-'      ; previous char was a hyphen?
  962.         jne     cminb4b                 ; ne = no
  963.         pop     bx
  964.         call    bufdel                  ; delete the hyphen
  965.         jmp     repars
  966. cminb4b:pop     bx
  967.                                         ; Echoing done here
  968.         cmp     comand.cmquiet,0        ; quiet mode?
  969.         jne     cminb5                  ; yes, skip echoing
  970.         cmp     taklev,0                ; in a take file?
  971.         je      cminb4a                 ; e = no
  972.         cmp     flags.takflg,0          ; echo take file?
  973.         je      cminb5                  ; e = no
  974. cminb4a:push    ax                      ; save the char
  975.         cmp     ah,' '                  ; printable?
  976.         jae     cminb4c                 ; yes, no translation needed
  977.         cmp     ah,cr                   ; this is printable
  978.         je      cminb4c
  979.         cmp     ah,lf
  980.         je      cminb4c
  981.         cmp     ah,escape               ; escape?
  982.         je      cminb4d                 ; do not echo this character
  983.         push    ax                      ; show controls as caret char
  984.         push    dx
  985.         mov     dl,5eh                  ; caret
  986.         mov     ah,conout
  987.         int     dos
  988.         pop     dx
  989.         pop     ax
  990.         add     ah,'A'-1                ; make control code printable
  991. cminb4c:push    dx
  992.         mov     dl,ah
  993.         mov     ah,conout
  994.         int     dos                     ; echo it ourselves
  995.         pop     dx
  996. cminb4d:pop     ax                      ; and return char in ah
  997.  
  998. cminb5: cmp     ah,cr                   ; Is it a carriage return?
  999.         je      cminb6
  1000.         cmp     ah,lf                   ; Is it a line feed?
  1001.         je      cminb6
  1002.         cmp     ah,ff                   ; Is it a formfeed?
  1003.         jne     cminb7                  ; none of the above, report bare char
  1004.         call    cmblnk                  ; FF: clear the screen and
  1005.         push    bx
  1006.         push    cx
  1007.         push    dx
  1008.         call    locate                  ; Home the cursor
  1009.         mov     bx,comand.cmwptr        ; make the FF parse like a cr
  1010.         mov     byte ptr [bx-1],cr      ; pretend a carriage return were typed
  1011.         pop     dx
  1012.         pop     cx
  1013.         pop     bx
  1014. cminb6: cmp     comand.cmwptr,offset comand.cmdbuf ; parsed any chars yet?
  1015.         jne     cminb7                  ; ne = yes
  1016.         cmp     comand.cmcr,0           ; bare cr's allowed?
  1017.         jne     cminb7                  ; ne = yes
  1018.         jmp     prserr                  ; If not, just start over
  1019. cminb7: clc
  1020.         ret
  1021. cminbf  endp
  1022.  
  1023. ; Read chars from cminbf. Comand.cmrptr points to next char to be read.
  1024. ; Compresses repeated spaces if comand.cmsflg is non-zero. Exit with
  1025. ; comand.cmrptr pointing at a terminator or otherwise at next free slot.
  1026. ; Non-space then space acts as a terminator but comand.cmrptr is incremented.
  1027. ; Substitution variables, '\%x', are detected and expanded. Return char in AH.
  1028.  
  1029. CMGTCH  proc    near                    ; return char in AH, from rescan buf
  1030.         call    cminbf                  ; get char from buffer or user
  1031.         push    bx
  1032.         mov     bx,comand.cmrptr        ; get read pointer into the buffer
  1033.         mov     ah,[bx]                 ; read the next char
  1034.         inc     bx
  1035.         mov     comand.cmrptr,bx        ; where to read next time
  1036.         pop     bx
  1037.         call    subst                   ; examine for text substitution
  1038.         jnc     cmgtc1                  ; nc = no substitutions done
  1039.         jmp     repars                  ; reparse line with new material
  1040.  
  1041. cmgtc1: cmp     ah,' '                  ; Is it a space?
  1042.         jne     cmgtc3                  ; ne = no
  1043. cmgtc2: cmp     comand.cmsflg,0         ; space flag, was last char a space?
  1044.         jne     cmgtch                  ; ne = yes, get another char
  1045.         mov     comand.cmsflg,0FFH      ; Set the space(s)-seen flag
  1046.         mov     ah,' '                  ; character for caller
  1047.         stc                             ; set carry for terminator
  1048.         ret                             ; return space as a terminator
  1049. cmgtc3: mov     comand.cmsflg,0         ; clear the space-seen flag
  1050.         cmp     ah,escape               ; terminators remain in buffer but
  1051.         je      cmgtc4                  ;  are ready to be overwritten
  1052.         cmp     ah,'?'                  ; Is the user curious?
  1053.         jne     cmgtc3a                 ; ne = no
  1054.         cmp     taklev,0                ; in a Take file?
  1055.         jne     cmgtc3b                 ; ne = yes, make query ordinary char
  1056.         je      cmgtc4
  1057. cmgtc3a:cmp     ah,cr
  1058.         je      cmgtc4
  1059.         cmp     ah,lf
  1060.         je      cmgtc4
  1061.         cmp     ah,ff
  1062.         je      cmgtc4
  1063. cmgtc3b:clc                             ; carry clear for non-terminator
  1064.         ret
  1065. cmgtc4: dec     comand.cmrptr           ; point at terminating char
  1066.         stc                             ; set carry to say it is a terminator
  1067.         ret
  1068. cmgtch  endp
  1069.  
  1070. ; Reset comand.cmdbuf write pointer (.cmwptr) to where the read pointer
  1071. ; (.cmrptr) is now. Discards material not yet read.
  1072. bufreset proc   near
  1073.         push    comand.cmrptr           ; where next visible char is read
  1074.         pop     comand.cmwptr           ; where new char goes in buffer
  1075.         ret
  1076. bufreset endp
  1077.  
  1078. ; Delete character from screen and adjust buffer. Returns carry clear if
  1079. ; no erasure, carry set otherwise.
  1080. bufdel  proc    near
  1081.         dec     comand.cmrptr           ; remove previous char from buffer
  1082.         cmp     comand.cmrptr,offset comand.cmdbuf ; back too far?
  1083.         jae     bufde2                  ; ae = no, material can be erased
  1084.         mov     comand.cmrptr,offset comand.cmdbuf ; set to start of buffer
  1085.         call    bufreset                ; reset buffer
  1086.         clc                             ; say no erasure
  1087.         ret
  1088. bufde2: call    bufreset                ; reset buffer
  1089.         stc                             ; say did erasure
  1090.         ret
  1091. bufdel  endp
  1092.  
  1093. ; Come here is user types ^W when during input. Remove word from buffer.
  1094. cntrlw  proc    near
  1095.         push    ax
  1096.         push    cx
  1097.         push    dx
  1098.         mov     cx,comand.cmrptr        ; char beyond what user sees
  1099.         mov     comand.cmwptr,cx        ; truncate buffer there
  1100.         sub     cx,offset comand.cmdbuf ; compute chars in buffer
  1101.         clc                             ; say have not yet modified line
  1102.         jcxz    ctlw2                   ; z = nothing to do, exit no-carry
  1103.         push    es
  1104.         std                             ; scan backward
  1105.         mov     ax,ds
  1106.         mov     es,ax                   ; point to the data are
  1107.         mov     di,comand.cmwptr        ; looking from here
  1108.         dec     di
  1109.         mov     al,' '
  1110.         repe    scasb                   ; look for non-space
  1111.         je      ctlw1                   ; all spaces, nothing to do
  1112.         inc     di                      ; move back to non-space
  1113.         inc     cx
  1114.         repne   scasb                   ; look for a space
  1115.         jne     ctlw1                   ; no space, leave ptrs alone
  1116.         inc     di
  1117.         inc     cx                      ; skip back over space
  1118. ctlw1:  inc     di
  1119.         pop     es
  1120.         cld                             ; reset direction flag
  1121.         mov     comand.cmwptr,di        ; update pointer
  1122.         stc                             ; set carry to say modified line
  1123. ctlw2:  pop     dx
  1124.         pop     cx
  1125.         pop     ax
  1126.         ret
  1127. cntrlw  endp
  1128.  
  1129. ; Jump to REPARS to do a rescan of the existing buffer.
  1130. ; Jump to PRSERR on a parsing error (quits command, clears old read material)
  1131.  
  1132. PRSERR  PROC NEAR
  1133.         mov     comand.cmwptr,offset comand.cmdbuf ; initialize write pointer
  1134.         mov     ah,prstr
  1135.         mov     dx,offset crlf          ; leave old line, start a new one
  1136.         int     dos
  1137.                                         ; reparse current line
  1138. REPARS: mov     comand.cmrptr,offset comand.cmdbuf ; reinit read pointer
  1139.         mov     comand.cmper,0          ; reset to variable recognition
  1140.         mov     comand.cmsflg,0FFH      ; strip leading spaces
  1141.         cmp     taklev,0                ; in Take cmd?
  1142.         je      prser2                  ; e = no
  1143.         cmp     flags.takflg,0          ; echo contents of Take file?
  1144.         je      prser3                  ; e = no
  1145. prser2: call    ctlu                    ; clear display's line, reuse it
  1146.         mov     ah,prstr
  1147.         mov     dx,comand.cmprmp        ; display the prompt
  1148.         int     dos
  1149. prser3: mov     bx,0ffffh               ; returned keyword value
  1150.         mov     sp,comand.cmostp        ; set new sp to old one
  1151.         jmp     comand.cmrprs           ; jump to just before the prompt call
  1152. PRSERR  ENDP
  1153.  
  1154. ; This routine prints the prompt and specifies the reparse address.
  1155. ; Enter with pointer to prompt string in dx.
  1156. PROMPT  PROC  NEAR
  1157.         mov     comand.cmprmp,dx        ; save the prompt
  1158.         pop     ax                      ; Get the return address
  1159.         mov     comand.cmrprs,ax        ; Save as address to go to on reparse
  1160.         mov     comand.cmostp,sp        ; Save for later restoration
  1161.         push    ax                      ; Put it on the stack again
  1162.         mov     ax,offset comand.cmdbuf
  1163.         mov     comand.cmwptr,ax        ; reset buffer read/write pointers
  1164.         mov     comand.cmrptr,ax
  1165.         mov     ax,0
  1166.         mov     comand.cmper,0          ; allow substitutions
  1167.         mov     comand.cmsflg,0FFH      ; remove leading spaces
  1168.         cmp     flags.takflg,0          ; look at Take flag
  1169.         jne     promp1                  ; ne=supposed to echo, skip this check
  1170.         cmp     taklev,0                ; inside a take file?
  1171.         je      promp1                  ; no, keep going
  1172.         ret                             ; yes, return
  1173. promp1: mov     ah,prstr
  1174.         mov     dx,offset crlf
  1175.         int     dos
  1176.         mov     ah,prstr                ; display the prompt
  1177.         mov     dx,comand.cmprmp
  1178.         int     dos
  1179.         ret
  1180. PROMPT  ENDP
  1181.  
  1182. ISDEV   PROC    NEAR                    ; Set carry if STDIN is non-disk
  1183.         push    ax
  1184.         push    bx
  1185.         push    dx
  1186.         mov     al,0                    ; get device info
  1187.         mov     ah,ioctl
  1188.         mov     bx,0                    ; handle 0 is stdin
  1189.         int     dos
  1190.         and     dl,80h                  ; bit set if handle is for a device
  1191.         rcl     dl,1                    ; put it into the carry bit
  1192.         pop     dx
  1193.         pop     bx
  1194.         pop     ax
  1195.         ret                             ; carry set if device
  1196. ISDEV   ENDP
  1197.  
  1198. ISEOF   PROC    NEAR                    ; Set carry if STDIN is at EOF
  1199.         push    ax                      ;  but only if stdin is a non-device
  1200.         push    bx
  1201.         push    dx
  1202.         mov     al,0                    ; get device info
  1203.         mov     ah,ioctl
  1204.         mov     bx,0                    ; handle 0 is stdin
  1205.         int     dos
  1206.         test    dl,80h                  ; bit set if handle is for a device
  1207.         mov     ah,ioctl
  1208.         mov     al,6                    ; get handle input status, set al
  1209.         jnz     iseof1                  ; nz = device, always ready (al != 0)
  1210.         int     dos
  1211. iseof1: or      al,al                   ; EOF?
  1212.         pop     dx
  1213.         pop     bx
  1214.         pop     ax
  1215.         jnz     iseof2                  ; nz = no
  1216.         stc                             ; set carry for eof
  1217.         ret
  1218. iseof2: clc                             ; clear carry for not-eof
  1219.         ret
  1220. ISEOF   ENDP
  1221. ; Convert ascii characters in al and ah to lowercase. [jrd]
  1222. ; All registers are preserved except AX, of course.
  1223.  
  1224. TOLOWR PROC NEAR
  1225.         cmp     ah,'A'                  ; less that cap A?
  1226.         jl      tolow1                  ; l = yes. leave untouched
  1227.         cmp     ah,'Z'+1                ; more than cap Z?
  1228.         jns     tolow1                  ; ns = yes
  1229.         or      ah,20H                  ; convert to lowercase
  1230. tolow1: cmp     al,'A'                  ; less that cap A?
  1231.         jl      tolow2                  ; l = yes. leave untouched
  1232.         cmp     al,'Z'+1                ; more than cap Z?
  1233.         jns     tolow2                  ; ns = yes
  1234.         or      al,20H                  ; convert to lowercase
  1235. tolow2: ret
  1236. TOLOWR  endp
  1237.  
  1238. ; Jumping to this location is like retskp.  It assumes the instruction
  1239. ;   after the call is a jmp addr.
  1240.  
  1241. RSKP    PROC    NEAR
  1242.         pop     bp
  1243.         add     bp,3
  1244.         push    bp
  1245.         ret
  1246. RSKP    ENDP
  1247.  
  1248. ; Jumping here is the same as a ret.
  1249.  
  1250. R       PROC    NEAR
  1251.         ret
  1252. R       ENDP
  1253.  
  1254. code    ends
  1255.         end
  1256.