#!/usr/bin/perl -wd

# rgrep - rekurencyjny grep
# (c) 2000 by Marcin Owsiany

use File::stat;

my $FALSE = 0;
my $TRUE = 1;

#my $debug = $TRUE;
my $debug = $FALSE;
my $curdir = ".";
my @opts;
my @args;
my $endopts = $FALSE;
my $noregex = $FALSE;
my $symlinks = $FALSE;	# follow symlinks if -g given

sub grepfile()
{
	# pobiera nazwę pliku jako argument
	# uruchamia grepa i wypisuje rezultat
	my @msg;
	my $prefix;
	my $file = $_;
	print "\tgrepfile( $curdir/$file )\n" if $debug;
	$opts = join ' ', @opts;
	@msg = qx/grep $opts '$file' 2>&1/ unless $debug;
	if (($? >> 8) > 1) { print "@msg"; exit 2 };
	@msg = ("\t\tgrep $opts $file\n") if $debug;
	if ($curdir ne ".") {
		$prefix = "$curdir/$file:";
	} else { # Usuń zbędne "./"
		$prefix = "$file:";
	}
	$prefix = "" if $debug;
	while (defined ($msg = shift @msg)) { print "$prefix$msg"; }
}

sub grepit()
{
	# pobiera nazwę jako argument
	# - wywołuje grepfile jeśli nazwa jest plikiem
	# - wywołuje grepit dla każdego pliku i katalogu pod $_ jeśli $_ jest
	# 	katalogiem
	my $something = $_;
	print "grepit( $something )\n" if $debug;
	if ( -d $something ) {
		local $tmpdir = $curdir;
		$curdir .= "/"."$something" unless $curdir eq "." and $something eq ".";
		chdir "$something";
		foreach (glob "*") {
			my $st = stat($_) or die "stat($_): $!";
			my $lst = lstat($_) or die "lstat($_): $!";
			&grepit unless ((not $symlinks) and
					(($st->mode & 0040000) and
					 ($st->ino != $lst->ino or
					  $st->dev != $lst->dev)));
		}
		chdir "..";
		$curdir = $tmpdir;
	} elsif ( -f $something) {
		&grepfile($something);
	}
}

print "Parsing:\n" if $debug;
# obsługuje opcje -e, --regexp, -f, --file, --, --help, --version i -V
# tworzy @opts i @args przekazywane grepowi w grepfile
while (defined ($arg = shift @ARGV)) {
	print "\t$arg\n" if $debug;
	if ($endopts) {
		push @args, $arg;
	} else {
		if ($arg =~ /^-([ef])(.*)/) {
			if ($2) {	# -[ef]blah
				push @opts, "-$1$2";
				$noregex = $TRUE;
			} else {		# -[ef] blah
				push @opts, ("-$1" . shift @ARGV);
				$noregex = $TRUE;
			}
		} elsif ($arg =~ /^--(regexp|file)(.*)/) {
			if ($2) {	# --(regexp|file)=blah
				push @opts, "--$1$2";
						# let grep worry about wrong syntax
				$noregex = $TRUE;
			} else {		# --(regexp|file) blah
				push @opts, ("--$1=" . shift @ARGV);
				$noregex = $TRUE;
			}
		} elsif ($arg =~ /^-([AB])(.*)/) {
			if ($2) {	# -AX
				push @opts, "-$1" . "$2";
			} else {		# -A X
				push @opts, ("-$1", shift @ARGV);
			}
		} elsif ($arg =~ /^--(before|after)-context(.*)/) {
			if ($2) {	# --(before|after)-context=X
				push @opts, "--"."$1"."-context"."$2";
						# let grep worry about wrong syntax
			} else {		# --(before|after)-context X
				push @opts, "--"."$1"."-context". shift @ARGV;
			}
		} elsif ($arg eq "--") {
			push @opts, $arg;
			$endopts = $TRUE;
		} elsif ($arg =~ /^(--version|-V|--help)$/) {
			print `grep $1`;
			exit 0;
		} elsif ($arg =~ /^-g$/){
			$symlinks = $TRUE;
		} elsif ($arg !~ /^-/) {
			if ($noregex) {
				push @args, $arg;
			} else {
				push @opts, $arg;
				$noregex = $TRUE;
			}
		} else {
			push @opts, $arg;
		}
	}
}

# Jeśli nie podano parametru, to domyślnie przeszukuj katalog bieżący
push @args, "." unless defined @args;

eval {	print "\nOptions: ";
	foreach (@opts) {
		print "$_ ";
	}
	print "\n";
} if $debug;

foreach (@args) {
	&grepit;
}
