; File MSSCMD.ASM
; Edit history:
; [2.29] [jrd]
; [2.28 jrd]
; Fix filename error, under cmif7x, which possibly corrupts some filenames.
; Replace cmifi with cmfile for full path name support.
; Joe R. Doupnik  4 Oct 1985
; Add procedure tolowr and use it to allow mixed case keywords.
; Fix bug of single char keywords causing unbounded help display.
; Joe R. Doupnik 27 Dec 1985.
; [v2.28]
; Fixed up '?' a bit - don't jump into next field before seeing
; a separator at the end of a keyword.
; JD 15 May 1985

        public comnd, cmcfrm, prserr, repars, cmgtch, comand
        public cmgetc
        include mssdef.h

datas   segment public 'datas'
        extrn   flags:byte, trans:byte
        extrn   taklev:byte, takadr:word, dosnum:byte

comand  cmdinfo <>
cmer00  db      cr,lf,'?Program error   Invalid COMND call$'
cmer01  db      cr,lf,'?Ambiguous$'
cmer03  db      cr,lf,'?Invalid command$'                ; [19e]
cmer04  db      cr,lf,'?Invalid command or operand$'     ; [1]
cmin00  db      ' Confirm with carriage return$'
cmin01  db      ' One of the following:',cr,lf,'$'

cmthlp  dw      0               ; Text of help message for random input.
crlf    db      cr,lf,'$'
ctcmsg  db      '^C$'
prsp    db      ' $'                    ; Print a space.
hlpmsg  dw      0                       ; Address of help message.
escspc  db      BS,' ',BS,'$'           ; Clear escape.
clrspc  db      ' ',BS,'$'              ; Clear space.
tbuff   db      80  DUP(?)
temp    db      ?                       ; temp (counts char/line so far)
cmdstk  dw      ?
datas   ends

code    segment public
        extrn   dodel:near, ctlu:near, cmblnk:near, locate:near, takrd:near
        extrn   clearl:near
        assume  cs:code,ds:datas,es:datas

;       This routine parses the specified function in AH. Any additional
;       information is in DX and BX.
;       Returns +1 on success
;               +4 on failure (assumes a JMP follows the call)

CMND    PROC NEAR
comnd:  mov comand.cmstat,ah    ; Save what we are presently parsing.
        mov cmdstk,sp           ; save stack ptr locally.
        call cminbf             ; Get chars until an action or a erase char.
        mov ah,comand.cmstat    ; Restore 'ah' for upcoming checks.
        cmp ah,cmcfm            ; Parse a confirm?
        jz cmcfrm               ; Go get one.
        cmp ah,cmkey            ; Parse a keyword?
        jnz cm3
        jmp cmkeyw               ; Try and get one.
cm3:    cmp ah,cmtxt            ; Parse arbitrary text.   [8]
        jnz cm4
        jmp cmtext
cm4:    cmp ah,cmfile           ; parse text surrounded by whitespace [jrd]
        jnz cm5
        jmp cmfil0
cm5:    mov ah,prstr            ; Else give error. [jrd]
        mov dx,offset cmer00    ; "?Unrecognized COMND call"
        int dos
        ret

; This routine gets a confirm.

cmcfrm: call cmgtch             ; Get a char.
        cmp ah,0                ; Is it negative (a terminator; a space or
                                ; a tab will not be returned here as they
                                ; will be seen as leading white space.)
        js cmcfr0
        mov comand.cmstat,cmcfm-1 ; make sure status isn't = cmcfm
        ret                     ; If not, return failure.
cmcfr0: and ah,7FH                      ; Turn off the minus bit.
        cmp ah,esc                      ; Is it an escape?
        jne cmcfr2
        mov ah,conout
        mov dl,bell             ; Get a bell.
        int dos
        mov comand.cmaflg,0     ; Turn off the action flag.
        mov bx,comand.cmcptr    ; Move the pointer to before thee scape.
        dec bx
        mov comand.cmcptr,bx
        mov comand.cmdptr,bx
        dec comand.cmccnt       ; Decremrnt the char count.
        jmp cmcfrm              ; Try again.
cmcfr2: cmp ah,'?'              ; Curious?
        jne cmcfr3
        mov ah,prstr            ; Print something useful.
        mov dx,offset cmin00
        int dos
        mov ah,prstr
        mov dx,offset crlf      ; Print a crlf.
        int dos
        mov ah,prstr
        mov dx,comand.cmprmp    ; Reprint the prompt.
        int dos
        mov bx,comand.cmdptr    ; Get the pointer into the buffer.
        mov ah,'$'              ; Put a $ there for printing.
        mov [bx],ah
        mov bx,comand.cmcptr
        dec bx                  ; Decrement & save the buffer pointer.
        mov comand.cmcptr,bx
        mov ah,prstr
        mov dx,offset comand.cmdbuf
        int dos
        mov ah,0                        ; Turn off the action flag.
        mov comand.cmaflg,ah
        jmp repars              ; Reparse everything.

cmcfr3: cmp ah,ff                       ; Is it a form feed?
        jne cmcfr4
        call cmblnk             ; If so blank the screen.
cmcfr4: jmp rskp

;       This routine parses a keyword from the table pointed
;       to in DX.  The format of the table is as follows:
;
;       addr:   db      n       ; Where n is the # of entries in the table.
;               db      m       ; M is the size of the keyword.
;               db      'string$' ; Where string is the keyword.
;               dw      ab      ; Where ab is data to be returned.
;
;       The keywords must be in alphabetical order,
;       but they may be of mixed case. [jrd]

cmkeyw: mov comand.cmhlp,bx     ; Save the help.
        mov comand.cmptab,dx    ; Save the beginning of keyword table.
        mov bx,dx
        mov ch,[bx]             ; Get number of entries in table.
        inc bx
        mov dx,comand.cmdptr    ; Save command pointer.
        mov comand.cmsptr,dx    ; Save pointer's here.
cmky1:  cmp ch,0                ; Any commands left to check?
        jne cmky2
        jmp cmky41              ; no, go complain
cmky2:  dec ch
        mov cl,0                ; Keep track of how many chars read in so far.
        call cmgtch             ; Get a char from the user. [jrd]
        cmp ah,0                ; Do we have a terminator?
        jns cmky2x              ; ns = no. [jrd]
        jmp cmky4               ; Negative number means we do.
cmky2x: inc bx                  ; Point to first letter of keyword.
        inc cl                  ; count the user's char. [jrd]
        mov al,[bx]
        call tolowr             ; convert al (key) and ah (user) [jrd]
        cmp ah,al               ; do they match? [jrd]
        je cmky3                ; e = yes. [jrd]
        jg cmky2y               ; g = keychar < user's (keep looking) [jrd]
        jmp cmky41              ; Fail if ah preceeds al alphabetically.
cmky2y: jmp cmky6               ; Not this keyword - try the next.
cmky3:  inc bx                  ; We match here, how 'bout next char?
        mov al,[bx]
        call tolowr             ; lower case the key word char. [jrd]
        cmp al,'$'               ; End of keyword?
        jne cmky3x              ; ne = not yet. [jrd]
        jmp cmky7                ; Succeed.
cmky3x: mov dl,al               ; Save al's char here.
        call cmgtch
        inc cl                  ; Read in another char.
        mov al,dl
        call tolowr             ; lower case [jrd]
        cmp ah,esc+80H          ; Escape Recognition (escape w/minus bit on)?
        je cmky3y
        cmp ah,' '+80H          ; A space?
        je cmky3y
        cmp ah,cr+80H           ; Carriage return?
        je cmky3y
        cmp ah,'?'+80H          ; A question mark?    [3]
        je cmky3y
        cmp ah,al               ; user = keyword char? [jrd]
        je cmky3                ; e = yes. Check next letter. [jrd]
        jmp cmky6               ; no. Go to end of keyword and try next. [jrd]

cmky3y: mov comand.cmkptr,bx    ; Save bx here.
        mov comand.cmsiz,cx     ; Save size info.
        mov comand.cmchr,ah     ; Save char for latter.
        cmp ah,'?'+80h          ; question mark?
        je cmkyj1               ; yes, always print possibilities
        call cmambg             ; See if input is ambiguous or not.
         jmp cmky32             ; Succeeded (not ambiguous).
        mov ah,comand.cmchr
        cmp ah,esc+80H          ; Escape?
        je cmky3z
;       cmp ah,'?'+80H          ; maybe question mark?
;       je cmkyj1               ; yes, go handle
        jmp cmky41              ; Else fail.
cmky3z: mov ah,conout           ; Ring a bell.
        mov dl,bell
        int dos
        mov bx,comand.cmcptr    ; Move pointer to before the escape.
        dec bx
        mov comand.cmcptr,bx
        mov comand.cmdptr,bx
        dec comand.cmccnt       ; Decrement char count.
        mov bx,comand.cmkptr    ; Failed - pretend user never typed ....
        mov cx,comand.cmsiz     ; ... in a char.
        dec cl                  ; Don't count the escape.
        dec bx
        mov comand.cmaflg,0     ; Reset the action flag.
        jmp cmky3               ; Keep checking.

; Question mark entered by user.  Print out all the keywords that match
cmkyj1: mov dx,offset cmin01
        mov ah,prstr
        int dos
        mov temp,0              ; count # chars printed on this line. [jrd]
        mov bx,comand.cmkptr    ; this is current keyword
        mov cx,comand.cmsiz     ; we are cl chars into it
        mov ch,0
        sub bx,cx               ; back up to beginning
        inc bx                  ; not counting ?
        mov comand.cmkptr,bx    ; save beginning of kw
cmkyj2: mov bx,comand.cmkptr    ; start of keyword
        dec bx
        mov al,[bx]             ; its length
        add temp,al             ; count  chars printed so far [jrd]
        cmp temp,76             ; will this take us beyond column 78?
        jle cmkyj3              ; le = ok so far
        mov ah,prstr            ; print string
        mov dx,offset crlf      ; break the line
        int dos
        mov temp,0              ; and reset the count
cmkyj3: mov dl,spc              ; put two spaces before each keyword
        mov ah,conout
        int dos
        inc temp                ; count output chars
        int dos
        inc temp
        mov dx,comand.cmkptr    ; get current keyword
        mov ah,prstr
        int dos                 ; print it
        mov bx,comand.cmkptr    ; get keyword back
        dec bx
        mov al,[bx]             ; get length
        mov ah,0
        add ax,5                ; skip length, $, value, next length
        add bx,ax               ; this is next keyword
        mov si,bx
        mov di,comand.cmkptr    ; compare with last keyword
        mov comand.cmkptr,bx    ; update this
        mov cx,comand.cmsiz
        dec ch                  ; are we at end of table?
        jl cmkyj4               ; l = yes, don't go on [jrd]
        mov comand.cmsiz,cx     ; else update count
        mov ch,0
        dec cl                  ; this includes ?
        jcxz cmkyj2             ; empty, just print it
        repe cmpsb              ; compare to previous string
        je cmkyj2               ; same, go print this one
cmkyj4: jmp cmky50              ; else go finish up [jrd]

cmky32: mov cx,comand.cmsiz     ; Restore info.
        mov bx,comand.cmkptr    ; Our place in the keyword table.
        cmp comand.cmchr,' '+80H ; Space?
        je cmky35
        cmp comand.cmchr,'?'+80H ; Question mark?
        je cmky35
        cmp comand.cmchr,cr+80H ; Carriage return?
        je cmky35
        dec comand.cmcptr       ; Pointer into buffer of input.
        mov dx,comand.cmcptr
cmky33: mov ah,[bx]             ; Get next char in keyword.
        call tolowr             ; convert it to lower case.[jrd]
        cmp ah,'$'              ; Are we done yet?
        jz cmky34
        mov di,dx
        mov [di],ah
        inc bx
        inc dx
        inc comand.cmccnt
        jmp cmky33
cmky34: mov ah,' '
        mov di,dx
        mov [di],ah             ; Put a blank in the buffer.
        inc dx
        mov cx,comand.cmcptr    ; Remember where we were.
        mov comand.cmcptr,dx    ; Update our pointers.
        mov comand.cmdptr,dx
        mov ah,'$'
        mov di,dx
        mov [di],ah             ; Add '$' for printing.
        mov ah,prstr
        mov dx,cx               ; Point to beginning of filled in data.
        int dos
        inc bx                  ; Point to address we'll need.
        mov bx,[bx]
        mov comand.cmaflg,0     ; Turn off action flag.
        jmp rskp

cmky35: inc bx
        mov ah,[bx]             ; Find end of keyword.
        cmp ah,'$'
        jne cmky35
        inc bx
        mov bx,[bx]             ; Address of next routine to call.
;       mov comand.cmaflg,0     ; Zero the action flag.
        jmp rskp

cmky4:  and ah,7FH              ; Turn off minus bit.
        cmp ah,'?'              ; Need help?
        je cmky5
        cmp ah,' '              ; Just a space - no error.
        je cmky51
        cmp ah,cr
        je cmky51
        cmp ah,tab
        je cmky51
        cmp ah,esc              ; Ignore escape?
        je cmky43
cmky41: mov ah,prstr
        mov dx,offset cmer03
        int dos
        jmp prserr              ; Parse error - give up.

cmky43: mov ah,conout           ; Ring a bell.
        mov dl,bell
        int dos
        dec comand.cmcptr       ;[ESC] don't trash BX here.
        dec comand.cmdptr       ;[ESC] ditto
        dec comand.cmccnt       ; Don't count the escape.
        mov comand.cmaflg,0     ; Reset action flag.
        inc ch                  ; Account for a previous 'dec'.
        jmp cmky1               ; Start over.

cmky5:  inc bx                  ; point to actual keyword
        mov comand.cmkptr,bx    ; remember current kw
        mov cl,1                ; code above expects to count ?
        mov comand.cmsiz,cx     ; and size
        mov dx,comand.cmhlp
        or dx,dx                ; was any help given?
        jnz cmky5a              ; yes, use it
        jmp cmkyj1              ; else make our own message
cmky5a: mov ah,prstr
        int dos
cmky50: mov ah,prstr
        mov dx,offset crlf
        int dos
        mov dx,comand.cmprmp    ; Address of prompt.
        int dos
        mov bx,comand.cmdptr    ; Get pointer into buffer.
        mov al,'$'
        mov [bx],al             ; Add dollar sign for printing.
        mov dx,offset comand.cmdbuf
        int dos
        dec comand.cmcptr       ; Don't keep it in the buffer.
        dec comand.cmccnt       ; Don't conut it.
        mov comand.cmaflg,0     ; Turn off the action flag.
        jmp repars

cmky51: cmp comand.cmcr,1       ; Are bare CR's allowed?
        je cmky52               ; Yes.
        mov ah,prstr
        mov dx,offset cmer04    ; Complain.
        int dos
cmky52: jmp prserr

cmky6:  inc bx                  ; Find end of keyword.
        cmp byte ptr [bx],'$'
        jne cmky6
        add bx,3                  ; Beginning of next command.
        mov dx,comand.cmsptr    ; Get old cmdptr.
        mov comand.cmdptr,dx    ; Restore.
        mov comand.cmsflg,0FFH
        jmp cmky1               ; Keep trying.

cmky7:  call cmgtch             ; Get char.
        cmp ah,0
        js cmky71               ; Ok if a terminator.
        dec bx
        jmp cmky6               ; No match - try next keyword.
cmky71: cmp ah,'?'+80h          ; question mark?
        jne cmky72              ; yes, don't return yet
        inc cl                  ; count the '?' Fix single char keywords.[jrd]
;;;[jrd]dec bx                  ; back up over '$'
        jmp cmky3y              ; and process ? correctly
cmky72: inc bx                  ; Get necessary data.
        mov bx,[bx]
        cmp ah,esc+80h          ; An escape?
        jne cmky73
        mov ah,prstr
        mov dx,offset prsp      ; Print a space.
        int dos
        mov di,comand.cmcptr
        dec di
        mov ah,20H
        mov [di],ah             ; Replace escape char with space.
        mov comand.cmaflg,0
        mov comand.cmsflg,0FFH  ; Pretend they typed a space.
cmky73: jmp rskp

; See if keyword is unambiguous or not from what the user has typed in.

cmambg: cmp ch,0                ; Any keywords left to check?
        jne cmamb0
        ret                     ; If not then not ambiguous.
cmamb0: inc bx                  ; Go to end of keyword ...
        mov al,[bx]             ; So we can check the next one.
        cmp al,'$'
        jne cmamb0
        add bx,4                ; Point to start of next keyword.
        dec cl                  ; Don't count escape.
        mov dx,comand.cmsptr    ; Buffer with input typed by user.
cmamb1: mov ah,[bx]             ; Keyword char.
        mov di,dx
        mov al,[di]             ; Input char.
        call tolowr             ; convert to lower case. [jrd]
        cmp ah,al               ; Keyword bigger than input (alphabetically)?
        jle cmamb2              ; No - keep checking.
        ret                     ; Yes - not ambiguous.
cmamb2: inc bx                  ; Advance one char.
        inc dx
        dec cl
        jnz cmamb1
        jmp rskp                ; Fail - it's ambiguous.



; Parse arbitrary text up to a CR.  Put chars into data buffer sent to
; the host (pointed to by BX).   Called with text of help message in DX.
; Produces asciiz string. Return updated pointer in BX and input size in AH.

cmtext: mov comand.cmptab,bx    ; Save pointer to data buffer.   [8 start]
        mov cmthlp,dx           ; Save the help message.
        mov cl,0                ; Init the char count.
cmtxt1: mov comand.cmsflg,0     ; Get all spaces. [25]
        call cmgtch             ; Get a char.
        test ah,80H             ; is high-order bit on?
        jz cmtxt5               ; Nope, put into the buffer.
        and ah,07FH
        cmp ah,' '
        je cmtxt5
        cmp ah,esc              ; An escape?
        jne cmtxt2
        mov ah,conout
        mov dl,bell             ; Ring a bell.
        int dos
        mov comand.cmaflg,0     ; Reset action flag.
        dec comand.cmcptr       ; Move pointer to before the escape.
        dec comand.cmdptr
        dec comand.cmccnt       ; Decrement count.
        jmp cmtxt1              ; Try again.
cmtxt2: cmp ah,'?'              ; Asking a question?
        jz cmtx30
        cmp ah,ff               ; Formfeed?
        jne cmtx2x
        call cmblnk
cmtx2x: mov ah,cl               ; Return count in AH.
        mov bx,comand.cmptab    ; Return updated pointer.
        jmp rskp
cmtx30: mov comand.cmaflg,0     ; Reset action flag to zero.
        inc comand.cmdptr       ; count the ?
        cmp cl,0                ; Is "?" first char?
        jne cmtxt5              ; No, just add to buffer.
        dec comand.cmcptr       ;[ESC] (moved 3 lines) Don't keep in buffer.
        dec comand.cmccnt       ;[ESC] Don't count it.
        dec comand.cmdptr       ;[ESC] don't count if printing help.
        mov ah,prstr            ; Else, give some help.
        mov dx,cmthlp           ; Address of help message.
        int dos
        mov ah,prstr
        mov dx,offset crlf      ; Print a crlf.
        int dos
        mov ah,prstr
        mov dx,comand.cmprmp    ; Reprint the prompt.
        int dos
        mov bx,comand.cmdptr    ; Get the pointer into the buffer.
        mov byte ptr [bx],'$'
        mov ah,prstr
        mov dx,offset comand.cmdbuf
        int dos
        jmp cmtxt1              ; And keep going.
cmtxt5: inc cl                  ; Increment the count.
        mov bx,comand.cmptab    ; Pointer into destination array.
        mov [bx],ah             ; Put char into the buffer.
        inc bx
        mov al,0                ; [jrd]
        mov [bx],al             ; insert null terminator [jrd]
        mov comand.cmptab,bx
        jmp cmtxt1                                      ; [8 end]

;       [jrd]
; Parse arbitrary text up to whitespace.  Put chars into data buffer sent to
; the host (pointed to by DX).   Called with text of help message in BX.
; Produces asciiz string. Return updated pointer in DX and input size in AH.
; Skips leading whitespace.
; Does a return skip exit. Replaces old cmifi routine.

cmfil0: push    dx
        mov     dx,bx           ; interchange bx and bx internally
        pop     bx
        mov comand.cmptab,bx    ; Save pointer to data buffer.
        mov cmthlp,dx           ; Save the help message.
        mov cl,0                ; Init the char count.
        mov comand.cmsflg,0ffH  ; skip over leading spaces and tabs.
cmfil1: call cmgtch             ; Get a char.
        test ah,80H             ; is high-order bit on (i.e. terminator seen)?
        jnz cmfi1a              ; nz = yes
        jmp cmfil5              ; z = no, put char into the buffer.
cmfi1a: and ah,07FH             ; clear high order bit
        cmp ah,esc              ; An escape?
        je cmfi1b               ; e = yes.
        cmp ah,' '              ; is it a space or control char?
        jg cmfil2               ; g = no. keep it
        jmp cmfi2x              ; else, a space or control char; end here.

cmfi1b: mov ah,conout           ; handle the escape char; ie, complain
        mov dl,bell             ; Ring a bell.
        int dos
        mov comand.cmaflg,0     ; Reset action flag.
        dec comand.cmcptr       ; Move pointer to before the escape.
        dec comand.cmdptr
        dec comand.cmccnt       ; Decrement count.
        jmp cmfil1              ; Try again.
cmfil2: cmp ah,'?'              ; Asking a question?
        jz cmfil3               ; z = yes
        cmp ah,ff               ; Formfeed?
        jne cmfi2x              ; ne = no
        call cmblnk             ; a FF. clear the command line and end.

cmfi2x: mov bx,comand.cmptab    ; Pointer into destination array.
        mov ah,0
        mov [bx],ah             ; Put null terminator into the buffer.
        inc bx
        mov ah,cl               ; Return count in AH.
        mov dx,comand.cmptab    ; Return updated pointer.
        push dx                 ; re-interchange bx and dx
        mov dx,bx
        pop bx
        jmp rskp

cmfil3: mov comand.cmaflg,0     ; Reset action flag to zero.
        inc comand.cmdptr       ; count the ?
        cmp cl,0                ; Is "?" first char?
        jne cmfil5              ; No, just add to buffer.
        dec comand.cmcptr       ;[ESC] (moved 3 lines) Don't keep in buffer.
        dec comand.cmccnt       ;[ESC] Don't count it.
        dec comand.cmdptr       ;[ESC] don't count if displaying help.
        mov ah,prstr            ; Else, give some help.
        mov dx,cmthlp           ; Address of help message.
        int dos
        mov ah,prstr
        mov dx,offset crlf      ; Print a crlf.
        int dos
        mov ah,prstr
        mov dx,comand.cmprmp    ; Reprint the prompt.
        int dos
        mov bx,comand.cmdptr    ; Get the pointer into the buffer.
        mov byte ptr [bx],'$'
        mov ah,prstr
        mov dx,offset comand.cmdbuf
        int dos
        jmp cmfil1              ; And keep going.
cmfil5: inc cl                  ; Increment the count.
        mov bx,comand.cmptab    ; Pointer into destination array.
        mov [bx],ah             ; Put char into the buffer.
        inc bx
        mov comand.cmptab,bx
        jmp cmfil1              ; the end of cmfil0.


cmgetc: cmp taklev,0
        jne cmget1
        jmp cmge10                      ; no take file, get from keyboard
cmget1: push bx
        push si
        mov bx,takadr
        mov ax,[bx].takcnt
        or ax,[bx].takcnt+2
        jnz cmget5
cmget2: mov al,byte ptr [bx].taktyp     ; get type of take [jrd]
        cmp al,0ffh                     ; is it really a macro?
        je cmget4                       ; yes, better not try to close it
cmget3: mov bx,word ptr [bx].takhnd     ; get file handle [jrd]
        mov ah,close2                   ; use 2.0 close
        int dos
cmget4: dec taklev
        sub takadr,size takinfo
        pop si
        pop bx
        mov al,cr               ; end with carriage return...
        ret

cmget5: cmp [bx].takchl,0       ; Any chars left in buffer?
        jne cmget6
        call takrd
cmget6: dec [bx].takchl
        sub [bx].takcnt,1       ; DEC doesn't set carry!!
        sbb [bx].takcnt+2,0
        mov si,[bx].takptr
        lodsb
        mov [bx].takptr,si
        cmp al,ctlz             ; maybe control-z?
        je cmget2               ; yes, close take file (has to be before pops)
        pop si
        pop bx
        cmp al,lf               ; linefeed?
        jne cmget7
        jmp cmgetc              ; yes, ignore it.
cmget7: cmp al,';'              ; maybe a semicolon?
        je cmget9
        cmp flags.takflg,0      ; Echo contents of take file?
        je cmget8
        push dx
        mov dl,al
        mov ah,conout
        int dos
        pop dx
cmget8: ret                     ; else just return...
; semicolon seen, ignore chars until cr
cmget9: call cmgetc             ; get a character?
        cmp al,cr               ; carriage return?
        jne cmget9              ; no, keep reading
        ret                     ; else return it

cmge10: mov ah,coninq           ; Get a char.
        cmp flags.debug,0       ; in debug mode?
        je cmge11               ; yes, go on
        mov ah,8                ; else use read that recognizes ^C
cmge11: int dos
        and al,7fh              ; only allow 7-bit characters.
        push ax                 ; save the char
        cmp al,del
        je cmgex
        cmp al,' '              ; printable?
        jae cmge12              ; yes, no translation needed
        cmp al,cr               ; this is printable
        je cmge12
        cmp al,lf
        je cmge12
        cmp al,tab
        je cmge12
cmgex:  mov al,' '              ; else echo a space
cmge12: mov dl,al               ; put char here
        cmp comand.cmquiet,0    ; quiet mode?
        jnz cmge13              ; yes, skip echoing...
        mov ah,conout
        int dos                 ; echo it ourselves...
cmge13: pop ax                  ; and return it
        cmp al,'C'-40H          ; control-C?
        je cmge15               ; yes, go handle
        cmp al,tab
        jne cmge14
        mov al,' '
cmge14: ret
cmge15: mov dx,offset ctcmsg
        mov ah,prstr
        int dos
        mov flags.cxzflg,'C'    ; remember ^C'd
        mov sp,cmdstk           ; restore command stack ptr
        ret                     ; and fail

; Come here is user types ^W when during input.
cntrlw: mov ah,prstr
        mov dx,offset escspc
        int dos
        dec comand.cmccnt       ; Don't include it in the count.
        dec comand.cmcptr       ; Back up past the ^W.
        mov cl,comand.cmccnt
        mov ch,0
        jcxz ctlw2
        pushf
        push es
        std                     ; Scan backwards.
        mov ax,ds
        mov es,ax               ; Point to the data area.
        mov di,comand.cmcptr    ; Looking from here.
        dec di
        mov al,' '
        repe scasb              ; Look for non-space.
        je ctlw1                ; All spaces, nothing else to do
        inc di                  ; move back to non-space
        inc cx
        repne scasb             ; look for a space
        jne ctlw1               ; no space, leave ptrs alone
        inc di
        inc cx                  ; skip back over space
ctlw1:  inc di
        mov comand.cmccnt,cl    ; update count
        mov cx,comand.cmcptr    ; remember old ptr
        mov comand.cmcptr,di    ; update pointer
        sub cx,di               ; this is characters moved
        mov al,bs               ; backspace
        cld
        mov di,offset tbuff     ; temporary buffer
        rep stosb               ; put enough spaces in
        mov byte ptr [di],'$'   ; end buffer
        mov dx,offset tbuff
        mov ah,prstr
        int dos                 ; back up cursor
        call clearl             ; clear line
        pop es
        popf
        ret                     ; and return
ctlw2:  mov ah,conout
        mov dl,bell
        int dos
        ret

cminbf: push dx
        push bx
        mov cx,dx               ; Save value here too.
        mov ah,comand.cmaflg    ; Is the action char flag set?
        cmp ah,0
        je cminb1
        jmp cminb9              ; If so get no more chars.
cminb1: inc comand.cmccnt       ; Increment the char count.
        call cmgetc
        mov ah,al               ; Keep char in 'ah'.
        mov bx,comand.cmcptr    ; Get the pointer into the buffer.
        mov [bx],ah             ; Put it in the buffer.
        inc bx
        mov comand.cmcptr,bx
        cmp ah,'W'-64           ; Is it a ^W?
        jne cmnb11
        call cntrlw             ; Kill the previous word.
        jmp repars
cmnb11: cmp ah,25O              ; Is it a ^U?
        jne cminb2
cmnb12: call ctlu               ; Clear out the line.
        mov ah,prstr
        mov dx,comand.cmprmp    ; Print the prompt.
        int dos
        mov bx,offset comand.cmdbuf
        mov comand.cmcptr,bx    ; Reset the point to the start.
        mov comand.cmccnt,0     ; Zero the count.
        mov dx,cx               ; Preserve original value of dx.
        jmp repars              ; Go start over.
cminb2: cmp ah,bs              ; Or backspace?
        jz cminb3
        cmp ah,del              ; Delete?
        jne cminb4
cminb3: call dodel              ; Delete a character.
        mov ah,comand.cmccnt    ; Decrement the char count by two.
        dec ah
        dec ah
        cmp ah,0                        ; Have we gone too far?
        jns cmnb32              ; If not proceed.
        mov ah,conout           ; Ring the bell.
        mov dl,bell
        int dos
        jmp cmnb12              ; Go reprint prompt and reparse.
cmnb32: mov comand.cmccnt,ah    ; Save the new char count.
        mov ah,prstr            ; Erase the character.
        mov dx,offset clrspc
        int dos
        mov bx,comand.cmcptr    ; Get the pointer into the buffer.
        dec bx                  ; Back up in the buffer.
        dec bx
        mov comand.cmcptr,bx
        jmp repars              ; Go reparse everything.
cminb4: cmp ah,'?'              ; Is it a question mark.
        jz cminb6
        cmp ah,esc              ; Is it an escape?
        jz cminb8
        cmp ah,cr               ; Is it a carriage return?
        jz cminb5
        cmp ah,lf               ; Is it a line feed?
        jz cminb5
        cmp ah,ff               ; Is it a formfeed?
        jne cminb7
        call cmblnk
        call locate
cminb5: mov ah,comand.cmccnt    ; Have we parsed any chars yet?
        cmp ah,1
        jnz cminb6
        jmp prserr              ; If not, just start over.
cminb6: mov ah,0FFH             ; Set the action flag.
        mov comand.cmaflg,ah
        jmp cminb9
cminb7: jmp cminb1              ; Get another char.

cminb8: mov ah,prstr            ; Don't print the escape char.
        mov dx,offset escspc
        int dos
        jmp cminb6

cminb9: pop bx
        pop dx
        ret

cmgtch: push cx
        push bx
        push dx
cmgtc1: mov ah,comand.cmaflg
        cmp ah,0                        ; Is it set.
        jne cmgt10
        call cminbf             ; If the action char flag is not set get more.
cmgt10: mov bx,comand.cmdptr    ; Get a pointer into the buffer.
        mov ah,[bx]             ; Get the next char.
        inc bx
        mov comand.cmdptr,bx
        cmp ah,' '              ; Is it a space?
        jz cmgtc2
        cmp ah,tab              ; Or a tab?
        jne cmgtc3
cmgtc2: mov ah,comand.cmsflg    ; Get the space flag.
        cmp ah,0                ; Was the last char a space?
        jne cmgtc1              ; Yes, get another char.
        mov ah,0FFH             ; Set the space flag.
        mov comand.cmsflg,ah
        mov ah,' '
        pop dx
        pop bx
        jmp cmgtc5
cmgtc3: mov al,0
        mov comand.cmsflg,al    ; Zero the space flag.
        pop dx
        pop bx
        cmp ah,esc
        jz cmgtc5
        cmp ah,'?'              ; Is the user curious?
        jz cmgtc4
        cmp ah,cr
        jz cmgtc4
        cmp ah,lf
        jz cmgtc4
        cmp ah,ff
        je cmgtc4
        pop cx
        ret                     ; Not an action char, just return.
cmgtc4: dec comand.cmdptr
cmgtc5: or ah,80H               ; Make the char negative to indicate
        pop cx
        ret                     ; it is a terminator.
CMND    ENDP

;       This address is jumped to on reparse.

PARSE   PROC NEAR
repars: mov sp,comand.cmostp   ; new sp <-- old sp
        mov bx,offset comand.cmdbuf
        mov comand.cmdptr,bx
        mov ah,0FFH
        mov comand.cmsflg,ah
        jmp comand.cmrprs       ; go back to reparse address

;       This address can be jumped to on a parsing error.

prserr: mov sp,comand.cmostp    ; Set new sp to old one.
        mov bx,offset comand.cmdbuf
        mov comand.cmcptr,bx    ; Initialize the command pointer.
        mov comand.cmdptr,bx
        mov ah,0
        mov comand.cmaflg,ah    ; Zero the flags.
        mov comand.cmccnt,ah
        mov comand.cmsflg,0FFH
        cmp taklev,0            ; in take cmd?
        jne prser1              ; yes, don't print prompt
        mov ah,prstr
        mov dx,offset crlf
        int dos
        mov ah,prstr            ; Print the prompt.
        mov dx,comand.cmprmp    ; Get the prompt.
        int dos
; Instead return to before the prompt call.
prser1: jmp comand.cmrprs
PARSE   ENDP

; Convert ascii characters in al and ah to lowercase. [jrd]
; All registers are preserved except AX, of course.

TOLOWR PROC NEAR
        test    ah,80H                  ; sign bit set?
        jnz     tolow1                  ; nz = yes
        cmp     ah,'A'                  ; less that cap A?
        jl      tolow1                  ; l = yes. leave untouched
        cmp     ah,'Z'+1                ; more than cap Z?
        jns     tolow1                  ; ns = yes.
        or      ah,20H                  ; convert to uppercase
tolow1: test    al,80H                  ; sign bit set?
        jnz     tolow2                  ; nz = yes
        cmp     al,'A'                  ; less that cap A?
        jl      tolow2                  ; l = yes. leave untouched
        cmp     al,'Z'+1                ; more than cap Z?
        jns     tolow2                  ; ns = yes.
        or      al,20H                  ; convert to uppercase
tolow2: ret
TOLOWR  endp

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop bp
        add bp,3
        push bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

code    ends
        end



