; CP4CMD.ASM
;	KERMIT - (Celtic for "FREE")
;
;	This is the CP/M-80 implementation of the Columbia University
;	KERMIT file transfer protocol.
;
;	Version 4.0
;
;	Copyright June 1981,1982,1983,1984
;	Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others. 

;
;	This file provides a user oriented way of parsing commands.
;	It is similar to that of the COMND JSYS in TOPS-20.
;
; revision history (latest first):
; edit 3: July 8, 1984 (CJC)
;	integrate Toad Hall changes for LASM compatibility: CP4CPM is linked
;	by CP4WLD, and links CP4UTL.
;	
; edit 2: June 5, 1984 (CJC)
;	formatting and documentation; delete unnecessary code at cminb7; add
;	module version string.
;
; edit 1: May, 1984 (CJC)
;	extracted from CPMBASE.M80 version 3.9; modifications are described in
;	the accompanying .UPD file.

cmdver:	db	'CP4CMD.ASM (3)  8-Jul-84$'	; name, edit number, date

;	This routine prints the prompt in DE and specifies the reparse
;	address.
;	called by:  kermit

prompt:	pop	h		;Get the return address.
	push	h		;Put it on the stack again.
	shld	cmrprs		;Save it as the address to go to on reparse.
	lxi	h,0		;Clear out hl pair.
	dad	sp		;Get the present stack pointer.
	shld	cmostp		;Save for later restoral.
	xchg			;Save the pointer to the prompt.
	shld	cmprmp
	xchg
	lxi	h,cmdbuf
	shld	cmcptr		;Initialize the command pointer.
	shld	cmdptr
	xra	a
	sta	cmaflg		;Zero the flags.
	sta	cmccnt
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	call	prcrlf		;Print a CR/LF [Toad Hall]
	jmp	prprmp		;Print the prompt.  [Toad Hall]
;
;	This address is jumped to on reparse.
;	here from:  cmcfrm, cmkeyw, cmifil, cminbf

repars:	lhld	cmostp		;Get the old stack pointer.
	sphl			;Make it the present one.
	lxi	h,cmdbuf
	shld	cmdptr
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	lhld	cmrprs		;Get the reparse address.
	pchl			;Go there.

;	This address can be jumped to on a parsing error.
;	here from:  cmkeyw, cminbf

prserr:	lhld	cmostp		;Get the old stack pointer.
	sphl			;Make it the present one.
	lxi	h,cmdbuf
	shld	cmcptr		;Initialize the command pointer.
	shld	cmdptr
	xra	a
	sta	cmaflg		;Zero the flags.
	sta	cmccnt
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	call	prcrlf		;Print a CR/LF  [Toad Hall]
	call	prprmp		;Print the prompt  [Toad Hall]
;* Instead return to before the prompt call.
	lhld	cmrprs
	pchl
;
;	This routine parses the specified function in A.  Any additional
;	information is in DE and HL.
;	Returns +1 on success
;		+4 on failure (assumes a JMP follows the call)
;	called by:  log, setcom, read, send, xmit, dir, era, keycmd, cfmcmd

comnd:	sta	cmstat		;Save what we are presently parsing.
	call	cminbf		;Get chars until an action or a erase char.
	cpi	cmcfm		;Parse a confirm?
	jz	cmcfrm		;Go get one.
	cpi	cmkey		;Parse a keyword?
	jz	cmkeyw		;Try and get one.
	cpi	cmifi		;Parse an input file spec?
	jz	cmifil		;Go get one.
	cpi	cmifin		;Input file-spec silent?
	jz	cmifil		;do as he wishes
	cpi	cmofi		;Output file spec?
	jz	cmofil		;Go get one.
	cpi	cmtxt		;Parse arbitrary text?
	jz	cmtext		;Go do it.
	lxi	d,cmer00	;"?Unrecognized COMND call"
	call	prtstr
	ret
;
;	This routine parses arbitrary text up to a CR.
;	Accepts DE:	address to put text
;	Returns in A:	number of chars in text (may be 0)
;		  DE:	updated pointer
;	called by: comnd

cmtext:	xchg			;Put the pointer to the dest in HL.
	shld	cmptab		;Save the pointer.
	mvi	b,0		;Init the char count
cmtxt1:	call	cmgtch		;Get a char.
	ora	a		;Terminator?
	jp	cmtxt5		;No, put in user space.
	ani	7FH		;Turn off minus bit.
	cpi	esc		;An escape?
	jnz	cmtxt2		;No.
	mvi	c,conout
	mvi	e,bell		;Get a bell.
	call	bdos
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	jmp	cmtxt1		;Try again.

cmtxt2:	cpi	'?'		;Is it a question mark?
	jz	cmtxt3		;If so put it in the text.
	cpi	ff		;Is it a formfeed?
	cz	clrtop		;If so blank the screen.
	mov	a,b		;Return the count.
	lhld	cmptab		;Return updated pointer in HL.
	xchg
	jmp	rskp		;Return success.

cmtxt3:	lxi	h,cmaflg	;Point to the action flag.
	mvi	m,0		;Set it to zero.
cmtxt5:	inr	b		;Increment the count.
	lhld	cmptab		;Get the pointer.
	mov	m,a		;Put the char in the array.
	inx	h
	shld	cmptab		;Save the updated pointer.
	jmp	cmtxt1		;Get another char.

;
;	This routine gets a confirm.
;	called by: comnd

cmcfrm:	call	cmgtch		;Get a char.
	ora	a		;Is it negative (a terminator;a space or
				;a tab will not be returned here as they
				;will be seen as leading white space.)
	rp			;If not, return failure.
	ani	7FH		;Turn off the minus bit.
	cpi	esc		;Is it an escape?
	jnz	cmcfr2
	mvi	c,conout
	mvi	e,bell		;Get a bell.
	call	bdos
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	jmp	cmcfrm		;Try again.

cmcfr2:	cpi	'?'		;Curious?
	jnz	cmcfr3
	lxi	d,cmin00	;Print something useful.
	call	prtstr
	call	prcrlf		;Print a crlf.  [Toad Hall]
 	call	prprmp		;Reprint the prompt  [Toad Hall]
	lhld	cmdptr		;Get the pointer into the buffer.
	mvi	a,'$'		;Put a $ there for printing.
	mov	m,a
	lhld	cmcptr
	dcx	h		;Decrement and save the buffer pointer.
	shld	cmcptr
	lxi	d,cmdbuf
	call	prtstr
	xra	a		;Turn off the action flag.
	sta	cmaflg
	jmp	repars		;Reparse everything.

cmcfr3:	cpi	ff		;Is it a form feed?
	cz	clrtop		;If so blank the screen.
	jmp	rskp
;
;	This routine parses a keyword from the table pointed
;	to in DE.  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.
;		db	a,b	;Where a & b are pieces of data
;				;to be returned.  (Must be two of them.)
;
;	The keywords must be in alphabetical order.
;**** Note:  The data value a is returned in registers A and E.  The
;****	data value b is returned in register D.  This allows the two data
;	bytes to be stored as:
;		dw	xxx
;	and result in a correctly formatted 16-bit value in register pair
;	DE.
;	called by: comnd

cmkeyw:	shld	cmhlp		;Save the help.
	xchg			;Get the address of the table.
	shld	cmptab		;Save the beginning of keyword tab for '?'.
	mov	b,m		;Get the number of entries in the table.
	inx	h
	shld	cmkptr
	lhld	cmdptr		;Save the command pointer.
	shld	cmsptr
cmkey2: mov	a,b		;Get the number of entries left.
	ora	a		;Any left?
	rz			;If not we failed.
	lhld	cmkptr
	mov	e,m		;Get the length of the keyword.
	inx	h
cmkey3:	dcr	e		;Decrement the number of chars left.
	mov	a,e
	cpi	0FFH		;Have we passed the end?
	jm	cmkey5		;If so go to the next.
	call	cmgtch		;Get a char.
	ora	a		;Is it a terminator?
	jp	cmkey4		;If positive, it is not.
	ani	7FH		;Turn off the minus bit.
	cpi	'?'
	jnz	cmky31
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lxi	h,cmccnt	;Decrement the char count.
	dcr	m
;* Must go through the keyword table and print them.
	lhld	cmhlp		;For now print the help text.
	xchg
	call	prtstr
	call	prcrlf		;Print a crlf  [Toad Hall]
	call	prprmp		;Reprint the prompt  [Toad Hall]
	lhld	cmdptr		;Get the pointer into the buffer.
	mvi	a,'$'		;Put a $ there for printing.
	mov	m,a
	lhld	cmcptr
	dcx	h		;Decrement and save the buffer pointer.
	shld	cmcptr
	lxi	d,cmdbuf
	call	prtstr
	jmp	repars		;Reparse everything.

cmky31:	cpi	esc		;Is it an escape?
	jnz	cmky35
	xra	a
	sta	cmaflg		;Turn off the action flag.
	push	d
	push	b
	push	h
	call	cmambg
	 jmp	cmky32		;Not ambiguous.
	mvi	c,conout
	mvi	e,bell
	call	bdos		;Ring the bell.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	pop	h
	pop	b
	pop	d
	inr	e		;Increment the left to parse char count.
	jmp	cmkey3

cmky32:	lhld	cmcptr		;Pointer into buffer.
	dcx	h		;Backup to the escape.
	xchg
	pop	h
	push	h
cmky33:	mov	a,m		;Get the next char.
	cpi	'$'		;Finished?
	jz	cmky34
	inx	h
	xchg
	mov	m,a		;Move it into the buffer.
	inx	h
	xchg
	lda	cmccnt		;Increment the char count.
	inr	a
	sta	cmccnt
	jmp	cmky33

cmky34:	lda	cmccnt		;Get the character count.
	inr	a		;Increment and save it.
	sta	cmccnt
	xchg			;Put the command buffer pointer in HL.
	mvi	a,' '		;Get a blank.
	mov	m,a		;Put it in the command buffer.
	inx	h		;Increment the pointer
	shld	cmcptr		;Save the updated pointer.
	shld	cmdptr
	pop	h
	push	h
	xchg
	call	prtstr		;Print the rest of the keyword.
	mvi	c,conout
	mvi	e,' '
	call	bdos		;Print a blank.
	pop	h
	pop	b
	pop	d
	jmp	cmky37

cmky35:	push	h
	push	d
	call	cmambg
	 jmp	cmky36
	lxi	d,cmer01
	call	prtstr		;Say its ambiguous.
	jmp	prserr		;Give up.

cmky36:	pop	d
	pop	h
cmky37:	inr	e		;Add one incase it is negative.
	mvi	d,0
	dad	d		;Increment past the keyword.
	inx	h		;Past the $.
	mov	e,m		;Get the data.
	inx	h
	mov	d,m
	mov	a,e
	jmp	rskp

cmkey4:	cpi	'a'		;Is it less than a?
	jm	cmky41		;If so don't capitalize it.
	cpi	'z'+1		;Is it more than z?
	jp	cmky41		;If so don't capitalize it.
	ani	137O		;Capitalize it.
cmky41:	mov	d,m		;Get the next char of the keyword.
	inx	h
	cmp	d		;Match?
	jz	cmkey3		;If so get the next letter.

cmkey5:	mvi	d,0
	mov	a,e		;Get the number of chars left.
	ora	a		;Is it negative?
	jp	cmky51
	mvi	d,0FFH		;If so, sign extend.
cmky51:	dad	d		;Increment past the keyword.
	lxi	d,0003H		;Plus the $ and data.
	dad	d
	shld	cmkptr
	dcr	b		;Decrement the number of entries left.
	lhld	cmsptr		;Get the old cmdptr.
	shld	cmdptr		;Restore it.
;* check so we don't pass it.
	jmp	cmkey2		;Go check the next keyword.
;
;	Test keyword for ambiguity.
;	returns: nonskip if ambiguous, skip if OK.
;	called by: cmkeyw

cmambg:	dcr	b		;Decrement the number of entries left.
	rm			;If none left then it is not ambiguous.
	inr	e		;This is off by one;adjust.
	mov	c,e		;Save the char count.
	mov	a,e
	ora	a		;Any chars left?
	rz			;No, it can't be ambiguous.
	mvi	d,0
	dad	d		;Increment past the keyword.
	mvi	e,3		;Plus the $ and data.
	dad	d
	mov	b,m		;Get the length of the keyword.
	inx	h
	xchg
	lhld	cmkptr		;Get pointer to keyword entry.
	mov	a,m		;Get the length of the keyword.
	sub	c		;Subtract how many left.
	mov	c,a		;Save the count.
	cmp	b
	jz	cmamb0
	rp			;If larger than the new word then not amb.
cmamb0:	lhld	cmsptr		;Get the pointer to what parsed.
cmamb1:	dcr	c		;Decrement the count.
	jm	rskp		;If we are done then it is ambiguous.
	xchg			;Exchange the pointers.
	mov	b,m		;Get the next char of the keyword
	inx	h
	xchg			;Exchange the pointers.
	mov	a,m		;Get the next parsed char.
	inx	h
	cpi	'a'		;Is it less than a?
	jm	cmamb2		;If so don't capitalize it.
	cpi	'z'+1		;Is it more than z?
	jp	cmamb2		;If so don't capitalize it.
	ani	137O
cmamb2:	cmp	b		;Are they equal?
	rnz			;If not then its not ambiguous.
	jmp	cmamb1		;Check the next char.
;
;	cmofil - parse output filespec
;	cmifil - parse input filespec
;	here from: comnd

cmofil:	mvi	a,0		;Don't allow wildcards.
;	jmp	cmifil		;For now, the same as CMIFI.
cmifil:	sta	cmfwld		;Set wildcard flag
	xchg			;Get the fcb address.
	shld	cmfcb		;Save it.
	mvi	e,0		;Initialize char count.
	mvi	m,0		;Set the drive to default to current.
	inx	h
	shld	cmfcb2
	xra	a		;Initialize counter.
cmifi0:	mvi	m,' '		;Blank the FCB.
	inx	h
	inr	a
	cpi	0CH		;Twelve?
	jm	cmifi0
cmifi1:	call	cmgtch		;Get another char.
	ora	a		;Is it an action character?
	jp	cmifi2
	ani	7FH		;Turn off the action bit.
	cpi	'?'		;A question mark?
	jnz	cmif12
	lxi	h,cmaflg	;Blank the action flag.
	mvi	m,0
	lhld	cmcptr		;Increment the buffer pointer.
	inx	h		;(Gets decremented in 'cmgtch')
	shld	cmcptr
	lhld	cmdptr		;[jd] this is actually what is decremented
	inx	h		;[jd]
	shld	cmdptr		;[jd]
	jmp	cmifi8		;Treat like any other character.

cmif12:	cpi	esc		;An escape?
	jnz	cmif13
;Try to recognize file-spec a'la TOPS-20
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	mov	a,e		;Save character count up to now.
	sta	temp1
	cpi	9		;Past '.'?
	jm	cmfrec		;No.
	dcr	a		;Yes, don't count point.
cmfrec:	lhld	cmfcb2		;Fill the rest with CP/M wildcards.
cmfrc1:	cpi	11		;Done?
	jp	cmfrc2		;Yes.
	mvi	m,'?'
	inx	h
	inr	a
	jmp	cmfrc1

cmfrc2:	mvi	c,sfirst	;Find first matching file?
	lhld	cmfcb
	xchg
	call	bdos
	cpi	0FFH
	jz	cmfrc9		;No, lose.
	lxi	h,fcbblk	;Copy first file spec.
	call	fspcop
	lxi	h,fcbblk+10H	;Get another copy (in case not ambiguous).
	call	fspcop
	mvi	c,snext		;More matching specs?
	lhld	cmfcb
	xchg
	call	bdos
	cpi	0FFH
	jz	cmfrc3		;Only one.
	lxi	h,fcbblk+10H	;Copy second file spec.
	call	fspcop
cmfrc3:	lxi	d,fcbblk	;Start comparing file names.
	lxi	h,fcbblk+10H
	lda	temp1		;Bypass characters typed.
	cpi	9		;Past '.'?
	jm	cmfrc4		;No.
	dcr	a		;Yes, don't count point.
cmfrc4:	mvi	c,0
cmfrl1:	cmp	c		;Bypassed?
	jz	cmfrl2		;Yes.
	inx	d
	inx	h
	inr	c
	jmp	cmfrl1		;Repeat.

cmfrl2:	mov	a,c		;Get file name characters processed.
	cpi	11		;All done?
	jz	cmfrc5		;Yes.
	cpi	8		;End of file name?
	jnz	cmfrl3		;No.
	lda	temp1		;Exactly at point?
	cpi	9
	jz	cmfrl3		;Yes, don't output a second point.
	mvi	a,'.'		;Output separator.
	call	cmfput
cmfrl3:	ldax	d		;Get a character from first file spec.
	inx	d
	mov	b,m		;Get from second file spec.
	inx	h
	cmp	b		;Compare.
	jnz	cmfrc5		;Ambiguous.
	inr	c		;Same, count.
	cpi	' '		;Blank?
	jz	cmfrl2		;Yes, don't output.
	call	cmfput		;Put character into buffer.
	jmp	cmfrl2		;Repeat.

cmfrc5:	mov	a,c		;Get count of characters processed.
	sta	temp1		;Save it.
	mvi	a,'$'		;Get terminator.
	call	cmfput		;Put it into buffer.
	lhld	cmdptr		;Output recognized characters.
	xchg
	mvi	c,prstr
	call	bdos
	lhld	cmcptr		;Remove terminator from buffer.
	dcx	h
	shld	cmcptr
	lxi	h,cmccnt
	dcr	m
	lda	temp1		;Characters processed.
	cpi	11		;Complete file name.
	jz	repars		;Yes, don't beep.

cmfrc9:	mvi	c,conout
	mvi	e,bell
	call	bdos		;Ring the bell.
	jmp	repars
;
;	Continue file spec parsing.

cmif13:	mov	a,e		;It must be a terminator.
	ora	a		;Test the length of the file name.
	jz	cmifi9		;If zero complain.
	cpi	0DH
	jp	cmifi9		;If too long complain.
	jmp	rskp		;Otherwise we have succeeded.

cmifi2:	cpi	'.'
	jnz	cmifi3
	inr	e
	mov	a,e
	cpi	1H		;Any chars yet?
	jz	cmifi9		;No, give error.
	cpi	0AH		;Tenth char?
	jp	cmifi9		;Past it, give an error.
	mvi	c,9H
	mvi	b,0
	lhld	cmfcb
	dad	b		;Point to file type field.
	shld	cmfcb2
	mvi	e,9H		;Say we've gotten nine.
	jmp	cmifi1		;Get the next char.

cmifi3:	cpi	':'
	jnz	cmifi4
	inr	e
	mov	a,e
	cpi	2H		;Is it in the right place for a drive?
	jnz	cmifi9		;If not, complain.
	lhld	cmfcb2
	dcx	h		;Point to previous character.
	mov	a,m		;Get the drive name.
	sui	'@'		;Get the drive number.
	shld	cmfcb2		;Save pointer to beginning of name field.
	dcx	h		;Point to drive number.
	mov	m,a		;Put it in the fcb.
	mvi	e,0		;Start character count over.
	jmp	cmifi1

cmifi4:	cpi	'*'
	jnz	cmifi7
	lda	cmfwld		;Wildcards allowed?
	cpi	0
	jz	cmif11		;No,complain
	mov	a,e
	cpi	8H		;Is this in the name or type field?
	jz	cmifi9		;If its where the dot should be give up.
	jp	cmifi5		;Type.
	mvi	b,8H		;Eight chars.
	jmp	cmifi6

cmifi5:	mvi	b,0CH		;Three chars.
cmifi6:	lhld	cmfcb2		;Get a pointer into the FCB.
	mvi	a,'?'
	mov	m,a		;Put a question mark in.
	inx	h
	shld	cmfcb2
	inr	e
	mov	a,e
	cmp	b
	jm	cmifi6		;Go fill in another.
	jmp	cmifi1		;Get the next char.

cmifi7:	cpi	'0'
	jm	cmifi9
	cpi	'z'+1
	jp	cmifi9
	cpi	'A'		;Don't capitalize non-alphabetics.
	jm	cmifi8
	ani	137O		;Capitalize.
cmifi8:	lhld	cmfcb2		;Get the pointer into the FCB.
	mov	m,a		;Put the char there.
	inx	h
	shld	cmfcb2
	inr	e
	jmp	cmifi1

cmifi9:	lda	cmstat
	cpi	cmifin		;"silent"?
	jz	r		;Yes,let him go w/o check
	lxi	d,cmer02
cmif10:	mvi	c,prstr
	call	bdos
	ret

cmif11:	lxi	d,cmer03	;Complain about wildcards.
	jmp	cmif10

;

;	copy filename from buffer
;	called with HL = destination, A = position (0-3) in buffer
;	called by: cmifil

fspcop:	push	psw		;Save A.
	lxi	d,buff		;Get the right offset in the buffer.
	rlc
	rlc
	rlc
	rlc
	rlc
	add 	e
	inr	a		;Bypass drive spec.
	mov	e,a
	mvi	b,11		;Copy file name.
fspcp1:	ldax	d
	inx	d
	mov	m,a
	inx	h
	dcr	b
	jnz	fspcp1
	pop	psw		;Restore A.
	ret

;	append character in A to command buffer
;	called by: cmifil

cmfput:	push	h		;Save H.
	lhld	cmcptr		;Get buffer pointer.
	mov	m,a		;Store in buffer.
	inx	h
	shld	cmcptr
	lxi	h,cmccnt	;Count it.
	inr	m
	pop	h		;Restore H.
	ret
;
;	Read characters from the command buffer.
;	called by:  cmtext, cmcfrm, cmkeyw, cmifil

cmgtch:	push	h
	push	b
cmgtc1:	lda	cmaflg
	ora	a		;Is it set.
	cz	cminbf		;If the action char flag is not set get more.
	lhld	cmdptr		;Get a pointer into the buffer.
	mov	a,m		;Get the next char.
	inx	h
	shld	cmdptr
	cpi	' '		;Is it a space?
	jz	cmgtc2
	cpi	tab		;Or a tab?
	jnz	cmgtc3
cmgtc2:	lda	cmsflg		;Get the space flag.
	ora	a		;Was the last char a space?
	jnz	cmgtc1		;Yes, get another char.
	mvi	a,0FFH		;Set the space flag.
	sta	cmsflg
	mvi	a,' '
	pop	b
	pop	h
	jmp	cmgtc5

cmgtc3:	push	psw
	xra	a
	sta	cmsflg		;Zero the space flag.
	pop	psw
	pop	b
	pop	h
	cpi	esc
	jz	cmgtc5
	cpi	'?'		;Is the user curious?
	jz	cmgtc4
	cpi	cr
	jz	cmgtc4
	cpi	lf
	jz	cmgtc4
	cpi	ff
	rnz			;Not an action char, just return.
cmgtc4:	push	h
	lhld	cmdptr
	dcx	h
	shld	cmdptr
	pop	h
cmgtc5:	ori	80H		;Make the char negative to indicate it is
	ret			;a terminator.
;
;	Read characters from console into command buffer, processing
;	editing characters (^H, ^M, ^J, ^L, ^U, ^X, ?, del).
;	called by: comnd, cmgtch

cminbf:	push	psw
	push	d
	push	h
	lda	cmaflg		;Is the action char flag set?
	ora	a
	jnz	cminb9		;If so get no more chars.
cminb1:	lxi	h,cmccnt	;Increment the char count.
	inr	m
	mvi	c,conin		;Get a char.
	call	bdos
	lhld	cmcptr		;Get the pointer into the buffer.
	mov	m,a		;Put it in the buffer.
	inx	h
	shld	cmcptr
	cpi	25O		;Is it a ^U?
	jz	cmnb12		;Yes.
	cpi	30O		;Is it a ^X?
	jnz	cminb2
cmnb12:	call	clrlin		;Clear the line.
	call	prprmp		;Print the prompt  [Toad Hall]
	lxi	h,cmdbuf
	shld	cmcptr		;Reset the point to the start.
	lxi	h,cmccnt	;Zero the count.
	mvi	m,0
	jmp	repars		;Go start over.

cminb2:	cpi	10O		;Backspace?
	jz	cminb3
	cpi	del		;or Delete?
	jnz	cminb4
	call	delchr		;Print the delete string.
cminb3:	lda	cmccnt		;Decrement the char count by two.
	dcr	a
	dcr	a
	ora	a		;Have we gone too far?
	jp	cmnb32		;If not proceed.
	mvi	c,conout	;Ring the bell.
	mvi	e,bell
	call	bdos
	jmp	cmnb12		;Go reprint prompt and reparse.

cmnb32:	sta	cmccnt		;Save the new char count.
	call	clrspc		;Erase the character.
	lhld	cmcptr		;Get the pointer into the buffer.
	dcx	h		;Back up in the buffer.
	dcx	h
	shld	cmcptr
	jmp	repars		;Go reparse everything.

cminb4:	cpi	'?'		;Is it a question mark.
	jz	cminb6
	cpi	esc		;Is it an escape?
	jz	cminb6
	cpi	cr		;Is it a carriage return?
	jz	cminb5
	cpi	lf		;Is it a line feed?
	jz	cminb5
	cpi	ff		;Is it a formfeed?
	jnz	cminb1		;no - just store it and get another character.
	call	clrtop
cminb5:	lda	cmccnt		;Have we parsed any chars yet?
	cpi	1
	jz	prserr		;If not, just start over.
cminb6:	mvi	a,0FFH		;Set the action flag.
	sta	cmaflg
	jmp	cminb9

cminb9:	pop	h
	pop	d
	pop	psw
	ret
;
;Little utility to print the prompt.  (We do a LOT of these.)  [Toad Hall]
;Enters with nothing.
;Destroys HL (and I suppose B and DE and A).
 
prprmp:	lhld	cmprmp		;Get the prompt.
	xchg
	call	prtstr
	ret

IF	lasm
LINK	CP4UTL
ENDIF	;lasm  [Toad Hall]
