Merge from emacs--rel--22
[bpt/emacs.git] / lib-src / grep-changelog
index 4496a55..c4de805 100755 (executable)
@@ -1,13 +1,13 @@
 #! /usr/bin/perl
-# $Id: grep-changelog,v 1.1 1999/08/10 13:33:49 gerd Exp $
 
-# Copyright (C) 1999 Free Software Foundation, Inc.
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
+#               2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 #
 # This file is part of GNU Emacs.
 #
 # GNU Emacs 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 2, or (at your option)
+# the Free Software Foundation; either version 3, or (at your option)
 # any later version.
 #
 # GNU Emacs is distributed in the hope that it will be useful,
 #
 # You should have received a copy of the GNU General Public License
 # along with GNU Emacs; see the file COPYING.  If not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
 
 
 # Extract entries from ChangeLogs matching specified criteria.
 # Optionally format the resulting output to a form suitable for RCS
 # logs, like they are used in Emacs, for example.  In this format,
-# author lines leading spaces, and file names are removed.
+# author lines, leading spaces, and file names are removed.
 
 require 5;
+use strict;
 
 # Parse command line options.
 
+use vars qw($author $regexp $exclude $from_date $to_date
+            $rcs_log $with_date $version $help $reverse
+            @entries);
+
 use Getopt::Long;
-$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,
-                     "version" => \$version,
-                     "help"    => \$help);
-
-# If date options are specified, check that they have the format
-# YYYY-MM-DD.
-
-$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$/;
+
+my $result;
+
+if (@ARGV == 0) {
+
+    # No arguments cannot posibly mean "show everything"!!
+    $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);
+
+    # If date options are specified, check that they have the format
+    # YYYY-MM-DD.
+
+    $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$/;
+}
 
 # Print usage information and exit when necessary.
 
 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 
+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
-  --version              print version info
-  --help                 print this help
+  --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 
+"ChangeLog.N+" in the current directory.  Old-style dates in ChangeLogs
 are not recognized.
 USAGE
-    exit $help ? 0 : 1;
+    exit !$help;
 }
 
 # Print version info and exit if `--version' was specified.
 
 if ($version) {
-    print "0.1\n";
+    print "0.3\n";
     exit 0;
 }
 
@@ -86,9 +106,11 @@ if ($version) {
 # options specified, i.e. it matches $author, and its date is in
 # the range $from_date <= date <= $to_date.
 
-sub header_match_p ($) {
+sub header_match_p {
     my $header = shift;
 
+    return 0 unless $header;
+
     # No match if AUTHOR-regexp specified and doesn't match.
     return 0 if $author && $header !~ /$author/;
 
@@ -110,15 +132,17 @@ sub header_match_p ($) {
 }
 
 
-# Value is non-zero if ENTRY matches the ciiteria specified on the
+# Value is non-zero if ENTRY matches the criteria specified on the
 # command line, i.e. it matches $regexp, and it doesn't match
 # $exclude.
 
-sub entry_match_p ($) {
+sub entry_match_p {
     my $entry = shift;
 
+    return 0 unless $entry;
+
     if ($regexp) {
-       return 1 if ($entry =~ /$regexp/ 
+       return 1 if ($entry =~ /$regexp/
                     && (!$exclude || $entry !~ $exclude));
     } else {
        return 1 if !$exclude || $entry !~ $exclude;
@@ -133,8 +157,9 @@ sub entry_match_p ($) {
 # lines are not printed, and leading spaces and file names are removed
 # from ChangeLog entries.
 
-sub print_log ($$) {
+sub print_log {
     my ($header, $entry) = @_;
+    my $output = '';
 
     if ($rcs_log) {
        # Remove leading whitespace from entry.
@@ -145,44 +170,54 @@ sub print_log ($$) {
        $entry =~ s/^\*.*://mg;
         if ($with_date) {
            $header =~ /(\d\d\d\d-\d\d-\d\d)/;
-           print "!changelog-date $1\n";
+           $output = "!changelog-date $1\n";
        }
-       print $entry;
+       $output .= $entry;
     } else {
-       print $header, $entry;
+       $output .= $header . $entry;
+    }
+
+    if ($reverse) {
+        push @entries, $output;
+    } else {
+        print $output;
     }
 }
 
 # Scan LOG for matching entries, and print them to standard output.
 
-sub parse_changelog ($) {
+sub parse_changelog {
     my $log = shift;
-    my $entry;
-    my $match;
+    my $entry = undef;
+    my $header = undef;
+
+    @entries = () if $reverse;
 
     # Open the ChangeLog.
     open (IN, "< $log") || die "Cannot open $log: $!";
 
-    while ($line = <IN>) {
+    while (defined(my $line = <IN>)) {
        if ($line =~ /^\S/) {
            # Line is an author-line.  Print previous entry if
            # it matches.
-           print_log ($header, $entry) 
+           print_log ($header, $entry)
                if header_match_p ($header) && entry_match_p ($entry);
 
            $entry = "";
            $header = $line;
 
            # Add empty lines below the header.
-           while (($line = <IN>) && $line =~ /^\s*$/) {
+           while (defined($line = <IN>) && $line =~ /^\s*$/) {
                $header = "$header$line";
            }
-        } 
+        }
+
+        last unless defined $line;
 
        if ($line =~ /^\s*\*/) {
            # LINE is the first line of a ChangeLog entry.  Print
            # previous entry if it matches.
-           print_log ($header, $entry) 
+           print_log ($header, $entry)
                if header_match_p ($header) && entry_match_p ($entry);
            $entry = $line;
        } else {
@@ -192,29 +227,43 @@ sub parse_changelog ($) {
     }
 
     # Print last entry if it matches.
-    print_log ($header, $entry) 
+    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];
+        }
+    }
 }
 
 
 # Main program.  Process ChangeLogs.
 
-if (@ARGV > 0) {
-    # If files were specified on the command line, parse those files.
-    while ($log = shift @ARGV) {
-       parse_changelog ($log);
-    }
-} else {
-    # Parse default files ChangeLog and ChangeLog.9...ChangeLog.1 in
-    # that order.
-    parse_changelog ("ChangeLog");
-    for ($i = 9; $i >= 1; --$i) {
-       my $log = "ChangeLog.$i";
-       parse_changelog ($log) if -f $log;
-    }
+# If files were specified on the command line, parse those files in the
+# order supplied by the user; otherwise parse default files ChangeLog and
+# ChangeLog.NNN according to $reverse.
+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;
 }
 
 
-# gre-changelog ends here.
+# arch-tag: 9e4f6749-e053-4bb7-b3ad-11947318418e
+# grep-changelog ends here.