.TITLE INDEX .IDENT /M3.0/ ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ;* * ;* General permission to copy (but not for profit) is hereby * ;* granted, provided that reference is made to the fact that * ;* reproduction privileges were granted by DECUS. * ;* * ;* The information in this document is subject to change with- * ;* out notice and should not be construed as a commitment by * ;* the contributor(s), DECUS or Digital Equipment Corporation. * ;* * ;* These parties make no warranty as to the suitability of this * ;* material for use by the recipient, nor as to the accuracy or * ;* functioning of the software or related material, and no * ;* responsibility is assumed in connection therewith. * ;* * ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; INDEX COMMAND ; ; AUTHOR: L. WADE 1-JUN-72 ; ; MODIFIED BY: ; ; E. POLLACK U. OF W. 19-DEC-73 ; ; D. N. CUTLER 27-JUL-75 ; ; C. H. Spalding, Unimation, Apr. '83 ; ; MODIFICATIONS ; ; chs21a Fix bug: Entry longer than buffer length overwrote code ; chs21b Fix bug: Entries of "a", then "A", and then "a" gave 3 entries ; chs21c Code cleanup ; chs21d Ignore repeat entries on same page ; chs51a Add ENTRY ; chs51b Add subindexing ; chs51d Correct ordering of subindex entries ; chs52 Fix processing of underlined entries ; chs65 Ignore spec. chars. while ordering index ; chs78 Add text queue ; chs82 Add Table of Contents ; chs83 Add AUTOCONTENTS ; chs88c Add ENABLE/DISABLE INDEX ; chs88d Add ENABLE/DISABLE CONTENTS ; ; LOCAL DATA ; ; Index flags IDXCF: .BLKW 1 ;CASE DIFFERENCE FLAG IDXRF: .BLKW 1 ;REPEATED ITEM FLAG ICBUF: .BLKB 72. ;INDEX ITEM BUFFER ;chs ICBFE=.-2 .IIF NZ XENTRY, IDXPAG: .BLKW 1 ;BUFFER FOR REFERENCE PAGE NUMBER ;chs51a ; DATA STRUCTURE: ; ; Header layout for index entry is equivalent to: ; ; .WORD ; .WORD ; .WORD ; .WORD ; .WORD ; (high byte = -1 if low byte is chapter number) ; .ASCIZ ; (not present if repeated item) ; .EVEN ; Table of Contents routines ;chs82+ ; The table of contents (TOC) is stored as separate linked lists ; in the index buffer along with the normal index. TOC entries ; have the following formats: ; ; ; ; The level number is "0" for all entries created by the CONTENTS ; command. For entries created by the autocontents feature, it is the ; current header level plus 1 (i.e., chapter => 1, "HL 1" => 2, etc.) ; CONTENTS command .IF NZ TBLCON TOCCMD::CALL (R4) ;GET TABLE NUMBER MOV #1,R3 ;DEFAULT TO "TABLE OF CONTENTS" TST R3 ;VALUE MUST BE .GT. 0... BGT 20$ 10$: JMP ILCM ; PARAMETER ERROR 20$: CMP R3,#TBLCON ;...AND .LE. MAX. BGT 10$ CALL SKPSEP ;SKIP TO TEXT ARGUMENT MOVB R1,GCSCH ;SAVE BREAK CHARACTER FOR REREAD TOCMD1::CLR R1 ;PASS LEVEL NUMBER .IF NZ ATOTOC ;chs83+ BR TOCGO ;PROCESS TEXT AS INDEX ENTRY ; Routine to process automatic contents entries for APPENDIX, ; CHAPTER, HEADER LEVEL and DO INDEX commands ; ; TOC entries for chapters, header levels, etc. are to be output ; verbatim, except that the first space is to be stretched as ; required to align the left edge of the text at each level. ; TOCPAD are buffers used to store the respective indents. HDRTOC::MOV HDRLVL,R1 ;GET CURRENT LEVEL MOV SDINP+2,R2 ;GET POINTER TO END OF LEVEL # TEXT SUB #SDBUF-1,R2 ;CALCULATE STRING LENGTH ; (CONSIDER 2 QTS'S IN BUFFER) CMPB R2,TOCIND(R1) ;LONGER THAN ANY PREVIOUS? BLE 20$ ; NO, SKIP MOVB R2,TOCIND(R1) ; YES, STORE NEW LENGTH 20$: CMP HDRLVL,#2 ;HEADING LEVEL 3, 4, OR 5? BGT 30$ ; YES, SKIP CALL SHFUC ;SHIFT TO UPPERCASE AS FOR HEADING LINE 30$: INC R1 ;CONVERT TO INTERNAL VALUE MOV #1,R3 ;SIGNAL "CONTENTS" TABLE COMB $SDISW ;DIRECT INPUT FROM SEC. BUFFER .ENDC ; NZ ATOTOC ;chs83- ; Local routine to allocate and fill TOC record ; On entry: R1 = Level number for indent control (0 => no indent) ; R3 = Index of TOC table being built TOCGO: MOV #ICBUF,R0 ;POINT TO TEMP. INDEX BUFFER MOVB R1,(R0)+ ;STORE LEVEL NUMBER MOV #,R2 ;SET MAX. BUFFER LENGTH 10$: CALL GCIN ;GET NEXT CHARACTER CMPEQB #CR,R1,20$ ;SKIP IF AT END OF LINE MOVB R1,(R0)+ ;PUT CHARACTER IN BUFFER SOB R2,10$ ;LOOP UNTIL BUFFER FULL 20$: .IIF NZ ENATOC, TSTEQB $TOCSW,80$ ;SKIP IF CONTENTS DISABLED ;chs88d CLRB (R0)+ ;MARK END OF STRING CLRB (R0)+ ;MAKE SURE LENGTH BIC #1,R0 ; IS EVEN SUB #ICBUF,R0 ;CALCULATE STRING LENGTH MOV R0,S1 ;STORE VALUE FOR REFERENCE .IIF NZ XENTRY, MOV PAGENO,IDXPAG ;PASS CURRENT PAGE NUMBER ;chs51a CALL INDXAD ;ALLOCATE RECORD & STORE TEXT & PAGE REF. ASL R3 ;CONVERT TOC NUMBER TO TABLE OFFSET ADD #,R3 ; AND TO POINTER ADDRESS 30$: TSTEQ (R3),40$ ;LOOK FOR FORWARD POINTER NOT SET MOV (R3),R3 ;POINT TO NEXT RECORD BR 30$ ; AND LOOP 40$: MOV R4,(R3) ;STORE POINTER TO NEW RECORD ; Determine length of page reference CLR R2 ;BUILD LENGTH HERE MOVB APNDN,R0 ;GET APPENDIX NUMBER BEQ 50$ ;SKIP IF NONE DEC R2 ;ADJUST FOR APPENDIX LETTER BR 60$ 50$: MOVB CHPTN,R0 ;GET CHAPTER NUMBER BEQ 70$ ;SKIP IF NONE CALL PPGNO ;ADJUST FOR LENGTH 60$: DEC R2 ;ADJUST FOR DASH 70$: MOV PAGENO,R0 ;GET PAGE NUMBER CALL PPGNO ;ADJUST FOR ITS LENGTH NEG R2 ;CHANGE TO REAL LENGTH CMP R2,TOCPAG ;LONGER THAN PREVIOUS RECORD? BLE 80$ ; NO, SKIP MOV R2,TOCPAG ; YES, STORE THIS LENGTH 80$: RETURN .ENDC ; NZ TBLCON ;chs82- ; ENTRY and INDEX commands ; ENTRY -- Add index item to index data without page reference ; INDEX -- Add index item to index data with page reference .IF NZ XENTRY ;chs51a+ ENTRY:: CLR IDXPAG ;RECORD WITHOUT PAGE NUMBER BR INDX0 .IFTF ;chs51a- INDEX:: .IFT ;chs51a+ MOV PAGENO,IDXPAG ;RECORD WITH CURRENT PAGE NUMBER INDX0: .ENDC ; -NZ XNTRY ;chs51a- MOV #ICBUF,R0 ;GET ADDRESS OF INDEX ITEM BUFFER MOV R0,R5 ;COPY INDEX ITEM BUFFER ADDRESS 10$: CLR (R0)+ ;CLEAR INDEX ITEM BUFFER CMP R0,#ICBFE BLOS 10$ MOV #,R3 ;END TEST ON BUFFER ;chs21a .IIF Z ATOSBI, CLR IDXRF ;CLEAR REPEATED ITEM FLAG ;chs51e CALL $FRCND ;FORCE TO LOGICAL END OF COMMAND MOV NSPCH,-(SP) ;SAVE CURRENT NON-SPACING COUNT ;chs52 INDX1: CALL GCIN ;READ CHARACTER FROM FILE CMPEQ R1,#CR,20$ ;END OF LINE? ;chs52 .IF NZ SUBIDX ;chs51b+ TSTEQ $SFLSW,10$ ;SKIP IF SUBINDEX FLAGS DISABLED TSTNEB QTFLG,10$ ;SKIP IF NOT QUOTED CHARACTER CMPNEB #SBIDX,R1,10$ ;SKIP IF NOT SUBINDEX FLAG .IF NZ ATOSBI ;chs51e+ MOV IDXPAG,-(SP) ;SAVE REFERENCE PAGE NUMBER CLR IDXPAG ;CLEAR FOR "ENTRY" MOV R3,-(SP) ;SAVE REGISTERS MOV R5,-(SP) CALL INDX2 ;PROCESS PORTION OF ENTRY MOV (SP)+,R5 ;RESTORE REGISTERS MOV (SP)+,R3 MOV (SP)+,IDXPAG ;RESTORE REFERENCE PAGE NUMBER .ENDC ; NZ ATOSBI ;chs51e- MOVB #<200+SPC-1>,R1 ;SET TO INTERNAL FLAG 10$: .ENDC ; NZ SUBIDX ;chs51b- MOVB R1,(R5)+ ;STORE CHARACTER OF INDEX DATA SOB R3,INDX1 ;LOOP IF ROOM ;chs21c 20$: MOV (SP)+,NSPCH ;RESTORE NON-SPACING COUNT ;chs52 INDX2: .IIF NZ ENAIDX, TSTEQB $IDXSW,INDRET ;QUIT IF INDEXING DISABLED ;chs88c .IIF NZ ATOSBI, CLR IDXRF ;CLEAR REPEATED ITEM FLAG ;chs51e BIC #1,R5 ;CHECK FOR BOUNDARY ALIGNMENT ;chs21c SUB #ICBUF-2,R5 ;CALCULATE LENGTH OF ASCIZ STRING MOV R5,S1 ;SAVE FOR LATER USE MOV XFIRST,R2 ;GET ADDRESS OF FIRST ITEM SO FAR BNE INDXL2 ;IF PRESENT, CONTINUE...ELSE START LIST INDXV: CALL INDXAD ;CREATE TEXT AND POINTER BLOCK, PAGE NO MOV R4,XFIRST ;THIS IS FIRST ITEM (AND ONLY) CLR (R4)+ ;NO LINKS AT ALL CLR (R4) INDRET: RETURN ;chs88c INDXL2: CLR IDXCF ;CLEAR CASE DIFFERENCE FLAG MOV 4(R2),R3 ;ADDRESS OF ASCIZ OF OLD ITEM MOV #ICBUF,R4 ;POINTER TO NEW ITEM INDXL1: .IF NZ IDXPUN ;chs65 CALL GETCHR ;GET NEXT CHARACTERS ;chs65 .IFF ;chs65 MOVB (R3)+,R1 ;GET CHAR OF OLD MOVB (R4)+,R0 ;GET CHAR OF NEW .ENDC ; -NZ IDXPUN ;chs65 .IF NZ SUBIDX ;chs51b+ TST R1 ;SUBINDEX FLAG IN OLD? BLT 2$ ; YES, CHECK ROOT TST R0 ;SUBINDEX FLAG IN NEW? BGE 4$ ; NO, CONTINUE NORMALLY 2$: CALL ROOTCK ;CHECK FOR MATCH OF ROOT ENTRY BCC 4$ ;CONTINUE IF THEY MATCH TST R0 ;WHICH IS FIRST? BNE IDX4A ; OLD IS FIRST, LOOK FURTHER BR INDX3 ; NEW IS FIRST, INSERT IT 4$: .ENDC ; NZ SUBIDX ;chs51b- CMPEQ R1,R0,35$ ;SKIP IF SAME BEFORE CASE MERGE ;chs21c MOV SP,IDXCF ;SET CASE DIFFERENCE FLAG 10$: CMP R1,#141 ;CONVERT LC TO UC BLT 20$ BIC #40,R1 20$: CMP R0,#141 BLT 30$ BIC #40,R0 30$: CMPNE R1,R0,40$ ;NOT SAME? 35$: TSTNE R1,INDXL1 ;LOOP IF NOT END OF STRINGS ;chs21c BR INDX4 ; ELSE, APPEARS OLD = NEW ;chs21c 40$: BLT IDX4A ;OLD ONE IS FIRST, LOOK FURTHER ; ELSE, NEW ONE IS FIRST; INSERT IT ;chs21c INDX3: TSTNE IDXRF,IDX4B ;REPEATED ITEM? CALL INDXAD ;ADD ITEM WITH PAGE NO TO STORAGE (UNLINKED? MOV 2(R2),R0 ;WHO PRECEDED OLD? BNE 10$ ;ANYONE? MOV R4,XFIRST ;NO. NEW IS FIRST OF ALL. 10$: MOV R4,2(R2) ;NEW IS PREDECESSOR OF OLD MOV R2,(R4) ;OLD IS SUCCESSOR OF NEW, NO PREDECESSOR MOV R0,2(R4) ;SET OLD PREDECESSOR BEQ 20$ ;IF EQ NONE MOV R4,(R0) ;MAKE NEW ONE BE HIS SUCCESSOR 20$: RETURN INDX4: TSTEQ IDXCF,20$ ;TRULY THE SAME? ;chs21b MOV 4(R2),R3 ;ADDRESS OF ASCIZ OF OLD ITEM ;chs21b MOV #ICBUF,R4 ;POINTER TO NEW ITEM ;chs21b 10$: .IF NZ IDXPUN ;chs65 CALL GETCHR ;GET NEXT CHARACTERS ;chs65 .IFF ;chs65 MOVB (R3)+,R1 ;GET CHAR OF OLD ;chs21b MOVB (R4)+,R0 ;AND ONE OF NEW ;chs21b .ENDC ; -NZ IDXPUN ;chs65 CMPEQ R1,R0,10$ ;SAME, KEEP LOOKING? ;chs21b+ BGT INDX3 ; NEW LOWER, PUT IT FIRST BR IDX4A ; NEW HIGHER, KEEP LOOKING AT LIST 20$: MOV SP,IDXRF ; YES, SET REPEATED ITEM FLAG ;chs21b- IDX4A: MOV (R2),R3 ;LOOK FURTHER ;chs21c+ BEQ INDX5 ;END OF LIST. NEW IS LAST MOV R3,R2 ;MOVE LINK TO A BR INDXL2 ;LOOK FURTHER ;chs21c- IDX4B: MOV 2(R2),R2 ;AT END OF REPEAT. GET LAST ONE. IDX4C: ;NEW ITEM IS SAME AS OLD ;chs21d .IF NZ XENTRY ;chs51a+ TSTEQ IDXPAG,20$ ;SKIP IF NEW IS "ENTRY" MOV 6(R2),R3 ;GET PAGE NUMBER OF OLD BNE 2$ ;CONTINUE IF NOT "ENTRY" MOV R2,R4 ; ELSE POINT TO OLD BR IDXAX2 ;GO FILL IN NEW PAGE NUMBER 2$: CMPNE IDXPAG,R3,6$ ;STILL ON SAME PAGE? .IFF ;chs51a- CMPNE PAGENO,6(R2),6$ ;ON SAME PAGE AS LAST ENTRY? ;chs21d .ENDC ; -NZ XENTRY ;chs51a MOVB 10(R2),-(SP) ;GET OLD CHAPTER NUMBER ;chs21d+ MOVB CHPTN,R3 ;COMPARE TO CHAPTER NUMBER? TSTNEB 11(R2),4$ ;YES, IF OLD BYTE SET MOVB APNDN,R3 ; ELSE USE CURRENT APPENDIX 4$: CMPEQB (SP)+,R3,20$ ;ON SAME PAGE IN SAME CHAPTER? ;chs21d- 6$: CALL INDXAP ;ADD POINTERS ONLY (WITH PAGE. NO LINK) MOV 4(R2),4(R4) ;NEW POINTS TO SAME TEXT AS OLD MOV (R2),R0 ;GET PREVIOUS SUCCESSOR OF OLD MOV R4,(R2) ;MAKE NEW SUCCEED OLD TSTEQ R0,10$ ;NO OLD NEXT? MOV R4,2(R0) 10$: MOV R0,(R4)+ ;OLD SUCCESSOR IS SUCCESSOR OF NEW MOV R2,(R4) ;OLD IS PREDECESSOR OF NEW 20$: RETURN INDX5: TSTNE IDXRF,IDX4C ;REPEATED ITEM? CALL INDXAD ;CREATE TEXT AND POINTER BLOCK WITH PAGENO MOV R4,(R2) ;MAKE NEW FOLLOW OLD CLR (R4)+ ;CLEAR FORWARD LINK MOV R2,(R4) ;AND OLD PRECEDE NEW. RETURN INDXAD: CALL INDXAX ;ALLOCATE ITEM AND BUFFER MOV R4,-(SP) ;SAVE BASE OF NEW ITEM CLR (R4)+ ;CLEAR FORWARD LINK CLR (R4)+ ;CLEAR BACKWARD LINK MOV #ICBUF,R0 ;TRANSFER TEXT INTO BUFFER MOV S1,R1 ;GET COUNT OF BYTES IN INDEX ITEM ADD #6,R4 ;POINT TO TEXT AREA MOV R4,-6(R4) ;STORE POINTER TO TEXT 10$: MOVB (R0)+,(R4)+ ;TRANSFER INDEX ITEM SOB R1,10$ ;ANY MORE BYTES TO MOVE? ;chs21c MOV (SP)+,R4 ;RESTORE BASE OF INDEX. RETURN ; Local subroutine to allocate only link block .ENABL LSB INDXAP: CLR -(SP) ;INDICATE NO ADDITIONAL STORAGE BR 10$ ; ; Local subroutine to allocate link block and ASCIZ buffer INDXAX: MOV S1,-(SP) ;INDICATE BUFFER STORAGE NEEDED 10$: MOV XBOT,R4 ;GET STARTING ADDRESS OF STORAGE POOL ADD #10.,(SP) ;ALLOCATE LINK BLOCK STORAGE SUB (SP),R4 ;CALCULATE NEW ENDING POOL ADDRESS .IF NZ TXTQUE ;chs78+ CMP R4,QEND ;OVERLAY WITH DEFERRED TEXT QUEUE? .IFF ;chs78- CMP R4,FOOTP2 ;OVERLAY WITH FOOTNOTE STORAGE POOL? .ENDC ; -NZ TXTQUE ;chs78 BHI 20$ ;IF HI NO CALL EXPAND ;EXPAND MEMORY 20$: SUB (SP)+,XBOT ;ALLOCATE STORAGE FROM POOL MOV XBOT,R4 ;GET ADDRESS OF LINK BLOCK .IF NZ XENTRY ;chs51a+ IDXAX2: CLR 10(R4) ;ASSUME NO CHAPTER/APPENDIX MOV IDXPAG,6(R4) ;INSERT PAGE NUMBER BEQ 30$ ;ALL DONE IF ZERO .IFF ;chs51a- MOV PAGENO,6(R4) ;INSERT PAGE NUMBER CLR 10(R4) ;ASSUME NO CHAPTER/APPENDIX .ENDC ; -NZ XNTRY ;chs51a MOVB APNDN,10(R4) ;INSERT CURRENT APPENDIX BNE 30$ ;IF NE OKAY MOVB CHPTN,10(R4) ;INSERT CHAPTER NUMBER BEQ 30$ ;IF EQ NONE COMB 11(R4) ;DESIGNATE CHAPTER NUMBER 30$: RETURN .DSABL LSB ; Subroutine to check order of subindex roots ;chs51b+ ; ON ENTRY: R0 = First char after root of "new" ;chs51d+ ; R1 = First char after root of "old" ; R2 = Pointer to current "old" record ;chs51d- ; ON EXIT: C bit clear if root of "new" same as that of "old" ; else, C bit set and R0 = 0 if "new" is first ; R0 > 0 if "old" is first .IF NZ SUBIDX ROOTCK: MOV R3,-(SP) ;SAVE STATUS MOV R4,-(SP) TST R0 ;SUBINDEX FLAG IN NEW? ;chs51d+ BGT 30$ ; NO, NEW IS LONGER TST R1 ;SUBINDEX FLAG IN OLD? BGT 40$ ; NO, OLD IS LONGER TSTNE IDXCF,10$ ;ROOTS REALLY SAME TSTEQ R0,40$ ;NEW FIRST? TSTEQ R1,30$ ;OLD FIRST? BR 60$ ;BOTH SAME ;chs51d- 10$: MOV 4(R2),R3 ;POINT TO OLD ITEM MOV #ICBUF,R4 ; AND NEW ITEM 20$: .IF NZ IDXPUN ;chs65 CALL GETCHR ;GET NEXT CHARACTERS ;chs65 .IFF ;chs65 MOVB (R3)+,R1 ;GET CHAR OF OLD MOVB (R4)+,R0 ;GET CHAR OF NEW .ENDC ; -NZ IDXPUN ;chs65 CMPEQ R1,R0,20$ ;CONTINUE IF THEY MATCH BGT 40$ ;SKIP IF NEW FIRST 30$: MOV SP,R0 ;SET FLAG FOR OLD FIRST BR 50$ ; AND TAKE ERROR RETURN 40$: CLR R0 ;SET FLAG FOR NEW FIRST 50$: SEC ;SET ERROR RETURN BR 70$ ; AND TAKE IT 60$: CLC ;MAKE SURE C BIT NOT SET 70$: MOV (SP)+,R4 ;RESTORE STATUS MOV (SP)+,R3 RETURN .ENDC ; NZ SUBIDX ;chs51b- .IF NZ IDXPUN ;chs65+ ; Local subroutine to get next characters of index entries ; ignoring special characters (e.g., punctuation) ; ; ON ENTRY: R3 = Pointer to next character of "old" entry ; R4 = Pointer to next character of "new" entry ; ON EXIT: R0 = Next character of "new" ; R1 = Next character of "old" GETCHR: MOV R2,-(SP) ;SAVE WORKING REGISTER 10$: MOVB (R3)+,R2 ;GET CHARACTER CALL TSTCHR ;CHECK FOR PUNCTUATION BCS 10$ ; C BIT => SKIP CHAR MOV R2,R1 ;PUT CHAR IN OUTPUT REG. 20$: MOVB (R4)+,R2 ;GET CHARACTER CALL TSTCHR ;CHECK FOR PUNCTUATION BCS 20$ ; C BIT => SKIP CHAR MOV R2,R0 ;PUT CHAR IN OUTPUT REG. MOV (SP)+,R2 ;RESTORE REGISTER RETURN ; Local subroutine to check if character in R2 is punctuation TSTCHR: CMPB #SPC,R2 ;CONTROL CHAR? .IF NZ IDXSPC BGE 20$ ; YES, USE IT .IFF BGT 20$ ; YES, USE IT .ENDC ; -NZ IDXSPC CALL ALPH2 ;CHECK FOR LETTER BCC 30$ ; IF SO, USE IT CMPB #'0,R2 ;PUNCTUATION? BGE 10$ ; YES, SKIP IT CMPB #'9,R2 ;NUMBER? BGE 20$ ; YES, USE IT 10$: SEC ;SIGNAL PUNCTUATION BR 30$ 20$: CLC ;SIGNAL GOOD CHARACTER 30$: RETURN .ENDC ; NZ IDXPUN ;chs65- .END