#/usr/local/bin/perl
#
# Copyright (C) 1991 by Lutz Prechelt, Karlsruhe
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# If you don't have a copy of the GNU General Public License write to
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Author: Lutz Prechelt (
[email protected]),
# 23.03.91
# Change: Lutz Prechelt, 02.07.91
#
# Usage: see message at "die" below.
$infinity = 10000;
$precontext = 2;
$postcontext = 2;
$paragraphmode = 0;
$withlinenumber = 0;
$withfilename = 0;
$wrong_option = 0;
$reversemode = 0;
$delimiterstring = "-----------\n";
# $endpara = '\S.*\n';
sub showline {
if ($withfilename != 0) {
printf ("\"%s\"", $ARGV);
}
if ($withfilename != 0 && $withlinenumber != 0) {
print ",";
}
if ($withlinenumber != 0) {
printf ("%4d", $.);
}
if ($withfilename != 0 || $withlinenumber != 0) {
print ": ";
}
print ($_[0]);
}
# Process the Options:
do {
$something_done = 1;
if ($ARGV[0] =~ /^-(\d+)$/) {
$precontext = $postcontext = $1;
shift;
}
elsif ($ARGV[0] =~ /^-(\d+)[\,\+\/\;](\d+)$/) {
$precontext = $1;
$postcontext = $2;
shift;
}
elsif ($ARGV[0] =~ /^-d$/ && $#ARGV > 0) {
$delimiterstring = $ARGV[1];
$delimiterstring =~ s/\\n/\n/o;
shift; shift;
}
elsif ($ARGV[0] =~ /^-d(.*)$/) {
$delimiterstring = $1;
$delimiterstring =~ s/\\n/\n/o;
shift;
}
elsif ($ARGV[0] =~ /^-p$/) {
$paragraphmode = 1;
shift;
}
elsif ($ARGV[0] =~ /^-n$/) {
$withlinenumber = 1;
shift;
}
elsif ($ARGV[0] =~ /^-h$/) {
$withfilename = 1;
shift;
}
elsif ($ARGV[0] =~ /^-v$/) {
$reversemode = 1;
shift;
}
elsif ($ARGV[0] =~ /^-e$/) { # end options (for expressions starting with - )
$something_done = 0;
shift;
}
elsif ($ARGV[0] =~ /^-/) {
printf ("don't know option '%s'\n", $ARGV[0]);
$wrong_option = 1;
$something_done = 0;
shift;
}
else {
$something_done = 0;
}
} while ($something_done);
# Usage message:
if ($#ARGV == -1 || $wrong_option) {
die "
Usage: cgrep [-pre[,post]] [-p] [-v] [-h] [-n] [-d string] pattern
[file...]
cgrep is a context grep. It displays more than the one matching line for
every match (2 before and 2 after as default).
-3 means display 3 lines before and 3 lines after the match
-5,12 means display 5 lines before the match and 12 lines after
-p means display only as much of the context as belongs to the
current paragraph. (paragraphs bounded by empty lines)
-v means invert search (display nomatches)
-h means toggle display filename before every line
-n means display line number before every line
-d string means use string as the output delimiter string
pattern is a Perl regular expression (you better quote it !)
Exiting";
}
if (length (@ARGV) > 1) {
$withfilename = !$withfilename;
}
# Get the pattern and protect the delimiter.
$pat = shift;
$pat =~ s#/#\\/#g;
# current line will always be at end of array, i.e. $ary[$currentpre]
$_ = <>;
push(@ary,$_);
$currentpre = 0;
# now use @ary as a silo, shifting and pushing.
# the length of the @ary at any time is $currentpre + 1
# the current line is @ary[$currentpre], the postcontext is not held in @ary.
$seq = 0;
$lastoutput = $infinity; #last output is infinitely many lines ago
$cur = @ary[0]; #current line
while ($cur) { #as long as there is something to look at
if ($reversemode == 1 ? $cur !~ /$pat/o : $cur =~ /$pat/o) { #match found
if ($lastoutput <= $postcontext) {
&showline ($cur);
}
else {
print $delimiterstring if ($seq++ && $precontext + $postcontext > 0);
foreach $line (@ary) {
&showline ($line);
}
}
$lastoutput = 0;
}
elsif (($cur !~ /\S.*\n/o && $paragraphmode == 1) || eof) {
#paragraph/file end
for (; $currentpre >= 0; $currentpre--) {
shift (@ary);
}
$lastoutput = $infinity;
close (ARGV) if (eof);
}
elsif ($lastoutput <= $postcontext) { #another line of postcontext
&showline ($cur);
}
#goto next line of input:
$lastoutput++;
$_ = <> if $_;
push(@ary,$_);
if ($currentpre < $precontext) {
$currentpre++;
}
else {
shift(@ary);
}
$cur = $ary[$currentpre];
}