EXTERNAL INTEGER FN MATCH ADDR (INTEGER PATTERN ADDRESS, PATTERN LENGTH, C
RANGE ADDRESS, RANGE LENGTH)
! Scans a row of RANGE LENGTH bytes at RANGE ADDRESS to find the first
! slice which matches the pattern of PATTERN LENGTH bytes at PATTERN ADDRESS.
! Returns the address of the first byte of the slice, if found: otherwise
! returns zero. The pattern may overlap the range at either end. A zero
! length pattern will produce a match and return a copy of RANGE ADDRESS
! as the result. Otherwise zero or negative lengths, or lengths not less
! than 2**24, will produce a result of zero. If the pattern is longer than
! the range then a zero result will also be returned.
LONG INTEGER SD
INTEGER D
UNLESS 0<RANGE LENGTH<=X'00FFFFFF' C
AND 0<=PATTERN LENGTH<=X'00FFFFFF' C
THEN RESULT = 0
IF PATTERN LENGTH=0 THEN RESULT = RANGE ADDRESS
D = RANGE LENGTH - PATTERN LENGTH + 1; ! A match may start at any offset from 0
! to D-1 within the range, so this is
! the number of bytes that can usefully
! be scanned for instances of the first
! byte of the pattern.
IF D<=0 THEN RESULT = 0
*LDTB_X'18000000'; ! Byte vector descriptor.
*LDB_PATTERN LENGTH
*LDA_PATTERN ADDRESS
*LB_(DR ); ! Pick up first byte of pattern.
*STD_SD; ! Save descriptor to pattern.
*LDB_D; ! Construct descriptor to range (only
! the bytes which need to be checked
! against the leading byte of pattern).
*LDA_RANGE ADDRESS
SCAN:
*SWNE_L =DR ; ! Mask=0, Ref=1st. byte of pattern
! (in B register).
*JCC_8,<NOT FOUND>; ! -> if no match found.
!
! DR points to byte in range which matches first byte in pattern.
*STD_TOS ; ! Save the pointer to it.
*LDTB_SD; ! Pick up length of pattern.
*LSD_SD; ! Acc points to pattern.
*CPS_L =DR ; ! Try to match pattern.
*JCC_8,<FOUND>; ! -> if match found.
*LD_TOS ; ! If no match found, recover
! descriptor to residue of range,
*MODD_1; ! skip past the last byte tested,
*J_<SCAN>; ! and try again.
FOUND:
*LSS_TOS ; ! Match found: pick up address where
*EXIT_-64; ! it was found, and return that.
NOT FOUND:
RESULT = 0
END
END OF FILE