	.TITLE	TTYIO	TERMINAL I/O PACKAGE
	.IDENT	/1.0/			;FILE: "TTYIO.MAR"

;
;	COPYRIGHT (C) 1979
;		MANAGEMENT SCIENCE ASSOCIATES, INC.
;		5100 CENTRE AVENUE
;		PITTSBURGH, PENNSYLVANIA  15232
;
;	THIS SOFTWARE IS DISTRIBUTED WITHOUT COST, AND MAY BE
;	REPRODUCED ONLY WITH THE INCLUSION OF THIS COPYRIGHT
;	STATEMENT.  MANAGEMENT SCIENCE ASSOCIATES ASSUMES NO
;	RESPONSIBILITY FOR THE PERFORMANCE OF THIS SOFTWARE.
;

;++
;	TTYIO
;
;	DEC-10 TERMINAL I/O EMULATION (ALMOST) PACKAGE
;	 (SEE TTYIO.DOC FOR DETAILS)
;--

; DEFINE EXTERNAL SYMBOLS
	$IODEF				;DEFINE I/O SYMBOLS
	$CLIDEF				;DEFINE CLI SYMBOLS FOR RESCAN

; STANDARD EXTERNAL ENTRY PROLOGUE MACRO
	.MACRO	HELLO	ENTPNT,?L	;;ARGUMENT IS ENTRY NAME
	ENTPNT'$::			;;ESTABLISH GLOBAL ENTRY
		.WORD	^M<R0,R1,R2>	;;SAVE MASK FOR ALL ENTRIES
		MOVAL	TTYIODATA,R2	;;ESTABLISH DATA BASE ADDRESS
		CMPW	#-1,CHANNL(R2)	;;CHECK FOR FIRST TIME ENTERED
		BNEQ	L		;;NOT -1 SO PRESUME REAL
		BSBW	GETCHN		;;CALL GET CHANNEL SUBROUTINE
	L:				;;JOIN FOLLOWING CODE
		.ENDM	HELLO		;;
	.PAGE
	.SBTTL	PROTOTYPE IMPURE AREA

	.PSECT	$TTYIODATA	PIC,OVR,REL,GBL,SHR,NOEXE,RD,WRT,PAGE
TTYIODATA:				;PAGE BASE ADDRESS - ALL SYMBOLS
					; ARE OFFSETS FROM THIS BASE
					;
CHANNL=.-TTYIODATA			;THE CHANNEL TO TERMINAL TTYNAM
	.WORD	-1			; ESTABLISHED BY GETCHN
					;
BUFPTR=.-TTYIODATA			;OFFSET FROM BUFFER OF LAST CHAR
	.BLKW	1			; DELIVERED - SET TO -1 RESCANS
					;
INPCHX=.-TTYIODATA			;INPUT CHARACTERISTICS - MODIFIERS
	.BLKW	1			; FOR QIO IO$_READVBLK FUNCTION
OUTCHX=.-TTYIODATA			;OUTPUT CHARACTERISTICS- MODIFIER
	.BLKW	1			; FOR QIO IO$_WRITEVBLK FUNCTION
					; REFERENCED AS PART OF INPCHX IN
					; THE CHARACTERISTICS LONGWORD
					;
STATUS=.-TTYIODATA			;STATUS RETURNED HERE AS PART OF
	.BLKW	1			; QUADWORD FROM QIO IOSB PARAMETER
					; ON INPUT (IO$_READVBLK).   KEEP
					; THIS QUAD BLOCK INVARIANT TO OUTPUT
XFRCNT=.-TTYIODATA			;UPDATED BY ADDITION OF TRMLEN
	.BLKW	1			; AFTER BLOCK RETURNED FROM QIO
					; TO HAVE THE NUMBER OF CHARS
					; IN THE LINE BUFFER
TRMCHR=.-TTYIODATA			;TERMINATING CHAR
	.BLKW	1			; (UNREFERENCED)
TRMLEN=.-TTYIODATA			;NUMBER OF CHARS IN ADDITION TO
	.BLKW	1			; QIO VALUE OF XFRCNT ACTUALLY
					; PLACED IN BUFFER BY QIO
					;
BUFFER=.-TTYIODATA			;LINE BUFFER BASE ADDRESS
BUFLEN=512-BUFFER			;LENGTH OF BUFFER SELECTED TO
					; BE AS LARGE AS POSSIBLE WITH
					; THE CONFINES OF A PAGE
	.BLKB	BUFLEN			;A BUNCH OF CHARACTERS LIVE HERE
	.PAGE
	.PSECT	$TTYIOCODE	PIC,CON,REL,LCL,SHR,EXE,RD,NOWRT,LONG

	.SBTTL	GETCHN AND ERROR ROUTINES

TTYNAM:	.ASCID	/TT/			;GENERIC TERMINAL NAME

GETCHN:	$ASSIGN_S	DEVNAM=TTYNAM,CHAN=CHANNL(R2) ;GET TTY CHANNEL
	BLBC	R0,99$			;
	MCOMW	#0,XFRCNT(R2)		;-1 BYTES IN BUFFER INITIALLY
	MCOMW	#0,BUFPTR(R2)		;NEXT BYTE HAS ZERO OFFSET
	MOVL	#<<<IO$M_NOFORMAT>@16>!-
		<IO$M_CVTLOW>>,INPCHX(R2) ;SET DEFAULT CHARACTERISTICS
	RSB				;RETURN
99$:					;FALL THROUGH TO TERROR

TERROR:	$EXIT_S	R0			;GENERAL ERROR RESPONSE
	.PAGE
	.SBTTL	GETCHR	GET CHAR ARGUMENT

GETCHR:	CASEL	4(AP),#0,#11		;CHECK FOR ARG IN REGISTER
1$:	.WORD	GETR0-1$
	.WORD	GETR1-1$
	.WORD	GETR2-1$
	.WORD	GETR3-1$
	.WORD	GETR4-1$
	.WORD	GETR5-1$
	.WORD	GETR6-1$
	.WORD	GETR7-1$
	.WORD	GETR8-1$
	.WORD	GETR9-1$
	.WORD	GETR10-1$
	.WORD	GETR11-1$
GETADR:	MOVZBL	@4(AP),R0		;GET BYTE FROM MEMORY
	RSB				;RETURN
GETR0:	MOVL	20(FP),R0		;ORIGINAL R0 FROM STACK
	RSB				;RETURN
GETR1:	MOVL	24(FP),R0
	RSB
GETR2:	MOVL	28(FP),R0
	RSB
GETR3:	MOVL	R3,R0
	RSB
GETR4:	MOVL	R4,R0
	RSB
GETR5:	MOVL	R5,R0
	RSB
GETR6:	MOVL	R6,R0
	RSB
GETR7:	MOVL	R7,R0
	RSB
GETR8:	MOVL	R8,R0
	RSB
GETR9:	MOVL	R9,R0
	RSB
GETR10:	MOVL	R10,R0
	RSB
GETR11:	MOVL	R11,R0
	RSB
	.PAGE
	.SBTTL	RETCHR	RETURN CHAR FROM BUFFER

RETCHR:	MOVZWL	BUFPTR(R2),R0		;GET BUFFER OFFSET OF CHAR
	MOVZBL	BUFFER(R2)[R0],R0	;GET CHAR IN R0
	CASEL	4(AP),#0,#11		;SELECT CHAR DESTINATION
1$:	.WORD	RETR0-1$
	.WORD	RETR1-1$
	.WORD	RETR2-1$
	.WORD	RETR3-1$
	.WORD	RETR4-1$
	.WORD	RETR5-1$
	.WORD	RETR6-1$
	.WORD	RETR7-1$
	.WORD	RETR8-1$
	.WORD	RETR9-1$
	.WORD	RETR10-1$
	.WORD	RETR11-1$
RETADR:	MOVB	R0,@4(AP)
	RET
RETR0:	MOVL	R0,20(FP)
	RET
RETR1:	MOVL	R0,24(FP)
	RET
RETR2:	MOVL	R0,28(FP)
	RET
RETR3:	MOVL	R0,R3
	RET
RETR4:	MOVL	R0,R4
	RET
RETR5:	MOVL	R0,R5
	RET
RETR6:	MOVL	R0,R6
	RET
RETR7:	MOVL	R0,R7
	RET
RETR8:	MOVL	R0,R8
	RET
RETR9:	MOVL	R0,R9
	RET
RETR10:	MOVL	R0,R10
	RET
RETR11:	MOVL	R0,R11
	RET
	.PAGE
	.SBTTL	GTSPTR	GET STRING POINTER

GTSPTR:	CMPL	#11,4(AP)		;CHECK FOR REGISTER LOCATION
	BGEQU	GTSNTR			;XFER IF STRING IN REGISTER(S)
	MOVL	4(AP),R0		;STRING ADDRESS TO R0
	RSB				;RETURN
GTSNTR:	MOVL	(SP),R1			;SAVE RETURN ADDRESS
	PUSHL	#0			;ASSURE STRING ENDS WITH NULL
	CASEL	4(AP),#0,#11		;SELECT STARTING REGISTER
1$:	.WORD	GTSR0-1$
	.WORD	GTSR1-1$
	.WORD	GTSR2-1$
	.WORD	GTSR3-1$
	.WORD	GTSR4-1$
	.WORD	GTSR5-1$
	.WORD	GTSR6-1$
	.WORD	GTSR7-1$
	.WORD	GTSR8-1$
	.WORD	GTSR9-1$
	.WORD	GTSR10-1$
	.WORD	GTSR11-1$
GTSR0:	PUSHR	#^M<R3,R4,R5,R6,R7,R8,R9,R10,R11>
	PUSHL	28(FP)
	PUSHL	24(FP)
	PUSHL	20(FP)
	BRB	GTSXIT
GTSR1:	PUSHR	#^M<R3,R4,R5,R6,R7,R8,R9,R10,R11>
	PUSHL	28(FP)
	PUSHL	24(FP)
	BRB	GTSXIT
GTSR2:	PUSHR	#^M<R3,R4,R5,R6,R7,R8,R9,R10,R11>
	PUSHL	28(FP)
	BRB	GTSXIT
GTSR3:	PUSHR	#^M<R3,R4,R5,R6,R7,R8,R9,R10,R11>
	BRB	GTSXIT
GTSR4:	PUSHR	#^M<R4,R5,R6,R7,R8,R9,R10,R11>
	BRB	GTSXIT
GTSR5:	PUSHR	#^M<R5,R6,R7,R8,R9,R10,R11>
	BRB	GTSXIT
GTSR6:	PUSHR	#^M<R6,R7,R8,R9,R10,R11>
	BRB	GTSXIT
GTSR7:	PUSHR	#^M<R7,R8,R9,R10,R11>
	BRB	GTSXIT
GTSR8:	PUSHR	#^M<R8,R9,R10,R11>
	BRB	GTSXIT
GTSR9:	PUSHR	#^M<R9,R10,R11>
	BRB	GTSXIT
GTSR10:	PUSHR	#^M<R10,R11>
	BRB	GTSXIT
GTSR11:	PUSHL	R11
GTSXIT:	MOVL	SP,R0			;STRING ADDRESS TO R0
	JMP	(R1)			;RETURN
	.PAGE
	.SBTTL	INCHRW	INPUT CHAR WAIT

	HELLO	INCHRW			;ESTABLISH ENTRY AND CHANNEL
	INCW	BUFPTR(R2)		;POINTER TO NEXT CHAR
	CMPW	BUFPTR(R2),XFRCNT(R2)	;PAST END OF DATA?
	BGEQ	1$			;YES, NEED TO READ TTY
	BRW	RETCHR			;NO, RETURN CHAR POINTED TO
1$:	BISW3	#IO$_READVBLK,INPCHX(R2),R0 ;INCLUDE CHARACTERISTICS
	$QIOW_S	CHAN=CHANNL(R2),FUNC=R0,IOSB=STATUS(R2),-
		P1=BUFFER(R2),P2=#1	;READ ONE BYTE
	BLBC	R0,99$			;
	CLRW	BUFPTR(R2)		;ZERO OFFSET TO NEW CHAR
	MOVW	#1,XFRCNT(R2)		;ONE BYTE IN BUFFER
	BRW	RETCHR			;RETURN CHAR TO CALLER
99$:	BRW	TERROR			;
	.PAGE
	.SBTTL	INCHWL	INPUT CHAR WAIT LINE

	HELLO	INCHWL			;ESTABLISH ENTRY AND CHANNEL
	INCW	BUFPTR(R2)		;POINT TO NEXT CHAR
	CMPW	BUFPTR(R2),XFRCNT(R2)	;PAST LAST CHAR?
	BGEQ	1$			;YES, GO GET NEW LINE
	BRW	RETCHR			;NO, RETURN CHAR POINTED TO
1$:	BISW3	#IO$_READVBLK,INPCHX(R2),R0 ;INCLUDE CHARACTERISTICS
	$QIOW_S	CHAN=CHANNL(R2),FUNC=R0,IOSB=STATUS(R2),-
		P1=BUFFER(R2),P2=#BUFLEN ;READ A NEW LINE
	BLBC	R0,99$			;
	CLRW	BUFPTR(R2)		;CURRENT CHAR HAS ZERO OFFSET
	ADDW	TRMLEN(R2),XFRCNT(R2)	;INCLUDE TERMINATOR IN SIZE
	BRW	RETCHR			;RETURN CHAR FROM BUFFER
99$:	BRW	TERROR			;
	.PAGE
	.SBTTL	OUTCHR	OUTPUT CHAR

	HELLO	OUTCHR			;ESTABLISH ENTRY AND CHANNEL
	BSBW	GETCHR			;GET CHARACTER IN R0
	MOVB	R0,-(SP)		;PUT CHAR IN MEMORY
	MOVL	SP,R0			;CHAR ADDRESS IN R0
	BISW3	#IO$_WRITEVBLK,OUTCHX(R2),R1 ;SET I/O FUNCTION CODE
	$QIOW_S	CHAN=CHANNL(R2),FUNC=R1,-
		P1=(R0),P2=#1		;WRITE ONE CHAR
	BLBC	R0,99$			;
	RET				;RETURN TO CALLER
99$:	BRW	TERROR			;
	.PAGE
	.SBTTL	RESCAN	INIT TO PREVIOUS LINE

	HELLO	RESCAN			;ESTABLISH ENTRY AND CHANNEL
	TSTW	XFRCNT(R2)		;DONE ANY I/O BEFORE?
	BGEQ	2$			;YES, SO GO RESET BUFPTR
	PUSHR	#^M<R2,R3,R4,R5,R6>	;NO, READY TO MOVC FROM CLI
	MOVL	R2,R6			;PRESERVE BASE ACROSS MOVC
	SUBL	#CLI$C_REQDESC,SP	;MAKE ROOM ON STACK FOR DESC
	MOVC5	#0,(R2),#0,#CLI$C_REQDESC,(SP) ;ZERO DESCRIPTOR
	MOVB	#CLI$K_GETCMD,CLI$B_RQTYPE(SP) ;INSERT REQUEST TYPE
	PUSHL	SP			;ADDRESS OF DESCRIPTOR
	CALLS	#1,G^SYS$CLI		;ASK FOR LAST STRING CLI HAS
	MOVW	CLI$W_RQSIZE(SP),XFRCNT(R6) ;SAVE CHAR COUNT
	CMPW	#BUFLEN,XFRCNT(R6)	;MORE THAN WE CAN HANDLE?
	BGEQ	1$			;NO, WE'LL TAKE ALL
	MOVW	#BUFLEN,XFRCNT(R6)	;YES, USE ALL THAT WILL FIT
1$:	MOVC3	XFRCNT(R6),@CLI$A_RQADDR(SP),BUFFER(R6) ;GET CLI CHARS
	ADDL	#CLI$C_REQDESC,SP	;FREE STACK SPACE
	POPR	#^M<R2,R3,R4,R5,R6>	;RETRIEVE OUR REGISTERS
2$:	MCOMW	#0,BUFPTR(R2)		;NEXT CALL GETS OFFSET ZERO
	RET				;RETURN TO CALLER
	.PAGE
	.SBTTL	OUTSTR	OUTPUT STRING

	HELLO	OUTSTR			;ESTABLISH ENTRY AND CHANNEL
	BSBW	GTSPTR			;GET STRING POINTER IN R0
	LOCC	#0,#512,(R0)		;FIND THE TERMINATING NULL
	SUBL3	R0,#512,R0		;NUMBER OF CHARS BEFORE NULL
	BLEQ	1$			;GET OUT IF BEGINS WITH NULL
	SUBL	R0,R1			;RECOVER BEGINNING OF STRING
	PUSHL	R3			;NEED ANOTHER REGISTER HERE
	BISW3	#IO$_WRITEVBLK,OUTCHX(R2),R3 ;BUILD FUNCTION CODE
	$QIOW_S	CHAN=CHANNL(R2),FUNC=R3,-
		P1=(R1),P2=R0		;WRITE THE STRING
	POPL	R3			;PUT BACK UNMASKED REGISTER
	BLBC	R0,99$			;
1$:	RET				;RETURN TO CALLER
99$:	BRW	TERROR			;
	.PAGE
	.SBTTL	CLRBFI	CLEAR INPUT BUFFER

	HELLO	CLRBFI			;ESTABLISH ENTRY AND CHANNEL
	CLRW	XFRCNT(R2)		;SAY NO CHARS IN BUFFER
	$QIOW_S	CHAN=CHANNL(R2),FUNC=#<IO$_READVBLK!IO$M_PURGE>,-
		P1=BUFFER(R2),P2=#0	;FORCE PURGE NOW
	BLBC	R0,99$			;
	RET				;RETURN TO CALLER
99$:	BRW	TERROR			;
	.PAGE
	.SBTTL	SETLCH	SET LINE CHARACTERISTICS

	HELLO	SETLCH			;ESTABLISH ENTRY AND CHANNEL
	BSBB	GETCHX			;GET CHARACTERISTICS LONGWORD
	BICL3	#^C<<<IO$M_CANCTRLO!IO$M_NOFORMAT>@16>!-
		<IO$M_NOECHO!IO$M_CVTLOW!IO$M_NOFILTR!-
		IO$M_TRMNOECHO>>,R0,INPCHX(R2) ;FORCE LEGAL CHARACTERISTICS
	RET				;RETURN TO CALLER

GETCHX:	CASEL	4(AP),#0,#11		;CHECK FOR REGISTER ARG
1$:	.WORD	GETR0-1$
	.WORD	GETR1-1$
	.WORD	GETR2-1$
	.WORD	GETR3-1$
	.WORD	GETR4-1$
	.WORD	GETR5-1$
	.WORD	GETR6-1$
	.WORD	GETR7-1$
	.WORD	GETR8-1$
	.WORD	GETR9-1$
	.WORD	GETR10-1$
	.WORD	GETR11-1$
GTXADR:	MOVL	@4(AP),R0		;GET CHARACTERISTICS FROM MEMORY
	RSB				;RETURN
	.PAGE
	.SBTTL	GETLCH	GET LINE CHARACTERISTICS

	HELLO	GETLCH			;ESTABLISH ENTRY AND CHANNEL
	MOVL	INPCHX(R2),R0		;PUT CHARACTERISTICS IN R0
	CASEL	4(AP),#0,#11		;CHECK FOR REGISTER RETURN
1$:	.WORD	RETR0-1$		;
	.WORD	RETR1-1$		;
	.WORD	RETR2-1$		;
	.WORD	RETR3-1$		;
	.WORD	RETR4-1$		;
	.WORD	RETR5-1$		;
	.WORD	RETR6-1$		;
	.WORD	RETR7-1$		;
	.WORD	RETR8-1$		;
	.WORD	RETR9-1$		;
	.WORD	RETR10-1$		;
	.WORD	RETR11-1$		;
	MOVL	R0,@4(AP)		;MOVE TO MEMORY
	RET				;RETURN TO CALLER

	.END				;THAT'S ALL, FOLKS!
