#!/usr/bin/perl -w

use strict;

my (%mailmap);
my (%email);
my (%map);
my $pstate = 1;
my $n_records = 0;
my $n_output = 0;

sub shortlog_entry($$) {
	my ($name, $desc) = @_;
	my $key = $name;

	$desc =~ s#/pub/scm/linux/kernel/git/#/.../#g;
	$desc =~ s#\[PATCH\] ##g;

	# store description in array, in email->{desc list} map
	if (exists $map{$key}) {
		# grab ref
		my $obj = $map{$key};

		# add desc to array
		push(@$obj, $desc);
	} else {
		# create new array, containing 1 item
		my @arr = ($desc);

		# store ref to array
		$map{$key} = \@arr;
	}
}

# sort comparison function
sub by_name($$) {
	my ($a, $b) = @_;

	uc($a) cmp uc($b);
}

sub shortlog_output {
	my ($obj, $key, $desc);

	foreach $key (sort by_name keys %map) {
		# output author
		printf "%s:\n", $key;

		# output author's 1-line summaries
		$obj = $map{$key};
		foreach $desc (reverse @$obj) {
			print "  $desc\n";
			$n_output++;
		}

		# blank line separating author from next author
		print "\n";
	}
}

sub changelog_input {
	my ($author, $desc);

	while (<>) {
		# get author and email
		if ($pstate == 1) {
			my ($email);

			next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/;

			$n_records++;

			$author = $1;
			$email = $2;
			$desc = undef;

			# cset author fixups
			if (exists $mailmap{$email}) {
				$author = $mailmap{$email};
			} elsif (exists $mailmap{$author}) {
				$author = $mailmap{$author};
			} elsif (!$author) {
				$author = $email;
			}
			$email{$author}{$email}++;
			$pstate++;
		}

		# skip to blank line
		elsif ($pstate == 2) {
			next unless /^\s*$/;
			$pstate++;
		}

		# skip to non-blank line
		elsif ($pstate == 3) {
			next unless /^\s*?(.*)/;

			# skip lines that are obviously not
			# a 1-line cset description
			next if /^\s*From: /;

			chomp;
			$desc = $1;

			&shortlog_entry($author, $desc);

			$pstate = 1;
		}
	
		else {
			die "invalid parse state $pstate";
		}
	}
}

sub read_mailmap {
	my ($fh, $mailmap) = @_;
	while (<$fh>) {
		chomp;
		if (/^([^#].*?)\s*<(.*)>/) {
			$mailmap->{$2} = $1;
		}
	}
}

sub setup_mailmap {
	read_mailmap(\*DATA, \%mailmap);
	if (-f '.mailmap') {
		my $fh = undef;
		open $fh, '<', '.mailmap';
		read_mailmap($fh, \%mailmap);
		close $fh;
	}
}

sub finalize {
	#print "\n$n_records records parsed.\n";

	if ($n_records != $n_output) {
		die "parse error: input records != output records\n";
	}
	if (0) {
		for my $author (sort keys %email) {
			my $e = $email{$author};
			for my $email (sort keys %$e) {
				print STDERR "$author <$email>\n";
			}
		}
	}
}

&setup_mailmap;
&changelog_input;
&shortlog_output;
&finalize;
exit(0);


__DATA__
#
# Even with git, we don't always have name translations.
# So have an email->real name table to translate the
# (hopefully few) missing names
#
Adrian Bunk <bunk@stusta.de>
Andreas Herrmann <aherrman@de.ibm.com>
Andrew Morton <akpm@osdl.org>
Andrew Vasquez <andrew.vasquez@qlogic.com>
Christoph Hellwig <hch@lst.de>
Corey Minyard <minyard@acm.org>
David Woodhouse <dwmw2@shinybook.infradead.org>
Domen Puncer <domen@coderock.org>
Douglas Gilbert <dougg@torque.net>
Ed L Cashin <ecashin@coraid.com>
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Felix Moeller <felix@derklecks.de>
Frank Zago <fzago@systemfabricworks.com>
Greg Kroah-Hartman <gregkh@suse.de>
James Bottomley <jejb@mulgrave.(none)>
James Bottomley <jejb@titanic.il.steeleye.com>
Jeff Garzik <jgarzik@pretzel.yyz.us>
Jens Axboe <axboe@suse.de>
Kay Sievers <kay.sievers@vrfy.org>
Mitesh shah <mshah@teja.com>
Morten Welinder <terra@gnome.org>
Morten Welinder <welinder@anemone.rentec.com>
Morten Welinder <welinder@darter.rentec.com>
Morten Welinder <welinder@troll.com>
Nguyen Anh Quynh <aquynh@gmail.com>
Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Peter A Jonsson <pj@ludd.ltu.se>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
Rudolf Marek <R.Marek@sh.cvut.cz>
Rui Saraiva <rmps@joel.ist.utl.pt>
Sachin P Sant <ssant@in.ibm.com>
Santtu Hyrkk,Av(B <santtu.hyrkko@gmail.com>
Simon Kelley <simon@thekelleys.org.uk>
Tejun Heo <htejun@gmail.com>
Tony Luck <tony.luck@intel.com>