	.TITLE	INDEX
	.IDENT	/BL2.0/
XTSIZ=24.
;
;	This is a completely rewritten version of INDEX designed
;	to word with the dynamic memory routines.
;
;	J. CLEMENT	September 1982
;
;								AZ (new)
;	NSWC Changes:						     V
;
;		15 Mar 88 - Allow use of all 256 Extended ASCII characters.
;		 5 Apr 88 - Make SETBF routine global for .TYPE, etc.
;								     ^
;								AZ (new)
; INDEX COMMAND
;
;		NOTE THAT MULTINATIONAL CHARACTERS DO NOT	; AZ 3/88
;		SORT IN ASCII ORDER--A UMLAUTs COME AFTER	; AZ 3/88
;		Zs, NOT BEFORE Bs.				; AZ 3/88
;
;	Index generates a table with the following structure
;	Word 1	- First entry
; Entry:
;	Word 1	- Next entry
;	Byte	- Status = X.ENT+subentry number
;	N bytes	- Text terminated by zero
;  .or....
;
; Entry
;	Word	- Next entry
;	byte	- Status = X.pag+(X.ch,x.spg,x.apn)	(or/and)
;	byte	- number - If(x.chp or x.apn)
;	word	- number - If(x.pag)
;	byte	- number - If(x.spg)
;	This is filled in later when the page number is determined.
;
; Fast index table
;	Word	- Next entry
;	byte	- Status = X.ent+X.pag+Subentry number
;	byte	- Letter A+^o200
;	Word	- Next entry
;	byte	- Status = X.ent+X.pag+Subentry number
;	byte	- Letter B+^o200
;		........
;	byte	- Letter Z+^o200
;	Word	- Next entry
;	byte	- Status
;	byte	- -1
;		This is used to find entries quickly and is set up
; If FASTX is defined. 
;
; LOCAL DATA
	.vars
;
;	Impure data section
;
FCHAR:	.BLKA	1		; First char
BLINK:	.BLKA	1		; Points back to last item
LINK:	.BLKA	1		; Points to current item
FLINK:	.BLKA	1		; Points to next item
STAT:	.BLKA	1		; Status byte
SUBINX:	.BLKA	1		; Current Subindex count
SUBINT:	.BLKA	1		; Total subindex count
STRADD:	.BLKA	1		; String address
SIZ=<.-BLINK>/$WORDL
ENT:	.BLKA	1		; Non zero if entry only
	.code
;
;	INDEX	- ADD INDEX ITEM TO INDEX DATA
;	AINDEX	- Autoindex by flag
;
AINDEX::TSTEQB	$INXSW,10$	; INDEXING ENABLED?
	RETURN			; NO		
10$:	CALL	BRKSV		; Save current loc. in input buffer
	INCB	RETSW		; Set up return on breakable char
	MOVB	$IFLSW,R1	; Get index flag
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	MOV	R1,R0
	ADD	#GCTABL,R0
	MOVB	(R0),-(SP)	; Save old flag
	MOVB	#GC.SPC,(R0)	; and substitute new
	CALL	SETBF		; Get index term
	MOVB	$IFLSW,R1	; Get index flag
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	MOV	R1,R0
	ADD	#GCTABL,R0
	MOVB	(SP)+,(R0)	; Restore flag
	CLRB	RETSW
	CALL	BKUP		; Back up to break
	CLRB	ENT
	BR	INDEX1
ENTRY::	MOVB	#-1,ENT
	BR	INDEX0
INDEX::	CLRB	ENT
INDEX0:	CALL	$FRCND		; FORCE TO LOGICAL END OF COMMAND
	MOVB	$SIFSW,R1	; Get subindex flag
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	MOV	R1,R0
	ADD	#GCTABL,R0
	MOVB	(R0),-(SP)	; Save old flag
	TSTNEB	$SIFSW+1,5$	; Subindex flag disabled ?
	CMPEQB	(R0),#GC.MSC,4$	; Flag not already in use ?
	CMPNEB	(R0),#GC.IFL,5$	; Flag not index flag ?
4$:	MOVB	#GC.SIX,(R0)	; and substitute new
5$:	CALL	SETBF		; Get index term
	MOVB	$SIFSW,R1	; Get subindex flag
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	MOV	R1,R0
	ADD	#GCTABL,R0
	MOVB	(SP)+,(R0)	; Restore flag
	TSTEQB	$INXSW,10$	; INDEXING ENABLED?
	RETURN			; NO		
10$:	MOV	#TTBUF,R2	; Get buffer address
	MOV	R2,R4		; Again
20$:	MOVB	(R2)+,R1	; Strip out leading blanks after subindex
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	CMPEQB	R1,#SPC,20$	; Blank ?
	TST	R1						; AZ 3/88
	BR	35$		; Save it
30$:	MOVB	(R2)+,R1	; Get char
	BIC	#^C<M$CHR>,R1					; AZ 3/88
35$:	BEQ	50$		; Done ?
	CMPNEB	R1,#SXCHR,40$	; Not Subindex flag ?
	CLRB	(R4)+		; Make flag a null
	INC	SUBINT		; Total number of subindex flags
	CMP	SUBINT,#X.SEN	; Check number
	BLT	20$		; Not too many ?
	MOV	#36.,R0		; Message number to output
	JMP	ILCMA		; too many, give error
40$:	MOVB	R1,(R4)+	; Save char
	BR	30$		; And try again
50$:	CLRB	(R4)+		; Chock it again
INDEX1:	MOV	#TTBUF,STRADD	; Clear string address
	MOVB	#X.ENT,STAT	; first entry status
	CLR	BLINK		; Clear for first time
	CLR	LINK
	CLR	FLINK
	MOV	#INXBF,R3	; Index buffer
	CALL	BEGBF		; Set to start of buffer
	CALL	GWRD		; get foreward link
	BCC	10$		; not first time for indexing
	MOV	#INXBF,R3	; Get index buffer
	CALL	CLRBF
	.if df	FASTX		; Fast indexing ??
	CLR	FCHAR						; AZ 3/88
	MOV	#$WORD2,R1	; Points to first entry
	CALL	PWRD		; Initial word
	CALL	XTSET
	.endc
	CALL	CWRD
	CALL	BEGBF		; Start at beginning again
	CALL	GWRD		; Get foreward link
10$:	MOV	R1,FLINK	; foreward link
	CALL	TSTS		; Test string
	BCS	KEEP		; New entry/ save it
	CALL	GETLNK
	MOV	#-1,STAT	; Set status			; AZ 3/88
	JMP	KEEP1
;
;	Subroutine to Keep the entry + fill in page number etc.
;
KEEP:	CLR	STAT		; Initial status		; AZ 3/88
KEEP0:	TSTNEB	@STRADD,5$	; Not null entry ?
	INC	STRADD		; Skip it
	JMP	95$		; Do not enter it
5$:	MOV	#INXBF,R3	; Get index buffer
	MOV	BLINK,R1	; Backward link
	CALL	FNDBF		; go to it
	BCC	10$
	CALL	HLTER
10$:	MOV	BF.MAX(R3),R1	; Final index
	MOV	R1,BLINK	; Now set current entry as backward link
	CALL	PWRD		; link it in
	CALL	ENDBF		; back to end buffer
	MOV	LINK,R1		; foreward link
	CALL	PWRD		; link it in
	MOV	#X.ENT,R1	; Initial status
	ADD	SUBINX,R1	; Current subindex number	
	MOV	R1,STAT		; Save				; AZ 3/88
	CALL	PBYT		; Store status
	MOV	STRADD,R2	; Entry buffer
90$:	MOVB	(R2)+,R1	; get byte
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	CALL	PBYT		; save it
	TSTNE	R1,90$		; more to come?
	MOV	R2,STRADD	; Next starting address
95$:	CMPNE	SUBINX,SUBINT,100$	; More levels ?
	JMP	KEEP1 		; Finished all levels
100$:	INC	SUBINX		; Do next level
	.if df	fastx		; Fast indexing ??
	INC	STAT		; Set to current level		; AZ 3/88
	TSTEQB	ENT,130$	; Not optimized subindex ??
	MOVB	@STRADD,R1	; First char.	
	BIC	#^C<M$CHR>,R1					; AZ 3/88
	MOV	R1,R4
;	BIC	#^C<^o177>,R4	; strip char.			; AZ 3/88 (;)
	ADD	#GCTABL,R4
	CMPNEB	(R4),#GC.LC,110$ ; Not lower case?
	SUB	#^o40,R1	; Convert to upper case
110$:	MOV	R1,FCHAR					; AZ 3/88
	MOV	BLINK,R1	; Backward link
	CALL	FNDBF		; go to it
	BCC	120$
	CALL	HLTER
120$:	MOV	LINK,FLINK	; Get current link
	MOV	BF.MAX(R3),R1	; Final index
	MOV	R1,LINK		; New Current link
	CALL	PWRD		; link it in
	CALL	ENDBF		; back to end buffer
	CALL	XTSET		; Set up table
130$:
	.endc
	JMP	KEEP0
KEEP1:	TSTEQ	STAT,110$	; No entry ?			; AZ 3/88
	TSTNEB	ENT,110$	; No page number saved ?
	CALL	LINFAK
	MOV	#INDX,R1	; Get index flag
	CALL	PBYT		; Into output buffer
	MOV	BLINK,R1	; Link
	CALL	PWRD		; Save it too
	TSTNE	BF.HED(R3),110$	; Header exists ?
	CALL	CBYT		; Chock the line
	CALL	OUTLIN		; And output it
110$:	RETURN
;
;	Subroutine to get next link
;
GETLNK:	MOV	LINK,BLINK
	MOV	FLINK,R1	; next entry
	MOV	R1,LINK		; stack the links
	BNE	10$		; no more
	SEC			; end of buffer
	RETURN
10$:	CALL	FNDBF		; find it
	BCC	20$		; OK ?
	CALL	HLTER
20$:	CALL	GWRD		; get next foreward link
	BCC	30$		; OK ?
	CALL	HLTER		; End of buffer is error
30$:	MOV	R1,FLINK	; next foreward link
	CALL	GBYT		; get status byte
	BCC	40$		; OK ?
	CALL	HLTER		; End of buffer is error
40$:	BITEQ	#X.ENT,R1,GETLNK; No entry ?
	MOV	R1,STAT		; get status			; AZ 3/88
	CLC			; Success for next entry
	RETURN
;
;	Subroutine to compare input string to table
;
TSTS:	CALL	GETLNK		; Get link and status
	BCC	1$
	RETURN			; None so save current entry
1$:	MOV	STAT,R0		; Get current status		; AZ 3/88
	BIC	#^C<X.SEN>,R0	; Get subentry number
	CMPEQ	R0,SUBINX,5$	; Not same level ?
	.if df	FASTX
	BGT	6$		; LArger
	.endc
	JMP	65$
	.if df	FASTX
6$:	BITEQ	#X.PAG,STAT,TSTS	; Not fast entry ?	; AZ 3/88
	MOV	LINK,R1
	ADD	#<XTSIZ*<$WORD2+2>>,R1	; End of table
	MOV	R1,LINK
	CALL	FNDBF
	CALL	GWRD		; Get end of table
	MOV	R1,FLINK	; Next link
	BR	TSTS
	.endc
5$:	MOV	STRADD,R2	; Input string address
10$:	CALL	GBYT		; get table entry
	MOVB	(R2)+,R0	; input string char
	BIC	#^C<M$CHR>,R0					; AZ 3/88
	BEQ	50$		; end of string?
	CMPEQ	R0,R1,10$	; same, continue		; AZ 3/88
	MOV	R1,R4
	BIC	#^C<M$CHR>,R4	; strip char.			; AZ 3/88
	ADD	#GCTABL,R4
	CMPNEB	(R4),#GC.LC,20$ ; Not lower case?
	SUB	#^o40,R1	; Convert to upper case
20$:	MOV	R0,R4
;	BIC	#^C<^o177>,R4	; strip char.			; AZ 3/88 (;)
	ADD	#GCTABL,R4
	CMPNEB	(R4),#GC.LC,30$	; Not lower case?
	SUB	#^o40,R0	; Convert to upper case
30$:	CMPEQ	R0,R1,10$	; same, continue		; AZ 3/88
	.if df	FASTX		; Fast index ??
      .if df $A256						; AZ 3/88
	BITEQ	#^x100,R1,60$					; AZ 3/88
      .endc							; AZ 3/88
      .if ndf $A256						; AZ 3/88
	TST	R1		; No fast ?
	BGE	60$		; None ?
      .endc							; AZ 3/88
	CMPEQ	R1,#^o177777,40$; Terminator ?			; AZ 3/88
	BIC	#^C<M$CHR>,R1	; Clear extra bit		; AZ 3/88
	CMPEQ	R0,R1,40$	; Correct char ?		; AZ 3/88
	BLT	80$		; Before ??
	MOV	BF.FUL(R3),FLINK	; NEXT LINK
40$:	JMP	TSTS
	.endc
	BR	60$
50$:	CMPEQ	SUBINX,SUBINT,60$ ; End of entire string ?
	TSTNE	R1,60$		; Not end of entry too ?
	INC	SUBINX		; Count it
	MOV	R2,STRADD	; Save next subentry address
	MOV	#-1,R1		; Guarantee another compare
60$:	CMP	R0,R1		; final compare			; AZ 3/88
65$:	BEQ	70$		; Ok ?
	BLT	80$		; Less than ?
	JMP	TSTS		; Input string > table entry (try again)
70$:	CLC			; Found same string
	RETURN
80$:	SEC
	RETURN
;
;
;
SETBF::	CALL	VARSAV		; Save variables		; AZ 4/88 (::)
	MOV	#BLINK,R0	; Table to clear
	MOV	#SIZ,R1		; Size of table
5$:	CLR	(R0)+		; Clear entries
	SOB	R1,5$		; Till done
	MOV	#TTBF,R3	; BUFFER TO GET TITLE
	CALL	CLRBF		; Clear the buffer
	MOV	#SW.IDS,R0	; Input disable bits
	BISB	R0,$EQFSW+1	; Disable equation mode
	BISB	R0,$IFLSW+1	; DISable index flag
	BISB	R0,$UNLSW	; Disable underlining
	BISB	R0,$OVRSW	; Disable overstriking
	BISB	R0,$AUBRK	; Disable autobreak
	BISB	R0,$TABSW	; DISABLE TABS
	BISB	R0,$ESCSW	; DISABLE ESCAPE SEQ.
	BISB	R0,$HYPSW	; Disable hyphenation
	BIS	#FILLF,F.1	; SET TO FILL (GET RID OF SPACES)
	CALL	VARSET		; Set the variables for begin line
	MOV	#100.,R0	; Max size for index terms
	CALL	CVHSP		; Convert
	MOV	R1,LINBK	; Now is max
10$:	CALL	GCIN		; READ TITLE OR SUBTITLE
	CMPNE	R1,#LF,11$	; End of line?
	CALL	BKSPI		; Backspace over LF
11$:	TST	LINBK		; Past end of line?
	BLT	15$		; No
	CMPNEB	LCH,#SPC,20$	; Last char in buffer not space?
15$:	MOV	#-1,BF.hed(R3)	; Fake header
	CALL	BKOUT		; Back up over last space
	CLR	BF.hed(R3)	; Fake header
20$:	MOV	#TTBF,R3	; Restore buffer address
	CALL	CBYT		; Insert null into title
	RETURN			;
;
;	Setup fast index table
;
	.if df	FASTX		; Fast indexing ??
XTSET:	MOV	#A,R4		; First char
	MOV	#XTSIZ,R2	; Number of entries
	BIS	#X.pag,STAT	; Setup table entry		; AZ 3/88
1$:	MOV	BF.FUL(R3),R1	; Next entry
	CMPNE	R4,FCHAR,10$	; Not first char		; AZ 3/88
	MOV	R1,BLINK	; Save backward link
10$:	ADD	#$WORD2+2,R1	; Points to next
	CALL	PWRD		; Next entry
	MOV	STAT,R1		; Get status			; AZ 3/88
	CALL	PBYT		; Set entry status
	MOV	R4,R1		; Next letter
      .if df $A256						; AZ 3/88
	BIS	#^x100,R1					; AZ 3/88
      .endc							; AZ 3/88
      .if ndf $A256						; AZ 3/88
	BIS	#^o200,R1	; Negative
      .endc							; AZ 3/88
	CALL	PBYT		; Single letter for index
	CMPNE	R4,FCHAR,20$	; Not first char		; AZ 3/88
	MOV	BF.FUL(R3),LINK	; Save backward link
20$:	INC	R4		; Next letter
	SOB	R2,1$		; Continue till done
	CMP	R4,FCHAR	; Test				; AZ 3/88
	BGT	30$		; Already taken care of ?
	MOV	BF.FUL(r3),R1	; Current address
	MOV	R1,LINK		; Current link
	SUB	#$WORD2+2,R1	; Points to previous link
	MOV	R1,BLINK	; Backwards link
30$:	MOV	FLINK,R1		; Next link
	CALL	PWRD		; Last
	MOV	STAT,R1		; Current status		; AZ 3/88
	CALL	PBYT
	MOV	#-1,R1		; Maximum char stops search
	CALL	PBYT
	RETURN
	.endc
	.END
