#!/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