	.enabl	lsb
	.title	ttin	Terminal input
	.ident	"V02.00"
;+
; Index 	Terminal input
;
; Usage
;
;	length = ttise(buffer, size);
;	int length;		/* Number of bytes read */
;	char *buffer;   	/* Address of input buffer */
;	int size;		/* size of input buffer */
;
;
;	length = ttisne(buffer, size);
;	int length;		/* Number of bytes read */
;	char *buffer;   	/* Address of input buffer */
;	int size;		/* size of input buffer */
;
;
;	extern char ttice();
;	ch = ttice();
;	char ch;		/* returned character */
;
;
;	extern char tticne();
;	ch = tticne();
;	char ch;		/* returned character */
;
;
; Description
;
;	ttise() reads a maximum of "size" characters into "buffer"
;	echoing them on the terminal, and appends a null  (see the
;	NOTE below!) to the end of the just read string.
;
;	ttisne() reads a maximum of "size" characters into "buffer"
;	without echoing them on the terminal, and appends a null
;	(see the NOTE below!) to the end of the just read string.
;
;	Both ttise() and ttisne() return the number of characters
;	read (excluding the terminator such as <CR>) or 0 if
;	there was an error.
;
;	NOTE: The string in the buffer is null terminated, so be
;	sure there is room for the null ( i.e. the actual size of
;	the buffer must be at least 1 byte larger than the size
;	passed to the routine).  If the string read completes because
;	the buffer filled (as far as the QIO was concerned), there
;	MUST be room for the terminating null!
;
;	ttice() reads one character echoing it on on the terminal.
;	The actual character read is returned with the hi byte
;	cleared, or a 0 is returned if there was an error.
;
;	tticne() reads one character without echoing it on the terminal.
;	The actual character read is returned with the hi byte
;	cleared, or a 0 is returned if there was an error.
;
;	The ttice() and tticne() routines do NOT clear bit 7 (usually
;	the parity bit).
;
;	The single character input routines ttice() and tticne()
;	use the IO.RAL function, so that any 8-bit character may be
;	read without trapping and interpretation by the terminal
;	driver.  The exceptions to this are ^S and ^Q, which
;	are trapped by the ttic(n)e() routine(s) and used to manually
;	synchronize the terminal driver.
;
;	It is possible to get into a lockup or overrun condition with
;	terminals which automatically generate ^S and ^Q to
;	synchronize with the host computer when using the IO.RAL,
;	since both of these characters are passed to the program.
;
;	For instance, suppose the program sends something which
;	causes the terminal to send back a ^S, and then posts an
;	IO.RAL.  If the ^S arrives before the RAL gets queued to
;	the terminal driver, the ^S will cause terminal output to
;	be suspended, since the terminal driver has no reason to
;	do anything special with the ^S.  Now the RAL arrives and
;	shortly thereafter the terminal sends a ^Q, expecting
;	terminal output to be resumed.  But instead, the terminal
;	driver faithfully passes the ^Q to the program. Meanwhile,
;	the terminal driver still has output suspended, and the
;	terminal is never going to generate another ^Q on it's own.
;	The terminal will appear to have mysteriously locked up.
;
;	This and other scenarios make it wise to trap ^S and ^Q
;	within the CS library character input routines and issue
;	the appropriate SF.SMC function to suspend or resume terminal
;	output. The effect is to make the IO.RAL look like "read pass
;	almost all" (except for ^S and ^Q).  After processing the
;	^S or ^Q, the routine issues another read without returning
;	to the caller.
;
;-
; Edit History
; V02.00 19-Oct-82 TTC		Rework of CS library
;

	.psect	c$data

ch.spn:	.byte	TC.CTS,1		; SF.SMC char to suspend TIO
ch.rsm:	.byte	TC.CTS,0		; SF.SMC char to resume TIO
char:	.byte	0			; Character buffer
	.even

	.psect	c$code

ttice::
	mov	#IO.RAL,ttqio+q.iofn	; Function: IO.RAL
	mov	#ttice,-(sp)		; Remember for ^S/^Q code
	br	readch			; Branch to common char read code

ttise::
	mov	#IO.RLB,ttqio+q.iofn 	; Function: IO.RLB
	clr	-(sp)			; Fake for consistency
	br	readst			; Branch to common string read code

tticne::
	mov	#IO.RAL!TF.RNE,ttqio+q.iofn ; Function: IO.RAL
	mov	#tticne,-(sp)		; Remember for ^S/^Q code
	br	readch			; Branch to common char read code

ttisne::
	mov	#IO.RLB!TF.RNE,ttqio+q.iofn ; Function: IO.RLB
	clr	-(sp)			; Fake for consistency
	;
	; Falls through to common string read code
	;

readst:					; Common string read code
	mov	#ttqio+q.iopl,r0	; r0 --> qio param list for prmclr
	call	prmclr			; Clear qiow parameters
	mov	4(sp),ttqio+q.iopl   	; Parameter #1: Buffer addr.
	mov	6(sp),ttqio+q.iopl+2 	; Parameter #2: Buffer size
	br	common			; Branch to common read code

readch:					; Common character read code
	mov	#ttqio+q.iopl,r0	; r0 --> qio param list for prmclr
	call	prmclr			; Clear qiow parameters
	mov	#char,ttqio+q.iopl	; Parameter #1: Character buffer
	mov	#1,ttqio+q.iopl+2	; Parameter #2: Buffer size (1)
	;
	; Falls through to common read code
	;

common:					; Common read code
	mov	#ttqio,r0		; Put qio address in r0 for .xqiow
	call	.xqiow			; Execute qiow
	cmp	$dsw,#is.suc		; How'd things go?
	bne	20$			; Bad
	cmpb	t.iosb,#is.suc
	bne	20$
	mov	ttqio+q.iopl,r1		; r1 --> char or string buffer
	cmp	#char,r1		; Character read?
	beq	10$			; (Yes)
	mov	t.iosb+2,r0		; (No), r0 = # of bytes read
	add	r0,r1			; r1 --> end of string
	clrb	(r1)			; Tag on NULL
	br	25$			; Return

10$:	cmpb	char,#21		; ^Q ?
	beq	rsum			; (yes, resume terminal output)
	cmpb	char,#23		; ^S ?
	beq	spnd			; (yes, suspend terminal output)
	clr	r0			; Copy character without sign extend
	bisb	char,r0			;   (the efficient way)
	br	25$			; Return

20$:	clr	r0			; Error, r0 = 0
25$:	tst	(sp)+			; Clean off the stack
	return				; Retrun

rsum:	mov	#ch.rsm,r1		; Resume terminal output
	br	smc
spnd:	mov	#ch.spn,r1
smc:	mov	#ttqio+q.iopl,r0	; r0 --> qio param list for prmclr
	call	prmclr			; Clear qiow parameters
	mov	r1,ttqio+q.iopl   	; Buffer addr = characteristic pair
	mov	#2,ttqio+q.iopl+2 	; Buffer size = 2 bytes
	mov	#SF.SMC,ttqio+q.iofn 	; Function: SF.SMC
	mov	#ttqio,r0		; Put qio address in r0 for .xqiow
	call	.xqiow			; Execute qiow (tough if fails)
	jmp	@(sp)+			; Jump back for another try

	.end
