#!/usr/sbin/perl

# findtext - recursively descend a directory hierarchy searching for text
#
#   This software is Public Domain. Please maintain version history.
#   Report all bugs to Greg Ercolano (erco@3dsite.com).
#
#	1.00 erco@3dsite.com
#	1.10 erco@3dsite.com - added -name/-i/-d/-v, and gzip/pack/uncompress
#	1.20 erco@3dsite.com - small fixes, 'set iflag=""', etc
#	2.00 erco@3dsite.com - perl4 compatible rewrite
#	2.01 erco@3dsite.com - Added '-type f'
#

$G_debug = 0;
$G_verbose = 0;
$G_search = "";
$G_iflags = "";

# MAIN
{
    local ($name)  = "";
    local ($follow) = "";
    local ($i, $filename, @list);

    if ( $#ARGV < 0 ) { &HelpAndExit(); }

    for ( $i=0; $i <= $#ARGV; $i++ )
    {
	if ( $ARGV[$i] eq "-follow" ) { $follow = "-follow"; next; }
	if ( $ARGV[$i] eq "-i"      ) { $G_iflags = "i"; next; }
	if ( $ARGV[$i] eq "-v"      ) { $G_verbose = 1; next; }
	if ( $ARGV[$i] eq "-d"      ) { $G_debug = 1; next; }
	if ( $ARGV[$i] eq "-h" || $ARGV[$i] eq "-help" )
	    { &HelpAndExit(); }
	if ( $ARGV[$i] eq "-name"   )
	    { $name = sprintf("-name '%s'",$ARGV[++$i]); next; }
	if ( $G_search eq "" )
	    { $G_search = $ARGV[$i]; }
	else
	    { push(@list, $ARGV[$i]); }
    }

    # WALK EACH DIRECTORY
    foreach ( @list )
    {
        $filename = "find $_ $name -type f $follow -print";
	if ( $G_debug )
	    { print STDERR "Executing: $filename\n"; }
	unless ( open(FDIR, "$filename|") )
	{
	    print STDERR "$0: $filename: $!\n";
	    next;
	}
	# WALK EACH FILE
	while ( <FDIR> )
	{
	    local ($cmd) = "cat";
	    local ($filename) = $_;
	    chop($filename);

	    if ( $G_debug || $G_verbose )
	        { print "--- " . $filename . "\n"; }

	    if ( /\.z/  ) { $cmd = "pcat"; }		# unpack man pages
	    if ( /\.Z/  ) { $cmd = "uncompress -c"; }	# compress(1)ed files
	    if ( /\.gz/ ) { $cmd = "gunzip -c"; }	# gzip'ed files
	    &Search("$cmd $filename | col -bx", $filename); # col: for man pages
	}
	close(FDIR);
    }
}

# SEARCH FILE
sub Search
{
    local ( $cmd, $filename ) = @_;

    if ( $G_debug )
	{ print STDERR "Executing: $cmd\n"; }

    unless ( open ( FILE, "$cmd|" ) )
    {
        print STDERR "$cmd: $!\n";
	return(0);
    }
    while ( <FILE> )
    {
        if ( $G_iflags eq "i" )
	{
	    if ( /$G_search/i )
		{ print "$filename: $_"; }
	}
	else
	{
	    if ( /$G_search/ )
		{ print "$filename: $_"; }
	}
    }
    close(FILE);
    return(0);
}

sub HelpAndExit
{
    print STDERR <<"EOF";
findtext - recursively search files for a string of text
           Searches plain ascii files, .gz, .Z and .z files

usage: findtext [-v] [-name pat] [-i] regex dir [dir ..]
       --------                       ----- ---

    Underlined items must be specified.

OPTIONS
    -name pat - search for filename pattern 'pat' (eg. find(1) '-name')
    -follow   - follow symbolic links
    -i        - ignore case
    -v        - verbose - print expansion commands
    -d        - debug
    'regex'   - a perl regular expression, ie. 'Jeff|Rob' [similar to egrep(1)]
    'dir'     - a directory

EXAMPLES
    findtext -i 'pagesize|page.size' /usr/share/catman/u_man/cat1
    findtext 'memory.*alloc' /usr/include
    findtext 'NPROC' /var/sysgen /usr/include /usr/tmp/kernel.new
    findtext -name '*.c' 'include|define' ./src

EOF
    exit(1);
}
