require 5;
use strict;
use vars qw($author $regexp $exclude $from_date $to_date
$rcs_log $with_date $version $help $reverse
@entries);
use Getopt::Long;
my $result;
if (@ARGV == 0) {
$result = 0;
} else {
$result = GetOptions ("author=s" => \$author,
"text=s" => \$regexp,
"exclude=s" => \$exclude,
"from-date=s" => \$from_date,
"to-date=s" => \$to_date,
"rcs-log" => \$rcs_log,
"with-date" => \$with_date,
"reverse!" => \$reverse,
"version" => \$version,
"help" => \$help);
$result = 0 if $from_date && $from_date !~ /^\d\d\d\d-\d\d-\d\d$/;
$result = 0 if $to_date && $to_date !~ /^\d\d\d\d-\d\d-\d\d$/;
}
if ($result == 0 || $help) {
print <<USAGE;
Usage: $0 [options] [CHANGELOG...]
Print entries in ChangeLogs matching various criteria.
Valid options are:
--author=AUTHOR Match entries whose author line matches
regular expression AUTHOR
--text=TEXT Match entries whose text matches regular
expression TEXT
--exclude=TEXT Exclude entries matching TEXT
--from-date=YYYY-MM-DD Match entries not older than given date
--to-date=YYYY-MM-DD Match entries not younger than given date
--rcs-log Format output suitable for RCS log entries
--with-date Print short date line in RCS log
--reverse Show entries in reverse (chronological) order
--version Print version info
--help Print this help
If no CHANGELOG is specified scan the files "ChangeLog" and
"ChangeLog.N+" in the current directory. Old-style dates in ChangeLogs
are not recognized.
USAGE
exit !$help;
}
if ($version) {
print "0.3\n";
exit 0;
}
sub header_match_p {
my $header = shift;
return 0 unless $header;
return 0 if $author && $header !~ /$author/;
if ($from_date || $to_date) {
if ($header =~ /^(\d\d\d\d-\d\d-\d\d)/) {
my $date = $1;
return 0 if $from_date && $date lt $from_date;
return 0 if $to_date && $date gt $to_date;
} else {
return 0;
}
}
return 1;
}
sub entry_match_p {
my $entry = shift;
return 0 unless $entry;
if ($regexp) {
return 1 if ($entry =~ /$regexp/
&& (!$exclude || $entry !~ $exclude));
} else {
return 1 if !$exclude || $entry !~ $exclude;
}
return 0;
}
sub print_log {
my ($header, $entry) = @_;
my $output = '';
if ($rcs_log) {
$entry =~ s/^\s+//mg;
$entry =~ s/^\*.*\(/(/mg;
$entry =~ s/^\*.*://mg;
if ($with_date) {
$header =~ /(\d\d\d\d-\d\d-\d\d)/;
$output = "!changelog-date $1\n";
}
$output .= $entry;
} else {
$output .= $header . $entry;
}
if ($reverse) {
push @entries, $output;
} else {
print $output;
}
}
sub parse_changelog {
my $log = shift;
my $entry = undef;
my $header = undef;
@entries = () if $reverse;
open (IN, "< $log") || die "Cannot open $log: $!";
while (defined(my $line = <IN>)) {
if ($line =~ /^\S/) {
print_log ($header, $entry)
if header_match_p ($header) && entry_match_p ($entry);
$entry = "";
$header = $line;
while (defined($line = <IN>) && $line =~ /^\s*$/) {
$header = "$header$line";
}
}
last unless defined $line;
if ($line =~ /^\s*\*/) {
print_log ($header, $entry)
if header_match_p ($header) && entry_match_p ($entry);
$entry = $line;
} else {
$entry = "$entry$line";
}
}
print_log ($header, $entry)
if header_match_p ($header) && entry_match_p ($entry);
close IN;
if ($reverse) {
for (my $entry = @entries; $entry; $entry--) {
print $entries[$entry-1];
}
}
}
unless (@ARGV > 0) {
@ARGV = ("ChangeLog");
push @ARGV,
map {"ChangeLog.$_"}
sort {$b <=> $a}
map {/\.(\d+)$/; $1}
do {
opendir D, '.';
grep /^ChangeLog\.\d+$/, readdir D;
};
@ARGV = reverse @ARGV if $reverse;
}
while (defined (my $log = shift @ARGV)) {
parse_changelog ($log) if -f $log;
}