#!/usr/bin/perl
#
# searchdown.pl.2
#
# search all directories below specified dir for text file containing a given string
#
# searchdown.pl.2 <dir> <search_string>
#
# NOTE: Strings containing "/" must have them escaped with a backslash,
#       just as in a Perl substitution string, or the substitution command
#       will probably fail.
#
# NOTE 2: The subroutine "dodir()" used in this script is loosely based on an example
#         provided in _Programming_Perl_ by Wall & Schwartz.


use Cwd;

# complain if there aren't enough args
if ( $#ARGV != 1 )
{ 
	print "Usage: $0 dir search_string\n";
    die "\tIncorrect args found; $#ARGV";
}

# get the directory and search string 
(( my $topdir = shift ) && ( my $search_string = shift )) 
	|| die "Usage: $0 dir search_string\n";

#complain if we didn't get a valid directory
if ( ! -d $topdir ) 
{ die "Can't `$topdir'; must be relative to current directory"; }

my $currdir = cwd();  # in Cwd lib

chdir $topdir;
print "Checking in $topdir...\n";
&dodir($topdir);

sub dodir 
{
    local($dir,$nlink) = @_;
    local($dev,$ino,$mode,$subcount);
    my( $filename );

    # At the top level, we need to find nlink ourselves.

    ($dev,$ino,$mode,$nlink) = stat('.') unless $nlink;

    # Get the list of files in the current directory.

    opendir(DIR,'.') || die "Can't open $dir";
    local(@filenames) = readdir(DIR);
    closedir(DIR);

    if ($nlink == 2) {        # This dir has no subdirectories.
        for (@filenames) {
            next if $_ eq '.';
            next if $_ eq '..';
            # print "Thatlevel: $dir/$_\n";
            $filename = "$currdir/$dir/$_";

            if ( -f $filename && -T _ )
            { 
                # print "Checking filename $filename\n";

                $pid = open FILE, "<$filename"; 
                while (<FILE>)
                {
                    chop;
                    if (/$search_string/)
                    { print "$filename: $_\n"; }
                }
                close FILE;
            }
        } 
    }
    else 
    {                    # This dir has subdirectories.
        $subcount = $nlink - 2;
        for (@filenames) {
            next if $_ eq '.';
            next if $_ eq '..';
            $name = "$dir/$_";

            # print "Thislevel: $name,\n";

            $filename = "$currdir/$name";

            if ( -f $filename && -T _ )
            { 
                # print "Checking name $filename\n";
                $pid = open FILE, "<$filename";
                while (<FILE>)
                {
                    chop;
                    if (/$search_string/)
                    { print "$filename: $_\n"; }
                }
                close FILE;
            }
            next if $subcount == 0;    # Seen all the subdirs?

            # Get link count and check for directoriness.

            ($dev,$ino,$mode,$nlink) = lstat($_);
            next unless -d _;

            # It really is a directory, so do it recursively.

            chdir $_ || die "Can't cd to $name";
            print "Checking in $_...\n";
            &dodir($name,$nlink);
            chdir '..';
            --$subcount;
        }
    }
}

# end.

