PROCEDURE	<IND -- handle indirect files>,010001
;+
; abstract:	IND
;
;	This module has support for the include files for
;	RUNOFF.
;
; calling sequence:
;
;	MOV	#new_file_name,R0
;	MOV	#new_file_name_length,R1
;	CALL	newfil	; open a new file
;
;	CALL	pshfil	; push current file on stack
;
;	CALL	popfil	; attempt to pop old file from
;			; stack.  If the stack is now
;			; empty, the carry bit is set.
;
; written: 24-JAN-80, -1.0.0-, Bruce C. Wright
; modified:
; verified: 24-JAN-80, -1.0.0-, Bruce C. Wright
;
; Modified: 5-Dec-80, -1.0.1-, John D. Leonard
;	Changed to allow RUNOFF to proceed after reporting error
;	on INCLUDE file open failure. Also modified error message.
;-

	.MCALL	OFID$R,OPNS$R,CLOSE$,CSI$,CSI$1,CSI$2,FDBF$R
	.GLOBL	PLIST		; In RNOERR
;
; The include file list is a singly-linked list.  Its header is
; in FILHD, and the first word of all of the entries points to
; the next entry.  There is no limit on the number of entries
; which may be allocated, except for the amount of dynamic storage
; available.  An entry represents a saved file, e. g., the current
; file does NOT have an entry in the include list.  On an end-of-
; file, the top entry in the list (which is handled as a LIFO
; list), is restored and processing continues as if no end-of-file
; had occurred.  The two reserved words in the list (as shown
; below) are not used and are not anticipated to ever be used, but
; are reserved to make the list entry exactly equal to two index
; entries without the text, hopefully reducing the fragmentation
; of the free space.  Note that the length of the allocated block
; precedes a block, so that the actual length of an allocated
; index block is 6. words rather than 5. words as used in the
; index subroutines (the sixth word is invisible to the index
; subroutines). The number of words allocated by an include entry
; is 11. in the declared part and 1. (the length word) in the
; system part, so that it is exactly equal to 12. words or two
; index entries.
;
FI.LNK	=	0		; link to next file block
FI.FID	=	FI.LNK+2	; fid of current file
FI.DEV	=	FI.FID+6	; device name of current file
FI.UNI	=	FI.DEV+2	; device unit # of current file
FI.BLK	=	FI.UNI+2	; block # of saved file
FI.BYT	=	FI.BLK+4	; byte within block
FI.LEN	=	FI.BYT+6	; *** two words reserved ***
	CODE	IND
POPFIL::
	MOV	R5,-(SP)	; save r5
	MOV	FILHD,R5	; get file list head.
	BNE	10$		; it's there -- pop files.
	MOV	(SP)+,R5	; recover R5
	SEC			; show were not able to open file.
	RETURN			; and return to the caller.
10$:	CLOSE$	#TTLDMY		; close the current file.
	BCS	FILERR		; error?
	MOV	(R5),FILHD	; indirect to next element in chain.
	MOV	FI.FID(R5),F.FNB+N.FID(R0) ; move in the fid
	MOV	FI.FID+2(R5),F.FNB+N.FID+2(R0)
	MOV	FI.FID+4(R5),F.FNB+N.FID+4(R0) ; ...
	MOV	FI.DEV(R5),F.FNB+N.DVNM(R0) ; move in the device
	MOV	FI.UNI(R5),F.FNB+N.UNIT(R0) ; move in the unit
	OFID$R	R0		; open the file by file-id
	BCS	FILERR		; error?
	MOV	R1,-(SP)	; save regs for .POINT
	MOV	R2,-(SP)	;
	MOV	R3,-(SP)	;
	MOV	FI.BLK(R5),R1	; get high order bits of block
	MOV	FI.BLK+2(R5),R2	; get low order bits of block #
	MOV	FI.BYT(R5),R3	; get the byte offset.
	CALL	.POINT		; point back into the file.
	MOV	(SP)+,R3	; Recover registers
	MOV	(SP)+,R2	; ...
	BCC	20$		; J if no errors
	CMP	F.ERR(R0),#<IE.EOF&377> ; Is it end-of-file?
	BNE	FILERR		; J if not, some other error.
	MOV	R5,R1		; Get the area to free.
	CALL	FREE		; Free it.
	MOV	(SP)+,R1	; Recover R1
	MOV	(SP)+,R5	; Recover R5
	BR	POPFIL		; And try to pop another level.
20$:	MOV	R5,R1		; remember the block address.
	CALL	FREE		; free it up.
	MOV	(SP)+,R1	; recover r1
	MOV	(SP)+,R5	; recover R5
	CLC			; show no error.
	RETURN			; and return to the caller.
FILERR:	MOV	R0,-(SP)	; save R0
	DIAG	INDERR,FCS	; it's an FCS error!
	JMP	RUNOFF		; and re-start.
PSHFIL::
	MOV	R0,-(SP)	; save registers
	MOV	R1,-(SP)	; ...
	MOV	R2,-(SP)	; ...
	MOV	R3,-(SP)	; ...
	MOV	#FI.LEN,R1	; try to pick a node.
	CALL	ALLOC		; allocate it.
	MOV	R1,-(SP)	; save it
	MOV	#TTLDMY,R0	; get input fdb
	CALL	.MARK		; mark current position.
	BCS	FILERR		; error?
	MOV	(SP)+,R0	; remember picked node.
	MOV	R1,FI.BLK(R0)	; remember high order bits of block #
	MOV	R2,FI.BLK+2(R0)	; remember lower order bits
	MOV	R3,FI.BYT(R0)	; remember current byte offset in block
	MOV	TTLDMY+F.FNB+N.FID,FI.FID(R0) ; save fid
	MOV	TTLDMY+F.FNB+N.FID+2,FI.FID+2(R0) ; ...
	MOV	TTLDMY+F.FNB+N.FID+4,FI.FID+4(R0) ; ...
	MOV	TTLDMY+F.FNB+N.DVNM,FI.DEV(R0) ; save device
	MOV	TTLDMY+F.FNB+N.UNIT,FI.UNI(R0) ; and unit
	MOV	FILHD,FI.LNK(R0) ; link into the chain.
	MOV	R0,FILHD	; and remember the current one.
	CLOSE$	#TTLDMY		; close the file.
	BCS	FILERR		; error?
	MOV	(SP)+,R3	; recover registers
	MOV	(SP)+,R2	; ...
	MOV	(SP)+,R1	; ...
	MOV	(SP)+,R0	; ...
	RETURN			; and return to the caller.
NEWFIL::
	MOV	R2,-(SP)	; save R2
	MOV	R0,-(SP)	; Save R0
	MOV	R0,R2		; remember file name pointer.
	CSI$1	#CSIBLK,R2,R1	; perform preliminary parse.
	BCS	SYNERR		; syntax error?
	BITB	#CS.EQU,CSIBLK+C.STAT ; is there an = here?
	BNE	SYNERR		; yes, error.
	CSI$2	R0,OUTPUT	; get a file name.
	BCS	SYNERR		; syntax error?
	BITB	#CS.EQU!CS.WLD!CS.MOR,CSIBLK+C.STAT ; bad things set?
	BNE	SYNERR		; yes, error.

	.IF DF	I$$AS!R$$11D

	FDBF$R	#TTLDMY,,,#2,#FD.RAH ; Say we want multi-buffering

	.ENDC

	.IF DF	R$$11M!R$$STS

	FDBF$R	#TTLDMY,,,#1	; Say no multi-buffering

	.ENDC

	OPNS$R	R0,,#CSIBLK+C.DSDS ; open the file.
	.IF	NDF	A$$RAP
	BCS	FILERR		; error?
	.IFF
	BCC	100$		; No error
	MOV	R1,PLIST+2	; Report error and file name
	MOV	(SP),PLIST+4	;
	MOV	R0,-(SP)	; Save FDB address for error processing
	DIAG	IFOERR,FCS	; Include file open error
	TST	(SP)+		; Clear stack
	CALL	POPFIL		; get back to original level
100$:
	.ENDC
	MOV	(SP)+,R0	; Recover R0
	MOV	(SP)+,R2	; recover R2
	RETURN			; and return to the caller.
SYNERR:	MOV	R0,-(SP)	; save FDB address.
	DIAG	MGCDME,FCS	; report syntax error.
	JMP	RUNOFF		; and restart program.
	DATA	INDD
FILHD::	.WORD	0
	CSI$
CSIBLK:	.BLKB	C.SIZE
	.END
