Cover V12, I01

Article
Listing 1
Sidebar

jan2003.tar

Listing 1 wgrep.pl

#!/usr/bin/perl 
# wgrep.pl - windowed grep utility

use strict;
use IO::File;
use IO::Handle;

my ($before,$after,$show_stars,$show_nums,$sep,$show_fname);
my ($show_sep,$arg,$file,$regexp,$lnum,$fhandle,$nbef,$naft);
my ($matched,$matched2,@line_buf,@temp,$fh,$ret);

$before = 3; $after = 3;         # default window size 
$show_stars = 0; 
$show_nums = 0; 
$sep = "**********\n"; 
$show_fname = 1; 
$show_sep = 1;

# loop until an argument doesn't begin with a "-" 
while ($ARGV[0] =~ /^-(\w)(.*)/) { 
   $arg = $1;                    # $arg holds the option letter
if ($arg eq "s") { $show_stars = 1; } 
elsif ($arg eq "n") { $show_nums = 1; } 
elsif ($arg eq "m") { $show_fname = 0; } 
elsif ($arg eq "d") { $show_sep = 0; } 
elsif ($arg eq "w") {
   # parse 2nd matched section at colon
   @temp=split(/:/,$2);    
   $before = $temp[0] if $temp[0] ne ''; 
   $after = $temp[1] if $temp[1] ne ''; 
   } 
elsif ($arg eq "p") { 
   $before = 0; 
   $after = 0; 
   $show_sep = 0; } 
elsif ($arg eq "W") { 
   $before = 0; 
   $after = 0; 
   }
elsif ($arg eq "h") { &usage(""); } 
else { &usage("wgrep: invalid option: $ARGV[0]"); 
   }                             # end of if command 
shift;                           # go on to next argument 
}                                # end of foreach loop
&usage("wgrep: missing regular expression") if ! $ARGV[0]; 
$regexp = $ARGV[0]; 
shift; 
$regexp =~ s,/,\\/,g;            # "/" --> "\/"


# if no files are specified, use standard input 
if (! @ARGV[0]) { @ARGV[0] = "STDIN"; }

LOOP: 
foreach $file (@ARGV) {          # loop over file list 
   if ($file eq "STDIN") {
      $fh=new IO::Handle;
      $ret=$fh->fdopen(fileno(STDIN),"r");
      die "Can't open STDIN." unless $ret;
      }
   else {
      $fh = new IO::File "$file", "r";
      if (! defined $fh) {
         print STDERR "Can't open file $file; skipping it.\n"; 
         next LOOP;              # jump to LOOP label
         }
      } 
$lnum = 0; 
$nbef = 0; $naft = 0; 
$matched = 0; $matched2 = 0; 
&clear_buf(0) if $before > 0;
while (<$fh>) {                  # loop over the lines in the file 
   ++$lnum;                      # increment line number 
   if ($matched) {               # we're printing the match window
      if ($_ =~ /$regexp/) {     # if current line matches pattern: 
         $naft = 0;              #   reset the after window count,
         &print_info(1);         #   print preliminary stuff,
         print $_;               #   and print the line
         }
      else {                     # current line does not match
         if ($after > 0 && ++$naft <= $after) {
            # print line anyway if still in the after window
            &print_info(0); print $_;    
            }
         else {                  # after window is done
            $matched = 0;        # no longer in a match
            $naft = 0;           # reset the after window count
            # save line in before buffer for future matches
            push(@line_buf, $_); $nbef++;
            }                    # end else not in after window
         }                       # end else curr. line not a match
      }                          # end if we're in a match

   else {                        # we're still looking for a match 
      if ($_ =~ /$regexp/) {     # we found one
         $matched = 1;           # so set match flag
         # print file and/or section separator(s)
         print $sep if $matched2 && $nbef > $before && $show_sep && $show_fname;
         print "********** $file **********\n" if ! $matched2++ && $show_fname;
         # print and clear out before buffer and reset before counter
         &clear_buf(1) if $before > 0; $nbef = 0;
         &print_info(1);
         print $_;               # print current line
         } 
      elsif ($before > 0) {
         # pop off oldest line in before buffer & add current line
         shift(@line_buf) if $nbef >= $before;
         push(@line_buf,$_); $nbef++;
         }                       # end elseif before window is nonzero 
      }                          # end else not in a match 

   }                             # end while loop over lines in this file 
   $fh->close;
}                                # end foreach loop over list of files
exit;                            # end of script proper

# subroutines #
sub print_info { 
   print $_[0] ? "* " : "  " if $show_stars; 
   printf "%4d ", $lnum if $show_nums;
}                                # end subroutine print_info

sub clear_buf {
   # argument says whether to print before window or not 
   my ($i,$j,$print_flag);
   $print_flag = $_[0]; 
   $i = 0; $j = 0; 
   if ($print_flag) {
      # if we're printing line numbers, fiddle with the 
      # counter to account for the before window 
      if ($show_nums) {
         $lnum -= ($#line_buf + 1);
         }
      while ($j <= $#line_buf) { # print before window
         &print_info(0);
         print $line_buf[$j++];
         $lnum++ if $show_nums;
         }                       # end while 
      }                          # end if print_flag 
   @line_buf = ();               # clear line_buf array 
}                                # end subroutine clear_buf

sub usage {
   # optional argument is an additional message line
   print STDERR $_[0],"\n" if $_[0];
   print STDERR "Usage: wgrep [-n] [-w[B][:A] | -W] ";
   print STDERR "[-d] [-p] [-s] [-m] regexp file(s)\n";
   print STDERR "       -n = number lines\n";
   print STDERR "       -s = mark matched lines with asterisks\n";
   print STDERR "       -wB:A = display B lines before and A lines after\n";
   print STDERR "               each matched line [both default to 3]\n";
   print STDERR "       -W = suppress window; equivalent to -w0:0\n";
   print STDERR "       -d = suppress separation lines between sections\n";
   print STDERR "       -m = suppress file name header lines\n";
   print STDERR "       -p = plain mode: equivalent to -W -d\n";
   print STDERR "       -h = print this help message and exit\n";
   print STDERR "Note: If present, -h prevails; otherwise, the rightmost\n";
   print STDERR "      option wins in the case of contradictions.\n";
   exit;
   }                             # end subroutine usage