#!/usr/bin/perl -wT
#
<<<<<<< log_accum.pl
<<<<<<< log_accum.pl
<<<<<<< log_accum.pl
# $FreeBSD: CVSROOT/log_accum.pl,v 1.44 2000/08/30 08:08:47 joe Exp $
=======
# $FreeBSD: CVSROOT/log_accum.pl,v 1.72 2001/04/24 10:17:26 joe Exp $
>>>>>>> 1.72
=======
# $FreeBSD: CVSROOT/log_accum.pl,v 1.73 2001/05/07 20:31:12 joe Exp $
>>>>>>> 1.73
=======
# $FreeBSD: CVSROOT/log_accum.pl,v 1.74 2001/05/12 22:16:17 joe Exp $
>>>>>>> 1.74
#
# Perl filter to handle the log messages from the checkin of files in
# a directory.  This script will group the lists of files by log
# message, and mail a single consolidated log message at the end of
# the commit.
#
# This file assumes a pre-commit checking program that leaves the
# names of the first and last commit directories in a temporary file.
#
# Originally by David Hampton <hampton@cisco.com>
#
# Extensively hacked for FreeBSD by Peter Wemm <peter@netplex.com.au>,
#  with parts stolen from Greg Woods <woods@most.wierd.com> version.
#
# Lightly hacked by Mark Murray to allow it to work unmodified
#  on both the master repository (freefall) and the international
#  crypto repository (internat).
#

require 5.003;		# might work with older perl5

<<<<<<< log_accum.pl
use strict;
=======
###use strict;
use Sys::Hostname;	# get hostname() function
>>>>>>> 1.72


############################################################
#
# Environment
#
############################################################
<<<<<<< log_accum.pl
umask (002);

my $CVSROOT = $ENV{'CVSROOT'} || "/home/ncvs";
my $PID     = getpgrp();
my $LOGIN   = $ENV{USER} || getlogin || (getpwuid($<))[0] ||
		sprintf("uid#%d",$<);

# Detaint the world.
$ENV{PATH}  = "/bin:/sbin:/usr/bin:/usr/sbin";
delete	    @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$CVSROOT    =~ /(.*)/;
$CVSROOT    = $1;

# Get our configuration.
require		"$CVSROOT/CVSROOT/config.pm";
use vars	qw($DEBUG $MAILCMD $MAILBANNER 
		@RCSTEMPLATE_KEYWORDS $MAILADDRS $RCSIDINFO
		$X_BRANCH_HDR
		$TMPDIR $FILE_PREFIX @LOGFILE_MAP);
import config;


=======
#
# Where do you want the RCS ID and delta info?
# 0 = none,
# 1 = in mail only,
# 2 = rcsids in both mail and logs.
#
my $RCSIDINFO = 2;

# Debug level, 0 = off
my $DEBUG = 0;

# The command used to mail the log messages.  Usually something
# like '/usr/sbin/sendmail'.  
my $MAILCMD = "/usr/local/bin/mailsend -H";


# Email addresses of recipients of commit mail. (might be overridden below)
my $MAILADDRS = "nobody";


# Extra banner to add to top of commit messages.
# i.e. $MAILBANNER = "Project X CVS Repository";
my $MAILBANNER = "";


# Location of temporary directory.
my $TMPDIR = "/tmp/";


# The file prefix used for the temporary files.
my $FILE_PREFIX = "#cvs.files";


#-------------------------------------------------------
# FreeBSD site localisation
# Remember to comment out if using for other purposes.
#-------------------------------------------------------
if (hostname() =~ /^(freefall|internat)\.freebsd\.org$/i) {
	my $meister;

	$MAILADDRS='cvs-committers@FreeBSD.org cvs-all@FreeBSD.org';
	if ($1 =~ /freefall/i) {
		$meister = 'peter@FreeBSD.org';
	} else {
		$meister = 'markm@FreeBSD.org';
		$MAILBANNER = "FreeBSD International Crypto Repository";
	}
	$MAILADDRS = $meister if $DEBUG;
}


>>>>>>> 1.72
############################################################
#
# Constants
#
############################################################
<<<<<<< log_accum.pl
my $STATE_NONE    = 0;
my $STATE_CHANGED = 1;
my $STATE_ADDED   = 2;
my $STATE_REMOVED = 3;
my $STATE_LOG     = 4;

my $BASE_FN	  = "$TMPDIR/$FILE_PREFIX";
my $LAST_FILE     = "$BASE_FN.lastdir";
my $CHANGED_FILE  = "$BASE_FN.changed";
my $ADDED_FILE    = "$BASE_FN.added";
my $REMOVED_FILE  = "$BASE_FN.removed";
my $LOG_FILE      = "$BASE_FN.log";
my $SUMMARY_FILE  = "$BASE_FN.summary";
my $MAIL_FILE     = "$BASE_FN.mail";
my $SUBJ_FILE     = "$BASE_FN.subj";
my $TAGS_FILE     = "$BASE_FN.tags";
=======
my $STATE_NONE    = 0;
my $STATE_CHANGED = 1;
my $STATE_ADDED   = 2;
my $STATE_REMOVED = 3;
my $STATE_LOG     = 4;

my $BASE_FN       = "$TMPDIR/$FILE_PREFIX";
my $LAST_FILE     = "$BASE_FN.lastdir";
my $CHANGED_FILE  = "$BASE_FN.changed";
my $ADDED_FILE    = "$BASE_FN.added";
my $REMOVED_FILE  = "$BASE_FN.removed";
my $LOG_FILE      = "$BASE_FN.log";
my $SUMMARY_FILE  = "$BASE_FN.summary";
my $MAIL_FILE     = "$BASE_FN.mail";
my $SUBJ_FILE     = "$BASE_FN.subj";
my $TAGS_FILE     = "$BASE_FN.tags";
>>>>>>> 1.72

<<<<<<< log_accum.pl
=======
my $X_BRANCH_HDR  = "X-FreeBSD-CVS-Branch:";

my $CVSROOT       = $ENV{'CVSROOT'} || "/home/ncvs";
>>>>>>> 1.72

<<<<<<< log_accum.pl

=======
my $PID = getpgrp();		# Process id; used for generating filenames.


>>>>>>> 1.72
############################################################
#
# Subroutines
#
############################################################

<<<<<<< log_accum.pl
# Remove any temp files created for this process.
=======
# Remove the temporary files.
>>>>>>> 1.72
sub cleanup_tmpfiles {
<<<<<<< log_accum.pl
    # Don't clean up afterward if in debug mode.
    return if $DEBUG;

    my @files;

    opendir DIR, $TMPDIR or die "Cannot open directory: $TMPDIR!";
    push @files, grep /^$FILE_PREFIX\..*$PID$/, readdir(DIR);
    closedir DIR;
    foreach (@files) {
	unlink "$TMPDIR/$_";
    }
}
=======
	my @files;		# The list of temporary files.

	# Don't clean up afterwards if in debug mode.
	return if $DEBUG;
>>>>>>> 1.72

<<<<<<< log_accum.pl
sub append_to_logfile {
    my ($filename, @files, @lines) = @_;

    open FILE, ">>$filename" or die "Cannot append to file $filename!";
    print FILE join("\n", @lines), "\n";
    close FILE;
=======
	opendir DIR, $TMPDIR or die "Cannot open directory: $TMPDIR!";
	push @files, grep /^$FILE_PREFIX\..*$PID$/, readdir(DIR);
	closedir DIR;

	foreach (@files) {
		unlink "$TMPDIR/$_";
	}
>>>>>>> 1.72
}


# Append a line to a named file.
sub append_line {
<<<<<<< log_accum.pl
    my ($filename, $line) = @_;
    open FILE, ">>$filename" or die "Cannot open for append file $filename.\n";
    print FILE "$line\n";
    close FILE;
=======
	my $filename = shift;	# File to append to.
	my $line = shift;	# Line to append.

	open FILE, ">>$filename" or
	    die "Cannot open for append file $filename.\n";
	print FILE "$line\n";
	close FILE;
>>>>>>> 1.72
}


# Read the first line from a named file.
sub read_line {
<<<<<<< log_accum.pl
    my $filename = shift;

    open FILE, "<$filename" or die "Cannot read file $filename!";
    my $line = <FILE>;
    close FILE;
    chomp $line;
    return $line;
=======
	my $filename = shift;	# The file to read the line from.

	my $line;		# The line read from the file.

	open FILE, "<$filename" or die "Cannot read file $filename!";
	$line = <FILE>;
	close FILE;
	chomp $line;

	return $line;
>>>>>>> 1.72
}


# Return the contents of a file as a list of strings,
# with trailing line feeds removed.
# Return an empty list of the file couldn't be opened for some reason.
sub read_logfile {
<<<<<<< log_accum.pl
    my $filename = shift;

    my @text = ();
    open FILE, "<$filename" and do {
	while (<FILE>) {
	    chomp;
	    push @text, $_;
	}
	close FILE;
    };
    return @text;
=======
	my $filename = shift;	# The file to read from.

	my @text = ();		# The contents of the file.

	if (open FILE, "<$filename") {
		while (<FILE>) {
			chomp;
			push @text, $_;
		}
		close FILE;
	}

	return @text;
>>>>>>> 1.72
}


# Write a list to a file.
sub write_logfile {
<<<<<<< log_accum.pl
    my ($filename, @lines) = @_;
=======
	my $filename = shift;	# File to write to.
	my @lines = @_;		# Contents to write to file.
>>>>>>> 1.72

<<<<<<< log_accum.pl
    open FILE, ">$filename" or die "Cannot write to $filename!";
    print FILE join("\n", @lines), "\n";
    close FILE;
=======
	open FILE, ">$filename" or
	    die "Cannot open for write log file $filename.";
	print FILE join("\n", @lines), "\n";
	close FILE;
>>>>>>> 1.72
}


sub format_names {
<<<<<<< log_accum.pl
    my ($dir, @files) = @_;
=======
	my $dir = shift;
	my @files = @_;
>>>>>>> 1.72

<<<<<<< log_accum.pl
    my $indent = length $dir;
    if ($indent < 20) {
	$indent = 20;
    }

    my $format = "    %-" . sprintf("%d", $indent) . "s ";

    my @lines = (sprintf($format, $dir));

    if ($DEBUG) {
	print STDERR "format_names(): dir = ", $dir;
	#XXX print STDERR "tag = ", $tag;
	print STDERR "; files = ", join(":", @files), ".\n";
    }
    foreach my $file (@files) {
	if (length($lines[$#lines]) + length($file) > 66) {
	    $lines[++$#lines] = sprintf($format, "", "");
=======
	my $indent = length($dir);
	$indent = 20 if $indent < 20;

	my $format = "    %-" . sprintf("%d", $indent) . "s ";

	my @lines = (sprintf($format, $dir));

	if ($DEBUG) {
		print STDERR "format_names(): dir = ", $dir;
		#print STDERR "; tag = ", $tag;
		print STDERR "; files = ", join(":", @files), ".\n";
>>>>>>> 1.72
	}

<<<<<<< log_accum.pl
    return @lines;
=======
	foreach my $file (@files) {
		if (length($lines[$#lines]) + length($file) > 66) {
			$lines[++$#lines] = sprintf($format, "", "");
		}
		$lines[$#lines] .= $file . " ";
	}

	return @lines;
>>>>>>> 1.72
}

<<<<<<< log_accum.pl
sub format_lists {
    my ($header, @lines) = @_;

    print STDERR "format_lists(): ", join(":", @lines), "\n" if $DEBUG;
=======

sub format_lists {
	my $header = shift;
	my @lines = @_;
>>>>>>> 1.72

<<<<<<< log_accum.pl
    my @text = ();
    my @files = ();
    my $lastdir = '';
    my $lastsep = '';

    my $tag;
    foreach my $line (@lines) {
	if ($line =~ /.*\/$/) {
	    if ($lastdir ne '') {
		push @text, &format_names($lastdir, @files);
	    }
	    $lastdir = $line;
	    $lastdir =~ s,/$,,;
	    $tag = "";	# next thing is a tag
	    @files = ();
	} elsif ($tag eq '') {
	    $tag = $line;
	    next if ($header . $tag eq $lastsep);
	    $lastsep = $header . $tag;
	    if ($tag eq 'HEAD') {
		push(@text, "  $header files:");
	    } else {
		push(@text, sprintf("  %-22s (Branch: %s)", "$header files:",
		    $tag));
	    }
	} else {
	    push(@files, $line);
=======
	my @text = ();
	my @files = ();
	my $lastdir = '';
	my $lastsep = '';

	print STDERR "format_lists(): ", join(":", @lines), "\n" if $DEBUG;

	foreach my $line (@lines) {
		if ($line =~ /.*\/$/) {
			if ($lastdir) {
				push @text, &format_names($lastdir, @files);
			}

			$lastdir = $line;
			$lastdir =~ s,/$,,;
			$tag = "";	# next thing is a tag
			@files = ();
		} elsif (!$tag) {
			$tag = $line;
			next if ($header . $tag eq $lastsep);
			$lastsep = $header . $tag;
			if ($tag eq 'HEAD') {
				push @text, "  $header files:";
			} else {
				push @text, sprintf("  %-22s (Branch: %s)",
				    "$header files:", $tag);
			}
		} else {
			push @files, $line;
		}
>>>>>>> 1.72
	}
<<<<<<< log_accum.pl
    }
    push @text, &format_names($lastdir, @files);
=======
	push @text, &format_names($lastdir, @files);
>>>>>>> 1.72

<<<<<<< log_accum.pl
    return @text;
=======
	return @text;
>>>>>>> 1.72
}


sub append_names_to_file {
<<<<<<< log_accum.pl
    my ($filename, $dir, $tag, @files) = @_;

    if (@files) {
	open FILE, ">>$filename" or die "Cannot append to $filename!";
=======
	my $filename = shift;
	my $dir = shift;
	my $tag = shift;
	my @files = @_;

	return unless @files;

	open FILE, ">>$filename" or die "Cannot append to file $filename.";

>>>>>>> 1.72
	print FILE $dir, "\n";
	print FILE $tag, "\n";
	print FILE join("\n", @files), "\n";
<<<<<<< log_accum.pl
	close FILE;
    }
=======
	close FILE;
>>>>>>> 1.72
}


#
# Summarise the file changes in the commit using 'cvs -Qn status'
# on each file to extract the info.
#
sub change_summary_changed {
<<<<<<< log_accum.pl
    my ($out, $tag, @filenames) = @_;

    foreach my $file (@filenames) {
	next unless $file;

	open(RCS, "-|") || exec 'cvs', '-Qn', 'status', $file;

	my $rev = "";
	my $delta = "";
	my $rcsfile = "";

	while (<RCS>) {
	    if (/^[ \t]*Repository revision/) {
		chomp;
		#XXX my @revline = split /\s*/, $_;
		my @revline = split;
		$rev = $revline[2];
		$revline[3] =~ m|^$CVSROOT/+(.*),v$|;
		$rcsfile = $1;
		last;
	    }
	}
	close RCS;

	if ($rev and $rcsfile) {
	    open(RCS, "-|") || exec 'cvs', '-Qn', 'log', "-r$rev", $file;
	    while (<RCS>) {
		if (/^date:.*lines:\s(.*)$/) {
		    $delta = $1;
		    last;
		}
	    }
	    close RCS;
	}
=======
	my $outfile = shift;		# File name of output file.
	my @filenames = @_;		# List of files to check.

	foreach my $file (@filenames) {
		next unless $file;

		my $rev = "";
		my $delta = "";
		my $rcsfile = "";

		open(RCS, "-|") || exec 'cvs', '-Qn', 'status', $file;
		while (<RCS>) {
			if (/^[ \t]*Repository revision/) {
				chomp;
				my @revline = split;
				$rev = $revline[2];
				$revline[3] =~ m|^$CVSROOT/+(.*),v$|;
				$rcsfile = $1;
				last;
			}
		}
		close RCS;

		if ($rev and $rcsfile) {
			open(RCS, "-|") || exec 'cvs', '-Qn', 'log', "-r$rev", $file;
			while (<RCS>) {
				if (/^date:.*lines:\s(.*)$/) {
					$delta = $1;
					last;
				}
			}
			close RCS;
		}
>>>>>>> 1.72

		&append_line($outfile, "$rev,$delta,$rcsfile");
	}
}

# Write these one day.
sub change_summary_added {
}
sub change_summary_removed {
}

sub build_header {
<<<<<<< log_accum.pl
    delete $ENV{'TZ'};

    my $datestr = `/bin/date +"%Y/%m/%d %H:%M:%S %Z"`;
    chomp $datestr;
    my $header = sprintf("%-8s    %s", $LOGIN, $datestr);

    my @text;
    push @text, $header;
    push @text, "";
    push @text, $MAILBANNER if $MAILBANNER;
=======
	delete $ENV{'TZ'};

	my $datestr = `/bin/date +"%Y/%m/%d %H:%M:%S %Z"`;
	chomp $datestr;

	my $header = sprintf("%-8s    %s", $login, $datestr);
>>>>>>> 1.72

<<<<<<< log_accum.pl
    return @text;
=======
	my @text;
	push @text, $header;
	push @text, "";
	push @text, "$MAILBANNER\n" if $MAILBANNER;

	return @text;
>>>>>>> 1.72
}

<<<<<<< log_accum.pl
# XXX !!! Mailing-list and commitlog history file mappings here !!!
sub name_commit_log {
    my $dir = shift;
=======
# !!! Mailing-list and commitlog history file mappings here !!!
# This needs pulling out as a configuration block somewhere so
# that others can easily change it.
sub mlist_map {
	my $dir = shift;	# Directory name
>>>>>>> 1.72
   
<<<<<<< log_accum.pl
    foreach my $i (0 .. (scalar @LOGFILE_MAP / 2) - 1) {
	my $pattern = $LOGFILE_MAP[$i * 2];
	my $filename = $LOGFILE_MAP[$i * 2 + 1];

	$pattern =~ s/\//\\\//g;
	$pattern =~ s/\./\\./g;
	$pattern =~ s/\*/\[\^\\\/\]\*/g;

	return $filename if $dir =~ /^$pattern/;
    }
=======
	return 'cvs-CVSROOT'	if $dir =~ /^CVSROOT\//;
	return 'cvs-ports'	if $dir =~ /^ports\//;
	return 'cvs-www'	if $dir =~ /^www\//;
	return 'cvs-doc'	if $dir =~ /^doc\//;
	return 'cvs-distrib'	if $dir =~ /^distrib\//;

	return 'cvs-other'	unless $dir =~ /^src\//;

	$dir =~ s,^src/,,;

	return 'cvs-bin'	if $dir =~ /^bin\//;
	return 'cvs-contrib'	if $dir =~ /^contrib\//;
	return 'cvs-eBones'	if $dir =~ /^eBones\//;
	return 'cvs-etc'	if $dir =~ /^etc\//;
	return 'cvs-games'	if $dir =~ /^games\//;
	return 'cvs-gnu'	if $dir =~ /^gnu\//;
	return 'cvs-include'	if $dir =~ /^include\//;
	return 'cvs-kerberosIV'	if $dir =~ /^kerberosIV\//;
	return 'cvs-lib'	if $dir =~ /^lib\//;
	return 'cvs-libexec'	if $dir =~ /^libexec\//;
	return 'cvs-lkm'	if $dir =~ /^lkm\//;
	return 'cvs-release'	if $dir =~ /^release\//;
	return 'cvs-sbin'	if $dir =~ /^sbin\//;
	return 'cvs-share'	if $dir =~ /^share\//;
	return 'cvs-sys'	if $dir =~ /^sys\//;
	return 'cvs-tools'	if $dir =~ /^tools\//;
	return 'cvs-usrbin'	if $dir =~ /^usr\.bin\//;
	return 'cvs-usrsbin'	if $dir =~ /^usr\.sbin\//;
>>>>>>> 1.72

<<<<<<< log_accum.pl
    return "unknown";
}
=======
	return 'cvs-user';
}    
>>>>>>> 1.72

sub do_changes_file {
<<<<<<< log_accum.pl
    my @text = @_;

    my %unique = ();
    my @mailaddrs = &read_logfile("$MAIL_FILE.$PID");
    foreach my $category (@mailaddrs) {
	next if $unique{$category};
	$unique{$category} = 1;
	if ($category =~ /^cvs-/) {
	    # convert mailing list name back to category
	    $category =~ /^cvs-([a-z]*$)/ or die "Erp!\n";

	    my $changes = "$CVSROOT/CVSROOT/commitlogs/$1";
	    open CHANGES, ">>$changes" or die "Cannot open $changes.\n";
	    print CHANGES join("\n", @text), "\n\n";
	    close CHANGES;
=======
	my @text = @_;

	my %unique = ();
	my @mailaddrs = &read_logfile("$MAIL_FILE.$PID");
	foreach my $category (@mailaddrs) {
		next if ($unique{$category});
		$unique{$category} = 1;
		if ($category =~ /^cvs-/) {
			# convert mailing list name back to category
			chomp $category;
			$category =~ s/^cvs-//;

			my $changes = "$CVSROOT/CVSROOT/commitlogs/$category";
			open CHANGES, ">>$changes"
				or die "Cannot open $changes.\n";
			print CHANGES join("\n", @text), "\n\n";
			close CHANGES;
		}
>>>>>>> 1.72
	}
}

sub mail_notification {
<<<<<<< log_accum.pl
    my @text = @_;
=======
	my @text = @_;
>>>>>>> 1.72

<<<<<<< log_accum.pl
    print "Mailing the commit message...\n";
=======
	print "Mailing the commit message...\n";
>>>>>>> 1.72

<<<<<<< log_accum.pl
    my @mailaddrs = &read_logfile("$MAIL_FILE.$PID");
    open MAIL, "| $MAILCMD $MAILADDRS" or die 'Please check $MAILCMD.';
=======
	my @mailaddrs = &read_logfile("$MAIL_FILE.$PID");
	open MAIL, "| $MAILCMD $MAILADDRS" or die 'Please check $MAILCMD.';
>>>>>>> 1.72

# This is turned off since the To: lines go overboard.
# Also it has bit-rotted since, and can't just be switched on again.
# - but keep it for the time being in case we do something like cvs-stable
<<<<<<< log_accum.pl
#    my %unique = ();
#    print(MAIL 'To: cvs-committers' . $dom . ", cvs-all" . $dom);
#    foreach $line (@mailaddrs) {
#	next if ($unique{$line});
#	$unique{$line} = 1;
#	next if /^cvs-/;
#	print(MAIL ", " . $line . $dom);
#    }
#    print(MAIL "\n");

    my $subject = 'Subject: cvs commit:';
    my @subj = &read_logfile("$SUBJ_FILE.$PID");
    my $subjlines = 0;
    my $subjwords = 0;	# minimum of two "words" per line
    LINE: foreach my $line (@subj) {
	foreach my $word (split(/ /, $line)) {
	    if ($subjwords > 2 && length($subject . " " . $word) > 75) {
		if ($subjlines > 2) {
		    $subject .= " ...";
		}
		print MAIL $subject, "\n";
		if ($subjlines > 2) {
		    $subject = "";
		    last LINE;
=======
#	print(MAIL 'To: cvs-committers' . $dom . ", cvs-all" . $dom);
#	foreach $line (@mailaddrs) {
#		next if ($unique{$line});
#		$unique{$line} = 1;
#		next if /^cvs-/;
#		print(MAIL ", " . $line . $dom);
#	}
#	print(MAIL "\n");

	my $subject = 'Subject: cvs commit:';
	my @subj = &read_logfile("$SUBJ_FILE.$PID");
	my $subjlines = 0;
	my $subjwords = 0;	# minimum of two "words" per line
	LINE: foreach my $line (@subj) {
		foreach my $word (split(/ /, $line)) {
			if ($subjwords > 2 &&
			    length($subject . " " . $word) > 75) {
				if ($subjlines > 2) {
					$subject .= " ...";
				}
				print MAIL $subject, "\n";
				if ($subjlines > 2) {
					$subject = "";
					last LINE;
				}

				# rfc822 continuation line
				$subject = "        ";
				$subjwords = 0;
				$subjlines++;
			}
			$subject .= " " . $word;
			$subjwords++;
>>>>>>> 1.72
		}
<<<<<<< log_accum.pl
		$subject = "        ";		# rfc822 continuation line
		$subjwords = 0;
		$subjlines++;
	    }
	    $subject .= " " . $word;
	    $subjwords++;
	}
    }
    print MAIL $subject, "\n" if $subject;

    # Add a header to the mail msg showing which branches
    # were modified during the commit if required.
    if ($X_BRANCH_HDR) {
	    my %tags = map { $_ => 1 } &read_logfile("$TAGS_FILE.$PID");
	    print MAIL "$X_BRANCH_HDR ", join(",", sort keys %tags), "\n";
    }
=======
	}
	print MAIL "$subject\n" if $subject;
>>>>>>> 1.72

<<<<<<< log_accum.pl
    print MAIL "\n";
=======
	# If required add a header to the mail msg showing
	# which branches were modified during the commit.
	if ($X_BRANCH_HDR) {
		my %tags = map { $_ => 1 } &read_logfile("$TAGS_FILE.$PID");
		print MAIL "$X_BRANCH_HDR ", join(",", sort keys %tags), "\n";
	}
>>>>>>> 1.72

<<<<<<< log_accum.pl
    print MAIL join "\n", @text;
    close MAIL;
=======
	print MAIL "\n";
	print MAIL join("\n", @text);
	close MAIL;
>>>>>>> 1.72
}


# Return the length of the longest value in the list.
sub longest_value {
	my @values = @_;

	my @sorted = sort { $b <=> $a } map { length $_ } @values;
	return $sorted[0];
}

sub format_summaries {
	my @filenames = @_;

	my @revs;
	my @deltas;
	my @files;

	# Parse the summary file.
	foreach my $filename (@filenames) {
		open FILE, $filename or next;
		while (<FILE>) {
			chomp;
			my ($r, $d, $f) = split /,/, $_;
			push @revs, $r;
			push @deltas, $d;
			push @files, $f;
		}
		close FILE;
	}    

<<<<<<< log_accum.pl
    # Format the output
    my $r_max = longest_value("Revision", @revs) + 2;
    my $d_max = longest_value("Changes", @deltas) + 2;

    my @text;
    my $fmt = "%-" . $r_max . "s%-" . $d_max . "s%s";
    push @text, sprintf $fmt, "Revision", "Changes", "Path";
    foreach (0 .. $#revs) {
	push @text, sprintf $fmt, $revs[$_], $deltas[$_], $files[$_];
    }
=======
	# Format the output, extra spaces after "Changes"
	# to match historic formatting.
	my $r_max = longest_value("Revision", @revs) + 2;
	my $d_max = longest_value("Changes  ", @deltas) + 2;

	my @text;
	my $fmt = "%-" . $r_max . "s%-" . $d_max . "s%s";
	push @text, sprintf $fmt, "Revision", "Changes", "Path";
	foreach (0 .. $#revs) {
		push @text, sprintf $fmt, $revs[$_], $deltas[$_], $files[$_];
	}
>>>>>>> 1.72

	return @text;
}

#############################################################
#
# Main Body
#
############################################################

<<<<<<< log_accum.pl
=======
#
# Setup environment
#
umask (002);
>>>>>>> 1.72

#
# Initialize basic variables
#
<<<<<<< log_accum.pl
my $filenames = $ARGV[0];
die "Error: No files specified, were we evoked properly?\n" unless $filenames;


my $state = $STATE_NONE;
my $tag = '';
my @files = split(' ', $filenames);
my @path = split('/', $files[0]);
my $header;
my @text;

my $dir;
=======
$login = $ENV{'USER'} || getlogin || (getpwuid($<))[0] || sprintf("uid#%d",$<);
@files = split(' ', $ARGV[0]);
@path = split('/', $files[0]);
>>>>>>> 1.72
if ($#path == 0) {
	$dir = ".";
} else {
	$dir = join('/', @path[1..$#path]);
}
$dir = $dir . "/";

<<<<<<< log_accum.pl
if ($DEBUG) {
  print("ARGV  - ", join(":", @ARGV), "\n");
  print("files - ", join(":", @files), "\n");
  print("path  - ", join(":", @path), "\n");
  print("dir   - ", $dir, "\n");
  print("pid   - ", $PID, "\n");
=======
if ($DEBUG) {
	print("ARGV  - ", join(":", @ARGV), "\n");
	print("files - ", join(":", @files), "\n");
	print("path  - ", join(":", @path), "\n");
	print("dir   - ", $dir, "\n");
	print("pid   - ", $PID, "\n");
>>>>>>> 1.72
}

# Was used for To: lines, still used for commitlogs naming.
<<<<<<< log_accum.pl
&append_line("$MAIL_FILE.$PID", name_commit_log($files[0] . "/"));
&append_line("$SUBJ_FILE.$PID", $ARGV[0]);
=======
&append_line("$MAIL_FILE.$PID", &mlist_map($files[0] . "/"));
&append_line("$SUBJ_FILE.$PID", $ARGV[0]);
>>>>>>> 1.72

#
# Check for a new directory first.  This will always appear as a
# single item in the argument list, and an empty log message.
#
if ($ARGV[0] =~ /New directory/) {
<<<<<<< log_accum.pl
    @text = &build_header();

    push @text, "  ".$ARGV[0];
    &do_changes_file(@text);
    #&mail_notification(@text);
    &cleanup_tmpfiles();
    exit 0;
=======
	@text = &build_header();

	push(@text, "  ".$ARGV[0]);
	&do_changes_file(@text);
	#&mail_notification(@text);
	&cleanup_tmpfiles();
	exit 0;
>>>>>>> 1.72
}

#
# Check for an import command.  This will always appear as a
# single item in the argument list, and a log message.
#
if ($ARGV[0] =~ /Imported sources/) {
<<<<<<< log_accum.pl
    @text = &build_header();

    push @text, "  ".$ARGV[0];
    &do_changes_file(@text);
=======
	@text = &build_header();

	push(@text, "  ".$ARGV[0]);
<<<<<<< log_accum.pl
	&do_changes_file(@text);
>>>>>>> 1.72
=======
>>>>>>> 1.73

<<<<<<< log_accum.pl
    while (<STDIN>) {
	chomp;			# Drop the newline
	push @text, "  ".$_;
    }

    &mail_notification(@text);
    &cleanup_tmpfiles();
    exit 0;
=======
	while (<STDIN>) {
		chop;                   # Drop the newline
		push(@text, "  ".$_);
	}

	&do_changes_file(@text);
	&mail_notification(@text);
	&cleanup_tmpfiles();
	exit 0;
>>>>>>> 1.72
}    

#
# Iterate over the body of the message collecting information.
#
<<<<<<< log_accum.pl
$tag = "HEAD";
my @log_lines;
my %changed_files;
my %added_files;
my %removed_files;

=======
my %added_files;		# Hashes containing lists of files
my %changed_files;		# that have been changed, keyed
my %removed_files;		# by branch tag.

my @log_lines;			# The lines of the log message.

my $tag = "HEAD";		# Default branch is HEAD.
my $state = $STATE_NONE;	# Initially in no state.

>>>>>>> 1.72
while (<STDIN>) {
<<<<<<< log_accum.pl
    s/[ \t\n]+$//;		# delete trailing space
    if (/^Revision\/Branch:/) {
	s,^Revision/Branch:,,;
	$tag = $_;
	next;
    }
    if (/^[ \t]+Tag:/) {
	s,^[ \t]+Tag: ,,;
	$tag = $_;
	next;
    }
    if (/^[ \t]+No tag$/) {
	$tag = "HEAD";
	next;
    }
    if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
    if (/^Added Files/)    { $state = $STATE_ADDED;   next; }
    if (/^Removed Files/)  { $state = $STATE_REMOVED; next; }
    if (/^Log Message/)    { $state = $STATE_LOG;     next; }
    
    push (@{ $changed_files{$tag} }, split) if $state == $STATE_CHANGED;
    push (@{ $added_files{$tag} },   split) if $state == $STATE_ADDED;
    push (@{ $removed_files{$tag} }, split) if $state == $STATE_REMOVED;
    if ($state == $STATE_LOG) {
	my $keyword;
	foreach $k (@RCSTEMPLATE_KEYWORDS) {
		$keyword = 1 if /^$k$/i;
	}
	next if $keyword;

	push (@log_lines,     $_);
    }
=======
	s/[ \t\n]+$//;		# delete trailing space

	# parse the revision tag if it exists.
	if (/^Revision\/Branch:(.*)/)	{ $tag = $1;	 next; }
	if (/^[ \t]+Tag: (.*)/)		{ $tag = $1;	 next; }
	if (/^[ \t]+No tag$/)		{ $tag = "HEAD"; next; }

	# check for a state change, guarding against similar markers
	# in the log message itself.
	unless ($state == $STATE_LOG) {
		if (/^Modified Files/)	{ $state = $STATE_CHANGED; next; }
		if (/^Added Files/)	{ $state = $STATE_ADDED;   next; }
		if (/^Removed Files/)	{ $state = $STATE_REMOVED; next; }
		if (/^Log Message/)	{ $state = $STATE_LOG;	   next; }
	}

	# don't so anything if we're not in a state.
	next if $state == $STATE_NONE;

	# collect the log line (ignoring empty template entries)?
	if ($state == $STATE_LOG) {
		unless (
		    /^PR:$/i ||
		    /^Reviewed by:$/i ||
		    /^Submitted by:$/i ||
		    /^Obtained from:$/i ||
		    /^MFC after:$/i ||
		    /^Approved by:$/i) {
			push @log_lines, $_;
		}
		next;
	}

	# otherwise collect information about which files changed.
	my @files = split;
	push @{ $changed_files{$tag} },	@files if $state == $STATE_CHANGED;
	push @{ $added_files{$tag} },	@files if $state == $STATE_ADDED;
	push @{ $removed_files{$tag} },	@files if $state == $STATE_REMOVED;
>>>>>>> 1.72
}
&append_line("$TAGS_FILE.$PID", $tag);

#
# Strip leading and trailing blank lines from the log message.  Also
# compress multiple blank lines in the body of the message down to a
# single blank line.
# (Note, this only does the mail and changes log, not the rcs log).
#
<<<<<<< log_accum.pl
while (@log_lines) {
    last if $log_lines[0];
    shift @log_lines;
}
while (@log_lines) {
    last if $log_lines[$#log_lines];
    pop @log_lines;
=======
while ($#log_lines > -1) {
	last if ($log_lines[0] ne "");
	shift(@log_lines);
}
while ($#log_lines > -1) {
	last if ($log_lines[$#log_lines] ne "");
	pop(@log_lines);
>>>>>>> 1.72
}
<<<<<<< log_accum.pl
for (my $l = $#log_lines; $l > 0; $l--) {
    if (($log_lines[$l - 1] eq "") && ($log_lines[$l] eq "")) {
	splice(@log_lines, $l, 1);
    }
=======
for (my $l = $#log_lines; $l > 0; $l--) {
	if (($log_lines[$l - 1] eq "") && ($log_lines[$l] eq "")) {
		splice(@log_lines, $l, 1);
	}
>>>>>>> 1.72
}

#
# Find the log file that matches this log message
#
my $i;
for ($i = 0; ; $i++) {
<<<<<<< log_accum.pl
    last unless -e "$LOG_FILE.$i.$PID";
    my @text = &read_logfile("$LOG_FILE.$i.$PID");
    last unless @text;
    last if join(" ", @log_lines) eq join(" ", @text);
=======
	last if (! -e "$LOG_FILE.$i.$PID");
	@text = &read_logfile("$LOG_FILE.$i.$PID");
	last if ($#text == -1);
	last if (join(" ", @log_lines) eq join(" ", @text));
>>>>>>> 1.72
}

#
# Spit out the information gathered in this pass.
#
<<<<<<< log_accum.pl
foreach $tag ( keys %added_files ) {
    &append_names_to_file("$ADDED_FILE.$i.$PID",   $dir, $tag,
	@{ $added_files{$tag} });
}
foreach $tag ( keys %changed_files ) {
    &append_names_to_file("$CHANGED_FILE.$i.$PID", $dir, $tag,
	@{ $changed_files{$tag} });
}
foreach $tag ( keys %removed_files ) {
    &append_names_to_file("$REMOVED_FILE.$i.$PID", $dir, $tag,
	@{ $removed_files{$tag} });
}
&write_logfile("$LOG_FILE.$i.$PID", @log_lines);

if ($RCSIDINFO) {
    # XXX foreach $tag (keys %added_files) {
    # XXX	&change_summary_added("$SUMMARY_FILE.$i.$PID", $tag,
    # XXX		@{ $added_files{$tag} });
    # XXX }
    foreach $tag (keys %changed_files) {
	&change_summary_changed("$SUMMARY_FILE.$i.$PID", $tag,
	    @{ $changed_files{$tag} });
    }
    # XXX foreach $tag (keys %removed_files) {
    # XXX	&change_summary_removed("$SUMMARY_FILE.$i.$PID", $tag,
    # XXX		@{ $removed_files{$tag} });
    # XXX }
=======
foreach my $tag ( keys %added_files ) {
	&append_names_to_file("$ADDED_FILE.$i.$PID",   $dir, $tag,
	    @{ $added_files{$tag} });
}
foreach my $tag ( keys %changed_files ) {
	&append_names_to_file("$CHANGED_FILE.$i.$PID", $dir, $tag,
	    @{ $changed_files{$tag} });
}
foreach my $tag ( keys %removed_files ) {
	&append_names_to_file("$REMOVED_FILE.$i.$PID", $dir, $tag,
	    @{ $removed_files{$tag} });
}
&write_logfile("$LOG_FILE.$i.$PID", @log_lines);

if ($RCSIDINFO) {
	foreach my $tag ( keys %added_files ) {
		&change_summary_added("$SUMMARY_FILE.$i.$PID",
		    @{ $added_files{$tag} });
	}
	foreach my $tag ( keys %changed_files ) {
		&change_summary_changed("$SUMMARY_FILE.$i.$PID",
		    @{ $changed_files{$tag} });
	}
	foreach my $tag ( keys %removed_files ) {
		&change_summary_removed("$SUMMARY_FILE.$i.$PID",
		    @{ $removed_files{$tag} });
	}
>>>>>>> 1.72
}

#
# Check whether this is the last directory.  If not, quit.
#
<<<<<<< log_accum.pl
if (-e "$LAST_FILE.$PID") {
    $_ = &read_line("$LAST_FILE.$PID");
    my $tmpfiles=$files[0];
    $tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
    unless (grep /$tmpfiles$/, $_) {
	print "More commits to come...\n";
	exit 0
    }
=======
if (-e "$LAST_FILE.$PID") {
	$_ = &read_line("$LAST_FILE.$PID");
	my $tmpfiles = $files[0];
	$tmpfiles =~ s,([^a-zA-Z0-9_/]),\\$1,g;
	if (! grep(/$tmpfiles$/, $_)) {
		print "More commits to come...\n";
		exit 0
	}
>>>>>>> 1.72
}

#
# This is it.  The commits are all finished.  Lump everything together
# into a single message, fire a copy off to the mailing list, and drop
# it on the end of the Changes file.
#

#
# Produce the final compilation of the log messages
#
<<<<<<< log_accum.pl
push @text, &build_header();
for (my $i = 0; ; $i++) {
    last unless -e "$LOG_FILE.$i.$PID";

    my @lines;
    @lines = &read_logfile("$CHANGED_FILE.$i.$PID");
    if ($#lines >= 0) {
	push @text, &format_lists("Modified", @lines);
    }
    @lines = &read_logfile("$ADDED_FILE.$i.$PID");
    if ($#lines >= 0) {
	push @text, &format_lists("Added", @lines);
    }
    @lines = &read_logfile("$REMOVED_FILE.$i.$PID");
    if ($#lines >= 0) {
	push @text, &format_lists("Removed", @lines);
    }

    @lines = &read_logfile("$LOG_FILE.$i.$PID");
    if ($#lines >= 0) {
	push @text, "  Log:";
	push @text, map { "  $_" } @lines;
    }
    if ($RCSIDINFO == 2) {
	if (-e "$SUMMARY_FILE.$i.$PID") {
	    push @text, "  ";
	    push @text, map {"  $_"} format_summaries("$SUMMARY_FILE.$i.$PID");
=======
my @log_msg = &build_header();
for (my $i = 0; ; $i++) {
	last unless -e "$LOG_FILE.$i.$PID";

	my @mod_lines = &read_logfile("$CHANGED_FILE.$i.$PID");
	push @log_msg, &format_lists("Modified", @mod_lines) if @mod_lines;

	my @add_lines = &read_logfile("$ADDED_FILE.$i.$PID");
	push @log_msg, &format_lists("Added", @add_lines) if @add_lines;

	my @rem_lines = &read_logfile("$REMOVED_FILE.$i.$PID");
	push @log_msg, &format_lists("Removed", @rem_lines) if @rem_lines;

	my @msg_lines = &read_logfile("$LOG_FILE.$i.$PID");
	push @log_msg, "  Log:", (map { "  $_" } @msg_lines) if @msg_lines;


	if ($RCSIDINFO == 2) {
		if (-e "$SUMMARY_FILE.$i.$PID") {
			push @log_msg, "  ", map {"  $_"}
			    format_summaries("$SUMMARY_FILE.$i.$PID");
		}
>>>>>>> 1.72
	}
<<<<<<< log_accum.pl
    }
    push @text, "", "";
=======

	push @log_msg, "", "";
>>>>>>> 1.72
}
#
# Put the log message at the beginning of the Changes file
#
&do_changes_file(@log_msg);

#
# Now generate the extra info for the mail message.
#
<<<<<<< log_accum.pl
if ($RCSIDINFO == 1) {
    my @summary_files;
    for (my $i = 0; ; $i++) {
	last unless -e "$LOG_FILE.$i.$PID";
	push @summary_files, "$SUMMARY_FILE.$i.$PID";
    }
    push @text, format_summaries(@summary_files);
    push @text, "";
=======
if ($RCSIDINFO == 1) {
	my @summary_files;
	for (my $i = 0; ; $i++) {
		last unless -e "$LOG_FILE.$i.$PID";
		push @summary_files, "$SUMMARY_FILE.$i.$PID";
	}
	push @log_msg, format_summaries(@summary_files);
	push @log_msg, "";
>>>>>>> 1.72
}

#
# Mail out the notification.
#
&mail_notification(@log_msg);
&cleanup_tmpfiles();
exit 0;
# EOF
