Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93e-bb - 7,6/ap016/swilio.x16
There are 2 other files named swilio.x16 in the archive. Click here to see a list.
	TITLE	.IO	SWIL I/O routines
	SUBTTL	Robert Houk/RDH

	SEARCH	SWIDEF,	SWIL		;SWIL PACKAGE DEFINITIONS
	SEARCH	JOBDAT,	MACTEN,	UUOSYM	;STANDARD DEFINITIONS

	SALL				;PRETTY LISTINGS
	.DIREC	FLBLST			;PRETTIER LISTINGS

	TWOSEG	400000


	COMMENT	\

COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1986.  ALL RIGHTS RESERVED.


THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
TRANSFERRED.

THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.

DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

\
	SUBTTL	Version and Revision History

MAJVER==13	;MAJOR VERSION LEVEL
MINVER==0	;MINOR (MAINTENANCE RELEASE) LEVEL
CSTVER==0	;CUSTOMER VERSION (WHO LAST . . .)
EDTVER==1051	;EDIT LEVEL

%%IO==:<BYTE (3)CSTVER(9)MAJVER(6)MINVER(18)EDTVER>
%%SWIL==:%%SWIL	;SHOW (AND SYNCHRONIZE) SWIL VERSION

IF2,<	PURGE	CSTVER,MAJVER,MINVER,EDTVER>



;INITIAL CREATION

;1000	RDH	01-Jan-84
;	Incorporate into SWIL %12(1000), sync edit level at 1000.

;1005	RDH	12-Oct-84
;	Implement support for "Stream-CR" and "Stream-LF" VAX files.

;1015	DRB	29-Jan-85
;	ORNIX5 incorrectly tests for passive connection (assumes .IOCCF
;	loaded into M0, and it isn't).

;1022	LEO	09-Sep-85
;	Do Copyrights.

;1040	RDH	3-Jan-86
;	ORNIX5 doesn't pass incoming DAP (e.g., aborting ACCOMP) messages
;	back up to FAL. Supersedes edit 1015.

;1041	RDH	4-Jan-86
;	No support for network Line Sequence Numbers.

;1042	RDH	23-Jan-86
;	Implement /IOMODE:A8CII.

;1044	BSC	16-Jun-86
;	Fix ? UNKNOWN ISF FLAGS IN IRAS90 when VAX file with FORTRAN carriage
;	carriage control record starts with "0" or "-" which requires
;       conversion to multiple line-feeds. AC T1 was getting trashed.

;1047	TL	4-Dec-86
;	Fix VAX receives of records like <FF>text<EOR>more when IS.ICL is set.
;	See detailed description in SWIDEF.

;1051	KDO	20-Mar-87
;	Add ULTRIX support.
	SUBTTL	INPUT SERVICE ROUTINES

;All Input Service Routines are called with the I/O CDB address in
;register T1.
;
;On the error/exception return M0 has the error/exception code
;
;On normal return, data is passed in T2 (and if needed T3, T4).
;
;In all cases, T1 is preserved, as is any other T register not used
;to return data.

	ENTRY	.IOIIN

.IOIIN:	PUSHJ	P,IOIIN0	;DO THE WORK
	 POPJ	P,		;ERROR
	PJRST	@.IOISR(T1)	;DISPATCH TO SELECTED INPUT SERVICE ROUTINE

IOIIN0:	PUSHJ	P,.SACIO##	;SELECT I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S
	SETZM	.IOISF(IO)	;CLEAR OUT INPUT PROCESSING FLAGS
	XMOVEI	P3,.POPJ1##	;SUCCESSFUL RETURNER
	MOVEM	P3,.IOISS(IO)	;NO SPECIAL CLOSE PROCESSING REQUIRED
	MOVX	P1,IO.IOA	;THE I/O-ACTIVE FLAG
	IORB	P1,.IOCCF(IO)	;FLAG I/O BEING PERFORMED
	TXNE	P1,IO.NET	;LOCAL OR REMOTE (NETWORK) I/O?
	JRST	IRINI		;REMOTE
				;LOCAL, FALL INTO ILINI

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;ILINI  --  INPUT, LOCAL, INITIALIZATION

ILINI:	TXNE	P1,IO.IBA	;INPUT BUFFERS ALLOCATED?
	JRST	ILINI4		;YES, SELECT ISR AND START I/O

;NO INPUT BUFFERS, GENERATE SOME FOR FREE

	PUSHJ	P,FILBI1##	;SETUP INPUT BUFFERS
	 POPJ	P,		;OH WELL

;SELECT ISR BASED ON FILE MODE AND OPTIONS

ILINI4:	MOVE	P4,.IOIOC(IO)	;I/O CONTROL
	LDB	P2,[POINTR P4,IC.MOD]  ;GET FILE MODE
	XMOVEI	P3,.		;GET OUR SECTION IN LH
	HRR	P3,MOISTB(P2)	;SELECT ISR BASED ON FILE MODE ALONE
	TXNE	P4,IC.RSI	;USER WANT RECORD-STRUCTURED I/O?
	HRRI	P3,ILREC	;YES, TOO BAD
	TXNE	P4,IC.BLK	;USER WANT BLOCK MODE BUFFERS
	HRRI	P3,ILBLK	;YES, LET HIM DO HIS OWN STUFF THEN
	TXNE	P4,IC.MCY!IC.MEY;WANT TO READ MACY11-PACKED DATA?
	HRRI	P3,ILMCI	;YES, USE MACY11 ISR
	MOVEM	P3,.IOISR(IO)	;SET ISR IN THE CDB

;INITIALIZE COUNTERS

	SETZM	.IOIUC(IO)	;NO BUFFERS READ YET
	JRST	.POPJ1##	;INPUT INITIALIZED
;ILASC  --  INPUT, LOCAL, ASCII CHARACTERS

ILASB:	PUSHJ	P,ILBUF		;ASK MONITOR FOR ANOTHER BUFFER
	 POPJ	P,		;ERROR
ILASC:	SOSGE	.IOIBC(T1)	;ANY CHARACTERS LEFT?
	JRST	ILASB		;NO, GET A NEW BUFFER-FULL
	ILDB	T2,.IOIBP(T1)	;YES, RETREIVE THE NEXT ASCII CHARACTER
	MOVE	M0,@.IOIBP(T1)	;FETCH A COPY OF THE WORD
	TRZE	M0,1		;A LINE-SEQUENCE-NUMBER?
	JRST	ILASN		;YES (YUCH)
	JUMPE	T2,ILASC4	;NO, WATCH OUT FOR NULLS
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

;CHECK OUT A NULL

ILASC4:	MOVE	M0,.IOIOC(T1)	;I/O CONTROL BITS
	TXNN	M0,IC.LSN	;LSN DEFEATS NULLS
	TXNN	M0,IC.NUL	;USER WANT NULLS AS NORMAL CHARACTERS?
	JRST	ILASC		;NO, EAT THE NULL
	JRST	.POPJ1##	;YES, SUCCESSFUL RETURN
;LINE-SEQUENCE-NUMBER DETECTED, SLURP IT UP AND SEE WHAT TO DO WITH IT

ILASN:	PUSHJ	P,TSAV14##	;FOR FUNNY GRUNDGE BELOW
	MOVE	T4,M0		;PRESERVE COPY OF LSN
	MOVNI	T3,4		;AN LSN IS 5 CHARACTERS
	ADDM	T3,.IOIBC(T1)	;SO MARK ALL 5 AS "SOSGE"ED
	MOVSI	T3,(POINT 7,,34);ALSO FAKE OUT THE BYTE POINTER
	HLLM	T3,.IOIBP(T1)	;SO ILDB WILL START ON NEXT WORD
	CAMN	T4,[<ASCII/     />]  ;IS THIS AN SOS-STYLE PAGE-MARK?
	JRST	ILASP		;PROBABLY
	SETZ	T2,		;INITIALIZE LSN
ILASN1:	SETZ	T3,		;CLEAR OUT FOR NEXT LSN DIGIT
	LSHC	T3,^D7		;SHIFT UP NEXT ASCII DIGIT CHARACTER
	CAIL	T3,"0"		;IS IT A DECIMAL DIGIT?
	CAILE	T3,"9"		;IS IT A DECIMAL DIGIT?
	JRST	[MOVX	M0,$EILLN	;NO, LUDICROUS LINE NUMBER
		POPJ	P,]		;RETURN
	IMULI	T2,^D10		;MAKE ROOM FOR NEW DECADE
	ADDI	T2,-"0"(T3)	;ADD IN THIS DECADE
	JUMPN	T4,ILASN1	;LOOP FOR ALL FIVE DIGITS
	MOVEM	T2,-T2(P)	;ASSUME USER WILL WANT THE LSN RETURNED

;NOW CHECK FOR SOS'S <TAB>, EATING INTERVENING NULLS

	MOVE	T3,.IOIOC(T1)	;A SAFE COPY OF THE I/O CONTROL BITS
ILASN3:	PUSHJ	P,ILBYT		;READ NEXT INPUT BYTE
	 JRST	[CAIN	M0,$EIEOF	;ERROR - END OF FILE?
		MOVX	M0,$EIEFL	;YES, ERROR, EOF READING LSN
		POPJ	P,]		;RETURN EXCEPTION CODE
	MOVE	M0,@.IOIBP(T1)	;COPY OF WHOLE WORD TOO
	TRZE	M0,1		;THIS WORD ALSO CLAIM TO BE AN LSN?
	JRST	[MOVX	M0,$EIMLN	;YES, MULTIPLE LINE NUMBERS
		POPJ	P,]		;ERROR RETURN
	JUMPE	T2,[TXNN P1,IC.NUL	;USER WANT NULLS?
		JRST	ILASN3		;NO, EAT IT, KEEP SEARCHING
		JRST	ILASN8]		;YES, VALID DATA CHARACTER
	CAIE	T2,.CHTAB	;VALID CHARACTER, SOS-STYLE <TAB>?
	JRST	ILASN8		;NO, VALID DATA CHARACTER

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;NOW SCAN TO NEXT VALID DATA CHARACTER, SUPPRESSING NULLS IF NEED BE

ILASN5:	PUSHJ	P,ILBYT		;GET NEXT INPUT BYTE
	 JRST	[CAIN	M0,$EIEOF	;END OF FILE?
		MOVX	M0,$EIEFL	;YES, ERROR
		POPJ	P,]		;ERROR RETURN
	MOVE	M0,@.IOIBP(T1)	;COPY OF WORD ALSO
	TRZE	M0,1		;MAKE SURE NOT ANOTHER LSN
	JRST	[MOVX	M0,$EIMLN	;ERROR - MULTIPLE LSN
		POPJ	P,]		;ERROR RETURN
	JUMPE	T2,[TXNN P1,IC.NUL	;USER SAY NULL IS VALID DATA?
		JRST	ILASN5		;NO, EAT THE NULL
		JRST	ILASN8]		;YES, RETURN NULL AS DATA CHAR

;HERE WITH T2 HAVING FIRST VALID CHARACTER AFTER THE LSN

ILASN8:	EXCH	T2,-T2(P)	;ASSUME USER DOESN'T WANT THE LSN
	MOVE	T3,.IOIOC(T1)	;FETCH I/O CONTROL FLAGS
	TXNN	T3,IC.LSN	;DID I GUESS RIGHT?
	JRST	.POPJ1##	;YEAH, HOW CONVENIENT
	EXCH	T2,-T2(P)	;NO, RETURN THE LSN THEN
	MOVEM	T2,.IOIS0(T1)	;AND REMEMBER THE DATA CHARACTER
	XMOVEI	T2,ILASN9	;SET STATE INTERCEPT
	MOVEM	T2,.IOISR(T1)	;TO RETURN DATA CHARACTER NEXT CALL
	MOVEI	M0,$EILSN	;NOTE A LINE SEQUENCE NUMBER ENCOUNTERED
	POPJ	P,		;AND TAKE EXCEPTION RETURN THIS CALL

;RETURN SAVED DATA CHARACTER

ILASN9:	XMOVEI	T2,ILASC	;RESTORE NORMAL ASCII INPUT
	MOVEM	T2,.IOISR(T1)	;SET ISR IN CDB
	MOVE	T2,.IOIS0(T1)	;FETCH SAVED CHARACTER
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;HERE ON SOS-STYLE PAGE MARK COMING UP

ILASP:	PUSHJ	P,ILBYT		;GET NEXT 7-BIT BYTE
	 JRST	[CAIN	M0,$EIEOF	;ERROR - END OF FILE?
		MOVEI	M0,$EIEFL	;YES, ERROR, EOF READING LSN
		POPJ	P,]		;PROPAGATE ERROR
	MOVE	M0,@.IOIBP(T1)	;COPY OF WHOLE WORD TOO
	TRZE	M0,1		;CAN'T BE ANOTHER LSN
	JRST	[MOVEI	M0,$EIMLN	;MULTIPLE LSN'S
		POPJ	P,]		;RETURN ERROR
	CAIE	T2,.CHCRT	;THIS MUST BE A <CR>
	JRST	[MOVEI	M0,$EILLN	;NOT, LUDICROUS LINE NUMBER
		POPJ	P,]		;RETURN ERROR
	PUSHJ	P,ILBYT		;GET NEXT 7-BIT BYTE
	 JRST	[CAIN	M0,$EIEOF	;ERROR - END OF FILE?
		MOVEI	M0,$EIEFL	;YES, ERROR, EOF READING LSN
		POPJ	P,]		;PROPAGATE ERROR
	CAIE	T2,.CHFFD	;THIS MUST BE A <FF>
	JRST	[MOVEI	M0,$EILLN	;NOT, LUDICROUS LINE NUMBER
		POPJ	P,]		;RETURN ERROR
	MOVEM	T2,-T2(P)	;THIS IS THE DESIRED <FF>
	MOVNI	T3,3		;THERE ARE THREE MORE NULLS THERE
	ADDM	T3,.IOIBC(T1)	;SO SKIP PAST THEM
	MOVSI	T3,(POINT 7,,34);ALSO FAKE OUT
	HLLM	T3,.IOIBP(T1)	;THE BYTE POINTER
	MOVE	T3,.IOIOC(T1)	;GET INPUT I/O CONTROL FLAGS
	TXNN	T3,IC.LSN	;CALLER WANT INPUT LSNS?
	JRST	.POPJ1##	;NO, JUST RETURN <FF>
	MOVSI	T2,(1B0)	;YES, FORMAT SOS-STYLE PAGE MARK
	MOVEM	T2,-T2(P)	;AND RETURN THAT TO THE CALLER
	MOVEI	M0,$EILSN	;AS AN LSN
	POPJ	P,		;TAKE EXCEPTION RETURN
;ILBYT  --  INPUT, LOCAL, BYTE STREAM

ILBYB:	PUSHJ	P,ILBUF		;ASK FOR ANOTHER BUFFER
	 POPJ	P,		;ERROR (OR END OF FILE)
ILBYT:	SOSGE	.IOIBC(T1)	;ANY BYTES LEFT IN CURRENT BUFFER?
	JRST	ILBYB		;NO, ASK FOR ANOTHER BUFFER'S WORTH
	ILDB	T2,.IOIBP(T1)	;GET NEXT DATA BYTE
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN



;ILREC  --  INPUT, LOCAL, RECORD-STRUCTURED I/O

ILREC:	STOPCD	<Record-structured local I/O illegal>



;ILBLK  --  INPUT, LOCAL, BLOCK-AT-A-TIME MODE

ILBLB:	PUSHJ	P,ILBUF		;ASK MONITOR FOR A BUFFER
	 POPJ	P,		;ERROR (OR END OF FILE)
ILBLK:	MOVE	T2,.IOIUC(T1)	;RETURN VIRTUAL BLOCK NUMBER (OR SOMETHING)
	SETO	T3,		;FLAG EMPTY
	EXCH	T3,.IOIBC(T1)	;ACCOUNT FOR THIS BUFFER'S WORTH OF DATA
	MOVE	T4,.IOIBP(T1)	;BYTE POINTER TO THE DATA
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;ILMCY  --  INPUT, LOCAL, MACY11 PACKED

;MACY11 packing involves writing 8-bit bytes packed four to a 36-bit word,
;but not in an obvious manner. The four bytes are layed out as follows:
;
;	    2      9 10    17    20    27 28    35
;	+--+--------+--------+--+--------+--------+
;	|  |  two   |  one   |  |  four  | three  |
;	+--+--------+--------+--+--------+--------+
;
;This format can be thought of as aligning one -11 16-bit word per -10
;halfword (although it should be emphasized that the packing is in
;terms of bytes, so that the "16-bit words" might be (and often are)
;split across "18-bit halfwords"!).
;
;The record structure imposed is:
;
;	000001		;record header
;	length		;count of bytes (includes MACY11 header - 6 bytes)
;	address		;for .LDA files, address to load record
;			; ignored for pure data records
;	-data-		;length-6 data bytes
;	...cks		;one-byte checksum (not included in count)
;
;The output variables (in the CDB) are used as follows:
;
;	.IOIS0		;record "address" (typically meaningless, but preserved)
;	.IOIS1		;record (actual data) byte count
;	.IOIS2		;ILMCB (byte-stuffing) state
;	.IOIS3		;ILMCR (record-header) state
;	.IOIS4		;ILMCB 36-bit word
;	.IOIS5		;MACY11 checksum value

;The ISR call is:
;
;	MOVX	T3,<CNT>
;	MOVX	T4,<PTR>
;	PUSHJ	P,@.IOISR
;	 error return
;	normal return
;
;Where <CNT> is the maximum count of bytes that can fit in the user-supplied
;record buffer; and <PTR> is the byte pointer to the record buffer.
;
;On error return an error code is in M0 - such as record format error.
;
;On normal return T2 has the record "address" (as per the .LDA/MACY11 format
;typically ignored for data files), T3 has the count of bytes returned in
;the current record, and T4 is unchanged (points to start of record).
;HERE TO INITIALIZE MACY11 INPUT (FROM ILINI)

ILMCI:	SETZM	.IOIS3(T1)	;NOT IN A RECORD STATE
	SETZM	.IOIS2(T1)	;NOT IN A WORD EITHER
	XMOVEI	M0,ILMCY	;THE NORMAL MACY11 ISR
	MOVEM	M0,.IOISR(T1)	;SET FOR REST OF THE WORLD
				;FALL INTO ILMCY


;HERE TO INPUT ONE MACY11 LOGICAL DATA BYTE (CALLED AS AN ISR)

ILMCY:	PUSHJ	P,.SAVE2##	;NEED A COUPLA MORE ACS HERE
	PUSHJ	P,TSAV14##	;SAVE/STORE THE T'S
	PUSHJ	P,ILMCR		;FIRE UP A DATA RECORD
	 POPJ	P,		;I/O ERROR? OR WORSE?
	MOVE	T2,.IOIS0(T1)	;GET RECORD "ADDRESS"
	MOVEM	T2,-T2(P)	;AND SET FOR CALLER (IF HE CARES)
	MOVN	T3,-T3(P)	;NEGATE CALLER'S BYTE COUNT
	SUBI	T3,1		;ALLOW FOR LOOPEDNESS
	HRLZ	P1,T3		;CONVERT TO AOBJN COUNTER
	SKIPA	P2,-T4(P)	;CALLER'S BUFFER BYTE POINTER

;LOOP READING THE RECORD, LH(P1) = BYTES TO GO, RH(P1) = BYTES RETURNED

ILMCY3:	IDPB	T2,P2		;STORE ANOTHER DATA BYTE IN CALLER'S BUFFER
ILMCY4:	SOSGE	.IOIS1(T1)	;ANY DATA LEFT?
	JRST	ILMCY6		;NOPE, ALL GONE
	PUSHJ	P,ILMCB		;INPUT THIS 8-BIT BYTE
	 JRST	ILMCY8		;I/O ERROR?
	ADDM	T2,.IOIS5(T1)	;ACCUMULATE MACY11 CHECKSUM
	AOBJN	P1,ILMCY3	;LOOP FOR REST OF RECORD
	SOJA	P1,ILMCY4	;RECORD OVERFLEW USER'S BUFFER, DISCARD DATA

ILMCY6:	PUSHJ	P,ILMCB		;READ CHECKSUM BYTE
	 JRST	ILMCY8		;OH BOTHER
	SETZM	.IOIS3(T1)	;CLEAR RECORD STATE
	HRRZM	P1,-T3(P)	;RETURN COUNT OF BYTES STORED FOR CALLER
	JUMPL	P1,.POPJ1##	;SUCCESSFUL RETURN IF RECORD FIT CALLER'S BUFFER
	MOVEI	M0,$EIRTB	;OOPS - RECORD TOO BIG FOR CALLER'S BUFFER
	POPJ	P,		;C'EST LA VIE!

;HERE ON I/O ERROR READING RECORD

ILMCY8:	HRRZM	P1,-T3(P)	;RETURN WHAT WE MANAGED TO READ
	POPJ	P,		;PROPAGATE ERROR RETURN
				; NOTE THAT .IOIS3 IS "IN-A-RECORD-STATE"
				;  AND WILL EAT THE REST OF THE RECORD UPON
				;  SUBSEQUENT CALLS.
				;  THIS WON'T WORK IN NON-BLOCKING MODE!
;ILMCR - MACY11 RECORD STARTUP

ILMCR:	SKIPL	T4,.IOIS3(T1)	;GET RECORD STATE, USUALLY 0 = START NEW RECORD
	CAILE	T4,^D12		;LOOK GOOD?
	STOPCD	<Record state (.IOIS3) trashed in ILMCR>
	JRST	@ILMCTA(T4)	;YES, START/RESUME RECORD STARTUP

;HERE TO START UP A NEW MACY11 INPUT DATA RECORD

;STAGE 0 - SEARCH FOR "000001" RECORD STARTUP

ILMCR0:	PUSHJ	P,ILMCB		;GET A PACKED BYTE
	 POPJ	P,		;DIED?
	JUMPE	T2,ILMCR0	;EAT THE NULLS (RECORD FILLER)
	CAIE	T2,1		;MUST BE THE LOW ORDER OF "000001"
	JRST	ILMCRE		;NO, RECORD FORMAT ERROR
	AOS	.IOIS3(T1)	;STAGE ONE
ILMCR1:	PUSHJ	P,ILMCB		;GET THE HIGH-ORDER "000001"
	 POPJ	P,		;DIED
	JUMPN	T2,ILMCRE	;IF NOT 0 THEN BAD RECORD FORMAT
	AOS	.IOIS3(T1)	;STAGE TWO
ILMCR2:	PUSHJ	P,ILMCB		;GET LOW-ORDER LENGTH
	 POPJ	P,		;DIED
	MOVEM	T2,.IOIS1(T1)	;HANG ON TO IT
	AOS	.IOIS3(T1)	;STAGE THREE
ILMCR3:	PUSHJ	P,ILMCB		;GET HIGH-ORDER LENGTH BYTE
	 POPJ	P,		;DIED
	LSH	T2,^D08		;POSITION
	IOR	T2,.IOIS1(T1)	;AND GET FULL RECORD LENGTH
	SUBI	T2,6		;DISCOUNT RECORD HEADER
	MOVEM	T2,.IOIS1(T1)	;SET DATA BYTE COUNT
	AOS	.IOIS3(T1)	;STAGE FOUR
ILMCR4:	PUSHJ	P,ILMCB		;GET LOW-ORDER ADDRESS
	 POPJ	P,		;DIED
	MOVEM	T2,.IOIS0(T1)	;STASH IT AWAY
	AOS	.IOIS3(T1)	;STAGE FIVE
ILMCR5:	PUSHJ	P,ILMCB		;GET HIGH-ORDER ADDRESS
	 POPJ	P,		;DIED
	LSH	T2,^D08		;POSITION
	IORM	T2,.IOIS0(T1)	;GENERATE RECORD "ADDRESS"
	AOS	.IOIS3(T1)	;STAGE SIX (IN A RECORD)
	SETZM	.IOIS5(T1)	;INITIALIZE CHECKSUM VALUE
	JRST	.POPJ1##	;SUCCESSFUL RETURN, READY TO READ DATA

;HERE WHEN ERROR READING A RECORD, FINISH OFF THE STATED LENGTH

ILMCR6:	PUSHJ	P,ILMCB		;EAT A BYTE
	 POPJ	P,		;HO HUM
	SOSL	.IOIS1(T1)	;STILL MORE TO DO (INC CHECKSUM BYTE)?
	JRST	ILMCR6		;YES
	SETZM	.IOIS3(T1)	;NO, FINISHED OFF OLD RECORD,
	JRST	ILMCR0		;START UP A NEW RECORD
;HERE ON BAD RECORD FORMAT

ILMCRE:	MOVEI	M0,^D10		;STAGE "10"
	MOVEM	M0,.IOOS3(T1)	;SET DISPATCH
	MOVEI	M0,$EIRFE	;RECORD FORMAT ERROR
	POPJ	P,		;ERROR RETURN

;HERE ON RECORD FORMAT ERROR CONTINUATION, LOOK FOR "000001"
;THERE IS NO REALLY RELIABLE WAY TO RECOVER FROM A CORRUPTED FILE,
;BUT THIS AT LEAST GIVES THE USER A FIGHTING CHANCE

ILMCS0:	MOVEI	T2,^D10		;WE ARE STAGE TEN
	MOVEM	T2,.IOIS3(T1)	;NOTE THAT (IN CASE HERE FROM ILMCS1)
	PUSHJ	P,ILMCB		;GET ANOTHER BYTE
	 POPJ	P,		;DIED?
	JUMPN	T2,ILMCS0	;SEARCH FOR 000
	PUSHJ	P,ILMCB		;GET ANOTHER BYTE
	 POPJ	P,		;DIED?
	JUMPN	T2,ILMCS0	;(MACY11 ALWAYS HAS FILLER BETWEEN RECORDS)
	PUSHJ	P,ILMCB		;GET ANOTHER BYTE
	 POPJ	P,		;DIED?
	JUMPN	T2,ILMCS0	;WANT THREE FILLER BYTES
	AOS	.IOIS3(T1)	;STAGE ELEVEN
ILMCS1:	PUSHJ	P,ILMCB		;GET ANOTHER BYTE
	 POPJ	P,		;DIED?
	JUMPE	T2,ILMCS1	;GOBBLE UP THE RECORD FILLERS
	CAIE	T2,001		;LOOK LIKE A RECORD STARTUP?
	JRST	ILMCS0		;NO, BACK TO STAGE TEN
	AOS	.IOIS3(T1)	;STAGE TWELVE
ILMCS2:	PUSHJ	P,ILMCB		;GET ANOTHER BYTE
	 POPJ	P,		;OH WELL
	JUMPN	T2,ILMCS0	;IF NOT "000001" THEN NOT START OF RECORD
	MOVEI	T3,2		;YES, ENTER STAGE TWO
	MOVEM	T3,.IOIS3(T1)	;SET NEW RECORD PROCESSING STAGE
	JRST	ILMCR2		;AND DISPATCH TO NEW STATE
;HERE TO INPUT ONE PHYSICAL 8-BIT MACY11-PACKED BYTE
;
;THIS IS NOT CALLED AS AN ISR!

ILMCB:	SOSGE	T2,.IOIS2(T1)	;ADVANCE [UN]PACKING STATE
	JRST	ILMCB5		;NEED A NEW WORD
ILMCB1:	LDB	T2,ILMCTB(T2)	;EXTRACT NEW CURRENT PACKED BYTE
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

ILMCB5:	PUSHJ	P,ILBYT		;ADVANCE TO ANOTHER -10 WORD
	 POPJ	P,		;ERROR
	MOVEM	T2,.IOIS4(T1)	;SAVE LATEST 4 PACKED BYTES
	MOVEI	T2,3		;VIRGIN UNPACKING STATE IS 4 BYTES LEFT
	MOVEM	T2,.IOIS2(T1)	;SET FOR ILMCB
	JRST	ILMCB1		;AND INPUT THE FIRST ONE
;MACY11 TABLES

;RECORD STARTUP STATE DISPATCH TABLE (USED IN ERROR RETRY)

ILMCTA:	IFIW	ILMCR0		;STAGE 0
	IFIW	ILMCR1		;STAGE 1
	IFIW	ILMCR2		;STAGE 2
	IFIW	ILMCR3		;STAGE 3
	IFIW	ILMCR4		;STAGE 4
	IFIW	ILMCR5		;STAGE 5
	IFIW	ILMCR6		;STAGE 6
	IFIW	[STOPCD]	;STAGE 7
	IFIW	[STOPCD]	;STAGE 8
	IFIW	[STOPCD]	;STAGE 9
	IFIW	ILMCS0		;STAGE 10
	IFIW	ILMCS1		;STAGE 11
	IFIW	ILMCS2		;STAGE 12



;BYTE-PACKING (36-BIT WORD IN .IOIS4)

ILMCTB:	POINT	8,.IOIS4(T1),27	;BYTE 4
	POINT	8,.IOIS4(T1),35	;BYTE 3
	POINT	8,.IOIS4(T1),9	;BYTE 2
	POINT	8,.IOIS4(T1),17	;BYTE 1
;ILBUF  --  INPUT, LOCAL, GET NEXT BUFFER FROM MONITOR

ILBUF:	PUSHJ	P,.SACIO##	;SET IO
ILBUF0:	PUSHJ	P,TSAV14##	;PRESERVE THE USER'S T'S

;ASK FOR ANOTHER BUFFER OF DATA

ILBUF1:	HRLZ	T2,.IOCHN(IO)	;I/O CHANNEL NUMBER
	HRRI	T2,.FOINP	;"INPUT" FUNCTION
	MOVE	T1,[1,,T2]	;FILOP. ARG POINTER TO
	FILOP.	T1,		;READ NEW BUFFER
	 JRST	ILBUF4		;HMMM, CHECK OUT POSSIBLE ERROR
	SKIPG	.IOIBC(IO)	;ENSURE THAT THE MONITOR GAVE US SOMETHING
	STOPCD	<FILOP IN returned successfully with no data in ILBUF>
	AOS	.IOIUC(IO)	;INCREMENT IN UUO COUNT
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;CHECK OUT INPUT EXCEPTION CONDITION

ILBUF4:	TXNE	T1,IO.EOF!IO.ERR;ERROR AND/OR END OF FILE?
	JRST	ILBUF6		;YES, GO HANDLE
	MOVE	T3,.IOIOM(IO)	;GET I/O MODE
	TXNN	T3,IM.AIO	;FILE OPEN FOR NON-BLOCKING I/O?
	STOPCD	<FILOP IN failed with no error/EOF bits in ILBUF>
	MOVX	T1,$SCNBI	;SCHEDULER - NON-BLOCKING INPUT
	PUSHJ	P,@.IOSCH(IO)	;CALL THE SCHEDULER
	 POPJ	P,		;DUH?
	JRST	ILBUF1		;TRY INPUTTING AGAIN
;ERROR OR END OF FILE

ILBUF6:	TXNN	T1,IO.ERR	;ERROR?
	JRST	IEIEF		;NO, EOF, SET INPUT END OF FILE

;I/O ERROR, TRY TO FIGURE OUT WHAT HAPPENED

	MOVEM	T1,.I1IOS(IO)	;SAVE TOPS-10 I/O STATUS WORD
	TXC	T1,IO.ERR	;FLIP ALL THE BITS
	TXCN	T1,IO.ERR	;WERE ALL BITS SET?
	JRST	ILBUE3		;YES, EXTENDED I/O ERROR STATUS
	LDB	T2,[POINTR .I1DTY(IO),TY.DEV]  ;GET DEVICE TYPE
	CAIN	T2,.TYDSK	;IS IT A DISK?
	JRST	ILBUD1		;YES, MORE GUESSWORK INVOLVED

;RANDOM I/O ERROR ENCODED INTO IO.ERR, TRANSLATE DIRECTLY AND RETURN

ILBUE1:	TXNE	T1,IO.BKT	;"BLOCK TOO LARGE" ?
	MOVEI	M0,$EIBKT	;YES
	TXNE	T1,IO.DTE	;"DATA CHECKSUM/PARITY ERROR" ?
	MOVEI	M0,$EIDAT	;YES
	TXNE	T1,IO.DER	;"DEVICE ERROR"
	MOVEI	M0,$EIDEV	;YES
	TXNE	T1,IO.IMP	;"IMPROPER MODE"
	MOVEI	M0,$EIIMP	;YES
	POPJ	P,		;RETURN I/O ERROR


;EXTENDED I/O ERROR, NEED TO RETRIEVE EXTENDED ERROR CODE

ILBUE3:	PUSHJ	P,IOERX1	;RETRIEVE AND TRANSLATE EXTENDED I/O ERROR CODE
	 MOVSI	M0,$EIXXX	;UNKNOWN ERROR
	HLRZ	M0,M0		;POSITION INPUT TRANSLATION
	POPJ	P,		;RETURN I/O ERROR


;DISK ERROR, SNIFF AROUND A BIT

ILBUD1:	MOVE	T2,.IOCHN(IO)	;I/O CHANNEL
	MOVEM	T2,.I1NSP+.DCNAM(IO)  ;SET IN DSKCHR BLOCK
	MOVSI	T2,.I1NSL	;LENGTH AND
	HRRI	T2,.I1NSP(IO)	;ADDRESS OF DSKCHR BLOCK
	DSKCHR	T2,		;READ ALL ABOUT THAT UNIT/STRUCTURE
	 JRST	ILBUE1		;FORGET IT
	MOVEI	M0,$EIOFL	;DEVICE OFFLINE
	TXNE	T2,DC.OFL	;IS DISK UNIT OFFLINE?
	POPJ	P,		;YES, ERROR
	JRST	ILBUE1		;NOTHING MUCH FOR NOW
;IOIIE  --  INPUT, ERROR, INPUT-NOT-OPEN

	ENTRY	.IOIIE

.IOIIE:	MOVX	M0,$EIINO	;INPUT-NOT-OPEN STATUS
	POPJ	P,		;RETURN ERROR CODE



;IEIEF  --  INPUT, ERROR, END-OF-FILE

IEIEF:	XMOVEI	M0,IEIEF1	;ADDRESS TO KEEP RETURNING EOF
	MOVEM	M0,.IOISR(IO)	;SET NEW INPUT STATE
IEIEF1:	MOVEI	M0,$EIEOF	;END-OF-FILE STATUS
	POPJ	P,		;RETURN EXCEPTION CODE
;INITIALIZE FOR REMOTE FILE READ

IRINI:	MOVD1	T1,ORG		;GET FILE ORGANIZATION
	CAIE	T1,$DVOSQ	;IS IT SEQUENTIAL?
	STOPCD	<DAP file organization not "sequential" in IRINI>
	MOVE	T1,.IOIOC(IO)	;GET I/O CONTROL
	TXNE	T1,IC.BLK!IC.DMP;FUNNY MODE SET?
	STOPCD	<Block/Dump mode selected in IRINI>

;LOOKS OK, INITIALIZE VARIABLES AS NEEDED

	MOVEI	T1,177777	;CRC POLYNOMIAL SEED
	MOVEM	T1,.IODIK(IO)	;SET FOR FILE DATA CRC COMPUTATION

;DISPATCH TO DATATYPE-DEPENDENT FINAL INITIALIZATION

	MOVD	T1,DTY		;GET DAP DATA TYPE FIELD
	TFNE	T1,ASC		;ASCII CHARACTER DATA?
	JRST	IRIA		;YES
	TFNE	T1,IMG		;BINARY (IMAGE) DATA?
	JRST	IRIB		;YES
	STOPCD	<DAP data type neither ASCII nor binary in IRINI>
;INITIALIZE FOR REMOTE ASCII CHARACTER DATA READ

IRIA:	MOVE	T1,.IOIOC(IO)	;GET I/O CONTROL FLAGS
	TXNE	T1,IC.RSI	;WANTING BYTE MODE I PRESUME
	STOPCD	<Record-structured I/O selected in IRIA>
	MOVD1	T2,RFM		;RECORD FORMAT
	MOVD	T3,RAT		;RECORD ATTRIBUTES FLAGS
	TFZ	T3,<MCY,NSB>	;REMOTE MACY11-PACKING DOESN'T AFFECT US
	JSP	T4,.CDISP##	;DISPATCH ON FORMAT TYPE
		IRIA10,,$DVFNR	;"NO FORMAT"
		IRIA10,,$DVFFX	;FIXED-LENGTH RECORDS
		IRIA10,,$DVFVR	;VARIABLE-LENGTH RECORDS
		IRIA10,,$DVFVF	;VARIABLE-LENGTH WITH FIXED CONTROL
		IRIA10,,$DVFST	;ASCII "STREAM"
		IRIA10,,$DVFSC	;ASCII "STREAM-CR"
		IRIA10,,$DVFSL	;ASCII "STREAM-LF"
		0		;NONE OTHER
	STOPCD	<Unknown record format in IRIA>

;KNOWN FORMAT, CHECK OUT ATTRIBUTES

IRIA10:	TFZ	T3,<FCC,ILC,PRN,EFC,CCC,LSA>  ;MASK OUT JUNK
	FJUMPE	T3,RAT,IRIA14	;ERROR IF ANY RECORD ATTRIBUTES LEFT OVER
	STOPCD	<Unknown or illegal record format/attributes in IRIA>
IRIA14:	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNE	T1,IO.NEP	;ACTIVE OR PASSIVE LINK?
	JRST	IRIA20		;PASSIVE, NO STARTUP NEEDED
	PUSHJ	P,DPSII1##	;ACTIVE, NEED CONTROL(CONNECT), CONTROL(GET)
	 POPJ	P,		;BUMMER
IRIA20:	XMOVEI	T2,IRAS		;ASCII INPUT SERVICE ROUTINE
	MOVEM	T2,.IOISR(IO)	;SET IN CDB DISPATCH
	XMOVEI	T2,IRACL	;ASCII CLOSE INPUT PROCESSOR
	MOVEM	T2,.IOISS(IO)	;SET SPECIAL SHUTDOWN FUNCTION
	JRST	.POPJ1##	;INPUT INITIALIZED
;HERE TO SHUTDOWN THE REMOTE ASCII INPUT DATA STREAM
;
;			*** NOTE ***
;
;		ENTERED FROM CLOSE AT SACIO LEVEL

IRACL:	SKIPG	T1,.IODIM(IO)	;IN A DAP MESSAGE?
	JRST	.POPJ1##	;NO, ALL SET THEN (CLOSE WILL EAT ANY NEW DATA)
	CAIE	T1,$DHDAT	;YES, IS IT DATA?
	STOPCD	<Non-data DAP message outstanding in IRACL>
	PUSHJ	P,RDEAT1##	;A DATA MESSAGE, SIMPLY EAT THE REST OF IT
	 POPJ	P,		;FAILED?
	JRST	.POPJ1##	;READY FOR CLOSE TO DO ITS THING
;REMOTE ASCII ISR. HANDLES ALL FORMS (STREAM, VAX, ETC.)

IRAS:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
IRAS02:	XMOVEI	T1,IRAS		;NOT-WITHIN-A-RECORD STATE
	MOVEM	T1,.IOISR(IO)	;SET IN CASE OF ERROR RESTART
	SKIPLE	.IODIM(IO)	;BETTER NOT BE IN A MESSAGE
	STOPCD	<DAP input message in progress in IRAS>
	PUSHJ	P,RDMSG1##	;START UP A NEW MESSAGE
	 POPJ	P,		;NETWORK DIED?
	CAIN	T2,$DHDAT	;IS IT EXPECTED DATA?
	JRST	IRAS20		;YES, START UP A NEW TEXT RECORD

;INPUT MESSAGE NOT DATA, SEE IF STATUS (MAYBE EOF).

IRAS10:	CAIE	T2,$DHSTS	;LOOKING AT A STATUS MESSAGE?
	JRST	IRAS17		;NO
	PUSHJ	P,RDSTS1##	;READ AND CONVERT THE DAP STATUS
	 POPJ	P,		;ERROR READING STATUS?
	CAIE	M0,$EGOIP	;"OPERATION IN PROGRESS"
	CAIN	M0,$EGAOK	;"A-OK"
	JRST	IRAS02		;YES, IGNORE IT, LOOK FOR A NEW ONE
	CAIE	M0,$EIEOF	;END OF FILE?
	POPJ	P,		;RETURN CODE (ERROR, ETC.)
	MOVE	T1,.IOISF(IO)	;GET INPUT SERVICE FLAGS
	TXNE	T1,IS.IVI	;VAX-PRINT-FILE FORMAT INITIALIZED?
	TXNN	T1,IS.IVC	;YES, WAS LAST THING <CR>?
	JRST	IEIEF		;NO TO ONE OF THE ABOVE, SET EOF STATUS
	XMOVEI	T1,IEIEF1	;YES, FLAG TO RETURN EOF STATUS
	MOVEM	T1,.IOISR(IO)	;ON NEXT ISR CALL
	MOVEI	T2,.CHLFD	;MEANWHILE, GENERATE A TRAILING <LF> CHAR
	PJRST	IRAS47		;AND RETURN THAT FOR THIS ISR CALL

IRAS17:	MOVE	M0,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	M0,IO.NEP	;ACTIVE OR PASSIVE LINK?
	STOPCD	<Received DAP message neither DATA nor STATUS in IRAS>
	PUSHJ	P,RDMSR1##	;PASSIVE, RE-EAT THE MESSAGE
	 POPJ	P,		;DUH?
	MOVEI	M0,$EINMP	;TELL FAL THAT AN INPUT MESSAGE IS PENDING
	POPJ	P,		;TAKE EXCEPTION RETURN
;HERE TO START UP A NEW DATA RECORD, HANDLING ALL THE PERMUTATIONS . . .

IRAS20:	PUSHJ	P,RDDAT1##	;STARTUP DATA MESSAGE READING
	 POPJ	P,		;ERROR?
	MOVD1	P1,RFM		;GET RECORD FORMAT
	MOVD	P2,RAT		;AND RECORD ATTRIBUTES
	CAIE	P1,$DVFVF	;VARIABLE WITH FIXED CONTROL HEADER?
	JRST	IRAS30		;NO, ALL OTHERS ARE FAIRLY STRAIGHTFORWARD

;HERE FOR VARIABLE-LENGTH RECORDS WITH FIXED-LENGTH CONTROL HEADER
;IT MUST BE EITHER A VAX "PRINT" FILE, OR THE LINE-SEQUENCE NUMBER
;FOR LINE-SEQUENCED ASCII.

	MOVD1	T3,FSZ		;GET FIXED-HEADER SIZE
	JUMPE	T3,IRAS30	;IF 0, IGNORE IT
	TFNE	P2,LSA		;LINE-SEQUENCED ASCII?
	JRST	IRAS30		;YES, HANDLED AT IRAS30

;HERE FOR NON-LSN FIXED CONTROL HEADERS (E.G., VAX PRINT FILE)

IRAS28:	PUSHJ	P,RDBYC0##	;GET LOW-ORDER HEADER BYTE
	 JRST	IRAS29		;ERROR, CAN'T END HERE
	MOVEM	T2,.IOISH(IO)	;SET LOW-ORDER HEADER BYTE
	SOJLE	T3,IRAS30	;END OF HEADER?
	PUSHJ	P,RDBYC0##	;GET HIGH-ORDER HEADER BYTE
	 JRST	IRAS29		;ERROR, CAN'T END HERE
	LSH	T2,1*^D8	;POSITION HIGH-ORDER BYTE
	IORM	T2,.IOISH(IO)	;AND MERGE IT IN
	SOJLE	T3,IRAS30	;END OF HEADER?
	PUSHJ	P,RDBYC0##	;GET ANOTHER BYTE (???)
	 JRST	IRAS29		;ERROR, CAN'T END HERE
	LSH	T2,2*^D8	;POSITION THIRD BYTE
	IORM	T2,.IOISH(IO)	;AND MERGE IT IN
	SOJLE	T3,IRAS30	;END OF HEADER?
	PUSHJ	P,RDBYC0##	;GET ANOTHER BYTE (???)
	 JRST	IRAS29		;ERROR, CAN'T END HERE
	LSH	T3,2*^D8	;POSITION FOURTH BYTE
	IORM	T2,.IOISH(IO)	;AND MERGE IT IN
	SOJLE	T3,IRAS30	;END OF HEADER?
	STOPCD	<Fixed-header greater than four bytes in IRAS20>


;ERRORS

IRAS29:	JUMPN	M0,.POPJ##	;PROPAGATE NETWORK DEATH
	MOVEI	M0,$EIRFE	;RECORD FORMAT ERROR
	POPJ	P,		;RETURN OUR OWN ERROR
;NOW START THE ACTUAL DATA PORTION OF THE RECORD

IRAS30:	MOVX	T3,IS.IVI!IS.IVC;THE IMPORTANT CROSS-RECORD FLAG(S)
	ANDM	T3,.IOISF(IO)	;CLEAR OUT JUNK POSSIBLY LEFT BY ERROR
	MOVX	T3,IS.ICL!IS.ICE;THE IMPLIED <CR><LF> AT EOR FLAGS
	TFZE	P2,ILC		;IMPLIED <LF>-<CR> ENVELOPE?
	IORM	T3,.IOISF(IO)	;YES, FLAG [PROBABLY] NEED <CR><LF> AT EOR
				; NOTE THAT VAX/VMS "STREAM-CR/LF" FORMATS
				; COME ACCROSS WITH IMPLIED LFCR ATTRIBUTES
				; WITH EMBEDDED CARRIAGE CONTROL WHICH WILL
				; OVERRIDE IS.ICL (SEE IRAS60/FOLLOWING).
	XMOVEI	T1,IRAS60	;IN-A-RECORD STATE DISPATCH
	MOVEM	T1,.IOISR(IO)	;SET NEW STATE DISPATCH
				; THIS IS DONE HERE SO THAT SHOULD IRAFC/ETC
				; GET AN ERROR, THE REST OF THE RECORD CAN
				; CONTINUE TO BE READ, ALBEIT PROBABLY NOT
				; CORRECTLY. HOWEVER, THIS SHOULD AT LEAST
				; GIVE THE USER A CHANCE TO SEE THE DATA!

;NOW HANDLE THE FUNNY RECORD ATTRIBUTE CASES - FORTRAN, VAX PRINT FILE, ETC.

	TFZE	P2,PRN		;VAX "PRINT" FILE FORMAT?
	JRST	IRAS40		;YES, HANDLE PRINT FILE FUNNIES
	TFNE	P2,LSA		;LINE SEQUENCED ASCII?
	JSP	P1,IRALS	;YES, HANDLE LSN
	TFZE	P2,CCC		;COBOL CARRIAGE CONTROL?
	JSP	P1,IRACC	;YES, HANDLE COBOL (???)
	TFZE	P2,FCC		;FORTRAN CARRIAGE CONTROL?
	JSP	P1,IRAFC	;YES, HANDLE FORTRAN SILLYNESS
IRAS36:	MOVE	T1,.IOIOC(IO)	;GET I/O CONTROL
	TFNE	P2,LSA		;IS LSN AVAILABLE?
	TXNN	T1,IC.LSN	; AND DOES THE USER WANT LSN'S?
	JRST	IRAS61		;NO, JUST RETURN DATA
	MOVE	T1,.IOISH(IO)	;GET FIXED-LENGTH HEADER WORD
	MOVEM	T1,-T2(P)	;AND SET TO RETURN IT
	MOVEI	M0,$EILSN	;FLAG LSN EXCEPTION RETURN
	POPJ	P,		;AND GIVE THE CALLER THE LSN
;HERE TO HANDLE VAX PRINT-FILE FORMAT RECORDS
;
;Each record has a two-byte fixed-length header which is interpreted
;as a prefix carriage-control byte and a postfix carriage-control byte.
;
;Each carriage-control byte is interpreted as follows:
;
;  BIT	7  6  5  4  3  2  1  0
;
;	0  <====LF COUNT=====>		;Count of line feeds
;	1  0  0  <=CTL CHAR==>		;Control character 000 - 037
;	1  1  0  <=CTL CHAR==>		;Control character 200 - 237
;	1  x  1  x  x  x  x  x		;Reserved/Unimplemented

;FIRST, SAVE POSTFIX CARRIAGE CONTROL FOR EVENTUAL END-OF-RECORD (IRAS90)

IRAS40:	LDB	T2,[POINTR .IOISH(IO),^O377_^D08]  ;GET POSTFIX CARRIAGE-CONTROL
	JUMPE	T2,IRAS45	;IF NULL, NO POSTFIX CARRIAGE CONTROL
	TRZE	T2,200		;LINEFEEDS OR CHARACTER?
	JRST	IRAS42		;CHARACTER
	MOVX	T1,IS.INL	;LINEFEED(S), THE "N" LINEFEEDS FLAG
	IORM	T1,.IOISF(IO)	;SET IN I/O FLAGS
	JRST	IRAS44		;AND SET IS.IXX TO LF COUNT

IRAS42:	TRZE	T2,100		;UPPER OR LOWER CONTROL?
	TRO	T2,200		;UPPER
	TRZE	T2,40		;RESERVED?
	MOVEI	T2,"?"		;*** NEEDS ERROR CODE DEFERRED
IRAS44:	DPB	T2,[POINTR .IOISF(IO),IS.IXX]  ;SAVE POSTFIX CONTROL CHARACTER

;NOW PROCESS PREFIX CARRIAGE-CONTROL

IRAS45:	LDB	T2,[POINTR .IOISH(IO),^O377_^D00]  ;GET PREFIX CARRIAGE-CONTROL
	JUMPE	T2,IRAS61	;IF NULL, START UP DATA
	TRZN	T2,200		;LINEFEED(S) OR CHARACTER
	JRST	IRAS48		;LINEFEED(S)
	TRZE	T2,100		;UPPER OR LOWER CONTROL?
	TRO	T2,200		;UPPER
	TRZE	T2,40		;RESERVED?
	MOVEI	T2,"?"		;*** NEEDS ERROR CODE NOW
IRAS47:	MOVEM	T2,-T2(P)	;POSITION RETURNED DATA CHARACTER
	JRST	.POPJ1##	;RETURN "DATA" CHARACTER TO USER
;LEADING <LF>'S

IRAS48:	MOVX	T1,IS.IVI	;THE "INITIALIZED" FLAG
	TDNN	T1,.IOISF(IO)	;IS THIS FIRST TIME HERE?
	JRST	[IORM	T1,.IOISF(IO)	;YES, FLAG THAT FACT
		SOJE	T2,IRAS61	;SUPPRESS FIRST LEADING <LF>
		JRST	.+1]		;MULTIPLE LEADING <LF>S
	MOVEM	T2,.IOIS0(IO)	;SAVE LF COUNT
	MOVEI	T2,.CHLFD	;RETURN A <LF> CHARACTER
	XMOVEI	T1,IRAS49	;SPECIAL HACK ISR FOR MULTIPLE LFS
	SOSE	.IOIS0(IO)	;NEED MORE THAN ONE LF?
	MOVEM	T1,.IOISR(IO)	;YES
	JRST	IRAS47		;RETURN THIS LINEFEED


;SPECIAL INTERMEDIATE ISR FOR MULTIPLE-LINEFEEDS

IRAS49:	SOSGE	.IOIS0(T1)	;NEED ANOTHER LINEFEED?
	JRST	IRAS60		;NO
	MOVEI	T2,.CHLFD	;YES
	JRST	.POPJ1##	;SUCCESS RETURN WITH "DATA" CHARACTER
;HERE TO START UP AN ASCII DATA RECORD

;ENTER HERE AS AN ISR

IRAS60:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S
IRAS61:	MOVD1	T1,RFM		;DAP RECORD FORMAT
	CAIN	T1,$DVFNR	;UNFORMATTED ASCII?
	JRST	IRAS63		;YES, SIMPLEST CASE (NO PROCESSING NEEDED)
	CAIE	T1,$DVFSC	;ASCII "STREAM-CR"?
	CAIN	T1,$DVFSL	;ASCII "STREAM-LF"?
	JRST	IRAS70		;YES, WEIRD TWIST ON G.P. ASCII ISR
	JRST	IRAS80		;NO, USE GENERAL-PURPOSE NETWORK ASCII ISR


;HERE TO DEAL WITH UNFORMATTED ASCII (E.G., TOPS10)

IRAS63:	XMOVEI	T2,IRAS65	;SELECT UNFORMATTED ASCII ISR
	MOVEM	T2,.IOISR(IO)	;AND SET IT FOR FUTURE CALLS
	MOVE	T1,IO		;REPOSITION CDB ADDRESS
	PUSHJ	P,IRAS65	;GET FIRST CHARACTER IN DAP "RECORD"
	 POPJ	P,		;PROPAGATE ERROR TO USER
	MOVEM	T2,-T2(P)	;POSITION RETURN DATA BYTE
	JRST	.POPJ1##	;SUCCESS RETURN


;ENTER HERE AS AN ISR (UNFORMATTED ASCII)

IRAS65:	PUSHJ	P,.RDBYC##	;GET A DATA BYTE
	 CAIA			;OOPS, ERROR/EXCEPTION RETURN
	JRST	.POPJ1##	;SUCCESS RETURN WITH DATA BYTE IN T2

;GOT ERROR/EXCEPTION, MUST SWITCH TO "IRASXX CONTEXT" TO PROCESS ERROR

	PUSHJ	P,.SACIO##	;SELECT I/O CONTEXT
	PUSHJ	P,.SAVE4##	;PROTECT THE P'S
	PUSHJ	P,TSAV14##	;PROTECT THE T'S
	JRST	IRAS90		;DECIPHER THE ERROR/EXCEPTION RETURN
;HERE TO DEAL WITH ASCII "STREAM-CR" OR "STREAM-LF" RECORDS

IRAS70:	XMOVEI	T2,IRAS72	;SELECT "STREAM-CR/LF" ISR
	MOVEM	T2,.IOISR(IO)	;AND SET IT FOR FUTURE CALLS
	JRST	IRAS73		;FIRE UP FIRST DATA CHARACTER


;ENTER HERE AS AN ISR

IRAS72:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S
IRAS73:	PUSHJ	P,RDBYC1##	;GET NEXT DAP DATA BYTE
	 JRST	IRAS90		;NO MORE DATA BYTES?
	MOVEM	T2,-T2(P)	;POSITION RETURN DATA BYTE
	CAIGE	T2," "		;IF NOT CONTROL CHARACTER
	CAIN	T2,.CHTAB	;OR IF A TAB
	JRST	.POPJ1##	;THEN SUCCESSFUL RETURN NOW

;EMBEDDED CONTROL CHARACTER, SEE IF END OF RECORD

	MOVD1	T1,RFM		;GET DAP RECORD FORMAT FIELD
	CAIN	T1,$DVFSC	;ASCII "STREAM-CR" FORMAT?
	CAIE	T2,.CHCRT	;YES, IS THIS A <CR>?
	CAIA			;NO
	JRST	IRAS75		;STREAM-CR AND A <CR>, SEE IF EOR
	CAIN	T1,$DVFSL	;ASCII "STREAM-LF" FORMAT?
	CAIE	T2,.CHLFD	;YES, IS THIS A <LF>?
	JRST	IRAS85		;NO, TREAT AS RANDOM EMBEDDED CONTROL CHAR

;CHECK FOR EOR, IF SO THEN TIME TO GENERATE <CR><LF> SEQUENCE

IRAS75:	PUSHJ	P,RDBYT1##	;READ ANOTHER DAP DATA BYTE
	 JRST	IRAS76		;NO MORE DATA (WHICH IS WHAT WE WANT HERE)
	HRROM	T2,.IODIR(IO)	;FLAG DATA BYTE TO BE RE-READ NEXT CALL
	JRST	IRAS87		;TREAT AS RANDOM EMBEDDED CARRIAGE CONTROL

IRAS76:	HRLI	M0,400000	;FLAG EXCEPTION RETURN
	MOVEM	M0,.IODIR(IO)	;FOR NEXT CALL TO RDBYT
	TRNE	M0,777777	;HIT A REAL ERROR, OR JUST NO MORE DATA?
	JRST	IRAS87		;ERROR, RETURN CHAR NOW, ERROR NEXT CALL
	MOVEI	T2,.CHCRT	;EOR, RETURN <CR> FIRST
	MOVEM	T2,-T2(P)	;SET RETURN DATA BYTE
	MOVX	T1,IS.ILF	;THE LF-AT-EOR FLAG
	IORM	T1,.IOISF(IO)	;MARK THAT WE NEED A <LF> LATER
	JRST	IRAS87		;SUCCESS RETURN, CLEARING IMPLIED LFCR
;GENERAL PURPOSE NETWORK ASCII ISR, HANDLING MOST OF THE RECORD-STRUCTURED
;CASES, RSX/VAX IMPLIED LFCR, "PRINT" FILES, ETC.)

IRAS80:	XMOVEI	M0,IRAS82	;SELECT THE G.P. ASCII ISR
	MOVEM	M0,.IOISR(IO)	;AND SET IT FOR FUTURE CALLS
	JRST	IRAS83		;GO READ FIRST DATA CHARACTER


;ENTER HERE AS AN ISR

IRAS82:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S
IRAS83:	PUSHJ	P,RDBYC1##	;GET NEXT DAP DATA BYTE
	 JRST	IRAS90		;NO MORE DATA BYTES?
	MOVEM	T2,-T2(P)	;POSITION RETURN DATA BYTE
	CAIGE	T2," "		;IF NOT CONTROL CHARACTER
	CAIN	T2,.CHTAB	;OR IF A TAB
	 CAIA			;DATA CHARACTER, MANIPULATE ICL IF NECESSARY
	JRST	IRAS85		;EMBEDDED CONTROL

;WE HAVE A LIVE DATA CHARACTER.  HOWEVER, A PRECEEDING IMBEDDED CONTROL 
;CHARACTER COULD HAVE CLEARED IS.ICL.  TO PREVENT CONCATENATING THE NEXT
;RECORD TO THIS ONE, WE WANT TO RE-SET IS.ICL IF IT ONCE WAS SET.  IS.ICE
;TELLS ALL.

	MOVX	M0,IS.ICE	;WAS IMPLIED <CR><LF> ENVELOPE SET AT START
	TDNN	M0,.IOISF(IO)	;OF THIS RECORD?
	 JRST	.POPJ1##	;NO, SUCCESSFUL RETURN
	MOVX	M0,IS.ICL	;YES, RE-SET IT NOW
	IORM	M0,.IOISF(IO)	;TO PREVENT GRATITUIOUS CONCATENATIONS
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;EMBEDDED CONTROL CHARACTER, CHECK IT OUT

IRAS85:	CAIL	T2,.CHLFD	;IF A <LF>, <VT>, OR <FF>
	CAILE	T2,.CHFFD	; . . .
	CAIL	T2,.CHDLE	;OR A <DLE>, <DC1>, <DC2>, <DC3>, OR <DC4>
	CAILE	T2,.CHDC4	; . . .
	CAIL	T2,.CHCNZ	;OR A <SUB>, OR <ESC>
	CAILE	T2,.CHESC	; . . .
	JRST	.POPJ1##	;RETURN RANDOM CONTROL CHARACTER
IRAS87:	MOVX	M0,IS.ICL	;THE IMPLIED <CR><LF> FLAG
	ANDCAM	M0,.IOISF(IO)	;EMBEDDED CARRIAGE-CONTROL ENCOUNTERED
	JRST	.POPJ1##	;RETURN ASCII CHARACTER
;HERE AT EOR, CHECK FOR IMPLIED <CR><LF> ETC.

IRAS90:	JUMPE	M0,IRAS92	;OK IF JUST EOR
	POPJ	P,		;ELSE REAL ERROR, DIE

;ENTER HERE AS AN ISR

IRAS91:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14	;AND THE T'S TOO
IRAS92:	MOVX	T1,IS.ICE	;CLEAR IMPLIED CRLF ENVELOPE FLAGE
	ANDCAB	T1,.IOISF(IO)	;IN CASE SET, AND GET STATUS
	JUMPE	T1,IRAS02	;IF NOTHING SPECIAL PENDING, START UP A NEW REC
	TXNE	T1,IS.INL	;"N" LINEFEED-FLAG SET?
	JRST	IRAS97		;YES
	TXZE	T1,IS.ICL	;IMPLIED <CR><LF> STILL PENDING?
	TXO	T1,IS.ICR!IS.ILF;YES, FLAG NEED <CR> AND <LF>
	MOVEI	T2,.CHCRT	;A <CR>
	TXZE	T1,IS.ICR	;NEED A <CR>?
	JRST	IRAS99		;YES
	MOVEI	T2,.CHLFD	;A <LF>
	TXZE	T1,IS.ILF	;NEED A <LF>?
	JRST	IRAS99		;YES
	LDB	T2,[POINTR T1,IS.IXX]  ;SPECIAL CHARACTER
	TXZE	T1,IS.IXX	;SPECIAL CHARACTER NEEDED?
	JRST	IRAS99		;YES
	TXZ	T1,IS.IVI!IS.IVC;CLEAR JUNK FLAGS
	JUMPE	T1,IRAS02	;AND START UP A NEW RECORD
	STOPCD	<Unknown ISF flags in IRAS90>

IRAS97:	LDB	T2,[POINTR T1,IS.IXX]  ;[1044] COUNT OF LINEFEEDS REMAINING
	SUBI	T2,1		;[1044] LESS THE ONE WE'RE ABOUT TO RETURN
	DPB	T2,[POINTR T1,IS.IXX]  ;[1044] IS NEW COUNT OF LINEFEEDS REMAINING
	TXNN	T1,IS.IXX	;MORE LINEFEEDS COMING?
	TXZ	T1,IS.INL	;NO, CLEAR THE "N" LINEFEEDS FLAG
	MOVEI	T2,.CHLFD	;RETURN A <LF> CHARACTER
IRAS99:	CAIE	T2,.CHCRT	;RETURNING A <CR>?
	TXZA	T1,IS.IVC	;NO, LAST THING NOT A <CR>
	TXO	T1,IS.IVC	;YES, LAST THING IS A <CR>
	MOVEM	T1,.IOISF(IO)	;SAVE NEW EOR FLAGS
	MOVEM	T2,-T2(P)	;POSITION RETURN DATA
	XMOVEI	T1,IRAS91	;SELECT NEW EOR ISR
	MOVEM	T1,.IOISR(IO)	;AND SET IT FOR CALLER
	JRST	.POPJ1##	;RETURN WITH ASCII DATA
;HELPERS FOR REMOTE ASCII INPUT

;IRACC  --  COBOL CARRIAGE CONTROL

IRACC:	STOPCD	<COBOL carriage control not implemented>
;IRAFC  --  FORTRAN CARRIAGE CONTROL
;CALL IS:
;
;	JSP	P1,IRAFC
;
;RETURN CPOPJ0 IF ERROR RETURN, CPOPJ1 IF VALID DATA BYTE, OR JRST (P1) IF
;NO DATA BYTE.

IRAFC:	PUSHJ	P,RDBYC0##	;GET THE FIRST BYTE OF THE RECORD
	 JRST	IRAFE0		;ERROR, IT MUST EXIST
	MOVEI	T4,IRAFCT	;THE CONVERSION TABLE
	PUSHJ	P,.CFIND##	;LOCATE CARRIAGE CONTROL
	 JRST	IRAFE1		;ERROR, UNKNOWN CARRIAGE CONTROL
	MOVE	T1,0(T1)	;FETCH CARRIAGE CONTROL SERVICE FLAGS
	DPB	T1,[POINTR .IOISF(IO),IS.IXX]  ;STORE SPECIAL CONTROL (IF ANY)
	TRZ	T1,777		;CLEAR OUT SPECIAL CHARACTER (IF ANY)
	IORM	T1,.IOISF(IO)	;SET NEW SERVICE FLAGS
	JRST	0(P1)		;SUCCESSFUL RETURN (WITH NO DATA CHARACTER)


;ERROR - PREMATURE EOR

IRAFE0:	JUMPN	M0,.POPJ##	;PROPAGATE NETWORK DEATH
	PUSHJ	P,RDEAT0##	;FLUSH RECORD REMNANTS
	 JFCL			;HO HUM
	MOVEI	M0,$EIEOR	;PREMATURE END-OF-RECORD ERROR
	POPJ	P,		;RETURN ERROR CONDITION

;ERROR - UNKNOWN CARRIAGE CONTROL

IRAFE1:	PUSHJ	P,RDBYR0##	;RETURN DATA BYTE TO BE RE-READ
	 JFCL			;HO HUM
	MOVEI	M0,$EIFCC	;ILLEGAL FORTRAN CARRIAGE CONTROL
	POPJ	P,		;ERROR RETURN


;THE FORTRAN CARRIAGE CONTROL TRANSLATION TABLE

IRAFCT:	XWD	[IS.ICR!IS.ILF],   " "	;SINGLE-SPACE TEXT LINE
	XWD	[IS.ICR!IS.INL+2], "0"	;DOUBLE-SPACE TEXT LINE
	XWD	[IS.ICR!IS.INL+3], "-"	;TRIPLE-SPACE TEXT LINE
	XWD	[IS.ICR+.CHFFD],   "1"	;NORMAL TEXT PAGE
	XWD	[IS.ICR+.CHDLE],   "2"	;1/2 PAGE SKIP
	XWD	[IS.ICR+.CHVTB],   "3"	;1/3 PAGE SKIP
	XWD	[IS.ICR+.CHDC4],   "/"	;1/6 PAGE SKIP
	XWD	[IS.ICR+.CHDC3],   "*"	;1/10 PAGE SKIP
	XWD	[IS.ICR+.CHDC2],   "."	;1/20 PAGE SKIP
	XWD	[IS.ICR+.CHDC1],   ","	;1/30 PAGE SKIP
	XWD	[IS.ICR],	   "+"	;OVERPRINT LINE
	0
;HERE FOR NETWORK LSN'S

IRALS:	SETZB	T4,.IOISH(IO)	;CLEAR OUT LSN TEMPLATE
	MOVD1	T3,FSZ		;GET SIZE OF LSN "FIXED CONTROL" FIELD
	JUMPE	T3,(P1)		;IF EMPTY, JUST IGNORE IT
IRALS1:	PUSHJ	P,RDBYC0##	;GET FIXED-CONTROL CHARACTER
	 JRST	IRAS29		;ERROR, CAN'T END HERE
	CAIE	T2,0		;IF NULL, OR
	CAIN	T2," "		;IF LEADING SPACE,
	SOJG	T3,IRALS1	;JUST EAT IT
	JUMPLE	T3,(P1)		;IF NULL CONTROL HEADER, JUST IGNORE IT
	CAIE	T2,.CHFFD	;PAGE MARK?
	JRST	IRALS5		;NO
	MOVSI	T2,(1B0)	;YES, FLAG IT
	MOVEM	T2,.IOISH(IO)	;AND SET IT FOR LATER
	SOJLE	T3,(P1)		;QUIT IF ONLY A PAGE MARK
IRALS4:	PUSHJ	P,RDBYC0##	;NEXT LSN DIGIT
	 JRST	IRAS29		;CAN'T END HERE
IRALS5:	CAIN	T2," "		;IF A SPACE
	MOVEI	T2,"0"		;THEN MAKE IT A ZERO
	CAIL	T2,"0"		;IF NOT AN ASCII DIGIT
	CAILE	T2,"9"		;IF NOT AN ASCII DIGIT
	JRST	[MOVEI	M0,$EILLN	;ERROR CODE: LUDICROUS LSN
		POPJ	P,]		;BOMB THIS RECORD
	IMULI	T4,^D10		;NEXT DECADE
	ADDI	T4,-"0"(T2)	;ACCUMULATE LSN AS AN INTEGER
	SOJG	T3,IRALS4	;LOOP FOR REST OF LSN
	HRRM	T4,.IOISH(IO)	;SET THE ACTUAL LSN
	JRST	(P1)		;GO PROCESS ASCII DATA
;INITIALIZE FOR REMOTE BINARY DATA READ

IRIB:	SETZ	P1,		;NO ISR SELECTED YET
	MOVE	P2,.IOIOC(IO)	;FETCH I/O CONTROL FLAGS
	MOVD1	T2,RFM		;RECORD FORMAT
	MOVD	T3,RAT		;RECORD ATTRIBUTES
	TFZ	T3,<MCY,NSB>	;MACY11-PACKING DOESN'T AFFECT US
	JSP	T4,.CDISP##	;DISPATCH ON RECORD FORMAT PROCESSING
		IRIB10,,$DVFNR	;"NO FORMAT"
		IRIB20,,$DVFFX	;FIXED-LENGTH RECORDS
		IRIB20,,$DVFVR	;VARIABLE-LENGTH RECORDS
		IRIB20,,$DVFVF	;VARIABLE-WITH-FIXED-HEADER RECORDS
		IRIB30,,$DVFST	;ASCII "STREAM"
		0		;THAT'S ALL
	STOPCD	<Unknown record format in IRIB>


;"NO FORMAT" BINARY DATA (NO RECORD STRUCTURE)

IRIB10:	MOVD1	T2,BSZ		;GET LOGICAL DATA BYTESIZE
	CAIN	T2,^D08		;8-BIT BYTES?
	XMOVEI	P1,IRBB		;YES, EASIEST CASE
	CAIN	T2,^D36		;36-BIT BYTES?
IRIB12:	XMOVEI	P1,IRBW		;YES, FAVORITE CASE
	TXNE	P2,IC.RSI	;TRYING FOR RECORDS?
	STOPCD	<Record-structured I/O selected in IRIB10>
	JUMPN	P1,IRIB80	;GO SETUP DATA STREAM
IRIB13:	STOPCD	<DAP data bytesize neither 8 nor 36 in IRIB10>


;FIXED, VARIABLE, AND VARIABLE-WITH-FIXED-HEADER RECORDS

IRIB20:	LDB	T2,[POINTR .IOIOC(IO),IC.RFM]  ;GET CONTROLLING /RECFORMAT
	CAIN	T2,.ICRF3	;DOING 36PACK SHANANIGANS?
	JRST	IRIB12		;YES . . .
	MOVD1	T2,BSZ		;LOGICAL DATA BYTESIZE
	JUMPN	T2,IRIB22	;VERIFY ITS SIZE
	MOVEI	T2,^D08		;SUPPLY A DEFAULT
	MOVD1M	T2,BSZ		;TELL OTHERS ABOUT IT
IRIB22:	CAIE	T2,^D08		;MUST BE 8-BIT BYTES (E.G., VAX ET AL)
	STOPCD	<DAP data bytesize not 8 in IRIB20>
	XMOVEI	P1,IRBR		;SELECT RECORD PROCESSOR
	TXNN	P2,IC.RSI	;IS USER EXPECTING RECORDS?
	STOPCD	<Record-structured I/O not selected in IRIB20>
	JRST	IRIB80		;GO SETUP DATA STREAM


;ASCII STREAM

IRIB30:	STOPCD	<Binary data with "ASCII STREAM" format records in IRIB30>
;ISR SELECTED, ESTABLISH THE DATA STREAM

IRIB80:	JUMPN	P1,IRIB82	;ERROR IF NO ISR SELECTED
	STOPCD	<No ISR selected in IRIB>
IRIB82:	TFZE	T3,<FCC,ILC,PRN,EFC,CCC,LSA>  ;ASCII-LIKE ATTRIBUTES?
	JRST	[MOVEI	M0,$EIBAI	;ASCII ATTR ILLEGAL FOR BINARY FILE
		POPJ	P,]		;TELL USER OF ERROR
	FJUMPE	T3,RAT,IRIB84	;ERROR IF ANY RECORD ATTRIBUTES LEFT OVER
	STOPCD	<Unknown or illegal record format/attributes in IRIB>
IRIB84:	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNE	T1,IO.NEP	;ACTIVE OR PASSIVE LINK?
	JRST	IRIB86		;PASSIVE, NO STARTUP NEEDED
	PUSHJ	P,DPSII0##	;ACTIVE, NEED CONTROL(CONNECT), CONTROL(GET)
	 POPJ	P,		;NETWORK DIED?
IRIB86:	MOVEM	P1,.IOISR(IO)	;SET INPUT SERVICE ROUTINE
	XMOVEI	P1,IRBCL	;SPECIAL CLOSE ROUTINE
	MOVEM	P1,.IOISS(IO)	;SPECIAL CLOSE PROCESSING REQUIRED
	JRST	.POPJ1##	;INPUT INITIALIZED
;HERE TO SHUTDOWN THE REMOTE BINARY INPUT DATA STREAM
;
;			*** NOTE ***
;
;		ENTERED FROM CLOSE AT SACIO LEVEL

IRBCL:	SKIPG	T1,.IODIM(IO)	;IN A DAP MESSAGE?
	JRST	.POPJ1##	;NO, ALL SET THEN (CLOSE WILL EAT ANY NEW DATA)
	CAIE	T1,$DHDAT	;YES, IS IT DATA?
	STOPCD	<Non-data DAP message outstanding in IRBCL>
	PUSHJ	P,RDEAT1##	;A DATA MESSAGE, SIMPLY EAT THE REST OF IT
	 POPJ	P,		;FAILED?
	JRST	.POPJ1##	;READY FOR CLOSE TO DO ITS THING
;REMOTE BINARY 8-BIT BYTE ISR

IRBB:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
IRBB01:	XMOVEI	T4,IRBB		;NOT-WITHIN-A-RECORD STATE
	MOVEM	T4,.IOISR(IO)	;SET IN CASE OF ERROR RESTART
	SKIPLE	.IODIM(IO)	;BETTER NOT BE PROCESSING A DAP MESSAGE
	STOPCD	<DAP input message in progress in IRBB>
	PUSHJ	P,RDMSG0##	;START READING NEW MESSAGE
	 POPJ	P,		;NETWORK DIED?
	CAIE	T2,$DHDAT	;DATA?
	JRST	IRBB10		;NO
	PUSHJ	P,RDDAT0##	;READ TEMPLATED PORTION OF DATA MESSAGE
	 POPJ	P,		;DIED?
	XMOVEI	T4,IRBB20	;NOW-WITHIN-A-RECORD STATE
	MOVEM	T4,.IOISR(IO)	;SET NEW STATE DISPATCH
	JRST	IRBB21		;READ FIRST DATA BYTE

;INPUT MESSAGE NOT DATA, SEE IF STATUS

IRBB10:	CAIE	T2,$DHSTS	;LOOKING AT A STATUS MESSAGE?
	JRST	IRBB17		;NO
	PUSHJ	P,RDSTS0##	;READ AND TRANSLATE THE DAP STATUS
	 POPJ	P,		;ERROR READING A STATUS MESSAGE?
	CAIE	M0,$EGOIP	;"OPERATION IN PROGRESS"
	CAIN	M0,$EGAOK	;"A-OK"
	JRST	IRBB01		;YES, IGNORE IT
	POPJ	P,		;RETURN ERROR

IRBB17:	MOVE	M0,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	M0,IO.NEP	;ACTIVE OR PASSIVE LINK?
	STOPCD	<Received DAP message neither DATA nor STATUS in IRBB>
	PUSHJ	P,RDMSR0##	;PASSIVE, RE-EAT THE MESSAGE
	 POPJ	P,		;DUH?
	MOVEI	M0,$EINMP	;TELL FAL THAT AN INPUT MESSAGE IS PENDING
	POPJ	P,		;TAKE EXCEPTION RETURN

;HERE TO READ NEXT DATA BYTE (ENTERED AS AN ISR)

IRBB20:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
IRBB21:	PUSHJ	P,RDBYC0##	;READ IN ANOTHER DATA BYTE
	 JRST	IRBB25		;MAYBE EOR
	MOVEM	T2,-T2(P)	;POSITION RETURN DATA BYTE
	JRST	.POPJ1##	;SUCCESSFUL RETURN

IRBB25:	JUMPE	M0,IRBB01	;EOR, START UP A NEW RECORD
	POPJ	P,		;ERROR
;REMOTE BINARY 36-BIT WORD ISR

IRBW:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
IRBW01:	XMOVEI	T4,IRBW		;NOT-WITHIN-A-RECORD STATE
	MOVEM	T4,.IOISR(IO)	;SET IN CASE OF ERROR RESTART
	SKIPLE	.IODIM(IO)	;STILL IN A DAP MESSAGE?
	STOPCD	<DAP input message in progress in IRBW>
	PUSHJ	P,RDMSG0##	;START READING NEXT DAP MESSAGE
	 POPJ	P,		;ERROR
	CAIE	T2,$DHDAT	;DATA MESSAGE?
	JRST	IRBW10		;NO
	PUSHJ	P,RDDAT0##	;YES, START UP A DATA RECORD
	 POPJ	P,		;DIED?
	XMOVEI	T4,IRBW20	;NOW-WITHIN-A-RECORD STATE
	MOVEM	T4,.IOISR(IO)	;SET NEW STATE
	JRST	IRBW21		;AND START READING NEW RECORD

;NOT A DATA MESSAGE, SEE IF STATUS (EOF, ETC.)

IRBW10:	CAIE	T2,$DHSTS	;STATUS?
	JRST	IRBW17		;NO
	PUSHJ	P,RDSTS0##	;READ AND TRANSLATE THE DAP STATUS
	 POPJ	P,		;DUH?
	CAIE	M0,$EGOIP	;"OPERATION IN PROGRESS"
	CAIN	M0,$EGAOK	;"A-OK"
	JRST	IRBW01		;IGNORE
	POPJ	P,		;ERROR, EOF, ETC.

IRBW17:	MOVE	M0,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	M0,IO.NEP	;ACTIVE OR PASSIVE LINK?
	STOPCD	<Received DAP message neither DATA nor STATUS in IRBW>
	PUSHJ	P,RDMSR0##	;PASSIVE, RE-EAT THE MESSAGE
	 POPJ	P,		;DUH?
	MOVEI	M0,$EINMP	;TELL FAL THAT AN INPUT MESSAGE IS PENDING
	POPJ	P,		;TAKE EXCEPTION RETURN
;HERE TO READ NEXT 36-BIT DATA WORD - DAP DATA BYTES 1 TO 4.5
;
;ENTERED AS AN ISR

IRBW20:	PUSHJ	P,.SACIO##	;SET I/O CONTEXT
	PUSHJ	P,TSAV14##	;AND THE T'S TOO
IRBW21:	SKIPE	T2,.IODIW(IO)	;GET SAVED PARTIAL WORD (IF ANY)
	JRST	IRBW31		;ODD WORD
	PUSHJ	P,RDBYC0##	;GET FIRST DAP BYTE
	 JRST	IRBW25		;EOR?
	MOVEM	T2,-T2(P)	;POSITION AND SET BITS 28 - 35
	PUSHJ	P,RDBYC0##	;GET SECOND DAP BYTE
	 JRST	IRBW28		;THIS IS NOT ALLOWED
	LSH	T2,<1*^D08>	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 20 - 27
	PUSHJ	P,RDBYC0##	;GET THIRD DAP BYTE
	 JRST	IRBW28		;THIS IS NOT ALLOWED
	LSH	T2,<2*^D08>	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 12 - 19
	PUSHJ	P,RDBYC0##	;GET FOURTH DAP BYTE
	 JRST	IRBW28		;THIS IS NOT ALLOWED
	LSH	T2,<3*^D08>	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 04 - 11
	PUSHJ	P,RDBYC0##	;GET FOURTH AND A HALFTH DAP BYTE
	 JRST	IRBW28		;THIS IS NOT ALLOWED
	LSHC	T1,<4*^D08>	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 00 - 03
	HRROM	T1,.IODIW(IO)	;SAVE PARTIAL WORD
	JRST	.POPJ1##	;RETURN 36-BIT DATA BYTE

IRBW25:	JUMPN	M0,.POPJ##	;ERROR RETURN IF ERROR
	SKIPN	.IODIB(IO)	;EOR, SHOULD HAVE USED ALL BITS
	JRST	IRBW01		;ALL SET, START UP A NEW RECORD
	STOPCD	<Unused bitcount non-zero in IRBW20>

IRBW28:	JUMPN	M0,.POPJ##	;ERROR RETURN IF ERROR
	STOPCD	<Premature DAP DATA end of message in IRBW20>
;HANDLE THE ODD WORD (DAP BYTES 4.5 TO 9)

IRBW31:	HRRZM	T2,-T2(P)	;SET PARTIAL WORD (LOW 4 BITS)
	SETZM	.IODIW(IO)	;CLEAR TRAILING PARTIAL WORD
	PUSHJ	P,RDBYC0##	;GET SIXTH DAP BYTE
	 JRST	IRBW35		;MAYBE NONE
	LSH	T2,<0*^D08>+4	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 24 - 31
	PUSHJ	P,RDBYC0##	;GET SEVENTH DAP BYTE
	 JRST	IRBW38		;THIS IS NOT ALLOWED
	LSH	T2,<1*^D08>+4	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 16 - 23
	PUSHJ	P,RDBYC0##	;GET EIGHTH DAP BYTE
	 JRST	IRBW38		;THIS IS NOT ALLOWED
	LSH	T2,<2*^D08>+4	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 08 - 15
	PUSHJ	P,RDBYC0##	;GET NINTH (AND LAST) DAP BYTE
	 JRST	IRBW38		;THIS IS NOT ALLOWED
	LSH	T2,<3*^D08>+4	;POSITION
	IORM	T2,-T2(P)	; AND SET BITS 00 - 07
	JRST	.POPJ1##	;RETURN WITH 36-BIT WORD

IRBW35:	JUMPN	M0,.POPJ##	;ERROR RETURN IF ERROR
	MOVE	T4,.IODIB(IO)	;GET UNUSED BIT COUNT
	CAIN	T4,4		;HAD BETTER BE A HALF-BYTE
	JRST	IRBW01		;OK, START READING NEXT RECORD
	STOPCD	<Unused bitcount not 4 in IRBW30>

IRBW38:	JUMPN	M0,.POPJ##	;ERROR RETURN IF REAL ERROR
	STOPCD	<Premature DAP DATA end of message in IRBW30>
;REMOTE BINARY 8-BIT BYTE RECORD-FORMATTED ISR

IRBR:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
IRBR01:	XMOVEI	T4,IRBR		;NOT-WITHIN-A-RECORD STATE
	MOVEM	T4,.IOISR(IO)	;SET IN CASE OF ERROR RESTART
	SKIPLE	.IODIM(IO)	;BETTER NOT BE PROCESSING A DAP MESSAGE
	STOPCD	<DAP input message in progress in IRBR>
	PUSHJ	P,RDMSG1##	;START READING NEW MESSAGE
	 POPJ	P,		;NETWORK DIED?
	CAIE	T2,$DHDAT	;DATA?
	JRST	IRBR70		;NO
	PUSHJ	P,RDDAT1##	;READ TEMPLATED PORTION OF DATA MESSAGE
	 POPJ	P,		;DIED?
	MOVD	T1,RCN		;FETCH "RECORD NUMBER"
	MOVEM	T2,-T2(P)	;AND RETURN TO CALLER (FOR WHAT IT'S WORTH)
	MOVN	T3,-T3(P)	;CALLER'S MAX RECORD SIZE
	SUBI	T3,1		;ALLOW FOR AOBJN
	HRLZ	P1,T3		;MAKE BYTE COUNTER/LOOPER
	SKIPA	P2,-T4(P)	;FETCH CALLER'S RECORD BUFFER STUFFER

;HERE TO READ NEXT DATA BYTE

IRBR20:	IDPB	T2,P2		;STASH ANOTHER RECORD BYTE
IRBR21:	PUSHJ	P,RDBYC1##	;READ IN ANOTHER DATA BYTE
	 JRST	IRBR25		;MAYBE EOR
	AOBJN	P1,IRBR20	;RETURN DATA TO CALLER
	SOJA	P1,IRBR21	;DATA OVERFLEW USER'S BUFFER, DISCARD

IRBR25:	HRRZM	P1,-T3(P)	;RETURN COUNT OF BYTES STUFFED
	JUMPN	M0,.POPJ##	;IF ERROR, PROPAGATE IT
	JUMPL	P1,.POPJ1##	;RETURN DATA RECORD
	MOVEI	M0,$EIRTB	;OOPS - RECORD WAS TOO BIG, DATA LOST!
	POPJ	P,		;TOO BAD
;INPUT MESSAGE NOT DATA, SEE IF STATUS

IRBR70:	CAIE	T2,$DHSTS	;LOOKING AT A STATUS MESSAGE?
	JRST	IRBR77		;NO
	PUSHJ	P,RDSTS1##	;READ AND TRANSLATE THE DAP STATUS
	 POPJ	P,		;ERROR READING A STATUS MESSAGE?
	CAIE	M0,$EGOIP	;"OPERATION IN PROGRESS"
	CAIN	M0,$EGAOK	;"A-OK"
	JRST	IRBR01		;YES, IGNORE IT
	POPJ	P,		;RETURN ERROR

IRBR77:	MOVE	M0,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	M0,IO.NEP	;ACTIVE OR PASSIVE LINK?
	STOPCD	<Received DAP message neither DATA nor STATUS in IRBR>
	PUSHJ	P,RDMSR1##	;PASSIVE, RE-EAT THE MESSAGE
	 POPJ	P,		;DUH?
	MOVEI	M0,$EINMP	;TELL FAL THAT AN INPUT MESSAGE IS PENDING
	POPJ	P,		;TAKE EXCEPTION RETURN
	SUBTTL	OUTPUT SERVICE ROUTINES

;All Output Service Routines are called with the I/O CDB address in
;register T1 and the output data in T2 (and if needed T3, T4).
;
;On the error/exception return M0 has the error/exception code.
;
;On normal return the data is in the output buffer.
;
;In all cases, the T registers are preserved!

	ENTRY	.IOOIN

.IOOIN:	PUSHJ	P,IOOIN0	;DO THE WORK
	 POPJ	P,		;OOPS
	PJRST	@.IOOSR(T1)	;DISPATCH TO SELECTED OUTPUT SERVICE ROUTINE

IOOIN0:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
	SETZM	.IOOSF(IO)	;RESET OUTPUT PROCESSING FLAGS
	XMOVEI	P1,.POPJ1##	;THE SKIP-RETURNER
	MOVEM	P1,.IOOSS(IO)	;USUALLY NO SPECIAL CLOSE PROCESSING NEEDED
	MOVX	P1,IO.IOA	;THE I/O-ACTIVE FLAG
	IORB	P1,.IOCCF(IO)	;NOTE I/O ACTIVITY
	TXNE	P1,IO.NET	;LOCAL OR REMOTE (NETWORK) I/O?
	JRST	ORINI		;REMOTE
				;LOCAL, FALL INTO OLINI

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;OLINI  --  OUTPUT, LOCAL, INITIALIZATION

OLINI:	TXNE	P1,IO.OBA	;OUTPUT BUFFERS ALLOCATED?
	JRST	OLINI4		;YES, SELECT OSR AND START I/O

;NO OUTPUT BUFFERS, GENERATE SOME FOR FREE

	PUSHJ	P,FILBO1##	;SETUP OUTPUT BUFFERS
	 POPJ	P,		;OH WELL

;SELECT OSR BASED ON FILE MODE AND OPTIONS

OLINI4:	MOVE	P4,.IOIOC(IO)	;GET I/O CONTROL
	LDB	P2,[POINTR P4,IC.MOD]  ;GET FILE MODE
	XMOVEI	P3,.		;GET OUR SECTION IN LH
	HRR	P3,MOOSTB(P2)	;SELECT OSR BASED ON FILE MODE ALONE
	TXNE	P4,IC.RSI	;USER WANT RECORD-STRUCTURED I/O?
	HRRI	P3,OLREC	;YES, TOO BAD
	TXNE	P4,IC.BLK	;USER WANT BLOCK MODE BUFFERS
	HRRI	P3,OLBLK	;YES, LET HIM DO HIS OWN STUFF THEN
	TXNE	P4,IC.MCY!IC.MEY;MACY11-FORMATTED OUTPUT?
	HRRI	P3,OLMCI	;YES, SELECT MACY11 OUTPUT SERVICE THEN
	MOVEM	P3,.IOOSR(IO)	;SET OSR IN THE CDB

;INITIALIZE COUNTERS

	SETOM	.IOOUC(IO)	;NO BUFFERS OUTPUT YET
	JRST	.POPJ1##	;OUTPUT INITIALIZED
;OLASC  --  OUTPUT, LOCAL, ASCII CHARACTERS

OLASB:	PUSHJ	P,OLBUF		;ASK MONITOR FOR ANOTHER BUFFER
	 POPJ	P,		;ERROR
OLASC:	SKIPE	.IOOS0(T1)	;GOT AN LSN PENDING?
	JRST	OLASC8		;YES, GO PROCESS IT FIRST
OLASC2:	SOSGE	.IOOBC(T1)	;ANY ROOM LEFT?
	JRST	OLASB		;NO, GET AN EMPTY BUFFER
	IDPB	T2,.IOOBP(T1)	;YES, STUFF AWAY THIS CHARACTER THEN
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

;HERE TO OUTPUT LINE SEQUENCE NUMBER PENDING (SET BY IFLSN)
;
;.IOOS0 CONTAINS THE LSN AS A INTEGER (NOT ASCII CHARACTERS) WHICH
;IF 1B0 THEN OUTPUT A "PAGE-MARK"

OLASC8:	PUSHJ	P,OLLSN		;ISSUE LSN
	 POPJ	P,		;I/O ERROR
	JRST	OLASC2		;GO ISSUE THE CHARACTER
;HERE TO ISSUE LSN FOR LOCAL FILE SERVICE

OLLSN:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;AND THE T'S

;FIRST, MOVE UP TO A WORD BOUNDRY

OLLSN2:	LDB	T2,[POINT 6,.IOOBP(T1),5]  ;GET OUTPUT POINTER "P" FIELD
	CAIE	T2,1		;ON A WORD BOUNDRY?
	CAIN	T2,44		;(ALTERNATE FORM)?
	JRST	OLLSN4		;YES
	JUMPE	T2,OLLSN4	;NULL MEANS UNINITIALIZED, NEED TO CALL OLBUF
OLLSN3:	SETZ	T2,		;GET A NULL AS A FILLER CHARACTER
	PUSHJ	P,OLBYT		;PAD THE PARTIAL WORD TO A WORD BOUNDRY
	 POPJ	P,		;BLETCH
	JRST	OLLSN2		;CHECK AGAIN

;SECOND, MAKE SURE THE SOS-STYLE <TAB> WILL FIT IMMEDIATELY AFTER THE
;THE LINE-SEQUENCE-NUMBER (THIS IS SO STUPID PROGRAMS CAN SIMPLY LOOK
;AT THE WORD IMMEDIATELY FOLLOWING THE LSN FOR THE SOS-STYLE <TAB>.

OLLSN4:	SKIPLE	T2,.IOOBC(T1)	;GET OUTPUT COUNT
	JRST	OLLSN5		;AND SEE IF ANY ROOM LEFT
	PUSHJ	P,OLBUF		;CURRENT BUFFER EMPTY, GET A NEW BUFFER
	 POPJ	P,		;I/O ERROR?
	JRST	OLLSN4		;TRY AGAIN
OLLSN5:	CAIGE	T2,6		;ROOM IN THIS BUFFER FOR LSN AND <TAB>?
	JRST	OLLSN3		;NO

;NOW THE TRADITIONAL "DECOUT" ROUTINE, KINDA TURNED SIDEWAYS

	MOVE	P1,.IOOS0(T1)	;RETRIEVE THE INPUT LSN
	IBP	.IOOBP(T1)	;POINT BYTE POINTER AT THE RIGHT WORD
	JUMPL	P1,[DMOVE T2,[EXP <<ASCII/     />!1>,<BYTE (7) 15,14,00,00,00>]
		DMOVEM	T2,@.IOOBP(T1)	;SET SOS-STYLE "PAGE MARK"
		AOS	.IOOBP(T1)	;BUMP POINTER PAST FIRST WORD
		MOVNI	T2,^D10		;JUST USED UP 10 CHARACTERS
		HRRZM	P1,.IOOS0(T1)	;SET FUTHER PROCESSING
		JRST	OLLSN7]		;CAP OFF LSN
	SETZ	T2,		;INITIALIZE LSN
	MOVEI	P3,5		;WILL WANT EXACTLY 5 DIGITS
OLLSN6:	IDIVI	P1,^D10		;GET LOWEST DIGIT LEFT
	IORI	T2,"0"(P2)	;TACK ON THE ASCIIZED DIGIT
	ROT	T2,-^D7		;POSITION DIGIT WITHIN WORD
	SOJG	P3,OLLSN6	;MAKE FIVE-DIGIT LSN
	IORI	T2,1		;TURN ON THE LSN BIT
	MOVEM	T2,@.IOOBP(T1)	;STASH AWAY LSN WORD
	SETZM	.IOOS0(T1)	;THE LSN HAS BEEN PROCESSED!
	MOVNI	T2,5		;ACCOUNT FOR THE 5 CHARACTERS
OLLSN7:	ADDM	T2,.IOOBC(T1)	;WHICH WERE JUST USED
	MOVSI	T2,(POINT 7,,34);ALSO DIDDLE THE BYTE POINTER
	HLLM	T2,.IOOBP(T1)	;TO LOOK "RIGHT"
	SKIPE	.IOOS0(T1)	;DID WE FINISH?
	JRST	OLLSN2		;NO, STILL HAVE MORE TO DO
	MOVEI	T2,.CHTAB	;NOW GET A <TAB> CHARACTER
	PJRST	OLBYT		;AND OUTPUT IT TOO
;OLBYT  --  OUTPUT, LOCAL, BYTE STREAM

OLBYB:	PUSHJ	P,OLBUF		;ASK FOR ANOTHER BUFFER
	 POPJ	P,		;ERROR
OLBYT:	SOSGE	.IOOBC(T1)	;ANY ROOM LEFT IN CURRENT BUFFER?
	JRST	OLBYB		;NO, ASK FOR AN EMPTY BUFFER
	IDPB	T2,.IOOBP(T1)	;STASH AWAY THIS DATA BYTE
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN



;OLREC  --  OUTPUT, LOCAL, RECORD-STRUCTURED I/O

OLREC:	STOPCD	<Record-structured local I/O illegal>



;OLBLK  --  OUTPUT, LOCAL, BLOCK MODE

OLBLK:	JRST	OLBLK2		;NEED A BUFFER
	MOVEM	T3,.IOOBC(T1)	;SET USER'S RETURNED BYTE COUNT
	MOVEM	T4,.IOOBP(T1)	;AND BYTE POINTER
	SOS	.IOOSR(T1)	;MARK NEED-A-BUFFER STATE
OLBLK2:	PUSHJ	P,OLBUF		;ASK FOR A NEW [EMPTY] BUFFER
	 JRST	OLBLK4		;NO BUFFER AVAILABLE
	AOS	.IOOSR(T1)	;WE HAVE A NEW [PRESUMABLY EMPTY] BUFFER
	MOVE	T3,.IOOBC(T1)	;RETURN USER THE NEW BYTE COUNT
	MOVE	T4,.IOOBP(T1)	;AND BYTE POINTER
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

;HERE WHEN CAN'T GET A BUFFER, RETURN -1 BYTE COUNT TO USER TO FORCE
;HIM TO IMMEDIATELY CALL OLBLK AGAIN SINCE THERE IS NO GUARANTEE THAT
;THERE IS A BUFFER AVAILABLE UNTIL HE FORCES ANOTHER OUTPUT ATTEMPT.
;WE MUST ALSO BE SURE NOT TO TOUCH THE RING HEADER COUNTER/POINTER
;SINCE THE MONITOR USES IT AS A STATE FLAG.

OLBLK4:	SETOB	T2,T3		;RETURN NO BYTES
	POPJ	P,		;PASS ERROR STATUS TO USER
;OLMCY  --  OUTPUT, LOCAL, MACY11 PACKED

;MACY11 packing involves writing 8-bit bytes packed four to a 36-bit word,
;but not in an obvious manner. The four bytes are layed out as follows:
;
;	    2      9 10    17    20    27 28    35
;	+--+--------+--------+--+--------+--------+
;	|  |  two   |  one   |  |  four  | three  |
;	+--+--------+--------+--+--------+--------+
;
;This format can be thought of as aligning one -11 16-bit word per -10
;halfword (although it should be emphasized that the packing is in
;terms of bytes, so that the "16-bit words" might be (and often are)
;split across "18-bit halfwords"!).
;
;The record structure imposed is:
;
;	000001		;record header
;	length		;count of bytes (includes MACY11 header - 6 bytes)
;	address		;for .LDA files, address to load record
;			; ignored for pure data records
;	-data-		;length-6 data bytes
;	...cks		;one-byte checksum (not included in count)
;
;The output variables (in the CDB) are used as follows:
;
;	.IOOS0		;not used
;	.IOOS1		;record byte count
;	.IOOS2		;OLMCB (byte-stuffing) state
;	.IOOS3		;OLMCR (record-header) state
;	.IOOS4		;OLMCB 36-bit word address
;	.IOOS5		;MACY11 checksum value

;The ISR call is:
;
;	MOVX	T2,<ADR>
;	MOVX	T3,<CNT>
;	MOVX	T4,<PTR>
;	PUSHJ	P,@.IOISR
;	 error return
;	normal return
;
;Where <ADR> is the record/.LDA "load" address (if any); <CNT> is
;the count of data bytes; and <PTR> is the byte pointer to the data bytes.
;
;On error return an error code is in M0
;
;On normal return the record as specified has been output suitably
;"encased" in MACY11 format.
;HERE TO INITIALIZE FOR MACY11 DATA PACKING (FROM OLINI)

OLMCI:	SETZM	.IOOS3(T1)	;CURRENTLY NOT IN A RECORD
	MOVEI	M0,4		;WORD-PACKING STATE
	MOVEM	M0,.IOOS2(T1)	;SET FOUR BYTES LEFT
	SETZM	.IOOS4(T1)	;INITIALIZE BYTE-PACKING WORD
	XMOVEI	M0,OLMCC	;SPECIAL CLOSE PROCESSING REQUIRED
	MOVEM	M0,.IOOSS(T1)	;SET FOR .IOCLO TO FIND
	XMOVEI	M0,OLMCY	;NORMAL OSR
	MOVEM	M0,.IOOSR(T1)	;SET FOR SUBSEQUENT CALLS
				;AND FALL INTO OLMCY


;HERE TO OUTPUT ONE MACY11 LOGICAL DATA RECORD (CALLED AS AN OSR)

OLMCY:	PUSHJ	P,.SAVE2##	;NEED A COUPLA EXTRA ACS
	PUSHJ	P,TSAV14##	;PRESERVE THE T'S
	PUSHJ	P,OLMCR		;FIRE UP AN OUTPUT RECORD
	 POPJ	P,		;CAN'T
	MOVE	P2,-T4(P)	;GET OUTPUT RECORD POINTER
	SKIPG	P1,-T3(P)	;AND OUTPUT BYTE COUNT
	JRST	OLMCY6		;NULL RECORD, DONE BEFORE WE START!

;LOOP WRITING THE DATA BYTES

OLMCY3:	ILDB	T2,P2		;FETCH ANOTHER DATA BYTE
	PUSHJ	P,OLMCB		;OUTPUT THIS 8-BIT BYTE
	 POPJ	P,		;DIED
	ADDM	T2,.IOOS5(T1)	;ACCUMUMLATE MACY11 CHECKSUM
	SOJG	P1,OLMCY3	;LOOP FOR REST OF RECORD

OLMCY6:	SETZM	.IOOS3(T1)	;CLEAR RECORD STATE
	MOVX	M0,IS.MCF!IS.MCK;FLAG FILLER AND CHECKSUM BYTE NEEDED
	IORM	M0,.IOOSF(T1)	; BUT NOT YET OUTPUT
	SETZ	T2,		;*** CALCULATE CHECKSUM
	PUSHJ	P,OLMCB		;OUTPUT 8-BIT CHECKSUM BYTE
	 POPJ	P,		;DIED
	MOVX	M0,IS.MCK	;FLAG THE CHECKSUM BYTE
	ANDCAM	M0,.IOOSF(T1)	; IS NO LONGER NEEDED
	JRST	.POPJ1##	;SUCCESSFUL RETURN FOR THIS RECORD
;OLMCR - MACY11 RECORD STARTUP
;
;On error return, the record header could not be written completely.
;If error recovery is attempted, the retry call must specify exactly
;the same record information as the original call which failed, as there
;is no way to determine (or unwind) the progress of the original call!

OLMCR:	MOVEM	T2,.IOOS0(T1)	;SAVE RECORD "ADDRESS"
	MOVEM	T3,.IOOS1(T1)	;AND RECORD LENGTH
	SKIPLE	T4,.IOOS3(T1)	;ERROR RECOVERY CALL?
	JRST	@OLMCTA(T4)	;YES, RESUME FROM WHENCE ABORTED
	MOVX	T3,IS.MCK	;THE CHECKSUM BYTE NEEDED FLAG
	TDNE	T3,.IOOSF(T1)	;HAVE A DANGLING CHECKSUM?
	JRST	[MOVE	T2,.IOOS5(T1)	;GET CHECKSUM BYTE
		PUSHJ	P,OLMCB		;OUTPUT MACY11 BYTE
		 POPJ	P,		;STILL HAVEN'T OUTPUT THE CHECKSUM
		ANDCAM	T3,.IOOSF(T1)	;THE CHECKSUM IS NOW OUTPUT
		JRST	.+1]		;BACK TO MAIN-LINE CODE
	MOVX	T3,IS.MCF	;THE INTER-RECORD FILLER FLAG
	TDNN	T3,.IOOSF(T1)	;SET IN THE OUTPUT SERVICE FLAGS?
	JRST	[MOVEI	T3,2		;NO - PROBABLY FIRST RECORD IN FILE
		MOVEM	T3,.IOOS3(T1)	;SKIP FIRST STAGE
		JRST	OLMCR2]		;AND START WITH STAGE TWO
	ANDCAM	T3,.IOOSF(T1)	;YES, CLEAR IT
	MOVEI	T4,6		;MACY11 PUTS 6-NULLS 'TWEEN RECORDS
	MOVE	T3,.IOIOC(T1)	;IO MODE CONTROL
	TXNN	T3,IC.MEY	;/MECY11 STRUCTURING?
	JRST	OLMCR0		;NO

;HERE TO TRY TO KEEP "-11 16-BIT WORDS" ALIGNED IN -10 HALFWORDS, FURTHER
;ENSURING THAT THE RECORD HEADER NEVER SPLITS ACROSS A BLOCK/BUFFER BOUNDRY.
;THE RESULTANT FORMAT YIELDS A ZERO [INTER-RECORD GAP] WORD, THEN
;1,,CNT, THEN ADR,,DATA, FOLLOWED BY (CNT-6-2)/2 MORE DATA HALFWORDS,
;AND FINALLY THE CHECKSUM. THIS MAKES LOOKING AT THE "MACY11" FILE
;MUCH EASIER VIA FILDDT/ET AL.

	SKIPGE	T3,.IOOBC(T1)	;YES, GET OUTPUT WORD COUNT IN BUFFER
	MOVEI	T3,1		;NONE LEFT, FORCE ONE WORD OF ZEROS
	LSH	T3,2		;NUMBER OF BYTES LEFT
	MOVEI	T4,4		;MINIMUM ONE ZERO WORD 'TWEEN RECORDS
	CAIGE	T3,^D12		;ENOUGH ROOM LEFT?
	MOVE	T4,T3		;NO, FLUSH OUT THIS BUFFER FIRST
	SETZM	.IOOS2(T1)	;RESET OLMCB TO START OF NEW WORD

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

OLMCR0:	MOVEM	T4,.IOOS5(T1)	;COUNT OF NULL BYTES NEEDED
	AOS	.IOOS3(T1)	;STAGE ONE
OLMCR1:	SETZ	T2,		;NULL BYTE
	PUSHJ	P,OLMCB		;WRITE ONE EIGHT-BIT BYTE
	 POPJ	P,		;OUTPUT ERROR
	SOSLE	.IOOS5(T1)	;COUNT DOWN FILLER
	JRST	OLMCR1		;STILL NEED MORE
	AOS	.IOOS3(T1)	;STAGE TWO
OLMCR2:	MOVEI	T2,1		;THE 000001 TO START A NEW RECORD
	PUSHJ	P,OLMCB		;WRITE LOW-ORDER BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOS	.IOOS3(T1)	;STAGE THREE
OLMCR3:	MOVEI	T2,0		;THE 000001 (HIGH BYTE)
	PUSHJ	P,OLMCB		;WRITE HIGH-ORDER BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOS	.IOOS3(T1)	;STAGE FOUR
OLMCR4:	MOVE	T2,.IOOS1(T1)	;RETRIEVE RECORD LENGTH
	ADDI	T2,6		;ALLOW FOR MACY11 HEADER INFO
	PUSHJ	P,OLMCB		;WRITE LOW-ORDER BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOS	.IOOS3(T1)	;STAGE FIVE
OLMCR5:	MOVE	T2,.IOOS1(T1)	;RETRIEVE RECORD LENGTH
	ADDI	T2,6		;ALLOW FOR MACY11 HEADER INFO
	LSH	T2,-^D08	;POSITION FOR HIGH BYTE
	PUSHJ	P,OLMCB		;WRITE HIGH-ORDER LENGTH BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOS	.IOOS3(T1)	;STAGE SIX
OLMCR6:	MOVE	T2,.IOOS0(T1)	;RETRIEVE RECORD ADDRESS (IF ANY)
	PUSHJ	P,OLMCB		;WRITE LOW-ORDER BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOSA	.IOOS3(T1)	;STAGE SEVEN
OLMCR7:	MOVE	T2,.IOOS0(T1)	;RETRIEVE RECORD ADDRESS (IF ANY)
	LSH	T2,-^D08	;POSITION HIGH-ORDER BYTE
	PUSHJ	P,OLMCB		;WRITE HIGH-ORDER BYTE
	 POPJ	P,		;OUTPUT ERROR
	AOS	.IOOS3(T1)	;STAGE EIGHT (IN A RECORD)
	SETZM	.IOOS5(T1)	;INITIALIZE CHECKSUM FOR THIS RECORD
	JRST	.POPJ1##	;SUCCESSFUL RETURN, READY TO WRITE DATA
;HERE TO OUTPUT ONE PHYSICAL 8-BIT MACY11-PACKED BYTE
;
;THIS IS NOT CALLED AS AN OSR!

OLMCB:	EXCH	M0,T4		;NEED A SCRATCH USEABLE AS AN INDEX
	SOSGE	T4,.IOOS2(T1)	;ADVANCE PACKING STATE
	JRST	OLMCB2		;NEED A NEW WORD
	DPB	T2,OLMCTB(T4)	;STASH AWAY THIS DATA BYTE
	EXCH	T4,M0		;RESTORE T4
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

OLMCB2:	EXCH	T4,M0		;RESTORE T4
	EXCH	T2,.IOOS4(T1)	;SAVE CURRENT BYTE, GET FULLY-PACKED WORD
	PUSHJ	P,OLBYT		;ADVANCE TO ANOTHER -10 WORD
	 POPJ	P,		;ERROR
	MOVEI	T2,4		;"VIRGIN" PACKING SO FAR THIS WORD
	MOVEM	T2,.IOOS2(T1)	;SET NEW PACKING STATE
	SETZ	T2,		;CLEAR NEW WORD TO BE PACKED
	EXCH	T2,.IOOS4(T1)	;RETRIEVE NEXT BYTE TO BE OUTPUT
	JRST	OLMCB		;GO OUTPUT THIS BYTE


;SPECIAL CLOSE PROCESSOR (CALLED AT SACIO LEVEL!)

OLMCC:	SKIPE	.IOOS3(IO)	;THE FINAL RECORD MUST HAVE BEEN FINISHED
	JRST	[MOVEI	M0,$EIRSO	;ERROR - RECORD STILL OUTSTANDING
		POPJ	P,]		;PROPAGATE ERROR
	MOVE	T2,.IOOSF(IO)	;GET PROCESSING FLAGS
	TXNN	T2,IS.MCF	;WANT A FILLER?
	JRST	.POPJ1##	;NO (THEN NO DATA WAS EVER WRITTEN)
	TXNN	T2,IS.MCK	;HAVE A DANGLING CHECKSUM BYTE TO OUTPUT?
	JRST	OLMCC2		;NO
	MOVE	T2,.IOOS5(IO)	;YES, GET CHECKSUM BYTE
	MOVE	T1,IO		;POSITION ISR-LEVEL CDB ADDRESS
	PUSHJ	P,OLMCB		;STASH FINAL CHECKSUM BYTE
	 POPJ	P,		;POOR FORM!

;FLUSH FINAL WORD BEING ASSEMBLED

OLMCC2:	MOVE	T2,.IOOS4(IO)	;GET WORD AS PARTIALLY BUILT
	MOVE	T1,IO		;POSITION ISR-LEVEL CDB ADDRESS
	PUSHJ	P,OLBYT		;OUTPUT FINAL 36-BIT WORD
	 POPJ	P,		;SIGH
	JRST	.POPJ1##	;NOW CAN CLOSE THE FILE
;MACY11 TABLES

;RECORD STARTUP STATE DISPATCH TABLE (USED IN ERROR RETRY)

OLMCTA:	IFIW	[STOPCD]	;STAGE 0 - CAN'T HAPPEN
	IFIW	OLMCR1		;STAGE 1
	IFIW	OLMCR2		;STAGE 2
	IFIW	OLMCR3		;STAGE 3
	IFIW	OLMCR4		;STAGE 4
	IFIW	OLMCR5		;STAGE 5
	IFIW	OLMCR6		;STAGE 6
	IFIW	OLMCR7		;STAGE 7



;BYTE-PACKING

OLMCTB:	POINT	8,.IOOS4(T1),27	;BYTE 4
	POINT	8,.IOOS4(T1),35	;BYTE 3
	POINT	8,.IOOS4(T1),9	;BYTE 2
	POINT	8,.IOOS4(T1),17	;BYTE 1
;OLBUF  --  OUTPUT, LOCAL, GET EMPTY BUFFER FROM MONITOR

OLBUF:	PUSHJ	P,.SACIO##	;SET IO
OLBUF0:	PUSHJ	P,TSAV14##	;PRESERVE THE USER'S T'S

;ASK FOR A NEW BUFFER

OLBUF1:	HRLZ	T2,.IOCHN(IO)	;I/O CHANNEL NUMBER
	HRRI	T2,.FOOUT	;"OUTPUT" FUNCTION
	MOVE	T1,[1,,T2]	;FILOP. ARG POINTER TO
	FILOP.	T1,		;READ NEW BUFFER
	 JRST	OLBUF4		;HMMM, CHECK OUT POSSIBLE ERROR
	SKIPG	.IOOBC(IO)	;ENSURE THAT THE MONITOR GAVE US SOMETHING
	STOPCD	<FILOP OUT returned successfully with 0-length buffer in OLBUF>
	AOS	.IOOUC(IO)	;INCREMENT OUT UUO COUNT
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;CHECK OUT OUTPUT EXCEPTION CONDITION

OLBUF4:	TXNE	T1,IO.EOF!IO.ERR;ERROR AND/OR END OF FILE?
	JRST	OLBUF6		;YES, GO HANDLE
	MOVE	T3,.IOIOM(IO)	;GET I/O MODE
	TXNN	T3,IM.AIO	;FILE OPEN FOR NON-BLOCKING I/O?
	STOPCD	<FILOP OUT failed with no error/EOF bits in OLBUF>
	MOVX	T1,$SCNBO	;SCHEDULER - NON-BLOCKING OUTPUT
	PUSHJ	P,@.IOSCH(IO)	;CALL THE SCHEDULER
	 POPJ	P,		;DUH?
	JRST	OLBUF1		;TRY OUTPUTTING AGAIN
;ERROR OR END OF FILE

OLBUF6:	MOVEM	T1,.I1IOS(IO)	;SAVE TOPS-10 I/O STATUS WORD
	TXC	T1,IO.ERR	;FLIP ALL THE BITS
	TXCN	T1,IO.ERR	;WERE ALL BITS SET?
	JRST	OLBUE3		;YES, EXTENDED I/O ERROR STATUS
	LDB	T2,[POINTR TY.DEV,.I1DTY(IO)]  ;GET DEVICE TYPE
	CAIN	T2,.TYDSK	;IS IT A DISK?
	JRST	OLBUD1		;YES, MORE GUESSWORK INVOLVED

;RANDOM I/O ERROR ENCODED INTO IO.ERR, TRANSLATE DIRECTLY AND RETURN

OLBUE1:	TXNE	T1,IO.BKT	;"BLOCK TOO LARGE" ?
	MOVEI	M0,$EIBKT	;YES
	TXNE	T1,IO.DTE	;"DATA CHECKSUM/PARITY ERROR" ?
	MOVEI	M0,$EIDAT	;YES
	TXNE	T1,IO.DER	;"DEVICE ERROR"
	MOVEI	M0,$EIDEV	;YES
	TXNE	T1,IO.IMP	;"IMPROPER MODE"
	MOVEI	M0,$EIIMP	;YES
	POPJ	P,		;RETURN I/O ERROR


;EXTENDED I/O ERROR, NEED TO RETRIEVE EXTENDED ERROR CODE

OLBUE3:	PUSHJ	P,IOERX1	;RETRIEVE AND TRANSLATE EXTENDED I/O ERROR CODE
	 MOVEI	M0,$EIXXX	;UNKNOWN ERROR
	HRRZ	M0,M0		;POSITION OUTPUT TRANSLATION
	POPJ	P,		;RETURN I/O ERROR
;DISK ERROR, SNIFF AROUND A BIT

OLBUD1:	MOVE	T2,.IOCHN(IO)	;I/O CHANNEL
	MOVEM	T2,.I1NSP+.DCNAM(IO)  ;SET IN DSKCHR BLOCK
	MOVSI	T2,.I1NSL	;LENGTH AND
	HRRI	T2,.I1NSP(IO)	;ADDRESS OF DSKCHR BLOCK
	DSKCHR	T2,		;READ ALL ABOUT THAT UNIT/STRUCTURE
	 JRST	ILBUE1		;FORGET IT
	MOVEI	M0,$EIQTA	;USER QUOTA EXHAUSTED
	SKIPG	.I1NSP+.DCUFT(IO)  ;ANY USER QUOTA LEFT?
	POPJ	P,		;NO, ERROR
	MOVEI	M0,$EIFUL	;FILE STRUCTURE STORAGE EXHAUSTED
	SKIPG	.I1NSP+.DCUNT(IO)  ;ANY ROOM LEFT ON DISK?
	POPJ	P,		;NO, ERROR
	MOVEI	M0,$EIHWL	;WRITE-LOCKED
	TXNE	T2,DC.HWP	;HARDWARE WRITE-LOCKED?
	POPJ	P,		;YES, ERROR
	MOVEI	M0,$EISWL	;WRITE-LOCKED BY SOFTWARE
	TXNE	T2,DC.SWP	;SOFTWARE WRITE-LOCKED?
	POPJ	P,		;YES, ERROR
	MOVEI	M0,$EIOFL	;DEVICE OFFLINE
	TXNE	T2,DC.OFL	;IS DISK UNIT OFFLINE?
	POPJ	P,		;YES, ERROR
	JRST	OLBUE1		;OH WELL, JUST CATCH-ALL THE ERROR
;IOOIE  --  OUTPUT, ERROR, OUTPUT-NOT-OPEN

	ENTRY	.IOOIE

.IOOIE:	MOVX	M0,$EIONO	;OUTPUT-NOT-OPEN STATUS
	POPJ	P,		;ERROR RETURN



;OENIR  --  OUTPUT ERROR, NOT IN A RECORD

OENIR:	MOVEI	M0,$EINIR	;NOT-IN-A-RECORD ERROR
	POPJ	P,		;EXCEPTION RETURN
;ORINI  --  OUTPUT, REMOTE, INITIALIZATION

ORINI:	MOVD1	T1,ORG		;GET FILE ORGANIZATION
	CAIE	T1,$DVOSQ	;IS IT SEQUENTIAL?
	STOPCD	<DAP file organization not "sequential" in ORINI>
	MOVE	T1,.IOIOC(IO)	;GET I/O CONTROL
	TXNE	T1,IC.BLK!IC.DMP;FUNNY MODE SET?
	STOPCD	<Block/Dump mode selected in ORINI>

;ENSURE FRESH START, NETWORK BUFFER-WISE

	PUSHJ	P,XDFLS0##	;FLUSH OUT ANYTHING ACCUMULATED
	 POPJ	P,		;NETWORK DIED

;INITIALIZE BASIC VARIABLES

	MOVEI	T1,177777	;CRC POLYNOMIAL SEED
	MOVEM	T1,.IODOK(IO)	;SET FOR FILE DATA CRC COMPUTATION

; INITIALIZATION DISPATCH BASED ON DATA TYPE

	MOVD	T1,DTY		;DATA TYPE ATTRIBUTE FIELD
	TFNE	T1,ASC		;ASCII CHARACTER DATA?
	JRST	ORIA		;YES, INIT FOR ASCII
	TFNE	T1,IMG		;IMAGE (BINARY) DATA?
	JRST	ORIB		;YES, INIT FOR BINARY
	STOPCD	<DAP data type neither ASCII nor binary in ORINI>
;REMOTE ASCII OUTPUT INITIALIZATION

ORIA:	SETZ	P1,		;INITIAL OSR SELECTION
	MOVE	P2,.IOIOC(IO)	;GET I/O CONTROL FLAGS
	TXNE	P2,IC.RSI	;WANTING BYTE MODE I PRESUME
	STOPCD	<Record-structured I/O selected in ORIA>
	MOVD1	T2,RFM		;GET RECORD FORMAT CONTROL
	MOVD	T3,RAT		;GET RECORD ATTRIBUTES
	TFZ	T3,MCY		;MACY11-PACKING DOESN'T AFFECT US
	JSP	T4,.CDISP##	;DISPATCH ON RECORD FORMAT REQUIRED
		ORIA20,,$DVFNR	;NO FORMAT
		ORIA30,,$DVFST	;STREAM FORMAT RECORDS
		ORIA40,,$DVFSL	;STREAM-LF FORMAT RECORDS
		ORIA40,,$DVFSC	;STREAM-CR FORMAT RECORDS
		ORIA50,,$DVFFX	;FIXED-LENGTH RECORDS
		ORIA50,,$DVFVR	;VARIABLE-LENGTH RECORDS
		ORIA50,,$DVFVF	;VARIABLE WITH FIXED-LENGTH HEADER
		0		;NONE OTHERS KNOWN
	STOPCD	<Unknown record format in ORIA>


;"NO FORMAT" ASCII

ORIA20:	XMOVEI	P1,ORAU		;UNFORMATTED ASCII OSR
	TFZN	T3,LSA		;WANT LINE SEQUENCE NUMBERS
	JRST	ORIA80		;NO, STARTUP DATA STREAM
				;YES, TREAT AS STREAM ASCII THEN


;"STREAM" ASCII

ORIA30:	XMOVEI	P1,ORAS		;STREAM ASCII OSR
	TFZ	T3,<EFC,LSA>	;CAN HANDLE LSN'S
	JRST	ORIA80		;STARTUP DATA STREAM


;"STREAM-LF" AND "STREAM-CR" ASCII

ORIA40:	XMOVEI	P1,ORAS		;STREAM ASCII OSR
	TFZ	T3,<ILC,LSA>	;CAN HANDLE LSN'S
	JRST	ORIA80		;STARTUP DATA STREAM


;"VARIABLE", ET AL, AS NEEDED FOR RSX, VAX, AND SO FORTH

ORIA50:	XMOVEI	P1,ORAV		;VAX (ET AL) ASCII OSR
	TFZ	T3,<ILC,LSA>	;CAN HANDLE LSN'S
	JRST	ORIA80		;STARTUP DATA STREAM
;STARTUP A DATA STREAM

ORIA80:	JUMPN	P1,ORIA82	;MAKE SURE AN OSR WAS SELECTED
	STOPCD	<No OSR selected in ORIA>
ORIA82:	FJUMPE	T3,RAT,ORIA84	;ANY RECORD ATTRIBUTES LEFT OVER?
	STOPCD	<Unknown or illegal record format/attributes in ORIA>
ORIA84:	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNE	T1,IO.NEP	;ACTIVE OR PASSIVE LINK?
	JRST	ORIA86		;PASSIVE, NO STARTUP NEEDED
	PUSHJ	P,DPSOI0##	;ACTIVE, NEED CONTROL(CONNECT), CONTROL(PUT)
	 POPJ	P,		;DIED
ORIA86:	MOVEM	P1,.IOOSR(IO)	;SET NEW STATE DISPATCH
	XMOVEI	T1,ORACL	;ASCII OUTPUT SHUTDOWN
	MOVEM	T1,.IOOSS(IO)	;SET FINAL STATE DISPATCH
	JRST	.POPJ1##	;OUTPUT INITIALIZED
;HERE TO CLOSE DOWN THE OUTPUT ASCII STREAM
;
;			*** NOTE ***
;
;		ENTERED FROM CLOSE AT SACIO LEVEL

ORACL:	SKIPG	T1,.IODOM(IO)	;IN A MESSAGE?
	JRST	.POPJ1##	;NO, ALL DONE
	CAIE	T1,$DHDAT	;DATA MESSAGE?
	STOPCD	<Non-data DAP message outstanding in ORACL>
	MOVE	T1,.IOOSF(IO)	;GET OUTPUT PROCESSING FLAGS
	TXZN	T1,IS.ICR	;GOT AN IMPLICIT <CR> HIDING IN THE BUSHES?
	JRST	ORACL3		;NO
	MOVEI	T2,.CHCRT	;YES, A <CR> CHARACTER
	PUSHJ	P,XDBYC0##	;SEND LONELY <CR> AS EMBEDDED CARRIAGE CONTROL
	 POPJ	P,		;BUTTS
ORACL3:	PUSHJ	P,XDEOM0##	;CLOSE OFF THIS MESSAGE
	 POPJ	P,		;OOPS
	JRST	.POPJ1##	;SUCCESSFUL
;REMOTE ASCII STREAM OUTPUT SERVICE ROUTINE

ORAS:	PUSHJ	P,TSAV14##	;NEED SOME ACS HERE!
	SKIPE	.IONIA(T1)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,.ORNIA	;YES, GO CHECK IT OUT
ORAS02:	SETZB	T2,T3		;JUNK RECORD NUMBER
	PUSHJ	P,.XDDAT##	;STARTUP A DATA MESSAGE
	 POPJ	P,		;BUMMER
	XMOVEI	T2,ORAS20	;NOW-WITHIN-A-RECORD STATE SERVICE
	MOVEM	T2,.IOOSR(T1)	;SET NEW STATE SERVICE DISPATCH
	MOVD	T2,RAT,.IDRAT(T1)  ;GET RECORD ATTRIBUTES OF OUTPUT STREAM
	TFNE	T2,LSA		;WAS FILE OPENED FOR LSN'S?
	JRST	ORAS10		;NO, JUST OUTPUT ASCII DATA BYTES
ORAS09:	MOVE	T2,-T2(P)	;RESTORE ASCII CHARACTER
	JRST	ORAS20		;AND OUTPUT ASCII DATA


;HERE TO SHIP A NETWORK LSN

ORAS10:	MOVEI	T2," "		;ASSUME NOT A PAGE MARK
	SKIPGE	T3,.IOOS0(T1)	;1B0 SET? (SOS PAGE MARK)
	MOVEI	T2,.CHFFD	;YES, SWITCH TO PAGE MARK
	PUSHJ	P,.XDBYC##	;OUTPUT PAGE MARK FLAG
	 POPJ	P,		;HO HUM
	MOVEI	T2,5		;NOW WANT 5 DIGITS
	HRRZ	T3,.IOOS0(T1)	;GET THE ACTUAL LSN
	SETZM	.IOOS0(T1)	;WHATEVER HAPPENS, NO MORE LSN
ORAS12:	IDIVI	T3,^D10		;EXTRACT NEXT DIGIT
	PUSH	P,T4		;SAVE IT MOMENTARILY
	SOJG	T2,ORAS12	;LOOP FOR ALL FIVE DIGITS
	SETZ	T3,		;CLEAR ACCUMULATOR
	MOVEI	T2,5		;MUST NOW RETRIEVE 5 DIGITS
ORAS14:	POP	P,T4		;RETRIEVE AN ASCIIZABLE DIGIT
	LSH	T3,^D07		;MAKE ROOM AND
	IORI	T3,"0"(T4)	;BLEND IT IN
	SOJG	T2,ORAS14	;LOOP FOR ALL FIVE DIGITS
	LSH	T3,1		;LEFT-JUSTIFY THE FIVE ASCII DIGITS
	MOVEI	T4,5		;NOW WE CAN OUTPUT THE 5 DIGITS
ORAS16:	LSHC	T2,7		;NEXT DIGIT
	ANDI	T2,177		;AND ONLY THE NEXT DIGIT
	PUSHJ	P,.XDBYC##	;OUTPUT ONE CHECKSUMMED DATA CHARACTER
	 POPJ	P,		;BUMMER, SO MUCH FOR THAT LSN
	SOJG	T4,ORAS16	;LOOP FOR ALL FIVE DIGITS
	JRST	ORAS09		;NOW CAN START UP USER DATA
;HERE TO OUTPUT ONE ASCII CHARACTER (CDB ADDRESS IN T1, CHAR IN T2)

ORAS20:	EXCH	T1,IO		;SET I/O CDB INDEX
	PUSHJ	P,XDBYC0##	;SHIP ONE DAP DATA MESSAGE BYTE
	 JRST	ORAS24		;ERROR
	CAIGE	T2," "		;PRINTING ASCII GRAPHIC?
	JRST	ORAS60		;NO, CONTROL, MAYBE EOR
ORAS23:	AOS	(P)		;YES, TAKE SUCCESSFUL RETURN
ORAS24:	EXCH	IO,T1		;RESTORE T1 AND IO
	POPJ	P,		;RETURN AS APPROPRIATE

;CHECK FOR END OF RECORD CHARACTER

ORAS60:	CAIN	T2,.CHTAB	;IF A TAB
	JRST	ORAS23		;THEN NOT EOR
	CAIL	T2,.CHLFD	;IF <LF>, <VT>, OR <FF>
	CAILE	T2,.CHFFD	; . . .
	CAIL	T2,.CHDLE	;IF <DLE>, <DC1>, <DC2>, <DC3>, OR <DC4>
	CAILE	T2,.CHDC4	; . . .
	CAIL	T2,.CHCNZ	;OR A <SUB>, OR <ESC>
	CAILE	T2,.CHESC	; . . .
	JRST	ORAS23		;RANDOM CONTROL, NOT EOR
;	JRST	ORAS70		;DAP ASCII EOR CHARACTER

;END OF RECORD CHARACTER (BUT BYTE *ALREADY* OUTPUT)

ORAS70:	EXCH	IO,T1		;PUT THE ACS BACK
	PUSHJ	P,TSAV14##	;PROTECT THE T'S
	XMOVEI	T2,ORAS77	;BYTE-ALREADY-OUTPUT STATE
	MOVEM	T2,.IOOSR(T1)	;SET IN CASE XDEOM FAILS
	PUSHJ	P,.XDEOM##	;CAP OFF THIS DATA MESSAGE
	 POPJ	P,		;ERROR (BUT BYTE ALREADY "OUTPUT")
ORAS77:	XMOVEI	T2,ORAS		;NOT-IN-A-RECORD STATE
	MOVEM	T2,.IOOSR(T1)	;SET FOR NEXT DATA BYTE
	JRST	.POPJ1##	;THIS BYTE OUTPUT SUCCESSFULLY
;REMOTE ASCII UNFORMATTED OUTPUT SERVICE ROUTINE

ORAU:	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORAU02:	SKIPE	.IONIA(T1)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,.ORNIA	;YES, GO CHECK IT OUT
	SETZB	T2,T3		;SELECT RECORD NUMBER
	PUSHJ	P,.XDDAT##	;STARTUP A NEW DATA MESSAGE
	 POPJ	P,		;BUMMER
	XMOVEI	T2,ORAU20	;MESSAGE-IN-PROGRESS STATE
	MOVEM	T2,.IOOSR(T1)	;SET NEW STATE DISPATCH
	MOVE	T2,-T2(P)	;RESTORE ASCII CHARACTER

;HERE TO OUTPUT ONE ASCII CHARACTER (CDB IN T1, CHAR IN T2)

ORAU20:	SKIPG	.IODOC(T1)	;ANY ROOM LEFT IN CURRENT DATA MESSAGE?
	JRST	ORAU60		;NO, STARTUP A NEW RECORD
	EXCH	T1,IO		;SETUP I/O CDB INDEX
	PUSHJ	P,XDBYC0##	;STASH THIS BYTE
	 CAIA			;FAILED (CAN'T HAPPEN)
	AOS	(P)		;INDICATE SUCCESS
	EXCH	IO,T1		;RESTORE T1 AND IO
	POPJ	P,		;RETURN AS INDICATED

;CLOSE CURRENT RECORD, START A NEW ONE (BYTE NOT YET OUTPUT)

ORAU60:	PUSHJ	P,TSAV14##	;SAVE THE T'S
	PUSHJ	P,.XDEOM##	;CAP OFF THIS MESSAGE
	 POPJ	P,		;ERROR (BYTE NOT YET OUTPUT)
	XMOVEI	T2,ORAU		;NEED-A-NEW-MESSAGE STATE
	MOVEM	T2,.IOOSR(T1)	;SET NEW STATE DISPATCHER
	JRST	ORAU02		;AND START UP A NEW DATA MESSAGE
;REMOTE ASCII VAX ET AL OUTPUT SERVICE ROUTINE

ORAV:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORAV02:	SKIPE	.IONIA(IO)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,ORNIA0	;YES, GO CHECK IT OUT
	SETZB	T2,T3		;ZERO RECORD NUMBER
	PUSHJ	P,XDDAT0##	;START UP A FRESH DATA RECORD
	 POPJ	P,		;CAN'T
	XMOVEI	T3,ORAV20	;THE IN-A-RECORD OSR
	MOVEM	T3,.IOOSR(IO)	;SET NEW OSR
	MOVX	T3,IS.ICR	;THE <CR> SEEN FLAG
	ANDCAM	T3,.IOOSF(IO)	;RESET IT SINCE NEW RECORD
	MOVE	T2,-T2(P)	;RESTORE OUTPUT DATA BYTE
	JRST	ORAV22		;GO OUTPUT DATA BYTE


;HERE TO OUTPUT ONE ASCII CHARACTER (ENTERED AS OSR)

ORAV20:	PUSHJ	P,.SACIO	;SWITCH TO I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORAV22:	CAIGE	T2," "		;CONTROL OR PRINTING GRAPHIC?
	JRST	ORAV40		;CONTROL, CHECK FOR EOR CONDITION
ORAV23:	PUSHJ	P,XDBYC0##	;OUTPUT DATA BYTE
	 POPJ	P,		;ERROR
	JRST	.POPJ1##	;SUCCESSFUL


;HERE ON CONTROL, END OF RECORD IF A BREAK CHARACTER

ORAV40:	CAIN	T2,.CHTAB	;IF A <TAB>
	JRST	ORAV23		;THEN TREAT AS NORMAL ASCII GRAPHIC
	CAIN	T2,.CHCRT	;IF A <CR>
	JRST	ORAV50		;TREAT SPECIAL (FOR <CR><LF> CONVERSION)
	CAIL	T2,.CHLFD	;IF A <LF>, <VT>, OR <FF>
	CAILE	T2,.CHFFD	; . . .
	CAIL	T2,.CHDLE	;OR A <DLE>, <DC1>, <DC2>, <DC3>, OR <DC4>
	CAILE	T2,.CHDC4	; . . .
	CAIL	T2,.CHCNZ	;OR A <SUB>, OR <ESC>
	CAILE	T2,.CHESC	; . . .
	JRST	ORAV23		;NO, RANDOM DATA CHARACTER
ORAV43:	PUSHJ	P,XDBYC0##	;OUTPUT EMBEDDED CARRIAGE-CONTROL CHARACTER
	 POPJ	P,		;NET DIED?
ORAV45:	XMOVEI	T3,ORAV47	;THE BYTE-ALREADY-OUTPUT STATE
	MOVEM	T3,.IOOSR(IO)	;SET NEW STATE DISPATCH
	MOVX	T3,IS.ICR	;THE <CR> FLAG
	ANDCAM	T3,.IOOSF(IO)	;RESET THAT TOO
	PUSHJ	P,XDEOM0##	;END OF RECORD
	 POPJ	P,		;ERROR
ORAV47:	XMOVEI	T3,ORAV		;NOT-IN-A-RECORD STATE
	MOVEM	T3,.IOOSR(IO)	;SET FOR NEXT OUTPUT DATA BYTE
	JRST	.POPJ1##	;SUCCESSFUL
;HERE ON <CR>, CHECK FOR <CR><LF> AND TREAT IT SPECIAL

ORAV50:	MOVX	T3,IS.ICR	;A <CR>, GET THE <CR> FLAG
	IORM	T3,.IOOSF(IO)	;AND NOTE ONE PENDING IN CASE OF CLOSE
	XMOVEI	T3,ORAV54	;SPECIAL CHECK OSR
	MOVEM	T3,.IOOSR(IO)	;FOR <CR><LF> FOR IMPLIED <LF><CR> SERVICE
	JRST	.POPJ1##	;SUCCESFUL RETURN


;HERE ON CHARACTER AFTER <CR> - ENTERED AS AN OSR

ORAV54:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S
	MOVD	T3,RAT		;GET RECORD ATTRIBUTES
	TFNE	T3,ILC		;DOING IMPLIED <LF><CR> ENVELOPE?
	CAIE	T2,.CHLFD	;YES, IS THIS A <CR><LF>?
	CAIA			;OUTPUT CHARACTERS AS EMBEDDED CARRIAGE CONTROL
	JRST	ORAV45		;A <CR><LF> TO IMPLIED <LF><CR> ENVELOPE

;HERE WHEN MUST OUTPUT THE <CR> AS EMBEDDED CARRIAGE CONTROL

	MOVEI	T2,.CHCRT	;THE <CR> CHARACTER
	PUSHJ	P,XDBYC0##	;OUTPUT IT
	 POPJ	P,		;BUMMER
	MOVX	T2,IS.ICR	;THE <CR>-PENDING FLAG
	ANDCAM	T2,.IOOSF(IO)	;CLEAR THAT OUT SINCE <CR> IS NOW PROCESSED
	XMOVEI	T2,ORAV20	;OTHERWISE EMBEDDED <CR>, NOTHING FANCY,
	MOVEM	T2,.IOOSR(IO)	;SO BACK TO NORMAL ASCII OSR
	MOVE	T2,-T2(P)	;RETRIEVE CHARACTER AFTER THE <CR>
	JRST	ORAV22		;OUTPUT FIRST OVERPRINT CHARACTER
;REMOTE BINARY OUTPUT INITIALIZATION

ORIB:	SETZ	P1,		;NO OSR YET
	MOVE	P2,.IOIOC(IO)	;I/O CONTROL FLAGS
	MOVD1	T2,RFM		;RECORD FORMAT
	MOVD	T3,RAT		;AND RECORD ATTRIBUTES
	TFZ	T3,MCY		;MACY11 DOESN'T AFFECT US HERE
	JSP	T4,.CDISP##	;DISPATCH ON RECORD FORMAT
		ORIB10,,$DVFNR	;"NO FORMAT"
		ORIB20,,$DVFFX	;FIXED LENGTH
		ORIB20,,$DVFVR	;VARIABLE LENGTH
		ORIB20,,$DVFVF	;VARIABLE WITH FIXED HEADER
		0		;THAT'S IT
	STOPCD	<Unknown/Illegal record format in ORIB>

;HERE FOR "NO FORMAT" RECORDS (I.E., NO "RECORDS" AT ALL)

ORIB10:	MOVD1	T2,BSZ		;GET DATA BYTE SIZE
	CAIN	T2,^D08		;8-BIT BYTES?
	XMOVEI	P1,ORBB		;YES, EASY BYTE BINARY ROUTINE
	CAIN	T2,^D36		;NO, 36-BIT BYTES?
ORIB12:	XMOVEI	P1,ORBW		;YES, BINARY WORD, SPECIAL-CASE IT
	TXNE	P2,IC.RSI	;TRYING FOR RECORDS?
	STOPCD	<Record-structured I/O selected in ORIB10>
	JUMPN	P1,ORIB80	;GO IF OSR SELECTED
	STOPCD	<DAP data byte size neither 8 nor 36 in ORIB10>


;HERE FOR BINARY RECORD FORMATTING

ORIB20:	LDB	T1,[POINTR P2,IC.RFM]  ;GET I/O CONTROL RECORD FORMAT
	CAIN	T1,.ICRF3	;36PACK'ED PDP-10 WORDS?
	JRST	ORIB12		;YES, SPECIAL SERVICE
	XMOVEI	P1,ORBR		;BINARY RECORD OSR
	TXNN	P2,IC.RSI	;USER EXPECTING RECORDS?
	STOPCD	<Record-structured I/O not selected in ORIB20>
	MOVD1	T2,BSZ		;GET DAP DATA BYTESIZE
	CAIE	T2,0		;IGNORE IF NULL
	CAIN	T2,^D08		;MUST BE 8
	JRST	ORIB80		;GO TO IT
	STOPCD	<DAP data byte size not 8 in ORIB20>
;HERE WITH OSR SELECTED, SETUP AND START I/O

ORIB80:	JUMPN	P1,ORIB82	;OK IF WE HAVE AN OSR
	STOPCD	<No OSR selected in ORIB80>
ORIB82:	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNE	T1,IO.NEP	;ACTIVE OR PASSIVE LINK?
	JRST	ORIB86		;PASSIVE, NO STARTUP NEEDED
	PUSHJ	P,DPSOI0##	;ACTIVE, NEED CONTROL(CONNECT), CONTROL(PUT)
	 POPJ	P,		;DIED
ORIB86:	MOVEM	P1,.IOOSR(IO)	;SET NEW STATE DISPATCH
	XMOVEI	P1,ORBCL	;BINARY OUTPUT SHUTDOWN
	MOVEM	P1,.IOOSS(IO)	;SET FINAL STATE DISPATCH
	JRST	.POPJ1##	;OUTPUT INITIALIZED
;HERE TO CLOSE DOWN THE OUTPUT BINARY STREAM
;
;			*** NOTE ***
;
;		ENTERED FROM CLOSE AT SACIO LEVEL

ORBCL:	SKIPG	T1,.IODOM(IO)	;IN A MESSAGE?
	JRST	.POPJ1##	;NO, ALL DONE
	CAIE	T1,$DHDAT	;DATA MESSAGE?
	STOPCD	<Non-data DAP message outstanding in ORBCL>
	PUSHJ	P,XDEOM0##	;CLOSE OFF THIS MESSAGE
	 POPJ	P,		;OOPS
	JRST	.POPJ1##	;SUCCESSFUL
;REMOTE 8-BIT BYTE BINARY OUTPUT SERVICE ROUTINE

ORBB:	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORBB02:	SKIPE	.IONIA(T1)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,.ORNIA	;YES, CHECK IT OUT
	SETZB	T2,T3		;CLEAR DATA RECORD NUMBER
	PUSHJ	P,.XDDAT##	;START UP A NEW DATA MESSAGE
	 POPJ	P,		;BUTTS
	XMOVEI	T2,ORBB20	;NOW-WITHIN-A-RECORD STATE
	MOVEM	T2,.IOOSR(T1)	;SET NEW STATE DISPATCH
	MOVE	T2,-T2(P)	;RESTORE ACTUAL DATA BYTE
				;AND FALL INTO BYTE OUTPUTTER

;HERE TO OUTPUT ONE 8-BIT BINARY DATA BYTE (CDB IN T1, BYTE IN T2)

ORBB20:	SKIPG	.IODOC(T1)	;ANY ROOM LEFT IN CURRENT MESSAGE?
	JRST	ORBB60		;NO, ALLOCATE A NEW MESSAGE
	EXCH	T1,IO		;YES, SET UP I/O CDB INDEX
	PUSHJ	P,XDBYC0##	;STASH THIS 8-BIT CHARACTER
	 CAIA			;FAILED???
	AOS	(P)		;SKIP RETURN
	EXCH	IO,T1		;RESTORE T1
	POPJ	P,		;RETURN AS APPROPRIATE

;END OF RECORD, CLOSE OFF DAP MESSAGE AND START UP A NEW ONE

ORBB60:	PUSHJ	P,TSAV14##	;SAVE THE T'S
	XMOVEI	T2,ORBB		;NEW STATE WILL BE NOT-IN-A-MESSAGE
	MOVEM	T2,.IOOSR(T1)	;SET WHAT WILL BE NEW STATE
	PUSHJ	P,.XDEOM##	;CLOSE OFF CURRENT DAP MESSAGE
	 POPJ	P,		;ERROR (DATA BYTE NOT OUTPUT)
	JRST	ORBB02		;NOW GO START UP A NEW RECORD
;REMOTE 36-BIT BINARY WORD OUTPUT SERVICE ROUTINE

ORBW:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORBW02:	SKIPE	.IONIA(IO)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,ORNIA0	;YES, CHECK IT OUT
	LDB	T2,[POINTR .IOIOC(IO),IC.RFM]  ;GET RECORD FORMAT CONTROL
	CAIN	T2,.ICRF3	;36PACK'ED PDP-10 WORDS?
	SKIPA	T2,.IORSZ(IO)	;YES, GET BYTE-COUNTED RECORD SIZE
	MOVEI	T2,123		;NO, RANDOM BIT PATTERN
	ADDI	T2,10		;ALLOW FOR DAP HEADER
	CAMG	T2,.IONOC(IO)	;ROOM FOR ANOTHER "RECORD"
	JRST	ORBW04		;YES
	PUSHJ	P,XDFLS0##	;NO, FLUSH OUT DATA RECORDS SO FAR
	 POPJ	P,		;NET DIED?
ORBW04:	SETZB	T2,T3		;OUTPUT RECORD NUMBER
	PUSHJ	P,XDDAT0##	;STARTUP A NEW OUTPUT DATA MESSAGE
	 POPJ	P,		;BUTTS
	LDB	T2,[POINTR .IOIOC(IO),IC.RFM]  ;GET RECORD FORMAT CONTROL
	CAIN	T2,.ICRF3	;36PACK'ED PDP-10 WORDS?
	SKIPA	T2,.IORSZ(IO)	;YES, GET RECORD-SIZE
	MOVE	T2,.IODOC(IO)	;NO, LIMIT BASED ON DAP MESSAGE SIZE THEN
	MOVEM	T2,.IOOS0(IO)	;SET BYTE COUNTER FOR THIS "RECORD"
	XMOVEI	T2,ORBW20	;NOW-IN-A-MESSAGE STATE
	MOVEM	T2,.IOOSR(IO)	;SET NEW DISPATCH
	MOVE	T2,-T2(P)	;RESTORE OUTPUT WORD (36-BITS)
	JRST	ORBW22		;FALL INTO OUTPUT SERVICE
;HERE FOR ONE 36-BIT BINARY BYTE - DAP DATA BYTES 1 - 4.5
;
;ENTERED AS AN OSR

ORBW20:	PUSHJ	P,.SACIO##	;RUN IN I/O CONTEXT HERE
ORBW22:	SKIPE	T1,.IODOB(IO)	;ANY UNUSED BITS FROM LAST TIME?
	JRST	ORBW30		;YES, THEN "ODD" WORD CALL
	MOVNI	T1,^D09		;ACCOUNT FOR A FULL 2*4.5 DAP BYTES
	ADDB	T1,.IOOS0(IO)	;TO BE USED FOR THE NEXT WORD PAIR
	JUMPL	T1,ORBW60	;IF OUT OF ROOM, START A NEW RECORD
	PUSHJ	P,XDBYC0##	;BYTE 1 = BITS 28 - 35
	 STOPCD	<XDBYC (1) failed in ORBW>
	ROT	 T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 2 = BITS 20 - 27
	 STOPCD	<XDBYC (2) failed in ORBW>
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 3 = BITS 12 - 19
	 STOPCD	<XDBYC (3) failed in ORBW>
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 4 = BITS 04 - 11
	 STOPCD	<XDBYC (4) failed in ORBW>
	MOVE	M0,.IODOK(IO)	;PRE-4.5TH BYTE CRC
	MOVEM	M0,.IODOK+1(IO)	;SAVE FOR ORBW30 (UGLY!!!)
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 4.5 = BITS 0 - 3
	 STOPCD	<XDBYC (4.5) failed in ORBW>
	ROT	T2,-^D04	;RESTORE T2
	MOVEI	M0,^D04		;4 BITS UNUSED IN LAST DAP DATA BYTE
	MOVEM	M0,.IODOB(IO)	;SET BITCNT FIELD
	JRST	.POPJ1##	;THIS WORD SUCCESSFULLY OUTPUT
;HANDLE THE ODD WORD - DAP DATA BYTES 4.5 - 9

ORBW30:	CAIE	T1,4		;HAD BETTER HAVE BEEN 4!
	STOPCD	<Unused bit count not 4 in ORBW30>
	SETZM	.IODOB(IO)	;CLEAR UNUSED BIT COUNTER
	MOVE	T1,T2		;POSITION "HIGH ORDER" WORD
	LDB	T2,.IONOP(IO)	;FETCH BACK LAST DAP DATA BYTE
	LSH	T2,+<4 * ^D08>	;ABUT IT UP TO THE HIGH-ORDER WORD
	LSHC	T1,-<4 * ^D08>	;POSITION FULL FIFTH BYTE
	DPB	T2,.IONOP(IO)	;AND RE-WRITE THE FIFTH DATA BYTE
	MOVE	M0,.IODOK+1(IO)	;NOW FETCH PRE-4.5TH BYTE CRC "SEED"
	MOVEM	M0,.IODOK(IO)	;AND RESTORE CRC
	PUSHJ	P,XDCRC1##	;CALCULATE NEW CRC BASED ON FULL 8 BITS
	 STOPCD			;CAN'T HAPPEN
	LSHC	T1,-^D04	;RESTORE T2
	ROT	T2,-^D04	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 6 = BITS 24 - 31
	 STOPCD	<XDBYC (6) failed in ORBW>
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 7 = BITS 16 - 23
	 STOPCD	<XDBYC (7) failed in ORBW>
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 8 = BITS 08 - 15
	 STOPCD	<XDBYC (8) failed in ORBW>
	ROT	T2,-^D08	;POSITION NEXT BYTE
	PUSHJ	P,XDBYC0##	;BYTE 9 = BITS 00 - 07
	 STOPCD	<XDBYC (9) failed in ORBW>
	ROT	T2,-^D08	;RESTORE T2
	JRST	.POPJ1##	;36-BIT BYTE SUCCESSFULLY OUTPUT

;NEED A NEW DATA MESSAGE

ORBW60:	PUSHJ	P,TSAV14##	;SAVE THE T'S MODULO ORBW02
	XMOVEI	T1,ORBW		;SET NEW NOT-IN-A-RECORD STATE
	MOVEM	T1,.IOOSR(IO)	;SET IN THE CDB
	PUSHJ	P,XDEOM0##	;TERMINATE THIS MESSAGE
	 POPJ	P,		;ERROR (BYTE NOT "OUTPUT")
	JRST	ORBW02		;START UP A NEW MESSAGE
;REMOTE RECORD-FORMATTED BINARY OUTPUT (ENTERED AS OSR)

ORBR:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
	PUSHJ	P,.SAVE4##	;SAVE THE P'S
	PUSHJ	P,TSAV14##	;SAVE THE T'S
ORBR02:	ADDI	T3,10		;ALLOW FOR DAP OVERHEAD (USUALLY 5, BUT...)
	CAMG	T3,.IONOC(IO)	;WILL THIS RECORD FIT?
	JRST	ORBR05		;YEAH
	PUSHJ	P,XDFLS1##	;NO, FLUSH OUT DAP SO FAR
	 POPJ	P,		;SOMETHING DIED

ORBR05:	SKIPE	.IONIA(IO)	;GOT AN INPUT MESSAGE LURKING ABOUT?
	PUSHJ	P,ORNIA0	;YES, CHECK IT OUT
	SETZ	T2,		;CLEAR DATA RECORD NUMBER
	MOVE	T3,-T2(P)	;GET USER'S DATA RECORD NUMBER
	PUSHJ	P,XDDAT1##	;START UP A NEW DATA MESSAGE
	 POPJ	P,		;BUTTS
	MOVE	P1,-T3(P)	;GET RECORD LENGTH
	CAMLE	P1,.IONOC(IO)	;ROOM FOR IT LEFT?
	JRST	[MOVEI	M0,$EIRTB	;RECORD TOO BIG
		POPJ	P,]		;TELL USER OF WOES
	MOVE	P2,-T4(P)	;GET POINTER TO RECORD DATA

;LOOP OUTPUTTING RECORD DATA BYTES

ORBR20:	ILDB	T2,P2		;FETCH NEXT RECORD DATA BYTE
	PUSHJ	P,XDBYC0##	;STASH THIS 8-BIT BYTE
	 POPJ	P,		;PROPAGATE ERROR RETURN
	SOJG	P1,ORBR20	;LOOP FOR REST OF RECORD

;HERE AT END OF RECORD

	PJRST	XDEOM1##	;CLOSE OFF THIS DAP DATA RECORD
;OUTPUT HELPER TO CHECK OUT PENDING INPUT MESSAGE (STATUS, ETC.)

.ORNIA:	EXCH	T1,IO		;SETUP I/O CONTEXT
	PUSHJ	P,ORNIX0	;CHECK OUT THE INPUT DATA
	 POP	P,0(P)		;TAKE CALLER'S ERROR RETURN
	EXCH	IO,T1		;RESTORE RANDOM ACS
	POPJ	P,		;RETURN AS APPROPRIATE

ORNIA0:	PUSHJ	P,ORNIX0	;CHECK OUT THE INPUT DATA
	 POP	P,0(P)		;TAKE CALLER'S ERROR RETURN
	POPJ	P,		;RETURN AS APPROPRIATE


;THE ACTUAL WORK IS DONE HERE

ORNIX0:	PUSHJ	P,.SAVE4##	;WANT LOTS OF ACS
	PUSHJ	P,TSAV14##	;WANT LOTS OF REGISTERS TOO
	MOVX	M0,IO.NBT	;BUT ESPECIALLY,
	IORM	M0,.IOCCF(IO)	; WE DON'T WANT TO BLOCK HERE!
	PUSHJ	P,RDMSG1##	;SEE WHAT THE NETWORK HAS FOR US
	JRST	[MOVX	T1,IO.NBT	;THAT FUNNY LITTLE BIT
		ANDCAM	T1,.IOCCF(IO)	;GET IT OUT OF THE WAY
		CAIE	M0,$EINTI	;NON-BLOCKING NETWORK INPUT?
		POPJ	P,		;NO, BAD NEWS
		WARNCD	<Network input set, but no data available>
		JRST	.POPJ1##]	;HMMM CONTINUE WITH OUTPUT
	MOVX	T1,IO.NBT	;THAT FUNNY WITTLE BIT
	ANDCAB	T1,.IOCCF(IO)	;GET IT OUT OF THE WAY
	CAIE	T2,$DHSTS	;LOOKING AT A STATUS MESSAGE?
	JRST	ORNIX5		;NO - LOOKS BAD, BUT THERE IS STILL HOPE
	TXNE	T1,IO.NEP	;BETTER BE AN ACTIVE DAPPER
	STOPCD	<FAL received a DAP STATUS message on output>
	PUSHJ	P,RDSTS1##	;GO SLURP UP THE STATUS MESSAGE
	 POPJ	P,		;BAD MESSAGE?
	POPJ	P,		;PROPAGATE EXCEPTION RETURN

;HERE FOR A NON-STATUS MESSAGE, BETTER BE RUNNING FAL!

ORNIX5:	TXNN	T1,IO.NEP	;[1040] BETTER BE A PASSIVE DAPPER
	STOPCD	<Received DAP message not STATUS on data output>
	PUSHJ	P,RDMSR1##	;FAL, RE-EAT THE MESSAGE
	 POPJ	P,		;HO HUM
	MOVEI	M0,$EINMP	;EXCEPTION RETURN:INPUT MESSAGE PENDING
	POPJ	P,		;TELL FAL TO DO SOMETHING ABOUT IT
;FILE MODE TO INPUT SERVICE ROUTINE

MOISTB:	XWD	0,	ILASC	;.ICDEF  --  DEFAULT (7-BIT ASCII)
	XWD	0,	ILASC	;.ICASC  --  ASCII (7-BIT)
	XWD	0,	ILASC	;.ICAS8  --  ASCII (8-BIT)
	XWD	0,	ILBYT	;.ICEBC  --  EBCDIC (RESERVED)
	XWD	0,	ILBYT	;.ICPIM  --  PACKED IMAGE
	XWD	0,	ILBYT	;.ICIMG  --  IMAGE
	XWD	0,	ILBYT	;.ICBYT  --  BINARY 8-BIT BYTES
	XWD	0,	ILBYT	;.ICBIN  --  BINARY 36-BIT BYTES


;FILE MODE TO OUTPUT SERVICE ROUTINE

MOOSTB:	XWD	0,	OLASC	;.ICDEF  --  DEFAULT (7-BIT ASCII)
	XWD	0,	OLASC	;.ICASC  --  ASCII (7-BIT)
	XWD	0,	OLASC	;.ICAS8  --  ASCII (8-BIT)
	XWD	0,	OLBYT	;.ICEBC  --  EBCDIC (RESERVED)
	XWD	0,	OLBYT	;.ICPIM  --  PACKED IMAGE
	XWD	0,	OLBYT	;.ICIMG  --  IMAGE
	XWD	0,	OLBYT	;.ICBYT  --  BINARY 8-BIT BYTES
	XWD	0,	OLBYT	;.ICBIN  --  BINARY 36-BIT BYTES
	SUBTTL	IOFUN - Random I/O functions

;IOFUN  --  RANDOM I/O FUNCTIONS
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<FUN>
;	MOVX	T3,<ARG>
;	MOVX	T4,<ETC>
;	 ERROR RETURN
;	NORMAL RETURN
;
;Where <CDB> is the address of the controlling I/O CDB; <FUN> is
;the function to be performed (.FUxxx); <ARG> is the first argument
;(if any) to be passed (or perhaps returned depending on the func-
;tion being performed); <ETC> is any other argument needed.
;
;On error return the requested function could not be performed (or
;possibly the function itself was illegal), an error code is in M0.
;
;On normal return the function completed successfully (see the in-
;dividual functions for more details).
;
;Uses T1 - T4.

	ENTRY	.IOFUN
	INTERN	IOFUN0,	IOFUN1

.IOFUN:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
IOFUN0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
IOFUN1:	PUSHJ	P,TSAV14##	;AND THE T'S AS WELL
	CAIL	T2,1		;IS FUNCTION IN RANGE?
	CAILE	T2,.FUMAX	; . . .
	JRST	[MOVEI	M0,$EIILF	;ILLEGAL FUNCTION
		POPJ	P,]		;ERROR RETURN
	MOVE	P1,.IOCCF(IO)	;CALL WITH P1 HOLDING CHANNEL CONTROL FLAGS
	MOVE	P2,.IOIOC(IO)	;AND P2 WITH THE I/O CONTROL FLAGS
	PJRST	@IOFUNT-1(T2)	;DISPATCH TO FUNCTION-SPECIFIC PROCESSOR
				; (FUNCTIONS START AT 1 . . .)


;THE FUNCTION DISPATCH TABLE

IOFUNT:	IFIW	IFBOR		;01 - WRITE BEGINING OF RECORD
	IFIW	IFLSN		;02 - WRITE ASCII LINE SEQUENCE NUMBER
	IFIW	IFIEC		;03 - ATTEMPT I/O ERROR RECOVERY CONTINUATION

	.FUMAX==.-IOFUNT	;MAXIMUM FUNCTION
	SUBTTL	IOFUN - IFBOR -- Write begining of record

;IFBOR - WRITE BEGINING OF RECORD
;Call is:
;
;	MOVX	T3,<LEN>
;	MOVX	T4,<ETC>
;	PUSHJ	P,IFBOR
;	 error return
;	normal return
;
;Where <LEN> is the length of the record about to be written (via calls
;to the I/O service routine operating in byte mode); <ETC> is the record
;"address" for MACY11-packed files.
;
;On error return an I/O error occurred, or the length is invalid (e.g.,
;too big, too small).
;
;On normal return the OSR is set to accept data bytes.
;
;Uses T1 - T4.

IFBOR:	TXNE	P1,IO.NET	;LOCAL OR REMOTE?
	JRST	RFBOR		;REMOTE
;	JRST	LFBOR		;LOCAL

;CONTINUED ON NEXT PAGE
;HERE ON LOCAL FILE SERVICE BEGINING OF RECORD

LFBOR:	TXNE	P2,IC.MCY!IC.MEY;MACY11-PACKING?
	JRST	LFMCY		;YES
	MOVEI	M0,$EINRS	;NO, NOT A RECORD-STRUCTURED FILE
	POPJ	P,		;PROPAGATE ERROR


;HERE TO START UP A MACY11-PACKED RECORD

LFMCY:	SKIPE	.IOOS3(IO)	;STILL IN A RECORD?
	JRST	[MOVEI	M0,$EIRSO	;YES, RECORD STILL OUTSTANDING
		POPJ	P,]		;RETURN ERROR
	CAIL	T3,0		;NOT IN A RECORD, RANGE-CHECK SIZE
	CAILE	T3,177777-6	;WILL IT FIT?
	JRST	[MOVEI	M0,$EIRTB	;NO, RECORD TOO BIG
		POPJ	P,]		;RETURN ERROR
	CAIL	T4,0		;RANGE-CHECK ADDRESS TOO
	CAILE	T4,177777	;WILL IT FIT?
	JRST	[MOVEI	M0,$EIRAI	;NO, RECORD ADDRESS ILLEGAL
		POPJ	P,]		;RETURN ERROR
	ADDI	T3,6		;ADD IN MACY11 OVERHEAD
	HRL	T3,T4		;POSITION ADDRESS
	MOVEM	T3,.IOOS0(IO)	;SET ADDRESS,,COUNT FLAG FOR OLMCY
	JRST	.POPJ1##	;SUCCESSFUL RETURN



;HERE FOR REMOTE BEGINING OF RECORD

RFBOR:	CAIG	T3,0		;*** CAN'T DO 0-LENGTH RECORDS
	STOPCD	<Zero/Negative length record in RFBOR>
	MOVEM	T3,.IOOS1(IO)	;JUST LEAVE IT FOR ORBR/ETC.
	JRST	.POPJ1##	;RETURN HAPPILY NOW
	SUBTTL	IOFUN - IFLSN -- Write ASCII line-sequence-number

;IFLSN - WRITE ASCII LINE-SEQUENCE-NUMBER
;Call is:
;
;	MOVX	T3,<LSN>
;	PUSHJ	P,IFLSN
;	 error return
;	normal return
;
;Where <LSN> is the binary line sequence number (maximum 99,999) to
;be written to the output file. If the <LSN> is 1B0 or -1 then the
;LSN is interpreted to mean only an SOS page mark. If the LSN is
;negative, then it is interpreted as being an SOS page mark followed
;by a normal LSN.
;
;On error return an I/O error occurred, or the LSN is illegal.
;
;On normal return the LSN has been set, the OSR is ready to accept
;output characters.
;
;It is the caller's responsibility to ensure that the output file is
;at the "begining" of a text line.
;
;Uses T1 - T4.

IFLSN:	JUMPGE	T3,IFLSN2	;IF POSITIVE, THEN NORMAL LSN
	MOVSI	T2,(1B0)	;1B0 TO FLAG PAGE MARK
	MOVEM	T2,.IOOS0(IO)	;REMEMBER THAT MUCH
	ANDI	T3,777777	;REDUCE TO JUST LSN FIELD
	CAIE	T3,0		;IF 0
	CAIN	T3,777777	;OR -1
	JRST	.POPJ1##	;THEN ALL DONE (ONLY A PAGE MARK)
IFLSN2:	CAIE	T3,0		;0 IS ILLEGAL
	CAILE	T3,^D99999	;WILL LSN FIT IN 5 DIGITS?
	JRST	[MOVX	M0,$EILTB	;LSN TOO BIG
		POPJ	P,]		;ERROR RETURN
	SKIPGE	.IOOS0(IO)	;STILL HAVE AN LSN OUTSTANDING?
	HRLI	T3,400000	;SET .LT. 0 TO INDICATE PAGE MARK
IFLSN5:	MOVEM	T3,.IOOS0(IO)	;SAVE LSN FOR OUTPUT SERVICE ROUTINE
				; (THIS IS DONE SINCE OUTPUT MAY NOT HAVE
				;  BEEN INITIALIZED YET SO WE CAN'T DIDDLE
				;  WITH .IOOBP/ETC HERE)
	JRST	.POPJ1##	;SUCCESSFUL RETURN
	SUBTTL	IOFUN - IFIEC -- I/O error recovery and continuation

;IFIEC - I/O ERROR CONTINUATION
;Call is:
;
;	PUSHJ	P,IFIEC
;	 error return
;	normal return
;
;On error return the I/O service routine cannot be continued (e.g., the
;network link is down, the disk was dismounted, etc.), an error code is
;in M0.
;
;On normal return the I/O service routine is ready to accept data again
;(for input, simply call the service routine again; for output the failed
;call must be re-executed since the data from the failed call was not
;accepted).
;
;Uses T1 - T4.

IFIEC:	STOPCD	<I/O error recovery not yet written (IFIEC)>
;IOERX - READ AND TRANSLATE EXTENDED I/O ERROR STATUS

IOERX1:	MOVE	T4,.IOCHN(IO)	;I/O CHANNEL IN QUESTION
	MOVEI	T3,.DFRES	;FUNCTION: RETURN ERROR STATUS
	MOVE	T2,[2,,T3]	;DEVOP. ARG POINTER TO
	DEVOP.	T2,		;READ EXTENDED I/O ERROR STATUS
	 POPJ	P,		;DUH?
	CAILE	T2,IOERXL	;WITHIN KNOWN RANGE?
	SETO	T2,		;NO
	MOVE	M0,IOERXT(T2)	;GET INPUT,,OUTPUT ERROR STATUS
	JRST	.POPJ1##	;RETURN WITH ERROR CODE IN M0


;THE EXTENDED ERROR STATUS TRANSLATION TABLE

	XWD	$EIXXX,$EIXXX	;(--) UNKNOWN ERROR STATUS
IOERXT:	XWD	$EIXXX,$EIXXX	;(00) UNKNOWN ERROR STATUS
	XWD	$EIXXX,$EILLE	;(01) PAGE LIMIT EXCEEDED
	XWD	$EIXXX,$EIVFE	;(02) VFU FORMAT ERROR
	XWD	$EILBL,$EILBL	;(03) LABEL TYPE ERROR
	XWD	$EILBL,$EILBL	;(04) HEADER LABEL ERROR
	XWD	$EILBL,$EILBL	;(05) TRAILER LABEL ERROR
	XWD	$EILBL,$EILBL	;(06) VOLUME LABEL ERROR
	XWD	$EIDEV,$EIDEV	;(07) HARD DEVICE ERROR
	XWD	$EIDAT,$EIDAT	;(10) DATA PARITY ERROR
	XWD	$EIHWL,$EIHWL	;(11) WRITE-LOCK ERROR
	XWD	$EILBL,$EILBL	;(12) ILLEGAL POSITIONING (MTA)
	XWD	$EILBL,$EILBL	;(13) BEGINING OF TAPE (MTA)
	XWD	$EILBL,$EILBL	;(14) ILLEGAL OPERATION (MTA)
	XWD	$EILBL,$EILBL	;(15) FILE NOT FOUND (MTA)
	XWD	$EILBL,$EILBL	;(16) OPR CANCELLED VOL SWITCH REQUEST (MTA)
	XWD	$EILBL,$EILBL	;(17) TOO MANY VOLUMES (MTA)
	XWD	$EINLA,$EINLA	;(20) NETWORK LINK DOWN
	XWD	$EIXXX,$EILUC	;(21) LP20 - UNDEFINED CHAR INTERRUPT
	XWD	$EIXXX,$EIVRP	;(22) LP20 - RAM PARITY ERROR
	XWD	$EILBL,$EILBL	;(23) LABELER REQUEST ABORTED BY RESET
	XWD	$EILBL,$EILBL	;(24) VOLUME PROTECTION FAILURE
	XWD	$EILBL,$EILBL	;(25) FILE PROTECTION FAILURE
	XWD	$EILBL,$EILBL	;(26) UNEXPIRED FILE

	IOERXL==.-IOERXT	;LENGTH OF EXTENDED ERROR TRANSLATION TABLE
	END