#!/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. # Version: 2, Patchlevel 0 # Author: Lutz Prechelt (prechelt@ira.uka.de), 23.03.91 # Correction by Sridhar Vasudevan, 03.07.91 # Last Change: Lutz Prechelt, 1995/04/05 # # Usage: see message at "die" below. #---------- constants: $infinity = 10000; #---------- Variables and their Defaults: $delimiterstring = "\n"; $matches = 0; $precontext = 2; $postcontext = 2; $wrong_option = 0; #---------- boolean Options: $paragraphmode = 0; $count_matches = 0; $ignorecase = 0; $withlinenumber = 0; $withfilename = 0; $reversemode = 0; # $endpara = '\S.*\n'; #---------- Subroutines: sub match_found { #bad style: uses the global variables # $ignorecase, $reversemode, $cur, $pat if ($ignorecase != 0) { ($reversemode == 1 ? $cur !~ /$pat/io : $cur =~ /$pat/io); } else { ($reversemode == 1 ? $cur !~ /$pat/o : $cur =~ /$pat/o); } } sub showline { if ($withfilename != 0) { printf ("\"%s\"", $ARGV); } if ($withfilename != 0 && $withlinenumber != 0) { print ","; } if ($withlinenumber != 0) { printf ("%4d", $_[1]); } 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] =~ /^-c$/) { $count_matches = 1; shift; } elsif ($ARGV[0] =~ /^-h$/) { $withfilename = 1; shift; } elsif ($ARGV[0] =~ /^-i$/) { $ignorecase = 1; shift; } elsif ($ARGV[0] =~ /^-n$/) { $withlinenumber = 1; shift; } elsif ($ARGV[0] =~ /^-p$/) { $paragraphmode = 1; shift; } elsif ($ARGV[0] =~ /^-v$/) { $reversemode = 1; shift; } elsif (($ARGV[0] =~ /^-e$/) || ($ARGV[0] =~ /^--$/)) { # 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] [-c] [-h] [-n] [-d string] [-e] 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 (e.g.) -5,12 means display 5 lines before the match and 12 lines after (e.g.) -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) -c means display number of matching lines at the end of run -h means toggle display filename before every line -i means ignore case when matching the regexp -n means display line number before every line -d string means use string as the output delimiter string -- (or -e) means end options (i.e. now comes the pattern, for patterns starting with - ) pattern is a Perl regular expression (you better quote it !) Exiting"; } if ($#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; #---------- do the search # 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 (&match_found()) { $matches++; if ($lastoutput <= $postcontext) { &showline ($cur, $.); } else { print $delimiterstring if ($seq++ && $precontext + $postcontext > 0); $lineno = $. - $#ary; foreach $line (@ary) { &showline ($line, $lineno++); } } $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]; } #---------- perhaps display number of matches: if ($count_matches != 0) { printf ("%d\n", $matches); }