#!/usr/bin/perl -w

my $inmemcheckheader = 0;
my $incallstack      = 0;
my $inmemstack       = 0;
my $blanklines       = 0;
my $message;
my $callstack;
my $memstack;
my $key;
my $insummary = 0;
my %stackhash = ();

while (<ARGV>)
{
    chomp;

    next if !( $_ =~ /.*==[0-9]+== / ); # skip non memcheck lines
    $_ =~ s/.*==[0-9]+== //;   # remove memcheck process id

    if ($_ =~ /Memcheck, a memory error detector/)
    {
	$inmemcheckheader = 1;
	$incallstack = $inmemstack = $insummary = 0;
	$blanklines       = 0;
	next;
    }

    if ($_ =~ /ERROR SUMMARY/)
    {
	$insummary = 1;
	$inmemcheckheader = $incallstack = $inmemstack = 0;
	$blanklines = 0;
    }

    next if ($insummary);
    
    if (!$_)
    {
	++$blanklines;
    }

    if ($inmemcheckheader)
    {
	if ($blanklines == 2)
	{
	    $inmemcheckheader = 0;
	    $incallstack = $inmemstack = 0;
	    $blanklines       = 0;
	}
	next;
    }

    if ($_ && !$incallstack && !$inmemstack)
    {
	$incallstack = 1;
	$message     = $_;
	@callstack   = ();
	@memstack    = ();
	next;
    }

    if ($_ =~ / Address/)
    {
	$incallstack = 0;
	$inmemstack  = 1;
	s/Address 0x[0-9A-F]*/Address/;
	s/[0-9,]* bytes inside a block of size [0-9,]*/inside a block/;
	push @memstack, $_;
	next;
    }

    if (($incallstack || $inmemstack) && $blanklines == 1)
    {
	my $depth = 3;
	my $idepth;

	$key = "$message;\t";

	for ($idepth = 0; $idepth < $depth && $idepth <= $#callstack; ++$idepth)
	{
	    $key .= $callstack[$idepth] . ";\t";
	}

	my $stack = "$message;\t" . 
	    (join ";\t", @callstack);

	if (@memstack)
	{
	    $stack .= "\n\t" . (join ";\t", @memstack);
	}

	if (!$stackhash{$key})
	{
	    $stackhash{$key} = [];
	    #print "KEY NEW: $key\n";
	}
	my $arrref = $stackhash{$key};
	$$arrref[$#$arrref+1] = $stack;
	#print "KEY CNT: $key \n$#$arrref\n";
       
	$incallstack = $inmemstack = 0;
	$blanklines = 0;
	@callstack = ();
	@memstack = ();

	next;
    }

    $_ =~ s/ *(at|by) 0x[0-9A-F]+: //;

    if ($incallstack)
    {
	push @callstack, $_;
    }

    if ($inmemstack)
    {
	push @memstack, $_;
    }
	
}

foreach $key (sort {
    my $arrrefa = $stackhash{$a};    
    my $arrrefb = $stackhash{$b};    
    $#$arrrefb <=> $#$arrrefa or $a cmp $b 
    #$a cmp $b 
    } keys %stackhash)
{

    my $stack;
    my $arrref = $stackhash{$key};
    my $count = $#$arrref+1;

    $key =~ s/;/\n/g;

    print "=" x 80 . "\nStack Group\n\n$count\t $key\n" . "=" x 80 . "\n\nIndividual Stacks\n\n";

    foreach $stack (@$arrref)
    {
	$stack =~ s/;/\n/g;

	print "$stack\n\n";
    }
}
