#!/usr/bin/perl -w

# This file parses the "winxp_sample_map.html" file as generated by Dave Miller on
# February 2nd, 2003, with the sole exception that each <br> was replaced by <br>\n.
#
# This parser is copyright (c) 2003 by Shachar Shemesh, and may be freely distributed
# under the terms of the GNU Lesser Public License version 2.1. You may, at your
# option, use any later version of the license, provided that that version was, at
# one time or another, adopted as the official license for the "Wine" project.

($#ARGV >= 0) or die "Usage: parse filename\n";

sub getdll($)
{
    my $dllname=shift;

    $dllname=~m{system(32)?/(\S*) imports:} or return;

    $dllname=lc($2);

    # Make sure we are not dealing with a duplicate of the DLL
    if( $dllname=~m{^dllcache/} )
    {
        return "";
    }

    # Trim the "dll" extension
    $dllname!~/(.*)\.dll/ or $dllname=$1;
   
    # Trim the directory name
    $dllname!~m{/([^/]*)$} or $dllname=$1;

    return $dllname;
}

# first thing's first - read in all the DLLs
open (HTML_FILE, "<$ARGV[0]") or die "Couldn't open file $ARGV[0]\n";

while( <HTML_FILE> )
{
    if( $dllname=getdll($_) )
    {
        # Add our newly found DLL to the list
        $dllnames[$#dllnames+1]=$dllname;
    }
}

@dllnames = sort @dllnames;

for( $i=0; $i<=$#dllnames; ++$i )
{
    $dllloc{$dllnames[$i]}=$i;
    $dllrefed[$i]=0;
}

$#dllxref=($#dllnames+1)*($#dllnames+1)-1;

# Now that we know how much DLLs we have, we can start filling in the cross reference.
# @dllxref is a $#dllnames x $#dllnames size array. The major index ($i*$#dllnames) is the DLL we
# are talking about (from the alphabetical list), and the minor index is the DLL it imports.
seek HTML_FILE, 0, 0;

while( <HTML_FILE> )
{
    if( defined($dllname=getdll($_)) )
    {
        # We are on a line defining a new DLL
        $currdll=$dllloc{$dllname};
    } elsif( m{<a href="#([\w\.]*)">} )
    {
        $dllname=$1;

        # Trim the "dll" extension
        $dllname!~/(.*)\.dll/ or $dllname=$1;

        if( defined($currdll) )
        {
            $dependon=$dllloc{$dllname};
            if( defined $dependon )
            {
                $dllxref[$currdll*$#dllnames+$dependon]=1; # 1 - static. 2 - dynamic. 3 - both. Always static
            } else
            {
                print STDERR "DLL $dllnames[$currdll] depends on DLL $dllname, which does not exist\n";
            }
        }
    }
}

for( $i=0; $i <= $#dllnames ; ++$i )
{
    $dllranks[$i]=$i;

    for( $j=0; $j <= $#dllnames ; ++$j )
    {
        # Count how many DLLs point at $i
        $dllxref[$j*$#dllnames+$i] and ++$dllrefed[$i];
    }
}

@dllranks = sort { $dllrefed[$b] <=> $dllrefed[$a] } @dllranks;

sub advance
# Advance $_[1] to be at $_[2]
{
    my ($orig, $dst) = @_;

    if( $orig>$dst )
    {
        my $moved=$dllranks[$orig];

        for( my $i=$orig; $i>$dst; --$i )
        {
            $dllranks[$i]=$dllranks[$i-1];
        }
        
        $dllranks[$dst]=$moved;
    }
}

# Make sure that no DLL is lower than the DLLs that depend on it
DEPENDSCAN: for( my $i=0; $i<=$#dllnames; ++$i )
{
    for( my $j=$i+1; $j<=$#dllnames; ++$j )
    {
        if( $dllxref[$dllranks[$i]*$#dllnames+$dllranks[$j]] and
                !$dllxref[$dllranks[$j]*$#dllnames+$dllranks[$i]] )
        {
            # $i is higher than $j, depends on it, and $j does not depend on $i.
            # Promote $j to take $i's place, and push everyone else down.
            advance( $j, $i );
            redo DEPENDSCAN;
        }
    }
}

#foreach my $i (@dllranks)
#{
#    print "$dllnames[$i] $dllrefed[$i]\n"
#}

# The time has come to generate an HTML. We are only generating the
# "interesting" part of the HTML here, and are assuming someone will paste
# a header and footer, and probably CSS to make it visually pleasing.
print <<EOS
<table class="DllDepend">
 <tr>
  <th>
EOS
;

# Print the table's header
foreach $i (@dllranks)
{
    $dllrefed[$i]>0 and print "  <th class=\"DllTo\"><a href=\"#$dllnames[$i]\">",
        join('<br>', split(//, $dllnames[$i])), "</a>\n";
}

# Print the actual rows
for( $i=1; $i<=$#dllnames; ++$i )
{
    my $index=$dllranks[$i];
    
    print " <tr><th class=\"DllFrom\"><a name=\"$dllnames[$index]\">$dllnames[$index]</a>\n";

    for( $j=0; $j<=$#dllnames; ++$j )
    {
        my $jndex=$dllranks[$j];
        my $class=($j>$i?" class=\"CyclicDepend\"":"");
        $dllrefed[$jndex]>0 and
            print "  <td$class>", ($dllxref[$index*$#dllnames+$jndex]!=0?
                    "<a href=\"#$dllnames[$jndex]\">X</a>":""), "\n";
    }
}

