.TITLE INSPECT .IDENT /101282/ .ENABL LC ; ; ; Written by Ray Di Marco ; 5-May-82. ; ; ;----------------------------------------------------------------------------- ; ; This module is linked with a user template and the database library to ; produce an inspect program. The program allows the user to specify a ; 'TARGET' string. It will then search through an 'INDEX' file to translate ; the target string into a database record number. The INDEX file is in the ; 'SORTER.DAT' format, and consists of an ascii string and the number of the ; database record associated with the string. ; ; Once the user enters a target, the program uses a binary search technique ; to locate the index file record that most closely matchs the target. The ; user may then advance through the index record, backtrack, enter a new ; target or display the database record associated with the index. ; ; Commands recognized consist of a single letter, and are ; ; B backup one index ; N advance to next index ; S show record associated with index ; T accept a new target ; ; E exit back to menu ; P print screen (VT100 only) ; R refresh screen ; ; The program will also suppport the following escape sequences generated ; by the VT100. (For equivalent keys on other terminals refer to appropriate ; terminal driver.) ; ; up-arrow backup one index ; down-arrow advance to next index ; right-arrow show record associated with index ; left-arrow accept a new target ; ; PF1 print screen (VT100 only) ; PF2 refresh screen ; .SBTTL Modifications ; ; ; 10-Dec-82 change program exit mechanism to bring into line with other ; DBSMNG cusps; program will now terminate if enter only ; as the target or if pressed while examining keys. ; ; .SBTTL Documentation .IF EQ,-1 This module, when linked with the user database template and the database library becomes the program INSPECT, that is used to provide online access to database records. Note that the template may optionally not be linked in when generating the program, in which case the user is requested to enter the name of the file that contains the user template (in .SAV format) when the program is run. The program allows the user to specify an ascii string, called a target; it will then searchs an index file to locate the closest matchs to the specified target. If an exact match is located, the database record associated with the index is automatically displayed. In the event of no exact match, the closest matching index is displayed, and the user may then step forward or backward through the indexs, which are ordered alphabetically, or cause the associated record to be displayed. Upon activation, the program requests that the name of the INDEX file be specified. This file consists of a series of alphabetically ordered indexs. Note that if the program is envoked as a CUSP from a menu program, the name of the index file may be passed through core common. In reality, the index file is a sorter-format data file, consisting of a header block followed by a number of equal lenght records. CUSPS are provived to simplify the generation of such a file. The steps needed to generate one are listed below The database manager must firstly decide upon which fields will be used as access keys. Typically this will be one or more of the ascii fields in the record. An index file will have to be allocated on disk to hold the index records. The pre-allocation of the file allows it to be position on the disk structure for optimum performance. The SELECT cusp is then used to process the database records and extract the contents of the fields that are to be used as access keys and store said data in the index file. Note that loaded data should be converted to upper case by including the appropiate SELECT command in the load sequence. The index file is then passed to the SORTER to sort the entries of extracted data in ascending order. The file is now ready as input to INSPECT. The INSPECT program provides a special facility to the VT100 user, in that it support a 'print' command, that will send the escape sequence to the VT100 that causes lines 4 to 24 to be printed via the printer port. .ENDC .SBTTL Declarations ; ; .MCALL .PRINT,.EXIT ; used for error handling ; ; .GLOBL FORM$$ ; start user template .GLOBL $$FORM ; pointer for rtns .GLOBL DBSLDR ; template loader ; .GLOBL CON.ST,CON.XY,CON.EX,CON.EL,CON.ES ; "CONIO" .GLOBL CON.LO,CON.LI,CON.CO,CON.CI ; "CONIO" .GLOBL FRM.FG,FRM.BG ; "FEDMNG" .GLOBL FIL.DR,FILINT ; "FILEIO" .GLOBL SFLINT,SFLPSN,SFLINP,SFLINC,SFLPAR,SFLNME ; "SRTFIO" ; .PSECT CODE ; open code ; ====== ==== ; ; .SBTTL Macro Definitions ; .MACRO DISPLAY STR,X=0,Y=0,ERASE=NO MOV #+X,R0 .IIF DIF,ERASE,NO, CALL CON.EL CALL CON.XY JSR R1,OUTIT .NLIST BIN .ASCII |'STR'| .BYTE 0 .EVEN .LIST BIN .ENDM DISPLAY ; ; .MACRO PRINT STR .IIF NB,STR, MOV STR,R0 CALL CON.LO .ENDM PRINT ; ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; ; .MACRO FATAL STR,?A,?B .PRINT #'B .EXIT B': .ASCIZ |INSPECT-fatal-'STR'| .EVEN .ENDM FATAL ; .SBTTL Initialization code ; ; ; We must open up the index and database files and initialize ; any other needed modules (such as the console driver). ; START: CALL CON.ST ; initialize TTY interface PRINT #7000$ ; identify self TST $$FORM ; template linked in? BNE 100$ ; yes -> skip GTLIN #..TARG,#7010$ ; get template name MOV #..TARG,R0 ; R0 -> name CALL DBSLDR ; load template MOV R0,$$FORM ; setup pointer 100$: GTLIN #SFLNME,#7100$ ; get name of 'SFL' file ; CALL SFLINT ; OPEN DATA FILE CMP SFLPAR,#3 ; minimum record size = 3 BLO 6000$ ; to small -> abort CMP SFLINT+2,#2 ; need at least 2 records BLOS 6100$ ; not enough -> abort CALL FILINT ; access database files CALL C.RFSH ; refresh CRT screen JMP RESTRT ; enter loop ; ; 6000$: FATAL 6100$: FATAL .NLIST BIN 7000$: .ASCIZ /Inspect RDM101282./ 7010$: .ASCII / DB Template: /<200> 7100$: .ASCII / Index file: /<200> .EVEN .LIST BIN .SBTTL Main Loop Code ; ; Start of by requesting the operator to enter a target string. This ; target is stored in the ..TARG string, and is padded out with ; spaces to the size of an index file record. ; RESTRT: DISPLAY < > 00,1,E ; erase command line DISPLAY 60,0,E ; tell whats needed DISPLAY 00,0 ; prompt MOV #..TARG,R0 ; R0 -> line buffer CALL CON.LI ; input line MOV #..TARG,R0 ; R0 -> line buffer TSTB (R0) ; got any input? BNE 400$ ; yes -> skip JMP CON.EX ; no --> exit ; 400$: MOV SFLPAR,R1 ; R1 = chars/record 1000$: MOVB (R0)+,R2 ; hit terminator? BEQ 1100$ ; yes -> skip CMPB R2,#140 ; LC character? BLO 1040$ ; no -> skip BICB #40,-1(R0) ; convert UC 1040$: SOB R1,1000$ ; loop till all done BR 2000$ ; seach time 1100$: DEC R0 ; R0 -> 1110$: MOVB #40,(R0)+ ; pad out rest of line SOB R1,1110$ ; loop till all padded BR 2000$ ; search time ; ; ; Initiate search for target in index file. Find sets the 'Z' and ; 'C' flags by comparing number of matchs found against constant 1. ; 2000$: DISPLAY 60,0 ; tell whats needed CALL FIND ; find best match BLO 2200$ ; not found -> 4000$ BNE 2100$ ; more than 1 -> 2000$ DISPLAY 60,0 ; tell found CALL C.SHOW ; show data JMP 3200$ ; get command 2100$: DISPLAY 60,0 ; tell found CALL C.SHOW ; show data JMP 3200$ ; get command 2200$: DISPLAY 60,0 ; tell failed JMP 3100$ ; go get commands ; ; ; ; This is the command dispatch section. We input a character from the ; keyboard and dispatch to appropriate routine via 7000$ table. ; 3000$: DISPLAY < > 00,0,E ; erase top line 3100$: DISPLAY 00,0 ; Header PRINT #..INDX ; display index 3200$: DISPLAY 60,1 ; show options DISPLAY 00,1 ; Prompt 3300$: CALL CON.CI ; get a character MOV #7000$,R1 ; R1 -> table 3310$: CMPB R0,(R1) ; match? BEQ 3320$ ; yes -> skip ADD #4,R1 ; R1 -> next entry TST (R1) ; eot? BNE 3310$ ; no -> try again BR 3300$ ; get another command 3320$: CALL @2(R1) ; envoke routine BR 3000$ ; loop ; ; ; Command disptach table, consisting of command letter and subroutine ; addresses. ; 7000$: .WORD 15,C.EXIT ; exit .WORD 'E,C.EXIT ; exit .WORD 'P,C.PRNT ; print .WORD 'R,C.RFSH ; Refresh screen ; .WORD 'P+200,C.PRNT ; PF1 .WORD 'Q+200,C.RFSH ; PF2 .WORD 'R+200,C.RFSH ; PF3 ; .WORD 'B,C.PREV ; backup one ... .WORD 301,C.PREV ; ... index .WORD 'N,C.NEXT ; forward one ... .WORD 302,C.NEXT ; ... index .WORD 'T,C.TARG ; Accept a new ... .WORD 304,C.TARG ; ... target .WORD 'S,C.SHOW ; Display record ... .WORD 303,C.SHOW ; ... for index .WORD 0,0 ; .SBTTL Command Routine - "C.TARG" ... define a new target ; ; This routine is called to allow the user to define a new ; target string. This is implemented by restarting the program. ; C.TARG: TST (SP)+ ; clean up stack JMP RESTRT ; restart time ; ; .SBTTL Command Routine - "C.EXIT" ... exit to menu ; ; C.EXIT: JMP CON.EX ; exit time ; ; .SBTTL Command Routine - "C.RFSH" ... refresh screen ; ; This routine is used to refresh the screen (after it gets mucked ; by by a power fail etc). The routine repaints the fixed part of ; the screen. ; C.RFSH: CALL CON.ES ; erase screen MOV $$FORM,R0 ; R0 -> template CALL FRM.BG ; display BG DISPLAY 60,2 ; identify self MOV $$FORM,R0 ; R0 -> Template ADD #40,R0 ; R0 -> DBS name PRINT R0 ; identify file RETURN ; exit ; ; .SBTTL Command Routine - "C.PRNT" ... Print data on printer ; ; C.PRNT: CMP #^RV10,@#542 ; VT100? BNE 1000$ ; NO -> skip .PRINT #7000$ ; send print command 1000$: RETURN ; exit ; .NLIST BIN 7000$: .ASCII <33>/[5i/<12><15><33>/[4i/ ; position head .ASCII <33>/[0;4;24i/ ; dump screen .ASCII <33>/[5i/ .ASCII <12><12><12><12><12><12><12><12><12><12> .ASCII <15><33>/[4i/ ; leave few lines .ASCIZ // .EVEN .LIST BIN ; .SBTTL Command Routine - "C.SHOW" ... Display Record on Screen ; ; This routine is called to display the contents of the currently ; selected record on the screen. ; C.SHOW: MOV ..RECN,R0 ; R0 = record number CALL FIL.DR ; read record MOV $$FORM,R0 ; R0 -> template MOV (R0),R5 ; R5 -> buffer CALL FRM.FG ; display record RETURN ; all done ; ; .SBTTL Command Routine - "C.NEXT" ... get next index ; ; ; Read in next index record. ; C.NEXT: MOV ..INDN,R0 ; R0 = index number INC R0 ; bump up by 1 CMP R0,SFLPAR+2 ; reached limit BHI 1000$ ; yes -> skip MOV R0,..INDN ; save index id CALL SFLPSN ; position file MOV SFLPAR,R1 ; R1 = rec size MOV #..RECN,R0 ; R0 -> buffer CALL SFLINP ; input record ADD SFLPAR,R0 ; R0 -> end of input CLRB (R0) ; terminate MOV ..INDN,R0 ; R0 = index number CALL SFLPSN ; position file TST ..MTCH ; in match md BEQ 1000$ ; no -> skip DEC ..MTCH ; used 1 more CALL C.SHOW ; display 1000$: RETURN ; all done ; ; .SBTTL Command Routine - "C.PREV" ... backup one index ; C.PREV: CLR ..MTCH ; disable m.md MOV ..INDN,R0 ; R0 = index number DEC R0 ; bump up by 1 BEQ 1000$ ; skip illegal MOV R0,..INDN ; save index id CALL SFLPSN ; position file MOV SFLPAR,R1 ; R1 = rec size MOV #..RECN,R0 ; R0 -> buffer CALL SFLINP ; input record ADD SFLPAR,R0 ; R0 -> end of input CLRB (R0) ; terminate MOV ..INDN,R0 ; R0 = index number CALL SFLPSN ; position file 1000$: RETURN ; all done ; ; .SBTTL Primitive - "OUTIT" ... output error messages ; OUTIT: MOVB (R1)+,R0 ; fetch BEQ 1000$ ; -> skip CALL CON.CO ; output R0 BR OUTIT ; loop 1000$: INC R1 ; ensure that R1 is .. BIC #1,R1 ; .... even RTS R1 ; all done ; .SBTTL Primitive - "FIND" ... find for target ; ; FIND: MOV SFLPAR+2,R4 ; R4 = number of entries CALL 5000$ ; R4 = R4 / 2 MOV R4,R3 ; R3 = starting entry ; 2000$: CMP R3,SFLPAR+2 ; in range? BLOS 2010$ ; yes -> skip MOV SFLPAR+2,R3 ; force into range 2010$: MOV R3,R0 ; R0 = next entry to search CALL SFLPSN ; position on entry R0 CALL 5000$ ; R4 = step size BEQ 2400$ ; out of steps -> done ADD R4,R3 ; assume going to step up CALL 5400$ ; compare TAR to REC BHI 2000$ ; TAR > REC -> step up SUB R4,R3 ; we are not stepping up ... SUB R4,R3 ; ... we are stepping down BGT 2000$ ; loop not wrapped arround MOV #1,R3 ; don't allow wrap arround BR 2000$ ; loop ; ; 2400$: CMP R3,#1 ; at first entry? BHI 2440$ ; no -> skip MOV #2,R3 ; force to second 2440$: DEC R3 ; skip back 1 record CLR ..MTCH ; no matchs as yet DEC R3 ; preloop fudge 2500$: INC R3 ; try next record CMP R3,SFLPAR+2 ; all done? BHI 2600$ ; yes -> terminate MOV R3,R0 ; R0 = match area CALL SFLPSN ; position file CALL 5400$ ; compare TAR with REC BLO 2700$ ; TAR < REC -> terminate BHI 2500$ ; TAR > REC -> loop INC ..MTCH ; found another match CMP ..MTCH,#1 ; first match found BNE 2500$ ; no -> loop MOV R3,..INDN ; save address of first match BR 2500$ ; loop ; 2600$: MOV SFLPAR+2,R3 ; ensure have legal index 2700$: TST ..MTCH ; have any matchs? BNE 2710$ ; yes -> skip MOV R3,..INDN ; use best match 2710$: MOV ..INDN,R0 ; R0 = best match CALL SFLPSN ; position file MOV SFLPAR,R1 ; R1 = number bytes/record MOV #..RECN,R0 ; R0 -> buffer CALL SFLINP ; input record/index ADD SFLPAR,R0 ; R0 -> end of input CLRB (R0) ; terminate record MOV ..INDN,R0 ; R0 = best match CALL SFLPSN ; position file CMP ..MTCH,#1 ; should only have 1 match RETURN ; exit ; ; ; 5000$: CMP R4,#1 ; last step = 1? BEQ 5040$ ; yes -> skip INC R4 ; R4 = number+1 5040$: ASR R4 ; R4 = number/2 rounded up BIC #100000,R4 ; ensure sign bit clear RETURN ; bye ; ; 5400$: MOV SFLPAR,R2 ; R2 = record size MOV #..TARG,R1 ; R1 = TARGET CALL SFLINC ; discard first byte CALL SFLINC ; discard second byte SUB #2,R2 ; 2 bytes not to check 5600$: CALL SFLINC ; R0 = next input character CMPB (R1)+,R0 ; comp TAR to REC byte BNE 5700$ ; skip no match SOB R2,5600$ ; loop if matched 5700$: RETURN ; all done ; .SBTTL Data Structures ; ; $$FORM: .WORD FORM$$ ; address user template ..TARG: .BLKB 100 ; Target to be found ..MTCH: .WORD 0 ; number of matchs ..INDN: .WORD 0 ; number of current index record ..RECN: .WORD 0 ; database record number for index ..INDX: .BLKB 100 ; index ; ; .END START