245 lines
4.4 KiB
Plaintext
245 lines
4.4 KiB
Plaintext
|
/*
|
||
|
|
||
|
findf
|
||
|
|
||
|
A very fast case-sensitive grep-style search program using
|
||
|
async i/o and the Boyer-Moore search algorithm.
|
||
|
|
||
|
Usage - same as 'c:search' for the commands implemented.
|
||
|
|
||
|
Michael Zucchi 1994
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
MODULE 'dos/dos', 'dos/dosasl',
|
||
|
'locale',
|
||
|
'tools/async'
|
||
|
|
||
|
DEF skip[256]:ARRAY OF CHAR, -> skip array
|
||
|
line[1024]:ARRAY OF CHAR, -> input buffer
|
||
|
buffer[1024]:ARRAY OF CHAR, -> for case-sensitive searches
|
||
|
m, -> length of string
|
||
|
string:PTR TO CHAR, -> string to match
|
||
|
uppertable[256]:ARRAY OF CHAR,-> lower->upper conversion table
|
||
|
quiet, nonum, quick, ncase -> settings
|
||
|
|
||
|
|
||
|
PROC main()
|
||
|
DEF args:PTR TO LONG, rdargs, p:PTR TO LONG, an:PTR TO anchorpath,go,
|
||
|
fib:PTR TO fileinfoblock, loc, i
|
||
|
|
||
|
args:=[0,0,0,0,0,0,0];
|
||
|
|
||
|
IF rdargs:=ReadArgs('FROM/M,SEARCH/A,ALL/S,NONUM/S,QUIET/S,QUICK/S,CASE/S', args, 0)
|
||
|
string:=args[1];
|
||
|
nonum:=args[3];
|
||
|
quiet:=args[4];
|
||
|
quick:=args[5];
|
||
|
ncase:=args[6]=0;
|
||
|
|
||
|
IF ncase
|
||
|
IF localebase:=OpenLibrary('locale.library', 0)
|
||
|
IF loc:=OpenLocale(0);
|
||
|
FOR i:=0 TO 255 DO uppertable[i]:=ConvToUpper(loc, i);
|
||
|
CloseLocale(loc);
|
||
|
ELSE
|
||
|
FOR i:=0 TO 255 DO uppertable[i]:=IF i>="a" AND i<="z" THEN i-32 ELSE i
|
||
|
ENDIF
|
||
|
ELSE
|
||
|
FOR i:=0 TO 255 DO uppertable[i]:=IF i>="a" AND i<="z" THEN i-32 ELSE i
|
||
|
ENDIF
|
||
|
CloseLibrary(localebase);
|
||
|
MOVE.L uppertable,A0
|
||
|
MOVE.L string,A1
|
||
|
MOVEQ #0,D0
|
||
|
mn_up: MOVE.B (A1),D0
|
||
|
MOVE.B 0(A0,D0.W),(A1)+
|
||
|
BNE.S mn_up
|
||
|
ENDIF
|
||
|
|
||
|
initskip();
|
||
|
|
||
|
IF an:=New(SIZEOF anchorpath + 256)
|
||
|
an.strlen:=255
|
||
|
an.breakbits:=SIGBREAKF_CTRL_C;
|
||
|
fib:=an.info
|
||
|
p:=args[0];
|
||
|
go:=0
|
||
|
WHILE p[] AND (go=0)
|
||
|
go:=MatchFirst(p[], an);
|
||
|
WHILE go=0
|
||
|
IF (fib.direntrytype) <0
|
||
|
go:=scanfile(an+SIZEOF anchorpath);
|
||
|
ELSE
|
||
|
IF args[2]
|
||
|
IF (an.flags AND APF_DIRCHANGED)=0 THEN an.flags:=an.flags OR APF_DODIR
|
||
|
ENDIF
|
||
|
ENDIF
|
||
|
IF go=0 THEN go:=MatchNext(an);
|
||
|
ENDWHILE
|
||
|
p++
|
||
|
ENDWHILE
|
||
|
IF quick THEN WriteF('\e[M');
|
||
|
Dispose(an);
|
||
|
ENDIF
|
||
|
FreeArgs(rdargs);
|
||
|
ELSE
|
||
|
WriteF('FindF, Michael Zucchi 1994.\nERROR: bad args\n'+
|
||
|
' FROM/M files/patterns to search\n'+
|
||
|
' SEARCH/A text to search for\n'+
|
||
|
' ALL/S recursively scan subdirectories\n'+
|
||
|
' NONUM/S do not output line numbers\n'+
|
||
|
' QUIET/S do not output matched lines\n'+
|
||
|
' QUICK/S faster file-scan display\n'+
|
||
|
' CASE/S do a case-sensitive search\n');
|
||
|
ENDIF
|
||
|
ENDPROC
|
||
|
|
||
|
|
||
|
/*
|
||
|
search a single file, by filename, line at a time
|
||
|
*/
|
||
|
|
||
|
PROC scanfile(name)
|
||
|
DEF number, file, found=0,go=0
|
||
|
|
||
|
IF quick
|
||
|
WriteF('\s\e[K\b', name);
|
||
|
ELSE
|
||
|
IF quiet=0 THEN WriteF('\s\n', name);
|
||
|
ENDIF
|
||
|
|
||
|
number:=1;
|
||
|
IF (file:=as_Open(name, MODE_OLDFILE, 3, 10240))
|
||
|
WHILE as_FGetS(file, line, 1023) AND (go=0)
|
||
|
IF testmatch()
|
||
|
IF quiet
|
||
|
IF found=0 THEN WriteF('\s\n', name);
|
||
|
JUMP close
|
||
|
ELSEIF nonum
|
||
|
-> IF quick AND found=0 THEN WriteF('\n');
|
||
|
WriteF('\s', line);
|
||
|
ELSE
|
||
|
-> IF quick AND found=0 THEN WriteF('\n');
|
||
|
WriteF('\d[6] \s', number, line);
|
||
|
ENDIF
|
||
|
found:=1
|
||
|
ENDIF
|
||
|
number++
|
||
|
go:=CheckSignal(SIGBREAKF_CTRL_C)
|
||
|
ENDWHILE
|
||
|
close:
|
||
|
as_Close(file);
|
||
|
ENDIF
|
||
|
|
||
|
ENDPROC go
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Initialise the skip table for a given search string
|
||
|
*/
|
||
|
|
||
|
PROC initskip()
|
||
|
DEF i
|
||
|
|
||
|
m:=StrLen(string);
|
||
|
|
||
|
-> initialise skip table for all characters
|
||
|
FOR i:=0 TO 255
|
||
|
skip[i]:=m+1;
|
||
|
ENDFOR
|
||
|
|
||
|
-> set skip table for characters in the string
|
||
|
FOR i:=0 TO m-1
|
||
|
skip[string[i]]:=m-i;
|
||
|
ENDFOR
|
||
|
|
||
|
ENDPROC
|
||
|
|
||
|
/*
|
||
|
Looks for a match in a given line
|
||
|
*/
|
||
|
|
||
|
PROC testmatch()
|
||
|
|
||
|
IF m<1 THEN RETURN
|
||
|
|
||
|
MOVEM.L A4-A5,-(A7)
|
||
|
|
||
|
MOVE.L m,D7
|
||
|
SUBQ.L #1,D7
|
||
|
|
||
|
TST.L ncase
|
||
|
BEQ.S tm_case
|
||
|
|
||
|
-> non case-sensitive
|
||
|
|
||
|
MOVE.L line,A3
|
||
|
MOVE.L buffer,A0
|
||
|
LEA 1(A0,D7.L),A2
|
||
|
MOVE.L uppertable,A1
|
||
|
MOVEQ #0,D0
|
||
|
tp_up: MOVE.B (A3)+,D0
|
||
|
MOVE.B 0(A1,D0.W),(A0)+
|
||
|
BNE.S tp_up
|
||
|
BRA.S tp_match
|
||
|
|
||
|
-> case sensitive
|
||
|
tm_case:
|
||
|
MOVE.L line,A0
|
||
|
LEA 1(A0,D7.L),A2 -> a[i]
|
||
|
tm_scan:
|
||
|
TST.B (A0)+ -> <hack> find end of string
|
||
|
BNE.S tm_scan
|
||
|
|
||
|
tp_match:
|
||
|
MOVE.L string,A1
|
||
|
MOVE.L A1,A5
|
||
|
LEA 1(A1,D7.L),A1 -> p[j]
|
||
|
|
||
|
MOVE.L skip,A4
|
||
|
|
||
|
MOVE.L D7,D3
|
||
|
ADDQ.L #2,D3
|
||
|
MOVEQ #0,D1
|
||
|
tm_loop0:
|
||
|
MOVE.L D7,D2
|
||
|
MOVE.L A1,A3
|
||
|
tm_loop:
|
||
|
MOVE.B -(A2),D1
|
||
|
CMP.B -(A3),D1
|
||
|
BEQ.S tm_matchchar
|
||
|
|
||
|
MOVE.L A5,D0
|
||
|
SUB.L A3,D0 -> -j
|
||
|
ADD.L D3,D0 -> M-j+1
|
||
|
|
||
|
MOVE.B 0(A4,D1.W),D1 -> skip[character]
|
||
|
CMP.L D0,D1
|
||
|
BLT.S tm_add0
|
||
|
|
||
|
ADD.L D1,A2
|
||
|
|
||
|
tm_ok: CMPA.L A0,A2
|
||
|
BLT.S tm_loop0
|
||
|
|
||
|
MOVEQ #0,D0
|
||
|
BRA.S tm_exit
|
||
|
|
||
|
tm_add0:
|
||
|
ADD.L D0,A2
|
||
|
BRA.S tm_ok
|
||
|
|
||
|
tm_matchchar:
|
||
|
DBF D2,tm_loop
|
||
|
|
||
|
MOVEQ #-1,D0
|
||
|
tm_exit:
|
||
|
MOVEM.L (A7)+,A4-A5
|
||
|
|
||
|
ENDPROC D0
|
||
|
|
||
|
|