Skip to content

Commit

Permalink
grep: implement -A context option
Browse files Browse the repository at this point in the history
* Show non-matching context lines after a matching line
* A new match may occur within the context lines being displayed; this resets the context counter unless the match limit (-m value) was already reached
* Display a line of "--" to indicate the end of the context block
* If -A is used with -n, follow line number with '-' instead of ':' to indicate context lines
* When -A is used with -m, terminate the search at the end of the context and not the exact line triggering match limit

%perl grep -n -A 8 perl ar # test1: context bleeds into the line8 match
1:#!/usr/bin/perl
2-
3-=begin metadata
4-
5-Name: ar
6-Description: create and maintain library archives
7-Author: dkulp
8:License: perl
9-
10-=end metadata
11-
12-=cut
13-
14-use strict;
15-
16-use POSIX qw(strftime);
--
%perl grep -n -A 8 -m 1 perl ar # test2: line8 match doesn't count due to -m1 limit
1:#!/usr/bin/perl
2-
3-=begin metadata
4-
5-Name: ar
6-Description: create and maintain library archives
7-Author: dkulp
8:License: perl
9-
--
%perl grep -A 4 perl ar # test3: no -n
#!/usr/bin/perl

=begin metadata

Name: ar
--
License: perl

=end metadata

=cut
--
  • Loading branch information
mknos authored Nov 13, 2024
1 parent 4932ef0 commit b6ad746
Showing 1 changed file with 40 additions and 10 deletions.
50 changes: 40 additions & 10 deletions bin/grep
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use File::Spec;
use File::Temp qw();
use Getopt::Std;

our $VERSION = '1.011';
our $VERSION = '1.012';

$| = 1; # autoflush output

Expand Down Expand Up @@ -88,7 +88,7 @@ sub VERSION_MESSAGE {

sub usage {
die <<EOF;
usage: $Me [-inCcwsxvHhLlFgurpaqT] [-e pattern] [-m NUM]
usage: $Me [-inCcwsxvHhLlFgurpaqT] [-e pattern] [-A NUM] [-m NUM]
[-f pattern-file] [-P sep] [pattern] [file...]
Options:
Expand All @@ -113,6 +113,7 @@ Options:
-r recursive on directories or dot if none
-p paragraph mode (default: line mode)
-P ditto, but specify separator, e.g. -P '%%\\n'
-A show lines after each matching line
-a treat binary files as plain text files
-s suppress errors for failed file and dir opens
-T trace files as opened
Expand Down Expand Up @@ -248,11 +249,14 @@ sub parse_args {
@ARGV = @tmparg;

$opt{'p'} = $opt{'P'} = ''; # argument to print()
getopts('inCcwsxvHhe:f:LlgurpP:aqTFZm:', \%opt) or usage();
getopts('inCcwsxvHhe:f:LlgurpP:aqTFZm:A:', \%opt) or usage();

if (defined $opt{'m'} && $opt{'m'} !~ m/\A[0-9]+\z/) {
die "$Me: invalid max count\n";
}
if (defined $opt{'A'} && $opt{'A'} !~ m/\A[0-9]+\z/) {
die "$Me: bad line count for -A\n";
}
$opt{'l'} = 0 if $opt{'L'};
my $no_re = $opt{F} || ( $Me =~ /\bfgrep\b/ );

Expand Down Expand Up @@ -454,23 +458,33 @@ FILE: while ( defined( $file = shift(@_) ) ) {
}

$total = $Matches = 0;
my $ctx_a = 0;

LINE: while (<$fh>) {
if (defined $opt->{'m'}) { # maximum may be zero
last LINE if $total >= $opt->{'m'};
last LINE if $total >= $opt->{'m'} && $ctx_a == 0;
}
$Matches = 0;

##############
&{$matcher}(); # do it! (check for matches)
##############

next LINE unless $Matches;
if ($ctx_a > 0) {
$ctx_a--; # show context line
} elsif (!$Matches) {
next LINE;
}

$total += $Matches;
last FILE if $opt->{'q'}; # single match for all files
last LINE if $opt->{'L'}; # one match is enough

if (defined $opt->{'A'} && $Matches) {
unless (defined($opt->{'m'}) && $opt->{'m'} < $total) {
$ctx_a = $opt->{'A'};
}
}
if ( $opt->{p} || $opt->{P} ) {
s/\n{2,}$/\n/ if $opt->{p};
chomp if $opt->{P};
Expand All @@ -485,8 +499,21 @@ FILE: while ( defined( $file = shift(@_) ) ) {
}
unless ($opt->{'c'}) {
print($name, ':') if $Mult;
print $opt->{n} ? "$.:" : "", $_,
( $opt->{p} || $opt->{P} ) && ( '-' x 20 ) . "\n";
if ($opt->{'n'}) {
print $.;
if ($Matches) {
print ':';
} else {
print '-';
}
}
print $_;
if ($opt->{'p'} || $opt->{'P'}) {
print ('-' x 20), "\n";
}
}
if ($ctx_a == 0 && !$Matches) {
print "--\n";
}
}
close $fh;
Expand All @@ -513,9 +540,8 @@ grep - search for regular expressions and print
=head1 SYNOPSIS
B<grep> [ B<-[incCwsxvhHlLFigurpaqT]> ] [ B<-e> I<pattern> ] [ B<-m> I<NUM> ]
[ B<-f> I<pattern-file> ] [ B<-P> I<sep> ] [ I<pattern> ] [ I<files> ... ]
grep [-incCwsxvhHlLFigurpaqT] [-e pattern] [-A NUM] [-m NUM]
[-f pattern-file] [-P sep] [pattern] [file ...]
=head1 DESCRIPTION
Expand All @@ -541,6 +567,10 @@ The following options are accepted:
Display a maximum of NUM matches per file.
=item B<-A> I<NUM>
Display NUM lines of context after each matching line.
=item B<-a>
List matching lines from binary files as if they were plain text files.
Expand Down

0 comments on commit b6ad746

Please sign in to comment.