package fif; ## fif : 'find in files' -- a package to do "find -exec grep" on ## feature-poor architectures (e.g. Win32) use strict; use warnings; use Carp; use File::Find; use Cwd; my $version = "1.1"; my ($pat, $dir, $fpat, $ins, $tree, $opref, $count, $dbg); ################### ## FindInFiles ## do "find -exec grep" on a dir or tree ## with Perl REs sub FindInFiles { my %args = @_; $pat = $args{-pat} or croak "-pat arg not given"; $dir = ( $args{-dir} or cwd() ); $fpat = ( $args{-fpat} or '.+'); $ins = ( $args{-ins} or 0 ); $tree = ( $args{-tree} or 0 ); $dbg = ( $args{-dbg} or 0 ); if( ($opref = $args{-opref}) and (ref($opref) ne 'CODE') ) { croak( "-opref arg is not a reference to code"); } if( ! is_valid_pattern( $pat ) ) { msgout("Invalid pattern '$pat'"); return; } if( ! is_valid_pattern( $fpat ) ) { msgout("Invalid file pattern '$fpat'"); return; } $dir =~ s/[\\\/]$//; #<-- strip a trailing slash from dir. if( ! -d $dir ) { msgout("Not a directory '$dir'."); return; } $count=0; if( $tree ) { find({wanted => \&ExamineFile, no_chdir => 1}, ($dir)); } else { if(! opendir(DIR, $dir)){ msgout("Can't opendir $dir: $!"); return } my @files = readdir DIR; closedir DIR; foreach my $file (@files){ local $_ = $dir.'/'.$file; ExamineFile(); } } msgout("Files found: $count"); return $count; } ################### ## ExamineFile ## Called by the file finder to process a file sub ExamineFile { ## Only consider plain files that match the filename pattern... return unless -f; return unless /$fpat/i; if( $dbg ) { msgout("DEBUG: Found: '$_'"); } my $file = $_; { ## Local line counter $. and default arg $_ so as not to mess ## with File::Find... local $_; local $.; if( ! open(FILE, "< $file") ) { msgout("WARNING: can't open '$file': $!"); return; } ## Translate slashes to backslashes for output... $file =~ tr/\//\\/; while() { if( $ins ) { next unless /$pat/i; } else { next unless /$pat/; } chomp; msgout("$file($.):'$_'"); $count++; } close FILE; } } ################### ## is_valid_pattern ## Check the given pattern for validity. ## (from the Perl Cookbook) sub is_valid_pattern { my $pat = shift; return eval { "" =~ /$pat/; 1 } || 0; } ################### ## msgout ## function for output of messages to STDOUT ## or a delegate function sub msgout { my $msg = "@_"; if( $opref ) { &$opref( $msg ); return; } print STDOUT $msg."\n"; } 1; __END__ =head1 SYNOPSIS use fif; ## Do directory-recursive search... fif::FindInFiles( -pat => 'erskine', -dir => 'D:/msemtd/Perl/fif', -fpat => '\.(pl|pm|pod)$', -tree => 1); ## Do non-recursive search of current dir... fif::FindInFiles( -pat => '^\#include', -fpat => '\.(c|cpp|h)$'); =head1 AUTHOR Michael Erskine michael.erskine@tecspy.com =head1 COPYRIGHT AND DISCLAIMER This program is Copyright 2001 by Michael Erskine. This program is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License or the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. If you do not have a copy of the GNU General Public License write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. =cut