#! /usr/bin/perl

my $gcc_ver = "4.1.0";
my $e_mail = "Andris Pavenis <andris.pavenis\@iki.fi>";

my $gcc_ver_s1 = del2dot($gcc_ver);
my $gcc_ver_s2 = del_all_dot($gcc_ver);
my $gcc_ver_s2a = $gcc_ver_s2; $gcc_ver_s2a =~ s/-.*$//;
my $gcc_ver_s1a = $gcc_ver_s1; $gcc_ver_s1a =~ s/-.*$//;
my $srcdir = "../gcc-$gcc_ver_s1";
my $docdir = "gnu/gcc-$gcc_ver_s1";
my $djver = getdjver();
my ($djver_desc, $djreq);


my @cpp_rename = (
"ext/pb_assoc/detail/basic_assoc_cntnr/constructor_destructor_fn_imps.hpp:cdfnimps.hpp",
"ext/pb_assoc/detail/basic_assoc_cntnr/constructors_destructor_fn_imps.hpp:csdfnimps.hpp",
"ext/pb_assoc/detail/basic_hash_assoc_cntnr/constructor_destructor_fn_imps.hpp:csdfnimps.hpp",
"ext/pb_assoc/detail/basic_hash_assoc_cntnr/constructors_destructor_fn_imps.hpp:csdfnimps.hpp",
"ext/pb_assoc/detail/basic_tree_assoc_cntnr/constructor_destructor_fn_imps.hpp:cdfnimps.hpp",
"ext/pb_assoc/detail/basic_tree_assoc_cntnr/constructors_destructor_fn_imps.hpp:csdfnimps.hpp",
"ext/pb_assoc/detail/cc_ht_map_/constructor_destructor_fn_imps.hpp:cdfnimps.hpp",
"ext/pb_assoc/detail/cc_ht_map_/constructor_destructor_no_store_hash_fn_imps.hpp:cdnshfnimps.hpp",
"ext/pb_assoc/detail/cc_ht_map_/constructor_destructor_store_hash_fn_imps.hpp:cdshfnimps.hpp",
"ext/pb_assoc/detail/gp_ht_map_/constructor_destructor_fn_imps.hpp:cdfnimps.hpp",
"ext/pb_assoc/detail/gp_ht_map_/constructor_destructor_no_store_hash_fn_imps.hpp:cdnshfnimps.hpp",
"ext/pb_assoc/detail/gp_ht_map_/constructor_destructor_store_hash_fn_imps.hpp:cdshfnimps.hpp",
"ext/pb_assoc/detail/lu_policy/counter_lu_metadata_imp.hpp:clumetadataimp.hpp",
"ext/pb_assoc/detail/lu_policy/counter_lu_policy_imp.hpp:clupolicyimp.hpp",
"ext/pb_assoc/detail/hash_fn/direct_mask_range_hashing_imp.hpp:dirmask_range_hashing_imp.hpp",
"ext/pb_assoc/detail/hash_fn/direct_mod_range_hashing_imp.hpp:dirmod_range_hashing_imp.hpp",
"debug/hash_multimap.h:hashmmap.h",
"debug/hash_multiset.h:hashmset.h",
"ext/pb_assoc/detail/value_type_adapter/iterator_fn_imps.hpp:iter_fn_imps.hpp",
"ext/pb_assoc/detail/standard_policies.hpp:std_policies.hpp",
"ext/pb_assoc/detail/standard_sizes.hpp:std_sizes.hpp",
"bits/stl_algobase.h:stlalgobase.h",
"bits/stl_iterator_base_funcs.h:stl_ibfn.h",
"bits/stl_iterator_base_types.h:stl_ibtp.h",
"bits/stl_multimap.h:stl_mmap.h",
"bits/stl_multiset.h:stl_mset.h",
"ext/pb_assoc/detail/typelist/typelist_append.hpp:tl_append.hpp",
"ext/pb_assoc/detail/typelist/typelist_apply.hpp:tl_apply.hpp",
"ext/pb_assoc/detail/typelist/typelist_at_index.hpp:tl_at_index.hpp",
"ext/pb_assoc/detail/typelist/typelist_contains.hpp:tl_contains.hpp",
"ext/pb_assoc/detail/typelist/typelist_filter.hpp:tl_filter.hpp",
"ext/pb_assoc/detail/typelist/typelist_transform.hpp:tl_transform.hpp",
"ext/pb_assoc/detail/typelist/typelist_typelist_append.hpp:tl_tl_append.hpp",
"tr1/unordered_map:unord_map",
"tr1/unordered_set:unord_set",
"bits/valarray_after.h:valarray.after",
"bits/valarray_array.h:valarray.array",
"bits/valarray_before.h:valarray.before",
"ext/pb_assoc/detail/value_type_adapter/value_type_adapter.hpp:vt_adapter.hpp",
"ext/pb_assoc/detail/value_type_adapter/value_type_traits.hpp:vt_traits.hpp",
"ext/vstring_fwd.h:vstr_fwd.h",
"ext/vstring_util.h:vstr_util.h",
"djgpp/bits/c++config.h:cxxconfig.h",
"djgpp/bits/c++allocator.h:cxxallocator.h",
"djgpp/bits/c++io.h:cxxio.h",
"djgpp/bits/c++locale.h:cxxlocale.h"
);

my @rename_list = (
"lib/libsupc++.la:#gcc_lib#/libsupcxx.la",
"lib/libsupc++.a:#gcc_lib#/libsupcxx.a",
"lib/libstdcxx.la:#gcc_lib#/libstdcxx.la",
"lib/libstdcxx.a:#gcc_lib#/libstdcxx.a",
"lib/libgf95begin.a:#gcc_lib#/libgf95begin.a",
"lib/libgfortran.a:#gcc_lib#/libgfortran.a",
"lib/libgf95begin.la:#gcc_lib#/libgf95begin.la",
"lib/libgfortran.la:#gcc_lib#/libgfortran.la",
"lib/libobjc.a:#gcc_lib#/libobjc.a",
"lib/libobjc.la:#gcc_lib#/libobjc.la",
"lib/libssp.a:#gcc_lib#/libssp.a",
"lib/libssp.la:#gcc_lib#/libssp.la",
"lib/libssp_nonshared.a:#gcc_lib#/libssp_nonshared.a",
"lib/libssp_nonshared.la:#gcc_lib#/libssp_nonshared.la",
"bin/g++.exe:##/gpp.exe",
"bin/c++.exe:",
"bin/djgpp-g++.exe:",
"bin/djgpp-gcc.exe:",
"bin/djgpp-gcc-4.10:",
"bin/djgpp-c++.exe:",
"info/dir:",
"man/man1/g++.1:##/gpp.1"
);

my @docfiles = (
"BUGS", "bugs.html", "COPYING", "COPYING.LIB", "FAQ", "faq.html",
"NEWS", "README", "README.SCO", "fixincludes/README-fixinc",
"fixincludes/README", "gcc/COPYING", "gcc/cp/NEWS", "gcc/objc/README",
"libobjc/README", "libobjc/THREADS", "libstdc++-v3/README",
);


copy_docs();
cxx_rename_proc(@cpp_rename);
rename_files_proc(@rename_list);
mkdir "gnu";
mkdir "gnu/gcc-$gcc_ver_s1";
convert_man_pages();
update_dsm();
update_readme_djgpp();
mk_manifest();
build_zip_archives();

sub create_dir_if_needed
{
    my $dname = $_[0];
    if ( ! -d $dname )
    {
        if ($dname =~ m:^(.*)/([^/]*)$:)
        {
            my $d1 = $1;
            create_dir_if_needed ($d1);
        }

        mkdir $dname or
            die "Failed to create directory $dname: $!\n";
    }
}



sub copy_docs
{
    if (0) # Not implemented. Should edit HTML files for this to work
    {
        my $fd;
        open ($fd, "find $srcdir/libstdc++-v3/docs/html -type f -a -not -name Makefile |") or die "Failed : $!\n";
        while (<$fd>)
        {
            chomp;
            $srcfile = $_;
            s/^.*\/html\///;
            my $n1 = $_;
            my $n2 = "$docdir/libstdcxx/html/$n1";
            my $n2xd = $n2;  $n2xd =~ s/\/[^\/]*$//;
            print "$n1 $n2 $n2xd\n";
            ;
            create_dir_if_needed $n2xd;
            system ("cp -v $srcfile $n2");
        }
    }

    foreach my $file (@docfiles)
    {
        my $dest = $file; $dest =~ s:\+\+:xx:g;
        my $dir = "$docdir/$dest"; $dir =~ s:/[^/]*$::;
        create_dir_if_needed $dir;
        system ("cp -v $srcdir/$file $docdir/$dest");
    }
}


sub cxx_rename_proc
{
    my %header_gcc;
    my $v = $gcc_ver_s1;
    $v =~ s/-.*$//;
    my $cxx_inc_dir = "include/cxx/$v";
    foreach (@_)
    {
        m/^([^:]*):([^:]*)$/;
        my $orig_path = $1;
        my $new_name = $2;
        $orig_path =~ m/^(.*)\/([^\/]*)$/;
        my $dir_name = $1;
        my $orig_name = $2;

        my $n1 = "$cxx_inc_dir/$dir_name/$orig_name";
        my $n2 = "$cxx_inc_dir/$dir_name/$new_name";

        if ( -f $n1 )
        {
            #print "Rename: $n1 ==>$n2\n";
            if (! rename ($n1, $n2)) 
            {
                #print "Rename: $n1 ==>$n2: $!\n";
            }
        }
        elsif ( -f $n2 )
        {
            #print "New file: $n2 already exists\n";
        }
        else
        {
            print "Neither $n1 nor $n2 found\n";
            next;
        }

        my $d1 = "";
        my $d2 = $dir_name;
        if (! /^djgpp\//)
        {
            $header_gcc{"header.gcc"} = $header_gcc{"header.gcc"} .
                "$d2/$orig_name $d2/$new_name\n";
            #print "Write: $d2/$orig_name $d2/$new_name >>header.gcc\n";
        }
        do
        {
            if ($d2 =~ m/^([^\/]*)\/(.*)$/)
            {
                $d1 = $d1 eq "" ? $1 : "$d1/$1";
                $d2 = $2;
            }
            else
            {
                $d1 = $d1 eq "" ? $d2 : "$d1/$d2";
                $d2 = "";
            }                                       
            my $d2a = $d2 ne "" ? "$d2/" : "";
            $header_gcc{"$d1/header.gcc"} = $header_gcc{"$d1/header.gcc"} .
                "$d2a$orig_name $d2a$new_name\n";
            #print "Write: $d2a$orig_name $d2a$new_name >>$d1/header.gcc\n";
        } while ($d2 ne "");
    }

    foreach (sort keys %header_gcc)
    {
        my $file = $_;
        my $contents = $header_gcc{$file};
        #print "\n###### $file\n\n$contents\n\n";
        my $fd;
        if (open $fd, ">$cxx_inc_dir/$file") 
        {
            print $fd $contents;
            close $fd;
        }   
        else
        {
            print "Failed to write file $file\n";
        }
    }
}

sub rename_files_proc
{
    my $v = $gcc_ver_s1;
    $v =~ s/-.*$//;
    foreach (@_)
    {
        if (! m/^([^:]*):([^:]*)$/)
        {
            print "Wrong line: $_\n";
            next:
        }

        my $old_path = $1;
        my $new_name = $2;
        $old_path =~ m#^(.*)/([^/]*)$# or next;
                
        my $dir = $1;
        my $old_name = $2;

        if ($new_name eq "")
        {
            if ( -f "$dir/$old_name" )
            {
                #print "Delete: $dir/$old_name\n";
                unlink ("$dir/$old_name") or
                   print "Delete failed: $!\n";
            }
            else
            {
                #print "File $dir/$old_name not found\n";
            }
        }
        else
        {
            $new_name =~ s:\#gcc_lib\#:lib/gcc/djgpp/$gcc_ver_s1a:;
            $new_name =~ s:\#\#:$dir:;
            if ( -f "$dir/$old_name" )
            {
                #print "Rename/move: $dir/$old_name ==> $new_name";
                rename ("$dir/$old_name", "$new_name") or die ": $!\n";
                #print "\n";
            }
            elsif ( -f $new_name )
            {
                #print "Renamed file $new_name found\n";
            }
            else
            {
                die "Neither $dir/$old_name nor $new_name found\n";
            }
        }
    }
}


sub del_all_dot
{
    my $x = $_[0];
    $x =~ s/\.//g;
    return $x;
}

sub del2dot
{
    my $x = $_[0];
    $x =~ s/\./_/;
    $x =~ s/\.//g;
    $x =~ s/_/./;
    return $x;
}

sub getdjver
{
    my $fd;
    my $major;
    my $minor;
    my $fname = "/dev/env/DJDIR/include/sys/version.h";
    open $fd, "<$fname" or die "Failed to open $fname: $!\n";
    while (<$fd>)
    {
        if (m/#define\s+__DJGPP__\s+([0-9]+)/)
        {
            $major = $1;
        }

        if (m/#define\s+__DJGPP_MINOR__\s+([0-9]+)/)
        {
            $minor = $1;
        }
    }
    close $fd;

    if ($major eq "2" && (($minor eq "3") || ($minor eq "4"))) 
    {
        if ($minor == 3)
        {
            $djver_desc = "2.03 Patchlevel 2";
            $djreq = $djver_desc;
        }
        else
        {
            $djver_desc = "2.04 Beta 1 or above";
            $djreq = ">= 2.04 Beta 1";
        }
        return sprintf("%d.%02d", $major, $minor);
    }
    return "";
}




sub update_readme_djgpp
{
    create_dir_if_needed $docdir;

    my $djdev="djdev$djver"; $djdev=~s/\.//g;
    my ($fdin, $fdout);
    open $fdin, "<$srcdir/readme.DJGPP" or
        die "Failed to open $srcdir/readme.DJGPP: $!\n";
    open $fdout, ">gnu/gcc-${gcc_ver_s1}/readme.DJGPP" or
        die "Failed to create file $srcdir/readme.DJGPP: $!\n";
    while (<$fdin>)
    {
        s/\@GCCVER\@/$gcc_ver/g;
        s/\@GCCVER2\@/$gcc_ver_s1/g;
        s/\@GCCVER3\@/$gcc_ver_s2a/g;
        s/\@DJVER\@/$djver_desc/g;
        s/\@DJDEV\@/$djdev/g;
        s/\@CONTACT\@/$e_mail/g;
        print $fdout $_;
    }
    close $fdin;
    close $fdout;
}


sub convert_man_pages
{
    my @manpages = (glob("man/man1/*"), glob("man/man7/*"));
    foreach my $src (@manpages)
    {
        my $dest = $src; $dest =~ s:/man:/cat:;
        my $dir = $dest; $dir =~ s:/[^/]*$::;
        create_dir_if_needed $dir;
        die "Failure\n" if $dest eq $src;
        system ("groff -man -Tascii $src >$dest");
    }
}


sub update_dsm
{
    create_dir_if_needed "manifest";

    foreach my $dsi (glob "dsmsrc/*.dsi")
    {
        $dsi =~ s/^dsmsrc\///;
        my $dsm = $dsi;
        $dsm =~ s/b\.dsi/${gcc_ver_s2a}b/;
        my ($fdin, $fdout);
        open $fdin, "<dsmsrc/$dsi" or
            die "Failed to open file dsmsrc/$dsi: $!\n";
        open $fdout, ">manifest/$dsm.dsm" or
            die "Failed to create file manifest/$dsm: $!\n";
        while (<$fdin>)
        {
            my $desc;
            s/\@version\@/$gcc_ver/g;
            s/\@arcv\@/$gcc_ver_s2a/g;
            s/\@version_status\@//g;
            s/\@djreq\@/$djreq/g;
            if (m/^short-description:\s+(.*)$/)
            {
                my $fdver;
                $desc = "$dsm.zip: $1 (Version $gcc_ver)";
                open $fdver, ">manifest/$dsm.ver";
                print $fdver $desc;
                close $fdver;
                open $fdver, ">manifest/$dsm.mft";
                close $fdver;
            }
            print $fdout $_;
        }
    }
}



sub mk_manifest
{
    my @cxxfiles = (
        'bin/gpp\.exe', '^include/cxx/', '/cc1plus\.exe',
        '/libstdcxx', '/libsupcxx', 'manifest/gpp',
        '/cat1/gpp', '/cp/NEWS'
    );

    my @gforfiles = (
        'bin/gfortran\.exe', 'info/gfortran.info',
        '/libgf', '/f951\.exe', 'manifest/gfor',
        '/cat1/gfortran'
    );

    my @adafiles = (
        'bin/gnat.*\.exe', 'bin/gprmake\.exe', 'info/gnat',
        '/adainclude/', '/adalib/', '/gnat1\.exe',
        'manifest/ada'
    );

    my @gccfiles = (
        'bin/gcc\.exe', 'bin/cpp\.exe', 'bin/gcov\.exe', 'bin/gccbug',
        'include/ssp/', 'info/(?:cpp|gcc)', '/djgpp\.ver$',
        '/include/(?:emmintrin|float|iso646|limits|mm|pmm|std|sys|unw|var|xmm)',
        '/install-tools/', '/libgcc\.a', '/libgcov\.a', '/libssp',
        '/cc1\.exe', '/collect2\.exe', 'manifest/gcc',
        'readme.DJGPP', '/cat1/(?:cpp|gcc|gcov)', '/cat7/',
        '/BUGS', '/COPYING', '/FAQ', '/NEWS', '/README',
        '/bugs\.html', 'faq\.html'
    );

    my @objcfiles = (
        'libobjc\.', '/include/objc/', '/cc1obj.*\.exe',
        'manifest/objc', '/libobjc/(README|THREADS)', '/objc/README'
    );

    my $fd;
    my %status;
    my (@mft_ignored, @mft_gcc, @mft_gpp, @mft_gfor, @mft_objc, @mft_ada);
    open ($fd, "find . -type f |") or die "Failed to get filelist:$!\n";

    my $NF=0;
    while (<$fd>)
    {
        chomp; s:^\./::;
        next if (! m/\//);
        $status{$_} = "unknown";
        $NF++;
    }
    close $fd;
    print "$NF files totally\n";
    my @files = sort keys %status;

    foreach my $file (@files)
    {
        if ($file =~ m/\.exe$/)
        {
            system ("strip $file");
            if ($file =~ m/(?:cc1|cc1obj|cc1plus|g951|gnat1)\.exe$/)
            {
                system ("stubedit $file minstack=1024K");
            }
        }
        elsif ($file =~ m/\.a$/)
        {
            system ("strip -g $file");
        }
    }

    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach my $expr (@ignore)
        {
            if ($file =~ $expr)
            {
                $status{$file} = "ignore";
                print "Ignore $file\n";
            }
        }
    }

    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach (@cxxfiles)
        {
            if ($file =~ $_)
            {
                $status{$file} = "gpp";
                push @mft_gpp, $file;
            }
        }
    }


    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach (@adafiles)
        {
            if ($file =~ $_)
            {
                $status{$file} = "ada";
                push @mft_ada, $file;
            }
        }
    }

    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach (@gforfiles)
        {
            if ($file =~ $_)
            {
                $status{$file} = "gfor";
                push @mft_gfor, $file;
            }
        }
    }

    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach (@objcfiles)
        {
            if ($file =~ $_)
            {
                $status{$file} = "objc";
                push @mft_objc, $file;
            }
        }
    }

    foreach my $file (@files)
    {
        next if ($status{$file} ne "unknown");
        foreach (@gccfiles)
        {
            if ($file =~ $_)
            {
                $status{$file} = "gcc";
                push @mft_gcc, $file;
            }
        }
    }

    my $fd_mft;
    open ($fd_mft, ">manifest/gcc${gcc_ver_s2a}b.mft") or
        die "Failed to create file manifest/gcc${$gcc_ver_s2a}b.mft: $!\n";
    foreach my $file (@mft_gcc)
    {
        print $fd_mft "$file\n";
    }
    close $fd_mft;

    open ($fd_mft, ">manifest/ada${gcc_ver_s2a}b.mft") or
        die "Failed to create file manifest/ada${$gcc_ver_s2a}b.mft: $!\n";
    foreach my $file (@mft_ada)
    {
        print $fd_mft "$file\n";
    }
    close $fd_mft;

    open ($fd_mft, ">manifest/gfor${gcc_ver_s2a}b.mft") or
        die "Failed to create file manifest/gfor${$gcc_ver_s2a}b.mft: $!\n";
    foreach my $file (@mft_gfor)
    {
        print $fd_mft "$file\n";
    }
    close $fd_mft;

    open ($fd_mft, ">manifest/gpp${gcc_ver_s2a}b.mft") or
        die "Failed to create file manifest/gpp${$gcc_ver_s2a}b.mft: $!\n";
    foreach my $file (@mft_gpp)
    {
        print $fd_mft "$file\n";
    }
    close $fd_mft;

    open ($fd_mft, ">manifest/objc${gcc_ver_s2a}b.mft") or
        die "Failed to create file manifest/objc{$gcc_ver_s2a}b.mft: $!\n";
    foreach my $file (@mft_objc)
    {
        print $fd_mft "$file\n";
    }
    close $fd_mft;


    open ($fd_mft, ">skipped.mft") or
        die "Failed to create file skipped.mft: $!\n";
    foreach my $file (@files)
    {
        if ($status{$file} eq "unknown")
        {
            print $fd_mft "$file\n";
        }
    }
    close $fd_mft;
}




sub build_zip_archives
{
    foreach my $mft (glob "manifest/*.mft")
    {
        my $zip = $mft;
        $zip =~ s:\.mft:.zip:;
        $zip =~ s:^.*/::;
        print "Creating $zip\n";
        system ("zip -9\@ $zip <$mft");
    }
}



syntax highlighted by Code2HTML, v. 0.9.1