	.title	k11edi	Command line editing
	.ident	/3.52/

;	18-Jul-86  12:00:29  Brian Nelson
;
;	This code is used (currently) for the RSTS/E Command Line
;	Editor (CLE.RTS) written by the above author, and for 5.1
;	of MINITAB. The encryption calls are for the RSTS/E CLE.





	.iif ndf, $MINITAB, $MINITAB = 0

	.if eq	,$Minitab
	.if ndf, K11INC
	.ift
	.include	/IN:K11MAC.MAC/
	.endc
	.endc

	.enabl	gbl

	.psect	rwdata	,rw,d,lcl,rel,con
	.psect	CLECTX	,rw,d,gbl,rel,con
curpos:	.word	edipos
curlen:	.word	edilen
curcmd:	.word	edicmd
maxsiz:	.word	edisiz
clests:	.word	edists
enckey:	.word	$enckey
deckey:	.word	$deckey

	.if ne	,$Minitab
	.ift


	.macro	dump	v
	mov	v	,-(sp)
	call	o$dump
	.globl	o$dump
	.endm	dump

	CR	=	15
	LF	=	12

	LN$MAX	=	80.
	LN$CNT	=	3

	ER$EOF	==	-1
$lastl:	.blkb	<<LN$MAX+2>*LN$CNT>+2
lastli:	.word	$lastl	,$lastl+<1*<LN$MAX+2>>,$lastl+<2*<LN$MAX+2>>,0
lastcn:	.word	LN$CNT
edipos:	.word	0
edilen:	.word	0
edicmd:	.word	-1
edists:	.word	0
edikey:	.word	0
edisiz:	.word	LN$MAX
$enckey:
$deckey:

	TTY	=	0

	.endc					; If NE, $Minitab

	.psect	$pdata	,ro,d,lcl,rel,con

	.psect	$code	,i,ro,i,lcl,rel


	FALSE	=	0
	TRUE	=	1

	IN$MODE	=	1
	SET$VT1	=	2

	$DEBUG	=	0
	.iif ndf, $DEBUG, $DEBUG = 0




	.sbttl	Define macros

	.if ne	,$MINITAB
	.ift

	.MACRO	ENCRYPT	txt,key
	.ENDM	ENCRYPT

	.MACRO	DECRYPT	txt,key
	.ENDM	DECRYPT

	.MACRO	DEBUG	a,b,c
	.ENDM	DEBUG


	.MACRO	STRCPY	dst,src
	mov	src	,-(sp)
	mov	dst	,-(sp)
	jsr	pc	,strcpy
	.ENDM	STRCPY

	.MACRO	STRLEN	src
	mov	src	,-(sp)
	call	strlen
	.ENDM	STRLEN

	.MACRO	SCAN	ch,str
	mov	str	,-(sp)
	clr	-(sp)
	bisb	ch	,@sp
	call	scanch
	.ENDM	SCAN

	.MACRO	SAVE	list
	.if b , <list>
	.ift
	 SAVE	<r0,r1,r2,r3,r4,r5>
	.iff
	.irp	x,<list>
	 mov	x,-(sp)
		.endr
	.endc
	.ENDM	SAVE


	.MACRO	UNSAVE	list
	.if b , <list>
	.ift
	UNSAVE	<r5,r4,r3,r2,r1,r0>
	.iff
	.irp	x,<list>
	 mov	(sp)+,x
		.endr
	.endc
	.ENDM	UNSAVE

	.MACRO	GLOBAL	LIST
	.GLOBL	LIST
	.ENDM	GLOBAL


	.iff				; Kermit or CLE

	.MACRO	ENCRYPT	txt,key
	mov	key	,-(sp)
	mov	txt	,-(sp)
	call	ENCRYPT
	.endm	ENCRYPT

	.MACRO	DECRYPT	txt,key
	mov	key	,-(sp)
	mov	txt	,-(sp)
	call	DECRYPT
	.endm	DECRYPT


	.MACRO	DEBUG	txt,sts=1,docr=1
	.if ne	,$DEBUG
	.if ne	,sts
	.save
	.psect	$pdata
	$$ = .
	.if b	,<txt>
	.ift
	.byte	15,12,0
	.iff
	.asciz	@txt@
	.endc
	.even
	.restore
	mov	#$$	,-(sp)		; dump the text next please
	CALL	mout			; to the terminal
	.globl	mout			; perhaps
	.if nb	,<txt>
	.ift
	.iif nb,docr, message
	.endc
	.endc
	.endc
	.endm	DEBUG

	.endc				; if NE, $Minitab

	.macro	WRTALL	arg		; IO.WAL for an .asciz string
	mov	arg	,-(sp)		; Pass the address
	call	wrtall			; Do it
	GLOBAL	<wrtall>		; Insure globalized
	.endm	WRTALL			; Done


	.enabl	lsb

Kbredi::.iif ne, $MINITAB, mov	r1,-(sp);
	.iif ne, $MINITAB, mov	r5,-(sp);
	SAVE	<r2,r3,r4>		; Save
	cmpb	vttype	,#TTY		; Not a VT100 or VT2xx?
	bne	10$			; No, try editing
	.if ne	,$MINITAB		; Minitab today?
	.ift				; Yes
	sec				; Just set carry and exit
	.iff				; Kermit or CLE
	WRTALL	@r5			; Prompt
	CALLS	kbread	,<2(r5)>	; Hardcopy, use vanilla reads
	.endc				; All done
	br	100$			; Exit
10$:	WRTALL	#$cr			;
	WRTALL	@r5			;
	bit	#SET$VT1,@clests	; Insure terminal in VT100 mode
	bne	15$			; Already did it
	WRTALL	#$setvt1		; Not done, do so
	bis	#SET$VT1,@clests	; Flag as having been done
15$:	clr	@curpos			; Assume at start of the line.
	clr	@curlen			; No length
	mov	2(r5)	,r4		; Buffer address
	clrb	@r4			; Insure starting with .ASCIZ
20$:	CALL	read1ch			; Read one character now
	mov	r0	,r3		; Any data persent?
	beq	90$			; Yes, treat as a control Z
	SCAN	r3	,#scanlst	; Look for a match
	asl	r0			; And dispatch
	jsr	pc	,@scandsp(r0)	; Do it
	bcs	20$			; Not done
	.iif ne, $MINITAB, mov	r1,r0	;
	br	100$			; Done
					;
90$:	mov	#ER$EOF	,r0		; Error, return END_OF_FILE
	clr	r1			; And no data
100$:	UNSAVE	<r4,r3,r2>		; Exit
	.iif ne, $MINITAB, mov 	(sp)+,r5;
	.iif ne, $MINITAB, mov 	(sp)+,r1;
	return

	.dsabl	lsb


	.save
	.psect	$pdata	
scanlst:.byte	'H&37	,'E&37	,'B&37	,'U&37	,'Z&37	,CR	,LF
	.byte	'I&37	,177	,33	,233	,'R&37	,'X&37	,'C&37
	.byte	'A&37
	.byte	0
	.even

scandsp:.word	INSCH
	.word	SOL	,EOL	,PREV	,CTRLU	,EOF	,NOOP	,DONE
	.word	NOOP	,DORUB	,DOESC	,DO220	,RETYPE	,CANTYP	,CTRLC
	.word	TOGGLE
esclst:	.byte	'A&137	,'B&137	,'C&137	,'D&137	,0
	.even
escdsp:	.word	NOOP
	.word	PREV	,NEXT	,RIGHT	,LEFT

$cc:	.asciz	/^C/
$cz:	.asciz	/^Z/
$bs:	.byte	'H&37,0
$cr:	.byte	15,0
$right:	.asciz	<33>/[C/
$left:	.asciz	<33>/[D/
$save:	.asciz	<33>/7/
$resto:	.asciz	<33>/8/
$ceol:	.asciz	<33>/[K/
$crlf:	.byte	CR,LF,0
$rrub:	.byte	10,40,10,0
$setvt:	.byte	33,'<
	.even
	.restore




Doesc:	DEBUG	<Doesc>			; ...
	CALL	read1ch			; Get next in esc seq
Do220:	DEBUG	<Do220>			; You know
	CALL	read1ch			; Ditto
	mov	r0	,r3		; Get the data
	beq	90$			; Error Exit
	SCAN	r3	,#esclst	; Process the character
 	asl	r0			; Convert to word offset
	jsr	pc	,@escdsp(r0)	; Do it
	br	100$			; Ok
90$:	sec				; Failure on the READ
100$:	return				; And Exit

Noop:	DEBUG	<Noop>			; ...
	sec				; Ignore
	return				; And Exit

Insch:	DEBUG	<Insch>,FALSE		; ...
	sub	#200	,sp		; A temp buffer
	mov	sp	,r2		; A pointer to it
	tst	r3			; Null?
	beq	100$			; Ignore
	cmp	@curlen	,@maxsiz	; Too many chars?
	blo	10$			; No
	CALL	done			; Yes, exit
	br	100$			; Bye
10$:	inc	@curlen			; Save this
	mov	@curpos	,r1		; Get the offset into line
	add	r4	,r1		; Where to stuff the data
	tstb	@r1			; Already at end of line?
	beq	20$			; Yes, we have the stop to stuff it
	bit	#IN$MODE,@clests	; Insert or overstrike?
	bne	15$			; Insert
	movb	r3	,(r1)+		; Overstrike
	br	30$			; Exit
15$:	STRCPY	r2	,r1		; No, so save the data now
	movb	r3	,(r1)+		; And insert the new character
	STRCPY	r1	,r2		; And put the trailing data back in.
	br	30$			; Now for the echoing
20$:	movb	r3	,(r1)+		; Already at eol, insert
	clrb	@r1			; And insure .ASCIZ
	dec	r1			; ...
	WRTALL	r1			; Echo
	br	90$			; Exit
30$:	WRTALL	#$save			; Save cursor pos
	dec	r1			; Back to to the new character
	WRTALL	r1			; Dump the data
	WRTALL	#$restore		; Put the cursor back now
	WRTALL	#$right			; Move over on the display
90$:	inc	@curpos			; Move over one
100$:	add	#200	,sp		; Pop buffer
	sec				; Not done
	return				; Exit



	.sbttl	More line editing routines


;	SOL	Move to start of line (Control H)

Sol:	DEBUG	<Sol>			; ...
	tst	@curpos			; Stop when at position 0
	ble	100$			; Done
	WRTALL	#$bs			; Move
	dec	@curpos			; Fix position
	br	sol			; Next please
100$:	clr	@curpos			; Insure correct
	sec				; Not done
	return				; Exit



;	EOL	Move to End of Line, Control E


Eol:	DEBUG	<Eol>			; ...
	STRLEN	r4			; Find string length
10$:	cmp	@curpos	,r0		; End yet?
	bhis	100$			; Yes
	WRTALL	#$right			; No
	inc	@curpos			; Fix this
	br	10$			; Next
100$:	sec				; Not done
	return				; Exit

Gotoeol:STRLEN	r4			; Find string length
10$:	cmp	@curpos	,r0		; End yet?
	bhis	100$			; Yes
	inc	@curpos			; Fix this
	br	10$			; Next
100$:	return				; Exit

;	EOF	Control Z on input

	.enabl	lsb			; Temp

Ctrlc:	DEBUG	<Control C>		; ...
	WRTALL	#$cc			; Echo a control C
	br	100$			; Common exit now

Eof:	DEBUG	<Eof>			; ...
	WRTALL	#$cz			; Echo a control Z
	.if ne	,$MINITAB		;
	WRTALL	#$crlf			;
	.endc				;
100$:	mov	#ER$EOF	,r0		; Control Z
	clr	r1			; And return byte count of zero
	clc				; All done
	return				; Exit

	.dsabl	lsb			; Done
	.enabl	lsb



	.sbttl	Carriage return (actually LF) processing

;	Done.	CR on input, store new line and bubble previous ones back

Done:	mov	r5	,-(sp)		; A scratch register we need
	DEBUG	<Done>			; ...
	WRTALL	#$crlf			;
	STRLEN	r4			; Get byte count (we have CR or LF)
	mov	r0	,r1		; Return it
	beq	90$			; Nothing there, don't copy it.
	clr	r2			; The index
	mov	lastcnt	,r3		; Number of lines to do
10$:	mov	lastli(r2),r0		; Look to find a free spot.
	tstb	@r0			; Empty?
	beq	60$			; Yes
	add	#2	,r2		; No, keep looking
	sob	r3	,10$		; ....
					; No room for command line.
	clr	r2			; The index
	mov	r4	,-(sp)		; Save it
	mov	lastcnt	,r3		; Number of lines to do
	dec	r3			; ...
	asl	r3			; See if this is same as last
	mov	lastli(r3),r5		; Current address
	inc	r5			; Skip the length
	mov	r5	,-(sp)		; Save
	DECRYPT	r5,deckey		; Undo the old line
	STRLEN	r4			; Length
	cmpb	-1(r5)	,r0		; Same length
	bne	20$			; No
15$:	cmpb	(r4)+	,(r5)+		; Check for string equality
	bne	20$			; Not the same
	sob	r0	,15$		; Same, check next
20$:	mov	(sp)+	,r5		; Restore old text pointer
	mov	(sp)+	,r4		; Restore the current pointer
	ENCRYPT	r5,enckey		; Restore the data
	asr	r3			; Restore r3
	tst	r0			; Same ?
	bne	30$			; No
	mov	r3	,@curcmd	; Yes, save index
	br	100$			; Exit
30$:
40$:	mov	lastli(r2),r0		; Counted string format
	mov	lastli+2(r2),r1		; Again
	movb	(r1)	,(r0)+		; Copy the string length
	beq	55$			; Can't happen, but may as well check
	clr	r5			; Counter for the copy operation
	bisb	(r1)+	,r5		; Copy the byte count
50$:	movb	(r1)+	,(r0)+		; Copy the string now
	sob	r5	,50$		; Next
55$:	add	#2	,r2		; Move up
	sob	r3	,40$		; Next please
					;
60$:	mov	lastli(r2),r1		; Copy the line at last
	STRLEN	r4			; Get the line length
	mov	@maxsiz	,r3		; For padding with spaces
	movb	r0	,(r1)+		; Copy the length
	beq	80$			; Nothing
	mov	r4	,r5		; Source string
	mov	r1	,-(sp)		; Save text address
70$:	movb	(r5)+	,(r1)+		; Copy the data now
	dec	r3			; Keep track of remaining space
	beq	75$			; No room left
	sob	r0	,70$		; Next please
74$:	movb	#40	,(r1)+		; Now space fill the line
	sob	r3	,74$		; Next please
75$:	mov	(sp)+	,r1		; Restore text address
	ENCRYPT	r1,enckey		; Encode it
80$:	asr	r2			; Set 'Current' Command index
	mov	r2	,@curcmd	; And save it
	br	100$			; Exit
90$:	movb	#CR	,@r4		; Return only a carriage return
	clrb	1(r4)			; .ASCIZ
100$:	STRLEN	r4			; Get line length
	mov	r0	,r1		; Where to return it.
	clr	r0			; No errors
	mov	(sp)+	,r5		; Restore r5
	clc				; All done
	return				; Exit

	.dsabl	lsb




;	PREV:	Recall previous command line, UP-Arrow Key.

Prev:	DEBUG	<Prev>			; ...
	mov	r5	,-(sp)		; Save it
10$:	mov	@curcmd	,r2		; Current command number
	blt	100$			; Never been here.
	CALL	sol			; Back up
	WRTALL	#$cr			; Start of line
	WRTALL	#$ceol			; Clear
	WRTALL	@r5			; Prompt
	asl	r2			; We want addresses today
	mov	lastli(r2),r2		; At last
	tstb	@r2			; Anything to copy?
	bne	20$			; Yes
	dec	@curcmd			; No, back up again
	bge	10$			; Ok
	clr	@curcmd			; Reached the end
	br	100$			; And exit
20$:	clrb	@r4			; TO be safe
	clr	r3			; Get length next
	bisb	(r2)+	,r3		; Do it
	beq	50$			; Nothing?
	mov	@maxsiz	,r0		; Copy all for DES types
	mov	r4	,r5		; A copy of the destination
30$:	movb	(r2)+	,(r5)+		; Copy it
	sob	r0	,30$		; Next please
	DECRYPT	r4,deckey		; Decode the data
	add	r4	,r3		; Point to the real end of data
	clrb	@r3			; Insure .asciz
	WRTALL	r4			; Echo it
50$:	CALL	gotoeol			; Move to end of the line
	STRLEN	r4			; Get length
	mov	r0	,@curlen	; And save it
	tst	@curcmd			; Check for underflow
	ble	100$			; Yes, exit
	dec	@curcmd			; No, backup now.
	br	100$			; Exit
90$:	clrb	@r4			; Nothing, kill the buffer
100$:	sec				; Not done yet
	mov	(sp)+	,r5		; Restore this
	return				; Exit


;	Control U:	Erase entire line

Ctrlu:	DEBUG	<Ctrlu>			; ...
	CALL	sol			; Move to start of the line
	WRTALL	#$ceol			; Erase to the end of the line
	clrb	@r4			; No data left over
	clr	@curlen			; No length
	sec				; Not done
	return				; Exit

Right:	DEBUG	<Right>			; ...
	STRLEN	r4			; Get current length of the line
	cmp	@curpos	,r0		; Already at EOL?
	bhis	100$			; Yes
	inc	@curpos			; No, move over
	WRTALL	#$right			; Simple to do.
100$:	sec				; Not done
	return				; Exit



	.sbttl	Rubouts and move left

;	DORUB:	Erase character

Dorub:	DEBUG	<Dorub>,FALSE		; ...
	sub	#200	,sp		; Allocate a buffer again
	mov	sp	,r3		; And a pointer to such.
	tstb	@r4			; Is there ANYTHING in the line?
	beq	100$			; No, it's a NO-OP
	tst	@curpos			; Already at SOL (start of line)?
	bgt	10$			; No
	clr	@curpos			; Insure correct position
	clr	@curlen			; Save this
	br	20$			; Off to common code
10$:	mov	r4	,r2		; See if at eoln
	add	@curpos	,r2		; Compute address
	dec	@curpos			; Correct offset now
	dec	@curlen			; Fix this up
	movb	@r2	,-(sp)		; Get current
	beq	20$			; Nothing to do
	WRTALL	#$LEFT			; Go back one please
20$:	mov	r4	,r2		; And move down
	add	@curpos	,r2		; Point to CURRENT character
	mov	r2	,r1		; Again
	inc	r1			; Next position please
	STRCPY	r3	,r1		; Make a temporary copy of the data
	STRCPY	r2	,r3		; Move it down
	tstb	(sp)+			; Were we already at EOL?
	bne	30$			; No
	WRTALL	#$rrub			; Use simple style BS SP BS if EOL
	br	100$			; Exit
30$:	WRTALL	#$save			; Save cursor position
	WRTALL	#$ceol			; Erase to EOL
	WRTALL	r2			; Dump buffer
	WRTALL	#$restore		; And go back
100$:	add	#200	,sp		; Pop local buffer and Exit
	sec				; Not done
	return				; Exit


;	Left:	Move left one character

Left:	DEBUG	<Left>			; ...
	tst	@curpos			; Can we back up ?
	ble	100$			; No
	dec	@curpos			; Yes, backup a bit
	WRTALL	#$left			; And do so.
100$:	sec				; Not done
	return				; Exit


	.sbttl	Command recall and control R processing

Next:	DEBUG	<Next>			; ...
	mov	r5	,-(sp)		; Save
	mov	curcmd	,r2		; Point to CURCMD
	tst	@r2			; Current command number
	blt	100$			; Never been here.
	mov	lastcnt	,-(sp)		; Get the recall buffer count
	dec	(sp)			; ...
	cmp	@r2	,(sp)+		; Can we move up?
	bge	100$			; No
	inc	@r2			; Yes, move up.
	CALL	sol			; Back up
	WRTALL	#$cr			; Start of line
	WRTALL	#$ceol			; Clear
	WRTALL	@r5			; Prompt
	mov	@r2	,r2		; Copy it.
	asl	r2			; We want addresses today
	mov	lastli(r2),r2		; At last
	tstb	@r2			; Anything to copy?
	beq	90$			; No
					;
	clrb	@r4			; TO be safe
	clr	r3			; Get length next
	bisb	(r2)+	,r3		; Do it
	mov	@maxsiz	,r0		; Copy ALL for DES type routines
	mov	r4	,r5		; A copy of the destination
30$:	movb	(r2)+	,(r5)+		; Copy it
	sob	r0	,30$		; Next please
	DECRYPT	r4,deckey		; Decode the data
	add	r4	,r3		; Point to the real end of data
	clrb	@r3			; And force to .ASCIZ
	WRTALL	r4			; Dump the data
	call	gotoeol			; Fix internal pointers
	STRLEN	r4			; Get last line length
	mov	r0	,@curlen	; And save it
	mov	lastcnt	,-(sp)		; Get the recall buffer count
	dec	(sp)			; ...
	cmp	@curcmd	,(sp)+		; Poised at the last command?
	bne	100$			; No
	dec	@curcmd			; Fix so PREV works correctly.
	br	100$			; Exit
90$:	clrb	@r4			; Nothing, kill the buffer
100$:	sec				; Not done yet
	mov	(sp)+	,r5		; Restore
	return				; Exit



Retype:	DEBUG	<Retype>		; ...
	WRTALL	#$cr			; Start of line
	WRTALL	#$ceol			; Clear
	WRTALL	@r5			; Prompt
	WRTALL	r4			; Dump the buffer
	WRTALL	#$cr			; Back up again
	STRLEN	@r5			; Get a new poistion now
	add	@curpos	,r0		; Get to correct position
	beq	100$			; Nothing (?)
10$:	WRTALL	#$right			; Move over
	sob	r0	,10$		; Simple
100$:	sec				; Not yet done
	return				; Exit

Cantyp:	call	clrcns			; Eat up console data
	sec				; Not done
	return				; Exit

Toggle:	mov	#IN$MODE,r0		; Toggle modes
	xor	r0	,@clests	; Do it
	sec				; Not done
	return				; Exit



	.sbttl	Utilities

	.if ne	,$MINITAB
	.ift

Strlen:	mov	2(sp)	,r0		; Get string length
10$:	tstb	(r0)+			; Look for end
	bne	10$			; Not yet
	sub	2(sp)	,r0		; Compute length
	dec	r0			; Fix
	mov	(sp)+	,(sp)		; Pop stack
	return				; Exit

;	Strcpy
;
;	input:
;		0(sp)	return address
;		2(sp)	dst address
;		4(sp)	src address
;	output:	r0	dest address


Strcpy:	save	<r1>			; save temp registers please
	mov	2+2(sp)	,r0		; destination address
	mov	2+4(sp)	,r1		; source .asciz address
10$:	movb	(r1)+	,(r0)+		; copy until a null
	bne	10$			; not done
	mov	2+2(sp)	,r0		; return the dst address
	unsave	<r1>			; pop r1 and exit
	mov	(sp)	,4(sp)		; move return address up now
	cmp	(sp)+	,(sp)+		; pop junk and exit
	return

;	S C A N C H 
;
;	input:	4(sp)	the string address
;		2(sp)	the character to look for
;	output:	r0	position of ch in string


Scanch:	save	<r2>			; save temps
	mov	6(sp)	,r2		; get address of the string
	clr	r0			; initial found position
10$:	tstb	@r2			; end of the string yet ?
	beq	90$			; yes
	inc	r0			; no, pos := succ(pos)
	cmpb	4(sp)	,(r2)+		; does the ch match the next one?
	bne	10$			; no, try again
	br	100$			; yes, exit loop
90$:	clr	r0			; failure, return postion = 0
100$:	unsave	<r2>			; pop r2
	mov	@sp	,4(sp)		; move return address up
	cmp	(sp)+	,(sp)+		; pop stack
	return				; and exit

	.endc				; If NE, $Minitab

	.end
