#!perl -w
#-------------------------------------------------------------------------------
#  Project :      Nice Delivery System
#  Module  :      nds_generate_makefile
#-------------------------------------------------------------------------------
#  Copyright:     2003 Texas Instruments Deutschland GmbH
#                 2004 Texas Instruments France SA
#                 All rights reserved. 
# 
#                 This file is confidential and a trade secret of Texas 
#                 Instruments.
#                 The receipt of or possession of this file does not convey 
#                 any rights to reproduce or disclose its contents or to 
#                 manufacture, use, or sell anything it may describe, in 
#                 whole, or in part, without the specific written consent of 
#                 Texas Instruments Framce SA. 
#-------------------------------------------------------------------------------
#  Authors :      jr  Joachim Richter
#                 mo  Martin Osieka
#                 ib  Isabelle Biffi
#-------------------------------------------------------------------------------
#  Versions:      2.0  ib
#-------------------------------------------------------------------------------


use strict;
use File::Copy;
use File::Find;
use File::Spec;
use Cwd;
use Getopt::Long qw(:config pass_through);


#-------------------------------------------------------------------------------
# Variables
#-------------------------------------------------------------------------------

my $command;

# makefile file name
my $makeFile;

# do not only store the drive in $current_drive, but rather store the path
# to the current dir (necessary to work directly on V:\<view>\...)
my $current_drive = cwd;
$current_drive =~ s|[\\/][^\\/]+$||;

# specifies whether output is being redirected (logged to a file) or not
my $outerr_redirected;

# command line options 
my $o_file;
my $o_logfile = "report.txt";
my $o_shell = 0;
my $o_help = 0;
# my $o_dlvcfg = "dlv_cfg0";
my $o_dlvcfg = "";
my $dlv_cfg_path = "system\\busyb\\deliverydefs\\";
my $dlv_cfg;

# make pass-through options
my $make_opt;


#-------------------------------------------------------------------------------
# Main Program
#-------------------------------------------------------------------------------

# parse command line, passing through all unknown options to make
parse_command_line();

# logging is enabled by default (unless $o_shell is set, done by option "-s")
if (!$o_shell)
{
    # attempt to redirect STDOUT+STDERR
    $outerr_redirected = redirect_output();
}
else
{
    # do not redirect output, it is being sent to shell
    $outerr_redirected = 0;
}

# ib 
my $build_message = "\nStarting generate makefile for configuration " . $o_file . ".
REDIRECT_PLACEHOLDER
\n";

if ($outerr_redirected)
{
    $build_message =~ s/REDIRECT_PLACEHOLDER/output is being logged to $o_logfile,/;
    print CONSOLE_OUT $build_message;
}
else
{
    $build_message =~ s/REDIRECT_PLACEHOLDER/output is not being logged!/;
    print $build_message;
}
step__check_environment (1);
&step__update_busyb_makefile (2, "system/unbusy_g23m.ini");

# restore redirected STDOUT+STDERR, if necessary 
restore_redirection()
    if $outerr_redirected;


exit 0;


#-------------------------------------------------------------------------------
# SUBROUTINES
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
# parses the command line, sets global $o_* variables to all specified options,
# checks which options/parameters are passed through to make or ABC
#-------------------------------------------------------------------------------
sub parse_command_line
{
    GetOptions (
        "file=s"=>\$o_file,
        "log=s"=>\$o_logfile,
        "shell"=>\$o_shell,
        "dlv=s"=>\$o_dlvcfg,
        "help|?" =>\$o_help);
    
    if ($o_help)
    {
        usage();
        exit 0;
    }
    
    # determine make/BuSyB pass-through options from @ARGV
    $make_opt = "";
    foreach (@ARGV)
    {
            # make/BuSyB pass-through option: all else
            $make_opt .= " " . $_;
    }
    
    # sanity checks: 
    # due to enabled 'pass_through' and 'permute' of GetOptions(),
    # some busyb.pl options may end up in other option parameters instead 
    # e.g. if options which require a parameter are specified w/o any parameter: 
    # "... -m", or "... -m -l", ...
    foreach ($o_file, $o_logfile)
    {
        # check all options which should take a parameter 
        # if they actually contain another option and no parameter
        if (defined($_) and /^-/)
        {
            print "\nERROR: Option missing mandatory parameter!\n\n";
            usage();
            exit 1;
        }
    }
    foreach ("-f", "-l")
    {
        # check if the pass-through options to make contain on of the busyb.pl
        # options
        if ($make_opt =~ /$_/i)
        {
            print "\nERROR: Option missing mandatory parameter!\n\n";
            usage();
            exit 1;
        }
    }
    
    if (!$o_file)
    {
        print "\nERROR: No input/configuration file specified with \"-f file\"!\n\n";
        usage();
        exit 1;
    }
    die "\nERROR: Input/configuration file \"" . $o_file . "\" not found, aborting"
        unless -e $o_file;
    # replace backslash with slash in filename
    $o_file =~ s:\\:/:g;

    
    if ($o_dlvcfg)
    {
        $dlv_cfg=$dlv_cfg_path.$o_dlvcfg.".xml";
        die "\nERROR: delivery configuration file \"" . $dlv_cfg . "\" not found, aborting"
            unless -e $dlv_cfg;
        # replace backslash with slash in filename
        $dlv_cfg =~ s:\\:/:g;
    }
}








#-------------------------------------------------------------------------------
# print short usage notes
#-------------------------------------------------------------------------------
sub usage
{
    print "\nUSAGE:
    perl xxx.pl -f XML-File [OPTIONS] 

Generate makefile for building Chipset software
Logging all output to report.txt by default.

OPTIONS:
    -l LOGFILE    log to LOGFILE (default is report.txt)
    -S            output to current shell, no logging to report.txt
    -dlv DLVCFG   delivery configuration, dlv_cfg0 by default

EXAMPLES:
    perl busyb.pl -f system\\busyb\\productdefs\\sample.xml
    perl busyb.pl -f system\\busyb\\productdefs\\sample.xml -dlv dlvcfg2
";
}


#-------------------------------------------------------------------------------
# print current step to STDOUT (usually redirected to report.txt) and
# additionally to CONSOLE_OUT
#-------------------------------------------------------------------------------
sub print_status
{
    print "\n----------------------------------------------------------------";
    print "\n$_[0]\n";
    print "----------------------------------------------------------------\n\n";
    
    print CONSOLE_OUT "$_[0]\n"
        if $outerr_redirected;
}



#-------------------------------------------------------------------------------
# Check/Initialize some necessary env. variables:
# - %PATH must contain gpf/bin, gpf/tools/bin, chipsetsw/system (in that order)
# - %PATH* variables must only contain slashes (no backslashes, semicolons)
#-------------------------------------------------------------------------------
sub init_environment
{
    my $current_drive_winformat = $current_drive;
    $current_drive_winformat =~ s:/:\\:g;

    # check if all necessary paths are in %PATH, add them if not (this removes
    # the dependency on initvars.bat)
    if (!($ENV{'PATH'} =~ m:[\\/]chipsetsw[\\/]system:))
    {
        # add \chipsetsw\system to %PATH (should be third)
        $ENV{'PATH'} = "$current_drive_winformat\\chipsetsw\\system;" . $ENV{'PATH'};
        print "%PATH   : \"$current_drive_winformat\\chipsetsw\\system\" + %PATH\n";
    }

    if (!($ENV{'PATH'} =~ m:[\\/]gpf[\\/]tools[\\/]bin:))
    {
        # add \gpf\tools\bin to %PATH (should be second)
        $ENV{'PATH'} = "$current_drive_winformat\\gpf\\tools\\bin;" . $ENV{'PATH'};
        print "%PATH   : \"$current_drive_winformat\\gpf\\tools\\bin\" + %PATH\n";
    }

    if (!($ENV{'PATH'} =~ m:[\\/]gpf[\\/]bin:))
    {
        # add \gpf\bin to %PATH (should be first)
        $ENV{'PATH'} = "$current_drive_winformat\\gpf\\bin;" . $ENV{'PATH'};
        print "%PATH   : \"$current_drive_winformat\\gpf\\bin\" + %PATH\n";
    }

    # check correct setting of environment variables for TI compiler and linker
    # PATH_CC_1_22e=C:\tools\TMS4701x_1.22e\NT
    die "\nERROR: environment variable %PATH_CC_1_22e must be set!\n"
      unless exists($ENV{'PATH_CC_1_22e'});
    $ENV{'PATH_CC_1_22e'} =~ s|\\|/|g;
    $ENV{'PATH_CC_1_22e'} =~ s|;.*||;
    print "%PATH_CC_1_22e  : \"" . $ENV{'PATH_CC_1_22e'} . "\"\n";
    
    
    # PATH_LNK_1_9902=C:\tools\vislink_1.9902
    die "\nERROR: environment variable %PATH_LNK_1_9902 must be set!\n"
      unless exists($ENV{'PATH_LNK_1_9902'});
    $ENV{'PATH_LNK_1_9902'} =~ s|\\|/|g;
    $ENV{'PATH_LNK_1_9902'} =~ s|;.*||;
    print "%PATH_LNK_1_9902  : \"" . $ENV{'PATH_LNK_1_9902'} . "\"\n";
    

} # init_environment


#-------------------------------------------------------------------------------
# Check for gnumake availability, returns gnumake depending or die
#-------------------------------------------------------------------------------
sub check_gnumake_available
{
    my ($rc) = int (system("gnumake -ver > NUL 2>&1") / 256);
    if(!$rc == 0){
      die "\nERROR: No make gnumake tool found, aborting";
    }
}

#-------------------------------------------------------------------------------
# Check if Java is installed (in the path), return version string of Java.
#-------------------------------------------------------------------------------
sub determine_java_version
{
    my $java_ver = `java -version 2>&1`;
    if ($? == 0)
    {
        # only keep the first line of java version string and remove "java", if present
        $java_ver =~ s/\n.*$//s;
        $java_ver =~ s/\s*java\s*//;
        print "Java    : " . $java_ver . "\n";
    }
    else
    {
        die "\nERROR: Java not found (not installed or not in the path), aborting";
    }
}


sub step__check_environment
{
    print_status ($_[0] . ". Checking environment");

    # create the makefile filename
    # param  = system\productdefs\sample.xml
    # o_file = system/productdefs/sample.xml
#     print_status ($_[0] . " 1 " .$makeFile);
#     print_status ($_[0] . " 2 " .$o_file);
#     print_status ($_[2] . " 3 " .$o_dlvcfg);
   
    $makeFile = (File::Spec->splitpath($o_file))[2];
    $makeFile =~ s/(\.xml)$//;
    if ($o_dlvcfg)
    {
        $makeFile =$makeFile."_".$o_dlvcfg;
    }
    $makeFile =$makeFile.".mak";

    # initialize necessary env. variables (%PATH, %C_DIR)
    init_environment();
    check_gnumake_available();
    determine_java_version();

}


#-------------------------------------------------------------------------------
# update BuSyB makefile, if necessary; takes an additional second parameter
# to specify the BuSyB .ini file
#-------------------------------------------------------------------------------
sub step__update_busyb_makefile
{

    my $temp_xml = "dlv_mak.xml";
    open( MSL_FD,">$temp_xml")
        or die "ERROR: Can't open file \"$temp_xml\" ($!), aborting";

    print MSL_FD "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print MSL_FD "<configDef name=\"dlv_mak\" description=\"\" reference=\"\">\n";
    print MSL_FD "<property include=\"$o_file\"/>\n";

    if ($o_dlvcfg)
    {
        print MSL_FD "<property include=\"$dlv_cfg\"/>\n";
    }
    print MSL_FD "</configDef>\n";

    close( MSL_FD)
        or die "ERROR: Can't close file \"$temp_xml\" ($!), aborting";

    use constant UBB_MAKETOOL => "gnumake ";
    use constant UBB_UPDATE_MAKE => "-f system/nds_update_makefile.mak ";

    print_status ($_[0] . ". Generate BuSyB makefile ($makeFile)");
#    $command = UBB_MAKETOOL.UBB_UPDATE_MAKE." MFILE=$makeFile XMLFILE=$o_file";
    $command = UBB_MAKETOOL.UBB_UPDATE_MAKE." MFILE=$makeFile XMLFILE=$temp_xml";
    print "$command\n\n";

    system($command) == 0
        or die "ERROR: Can't create makefile \"$makeFile\" ($!), aborting";
    print "\n";

    $command = "rm $temp_xml";
    print "$command\n\n";
   system($command) == 0
       or die "ERROR: Can't remove temporary file \"$temp_xml\" ($!), aborting";
    
}


#-------------------------------------------------------------------------------
# redirect STDOUT+STDERR to $o_logfile, return 1 if redirection successful or
# 0 if redirection failed
#-------------------------------------------------------------------------------
sub redirect_output
{
    my $redirected = 1;

    open (CONSOLE_OUT, ">&STDOUT");
    open (CONSOLE_ERR, ">&STDERR");

    open (STDOUT, '>', $o_logfile)
        or $redirected = 0;
    open (STDERR, ">&STDOUT")
        or $redirected = 0;

    if ($redirected)
    {
        # make output unbuffered
        select (STDERR); $| = 1;
        select (STDOUT); $| = 1;

        # install signal handler function for die()
        $SIG{__DIE__} = \&die_handler
          or print CONSOLE_ERR "WARNING: Could not install die() signal handler,
                console output may be corrupted when exiting with an error!\n";
    }
    else
    {
        # redirection failed: use old STDOUT+STDERR
        restore_redirection();
        print "WARNING: Could not redirect STDOUT+STDERR to " . $o_logfile . ", not logging output!\n";
    }
    return $redirected;
}


#-------------------------------------------------------------------------------
# close logging to $o_logfile and restore old STDOUT+STDERR
# (pointing to console)
#-------------------------------------------------------------------------------
sub restore_redirection
{
    # restore redirected STDOUT+STDERR
    close (STDOUT);
    close (STDERR);
    open (STDOUT, ">&CONSOLE_OUT");
    open (STDERR, ">&CONSOLE_ERR");    
}


#-------------------------------------------------------------------------------
# print die() error message, to also log it to $o_logfile and then restore
# the STDOUT+STDERR redirection
#-------------------------------------------------------------------------------
sub die_handler
{
    print STDERR $_[0];
    restore_redirection();
}
