;
; Copyright © 1991, 1992 by Walter Rothe. You may freely use and modify this
; program, but not for commercial profit. A modest fee for distribution is
; allowed. Derivative works must be released with source along with the
; executable or provisions made to provide the user source, if requested.
; Uploading source to a major bulletin board system within 6 months of the
; time of the request satisfies this requirement. This copyright notice
; must not be deleted from the source.
;
; Returns major term index if keyword match found, 2/3 if article delimiter
; found, and 4/5 if end of buffer pattern found. With the max number of major
; terms being 128, you would expect the major term index returned to be less
; than 256. However, duplicate keyword entries can have a major term index
; greater than 256.
        FAR     DATA
        XDEF    _FastSearch
_FastSearch:
        LINK    A5,#.2
        MOVEM.L .3,-(SP)
        CLR.W   D3
        CLR.L   D2
        CLR.L   D1
        CLR.L   D0
        MOVEA.L 8(A5),A0       ;Argument #1
        LEA     _SubPat,A1     ;64kb indexed by two chars
        LEA     _LowrCs,A4     ;Table to convert to lower case
JLOOP:  LEA     _DsplTb,A2     ;Displ to 1st char of keyword
        LEA     _FrstBt,A3     ;Table with 1st byte of keywords
        LEA     _ScndBt,A6     ;Table with 2nd byte of keywords
; Begin checking input stream for specific two char patterns.
ILOOP:  MOVE.W  (A0)+,D1       ; 8 clocks on 68K @ 7MHZ
        MOVE.B  0(A1,D1.L),D2  ; 14 clocks; Get maj term index
        BEQ     ILOOP          ; 10 clocks
; Since a two char match was found, go check to see if 1st 2 bytes of keyword
; matches the char at the predicted place in the input steam where it should
; be if the whole word matched. This is done for speed.
        MOVE.B  0(A2,D2.W),D0  ;Get displacement to 1st byte
        BEQ     DUPLIC         ;Check for duplicate two chars
        MOVE.B  -128(A0,D0.W),D3 ;1st char of keyword to be chkd
        MOVE.B  0(A4,D3.W),D3  ;Convert to lower case
        CMP.B   0(A3,D2.W),D3  ;Compare 1st byte
        BNE     ILOOP          ;Loop if 1st byte did not match
        MOVE.B  -127(A0,D0.W),D3 ;2nd char of keyword to be chkd
        MOVE.B  0(A4,D3.W),D3  ;Convert to lower case
        CMP.B   0(A6,D2.W),D3  ;Compare 2nd byte
        BNE     ILOOP          ;Loop if 2nd byte did not match
; Go check if the rest of the keyword matches with a less speed efficient code.
        MOVE.L  D2,D4          ;Major term number
        LSL.L   #3,D4          ;Index by long words(2 per)
        LEA     _KWTbl,A2      ;Address of keyword table of pointers
        MOVEA.L 0(A2,D4.L),A6  ;Addr of rest of keyword(may be 2 when null)
        MOVEA.L 4(A2,D4.L),A2  ;Address of "End of keyword"(may be 0 for null)
        LEA     -126(A0,D0.W),A3 ;Address of 3rd byte to test
FCMP:   CMPA.L  A6,A2          ;Finished comparing all of keyword?
        BLT     MATCH          ;Yes, so must have matched.
        MOVE.B  (A3)+,D3       ;Next byte from input stream
        MOVE.B  0(A4,D3.W),D3  ;Convert to lower case
        CMP.B   (A6)+,D3
        BNE     JLOOP          ;Jump on miscompare
        JMP     FCMP
MATCH3: SUBA.L  #_DKWTbl+12,A6 ;Get index into dup kw tbl
        MOVE.L  A6,D0
        LSR.L   #4,D0          ;Get major term #
        MOVE.L  A0,_BufIdx     ;Update index into buffer
        MOVEM.L (SP)+,.3
        UNLK    A5
        RTS
MATCH:  MOVE.L  D2,D0          ;Return major term number
        MOVE.L  A0,_BufIdx     ;Update index into buffer
        MOVEM.L (SP)+,.3
        UNLK    A5
        RTS
; Comes here when more than one keyword has the same two char sub-pattern(>5),
; if the two char sub-pattern of the article separator is found(2/3), or if
; the end of buffer delimiter is found(4)
DUPLIC: CMPI.W  #4,D2          ;Major term number < 4?
        BGE     NOTART         ;Jump if not article separator
        MOVE.L  _ArtSep,A2     ;Addr of rest of article separator
        MOVE.L  _EOASep,D4     ;Addr of last byte of article separator to test
        LEA     _DFASep,A3     ;Displacement to rest of art sep to check in buf
        MOVE.B  -2(A3,D2.W),D0 ;
        LEA     -128(A0,D0.W),A3 ;Address of 1st byte to test
FCMP4:  CMP.L   A2,D4          ;Finished comparing all of keyword?
        BLT     MATCH2         ;Yes, so must have matched.
        CMPM.B  (A2)+,(A3)+
        BEQ     FCMP4          ;Jump if same
        JMP     JLOOP
;
NOTART: CMPI.W  #6,D2
        BLT     EOB            ;Jump if maj term number is 4 or 5
        LSL.L   #4,D2          ;4 long words per entry
        MOVEA.L D2,A6
        ADDA.L  #_DKWTbl,A6    ;Addr of 1st dupl keyword pointers
FCMP3:  MOVEA.L (A6)+,A2       ;Addr of 1st byte of keyword
        MOVE.L  (A6)+,D4       ;Addr of last byte of keyword
        MOVE.L  (A6)+,D0       ;Displacement to rest of keyword to test
        LEA     -128(A0,D0.W),A3 ;Address of 1st byte to test
FCMP2:  CMP.L   A2,D4          ;Finished comparing all of keyword?
        BLT     MATCH3         ;Yes, so must have matched.
        MOVE.B  (A3)+,D3       ;Next byte from input stream
        MOVE.B  0(A4,D3.W),D3  ;Convert to lower case
        CMP.B   (A2)+,D3
        BEQ     FCMP2          ;Jump if same
        TST.L   (A6)           ;Addr of next dupl keyword data
        BEQ     JLOOP
        MOVEA.L (A6),A6
        JMP     FCMP3
EOB:    MOVEA.L _EOCB,A2       ;Get address of EOB
        CMPA.L  A2,A0          ;Did EOB really occur or is it user data
        BLT     JLOOP          ;Jump if not
MATCH2: MOVE.L  D2,D0          ;D2 is 2/3 for article sep and 4 or 5 for EOB
        MOVE.L  A0,_BufIdx     ;Update index into buffer
        MOVEM.L (SP)+,.3
        UNLK    A5
        RTS
.2      EQU     0
.3      REG     A2/A3/A4/D4
;
        DSEG
        XREF    _SubPat
        XREF    _LowrCs
        XREF    _DsplTb
        XREF    _FrstBt
        XREF    _ScndBt
        XREF    _KWTbl
        XREF    _DKWTbl
        XREF    _EOCB
        XREF    _ArtSep
        XREF    _EOASep
        XREF    _DFASep
        XREF    _BufIdx
        END


