	.title	RNODYN
	.ident	'BL3.0'
	.if ndf	$VMS
	.if ndf	RT11
	.MCALL	EXTK$S
	.ENDC
	.ENDC
;
;	The symbol $DEBUG is enabled for complte dynamic subroutine checking
; It is off for normal operation since it slows down the routines.
;$DEBUG=1
;
;	The following routines are designed to handle buffers in dynamic
; pool memory. The data should be accessed via these routines. The offset
; BF.FUL is the index to your data bytes. The BF.ADD always points to the
; current byte (one accessed last by GBYT or PBYT). All data in buffers should
; be accessed via these routines. BEGBF sets pointers to beginning of buffer.
; FNDBF sets to specified byte so you may use GBYT or GWRD to get the data. You
; may access the current byte via the offset BF.ADD,when BF.FUL is non zero,
; but no other bytes
; may be accessed directly. The routine RSTBF, and ENDBF set the index and then
; set up the buffers for input via PBYT,PWRD. After BEGBF,FNDBF reading past 
; past the end of the data is inhibited. If CARRY is set the routine failed.
; CLRBF resets all pointers, deallocates all dynamic memory and sets the
; buffer chain ready for output.  GBYT always returns an error if at end of
; buffer chain.  PBYT causes a fatal error if you attempt to write
; past the end of the chain while in input mode.
; In essence this is similar to reading and writing a sequential file with
; a record size of 1 byte.  The functions are:
;	GBYT,GWRD	Read a record during input mode
;	PBYT,PWRD	Write input or output mode
;	CBYT,CWRD	Write zero
;	BEGBF		Rewind set input mode
;	ENDBF		Find end of file and set output mode (append)
;	FNDBF		Find arbitrary record set input mode
;	RSTBF		Find arbitrary record, truncate file, set output mode
;
;	Registers:
;		R3	= buffer header
;		R1	= data
;		R0	destroyed
;
;	GBYT1,GBYT2	R1,R2 = buffer header
;
;	The buffer chain is a doubly linked list of buffers
;	With a foreward link, and backward link.
;	The last buffer has link=0
;
	.if ndf	$VMS
BFSIZ	= 200		; 128. BYTES OF DATA (MUST BE POWER OF 2)
	.endc
	.if df	$VMS
BFSIZ	= ^o100000
	.endc
;
;		R3=BUFFER HEADER
;		R1=DATA BYTE TO PUT/GET/FIND
;		R0=DESTROYED BY THESE ROUTINES
;
;	ROUTINE TO CLEAR BUFFER FOR MORE DATA
;		EXTRA BUFFERS ARE RETURNED TO POOL
;
	.code
CLRBF::	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	MOV	#BFSIZ,(R3) 	; SET UP COUNT
	CMPNE	R3,BUFADD,10$	; Not primary input buffer?
	MOV	#IBFSZ,(r3)	; Set to input buffer size
10$:	CLR	BF.FUL(R3)	; RESET INDEX
	CLR	BF.MAX(R3)	; RESET DATA RESIDENT
	CLR	BF.SPC(R3)	; clear spacing char count
	CLR	BF.VSP(R3)	; Clear vertical spacing
	CLR	BF.HED(R3)	; Clear header
	MOV	BF.BEG(R3),R0	; GET HEAD OF CURRENT BUFFER CHAIN
	MOV	R0,BF.CAD(R3)	; INTO CURRENT BUFFER ADDRESS
	MOV	R0,BF.ADD(R3)	; INTO DATA ADDRESS
	ADD	#BFLNK,BF.ADD(R3)	; POINTS TO FIRST BYTE-1
RETBF:	MOV	BF.CAD(R3),R0	; Current buffer
	TSTEQ	(R0),10$	; No more in chain ?
5$:	TSTEQ	(R0),6$		; At end of chain
	MOV	(R0),R0		; Next entry
	BR	5$
6$:	MOV	LNKHD,(R0)	; ADD BUFFER POOL TO END OF CHAIN
	MOV	@BF.CAD(R3),LNKHD	; PUT COMPLETE CHAIN INTO POOL
	CLR	@BF.CAD(R3)		; AND NO FOREWARD LINK
10$:	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	CLR	R1
	RETURN
;
; RSTBF
;	ROUTINE TO SET REQUESTED LOCATION AS END OF BUFFER READY FOR INPUT
;
; ENDBF
;	SET TO END OF BUFFER + MADE READY FOR PUTTING TO BUFFER
;	Both of these routines return excess buffers to the pool
;
ENDBF::	MOV	BF.MAX(R3),R1	; LOCATION TO GO TO
	BNE	RSTBF		; Not zero ?
	MOV	BF.FUL(r3),R1	; Current location
RSTBF::	CALL	FNDBF		; GO TO IT
	BCC	10$		; OK ?
	JMP	HLTER		; NO !!!!!
10$:	CLR	BF.MAX(R3)	; CLEAR DATA MAX
	MOV	#BFSIZ,(R3) 	; BUFFER SIZE
	CMPNE	R3,BUFADD,20$	; Not input buffer ?
	MOV	#IBFSZ,(R3)	; Input buffer size
20$:	SUB	R1,(R3)		; ADJUST COUNT TO BUFFER SIZE
	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	BR	RETBF
;
;	GETS NEXT BYTE FROM BUFFER
;		R1=data
;		C	= set if no data available
;		Z	= set if R1 is zero
;		N	= set if Byte R1 is negative
;		V	= undefined
;
GBYT2::	MOV	R2,R1		; Address of header
	BR	GBYT1
GBYT::	MOV	R3,R1		; FOR GBYT1
;
;	SPECIAL PURPOSE ROUTINE 
;		R1=HEADER (INPUT)
;		R1=DATA BYTE (OUTPUT)
;
GBYT1::	.if DF	$DEBUG
	MOV	R3,-(SP)	; *** DEBUG
	MOV	R1,R3		; *** DEBUG
	CALL	TEST		; *** DEBUG
	MOV	(SP)+,R3	; *** DEBUG
	.ENDC
	TSTEQ	BF.MAX(R1),40$	; Bad get ??
	DEC	(R1)+		; DECREMENT COUNT
	BLT	20$		; Nothing in buffer ?
	INC	(R1)+		; INCREMENT INDEX
	INC	(R1)		; NEXT BYTE
	MOVB	@(R1),R1	; GET BYTE
	CLC
	RETURN
20$:	INC	-(R1)		; Restore count to zero
	BLT	50$		; Bad CNT
	CMPEQ	BF.FUL(R1),BF.MAX(R1),40$; End of buffers ?
	BHI	50$		; ERROR ?????
	MOV	BF.CAD(R1),R0	; GET CURRENT BUFFER
	MOV	(R0),R0		; GET NEXT BUFFER IN CHAIN
	BEQ	50$		; NONE ??
	MOV	BF.MAX(R1),(R1)	; NUMBER OF BYTES TOTAL
	SUB	BF.FUL(R1),(R1)	; LESS INDEX=REMAINING
	CMP	(R1),#BFSIZ	; IS IT OK
	BLOS	30$		; YES
	MOV	#BFSIZ,(R1)	; NO, MAKE IT FULL BUFFER SIZE
30$:	MOV	R0,BF.CAD(R1)	; NEW CURRENT BUFFER
	ADD	#BFLNK,R0		; POINTS TO BYTE IN FRONT OF FIRST
	MOV	R0,BF.ADD(R1)	; SAVE ADDRESS
	BR	GBYT1		; AND GET THE BYTE FINALLY
40$:	.if DF	$DEBUG
	MOV	R3,-(SP)	; *** DEBUG
	MOV	R1,R3		; *** DEBUG
	CALL	TEST		; *** DEBUG
	MOV	(SP)+,R3	; *** DEBUG
	.ENDC
	CLR	R1
	SEC
	RETURN
50$:	CALL	HLTER		; bad count

;
;	PBYT - Puts next byte into buffer
;	CBYT - Clears next byte in buffer
;
CBYT::	CLR	R1
PBYT::	MOV	R3,R0		; BUFFER HEADER
	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	DEC	(R0)+		; DECREMENT REMAINDER COUNT
	BLT	10$		; YES, TRY TO ALLOCATE ANOTHER
	INC	(R0)+		; INCREMENT INDEX
	INC	(R0)		; INCREMENT ADDRESS
	MOVB	R1,@(R0)	; SAVE BYTE
	CLC
	RETURN
10$:	TSTEQ	BF.FUL(R3),11$	; Zero ??
	BITEQ	#BFSIZ-1,BF.FUL(R3),15$ ; legal end of buffer?
11$:	CALL	HLTER		; NO NO NO
15$:	CMPEQ	R3,BUFADD,11$	; Input buffer ??
	MOV	BF.CAD(R3),R0	; CURRENT ADDRESS
	MOV	(R0),R0		; ANOTHER IN CHAIN?
	BNE	20$		; YES, USE IT
	MOV	LNKHD,R0	; GET BUFFER FROM POOL?
	BEQ	30$		; NONE!
	MOV	(R0),LNKHD	; REMOVE IT FROM POOL
	CLR	(R0)		; NO FOREWARD LINK
	MOV	BF.CAD(R3),2(R0) ; BACKWARD LINK
	MOV	R0,@BF.CAD(R3)	; FOREWARD LINK
20$:	MOV	R0,BF.CAD(R3)	; NEW CURRENT BUFFER
	ADD	#BFLNK,R0	; POINTS TO BYTE IN FRONT OF FIRST
	MOV	R0,BF.ADD(R3)	; SAVE ADDRESS
	MOV	#BFSIZ,(R3)	; NEW COUNT
	MOV	BF.MAX(r3),R0	; Get max count
	BEQ	PBYT		; Output buffer ?
	SUB	BF.FUL(R3),R0	; Subtract current
	CMP	R0,#BFSIZ	; Check if smaller
	BLT	25$		; Smaller ?
	JMP	PBYT
25$:	MOV	R0,(R3)		; New count
	BR	PBYT		; AND GET THE BYTE FINALLY
30$:	.if ndf	RT11
	.if ndf	$VMS
	CALL	EXTEND		; try to extend memory
	BCC	10$		; success
	.ENDC
	.ENDC
	MOV	#12.,R0		; No more memory avilable message
	JMP	ILINP		; KILL KILL KILL
;
;	ROUTINE GETS 1 WORD FROM BUFFERS
;		R1=data
;		C	= set if no data
;		N,Z	correspond to value in R1
;
GWRD::	CALL	GBYT		; GET LOWER BYTE
	MOV	R1,-(SP)	; SAVE IT
	CALL	GBYT		; NEXT UPPER
	MOVB	R1,1(SP)
	MOV	(SP)+,R1	; GET RESULT
	RETURN
;
;	PWRD - Save 1 word in buffer
;	CWRD - Clear 1 word in buffer
;
CWRD::	CLR	R1
PWRD::	MOV	R1,-(SP)	; Save word
	CALL	PBYT		; SAVE LOWER BYTE
	MOVB	1(SP),R1	; Get upper byte
	CALL	PBYT		; SAVE UPPER
	MOV	(SP)+,R1	; Get word again
	RETURN
;
;	extend the available pool
;
	.if ndf	$VMS
	.if ndf	RT11
EXTEND:	EXTK$S	#5
	BCC	10$
	RETURN
10$:	ADD	#500,XTOP	; readjust top for extend
	.endc
	.endc
;
;	subroutine to set up linked list of dynamic buffers
;
LNKSET::	.if ndf	$VMS
	MOV	XBOT,R0		; save value
	ADD	#BFSIZ+6,XBOT	; raise bottom
	BCS	40$		; done
	CMP	XBOT,XTOP	; too big
	BHIS	40$		; yes
	MOV	LNKHD,(R0)	; Save current linked buffer chain
	CLR	2(R0)		; No backward link
	MOV	R0,LNKHD	; put current buffer at head
	BR	LNKSET		; try another
40$:	SUB	#BFSIZ+6,XBOT	; restore
	.endc
	CLC
	RETURN

;
;	ROUTINE SETS POINTER TO START OF BUFFER FOR GETTING DATA
;		IF BUFFER HAS NO DATA MAX SET, MAX=CURRENT INDEX
;
BEGBF::	CLR	R1
;
;	SETS POINTERS TO BUFFER LOCATION SPECIFIED IN R1
;		C	SET if bad location specified
;		C	CLEAR if good location
;		IF MAX IS NOT SET	MAX=CURRENT INDEX
;	To get the data GBYT or GWRD must be called
;	BF.ADD does not necessarily point to correct data
;
FNDBF::	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	TSTNE	BF.MAX(R3),1$	; Currently input ?
	MOV	BF.FUL(R3),BF.MAX(R3) ; Reset max so now input
1$:	CMP	R1,BF.MAX(R3)	; GREATER THAN CURRENT
	BLOS	5$		; NO
	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	CLR	R1
	SEC
	RETURN			; RETURN NO ACTION
5$:	CMPNE	R3,BUFADD,10$	; Not primary input buffer?
;
;	Section for input buffer only
;
	MOV	BF.MAX(R3),(R3) ; MAX SIZE
	SUB	R1,(R3)	; NOW REMAINING SIZE
	MOV	BF.CAD(R3),R0	; START OF BUFFER
	ADD	#BFLNK,R0	; POINTS TO DATA-1
	ADD	R1,R0		; CURRENT ADDRESS
	MOV	R0,BF.ADD(R3)	; Saved
	MOV	R1,BF.FUL(R3)	; NEW LOCATION
	BR	90$
;
;	Section for all other buffers
;
10$:	MOV	R2,-(SP)	; Save
	CMP	R1,#BFSIZ	; Compare with buffer size
	BGT	20$		; Not first buffer ?
	MOV	BF.BEG(R3),R0	; Start at first
	CLR	R2		; zero = base
	BR	60$
20$:	MOV	BF.ADD(R3),R0	; current address
	SUB	BF.CAD(R3),R0	; minus cuurrent buffer address
	SUB	#BFLNK,R0	; minus header offset=bytes this buff.
	MOV	BF.FUL(R3),R2
	SUB	R0,R2		; now set index to start of buffer
	MOV	BF.CAD(R3),R0	; CURRENT BUFFER
	CMP	R1,R2		; go foreward?
	BHI	40$		; yes
30$:	MOV	2(R0),R0	; GO BACK 1 BUFFER
	BNE	35$		; OK ?
	CALL	HLTER
35$:	SUB	#BFSIZ,R2
	CMP	R1,R2		; add on buffer size
	BLOS	30$		; NOT THERE YET
	BR	60$		; FOUND CORRECT ONE
40$:	ADD	#BFSIZ,R2
	CMP	R1,R2		; add on buffer size
	BLOS	50$		; yes
	MOV	(R0),R0		; GO FOREWARD
	BNE	40$		; OK ?
	CALL	HLTER		; ERROR ***
50$:	SUB	#BFSIZ,R2; ADJUST TO POSITIVE
60$:	MOV	R1,BF.FUL(R3)	; Final position
	MOV	R0,BF.CAD(R3)	; SAVE CURRENT BUFFER
	SUB	R2,R1		; Current cnt
	ADD	R1,R0		; ALMOST CURRENT DAT
	ADD	#BFLNK,R0	; DATA -1
	MOV	R0,BF.ADD(R3)	; SAVED
	MOV	BF.MAX(R3),R2	; Max bytest
	SUB	BF.FUL(r3),R2	; Count
	MOV	R2,(R3)		; Possible count
	MOV	#BFSIZ,R0	; BUFFER SIZE
	SUB	R1,R0		; - OFFSET = COUNT
	CMP	R0,R2		; Compare
	BGE	80$		; Too big ?
	MOV	R0,(R3)		; SMALLER ONE
80$:	MOV	(SP)+,R2
90$:	.if DF	$DEBUG
	CALL	TEST		; *** DEBUG
	.ENDC
	CLC			; Success !!
	RETURN
;
;	GET TEMPORARY BUFFER
;
;		R2= current buffer
;		R3= temporary buffer address
;
GETTBF::MOV	#TMPBF,R3	; Temporary buffer address
SAVTBF::MOV	R3,-(SP)	; Save R3
	MOV	R2,R0		; Will be input
	MOV	#<BF.VSP>/2+1,R1	; Number of words
10$:	MOV	(R0)+,(R3)+	; transfer
	SOB	R1,10$		; Till done
	MOV	(SP)+,R3	; Restore buffer address
	CLC
	RETURN
;
;	CALL	TMPIN
;	Set up input from temporary buffer
;		INPUT:	R2	= String address
;		OUTPUT:		= Last byte address in string+1
;		R0,R1	are destroyed
;	CALL	TMPINB
;		INPUT:	R2	= Buffer header
;
;	CALL	PSHINS	- Set up for next input stack entry
;		OUTPUT:	R3	= input buffer header formed on return
;	CALL	POPINS	- Go back 1 level in input stack
;
PSHINS::MOVB	SUBSTK,R0	; Get stack pointer
	CMPEQB	R0,SUBSTK+1,20$	; Is it too big ?
	MOV	R2,-(SP)	; Save R2
	MOV	#SUBF0,R2	; Lowest header
	TSTEQ	R0,2$
	MOV	BUFADD(R0),R2	; Previous header
2$:	ADD	#2,R0		; Add 2
	MOVB	R0,SUBSTK	; New stack
	MOV	BUFADD(R0),R3	; Get current buffer header
	MOV	R3,BUFAD	; Save it
	CALL	SAVTBF		; Make current same
	MOV	(SP)+,R2	; Restore
10$:	RETURN
20$:	CALL	HLTER
POPINS::MOVB	SUBSTK,R0	; Get stack pointer
	BEQ	20$		; Already at end ?
	SUB	#2,R0		; Backup 1 level
	MOVB	R0,SUBSTK	; New stack
	MOV	BUFADD(R0),BUFAD; Get current buffer header
10$:	RETURN
20$:	CALL	HLTER
TMPINB::MOV	#-1,R1		; Indicate buffer header
	BR	TMPIN1
TMPIN::	CLR	R1		; Indicates R2=string
TMPIN1:	MOV	R3,-(SP)	; Save R3
	MOV	R1,-(SP)	; Save R1
	CALL	SETINS		; Start temp input
	TSTEQ	(SP)+,10$	; String input ??
5$:	CALL	GBYT2		; Get byte
	BLOS	20$		; Done ?
	CALL	PBYT		; Save it
	BR	5$		; Continue till done
10$:	MOVB	(R2)+,R1	; Get 1 byte
	BEQ	20$		; At end of buffer ?
	CALL	PBYT		; Save it
	BR	10$
20$:	MOVB	#LF,R1		; Put line feed
	CALL	PBYT		; Into buffer
	MOV	BF.SPC(R3),R1	; Back to start of line
	CALL	FNDBF		; Set for reading buffer
	MOV	(SP)+,R3	; Restore
	CLC
	RETURN
;
;	Setup a temporary input buffer to simulate input.
;	This is used to bring in headers, numbers etc.
;	OUTPUT:	R3=temporary input buffer
;		note: input must be terminated by #LF or null
;
SETINS::CALL	PSHINS
	CALL	ENDBF		; go to end of buffer
	CALL	CWRD		; Chock buffer
	MOV	BF.FUL(R3),BF.SPC(R3)	; For traceback
	RETURN
;
;	This checks the integrity of the buffer chain
;	The stack contains the offset of the bad param
;
	.if DF	$DEBUG
TEST:	MOV	R0,-(SP)	; Save R0
	MOV	R1,-(SP)
	MOV	R2,-(SP)
	MOV	#BF.CAD,-(SP)
	MOV	#BFSIZ,R1
	CMPNE	R3,BUFADD,1$	; Not Input buffer ?
	MOV	#IBFSZ,R1	; Buffer size
	TSTNE	@BF.CAD(R3),10$	; Not only one in chain ?
1$:	MOV	BF.ADD(r3),R2
	SUB	BF.CAD(r3),R2
	SUB	#BFLNK,R2	; Now have count again
	MOV	R1,R0		; Save it
	SUB	R2,R0		; Same as BF.CNT
	TSTEQ	BF.MAX(R3),5$	; Output ?
	MOV	#BF.FUL,(SP)
	CMP	BF.FUL(R3),BF.MAX(R3)
	BHI	10$		; Not correct ?
	MOV	BF.MAX(R3),R1	; Last
	SUB	BF.FUL(R3),R1
	CMP	R1,R0		; Which is bigger ?
	BGE	5$
	MOV	R1,R0
5$:	MOV	#BF.CNT,(SP)
	CMPEQ	(R3),R0,7$; correct ?
	TSTNE	BF.MAX(R3),10$	; Not output ?
	TSTNE	(r3),10$	; Also not input ?
;		Check whole string
7$:	CLR	R1		; Backward link
	MOV	BF.BEG(R3),R0	; CHeck entire chain
	MOV	#BF.BEG,(SP)
8$:	CMPNE	2(R0),R1,10$	; Backward wrong ?
	MOV	R0,R1
	CMPNE	R0,BF.CAD(R3),18$	; Not current buffer ?
	MOV	#BF.FUL,(SP)
	CMPNE	R2,BF.FUL(R3),10$	; BAD ?
	MOV	#BF.BEG+100000,(SP)
18$:	ADD	#BFSIZ,R2	; add on next size
	MOV	(R0),R0		; Next in chain
	BNE	8$		; End of chain ??
;		CHeck if BF.CAD is in chain
9$:	TST	(SP)
	BGE	10$		; BF.CAD no in chain
	TST	(SP)+
	MOV	(SP)+,R2
	MOV	(SP)+,R1
	MOV	(SP)+,R0	; restore
	return
10$:	CALL	HLTER
	.ENDC
;
; The input file is the exception to the buffer access rules.
; Since it is never extended it may be accessed directly.
;
BFLNK==3				; Offset from buffer to data-1
;
;	Macro to create buffer header with data area (sub-buffer)
;
	.const
;
;	Input buffer stack table
;
BUFADD::.WORDA	IBUF1		; POINTS TO INPUT HEADER
	.WORDA	SUBF1
	.WORDA	SUBF2
	.WORDA	SUBF3
	.WORDA	SUBF4
	.WORDA	SUBF5
	.WORDA	SUBF6 ; subst. buffers
;
;	Variables used by this routine
;
	.vars
	.MACRO	BUFF,SIZE
	.WORDA	SIZE		; BF.CNT
	.WORDA	0		; BF.FUL
	.WORDA	10$+BFLNK	; BF.ADD
	.WORDA	10$		; BF.CAD
	.WORDA	10$		; BF.BEG
	.WORDA	0		; 
	.BLKA	4		; BF.MAX,SPC,HED,VSP
10$:	.BLKA	2		; buffer foreward/backward links
	.BLKB	SIZE		; data area
	.ENDM
;
;	extra header macro (no data area)
;
	.MACRO	BUFFHD,ADD
	.WORDA	0		; BF.CNT
	.WORDA	0		; BF.FUL
	.WORDA	ADD+BFLNK	; BF.ADD
	.WORDA	ADD		; BF.CAD
	.WORDA	ADD		; BF.BEG
	.WORDA	0		; 
	.BLKA	4		; BF.MAX,SPC,HED,VSP
	.ENDM
;
;	BUFFER DEFINITIONS
;		Each buffer consists of a header and a string of
;	sub-buffers each of uniform size.  While a buffer is being filled
;	sub-buffers are automatically added as needed from the pool.
;	If FNDBF or BEGBF are called then BF.MAX is generated and this
;	serves as a limit on adding more data, or reading past BF.MAX.
;	CLRBF and ENDBF reset BF.MAX so more data may be added.
;	Each sub-buffer consists of a Foreward link, backward link,
;	and data area.
;
BF.CNT==0			; Count of char remaining in sub-buffer
BF.FUL==1*$WORDL		; Index to current location in buffer chain
BF.ADD==2*$WORDL		; Current char address
BF.CAD==3*$WORDL		; Current sub-BUFFER address
BF.BEG==4*$WORDL		; First sub-BUFFER address

BF.MAX==5*$WORDL		; MAX # characters (all sub-buffers)
				; = 0 if currently at end + output allowed
BF.SPC==6*$WORDL		; Spacing chars (current line, or traceback)
BF.HED==7*$WORDL		; Header (begins current line, or traceback)
BF.VSP==8.*$WORDL		; Vertical spacing (all lines, or traceback)
;				; Traceback info is for input buffers only
;
;	THE ACTUAL DATA BUFFER HAS THE FOLLOWING FORMAT
;		WORD 1=	FOREWARD LINK
;		WORD 2= BACKWARD LINK
;		3 - N = N-4 BYTES OF DATA
;
;
;	TEXT BUFFER HEADER (PRECEEDS TEXT) TEXT TERMINATED BY A NULL
;		APPLIES TO FOOTNOTE + SECONDARY BUFFERS
;
; BYTE	0	LINE SKIP COUNT
;	1	FLAGS 1=CHANGE BAR
;	2	LEFT MARGIN SPACING
;	3	SPACES/EXPANDABLE SPACE
;	4	EXPANDABLE SPACES TO LEFT
;	5	LEFT/RIGHT INDICATOR
;

;
;	IMPURE DATA STORAGE FOR INPUT BUFFERS
;
SUBLEV==3			; Maximum number of substitutions
BUFAD::	.WORDA	IBUF1		; Current buffer pointer
SUBSTK:: .BYTE	0,SUBLEV*2	; current substitute pointer,max
;
;	Input buffer (contains 1 line only)
;
IBUF1::	BUFF	IBFSZ+4
;
;	substitution buffer headers
;
SUBF0::	BUFFHD	SUBBUF
SUBF1:	BUFFHD	SUBBUF
SUBF2:	BUFFHD	SUBBUF
SUBF3:	BUFFHD	SUBBUF
SUBF4:	BUFFHD	SUBBUF
SUBF5:	BUFFHD	SUBBUF
SUBF6:	BUFFHD	SUBBUF
SUBBUF:	.BLKB	BFSIZ+4		; Data for substitutions buffers
;
;	dynamic memory control locations
;
XBOT::	.BLKA	1		; BEGINNING OF ALLOCATED INDEX AREA
XTOP::	.BLKA	1		; HIGHEST VIRTUAL ADDRESS IN PROGRAM
LNKHD::	.BLKA	2		; POOL BUFFERS HEADER
;
;	Footnote buffer
;
FOTBF::	BUFF	BFSIZ
;
;	Deferred text buffer
;
TXDBF::	BUFF	BFSIZ
;
;	IF command buffer
;
IFBF::	BUFF	BFSIZ
;
;	Index entry buffer
;
INXBF::	BUFF	BFSIZ
;
;	Command line input buffer/ message buffer/ general format buffer
;		This buffer may be used freely as scratch storage
;
TTLIN==BFSIZ
TTBF::	BUFF	0		; Input buffer header
TTBUF::	.BLKB	BFSIZ+$WORDL	; COMMAND LINE INPUT BUFFER (82 bytes or more)
;
;	Final output buffer 
;
	.if ndf	RT11
	.WORDA	0
HFOUT::	.WORDA	OBFSZ
	.worda	0
	.worda	0				
OUBUF::	.BLKB	OBFSZ
	.endc
;
;	Escape sequence table
;
ESCBF::	BUFF	BFSIZ
;
;	Secondary text buffer
;
TX2BF::	BUFF	BFSIZ
;
;	Temporary buffers just a header/ no buffer
;
TMPBF:	BUFFHD	0
;
;	Title buffers
;
TTLBF::	BUFF	BFSIZ
;
;	Subtitle buffer
;
STLBF::	BUFF	BFSIZ
;
;	Tabulation buffer
;
TABBF::	BUFF	BFSIZ
;
;	Backspace buffer
;		This buffer contains a line with spaces and underline chars.
;	for underlining if not doing it by backspace.
;
ULNMAX:: .WORDA	0		; MAX NUMBER OF CHARS IN BUFFER
UBUFF::	.BLKB	ULNSZ+$WORDL
;
;	Traceback buffer
;		Format:
;		Address of current line number, followed by string
;		1 word line number
;		String-file-name
;		1 zero byte
;		Line number + string occupies <TRCLN> bytes
;
	.if  DF RT11
TRCBUF::.BLKA	1		; CURRENT BUFFER ADDRESS
	.BLKA	1		; LINE NUMBER
	.ASCIZ	"Main File"	; FILE NAME
	.blkb	TRCLN-12.	; COMPLETE FIRST BUFFER
	.BLKB	6*TRCLN		; UP TO 6 NESTED .REQ FILES
	.endc
	.if ndf	RT11
TRCBUF::.BLKB	<6*TRCLN>+$WORDL
	.ENDC
	.END
