	public comnd, cmcfrm, prserr, repars, cmgtch, drives, comand, fcbcpy
	include msdefs.h

datas 	segment	public 'datas'
	extrn	flags:byte, trans:byte, fcb:byte, buff:byte
	extrn	taklev:byte, takadr:word, dosnum:byte

comand	cmdinfo	<>
cmer00  db      cr,lf,'?Program error   Invalid COMND call$'
cmer01  db      cr,lf,'?Ambiguous$'
cmer02  db      cr,lf,'?Illegal input file spec$'
cmer03	db	cr,lf,'?Invalid command$'		 ; [19e]
cmer04	db	cr,lf,'?Invalid command or operand$'     ; [1]
cmer06	db	cr,lf,'?Wildcard not allowed$'		 ; [21a]
cmer07	db	cr,lf,'?Invalid drive specificaton$'	 ; [21a]
cmin00  db      ' Confirm with carriage return$'
cmin01	db	' One of the following:',cr,lf,'$'

cmthlp	dw	0		; Text of help message for random input.
drives	db	0		; How many drives we have. [21a]
crlf    db      cr,lf,'$'
ctcmsg	db	'^C$'
prsp	db	' $'			; Print a space.
hlpmsg	dw	0			; Address of help message.
spchar	db	24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
	db	3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
spclen	equ	$-spchar
spchar2	db	24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
	db	7BH,7DH,5FH,5EH,7EH,60H
spc2len	equ	$-spchar2
escspc	db	10O,' ',10O,'$'		; Clear escape.
clrspc  db      ' ',10O,'$'             ; Clear space.
filbuf  db	60H DUP(?)		; Character buffer.
tbuff	db	80  DUP(?)
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 cm1
        jmp cmkeyw               ; Try and get one.
cm1:    cmp ah,cmifi		; Parse an input file spec?
	jnz cm2
	jmp cmifil		; Go get one.
cm2:	cmp ah,cmofi		; Output file spec?
	jnz cm3
	jmp cmofil		; Go get one.
cm3:	cmp ah,cmtxt		; Parse arbitrary text.   [8]
	jnz cm4
	jmp cmtext
cm4:	mov ah,prstr		; Else give error.
	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
        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 ah,0
        mov comand.cmaflg,ah    ; 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.


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.
        cmp ah,0                ; Do we have a terminator?
        jns cmky2x 
	jmp cmky4               ; Negative number means we do.
cmky2x: inc bx                  ; Point to first letter of keyword.
	inc cl			; Read in another char.
        mov al,[bx]                   
        cmp ah,'a'              ; Less than a?
        jl cmky21               ; If so, don't capitalize.
        cmp ah,'z'+1            ; More than z?
        jns cmky21
        and ah,137O             ; Capitalize the letter.
cmky21: cmp ah,al
	je cmky3
	jg cmky2y
        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]
        cmp al,'$'               ; End of keyword?
	jne cmky3x
        jmp cmky7                ; Succeed.
cmky3x:	mov dl,al		; Save al's char here.
        call cmgtch
	inc cl			; Read in another char.
	mov al,dl
	cmp ah,'a'
	jl cmky31
	cmp ah,'z'+1
	jns cmky31
	and ah,137O
cmky31: cmp ah,esc+80H		; Escape Recognition (escape w/minus bit on)?
	je cmky3y
	cmp ah,'?'+80H		; A question mark?    [3]
	je cmky3y
	cmp ah,' '+80H		; A space?
	je cmky3y
	cmp ah,cr+80H		; Carriage return?
	je cmky3y
	jmp cmky38
cmky3y:	mov comand.cmkptr,bx	; Save bx here.
	mov comand.cmsiz,cx	; Save size info.
	mov comand.cmchr,ah	; Save char for latter.
	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.
; ambiguous.  Print out all the keywords that match
cmkyj1:	mov dx,offset cmin01
	mov ah,prstr
	int dos
	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 dl,tab		; put a tab before each keyword
	mov ah,conout
	int dos
	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 cmkyj3		; yes, don't go on
	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
cmkyj3:	jmp cmky50		; else go finish up

cmky32: mov cx,comand.cmsiz	; Restore info.
	mov bx,comand.cmkptr	; Our place in the keyword table.
	cmp comand.cmchr,0A0H	; Space?
	je cmky35
	cmp comand.cmchr,0BFH	; Question mark?     [3]
	je cmky35
	cmp comand.cmchr,8DH	; 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.
	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

cmky38:	cmp ah,al
	je cmky39
        jmp cmky6               ; Go to end of keyword and try next.
cmky39:	jmp cmky3		; Check next letter.
           
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.
        mov al,[bx]
        cmp al,'$'
        jne cmky6             
        inc bx                  ; Beginning of next command.
        inc bx
        inc bx
	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: inc bx                  ; Get necessary data.
        mov bx,[bx]
	cmp ah,9BH		; An escape?
	jne cmky72
	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.
cmky72: 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.
	cmp al,'a'		; Do capitalizing.
	jl cmam11
	cmp al,'z'+1
	jns cmam11
	and al,137O
cmam11:	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.

cmifil:	mov hlpmsg,bx		; Address of help message.
	mov bx,dx               ; Get the fcb address in bx.
        mov comand.cmfcb,bx     ; Save it.
        mov ch,0                ; Initialize char count.
        mov ah,0
        mov [bx],ah		; Set the drive to default to current.
	inc bx
        mov comand.cmfcb2,bx
        mov cl,' '
cmifi0: mov [bx],cl		; Blank the FCB.
        inc bx
        inc ah
        cmp ah,0BH		; Twelve?
        jl cmifi0
cmifi1: call cmgtch             ; Get another char.
        cmp ah,0                ; Is it an action character.
	js cmif1x		; Jump out of range. [21a]
        jmp cmifi2		; Ditto. [21a]
cmif1x: and ah,7FH              ; Turn off the action bit. [21a]
        cmp ah,'?'              ; A question mark?
        jne cmif12
        mov al,0
        mov comand.cmaflg,al    ; Blank the action flag.
        dec comand.cmcptr       ; Decrement the buffer pointer.
	dec comand.cmccnt	; Decrement count.
	mov ah,prstr
	mov dx,hlpmsg		; Help  message.
	int dos
	mov dx,offset crlf
	int dos
	mov dx,comand.cmprmp
	int dos
	mov bx,comand.cmdptr
	mov al,'$'
	mov [bx],al		; Put in dollar sign for printing.
	mov dx,offset comand.cmdbuf
	int dos
	jmp repars
cmif12: cmp ah,esc		; An escape?
	je cm12x
        jmp cmif13
cm12x:	mov comand.cmaflg,0	; Turn off the action flag.
	dec comand.cmcptr	; Move pointers to before the escape.
	dec comand.cmdptr
	dec comand.cmccnt	; Decrement char count.
	mov comand.cmchr,ch	; Save current character count.
	cmp ch,9		; Past '.'?
         jl cmf120		; No.
	dec ch			; Yes, don't count point.
cmf120:	mov di,comand.cmfcb2    ; Fill the rest with CP/M wildcards.
	mov ah,'?'

cmf121:	cmp ch,11		; Done?
	 jge cmf122		; Yes.
	mov [di],ah
	inc di
	inc ch
	jmp cmf121

cmf122: mov ah,sfirst		; Find first matching file?
	mov dx,comand.cmfcb	;[jd] use pointer to PASSED fcb
	int dos
	cmp al,0FFH		; Any found?
	jne cmf123		; Yes.
	 jmp cmf12b		; No, lose.
cmf123:	mov di,offset filbuf    ; Copy first file spec from DTA to buffer.
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy
	mov di,offset filbuf+10H ; Get another copy (if not ambiguous).
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy
	mov ah,snext		; More matching specs?
	mov dx,comand.cmfcb	;[jd] use PASSED fcb...
	int dos
	cmp al,0FFH
	 je cmf124		; Only one.
	mov di,offset filbuf+10H ; Copy second file spec.
	mov bx,offset buff+1
	mov cl,11
	call fcbcpy

cmf124:	mov si,offset filbuf	; Start comparing file names.
	mov bx,offset filbuf+10H
	mov di,comand.cmcptr	; Command buffer pointer
	mov cl,comand.cmchr	; Bypass characters typed.
	cmp cl,9		; Past '.'?
	 jl cmf125		; No.
	dec cl			; Yes, don't count point.
cmf125:	mov ch,0		; Adjust pointers.
	add si,cx
	add bx,cx
	mov ch,cl		; Update character count

cmf126:	cmp ch,11		; All done?
	jne cmf127		; No.
	 jmp cmf12a		; Yes.
cmf127:	cmp ch,8		; End of file name?
	 jne cmf128		; No.
	cmp comand.cmchr,9	; Exactly at point?
	 je cmf128		; Yes, don't output a second point.
	mov ah,'.'		; Output separator.
	mov [di],ah
	inc di
	inc comand.cmccnt
cmf128:	mov ah,[si]		; Get a character from first file spec.
	inc si
	mov al,[bx]		; Get another from second spec.
	inc bx
	cmp ah,al		; Compare.
	 jne cmf12a		; Ambiguous.
	inc ch			; Same, count.
	cmp ah,' '		; Blank?
	 je cmf129		; Yes, don't output.
	mov [di],ah
	inc di
	inc comand.cmccnt
cmf129:	jmp cmf126		; Repeat.

cmf12a:	mov comand.cmchr,ch	; Save count of characters processed.
	mov ah,'$'		; Put terminator into buffer.
	mov [di],ah
	mov comand.cmcptr,di    ; Save pointer for recognized characters.
	mov ah,prstr
	mov dx,comand.cmdptr
	int dos
	mov ch,comand.cmchr	; Characters processed.
	cmp ch,11		; Complete file name.
	 je cmf12c		; Yes, don't beep.

cmf12b:	mov ah,conout		; Beep, if not recognized.
	mov dl,bell
	int dos			; Ring the bell.
cmf12c:	jmp repars

cmif13: mov ah,ch               ; It must be a terminator.
        cmp ah,0                ; Test the length of the file name.
	jnz cmf3x
	cmp comand.cmcr,1	; Is zero length OK? [21a]
	je cmf3z		; Return successfully. [21a]
        jmp cmifi9              ; If zero complain.
cmf3x:  cmp ah,0DH
        js cmf3y
	jmp cmifi9              ; If too long complain.
cmf3y:  jmp rskp                ; Otherwise we have succeeded.
cmf3z:	push es
	mov ax,ds
	mov es,ax
	mov di,comand.cmfcb
	inc di
	mov cx,11
	mov al,'?'
	repne stosb
	pop es
	mov flags.wldflg,0FFH	; Remember we had a wildcard.
	jmp rskp
cmifi2: cmp ah,'.'
        jne cmifi3
        inc ch
        mov ah,ch
        cmp ah,1H		; Any chars yet?
      	jnz cmf2x
	jmp cmifi9		; No, give error.
cmf2x:  cmp ah,0AH		; Tenth char?
      	js cmf2y
	jmp cmifi9              ; Past it, give an error.
cmf2y:  mov dl,9H
        mov dh,0
        mov bx,comand.cmfcb
        add bx,dx               ; Point to file type field.
        mov comand.cmfcb2,bx
        mov ch,9H               ; Say we've gotten nine.
        jmp cmifi1              ; Get the next char.
cmifi3: cmp ah,':'
        jne cmifi4
        inc ch
        cmp ch,2H		; Is it in right place for a drive?
	je cmif3x
        jmp cmifi9              ; If not, complain.
cmif3x: mov ch,0		; Reset char count.
	mov flags.droflg,1	; Override default drive. [21a]
	mov flags.nmoflg,0	; Not so fast. [21a]
	mov bx,comand.cmfcb2
	mov al,':'		; Use for parsing drive name.
	mov [bx],al
	dec bx			; Point to drive spec.
	mov si,bx
	push es
	mov ax,ds
	mov es,ax
	mov di,offset tbuff	; Borrow this buffer.
	mov ah,prsfcb
	int dos
	pop es
	cmp al,0		; OK return code?
	je cmif3y		; Yes, keep going.
;        mov ah,[bx]		; Get the drive name.
;        sub ah,'@'              ; Get the drive number.
;	cmp ah,drives		; Did user specify a non-existant drive? [21a]
;	jle cmif3y		; Nope, so continue. [21a]
	mov dx,offset cmer07	; Fail with this error message. [21a]
	jmp cmif9x		; [21a]
cmif3y:	mov comand.cmfcb2,bx	; Put rest of filename starting here. [21a]
	mov ah,[bx]		; Pick up drive specified.
	sub ah,'@'		; Get real value.
 	mov bx,comand.cmfcb
        mov [bx],ah		; Put it in the fcb.
	push bx
	mov al,' '		; Overwrite the drive and ":".
	inc bx
	mov [bx],al
	inc bx
	mov [bx],al
	pop bx
        jmp cmifi1
cmifi4: cmp ah,'*'
        jne cmifi7
	cmp comand.cmrflg,1	; In receive mode?  [21a]
	jne cmif4x		; Jump out of range. [21a]
	mov dx,offset cmer06	; Set the error message. [21a]
	jmp cmif9x	        ; Fail - no wildcard allowed. [21a]
cmif4x: mov ah,ch		; [21a]
        cmp ah,8H		; Is this in the name or type field?
        jns cmifi5              ; Type.
        mov cl,8H               ; Say we have eight chars.
        js cmifi6		; Name field.
        jmp cmifi9		; If its where the dot should be give up.
cmifi5: mov cl,0CH              ; Three chars.
cmifi6: mov flags.wldflg,0FFH	; Remember we had a wildcard.
	mov bx,comand.cmfcb2    ; Get a pointer into the FCB.
        mov ah,'?'
        mov [bx],ah		; Put a question mark in.
        inc bx
        mov comand.cmfcb2,bx
        inc ch
        mov ah,ch
        cmp ah,cl
        jl cmifi6               ; Go fill in another.
        jmp cmifi1              ; Get the next char.
cmifi7: cmp ah,03DH		; Equals sign (wildcard)?
	jne cmif7x
	cmp comand.cmrflg,1	; In receive mode?  [21a]
	jne cmif7y		; No, so it's ok. [21a]
	mov dx,offset cmer06	; Set the error message. [21a]
	jmp cmif9x		; Fail - no wildcard allowed. [21a]
cmif7y:	mov ah,'?'		; New label. [21a]
	mov flags.wldflg,0FFH	; Say we have a wildcard.
	jmp cmifi8		; Put into FCB.
cmif7x:	cmp ah,'0'
        jl cmif8x
        cmp ah,'z'+1
        jns cmif8x
        cmp ah,'A'		; Don't capitalize non-alphabetics.
        jl cmifi8
        and ah,137O             ; Capitalize.
cmifi8: mov bx,comand.cmfcb2    ; Get the pointer into the FCB.
        mov [bx],ah             ; Put the char there.
        inc bx
        mov comand.cmfcb2,bx
	mov flags.nmoflg,1	; Overriding name from host. [21a]
        inc ch
        jmp cmifi1

cmif8x:	push es
	mov cx,ds
	mov es,cx		; Scan uses ES register.
	mov di,offset spchar    ; Special chars.
	mov cx,spclen		; How many of them.
	cmp dosnum,0		; Under version 2.0
	je cmif8y
	mov di,offset spchar2
	mov cx,spc2len
cmif8y:	mov al,ah		; Char is in al.
	repnz scasb		; Search string for input char.
	cmp cx,0		; Was it there?
	pop es
	jnz cmifi8
 
cmifi9: mov dx,offset cmer02
cmif9x:	mov ah,prstr
        int dos
	mov flags.droflg,0	; Not overriding drive. [21a] 
	mov flags.nmoflg,0	; Or name to save file under. [21a]
	mov comand.cmrflg,0	; Reset this flag too. [21a]
        ret

cmofil: jmp cmifil              ; For now, the same as CMIFI.

; 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.
; 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 conut 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 comand.cmptab,bx
	jmp cmtxt1					; [8 end]

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].takfcb	; get first byte of fcb
	cmp al,0ffh			; is it really a macro?
	je cmget4			; yes, better not try to close it
	cmp al,0feh			; or maybe a file handle?
	je cmget3			; yes, close w/2.0 call
	mov ah,closf
	lea dx,[bx].takfcb
	int dos
	jmp short cmget4			; skip over alternate close
cmget3:	mov bx,word ptr [bx].takfcb+1	; this is where file handle is stored
	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
	cmp flags.takflg,0
	je 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
	push ax			; save the char
	cmp al,bs		; backspace?
	je cmge13		; yes, skip echo
	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
	mov al,' '		; else echo a space
cmge12:	mov dl,al		; put char here
	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,';'		; semicolon?
	je cmget9		; yes, ignore rest of line...
	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
 
;	FCB must be remembered if found "*" in filename.      [7 start]
; 	Copy from place addressed by BX to place addressed by DI.
;	Also use to get the filename to the FCB from the DTA.

FCBCPY	PROC	NEAR
	push	es
	push	si
	mov	ax,ds
	mov	es,ax		; make sure destination segment is correct
	mov	ch,0		; high-order part of length
	jcxz	fcbcp1		; zero argument (is this necessary???)
	mov	si,bx		; this is source
	rep	movsb		; copy the whole thing
fcbcp1:	pop	si
	pop	es
	ret			; and return
FCBCPY	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
