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 = 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.[9-1]" in the current directory. Old-style dates in ChangeLogs
are not recognized.
USAGE
exit $help ? 0 : 1;
}
if ($version) {
print "0.1\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) {
while (defined (my $entry = pop @entries)) {
print $entry;
}
}
}
unless (@ARGV > 0) {
@ARGV = ("ChangeLog", map {"ChangeLog.$_"} reverse 1..9);
@ARGV = reverse @ARGV if $reverse;
}
while (defined (my $log = shift @ARGV)) {
parse_changelog ($log) if -f $log;
}