.TITLE VTLFND - Find Search String .IDENT /1.11/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided or ; otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: VTLFND.MAC ; Author: Robin Miller ; Date: June 30, 1983 ; ; Description: ; ; This module contains the routines neccessary to prompt for and ; find a specified search string. ; ;- .ENABL AMA .NLIST BEX ;+ ; ; Modification History: ; ; December 3, 1985 by Robin Miller. Edit (09), Version 1.11 ; Add a search string buffer for searching for next page (FF). ; We were using the format buffer for holding the foemfeed, but ; this buffer gets overwritten by the "Working" message. ; ; June 14, 1984 by Robin Miller. Edit (08), Version 1.10 ; Ignore the error return from the GETCMD routine so CTRL/C and ; CTRL/U are handled properly. ; ; June 7, 1984 by Robin Miller. Edit (07), Version 1.9 ; Add calls to the timer routines for displaying working message. ; ; June 5, 1984 by Robin Miller. Edit (06), Version 1.8 ; Call routines MRKFND/PNTFND to save/restore the last search ; record context. ; ; June 2, 1984 by Robin Miller. Edit (05), Version 1.7 ; Use common routine to Get/Mark the next input record. ; ; May 31, 1984 by Robin Miller. Edit (04), Version 1.6 ; Implement searching backwards through the file. ; ; May 30, 1984 by Robin Miller. Edit (03), Version 1.5 ; Break search routine into several routines in preparation for ; searching backwards. ; ; May 29, 1984 by Robin Miller. Edit (02), Version 1.4 ; If the search string is active and is on the first line on the ; screen, start the search at the next record instead of the top ; of screen record number. ; ; May 23, 1984 by Robin Miller. Edit (01), Version 1.3 ; If the search routine changes the margin indent so the string ; can be displayed, show the margin indent so the user knows. ; ; October 1983 by Robin Miller. Edit (xx), Version 1.2 ; Don't shift the margin if the search string ends at the last ; column on the screen. ; ; September 1983 by Robin Miller. Edit (xx), Version 1.1 ; Reset search string pointer for next record to search to prevent ; an "Access Violation". ; ;- ; Local equates: KEY4 = 't ; The ADVANCE key. KEY5 = 'u ; The BACKUP key. ; Local storage: SAVREC::.BLKW 2 ; Saved previous record number. (04) RCOUNT::.WORD 0 ; Record count for backward search.(04) FNDMSG: .ASCIZ %Search for: % NTFND1: .ASCIZ %String "% NTFND2: .ASCIZ %" was not found. % FORWM: .ASCIZ %(Forward)% ; Show direction (04) BACKM: .ASCIZ %(Backward)% ; of search. (04) PAGBUF: .ASCIZ ; For searching for next page. (09) .EVEN .SBTTL FNDCMD - Find a search string. ;+ ; ; FNDCMD - Find a search string. ; ; This routine is called from the table parser to find a search string. ; ; Format: ; FIND ! Prompt user for string. ; FIND search_string ! Find the specified string. ; ; Inputs: ; R3 = The remaining string byte count. ; R4 = The string buffer address. ; ; Outputs: ; All registers are preserved. ; ;- FNDCMD::TST R3 ; Is there a search string ? BEQ FNDPR ; If EQ, no (prompt for one). MOV #FNDBUF,R0 ; Set address of the find buffer. 10$: MOVB (R4)+,(R0)+ ; Copy the search string. SOB R3,10$ ; Loop until done. BR FNXCMD ; Now go search for the string. FNDPR:: ; Entry to prompt for search string. MOV #FNDMSG,R1 ; Set address of the prompt string. CALL WRTPRL ; Write the prompt to the terminal. MOV #FNDBUF,R0 ; Set the input buffer address. MOV #FNDSIZ,R1 ; Set the maxiumum byte count. BIS #B.SRCH,STATUS ; Show prompting for search string. CALL GETCMD ; Request the search string. BIC #B.SRCH,STATUS ; Reset search string prompt flag. ;(08) BCS 100$ ; If CS, error or time to exit. ; Check for change of direction keys (key 4/5 = Advance/Backup). TST R1 ; Did the user input anything ? BEQ 90$ ; If EQ, no. (04) MOV IENTRY,R2 ; Copy the file entry adddress. (04) BIC #S.SRCH,(R2) ; Init search string active flag(04) CMP TIOSB,#IS.ESQ ; Terminated by escape sequence?(04) BNE 20$ ; If NE, no. (04) ADD R1,R0 ; Point to end of input buffer. (04) DEC R0 ; Point to the last character. (04) CMPB #KEY4,(R0) ; Terminated by ADVANCE key ? (04) BNE 10$ ; If NE, no. (04) BIS #S.FORW,(R2) ; Yes, set forward direction. (04) 10$: CMPB #KEY5,(R0) ; Terminated by BACKUP key ? (04) BNE 20$ ; If NE, no. (04) BIC #S.FORW,(R2) ; Yes, set backup direction. (04) 20$: BR FNXCMD ; Go search for the string. (04) 90$: BIS #B.DOPR,STATUS ; Nope, show we should reprompt. 100$: RETURN ; Find the first/next occurance of a search string. FNXCMD::JSR R5,$SAVRG ; Save R3 - R5. MOV IENTRY,R5 ; Set the file entry address. TSTB FNDBUF ; Is there a search string ? BEQ FNDPR ; If EQ, no (prompt user for one). CALL MRKSAV ; Save the current record position ; so we can return here on failure. ; If search string is active, start next search from end of last. BIT #S.SRCH,(R5) ; Is a search string active ? BEQ 40$ ; If EQ, no. CMP O.FREC(R5),O.TOPR(R5) ; Yes, possibly this record ? BNE 40$ ; If NE, no. CMP O.FREC+2(R5),O.TOPR+2(R5) ; Is search string on the screen ? BLO 40$ ; If LO, no. (02) CMP O.FREC(R5),O.CREC(R5) ; Is it possibly this record ? BNE 40$ ; If NE, no. CMP O.FREC+2(R5),O.CREC+2(R5) ; Is it really this record ? BHI 40$ ; If HI, no. CALL PNTFND ; Position to the search record.(06) BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 30$ ; If NE, yes. (04) MOV O.FREC(R5),SAVREC ; Copy the search (04) MOV O.FREC+2(R5),SAVREC+2 ; string record number. (04) BR 50$ ; Now go do the search. (04) ; Searching forward, get ready to read record after search record. 30$: CALL GETM ; Read the the search record. (06) ;(06) MOV O.FREC(R5),WTGREC ; Copy the search ;(06) MOV O.FREC+2(R5),WTGREC+2 ; string record number. ;(06) ADD #1,WTGREC+2 ; Start one record ;(06) ADC WTGREC ; beyond search record. ;(06) CALL POINTR ; Point to the search record. BR 50$ ; Now do the search. ; Search string not active or not on the screen. 40$: BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 45$ ; If NE, yes. (04) MOV O.TOPR(R5),SAVREC ; Copy the high and (04) MOV O.TOPR+2(R5),SAVREC+2 ; low record number. (04) BR 50$ ; And continue ... (04) 45$: CALL PNTTOP ; Point to the top of page record. 50$: MOV #FNDBUF,R2 ; Set search string buffer address. CALL SEARCH ; Go search for it. BCC 60$ ; If CC, the string was found. CALL PNTSAV ; Else, reposition last dot. BIC #S.SRCH,(R5) ; Show no search string is active. TST STATUS ; Was CTRL/C typed to abort search ? BMI 55$ ; If MI, yes. ; Report the search string not found error. MOV #NTFND1,R1 ; Set address of "String " message. MOV #FNDBUF,R2 ; Set address of the search string. MOV #NTFND2,R3 ; Set address of " not found" message. MOV #FORWM,R4 ; Set address of "Forward" message.(04) BIT #S.FORW,(R5) ; Did we search forward ? (04) BNE 52$ ; If NE, yes. (04) MOV #BACKM,R4 ; No, set "Backward" msg addr. (04) 52$: CALL WRT4MS ; Display them at the terminal. (04) 55$: BIS #B.DOPR,STATUS ; Show we should prompt user again. RETURN 60$: BIS #S.SRCH,(R5) ; Show a search string is active. MOV O.MARG(R5),R0 ; Save the margin indent count. (03) CALL DOMARG ; Check the margin indentation. (03) MOV R5,R2 ; Copy the file entry address. MOV O.LMAX(R5),R1 ; Copy the maximum line count. ASR R1 ; Backup half a page to center CALL BACKUP ; the search string on the screen. ; This routine also clears the screen. CMP O.MARG(R5),R0 ; Was margin indent changed ? (01) BEQ 100$ ; If EQ, no (continue ...) (01) CALL CHKRUL ; Repaint the ruler if active. (01) CALL SHOMAR ; Show the margin indent count. (01) CALL WRTTOP ; Position to top of window. (01) 100$: RETURN .SBTTL PAGCMD - Find the next page. ;+ ; ; PAGCMD - Find the next page. ; ; This routine is called from the table parser to find the next page. ; ; Inputs: ; None. ; ; Outputs: ; All registers are preserved. ; ;- PAGCMD::JSR R5,$SAVRG ; Save R3 - R5. MOV IENTRY,R5 ; Set the file entry address. MOV R5,R2 ; Copy the file entry address. (04) CALL CHKTB ; Check for top/bottom of file. (04) BCC 3$ ; If CC, OK to do the search. (04) BIS #B.DOPR,STATUS ; Set to reprompt the user. (04) RETURN ; And return ... (04) 3$: BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 5$ ; If NE, yes. (04) MOV O.TOPR(R5),SAVREC ; Copy the high and (04) MOV O.TOPR+2(R5),SAVREC+2 ; low record number. (04) SUB #1,SAVREC+2 ; Point to previous record (04) SBC SAVREC ; incase it contains formfeed.(04) BR 7$ ; And continue ... (04) ; The top record is skipped incase it contains a formfeed. 5$: CALL PNTTOP ; Point to top of page record. CALL GETM ; Get/Mark the next record. (05) BCS 10$ ; If CS, error or end of file. 7$: MOV #PAGBUF,R2 ; Set address of page buffer. (09) CALL SEARCH ; Go do the search. BCS 20$ ; If CS, not found or CTRL/C typed. BIC #S.SRCH,(R5) ; Show no search string is active. CALL CLRWIN ; Clear the active display window. ; ; Now check for a formfeed at the end of the line: ; - by itself will start print at next line. ; text - " " " " ; text - the current line is printed (macro/bliss listings). ; MOV O.FDB(R5),R0 ; Copy the FDB address. MOV F.NRBD+2(R0),R1 ; Copy the record buffer address. ADD F.NRBD(R0),R1 ; Point to end of the record. DEC R1 ; Point at the last byte. CMPB (R1),#FF ; Is the last byte a formfeed ? BEQ 10$ ; If EQ, yes (we're done). CALL PNTFND ; Position before search record. (06) ;(06) CALL WRTBUF ; No, write the current record. ;(06) MOV O.CREC(R5),O.TOPR(R5) ; Copy the current ;(06) MOV O.CREC+2(R5),O.TOPR+2(R5) ; record number. ;(06) BIC #S.STOP,(R5) ; Show the top of page is setup. 10$: RETURN ; The next page was not found, or CTRL/C was typed to abort. 20$: TST STATUS ; Was CTRL/C typed to abort search ? BPL 100$ ; If PL, no (string was not found). CALL CLRWIN ; Clear the active display window. RETURN 100$: BIT #S.FORW,(R5) ; Did we search forward. (04) BNE 110$ ; If NE, yes. (04) JMP TOPCMD ; No, go to top of file. (04) 110$: JMP DOEOF ; Else, do end of file processing. .SBTTL SEARCH - Search for a specified pattern. ;+ ; ; SEARCH - Search for a specified pattern. ; ; This routine will search forward from the current record looking for ; a match for the specified pattern. ; ; Inputs: ; R2 = Address of search string (terminated by NULL). ; R5 = The file entry address. ; ; Implicit Inputs: ; If searching backwards: ; SAVREC = the starting record to start search. ; ; Outputs: ; C bit clear/set = string found/not found or CTRL/C typed. ; ; All registers are preserved. ; ;- SEARCH::CALL $SAVAL ; Save all registers. CALL STIMER ; Start working message timer. (07) MOV R2,R0 ; Copy the search string address. CALL GETLEN ; Get the string byte count. MOV R1,O.FSIZ(R5) ; Save the search string size. CLR R0 ; Search string found flag. (04) ; If we're searching backwards, we have to backup some records. BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 20$ ; If NE, yes. (04) 10$: TST R0 ; Previously find a string ? (04) BNE 40$ ; If NE, yes (we're done). (04) CALL DOBACK ; Backup to previous record. (04) BCS 90$ ; If CS, we're at top of file. (04) ; Read the next record and do the compare. 20$: CALL MRKPRV ; Mark previous record position.(04) CALL GETM ; Get/Mark the next record. (05) BCS 90$ ; If CS, error or end of file. TST STATUS ; Was CTRL/C typed to abort ? BMI 90$ ; If MI, yes (stop searching). CALL DOCOMP ; Do the string comparision. (03) BCC 30$ ; If CC, found the string. (04) BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 20$ ; If NE, yes (continue ...) (04) DEC RCOUNT ; Adjust the record count. (04) BGT 20$ ; If GT, read the next record. (04) BR 10$ ; Else, backup to next entry. (04) ; Found the specified search string. 30$: CALL MRKFND ; Save search record context. (06) MOV R3,O.FEND(R5) ; Save ending search string address. SUB O.FSIZ(R5),R3 ; Calculate the starting address. MOV R3,O.FBEG(R5) ; And save it for format routine. ; If searching backwards, make sure this is the last occurance. BIT #S.FORW,(R5) ; Are we searching forward ? (04) BNE 50$ ; If NE, yes. (04) DEC RCOUNT ; Any more records to search ? (04) BEQ 50$ ; If EQ, no (we're finished). (04) INC R0 ; Show search string was found. (04) BR 20$ ; And search for next occurance.(04) ; Point to last search string found searching backwards. 40$: CALL PNTFND ; Point to search string record.(06) CALL GETM ; Reread the search record. (05) 50$: CALL CTIMER ; Cancel working message timer. (07) CLC ; Show a search string was found. BR 100$ ; And use common return ... ; Did not find the specified search string. 90$: CALL CTIMER ; Cancel working message timer. (07) SEC ; Show search string was not found. 100$: RETURN .SBTTL DOBACK - Do backup for searching. ;+ ; ; DOBACK - Do backup for searching. ; ; This routine backs up to a previously marked record position for ; implementing backward searching. ; ; Inputs: ; R5 = The file entry address. ; ; Outputs: ; C bit clear/set = Ok to search/top of file. ; All registers are presevered. ; ; Implicit Outputs: ; SAVREC - Last record positioned to. ; RCOUNT - Number of records to search. ; ;- DOBACK::CALL $SAVAL ; Save all registers. MOV SAVREC,R0 ; Copy the high and MOV SAVREC+2,R1 ; low record number. TST R0 ; Possibly at top of file ? BNE 10$ ; If NE, no. CMP R1,#1 ; Really at top of file ? BLOS 90$ ; If LOS, yes (0 or 1). 10$: MOV R0,R2 ; Save the MOV R1,R3 ; record number. DIV O.MARK(R5),R0 ; Calculate the mark table entry ; R0 = The quotient (table entry) ; R1 = The remainder. TST R1 ; Currently at a marked record ? BNE 20$ ; If NE, no. MOV O.MARK(R5),RCOUNT ; Set number of records to search. SUB O.MARK(R5),R3 ; Yes, backup to SBC R2 ; previously marked record. BR 30$ ; And continue ... 20$: MOV R1,RCOUNT ; Set number of records to search. SUB R1,R3 ; Calculate the record SBC R2 ; number to go to. ; At top of file, we must adjust the records to search by 1. 30$: TST R0 ; Is this the first table entry ? BNE 40$ ; If NE, no. DEC RCOUNT ; Yes, adjust record count by one. 40$: MOV R2,SAVREC ; Save this MOV R3,SAVREC+2 ; record number. MOV R2,WTGREC ; Setup the record MOV R3,WTGREC+2 ; number to go to. CALL POINTR ; Point to this record number. CLC ; Show success. BR 100$ ; And use common return ... 90$: SEC ; Show we're at top of file. 100$: RETURN .SBTTL DOCOMP - Do the string compare. ;+ ; ; DOCOMP - Do the string compare. ; ; This routine reads the next input record and searchs for a substring. ; ; Inputs: ; R2 = The search string address. ; R5 = The file entry address. ; ; Outputs: ; C bit clear/set = string found/not found. ; R3 = The ending search string address within the record. ; R4 is destroyed, all other registers are preserved. ; ;- DOCOMP::JSR R2,$SAVVR ; Save R0 - R2. MOV O.FDB(R5),R0 ; Copy the FDB address. MOV F.NRBD+2(R0),R3 ; Copy the record address MOV F.NRBD(R0),R4 ; and the byte count. BEQ 90$ ; If EQ, it's a blank record. CMP R4,O.FSIZ(R5) ; Record smaller than search string ? BLT 90$ ; If LT, yes (get the next record). MOV #TMPBUF,R0 ; Set address of temporary buffer. MOV R2,R1 ; Save the search string address. ; Search for the specified pattern. 20$: TSTB (R2) ; At end of the search string ? BEQ 100$ ; If EQ, yes (string was found). DEC R4 ; Exceeding end of this record ? BMI 90$ ; If MI, yes (string was not found). MOVB (R3)+,(R0) ; Copy the next record character. BICB #^C177,(R0) ; Clear the parity bit (if any). ; Convert lowercase to uppercase so compare will work. BIT #B.XACT,SWMASK ; Are we doing an exact search ? BNE 30$ ; If NE, yes (don't do conversion). CALL CUCHAR ; Convert character to upper case. 30$: CMPB (R2)+,(R0) ; Does this character match ? BEQ 20$ ; If EQ, yes (check the next byte). MOV R1,R2 ; No, restore the starting address. ; Compare failed, see if start of search string matches. CMPB (R2),(R0) ; Does start of search string match ? BNE 20$ ; If NE, no (next record character). INC R2 ; Yes, start at the second character. BR 20$ ; And start the compare again ... 90$: SEC ; Show string was not found. 100$: RETURN .SBTTL DOMARG - Check for margin indentation. ;+ ; ; DOMARG - Do the margin indentation. ; ; After a search string is found, this routine is called to determine if ; the search string will be displayed on the screen. If not, the margin ; is adjusted so it will be displayed and the user is informed of the ; margin change. ; ; Inputs: ; R5 = The file entry adrdress. ; ; Outputs: ; All registers are preserved. ; ;- DOMARG: CALL $SAVAL ; Save all registers. MOV O.FDB(R5),R4 ; Copy the FDB address. MOV F.NRBD+2(R4),R0 ; Copy the buffer address. MOV O.FBEG(R5),R1 ; Copy the starting buffer address. SUB R0,R1 ; Calculate bytes into the record. CALL CALPOS ; Calculate the real position. ; R2 = Calculated character count. MOV R2,R1 ; Copy the calculated position. SUB O.MARG(R5),R1 ; Is string left of the margin ? BMI 10$ ; If MI, yes (adjust it). ADD O.FSIZ(R5),R1 ; Add the search string size. CMP R1,O.LWID(R5) ; Will the string be displayed ? BLE 20$ ; If LE, yes (leave margin alone). 10$: MOV R2,O.MARG(R5) ; Adjust margin to display string. 20$: RETURN .END