	SUBROUTINE SNOOPFIND
C
C	THIS ROUTINE IS USED TO PERFORM ASCII STRING SEARCHES, 4 BYTE
C	HEX SEARCHES, AND 4 BYTE BINARY SEARCHES OF THE FILE OPENED
C	FOR SNOOPY.  WHEN THE DESIRED MATCH IS MADE, INFO ON THE
C	LAST BYTE MATCHED IS TYPED AND CONTROL IS RETURNED TO SNOOPY.
C	ELSE, SNOOPY IS TERMININATED WITH AN END-OF-FILE WARNING.
C
C	NOTE THAT HEX AND BINARY SEARCH INPUTS MUST CONTAIN 8 CHARACTER
C	(0 - F) AND 32 CHARACTER (0 - 1) STRINGS, RESPECTIVELY.  ANY
C	OTHER CHARACTERS WILL BE TREATED AS "DON'T CARE" VALUES WITHIN
C	THE FIELDS.  SUCH FIELDS ARE ZEROED IN THE SEARCH VALUE AND
C	TARGET VALUE BEFORE COMPARISON TESTS ARE PERFORMED.  DO NOT USE
C	CONTROL CHARACTERS FOR DON'T CARES.
C
C	ALSO, DO NOT PUT TERMINATING BLANKS ON AN ASCII SEARCH STRING
C	AS THEY WILL BE STRIPPED BEFORE SEARCHING BEGINS.
C
C	J. THOMPSON  INTERMETRICS  JANUARY 17, 1979
C
	IMPLICIT INTEGER*2 (A-Z)
	INTEGER*4	I4(128),IDUM4
	INTEGER*4	N2	!NEED LONGWORD FOR ERROR CODE
	LOGICAL*1	STRING(80),MASK(4),ARG(4),TV(2),TM(2)
	LOGICAL*1	B(80),C(2)	!MAKES BYTE ARITHMETIC EASIER
	LOGICAL*1	I1(512),K1,K2,K3,K4,K1A,K2A,K3A,K4A
	COMMON/AAA/	NEXT,NBLK,NBEG,NEND,IDUM,NSKIP
	COMMON/BBB/	IB(256)		!BLOCK KEPT HERE
	COMMON/CCC/	FILENAME(40)
	COMMON/DDD/	NCHAR
	COMMON/EEE/	N2		!GB ERRORS PUT HERE
	COMMON/SNFC/	VAL,MASK
	EQUIVALENCE (B(1),FILENAME(1))
	EQUIVALENCE (NEXT,C(1))
	EQUIVALENCE (I4(1),I1(1),IB(1))
	EQUIVALENCE (TV(1),VAL),(TM(1),MSK)
C
C	TEST WHETHER FIRST BLOCK OF FILE HAS BEEN READ IN YET
	IF(NBLK.GT.0) GO TO 80 !YES
	CALL GB		!READ IT
	IF(N2.NE.0) STOP 'END-OF-FILE ON FIRST READ OF FILE'
	NBLK=NBLK+1
C	DETERMINE KIND OF SEARCH
80	WRITE(6,*) ' TYPE KEY FOR KIND OF SEARCH'
	WRITE(6,*) ' 1 = ASCII STRING, 2 = 4 BYTE HEX, 3 = 4 BYTE BINARY'
	READ(5,*,ERR=80) KEY
	IF((KEY.NE.1).AND.(KEY.NE.2).AND.(KEY.NE.3)) GO TO 80
C
	GO TO (100,500,600), KEY	!ASCII, HEX, BINARY
C
C	ASCII STRING SEARCH
C
100	WRITE(6,*) ' TYPE ASCII STRING. MAX 80 BYTES. NO TRAILING BLANKS'
	READ(5,10) STRING
10	FORMAT(81A)
C	FIND # CHARACTERS
	DO 200 J=1,80
	L=81-J
	IF(STRING(L).NE."40) GO TO 250
200	CONTINUE
	GO TO 100	!TRY ANOTHER STRING. THIS ALL BLANKS OR 0 LENGTH
250	NBYTES=L	!THIS MANY CHARACTERS TO BE MATCHED
C	FIND FIRST CHARACTER OF STRING
300	START=1		!BYTE POINTER IN TARGET BLOCK
	BOUND=0		!NO BLOCK BOUNDARIES CROSSED YET
	K1=STRING(1)
310	POINT=1		!BYTE POINTER IN STRING TO BE MATCHED
320	DO 330 J=START,512	!SEARCH REST OF BLOCK
	NEXT=J
	SAVE=J+1
	IF(K1-I1(J)) 330,340,330	!LOOP, FOUND, LOOP
330	CONTINUE
C	NO LUCK IN THIS BLOCK. GET NEXT BLOCK.
335	CALL GB
	IF(N2.NE.0) STOP 'END-OF-FILE (ASCII STRING NOT FOUND)'
	NBLK=NBLK+1
	GO TO 300
C	FOUND A CHARACTER. NOW FIND NEXT ONE
340	POINT=POINT+1
	IF(POINT.GT.NBYTES) GO TO 400 !FOUND IT MESSAGE
	NEXT=NEXT+1
	IF(NEXT.LE.512) GO TO 350
C	GET NEXT BLOCK
	CALL GB
	IF(N2.NE.0) STOP 'END-OF-FILE (PARTIAL ASCII STRING MATCH)'
	NBLK=NBLK+1
	PSAVE=POINT-1	!NUMBER OF BYTES MATCHED BEFORE BLOCK BOUNDARY
	BOUND=1		!NEW BLOCK AND HAD PARTIAL MATCH IN OLD BLOCK
	NEXT=1	!START AT BLOCK BEGINNING
C	TEST THE NEXT CHARACTER
350	IF(STRING(POINT).EQ.I1(NEXT)) GO TO 340 !FOUND ANOTHER CHARACTER
C	DIDN'T FIND IT
352	START=SAVE	!VERY IMPORTANT
	IF(BOUND.EQ.1) GO TO 360 !MUST USE SPECIAL TEST OVER BOUNDARY
	IF(START.GT.512) GO TO 335
	GO TO 310	!LOOK FOR FIRST CHARACTER IN STRING AGAIN
C
C	TEST FOR MATCH IN PART ALREADY MATCHED IN STRING BEFORE BLOCK BOUNDARY
C
360	IF(SAVE.GT.512) GO TO 300
	WRITE(6,*) '*** BOUNDARY TEST - ASCII ***'
	START=2
	IF(START.GT.PSAVE) STOP 'START.GT.PSAVE'
362	POINT=1
	K1=STRING(1)
	DO 364 J=START,PSAVE	!LOOK IN MATCHED PART OF STRING
	NEXT=J
	JSAVE=J+1
	IF(K1-STRING(J)) 364,366,364	!LOOP, FOUND, LOOP
364	CONTINUE
	GO TO 300	!NO LUCK IN FINDING ANOTHER MATCH, USE NEW BLOCK
C	MATCHED A BYTE IN MATCHED STRING, FIND ANOTHER
366	NEXT=NEXT+1
	IF(NEXT.GT.PSAVE) GO TO 368	!TIME TO TEST "TAIL" IN NEW BLOCK
	POINT=POINT+1
	IF(STRING(POINT).EQ.STRING(NEXT)) GO TO 366 !GOT ANOTHER
	GO TO 372	!NEXT ONE DIDN'T MATCH
C	NOW TEST FOR POSSIBILITY OF "TAIL" MATCH IN NEW BLOCK
368	NEXT=0
370	POINT=POINT+1
	IF(POINT.GT.NBYTES) GO TO 400	!FOUND STRING MESSAGE
	NEXT=NEXT+1
	IF(STRING(POINT).EQ.I1(NEXT)) GO TO 370	!GOT ANOTHER
C	DIDN'T FIND NEXT ONE
372	START=JSAVE
	IF(START.GT.PSAVE) GO TO 300	!BACK TO BASIC SEARCH IN NEW BLOCK
	GO TO 362	!TRY REST OF MATCHED PART
C
C	MATCHED WHOLE INPUT STRING
C
400	NB=NEXT
	NW2=NEXT/2
	IF((NEXT-(NW2*2)).NE.0) NW2=NW2+1
	NW4=NEXT/4
	IF((NEXT-(NW4*4)).NE.0) NW4=NW4+1
	WRITE(6,20) NBLK,NB,NW2,NW4	!BLOCK, BYTE, 2 BYTE WORD, 4 BYTE WD
20	FORMAT(' LAST BYTE OF MATCH IN BLOCK # ',I4,/
	1' (BYTE # ',I3,2X,'2 BYTE WORD # ',I3,2X,
	2'4 BYTE WORD # ',I3,')')
	NW4M1=NW4-1
	IF(NW4M1.GT.0) CALL DISPLAY4(NW4M1)
	CALL DISPLAY4(NW4)
C
C	DETERMINE IF IT IS DESIRED TO IGNORE THIS MATCH AND SEARCH FOR THE
C	NEXT OCCURENCE OF THE MATCH STRING OR VALUE
C
	WRITE(6,*) 'TYPE 1 TO IGNORE THIS MATCH AND CONTINUE SEARCHING'
	READ(5,*) GOON
	IF(GOON.NE.1) RETURN
	IF(BOUND.EQ.1) GO TO (372,592,592), KEY
	GO TO (352,572,572), KEY
C
C	HEX 4 BYTE STRING WITH DON'T CARES
C
500	WRITE(6,*) ' TYPE 8 CHARACTER HEX STRING'
	READ(5,10,ERR=500) STRING
C	CONVERT HEX TO INTERNAL BINARY
	K=0
	DO 520 J=1,8,2
	K=K+1
	L=9-J
	CALL CNVTHEX(STRING(L),VL,ML)
	CALL CNVTHEX(STRING(L-1),VH,MH)
	VAL=VH*16+VL
	MSK=MH*16+ML
	ARG(K)=TV(1)
520	MASK(K)=TM(1)
	NBYTES=4
C
C	FIND FIRST BYTE OF STRING WHEN HAVE DON'T CARE MASK
C
530	START=1
	BOUND=0		!NO BLOCK BOUNDARY CROSSED YET
535	POINT=1
	K1=ARG(1)
	K2=MASK(1)
540	DO 550 J=START,512
	NEXT=J
	SAVE=J+1	!SAVE RESTART LOCATION WITHIN BLOCK
	K3=K2.AND.I1(J)
	IF(K1-K3) 550,560,550	!LOOP, FOUND, LOOP
550	CONTINUE
C	GET NEXT BLOCK
555	CALL GB
	IF(N2.NE.0) STOP 'END-OF-FILE (HEX OR BIN SEARCH FAILED)'
	NBLK=NBLK+1
	GO TO 530	!START AT BLOCK BEGINNING AGAIN
C	FOUND A BYTE THAT MATCHES, NOW FIND IF NEXT ONE DOES TOO
560	POINT=POINT+1
	IF(POINT.GT.NBYTES) GO TO 400	!MATCHED WHOLE STRING MESSAGE
	NEXT=NEXT+1
	IF(NEXT.LE.512) GO TO 570
C	GET NEXT BLOCK
	CALL GB
	IF(N2.NE.0) STOP 'END-OF-FILE (PARTIAL HEX OR BIN MATCH)'
	NBLK=NBLK+1
	PSAVE=POINT-1	!NUMBER OF BYTES MATCHED BEFORE BLOCK BOUNDARY
	BOUND=1		!NEW BLOCK AND HAD PARTIAL MATCH IN OLD BLOCK
	NEXT=1		!START AT BLOCK BEGINNING
570	K1=ARG(POINT)
	K2=MASK(POINT)
	K3=K2.AND.I1(NEXT)
	IF(K1.EQ.K3) GO TO 560	!FOUND ANOTHER CHARACTER
C	DIDN'T FIND ANOTHER CHARACTER
572	START=SAVE	!VERY IMPORTANT
	IF(BOUND.EQ.1) GO TO 580 !MUST USE SPECIAL TEST OVER BOUNDARY
	IF(START.GT.512) GO TO 555
	GO TO 535
C
C	TEST FOR MATCH IN PART ALREADY MATCHED IN STRING BEFORE BLOCK BOUNDARY
C
580	IF(SAVE.GT.512) GO TO 530
	WRITE(6,*) '*** BOUNDARY TEST - HEX, BIN ***'
	START=2
	IF(START.GT.PSAVE) STOP 'START.GT.PSAVE'
582	POINT=1
	K1=ARG(1)
	K2=MASK(1)
	DO 584 J=START,PSAVE	!LOOK IN MATCHED PART OF STRING
	NEXT=J
	JSAVE=JSAVE+1
	K3=K2.AND.ARG(J)
	IF(K1-K3) 584,586,584	!LOOP, FOUND, LOOP
584	CONTINUE
	GO TO 530	!NO LUCK IN FINDING ANOTHER MATCH, USE NEW BLOCK
C	MATCHED A BYTE IN MATCHED STRING, FIND ANOTHER
586	NEXT=NEXT+1
	IF(NEXT.GT.PSAVE) GO TO 588 !TIME TO TEST "TAIL" IN NEW BLOCK
	POINT=POINT+1
	K1=ARG(POINT)
	K2=MASK(POINT)
	K3=K2.AND.ARG(NEXT)
	IF(K1.EQ.K3) GO TO 586 !GOT ANOTHER MATCH
	GO TO 592	!NEXT ONE DIDN'T MATCH
C	NOW TEST FOR POSSIBILITY OF "TAIL" MATCH IN NEW BLOCK
588	NEXT=0
590	POINT=POINT+1
	IF(POINT.GT.NBYTES) GO TO 400 !FOUND STRING MESSAGE
	NEXT=NEXT+1
	K1=ARG(POINT)
	K2=MASK(POINT)
	K3=K2.AND.I1(NEXT)
	IF(K1.EQ.K3) GO TO 590 !GOT ANOTHER MATCH
C	DIDN'T FIND NEXT ONE
592	START=JSAVE
	IF(START.GT.PSAVE) GO TO 530 !BACK TO BASIC SEARCH IN NEW BLOCK
	GO TO 582
C
C	BINARY 4 BYTE STRING WITH BIT DON'T CARES
C
600	WRITE(6,*) ' TYPE 32 BIT BINARY STRING'
	READ(5,10) STRING
C	CONVERT BINARY STRING TO INTERNAL BINARY
	CALL CNVTBIN(STRING,25,32,ARG(1),MASK(1))
	CALL CNVTBIN(STRING,17,24,ARG(2),MASK(2))
	CALL CNVTBIN(STRING,9,16,ARG(3),MASK(3))
	CALL CNVTBIN(STRING,1,8,ARG(4),MASK(4))
	NBYTES=4
C	NOW USE HEX STRING SEARCH
	GO TO 530
	END
