.MCALL .MODULE .MODULE INDEX,VERSION=16,COMMENT= ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only 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 except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ;+ ;COND ; MMG$T (0) controls FB/XM versions ; 0 FB (minimize memory version) ; 1 XM (minimize LOW memory version) ;- .IIF NDF MMG$T MMG$T=0 .IIF NE MMG$T MMG$T=1 ; ;AUTHOR: D.B. Fingerhut, March 1986 ;Edits: SGW 22-Jul-1986 Expand leading spaces for formatting ; 2nd- and 3rd-level entries; put book ; references on same line as index entry; ; fix missing line when scrolling; fix ; display of lines containing only a page ; number (no index entry text); fix CTRL/C ; tests; add comments about input file ; formats. ; SGW 1-Oct-86 Add initial explanation display ; SGW 7-Jan-87 Add support for Roman numerals (up to xxx) ; SGW 2-Mar-87 Disable SL so prompt string stays up ; SGW 13-Jul-87 Clear line before "End of index" msg ; SGW 14-Jul-87 Don't allow scrolling after error msgs ;09 JFW 24-Nov-87 Refresh screen (^W), cleanup ;11 JFW 11-Nov-88 Fixup search argument problems ; ;16 JFW 11-OCT-1990 bracket error messages in ;+/;ERROR/.../;- .MCALL .LOOKUP .READW .CLOSE .EXIT .GTLIN .PRINT .MCALL .SCCA .RCTRLO .READC .DSTAT .ASSUME .BR .MCALL .HERR .SERR .FETCH .RELEAS .PURGE .IIF EQ MMG$T .MCALL SOB ;+ ; Commands ; ; INDEX will also accept ^W and ^R whenever it is prompting for ; input. If ^W is entered, the screen will be refreshed ; with the search screen. If ^R is entered, the screen ; will be refreshed to the initial screen which contains the ; abbreviation summary. ;- ;+ ; Input files: ; ; This program expects three input files, INDEX.IDX, INDEXA.IMG, ; and INDEXB.IMG. INDEX.IMG is used below to describe the logical ; file resulting from a concatenation of INDEXA.IMG and INDEXB.IMG. ; ; INDEX.IDX is always 7 blocks long. Block 0, byte 0 contains the ; size (in bytes) of the following book id strings (manual titles, ; usually. Byte 1 is free. Byte 2 begins the book id strings. ; All the strings are the same length (which gets put in byte 0). ; ; Block 1 begins the pointers into the file INDEX.IMG. Each pointer ; is two words, consisting of a 1-word block number and a 1-word offset ; into the block. The pointers are set up corresponding to entries ; for: A, B, ... Z ; AA, AB, ... AZ, A$, A. ; BA, BB, ... BZ, B$, B. ; ... ; ZA, ZB, ... ZZ, Z$, Z. ; That is, the two words corresponding to the "AB" slot point to ; the place in INDEX.IMG where the first index entry beginning ; with AB.... starts. The special characters dollar and dot are ; arbitrarily assigned values "Z+1" and "Z+2" when computing their ; locations in the index table. If any combination doesn't exist ; (i.e. there is nothing in the file INDEX.IMG beginning with those ; two letters, ZQ for example) the pointer entries are -1's (177777). ; ; The pointers are created by ignoring all leading non-alpha characters ; in the index entries, and ignoring all except $ and . in the second ; character position. They also apply only to primary index entries. ; Primary index entries are distinguished by NOT beginning with a space. ; ; The index file itself is sorted ignoring leading non-alpha characters, ; but imbedded non-alpha characters get sorted. ; ; INDEX.IMG contains the actual text of the index entries, with book ; identifiers and chapter/page numbers. The format of an entry is: ; ; 1. Length of entry record (1 byte) ; 2. Text of the entry, 1 character per byte, ending with 0 byte ; 3. [optional] book id number (1 byte), starting with number 1. ; The sign bit of a book id byte is set. #1 corresponds to the ; first book id string in block 0 of INDEX.IDX, etc. If a ; book id byte is 200 (sign bit only) it corresponds to the ; word "to" in the format "3-14 to 3-21". ; 4. [optional] chapter/page reference(s). If present, there ; will be a 1-byte chapter number and a 2-byte page number, ; corresponding to a chapter-page reference of the form 3-14. ; If the chapter byte is 0, it means there is just an absolute ; page number (27, 114, 343, or whatever) in the next two bytes. ; There may be multiple chapter/page references for a single ; index entry, and possibly multiple book id's. You know you've ; come to the end when the length byte (1., above) runs out. ; If the page number word (2 bytes) has bit 40000 set, the page ; number is interpreted as a Roman numeral. ; ;- ;+ ; This macro generates calls to the formatting routine. The arguments ; are: ; BUFFER - a pointer to an output buffer. If not specified, ; R0 is assumed to point the output buffer. ; PICTUR - an ASCII string enclosed in '<>', containing the ; format string and/or formatting directives. See ; comments in file RESRC1.MAC. ; ARGUMENTS- values contained in '<>' to satisfy any formatting ; directives. SP addressing is not valid. ;- .MACRO FORMAT BUFFER,PICTUR,ARGUMENTS,LAB1 .IF NB PSECT $$$FMT ...FMT = . .ASCIZ \PICTUR\ .EVEN PSECT INCODE .ENDC ...ARG = 0 ..ARGC = 0 .IRP ARG, ..ARGC = ..ARGC +1 .ENDM ..LOOP = ..ARGC .REPT ..ARGC ..LOP1 = ..LOOP .IRP ARG, ..LOP1 = ..LOP1 -1 .IF EQ ..LOP1 MOV ARG,-(SP) ...ARG = ...ARG +1 .ENDC .ENDM ..LOOP = ..LOOP -1 .ENDR .IF NB MOV #...FMT,-(SP) .IFF .IF NB LAB1 MOV LAB1,-(SP) .IFF .ERROR ;No FORMAT string specified .ENDC .ENDC ...ARG = ...ARG +1 MOV #<...ARG*2>,-(SP) .IF NB BUFFER MOV BUFFER,R0 .ENDC .GLOBL $FORMAT CALL $FORMAT .ENDM FORMAT .MACRO ...... .ENDM ...... USERSP =: 42 ;original stack pointer JSW =: 44 ;JSW GTLIN$ =: 10 ;Input from command files EDIT$ =: 20 ; Turn off SL bit in JSW OVLY$ =: 1000 ; leave channel 17 open to pgm file VIRT$ =: 2000 ; Virtual bit in JSW TTSPC$ =: 10000 ;Immediate input from terminal TTLC$ =: 40000 ;Lowercase input NUL =: 000 ;Null char CTRLC =: 'C-100 ;CTRL/C char TAB =: 011 ;TAB char LF =: 012 ;Linefeed char CR =: 015 ;carriage return CTRLR =: 'R-100 ;CTRL/R char CTRLW =: 'W-100 ;CTRL/W char ESC =: 033 ;Escape char SPC =: 040 ;Space char CODE$ =: 133 ;code value for "$" in index table CODE. =: 134 ;code value for "." in index table NOCRLF =: 200 ;no CRLF terminator BOKSIZ =: 100/2 ;100 bytes (40 words) ROMBIT =: 40000 ;Roman numeral flag in page number word IDXCHN =: 0 ;Channel for INDEX.IDX IMACHN =: 1 ;Channel for INDEXA.IMG IMBCHN =: 2 ;Channel for INDEXB.IMG OVLCHN =: 17 ;channel for overlays BLKSZ =: 1000 ;Size of a block in bytes MAXREC =: 128. ;Max size of a data record ERRBYT =: 52 ;User error byte LINES =: 16. ;Number of lines in scroll region FL.ERR =: 1 ;Flag bit for "Error"; don't want to ; scroll after error message, because ; buffer may not be set up correctly ; in all cases. FL.FTT =: 2 ;Flag bit for first time thru. We ; could probably use FL.ERR for this ; case too, but this keeps the two ; conditions logically separate. FL.RES =: 4 ;Flag bit for restarting NOMATC =: 1 ;Flag bit in MATFLG word; "no match" RALPH =: 200 ; "Record Alpha" SALPH =: 100000 ; "String Alpha" .PSECT FIRST BASE:: .PSECT INCODE .PSECT .LIBC. .PSECT .LIBP. .PSECT .LIBD. .PSECT $$$FMT .PSECT .LIBO. OVR .ASECT .=JSW .IF EQ MMG$T .WORD EDIT$!OVLY$ .AUDIT .INDEX .IFF; EQ MMG$T .WORD VIRT$!EDIT$ .AUDIT .INDEX .AUDIT .INDROT .ENDC ;EQ MMG$T .SBTTL MAIN .PSECT INCODE .Enabl LSB DEBUG:: BPT ;debugging INDEX:: CALL INIT ;Do initialization 10$: CALL GETSTR ;Put an index string in STRING .PRINT #MSGERR ;Erase any error message TSTB STRING ;Was anything typed? BNE 20$ ;Branch if so BIT #FL.FTT!FL.ERR,FLAGS ;See if: First time thru, or if we ; just had an error message BEQ 40$ ;If not, go do it. BR 10$ ;Otherwise, require input ........... 20$: CALL GETIND ;Get the index value in R1 BCS 10$ ;Branch if invalid CALL GETIDX ;Get the offset for the info ; and read in first block of it. BCS 60$ ;Branch if no match found 30$: CALL MATCH ;Find a match BCS 60$ ;Branch if no match found .PRINT #MSGCLS ;Clear the scroll region 40$: MOV #LINES,R5 ;R5 = number of lines to print 50$: CALL PUTINF ;Print out the index information BIC #FL.FTT!FL.ERR,FLAGS ;Clear: First time thru, previous ; error message bits TST TSW ;Check .SCCA ^C flag BMI FINISH ;Branch if ^C^C seen CALL GETREC ;Get a record BCS 70$ ;Branch if no more records SOB R5,50$ ;Print a screen full of lines .PRINT #MSGNXT ;Print the bottom line BR 10$ ;Get another search string ........... 60$: .PRINT #MSGERO ;Position for error message ;+ ;ERROR .ERR #ERRARE,#SNF,RETURN=YES,LEVEL=W ; -W-Search string not found ;- BR 80$ ;Join common error code ........... 70$: .PRINT #MSGERO ;+ ;ERROR .ERR #ERRARE,#EIR,RETURN=YES,LEVEL=W ; -W-End of index reached ;- 80$: BIS #FL.ERR,FLAGS ;Set "Error" status bit BR 10$ ;Get new string ........... .dsabl LSB .SBTTL GETSTR .Enabl LSB ;+ ; GETSTR ; Get a string from the user. ; ; Output: STRING - Will contain the string ; ;- GETSTR:: 10$: .PRINT #MSGPOS ;Position cursor .RCTRLO GETLIN: .GTLIN #STRING ;collect a line BCS 30$ ;too long TST TSW ;Check for ^C^C BMI FINISH ;Branch if so MOV #STRING,R0 ;Set up to scan for ^C in bufr 20$: TSTB @R0 ;See if EOL BEQ 40$ ;Branch if so CMPB @R0,#CTRLC ;exit? BEQ FINISH ;yes CMPB @R0,#CTRLR ;restart? BEQ 50$ ;yes CMPB (R0)+,#CTRLW ;refresh? BNE 20$ ;no CALL INISCR ;refresh screen BR 10$ ;get another line ........... 30$: .PRINT #MSGERO ;+ ;ERROR .ERR #ERRARE,#FE.RTL,RETURN=YES,LEVEL=WARNING ; -W-String too long ;- BIS #FL.ERR,FLAGS ;Set "Error" status bit BR 10$ ;Get another line ........... 40$: RETURN ...... 50$: BIS #FL.RES!FL.FTT,FLAGS ;set flags MOV @#USERSP,SP ;restore stack pointer .IF EQ MMG$T .READW #IOAREA,#OVLCHN,#BASE,#DATA-BASE/2,#1 ;reload code .ENDC; EQ MMG$T JMP INDEX ;and begin again ............. FINISH::.PRINT #MSGEXT ;Clean up screen display format ABORT:: .EXIT ;and go away. ...... .Dsabl LSB .SBTTL GETIND .Enabl LSB ;+ ; ; GETIND ; Put the two character index value in R1. ; ; Input: STRING contains the user's input string (ASCIZ) ; ; Output: R1 = index value ; ; R0, R2 destroyed ;- GETIND:: MOV #STRING,R2 ;Start at beginning of string 10$: MOVB (R2)+,R0 ;Move in the first character BEQ 110$ ;End of string CMP #'A,R0 ;Is first character less than A? BGT 10$ ;Branch if so CMP #'Z,R0 ;Is it less than or eq to Z? BLT 10$ ;Branch if not (it's non-alpha) SUB #'A,R0 ;Make it an offset from zero 30$: MOVB (R2)+,R1 ;Move in second character BEQ 40$ ;Branch if end of string CMP #'$,R1 ;Is it a $? BNE 50$ ;Branch if not MOV #CODE$,R1 ;$ comes after Z BR 70$ ;Skip A-Z checks ........... 50$: CMP #'.,R1 ;Is it a .? BNE 60$ ;Branch if not MOV #CODE.,R1 ;'.' comes after '$' BR 70$ ;Skip A-Z checks ........... 60$: CMP #'A,R1 ;Is second character less than A? BGT 30$ ;Branch if so CMP #CODE.,R1 ;Is it less than or eq to '.'? BLT 30$ ;Branch if not 70$: SUB #'A+2,R1 ;Make it an offset from zero & adjust 80$: ADD #28.,R1 ;Next 26 element group DEC R0 ;Loop through BGE 80$ BR 90$ ........... 40$: MOV R0,R1 ;Use first character as low-order 90$: TST (PC)+ 100$: SEC ;Invalid input string RETURN ...... 110$: .PRINT #MSGERO ;+ ;ERROR .ERR #ERRARE,#INV,LEVEL=W,RETURN=YES ; -W-Invalid input string ;- BIS #FL.ERR,FLAGS ;Set "Error" status bit BR 100$ ............ .Dsabl LSB .SBTTL GETIDX .Enabl LSB ;+ ; ; GETIDX ; ; Get the offset into INDEX.IMG (INDEXA.IMG logically concatenated with ; INDEXB.IMG) of where to start displaying information and read the block ; into BUF. ; ; Input: R1 = element number in INDEX.IDX of (blockno,offset) pair. ; ; Output: INFBLK = block number into INDEX.IMG ; INFOFF = offset into block ; c-bit set -> no match found ; ;- GETIDX::ASL R1 ;Convert it to words ASL R1 ;Two words/element MOV R1,-(SP) ;Save offset/block BIC #777,R1 ;Clear out offset SWAB R1 ;Make it a block number ASR R1 ;Shift out low bit INC R1 ;Start at block 1 .Assume IDXCHN EQ 0 .READW #IOAREA,#0,#BUF,#BLKSZ/2,R1 BCS 20$ MOV (SP)+,R0 ;Restore the offset/block BIC #^C777,R0 ;Clear out block MOV BUF(R0),INFBLK ;Save block number BMI 10$ ;Branch if negative MOV BUF+2(R0),INFOFF ;Save offset CALL GETBLK ;Read INFBLK block from INDEX.IMG BCS 30$ ;Branch if error TST (PC)+ ;Clear carry 10$: SEC ;Indicate no match RETURN ...... 20$: MOV #RADIDX,R2 ;+ ;ERROR 30$: .ERR #ERRARE,#FE.INE,RETURN=NO,LEVEL=F,FILE=R2 ; -F-Input error INDEX.IDX ; -F-Input error INDEXA.IMG ; -F-Input error INDEXB.IMG ;- ......................................................... .Dsabl LSB .SBTTL MATCH .Enable LSB ;+ ; MATCH ; ; Search for the user's string in the data file. ; ; Input: STRING contains the user's string. ; ; Output: RECORD contains the matching (or closest) RECORD ; c bit clear -> match ; c bit set -> no match ; ; Matching: ; 1. If the index string runs out before the user's string, then it's ; not a match because the user's string could still show up in the ; index. ; 2. If the user's string runs out before the index string, it is a match ; because if the user's string is in the index, it would have shown ; up by then. ; 3. If there are any differences before the end of either string, then ; it's not a match. ; The search continues until either: ; a character in the index string .GT. a character in the search string ; or the end of the user's string is found. ; ".GT." in this case is a bit complicated because leading non- ; alphabetics are ignored in the index sort. All non-alphabetics are ; also considered to precede the alphabetics even though their ASCII ; codes may not (for example, ^ [ { \ | ] } etc.). Therefore, some ; strange convolutions are gone through to decide when to quit (see ; comments in code). ;- MATCH:: MOV R3,-(SP) ;Get a work register 10$: CLR MATFLG ;Clear all the "match" flags CALL GETREC ;Get a record BCS 80$ ;Branch if end of file 20$: CMPB #' ,RECORD+1 ;Is this a secondary entry? BEQ 10$ ;Branch if so CLR R1 MOV #1,R0 ;R0 = pointer into INDEX string 30$: CALL GETS ;Get a char from "STRING" into R2 BCC 40$ ;Branch if not EOS .ASSUME NOMATC EQ 1 ROR MATFLG ;See if "No match" detected BCS 10$ ;If so, keep looking BR 80$ ;We got a match! (C = 0) 40$: CALL GETR ;Get a char from "RECORD" into R3 BCS 10$ ;Branch if EOS detected CMPB R2,R3 ;Compare "STRING" and "RECORD" chars BEQ 30$ ;If match, keep comparing! .ASSUME NOMATC EQ 1 ROR MATFLG ;If NOMATC set, we've already been BCS 10$ ;through this once, don't do it again. .ASSUME NOMATC EQ 1 SEC ;(N.B. must rotate MATFLG back the way ;it was since there are other bits we ;care about too!) ROL MATFLG ;No match - set flag for later ;OK, we know that the string does not ;match the record. Now we have to ;determine if we've looked far enough ;in the index file to be sure that we ;would have found the string if it was ;there and, if not, to keep looking. ;DSR does *NOT* sort the index just by ;ASCII character code values. All ;non-alphabetics are considered to be ;sequential and to precede A-Z. ;Leading non-alphas, although they are ;sorted within themselves, are ignored ;as far as determining index order. ;If you're confused, join the club. ;Take a look at the printed master ;index to get a better idea of how ;all this weirdness works. .ASSUME RALPH EQ 200 50$: TSTB MATFLG ;See if we've seen an alpha yet in "RECORD" BMI 60$ ;If so, don't need to scan for one CALL GETR ;Scan "RECORD" until alpha seen BCS 10$ ;(We want to skip all leading non-alphas) BR 50$ ;Go check for alpha again. .ASSUME SALPH EQ 100000 60$: TST MATFLG ;See if we've seen an alpha yet in "STRING" BMI 70$ ;If so, don't need to scan for one CALL GETS ;Scan "STRING" until alpha seen BCS 10$ ;(We want to skip all leading non-alphas) BR 60$ ;Go check for alpha again. 70$: CMPB R2,R3 BHIS 30$ ; SEC ;Return C set for "not found" 80$: MOV (SP)+, R3 ;*C*Restore work register RETURN .Dsabl LSB .SBTTL GETR .Enabl LSB ;+ ; ; GETR ; ; Gets a character from "RECORD" into R3. ; ; Inputs: ; ASCIZ string in "RECORD", indexed by R0 ; R0 = index into "RECORD" ; Outputs: ; Character in R3, suitably modified by FIXCHR routine if necessary ; R0 incremented to point to next character in string ; "RALPH" (Record Alpha) bit set in MATFLG if alphabetic encountered ; C-bit set if end-of-string detected ; ;- GETR: MOVB RECORD(R0),R3 ;Get char from "RECORD" BEQ 20$ ;Branch if end-of-string INC R0 ;Increment index for next time CALL FIXCHR ;Change non-alphas, force uppercase BLO 10$ ;Branch if non-alpha BIS #RALPH, MATFLG ;Set "alpha char seen in RECORD" 10$: TST (PC)+ ;CLR C-bit 20$: SEC ;Return C=1 if EOS RETURN .Dsabl LSB .SBTTL GETS .Enabl LSB ;+ ; ; GETS ; ; Gets a character from "STRING" into R2. ; ; Inputs: ; ASCIZ string in "STRING", indexed by R1 ; R1 = index into "STRING" ; Outputs: ; Character in R2, suitably modified by FIXCHR routine if necessary ; R1 incremented to point to next character in string ; "SALPH" (String Alpha) bit set in MATFLG if alphabetic encountered ; C-bit set if end-of-string detected ; ;- GETS: MOV R3,-(SP) ;FIXCHR expect char in R3... MOVB STRING(R1),R3 ;Get char from "STRING" BEQ 20$ ;Branch if end-of-string INC R1 ;Increment index for next time CALL FIXCHR ;Change non-alphas, force uppercase BLO 10$ ;Branch if non-alpha BIS #SALPH,MATFLG ;Set "alpha char seen in STRING" 10$: MOV R3,R2 ;GETS has to return char in R2 TST (PC)+ ;CLR C-bit 20$: SEC ;Return C=1 if EOS MOV (SP)+,R3 ;*C*Restore work register RETURN .Dsabl LSB .SBTTL FIXCHR .Enable LSB ;+ ; ; FIXCHR ; Reassign codes to non-alphabetic characters so they are all within range ; 001-100 (i.e. less than the alphabetics) rather than being 40-100, 133-140, ; and 173-177. ; Change lowercase alphabetics to uppercase. ; ; Input: ; character code in R3 ; ; Outputs: ; modified character code in R3 ; Condition codes set so BLT or BLO = non-alpha; BGE or BHIS = alpha ; ;- FIXCHR: BICB #200,R3 ;Force 7-bit characters CMPB R3,#40 ;See if char is non-printing BLO 40$ ;If so, don't mess with it CMPB R3,#'A BLO 30$ ;Branch if less than alphabetics CMPB R3,#'Z BLOS 40$ ;Branch if in range A-Z CMPB R3,#'a BLO 20$ ;Branch if between (Z+1) and (a-1) CMPB R3,#'z BHI 10$ ;Branch if not in range a-z BICB #40,R3 ;Force uppercase BR 40$ 10$: SUB #<123-71>,R3 ;Change { | } ~ to 50 thru 54 20$: SUB #<71-37>,R3 ;Change [ \ ] ^ _ to 42 thru 47 30$: SUB #37,R3 ;Change thru @ to 01 thru 41 40$: CMPB R3,#'A ;Set up for test for char being alpha RETURN .Dsabl LSB .SBTTL PUTINF .Enabl LSB ;+ ; ; PUTINF ; Print out 3 lines of information from BUF beginning at INFOFF. ; ; Input: RECORD contains the record to output terminated with -1 ; ; Output: ; ;- PUTINF:: .PRINT #MSGINF ;Position cursor MOV #RECORD,R1 ;R1 -> Record MOV R1,R2 10$: TSTB (R2)+ BNE 10$ MOVB #200,-(R2) TSTB (R1)+ ;Skip over length .PRINT R1 ;Print index key CLRB @R2 CLR R2 20$: TSTB (R1)+ ;Skip over index key BNE 20$ CMPB #-1,@R1 ;Any references? BEQ 130$ ;Branch if not FORMAT #OUTBUF,<[A15][A33][A133]50C> ;Setup in column 50. MOV #BOKBUF,R4 ;R4 -> booknames CLR R3 MOVB BOKBUF,R3 ;R3 = length of booknames INC R4 ;Skip over length byte BITB #200,@R1 ;Book number? BEQ 50$ ;Branch if not CLR R2 BISB (R1)+,R2 ;R2 = book number BICB #200,R2 ;Clear out 8th bit 30$: DEC R2 ;Make it an offset BEQ 40$ ;Branch if book found ADD R3,R4 ;Jump to next book BR 30$ ;Repeat ........... 40$: FORMAT ,<[S]>, ;Output book id string 50$: FORMAT ,<[A40][A40]> 60$: CMPB #-1,@R1 ;Anything left? BEQ 120$ ;Branch if not TSTB @R1 ;Is there a chapter number? BEQ 80$ ;Branch if not CLR R2 MOVB @R1,R2 ;R2 = chapter number BITB #100,@R1 ;Is it an appendix? BEQ 70$ ;Branch if not FORMAT ,< [S]->, BR 80$ ........... 70$: FORMAT ,<[U3]->, 80$: INC R1 ;Skip over chapter/appendix number MOVB 1(R1),R2 ;Move in high byte SWAB R2 ;Move it over BISB (R1)+,R2 ;Move in and skip over low byte TSTB (R1)+ ;Skip over high byte BIT #ROMBIT,R2 ;Check for Roman numeral flag BEQ 90$ ;If not... CALL ROMAN ;Yup, bypass normal formatting routine BCC 100$ ;If error return, pretend we never went there 90$: FORMAT ,<[U]>, 100$: CMPB #-1,@R1 ;Any more chapter/pages? BEQ 120$ ;Branch if not CMPB #200,@R1 ;Is it "to"? BNE 110$ ;Branch if not TSTB (R1)+ ;Skip over the 200 FORMAT ,< to > ;Put in "to" BR 60$ ; and continue ........... 110$: FORMAT ,<, > ;Put in a comma and space BR 60$ ; and continue ........... 120$: MOV #OUTBUF,R0 BR 140$ ............ 130$: MOV #CRLF,R0 140$: .PRINT RETURN ...... .Dsabl LSB .Enabl LSB ; Converts value in R2 to roman numeral string stored beginning at address in R0. ; ; Inputs: ; R2 = value to convert (up to 89.) ; R0 = pointer to where to store roman numeral string ; Outputs: ; Success: ; R0 points to byte following stored roman numeral string; byte is set to 0. ; R2 is destroyed. ; C-bit = 0 ; Error: ; R0, R2 unchanged. ; C-bit = 1 ; ROMAN: BIC #ROMBIT,R2 ;remove roman flag CMP R2,#L+X+X+X-I+X ;too big? BHI 40$ ;yes MOV R1,-(SP) ;save a work register MOV #ROMTAB,R1 ;point at table 10$: CMP R2,@R1 ;can we use this letter? BGE 20$ ;yes CMP (R1)+,(R1)+ ;skip to next BR 10$ ;and try again ........... 20$: SUB (R1)+,R2 ;reduce by value of letter(s) MOVB (R1)+,(R0)+ ;move first letter MOVB (R1)+,(R0)+ ;and second possible letter BNE 30$ ;second letter exists DEC R0 ;back over one-letter 30$: CMP -(R1),-(R1) ;try this number again TST R2 ;done? BNE 10$ ;no, more letters to do CLRB @R0 ;supply a null to end line BR 50$ ........... 40$: SEC ;return error 50$: MOV (SP)+,R1 ;*C* restore register RETURN ...... I =: 1. V =: 5. X =:10. L =:50. ROMTAB: .WORD L .ASCII "l" .WORD -X+L .ASCII "xl" .WORD X .ASCII "x" .WORD -I+X .ASCII "ix" .WORD V .ASCII "v" .WORD -I+V .ASCII "iv" .WORD I .ASCII "i" .Dsabl LSB .SBTTL GETREC .Enabl LSB ;+ ; ; GETREC ; Put a complete record into RECORD. ; ; Input: INFBLK and INFOFF point to the start of a record ; ; Output: RECORD will contain the next record terminated with -1. ; A single leading space is expanded to four leading spaces. ; Two leading spaces are expanded to eight. ; INFBLK and INFOFF are updated. ; c-bit set -> no more records; RECORD will contain last record ; ; Registers changed: R0,R1,R2,R3 ;- GETREC:: CLR R1 ;R1 = pointer into RECORD CALL GETBYT ;R0 = byte count BCS 50$ ;Branch if end of file TSTB R0 ;Is it end of file? BEQ 40$ ;Branch if not MOVB R0,RECORD(R1) ;Move in the byte INC R1 MOV R0,R2 ;R2 = byte count DEC R2 ;byte count includes count MOV #2,R3 ;Keep track of leading spaces seen 10$: CALL GETBYT ;Get next data byte BCS 50$ ;Branch if end of file TST R3 ;Are we worrying about leading spaces? BLE 30$ ;Branch if not CMPB #SPC,R0 ;Space? BEQ 20$ ;...if yes CLR R3 ;Non-space seen, so clear leading flag BR 30$ ;And skip space-expansion stuff ........... 20$: MOVB R0,RECORD(R1) ;Output extra leading spaces INC R1 ;Maybe this should be a counted loop.. MOVB R0,RECORD(R1) INC R1 MOVB R0,RECORD(R1) INC R1 DEC R3 ;Decrement leading-space counter 30$: MOVB R0,RECORD(R1) ;Move in the byte INC R1 SOB R2,10$ ;Loop thru MOVB #-1,RECORD(R1) ;Terminate with -1 TST (PC)+ ;Clear carry 40$: SEC ;Indicate end of file 50$: RETURN ...... .Dsabl LSB .SBTTL GETBYT .Enabl LSB ;+ ; ; GETBYT ; Put the next byte from INDEX.IMG (logical concatenation of INDEXA.IMG ; and INDEXB.IMG) into R1. ; ; Input: INFBLK and INFOFF contain the current block and next avail byte ; ; Output: R0 = next byte of data ; INFBLK and INFOFF are updated ; c-bit set -> end of file ; ; NOTE: If the first byte is 0, end-of-file is assumed. ;- GETBYT::MOV R2,-(SP) ;Save R2; GETBLK returns ptr in R2 CMP #BLKSZ,INFOFF ;Are we beyond the current block? BGT 10$ ;Branch if not CLR INFOFF ;Reset offset INC INFBLK ;Update block number CALL GETBLK ;Read next block BCS 30$ ;Branch if error 10$: MOV INFOFF,R0 ;R0 = offset to be used MOVB BUF(R0),R0 ;R0 = data to be returned INC INFOFF ;Update to next byte TST (PC)+ 20$: SEC ;Indicate end of file MOV (SP)+,R2 ;Restore R2 RETURN ...... 30$: TSTB @#ERRBYT ;Is it end of file? BEQ 20$ ;yes ;+ ;ERROR .ERR #ERRARE,#FE.INE,LEVEL=F,RETURN=NO,FILE=R2 ; -F-Input Error INDEXA.IMG ; -F-Input Error INDEXB.IMG ...................................................... ;- .Dsabl LSB .SBTTL GETBLK .Enabl LSB ;+ ; ; GETBLK ; Read block INFBLK of INDEX.IMG (logical concatenation of INDEXA.IMG and ; INDEXB.IMG) into BUF. ; ; Input: INFBLK = block number into INDEX.IMG ; ; Output: INFBLK unchanged ; R2 = pointer to INDEX.IMG (INDEXA.IMG or INDEXB.IMG) filename ; c-bit set -> EOF or error reading block ; and ERRBYT contains .READW error code ;- .Enable LSB GETBLK:: MOV R1,-(SP) ;Save R1 for temporary use MOV #IMACHN,R1 ;R1 = channel INDEXA.IMG opened on MOV #RADIMA,R2 ;R2 -> INDEXA.IMG filename MOV INFBLK,-(SP) ;Get block number in INDEXA.IMG file CMP @SP,SWIBLK ;Is block number within INDEXA.IMG? BLO 10$ ;Branch if so SUB SWIBLK,@SP ;Compute blk # within INDEXB.IMG file MOV #IMBCHN,R1 ;@SP = channel INDEXB.IMG opened on MOV #RADIMB,R2 ;R2 -> INDEXB.IMG filename 10$: .READW #IMAREA,R1,#BUF,#BLKSZ/2,(SP)+ ;Read in block MOV (SP)+,R1 ;*C* Restore R1 RETURN ;Return carry and ERRBYT of .READW .Dsabl LSB RADIDX: .RAD50 /IDXINDEX IDX/ ; May get changed to "DK or SY ..." RADIMA: .RAD50 /IMAINDEXAIMG/ ; May get changed to "DK or SY ..." RADIMB: .RAD50 /IMBINDEXBIMG/ ; May get changed to "DK or SY ..." MSGEXT: .ASCII /[r/ MSGCLR: .ASCII /[H/ .ASCII /[J/ MSGTTL: .ASCII /[5;22r/ .ASCII /[1;8H/ .ASCII /[1;7m/ .ASCII /#6/ .ASCII /RT-11 ON-LINE / .NLCSI TYPE=I,PART=ALL .ASCII MSGSEA: .ASCII /[3;H/ .ASCII /[;4m/ .ASCII /Search string:/ .ASCII /[m/ MSGNXT: .ASCII /[;7m/ .ASCII /[27f/ .ASCII /Enter new search string or just press RETURN to scroll/ .ASCII /[m/ MSGINF: .ASCII /[22H/ ;Position to start info display MSGPOS: .ASCII /[3;16H/ ;Position for search string .ASCII /[K/ .ASCII /[m/ MSGERO: .ASCII /[27H/ ;Position for error message .ASCII /[K/ ;Erase last line .ASCII /[4H/ .ASCII /[7m/ MSGERR: .ASCII /[4H/ .ASCII /[K/ ;Erase error message line MSGCLS: .ASCII /[5;H/ .ASCII /[J/ ;Erase information lines NOMAT: .ASCII /No match found/ CRLF: .ASCIZ // ;In FB buffers overlay one-time code, in XM, they are separate ;Buffers and once-only message text. ; *** Buffers overlay the text...watch it! *** .IF EQ MMG$T .ASSUME OUTBUF GT BUF .EVEN BUF: ;1 block buffer, overlays initial text OUTBUF = BUF+1000 ;Output buffer, overlays initial text ; *** Gets overlaid by buffers *** .ENDC ;EQ MMG$T MSGINI: .ASCII /[3;H/ .ASCII /[0;m/ .ASCII /The on-line index data file includes indexes/ .ASCII / from several manuals in the RT-11/ .ASCII /documentation set. The on-line index display/ .ASCII / identifies index entries from each/ .ASCII /manual with a mnemonic:/ .ASCIZ // ;2nd CRLF from ASCIZ MSGIN2: .ASCII .ASCII /The on-line index does not include the entire/ .ASCII / RT-11 documentation set. In/ .ASCII /general, obvious references (for example, the/ .ASCII / KED manual to find out about/ .ASCII /KED, and the commands section of the System/ .ASCII / User's Guide) are omitted./ .ASCII /Type to continue: / .EVEN .SBTTL Book name table ;This table assumes that the books will be identified by standard 3-character ;mnemonics (block 0 of INDEX.IDX, see description of input files). MNETAB is ;a list of 3-character mnemonics and equivalent book titles for all books in ;the RT-11 doc set. The initialization code picks up each mnemonic supplied ;in block 0 of INDEX.IDX and searchs MNETAB for a match. When a match is ;(hopefully!) found, the initialization code displays the corresponding text ;string. (Alphabetical order not important) ; MNETAB: .ASCIZ /DEV Device Handlers/ ;replaces SSM .ASCIZ /GUI Guide to Documentation/ .ASCIZ /INS Installation Guide/ .ASCIZ /INT Introduction to RT-11/ .ASCIZ /MRM Mini-Reference Manual/ .ASCIZ /V5N Online Release Notes (V5NOTE.TXT)/ .ASCIZ /PRM Programmer's Reference/ .ASCIZ /SIM System Internals/ ;replaces SSM .ASCIZ /RLN System Release Notes/ .ASCIZ /SSM Software Support Manual/ ;replaced by DEV,SIM,VFF .ASCIZ /SUG System User's Guide/ .ASCIZ /SUM System Utilities Manual/ .ASCIZ /SYG System Generation Guide/ .ASCIZ /VFF Volume and File Formats/ ;replaces SSM ;Manuals below probably not included in online index, but here for ;completeness: .ASCIZ /BEG RT-11 For Beginners/ .ASCIZ /DBG DBG-11 User's Guide/ .ASCIZ /KED Keypad Editor User's Guide/ .ASCIZ /MAC MACRO-11 Language Manual/ .BYTE 0 .EVEN .SBTTL INIT .enabl LSB ;+ ; INIT ; ; Perform an initialization ; ; Open INDEX.IDX and INDEX.IMG (logical concatenation of INDEXA.IMG and ; INDEXB.IMG) ; ; For INDEX.IDX first tries on IDX:, then DK:, then SY: ; For INDEXA.IMG first tries on IMA:, then DK:, then SY: ; For INDEXB.IMG first tries on IMB:, then DK:, then SY: ; ;- INIT: .SCCA #IOAREA,#TSW ;Catch Control/C's BIC #TTLC$,@#JSW ;No lowercase input BIS #GTLIN$,@#JSW ;Postpone ^C if command line typed .RCTRLO ;Make sure JSW is updated MOV #IOAREA,R3 ;Use IOAREA as .DSTAT status block BIT #FL.RES,FLAGS ;restarting? BNE 10$ ;yes, skip opens MOV #RADIMA,R2 ;R2 -> IMA:INDEXA.IMG MOV #IMACHN,R1 ;R1 channel number for lookup CALL DSTLUK ;Do DSTAT and LOOKUP MOV R0,SWIBLK ;Block number to switch to INDEXB.IMG MOV #RADIMB,R2 ;R2 -> IMB:INDEXB.IMG MOV #IMBCHN,R1 ;R1 channel number for lookup CALL DSTLUK ;Do DSTAT and LOOKUP MOV #RADIDX,R2 ;R2 -> DK:INDEX.IDX .Assume IDXCHN EQ 0 CLR R1 ;Set up channel number for .LOOKUP CALL DSTLUK ;Do DSTAT and LOOKUP 10$: MOV #RADIDX,R2 ;R2 -> DK:INDEX.IDX in case of FNFERR .Assume IDXCHN EQ 0 .READW R3,#0,#BOKBUF,#BOKSIZ,#0 ;Read book id's BCS FNFERR ;Branch if error .PRINT #MSGCLR ;Clear the screen... .PRINT #MSGTTL ;put up header... .PRINT #MSGINI ;print 1st part of initial text... ;Now compare book id's to list of book id's given in "MNETAB". When a ;match is found, print out the line in MNETAB that gives the id plus ;the corresponding book title. MOV #BOKBUF,R1 ; R1 -> book id's MOVB (R1)+,R5 ;Get length byte INC R1 ;Skip unused byte 20$: MOV #MNETAB,R2 ; R2 -> id+title list 30$: MOV R2,R4 ;Save initial pointer value in R4 MOV R1,R3 ;Keep initial pointer value in R1 40$: CMPB (R2)+,(R3)+ ;See if match BNE 50$ ;...if not CMPB #SPC,@R3 ;End of book id? BNE 40$ ;Not yet, keep comparing CMPB #TAB,@R2 ;We should be pointing at a tab char ;in MNETAB now, if all is okay.... BEQ 60$ ;...if okay. ;+ ;ERROR .ERR #ERRARE,#FTL,RETURN=NO,LEVEL=F ; -F-Mismatched book identifier lengths, incompatible data file ...................................... ;- 50$: TSTB (R2)+ ;Scan MNETAB to next 0 byte to find BNE 50$ ;end of text string TSTB @R2 ;Is 0 byte followed by a 0 byte? BNE 30$ ;if not, another string follows ;? Put code in here someday to print non-matching mnemonics from BOKBUF? BR 70$ ;End of MNETAB, see if more in BOKBUF ........... 60$: .PRINT R4 ;Print proper string from MNETAB 70$: ADD R5,R1 ;Point to next book id CMPB #SPC,@R1 ;Space fill after list of book ids... BNE 20$ ;...if not done yet, keep matching. .PRINT #MSGIN2 ;Print end of intial text CALL GETLIN ;Get a line, waiting for or ^C INISCR: ;Initialize screen .PRINT #MSGCLR .PRINT #MSGTTL .PRINT #MSGSEA RETURN ...... .Dsabl LSB .Enabl LSB DSTLUK: CALL DSTLK1 ;Try finding file specified @R2 BCC 50$ ;Branch if file found MOV #^RDK ,@R2 ;change to DK: and try again CALL DSTLK1 ;Try finding file specified @R2 BCC 50$ ;Branch if file found MOV #^RSY ,@R2 ;change to SY: and try again CALL DSTLK1 ;Try finding file specified @R2 BCC 50$ ;Branch if file found .BR FNFERR ...... ;+ ;ERROR FNFERR: .ERR #ERRARE,#FE.FNF,RETURN=NO,LEVEL=F,FILE=R2 ; -F-File not found ................................................. ;- DSTLK1: MOV #FREE,R4 ;Point to free space pointer and MOV R4,R5 ; to tentative handler pointer .Assume CURHND EQ FREE-2 MOV @R4,-(R5) ;Get address to try to fetch into .DSTAT R3,R2 ;See if handler (@R2) is loaded BCS 40$ ;Branch if device is unknown TST 4(R3) ;Is handler in memory? BNE 10$ ;Branch if it is -- use it ADD 2(R3),@R4 ;Add size of handler for new free .SERR ;Trap monitor errors from .FETCH .FETCH @R5,R2 ;Try to fetch handler ROR -(SP) ;Save carry temporarily .HERR ;Don't trap monitor errors any more ROL (SP)+ ;Restore carry from .FETCH return BCS 30$ ;Branch if bad fetch -- dump handler 10$: .LOOKUP R3,R1,R2 ;Open filename pointed to by R2 BCS 20$ ;Branch if file not found TST R0 ;Is channel open file-structured? BNE 50$ ;*C=0* Branch if yes -- ok 20$: .PURGE R1 ;Don't leave channel open CMP @R5,@R4 ;Did we just .FETCH this handler? BEQ 40$ ;If not, just take error return 30$: .RELEAS R2 ;Get rid of handler MOV @R5,@R4 ;Restore free if dumping handler 40$: SEC ;C=1 indicates unable to find file 50$: RETURN .Dsabl LSB .SBTTL DATA ;CURHND and FREE are used temporarily only by DSTLK1. They can be overlaid ;with I/O buffers CURHND: .LIMIT FREE =: CURHND+2 .IF EQ MMG$T ;Buffer space must be 2 blocks long. If text being overlaid is not that ;big, do a .BLKW to fill out to 2-block boundary. .ASSUME BUF LT . .IIF GT <2000-<.-BUF>> .BLKB <2000-<.-BUF>> .IFF ;EQ MMG$T BUF: .BlkW 400 OUTBUF: .BLKW 400 .ENDC ;EQ MMG$T DATA:: ;beginning of data area STRING: .BLKB 81. ;Buffer for user string RECORD: .BLKB MAXREC ;Storage for data record .EVEN IOAREA: .BLKW 6 IMAREA: .BLKW 6 BOKBUF: .BLKW BOKSIZ ;Storage for book names TSW: .WORD SWIBLK: .WORD ;INFBLK block number at which to ; switch I/O from INDEXA.IMG to ; INDEXB.IMG INFBLK: .WORD ;Current block number INFOFF: .WORD ;Current offset FLAGS: .WORD FL.FTT ;Various state flag bits MATFLG: .WORD 0 ;Flags for string match algorithm .SBTTL Error messages ;+ ; Error messages ;- ERRSTP: .ASCII /[K/ ;erase to EOL .NLCSI TYPE=I,PART=PREFIX ;error message prefix LEVERR: .ASCII /X-/<200> ;Level string .EVEN ERRARE::.BYTE 0 ;Error code .BYTE 0 ;ASCII character level .WORD ERRSTP ;-> prefix string .WORD LEVERR ;-> level byte .WORD MSGTAB ;-> message table .WORD 0 ;-> filename .WORD ABORT ;abort exit ;+ ;ERROR MSGLST MSGTAB ERRMSG INV ERRMSG EIR ERRMSG SNF ERRMSG FTL MSGEND ;- .WORD 0 ;An extra word for good luck .END INDEX