Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap2_198111 - decus/20-0057/sddior.mac
There are 2 other files named sddior.mac in the archive. Click here to see a list.
	TITLE	S$$IOR INPUT/OUTPUT ROUTINES
	SUBTTL	P$$DTC DETACH(VARNAME) PRIMITIVE FUNCTION

	ENTRY	P$$DTC
	EXTERN	S$$ASB,S$$LKV
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 1.
	DETACH(VARNAME) DETACHES ANY INPUT AND(OR) OUTPUT ASSOCIATIONS
THE VARIABLE MAY HAVE, CLEARS THE ASSOCIATION TABLE ENTRY FOR THAT
VARIABLE, AND RETURNS NULL/

P$$DTC:	POP	ES,R1	; GET VARIABLE NAME (STRING)
	JSP	R10,S$$LKV	; LOOKUP VARIABLE
	HRRZ	R1,(R2)	; GET VARIABLE LOC POINTER
	CAIGE	R1,^O776000	; IS IT A TRAP ADDR?
	JRST	NULRET	; NO, NO ASSOCIATION, RETURN
	ASH	R1,2	; COMPUTE ASSOCIATION TABLE ENTRY
	ADD	R1,S$$ASB
	HRRZ	R3,(R1)	; GET ACTUAL VARIABLE LOC POINTER
	HRRM	R3,(R2)	; STORE IN NAME LOC
	SETZM	(R1)	; CLEAR ENTRY
	SETZM	1(R1)
	SETZM	2(R1)
	SETZM	3(R1)
NULRET:	SETZ	R1,	; RETURN NULL
	JRST	(R12)
	PRGEND
	SUBTTL	P$$RLS RELEASE(CHAN) PRIMITIVE FUNCTION

	ENTRY	P$$RLS
	EXTERN	S$$MKI,S$$PGL,S$$CHT,S$$MRS,S$$AST,S$$ASB
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 1.
	RELEASE(CHAN) RELEASES THE SOFTWARE CHANNEL AND ALL ASSOCIAYIONS
TO IT, RETURNS THE BUFFERS TO FREE STORAGE, AND RETURNS NULL. IF CHAN=0,
ALL CHANNELS ARE RELEASED/

P$$RLS:	POP	ES,R1	; GET CHANNEL NUMBER
	JSP	R7,S$$MKI	; MUST BE INTEGER
	CFERR	10,S$$PGL	; BAD ARG IF NOT
	JUMPL	R1,.+2	; IF <0
	CAILE	R1,15	; OR >15
	CFERR	12,S$$PGL	; IT IS AN ILLEGAL UNIT
	JUMPE	R1,MULRLS	; RELEASE ALL CHANNELS IF =0
	JSP	R11,CHNRLS	; OR RELEASE JUST ONE
NULRET:	SETZ	R1,	; RETURN NULL
	JRST	(R12)
MULRLS:	MOVEI	R1,15	; START WITH CHANNEL 15
	MOVEM	R1,MULCHN	; AND SAVE CHANNEL #
	JSP	R11,.+2	; ESTABLISH LOOP ADDR
	SOSLE	R1,MULCHN	; LOOP UNTIL CHANNEL=0
	JRST	CHNRLS	; RELEASE CHANNEL
	JRST	NULRET	; OR FINISH
CHNRLS:	SKIPN	R10,S$$CHT(R1)	; SKIP IF CHANNEL IN USE
	JRST	(R11)	; OTHERWISE RETURN
	SETZM	S$$CHT(R1)	; ZERO CHANNEL TABLE ENTRY
	MOVE	R9,R1	; SAVE CHANNEL NUMBER
	HRLZI	R1,(R1)	; FORM RELEAS CHAN, COMMAND
	LSH	R1,5
	ADD	R1,[RELEAS]
	XCT	R1	; AND EXECUTE
	SETZB	R7,R8	; INITIALIZE I/O CHANNEL FLAGS
	TRNN	R10,-1	; INPUT SIDE OPEN?
	JRST	RLSOUT	; NO, GO CHECK OUTPUT SIDE
	MOVEI	R1,-1(R10)	; POINTER TO BUFFER HEADER TABLE
	JSP	R6,S$$MRS	; RETURN BLOCK TO FREE STORAGE
	HRRZ	R1,(R1)	; POINTER TO BUFFERS
	JSP	R6,S$$MRS	; RETURN BLOCK
	MOVEI	R8,(R9)	; SET INPUT FLAG (CHAN #)
RLSOUT:	HLRZ	R1,R10	; GET OUTPUT SIDE
	JUMPE	R1,RLSASC	; SKIP IF OUTPUT SIDE IS NOT OPEN
	MOVEI	R1,-1(R1)	; POINTER TO BUFFER HEADER TABLE
	JSP	R6,S$$MRS	; RETURN BLOCK
	HRRZ	R1,(R1)	; POINTER TO BUFFERS
	JSP	R6,S$$MRS	; RETURN BLOCK
	MOVEI	R7,(R9)	; SET OUTPUT FLAG (CHAN # LSH 4)
	LSH	R7,4
RLSASC:	MOVE	R10,S$$AST	; GET ASSOC TABLE TOP POINTER
	ADDI	R10,1	; POINTER TO LAST ASSOCIATION ENTRY
	MOVE	R9,S$$ASB	; GET ASSOC. TABLE BOTTOM POINTER
	SUBI	R9,(R10)	; ASSOC. TABLE LENGTH
	LSH	R9,-2	; /4 = # OF ASSOCIATIONS
	JRST	.+2	; SKIP INTO LOOP
ASCLOP:	ADDI	R10,4	; POINTER TO NEXT ASSOCIATION ENTRY
	SKIPN	R6,(R10)	; IS IT ACTIVE?
	JRST	ASCEND	; NO, SKIP AND LOOP
	SKIPE	R5,1(R10)	; IS THERE NO OUTPUT ASSOCIATION?
	JUMPN	R7,.+2	; OR IS OUTPUT FLAG NOT SET?
	JRST	ASCINP	; YES, SKIP OVER
	MOVEI	R1,^O360	; EXTRACT OUTPUT CHANNEL #
	AND	R1,3(R10)
	CAIE	R1,(R7)	; IS IT SAME CHANNEL?
	JRST	ASCINP	; NO
	SETZB	R5,1(R10)	; YES, ERASE OUTPUT ASSOCIATION
	XORM	R1,3(R10)
ASCINP:	SKIPE	R4,2(R10)	; IS THERE NO INPUT ASSOCIATION?
	JUMPN	R8,.+2	; OR IS INPUT FLAG NOT SET?
	JRST	ASCDSC	; YES, SKIP OVER
	MOVEI	R1,^O17	; EXTRACT INPUT CHANNEL #
	AND	R1,3(R10)
	CAIE	R1,(R8)	; IS IT SAME CHANNEL?
	JRST	ASCDSC	; NO
	SETZB	R4,2(R10)	; YES, ERASE INPUT ASSOCIATION
	XORM	R1,3(R10)
ASCDSC:	JUMPN	R5,ASCEND	; LOOP IF OUTPUT ASSOC IS NOT 0
	JUMPN	R4,ASCEND	; LOOP IF INPUT ASSOC IS NOT 0
	SETZM	(R10)	; BOTH ZERO, RELEASE VARIABLE
	MOVS	R6,R6	; ASSOCIATION BY CHANGING NAME
	HLRM	R6,(R6)	; TO POINT TO LOCATION
ASCEND:	SOJG	R9,ASCLOP	; LOOP FOR EACH ENTRY
	JRST	(R11)	; RETURN
; STORAGE
MULCHN:	BLOCK	1
	PRGEND
	SUBTTL	P$$CLS	CLOSE(CHAN,INHIB,OUTHIB) PRIMITIVE FUNCTION

	ENTRY	P$$CLS
	EXTERN	S$$MKI,S$$PGL,S$$CHT
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 3.
	CLOSE(CHAN,INHIB,OUTHIB) CLOSES THE INPUT AND(OR) OUTPUT SIDE
OF THE SOFTWARE CHANNEL, AND RETURNS NULL. IF OUTHIB IS NON-NULL, THE
OUTPUT SIDE IS NOT CLOSED; IF INHIB IS NON-NULL, THE INPUT SIDE IS NOT
CLOSED/

P$$CLS:	MOVE	R8,[CLOSE]	; BARE CLOSE COMMAND
	POP	ES,R1	; GET OUTHIB
	SKIPE	R1	; IS IT NON-NULL?
	ADDI	R8,1	; YES, INHIBIT OUTPUT CLOSING
	POP	ES,R1	; GET INHIB
	SKIPE	R1	; IS IT NON-NULL?
	ADDI	R8,2	; YES, INHIBIT INPUT CLOSING
	POP	ES,R1	; GET CHANNEL #
	JSP	R7,S$$MKI	; MUST BE INTEGER
	CFERR	10,S$$PGL	; OR BAD ARG
	JUMPLE	R1,.+2	; IF NOT >0
	CAILE	R1,15	; OR IF >15
	CFERR	12,S$$PGL	; ILLEGAL UNIT
	SKIPN	S$$CHT(R1)	; HAS CHANNEL BEEN OPENED?
	JRST	NULRET	; NO, NO SENSE CLOSING
	ROT	R1,-13	; GET CHANNEL # INTO AC FIELD
	ADD	R8,R1
	XCT	R8	; EXECUTE CLOSE COMMMAND
NULRET:	SETZ	R1,	; RETURN NULL
	JRST	(R12)
	PRGEND
	SUBTTL	P$$LKF,P$$NTF LOOKUP(FILE,CHAN) AND ENTER(FILE,CHAN) PRIMITIVE FUNCTIONS

	ENTRY	P$$LKF,P$$NTF
	EXTERN	S$$MKI,S$$PGL,S$$CHT,S$$MKS,P$$OPN,S$$FLR
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 2.
	LOOKUP(FILE,CHAN) OPENS FILE FOR INPUT (READING) ON SOFTWARE CHANNEL, RETURNS CHANNEL, FAILS IF FILE NOT FOUND
	ENTER(FILE,CHAN) OPENS FILE FOR OUTPUT (WRITING) ON SOFTWARE CHANNEL, RETURNS CHANNEL
	IF CHANNEL IS 0, A PRELIMINARY OPEN('DSK') IS PERFORMED. IF INPUT
OR OUTPUT SIDE OF CHANNEL ALREADY SELECTS A FILE, THE OLD FILE IS CLOSED/

P$$LKF:	JSP	R11,P$$NTF+1	; LOOKUP, INDEX=0
P$$NTF:	JSP	R11,P$$NTF+1	; ENTER, INDEX=1
	SUBI	R11,P$$NTF
	POP	ES,R1	; GET CHAN #
	JSP	R7,S$$MKI	; MUST BE INTEGER
	CFERR	10,S$$PGL	; OR BAD ARG
	JUMPN	R1,CHKCHN	; SKIP OVER IF NONZERO
	PUSH	ES,DSKSTR	; OTHERWISE DO OPEN('DSK')
	PUSH	ES,R1
	HRL	R11,R12	; SAVE R11 AND R12
	MOVEM	R11,DSKSAV
	JSP	R12,P$$OPN
	MOVE	R11,DSKSAV	; RESTORE R11 AND R12
	HLRZ	R12,R11
	MOVEI	R1,(R1)	; GET CHANNEL #
CHKCHN:	JUMPL	R1,.+2	; IF <0
	CAILE	R1,15	; OR >15
	CFERR	12,S$$PGL	; BAD UNIT
	MOVE	R2,S$$CHT(R1)	; GET CHANNEL TABLE ENTRY
	XCT	[TRNN	R2,-1
		 TLNN	R2,-1](R11)	; TEST APPROPRIATE SIDE
	CFERR	12,S$$PGL	; APPROPRIATE SIDE NOT OPEN
	MOVEI	R10,(R1)	; SAVE CHANNEL#
	POP	ES,R1	; GET FILE NAME
	SETO	R0,	; CREATE STRING IF NECESSARY
	JSP	R7,S$$MKS
	CFERR	10,S$$PGL	; CANNOT DO
	JUMPE	R1,BADPRO	; BAD IF NULL
	HRRZ	R4,(R1)	; GET TOT CHARS IN STRING
	JUMPE	R4,BADPRO	; BAD IF ZERO
	SETZM	FILTBL	; INITIALIZE FILE TABLE
	SETZM	FILTBL+1
	SETZM	FILTBL+2
	SETZM	FILTBL+3
	MOVE	R2,[POINT 6,FILTBL]	; BYTE POINTER FOR FILE NAME
	MOVEI	R3,6	; MAX CHARS ALLOWED FOR FILE NAME
FILOOP:	ILDB	R0,R1	; GET CHAR
	SUBI	R0,^O40	; CONVERT TO SIXBIT
	JUMPL	R0,BADPRO
	CAILE	R0,^O77
	SUBI	R0,^O40
	CAIN	R0,'.'	; IS IT '.'?
	JRST	TRYEXT	; YES, GO LOOK FOR EXT
	CAIN	R0,'['	; NO, IS IT '['
	JRST	TRYPRJ	; YES,GO LOOK FOR PROJ,PROG #
	IDPB	R0,R2	; NO, PUT CHAR IN FILE NAME
	SOJLE	R4,FILFIN	; SKIP OUT IF NO MORE CHARS
	SOJG	R3,FILOOP	; KEEP LOOPING FOR SIX CHARS MAX
	ILDB	R0,R1	; GET NEXT CHAR
	CAIN	R0,"["	; IS IT "[" ?
	JRST	TRYPRJ	; YES, GO LOOK FOR PROJ,PROG #
	CAIE	R0,"."	; IS IT "."?
BADPRO:	CFERR	6,S$$PGL	; NO, BAD PROTOTYPE
TRYEXT:	SOJLE	R4,BADPRO	; ALSO BAD IF NO MORE CHARS AFTER "."
	MOVEI	R3,3	; MAX CHARS ALLOWED FOR EXT NAME
	MOVE	R2,[POINT 6,FILTBL+1]	; BYTE POINTER FOR FILE EXT
EXTLOP:	ILDB	R0,R1	; GET CHAR
	SUBI	R0,^O40	; CONVERT TO SIXBIT
	JUMPL	R0,BADPRO
	CAILE	R0,^O77
	SUBI	R0,^O40
	CAIN	R0,'['	; IS IT '[' ?
	JRST	TRYPRJ	; YES, GO LOOK FOR PROJ,PROG #
	CAIN	R0,'<'	; IS IT '<' ?
	JRST	TRYPRO	; YES, GO LOOK FOR PROTECTION
	IDPB	R0,R2	; PUT CHAR IN EXT
	SOJLE	R4,FILFIN	; SKIP OUT IF NO MORE CHARS
	SOJG	R3,EXTLOP	; LOOP FOR THREE CHARS MAX
	ILDB	R0,R1	; GET NEXT CHAR
	CAIE	R0,"["	; IS IT "["?
	JRST	BADPRO	; NO, BAD PROTOTYPE
TRYPRJ:	SOJLE	R4,BADPRO	; ALSO BAD IF NO MORE CHARS AFTER "["
	MOVEI	R3,6	; 6 CHASS MAX FOR PROJ #
	SETZ	R2,	; INITIAL VALUE FOR PROJ #
PRJLOP:	ILDB	R0,R1	; GET CHAR
	CAIN	R0,","	; IS IT ","?
	JRST	TRYPRG	; YES, GO LOOK FOR PROG #
	CAIL	R0,"0"	; NO, IS IT A DIGIT?
	CAILE	R0,"9"
	JRST	BADPRO	; NO, BAD PROTOTYPE
	SUBI	R0,"0"	; YES, CONVERT TO INTEGER
	IMULI	R2,10	; TOT=TOT*10+INT
	ADD	R2,R0
	SOJLE	R4,BADPRO	; BAD IF NO MORE CHARS
	SOJG	R3,PRJLOP	; LOOP FOR SIX CHARS MAX
	ILDB	R0,R1	; GET NEXT CHAR
	CAIE	R0,","	; IS IT ","?
	JRST	BADPRO	; NO, BAD PROTOTYPE
TRYPRG:	SOJLE	R4,BADPRO	; ALSO BAD IF NO MORE CHARS
	HRLZM	R2,FILTBL+3	; SAVE PROJ # IN LH OF FILE TABLE WORD
	MOVEI	R3,6	; 6 CHARS MAX FOR PROG #
	SETZ	R2,	; INITIAL VALUE FOR PROG #
PRGLOP:	ILDB	R0,R1	; GET CHAR
	CAIN	R0,"]"	; IS IT "]"?
	JRST	PRGFIN	; YES, END UP
	CAIL	R0,"0"	; IS IT A DIGIT
	CAILE	R0,"9"
	JRST	BADPRO	; NO
	SUBI	R0,"0"	; YES, CONVERT
	IMULI	R2,10	; TOTAL
	ADD	R2,R0
	SOJLE	R4,BADPRO	; BAD IF NO MORE CHARS
	SOJG	R3,PRGLOP	; LOOP FOR SIX CHARS MAX
	ILDB	R0,R1	; GET NEXT CHAR
	CAIE	R0,"]"	; IS IT "]"?
	JRST	BADPRO	; NO, BAD PROTOTYPE
PRGFIN:	HRRM	R2,FILTBL+3	; SAVE PROG # IN RH OF FILE TABLE WORD
	SOJLE	R4,FILFIN		;IF MORE, THEN MUST BE PROTECTION
	ILDB	R0,R1		;GET CHAR
	CAIE	R0,"<"		;PROT ?
	JRST	BADPRO		;LOSE
TRYPRO:	SOJLE	R4,BADPRO	;BAD IF NOT LAST CHAR
	SETZ	R2,		;PROTECTION REGISTER
	MOVEI	R3,4		;4 CHAR MAX
PROLOP:	ILDB	R0,R1		;GET A CHAR
	CAIL	R0,"0"		;DIGIT CHECK
	CAILE	R0,"7"
	JRST	PROFIN		;DONE
	SUBI	R0,"0"		;CONVERT TO BINARY
	IMULI	R2,8		;SHIFT
	ADD	R2,R0		;ADD
	SOJL	R4,BADPRO
	SOJG	R3,PROLOP
	ILDB	R0,R1
PROFIN:	CAIE	R0,">"	;END OF PROTECTION SPEC
	JRST	BADPRO		;NO - LOSE
	DPB	R2,[POINT 9,FILTBL+2,8]	;SET PROTECTION
	SOJG	R4,BADPRO	;> IS THE LAST CHAR OR ELSE
FILFIN:	HRRM	R10,RESULT	; SAVE CHANNEL # AS RESULT
	ROT	R10,-13	; FORM AC FIELD WITH CHANNEL #
	ADD	R10,[LOOKUP FILTBL
		     ENTER FILTBL](R11)	; FORM APPROPRIATE UUO
	XCT	R10	; EXECUTE LOOKUP OR ENTER COMMAND
	XCT	ERRRTN(R11)	; ERROR RETURN
	MOVE	R1,RESULT	; OK, RETURN CHANNEL #
	JRST	(R12)
ERRRTN:	JRST	S$$FLR	; FAIL IF LOOKUP
	CFERR	12,S$$PGL	; ILLEGAL I/O IF ENTER
; STORAGE
DSKSTR:	POINT	7,.+1,35
	BYTE	(2)2(16)2(18)3
	ASCII/DSK/
RESULT:	1B0
FILTBL:	REPEAT	4,<0>
	DSKSAV=FILTBL
	PRGEND
	SUBTTL	P$$OPN OPEN(DEV,CHAN) PRIMITIVE FUNCTION

	ENTRY	P$$OPN
	EXTERN	S$$MKI,S$$PGL,S$$CHT,S$$GNS,S$$GNP,.JBFF
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 2.
	OPEN(DEV,CHAN) OPENS A DEVICE FOR INPUT AND(OR) OUTPUT ON A
SOFTWARE CHANNEL AND ASSIGNS BUFFERS, AND RETURNS THE CHANNEL #/

P$$OPN:	POP	ES,R1	; GET CHANNEL
	JSP	R7,S$$MKI	; MUST BE INTEGER
	CFERR	10,S$$PGL	; OR IS BAD ARG
	JUMPL	R1,.+2	; IF <0
	CAILE	R1,15	; OR >15
	CFERR	12,S$$PGL	; ILLEGAL UNIT
	MOVEI	R11,S$$CHT(R1)	; GET POINTER TO ENTRY IN CHAN TABLE
	SKIPE	(R11)	; MUST BE UNUSED
BADUNT:	CFERR	12,S$$PGL	; OR IS A BAD UNIT
	JUMPN	R1,OPNCHN	; JUMP IF CHAN NOT =0
	HRLI	R11,-16	; OTHERWISE LOOK FOR AVAILABLE ONE
OPNCLP:	AOBJN	R11,.+2	; TRY ALL 15 CHANNELS
	UFERR	1,S$$PGL	; FATAL ERROR IF ALL CHANNELS ARE IN USE
	SKIPE	(R11)	; IS CHANNEL AVAILABLE?
	JRST	OPNCLP	; NO, LOOP
	MOVEI	R1,(R11)	; YES, GET CHANNEL #
	SUBI	R1,S$$CHT
OPNCHN:	HRRM	R1,OPNANS	; SAVE CHANNEL # AS RESULT
	ROT	R1,-13	; FORM AC FIELD FOR UUOS
	MOVEM	R1,OPNDCH	; AND SAVE
	POP	ES,R1	; GET DEVICE PROTOTYPE STRING
	TLNE	R1,^O770000	; IS IT A STRING?
	CFERR	10,S$$PGL	; NO
	JUMPE	R1,BADPRO	; SKIP OUT IF NULL
	SETZM	DEVNAM	; CLEAR DEVICE NAME
	MOVE	R2,[POINT 6,DEVNAM]	; SET UP SIXBIT POINTER
	HRRZ	R3,(R1)	; GET CHAR COUNT
	MOVEI	R4,6	; MAX CHARS FOR DEVICE NAME
	SOJL	R3,BADPRO	; SKIP OUT IF 0 CHARS
DEVLOP:	ILDB	R0,R1	; GET NEXT CHAR
	SUBI	R0,^O40	; CONVERT TO SIXBIT
	JUMPL	R0,BADPRO
	CAILE	R0,^O77
	SUBI	R0,^O40
	CAIN	R0,'('	; IS IT LEFT PAREN?
	JRST	BUFSPC	; YES, DECODE BUFFER SPECIFICATION
	SOJL	R4,BADPRO	; NO, ERROR IF >6 CHARS
	IDPB	R0,R2	; FORM DEVICE NAME
	SOJGE	R3,DEVLOP	; LOOP FOR EACH CHAR
	MOVE	R10,[XWD 2,2]	; DEFAULT BUFFER SPECIFICATION
DEVCHK:	MOVE	R0,DEVNAM	; GET DEVICE NAME
	DEVCHR	R0,	; GET CHARACTERISTICS
	JUMPE	R0,BADUNT	; DEVICE NOT FOUND
	TRNE	R0,1B19	; HAS DEVICE BEEN INIT'ED?
	TLNE	R0,1B19	; YES, IS IT A FILE STRUCTURE?
	JRST	.+2	; NOT INIT'ED OR IS FILE STRUCTURE
	CFERR	12,S$$PGL	; NOT FILE STRUCTURE, CAN'T OPEN TWICE
	TLNN	R0,1B34	; DOES DEVICE ALLOW INPUT?
	HLRI	R10,	; NO, NO INPUT BUFFERS
	TLNN	R0,1B35	; DOES DEVICE ALLOW OUTPUT?
	HLLI	R10,	; NO, NO OUTPUT BUFFERS
	SETZ	R9,	; INITIALIZE OBUF,IBUF
	TLNN	R10,-1	; ANY OUTPUT BUFFERS?
	JRST	INPHDR	; NO
	MOVEI	R0,4	; GET BLOCK FOR OUTPUT BUFFER HEADER TABLE
	JSP	R6,S$$GNS
	HRLZI	R9,1(R1)	; POINTER TO FIRST WORD OF HEADER
INPHDR:	TRNN	R10,-1	; ANY INPUT BUFFERS?
	JRST	OPNOPN	; NO
	MOVEI	R0,4	; GET BLOCK FOR INPUT BUFFER HEADER TABLE
	JSP	R6,S$$GNS
	HRRI	R9,1(R1)	; POINTER TO FIRST WORD OF HEADER
OPNOPN:	MOVEM	R9,(R11)	; SAVE POINTERS IN CHANNEL TABLE
	MOVEM	R9,DEVNAM+1	; AND DEVICE SPECIFICATION
	MOVE	R0,[OPEN DEVNAM-1]	; OPEN DEVICE
	ADD	R0,OPNDCH
	XCT	R0
	CFERR	12,S$$PGL	; IF ERROR, ILLEG UNIT
	SETZ	R8,	; INITIALIZE BUFFER SIZE
	HLRZ	R9,R9	; OUTPUT BUFFER HEADER TABLE POINTER
	JUMPE	R9,INPBUF	; SKIP IF 0
	MOVE	R11,[OUTBUF 1]	; UUO CALL FOR OUTPUT BUFFER SETUP
	HLRZ	R0,R10	; NUMBER OF BUFFERS
	JSP	R7,MAKBUF	; MAKE BUFFERS
INPBUF:	HRRZ	R9,DEVNAM+1	; SAME FOR INPUT BUFFERS
	JUMPE	R9,OPNFIN
	MOVE	R11,[INBUF 1]
	HRRZ	R0,R10
	JSP	R7,MAKBUF
OPNFIN:	MOVE	R1,OPNANS	; RETURN CHANNEL #
	JRST	(R12)
; MAKE BUFFER RING
MAKBUF:	ADD	R11,OPNDCH	; INSERT CHANNEL # IN BUFFER UUO
	JUMPN	R8,MAKBU1	; JUMP IF BUFFER SIZE KNOWN
	MOVE	R8,.JBFF	; SAVE .JBFF
	XCT	R11	; MAKE 1 DUMMY BUFFER
	EXCH	R8,.JBFF	; RESTORE .JBFF
	SUB	R8,.JBFF	; CALCULATE BUFFER SIZE
	SETZM	(R9)	; RESTORE HEADER TABLE
	HRLZI	R1,^O700
	MOVEM	R1,1(R9)
	SETZM	2(R9)
MAKBU1:	HRR	R11,R0	; SET # OF BUFFERS IN UUO CALL
	IMULI	R0,(R8)	; # OF BUFFERS * SIZE + 1
	ADDI	R0,1
	JSP	R6,S$$GNS	; GET BLOCK FOR BUFFERS
	HRRM	R1,-1(R9)	; SAVE PTR TO BUFFER BLOCK IN HEADER TABLE
	ADDI	R1,1	; START OF FIRST BUFFER
	EXCH	R1,.JBFF	; SAVE .JBFF
	XCT	R11	; DO UUO
	MOVEM	R1,.JBFF	; RESTORE .JBFF
	JRST	(R7)	; RETURN

; DECODE BUFFER SPEC, WITH PTR IN R1, CHAR COUNT IN R3
BUFSPC:	JSP	R4,S$$GNP	; GET NEXT NUMERICAL PARAMETER
BADPRO:	CFERR	6,S$$PGL	; NO DELIMETER FOUND
	JUMPL	R2,BADPRO	; PARAMETER NEGATIVE
	HRLZI	R10,(R2)	; # OF OUTPUT BUFFERS
	CAIN	R0,","	; IS DELIMETER A COMMA?
	JRST	BUFSP1	; YES, GO FOR SECOND PARAMETER
BUFSP0:	CAIN	R0,")"	; NO, IS DELIMETER A RPAREN?
	JUMPE	R3,DEVCHK	; YES, OK IF NO MORE CHARS
	CFERR	6,S$$PGL	; MORE CHARS OR NOT ")", ERROR
BUFSP1:	JSP	R4,S$$GNP	; GET NEXT NUMERICAL PARAMETER
	CFERR	6,S$$PGL	; NO DELIMITER
	JUMPL	R2,BADPRO	; ERROR IF NEG PAR
	HRRI	R10,(R2)	; # OF INPUT BUFFERS
	JRST	BUFSP0	; CHECK FOR PROPER ENDING
; STORAGE
OPNANS:	1B0
OPNDCH:	BLOCK	1
	0
DEVNAM:	BLOCK	2
	SUBTTL	S$$NIO NORMAL I/O ROUTINES

	ENTRY	S$$NIO
	EXTERN	S$$IOI,S$$IIX,S$$IOX,S$$FLR

	COMMENT/ THESE ROUTINES PERFORM INPUT AND OUTPUT ON DEVICES OTHER THAN THE
CONTROLLING TTY OR NON-TTYCAL INPUT AND OUTPUT ON THE CONTROLLING TELETYPE.
THEY ARE REQUIRED ONLY IF A SOFTWARE CHANNEL IS OPENED AND THUS ARE IN-
CLUDED IN THIS MODULE FOR THAT REASON/

; NORMAL LINE MODE INPUT
NIOLMI:	HRRI	R9,0	; START COUNT AT 0
	HRRZ	R8,3(R8)	; GET INPUT CHANNEL #
	ANDI	R8,^O17
	MOVEM	R8,VIOCHN	; SAVE
	HRRZ	R8,S$$CHT(R8)	; GET HEADER BLOCK POINTER
	EXCH	R10,1(R8)	; HEADER BYTE PTR
	EXCH	R11,2(R8)	; HEADER BYTE COUNT
	MOVE	[XWD NLILOP,NLICHR]	; MOVE LOOP INTO R2 - R8
	BLT	NLIEND
	JRST	NLICHR	; START LOOP
NLILOP:	PHASE	2
NLICHR:	SOJL	R11,NEWIBF	; R2: DECREMENT BUF BYTE COUNT
	ILDB	R0,R10	; R3: GET NEXT BYTE FROM BUF
	CAIG	R0,^O15	; R4: TEST FOR NULL OR CR
	JRST	NLIFIN	; R5: BY JUMPING OUT OF LOOP
NLICON:	IDPB	R0,R1	; R6: PUT CHAR IN STRING
	AOBJN	R9,NLICHR	; R7: LOOP UNTIL ASSOC LEN EXHAUSTED
NLIEND:	JRST	NLIWST	; R8: THROW AWAY REST OF LINE
	DEPHASE
NLIFIN:	JUMPE	R0,NLICHR	; KEEP GOING IF NULL
	CAIE	R0,^O15	; IS IT CR?
	JRST	NLICON	; NO, KEEP GOING
NEWIBR:	SOJL	R11,NEWIB1	; DECREMENT BUF BYTE COUNT
	ILDB	R0,R10	; GET NEXT CHAR
	JUMPE	R0,.-2	; IGNORE IF NULL OTHERWISE MUST BE LF
	MOVE	R8,VIOCHN	; GET CHAN #
	HRRZ	R8,S$$CHT(R8)	; GET BUFFER HEADER PTR
	EXCH	R10,1(R8)	; RESTORE HEADER BYTE POINTER
	EXCH	R11,2(R8)	; RESTORE HEADER BYTE COUNT
	JRST	S$$IIX	; FINISH UP INPUT SEQUENCE
NLIWST:	MOVE	R6,.+1	; SET UP LOOP TO THOW AWAY REST OF LINE
	JRST	NLICHR
NEWIB1:	MOVE	R2,[JRST NEWIBR]	; MODIFY LOOP SO RETURN IS TO NEWIBR
NEWIBF:	MOVE	R8,VIOCHN	; GET CHAN #
	DPB	R8,[POINT 4,NEWIB2,12]	; PUT IN APPROPRIATE
	DPB	R8,[POINT 4,NEWIB3,12]	; UUO CALLS
	HRRZ	R8,S$$CHT(R8)	; GET BUFFER HEADER PTR
	EXCH	R10,1(R8)	; RESTORE R10 AND R11
	EXCH	R11,2(R8)
NEWIB2:	IN	.-.,	; READ IN NEXT BUFFER
	JRST	NEWIOK	; TRANSMISSION OK
NEWIB3:	STATZ	.-.,^O740000	; CHECK STATUS
	CFERR	11,S$$IOI+1	; ERROR
VIOEOF:	SETZM	@S$$IOI	; EOF, SET VAL TO NULL
	JRST	S$$FLR	; FAIL
NEWIOK:	EXCH	R10,1(R8)	; GET HEADER BYTE PTR
	EXCH	R11,2(R8)	; GET HEADER BYTE COUNT
	MOVE	R8,NLIFIN-1	; RESTORE LAST INSTRUCTION WORD OF LOOP
	JRST	NLICHR	; GO TO BEGINNING OF LOOP

; NORMAL CHARACTER MODE INPUT
NIOCMI:	HRRZI	R9,1	; 1 CHARACTER
	HRRZ	R8,3(R8)	; GET INPUT CHANNEL #
	ANDI	R8,^O17
	HRRZ	R7,S$$CHT(R8)	; GET BUFFER HEADER TABLE POINTER
NCICHR:	SOSGE	2(R7)	; DECREMENT BYTE COUNT
	JRST	NEWIBC	; NEED NEW BUFFER
	ILDB	R0,1(R7)	; LOAD CHAR
	JUMPE	R0,NCICHR	; LOOP IF NULL
	IDPB	R0,R1	; OTHERWISE, PUT IN STRING
	HRRM	R9,-1(R1)	; SET CHAR COUNT TO 1
	JRST	S$$IIX+2	; GO RESTORE IN INPUT SEQUENCE
NEWIBC:	DPB	R8,[POINT 4,NEWIB4,12]	; PUT CHANNEL # IN APPROPRIATE
	DPB	R8,[POINT 4,NEWIB5,12]	; UUO CALLS
NEWIB4:	IN	.-.,	; READ IN NEXT BUFFER
	JRST	NCICHR	; TRANSMISSION OK
NEWIB5:	STATZ	.-.,^O740000	; CHECK STATUS
	CFERR	11,S$$IOI+1	; ERROR
	JRST	VIOEOF	; EOF
; NORMAL LINE MODE OUTPUT
NIOLMO:	HRRI	R9,0	; START COUNT AT 0
	MOVE	[XWD NLOLOP,NLOCHR]	; MOVE LOOP INTO R2 - R7
	BLT	NLOEND
	HRRZ	R8,3(R8)	; GET OUTPUT CHANNEL #
	LSH	R8,-4
	MOVEM	R8,VIOCHN	; SAVE
	HLRZ	R8,S$$CHT(R8)	; GET BUFFER HEADER TABLE POINTER
	EXCH	R10,1(R8)	; GET BYTE PTR
	EXCH	R11,2(R8)	; GET BYTE COUNT
	JUMPE	R1,CRLFNM	; SKIP OUT IF NULL STRING
	HRRZ	R8,(R1)	; GET CHAR COUNT
	JUMPE	R8,CRLFNM	; SKIP OUT IF 0
	JRST	NLOCHR	; START LOOP
NLOLOP:	PHASE	2
NLOCHR:	SOJL	R11,NEWOBF	; R2: GET NEW BUFFER IF OUT OF CHARS
	ILDB	R0,R1	; R3: GET CHAR FROM STRING
	IDPB	R0,R10	; R4: PUT CHAR IN BUFFER
	SOJE	R8,CRLFNM	; R5: SKIP OUT IF STRING EXHAUSTED
	AOBJN	R9,NLOCHR	; R6: LOOP IF WITHIN ASSOC LEN
NLOEND:	JRST	ASCLNM	; R7: OTHERWISE, PUT OUT EXTRA CR,LF
	DEPHASE
CRLFNM:	ADDI	R5,CRLFND-CRLFNM	; COME BACK TO CRLFND
	MOVE	R1,CRLFST	; GET CR,LF STRING PTR
	MOVEI	R8,2	; 2 CHARS
	MOVE	R6,.+1	; DON'T WORRY ABOUT ASSOC LEN
	JRST	NLOCHR	; GO TO LOOP
CRLFND:	MOVE	R8,VIOCHN	; GET OUTPUT CHAN #
	HLRZ	R8,S$$CHT(R8)	; GET BUFFER HEADER TABLE PTR
	EXCH	R10,1(R8)	; RESTORE BYTE PTR
	EXCH	R11,2(R8)	; RESTORE CHAR COUNT
	JRST	S$$IOX	; FINISH UP OUTPUT SEQUENCE
ASCLNM:	MOVEM	R1,ASCLR1	; SAVE R1 AND R8
	MOVEM	R8,ASCLR8
	ADDI	R5,ASCLND-CRLFNM	; COME BACK TO ASCLND
	JRST	CRLFNM+1	; GET IN A CR,LF SEQUENCE
ASCLND:	MOVE	R1,ASCLR1	; RESTORE R1 AND R8
	MOVE	R8,ASCLR8
	SUBI	R5,ASCLND-CRLFNM	; RESTORE NORMAL EXIT FROM LOOP
	MOVE	R6,CRLFNM-2	; RESTORE ASSOC LEN TEST
	MOVNI	R9,(R9)	; GET -ASSOC LEN,0 INTO R9
	HRLZI	R9,(R9)
	JRST	NLOCHR	; GO BACK TO LOOP
NEWOBF:	MOVE	R2,VIOCHN	; GET OUTPUT CHAN #
	DPB	R2,[POINT 4,NEWOB1,12]	; PUT IN UUO CALL
	HLRZ	R2,S$$CHT(R2)	; GET BUFFER HEADER TABLE POINTER
	EXCH	R10,1(R2)	; RESTORE R10 AND R11
	EXCH	R11,2(R2)
NEWOB1:	OUT	.-.,	; OUTPUT BUFFER
	JRST	.+2	; TRANSMISSION OK
	UFERR	11,S$$IOI+1	; OUTPUT ERROR
	EXCH	R10,1(R2)	; GET BYTE PTR
	EXCH	R11,2(R2)	; GET BYTE COUNT
	MOVE	R2,NLOLOP	; RESTORE FIRST WORD OF LOOP
	JRST	NLOCHR	; RETURN TO LOOP

; NORMAL CHARACTER MODE OUTPUT
NIOCMO:	JUMPE	R1,S$$IOX	; SKIP OUT IF NULL
	HRRZ	R7,(R1)	; GET CHAR COUNT
	JUMPE	R7,S$$IOX	; SKIP OUT IF 0
	HRRZ	R8,3(R8)	; GET OUTPUT CHANNEL #
	LSH	R8,-4
	MOVEM	R8,VIOCHN	; SAVE
	HLRZ	R8,S$$CHT(R8)	; GET BUFFER HEADER TABLE POINTER
	EXCH	R10,1(R8)	; GET BYTE PTR
	EXCH	R11,2(R8)	; GET BYTE COUNT
	MOVE	[XWD NCOLOP,NCOCHR]	; MOVE LOOP INTO R2 - R6
	BLT	NCOEND
	JRST	NCOCHR	; JUMP INTO LOOP
NCOLOP:	PHASE	2
NCOCHR:	SOJL	R11,NEWOBF	; R2: GET NEW BUFFER IF NO MORE CHARS
	ILDB	R0,R1	; R3: GET CHAR FROM STRING
	IDPB	R0,R10	; R4: PUT CHAR IN BUFFER
	SOJN	R7,NCOCHR	; R5: LOOP UNTIL STRING IS EXHAUSTED
NCOEND:	JRST	CRLFND+2	; R6: RESTORE BYTE PTR, COUNT, AND QUIT
	DEPHASE

; STORAGE
S$$NIO:	XWD	NIOLMO,NIOLMI	; NORMAL LINE MODE OUTPUT/INPUT
	XWD	NIOCMO,NIOCMI	; NORMAL CHAR MODE OUTPUT/INPUT
VIOCHN:	BLOCK	1
ASCLR1:	BLOCK	1
ASCLR8:	BLOCK	1
CRLFST:	POINT	7,.+1	; CR,LF SEQUENCE
	BYTE	(7)^O15,^O12
	PRGEND
	SUBTTL	P$$INP,P$$OUT INPUT() AND OUTPUT() PRIMITIVE FUNCTIONS

	ENTRY	P$$INP,P$$OUT
	EXTERN	S$$MKI,S$$PGL,S$$CHT,S$$AST,S$$ASB,S$$NIO
	EXTERN	S$$LKV,S$$MRS,S$$GNS
	RADIX	10
	SEARCH	S$$NDF

	COMMENT/
CALL:	FUNCTION CALL, WITH ARGUMENTS EQUALIZED TO 3.
	INPUT(VARNAM,CHAN,LENGTH) CREATES AN INPUT ASSOCIATION BETWEEN
A VARIABLE AND A SOFTWARE CHANNEL, IN EITHER CHARACTER MODE OR LINE MODE
WITH ASSOCIATION LENGTH SPECIFIED, AND RETURNS NULL
	OUTPUT(VARNAM,CHAN,LENGTH) IS LIKE 'INPUT()', BUT CREATES AN OUT-
PUT ASSOCIATION INSTEAD
	LENGTH > 0 INDICATES LINE MODE
	LENGTH = 0 INDICATES LINE MODE WITH DEFAULT LENGTH
	LENGTH < 0 OR NOT INTEGER INDICATES CHARACTER MODE
	CHANNEL = 0 INDICATES TELETYPE (TTYCAL) INPUT AND OUTPUT
	CHANNEL > 0 INDICATES NORMAL BUFFERED OUTPUT AND INPUT ON THAT
SOFTWARE CHANNEL
	CHANNEL < 0 OR NOT INTEGER INDICATES THAT THE APPROPRIATE
ASSOCIATION IS TO BE DISCONNECTED (BUT THE VARIABLE IS NOT DETACHED)
	IF AN ASSOCIATION ALREADY EXISTS, THE NEW ONE REPLACES IT/

P$$INP:	JSP	R11,P$$OUT+1	; 'INPUT', INDEX = 0
P$$OUT:	JSP	R11,P$$OUT+1	; 'OUTPUT', INDEX = 1
	SUBI	R11,P$$OUT

; DETERMINE LENGTH
	POP	ES,R1	; GET LENGTH
	JSP	R7,S$$MKI	; IS IT INTEGER?
	SETO	R1,	; NO, SET = -1
	JUMPN	R1,.+2	; IS IT 0?
	MOVEI	R1,P$ALEN	; YES, SET = DEFAULT ASSOC LEN
	MOVEM	R1,SAVLEN	; SAVE LENGTH

; DETERMINE CHANNEL
	POP	ES,R1	; GET CHAN #
	JSP	R7,S$$MKI	; IS IT INTEGER?
	SETO	R1,	; NO, SET = -1
	CAILE	R1,15	; IS IT > 15?
	CFERR	12,S$$PGL	; YES, ILLEGAL UNIT
	MOVEM	R1,SAVCHN	; SAVE CHANNEL #
; DETERMINE VARIABLE
	POP	ES,R1	; GET VARNAM
	JSP	R10,S$$LKV	; LOOKUP VARIABLE
	MOVE	R1,(R2)	; GET NAME DESCR FOR VARIABLE
	TLNE	R1,3B23	; IS IT DEDICATED?
	CFERR	10,S$$PGL	; YES, ERROR
	HRRZI	R1,(R1)	; FORM ADDRESS ONLY
	CAIL	R1,^O776000	; IS IT A TRAP ADDR?
	HRREI	R1,(R1)	; YES, MAKE NEG
	SKIPL	R10,SAVCHN	; GET CHAN # AND SKIP IF < 0
	JRST	NEWASC	; OTHERWISE GO TO NEW ASSOCIATION SECTION

; DELETE OLD ASSOCIATION
	JUMPGE	R1,NULRET	; FINISH IF NOT ASSOCIATED ALREADY
	ASH	R1,2	; OTHERWISE COMPUTE ASSOC TABLE ENTRY PTR
	ADD	R1,S$$ASB
	XCT	[SETZM	2(R1)
		 SETZM	1(R1)](R11)	; AND ELIMINATE APPROPRIATE
	JRST	NULRET	; ASSOCIATION AND RETURN NULL

; CHECK FOR OLD ASSOCIATION
NEWASC:	JUMPE	R10,.+4	; SKIP OVER IF CHAN # IS 0
	SKIPE	R3,S$$CHT(R10)	; TEST IF APPROPRIATE SIDE OPEN
	XCT	[TRNN	R3,-1
		 TLNN	R3,-1](R11)
	CFERR	12,S$$PGL	; NO, BAD UNIT
	JUMPGE	R1,CRTASC	; CREATE NEW ASSOCIATION IF ADDR > 0
	ASH	R1,2	; OTHERWISE COMPUTE ASSOCIATION TABLE ENTRY PTR
	ADD	R1,S$$ASB
	JRST	SAVASC	; AND GO SAVE ASSOCIATION

; CREATE NEW ASSOCIATION
CRTASC:	MOVE	R3,S$$AST	; ASSOC TBL TOP PTR
	MOVE	R4,S$$ASB	; COMPUTE -TOT # OF ASSOC ENTRIES
	SUBI	R4,1(R3)
	ASH	R4,-2
	MOVN	R4,R4
	HRLI	R3,(R4)	; AND SAVE FOR AOBJ COUNT
CRTLOP:	SKIPN	1(R3)	; IS ENTRY AVAILABLE?
	JRST	CRTFND	; YES
	ADDI	R3,3	; OTHERWISE POINT TO NEXT ENTRY
	AOBJN	R3,CRTLOP	; AND LOOP
; EXPAND ASSOCIATION TABLE
	MOVEM	R2,SAVCHN	; NO FREE ENTRIES, SAVE POINTER TO NAME
	MOVE	R1,S$$AST	; GET OLD ASSOC TABLE BLOCK
	HLRZ	R0,(R1)	; MAKE NEW ONE OF SIZE =
	ANDI	R0,^O177777	; OLD SIZE +
	HRRZ	R7,(R1)	; EXTENSION SIZE
	ADDI	R0,(R7)
	JSP	R6,S$$GNS
	HRRM	R7,(R1)	; SAVE EXTENSION SIZE IN NEW BLOCK
	MOVEI	R2,2(R1)	; ZERO ALL NEW ADDITIONAL ENTRIES
	HRLI	R2,1(R1)
	SETZM	1(R1)
	ADDI	R7,(R1)
	BLT	R2,(R7)
	ADDI	R0,(R1)	; NEW TABLE BASE POINTER
	EXCH	R1,S$$AST	; SAVE NEW TABLE TOP POINTER
	JSP	R6,S$$MRS	; RETURN OLD BLOCK
	HRRZI	R2,1(R7)	; MOVE REMAINING ENTRIES FROM OLD TABLE
	HRLI	R2,1(R1)	; TO NEW ONE
	MOVEM	R0,S$$ASB	; AND SAVE NEW TABLE BASE POINTER
	MOVE	R1,R0
	BLT	R2,-1(R1)
	MOVE	R2,SAVCHN	; RESTORE PTR TO NAME
	HRRZ	R1,(R2)	; AND PTR TO VARIABLE
	JRST	CRTASC	; AND GO FIND ENTRY

; NEW ENTRY SPACE FOUND
CRTFND:	HLRM	R3,(R2)	; SAVE ENT^Y INDEX IN NAME DESCR
	HRLI	R1,(R2)	; AND NAME POYNTER, VAR POINTER
	MOVEM	R1,1(R3)	; IN FIRST WORD OF ENTRY
	MOVEI	R1,1(R3)	; POINTER TO ENTRY
; DETERMINE TYPE OF I/O
SAVASC:	MOVEI	R2,S$$NIO	; NORMAL I/O ROUTINES POINTER
	JUMPN	R10,.+2	; IS CHANNEL 0?
	MOVEI	R2,S$$ASB+1	; YES, POINT TO TTYCAL ROUTINES
	SKIPGE	R3,SAVLEN	; IS IT LINE MODE?
	ADDI	R2,1	; NO, <0, CHAR MODE, DIFFERENT I/O ROUTINES
	XCT	[HRRZ	R4,(R2)
		 HLRZ	R4,(R2)](R11)	; GET APPROPRIATE ROUTINE
	JUMPL	R3,.+3	; SKIP IF CHAR MODE
	MOVNI	R5,(R3)	; OTHERWISE LOAD -LENGTH
	HRLI	R4,(R5)

; SAVE ASSOCIATION INFO IN ENTRY
	XCT	[MOVEM	R4,2(R1)
		 MOVEM	R4,1(R1)](R11)	; SAVE IN ENTRY
	MOVEI	R9,^O17	; CHANNEL BYTE MASK
	XCT	[JRST	SAVINP
		 LSHC	R9,4](R11)	; PREPARE FOR ENTRY MODIFICATION
SAVINR:	ANDCAM	R9,3(R1)	; CLEAR CHANNEL BYTE, ETC
	ADDM	R10,3(R1)	; SET CHANNEL BYTE, ETC
NULRET:	SETZ	R1,	; RETURN NULL
	JRST	(R12)
SAVINP:	JUMPGE	R3,.+2	; SKIP IF LINE MODE
	AOJA	R3,.+2	; SET R3=0 FOR CHAR MODE
	MUL	R3,[^F0.2B0]	; COMPUTE # WORDS IN INPUT STRING BLOCK
	HRLI	R10,2(R3)
	HRROI	R9,(R9)	; MODIFY CHANNEL BYTE MASK
	JRST	SAVINR	; GO BACK TO SEQUENCE
; STORAGE
SAVLEN:	BLOCK	1
SAVCHN:	BLOCK	1
	END