#!/home/sburke/bin/perl

use strict;
unless(@ARGV > 1) {
  print STDERR <<'EOUSAGE' ; exit 1;
Usage:
 findgrep  regexp  filespec patterns
   ...looks for lines matching the given regexp, in files named, or
      files matching patterns, e.g.:   findgrep 'stuff\d*' '*.pl'
EOUSAGE
}

#--------------------------------------------------------------------------
my $initial_RS = $/;
sub taste_handle_RS ($;$) {
  # Taste the given input channel, set $/ as needed, and rewind back
  #  over it again.
  # Sample use:
  #   open(IN, $file);
  #   my $nl = taste_handle_RS(*IN{IO});
  # Optional second parameter is a byte count that the first line (plus newline)
  #  is guaranteed to be smaller than.

  my $h = $_[0];
  die "argument to taste_text_handle must be a IO-ref"
   unless ref $h and UNIVERSAL::isa($h, 'IO::Handle');
  my $snip = '';
  my $there = tell($h);
  read($h,$snip, $_[1] || 1024); # read
  seek($h,$there,0); # and rewind

  # to do: recognize unicode prefix?

  if(defined $snip and $snip =~ m<(\cm\cj|\cm|\cj)>s) {
    #print "$h\'s NL is ", unpack("H*", $1), "\n" if $Debug;
    #print "\$/ is ", unpack("H*",$/), "\n" if $Debug;
    $/ = $1;
    #print "\$/ is ", unpack("H*",$/), "\n" if $Debug;
  } else {
    #print "No newline in first 1K of $h?" if $Debug;
    $/ = $initial_RS;
  }
  return $/;
}

#--------------------------------------------------------------------------

my $matched = 0;
my $files = 0;

use File::Find;

my $fregexp = shift @ARGV;

sub simple_glob2re {
  # Doesn't keep '*' from matching .foo, tho.
  my $glob = $_[0];
  '^' . 
  join('',
    map {
        $_ eq '*' ? '.*'
      : $_ eq '?' ? '.'
      : quotemeta($_)
    }
    split '', $glob
  ) . '$';
}

my $here;
chomp($here = `pwd`);

my @files;
foreach my $item (@ARGV) {
  
  if($item !~ m</>) {  # slashless
    next unless length $item;
    if(-e $item and -f _) {
      push @files, $item;
    } elsif(-d _) {
      find sub { push @files, $File::Find::name if -f $_ }, $item;
      chdir($here);
    } else { # it's a pattern for hereunder
      $item = simple_glob2re($item);
      find sub { push @files, $File::Find::name if m/$item/s and -f $_ }, './';
      chdir($here);
    }
  } else {
    $item .= '/' if $item !~ m/[*?]/s and -d $item;
     # it's a dirname.  Tweak so it matches the next pattern:
    
    my $path = $item;
    my $spec = '';
    $spec = $1 if $path =~ s<([^/]+)$><>s;
    #print "<$path> <$spec>\n";
    if(length $spec) { # no pattern
      find sub { push @files, $File::Find::name if -f $_ }, $path;
      chdir($here);
    } else {
      $spec = simple_glob2re($spec);
      find sub { push @files, $File::Find::name if m/$spec/s and -f $_ }, $path;
      chdir($here);
    }
  }
}

{
  my %seen;
  #@files = grep !(++$seen{$files}), @files;
}
die "No files match\n" unless @files;
#print "Files: <@files> (", scalar(@files), ")\n";

my $short;
foreach my $file (@files) {
  if($file =~ m<\.(gif|png|jpg|bmp|wav|au|exe|com|img|pdf|ps|mid|sit|mp3|hqx|uu|uue|swf|tgz|tar\.gz|zip|z|)$>is) {
    next;
  } elsif($file =~ m<\.gz>s) {
    $/ = "\n";
    
    $short = $file;
    #$short = ($file =~ m<([^/]+)$>s) ? $1 : '????';
    
    $file =~ s/([^a-z0-9A-Z.])/\\$1/g; # escape things
    open(IN, "gzip -c -d $file |") ||die "Can't open gzip -c -d $file| : $!\n";
  } else {
    $/ = "\n";
    
    $short = $file;
    #$short = ($file =~ m<([^/]+)$>s) ? $1 : '????';
    
    #print "Norm-reading $file\n";
    #$file =~ s/([^a-z0-9A-Z.])/\\$1/g;
    sysopen(IN, $file,0,0) or die "Can't sysopen-read $file: $!\n";
    taste_handle_RS(*IN{IO});
  }
  
  if($/ eq "\n") {
    while(<IN>) {
      print "$short $.: $_" if m/$fregexp/io;
    }
  } else {
    while(<IN>) {
      if(m/$fregexp/io) {
        chomp $_;
        print "$short $.: $_\n";
      }
    }
  }
  
  close(IN);
}

exit;

__END__
