#!perl 

use strict;
use Getopt::Long ;
Getopt::Long::config qw[pass_through]; 
use File::Copy;

########################################################################
# (C) Copyright 2007 NXP Semiconductors , All Rights Reserved   
#                                                                            
#  This source code and any compilation or derivative thereof is the sole   
#  property of NXP Semiconductors and is provided pursuant to a Software   
#  License Agreement.  This code is the proprietary information of          
#  NXP Semiconductors and is confidential in nature.  Its use and          
#  dissemination by any party other than NXP Semiconductors is strictly    
#  limited by the confidential information provisions of the Agreement      
#  referenced above.                                                         
########################################################################
# Author: Roopa Mahishi (RM) 
########################################################################
# Revision history:
# -----------------|--------------|------------------------------------------
# Date             | Version      | Description
# -----------------|--------------|------------------------------------------
# 2005-09-05       | 1.4, RM      | Initial version
# -----------------|--------------|------------------------------------------
# 2005-09-29       | 1.5, RM      | Remove checking of presence of target, lib
#                  |              | configuration, java in makefile.
#                  |              | Check for presence of only all: target
# -----------------|--------------|------------------------------------------
# 2007-05-23       | 1.6, BG      | Consolidation of environment variables
########################################################################

if($#ARGV<0){
    DisplayUsage();
    exit 1;
}

##################################################################
# Global Variables
##################################################################

# Defines values.where the user may require to change the value if
# required

#Retaining the version number from the previous script
#Update the version number as and when you make changes
my $ScriptVersion = 1.6 ;


# The values are not to be changed by the user
#Hashes


#Arrays
my @CompOptionNames = "";

#Variables
my $EnvOption = 1;
my $ShowallOption =1 ;

die ( "Environment variable _TMROOT is not set\n")
       if(!defined $ENV{_TMROOT} || $ENV{_TMROOT} eq "");


my $AllEnvListingFile = $ENV{_TMROOT}."/project/allenvlisting.txt";

my $MaxVal4SupportedConfg = 3;
my $TotalErrorCount = 0;
my $TotalWarnCount = 0;
my $MinimumGmakeVersion = "3.79";
my $MinimumSedVersion = "3.02";

my $SingleValue = 1;
my $DoubleValue = 2;
my $CPUCLASS="";
my $OSCLASS="";

#################################################################
# Main starts here
##################################################################
CheckCommandLineArguments();
print "\n\n","=" x 80, "\n"; 
print "Auto-detection script: Execution completed with $TotalErrorCount ERRORS and $TotalWarnCount WARNINGS\n";
print "=" x 80, "\n";


#################################################################
# Main ends here
##################################################################

#Subroutines

########################################################################
# Subroutine       :  PrintHash                       
# Description      :  This subroutine prints the values of the hash
#                  :                                                    
#########################################################################
sub PrintHash  {
    my ($refHash ) = @_;
    for my $key(sort keys %$refHash) {
        print "$key = $ENV{$key}\n";
    }
    print "\n";
}


########################################################################
# Subroutine       :  CheckCommandLineArguments                       
# Description      :  This subroutine checks for the commandline arguments
#                  :                                                    
#########################################################################
sub CheckCommandLineArguments  {

   #Local variables
   my %MainGenericEnvVars = ();
   my %OptGenericEnvVars = ();
   my %UnameEnvVars = ();
   my %AllSupportedConfgs = ();

   my %LocListValues = ();
 
   my @AllCompArray = ();
   my $ref2Array = "";

   my $EachConfigDetails = "";
   my $help = 1;
   
   GetOptions (  "env:i"   => \$EnvOption,
                 "showall:i"   => \$ShowallOption,
                 "comp:s" => \@CompOptionNames,
                 "help:i"    =>  \$help,
                 '<>' => \&CheckForUnHandledCommandOption
               );

  if(!$help ){
      DisplayUsage();
      exit(0);
   }   

   #Remove if there any duplicate entries on the commandline 
   my %hash = ""; 
   foreach (@CompOptionNames){
     $hash{$_} =1 if ($_ ne "");
   }
   @CompOptionNames = keys (%hash);

   print "*" x 80,"\n";
   print  "\nauto_det.pl script version $ScriptVersion \n";
   print  "(c) NXP Semiconductors, 2007\n\n";
   print "*" x 80,"\n";
  if (!-f "makefile") {
	printf "makefile not found!!\n";
	printf "auto_det.pl should be run from a component/application directory\n";
	exit 1; 
	}

   open( IN, $AllEnvListingFile) or die "_TMROOT is not set properly.\nSet proper value of _TMROOT.\n";

   while (<IN>) {
        chomp; 
        #Ignore blank lines
        $_ =~ s/^\s+|\s+$//g;
        #Ignore comment lines   
        next if(/^#/ || /^\n/);

        GetVarsFromFile(\*IN, \%MainGenericEnvVars) 
            if(/main_generic_environment_variables/);
        GetVarsFromFile(\*IN, \%OptGenericEnvVars) if(/optional_generic_environment_variables/);
        GetVarsFromFile(\*IN, \%UnameEnvVars) if(/uname_environment_variables/);
        if(!$EnvOption){ 
           GetAllSupportedConfgs(\*IN, \%AllSupportedConfgs) if(/all_supported_configurations/);
        }
        $EachConfigDetails = GetConfigDetails(\*IN, $_) if (/config_details_/);
   }

   close IN;
   if(!$EnvOption){
       Check4EnvOption(\%AllSupportedConfgs,$EachConfigDetails);
       CheckExistenceNValidityOfVars(\%MainGenericEnvVars,"Checking generic environment variables");
       Check4OptionalEnvVarSetting(\%OptGenericEnvVars,"Checking optional environment variables")
                    if(!$ShowallOption);
       Check4CygwinVariableSetting(\%UnameEnvVars);
       Check4GmakeVersion();
       Check4SedVersion();
       %LocListValues = Check4LocListFile();
   }
   
    #Remove the null elements from the array
    my $tmp_string = join("," , @CompOptionNames); 
    $tmp_string =~ s/,,/,/; 
    @CompOptionNames = split(/,/, $tmp_string); 
    my $Check4AllComps = 0;
    if ($tmp_string =~ m/(\,\s*all\s*\,)|(^all)\,|\,all$/) {
       $Check4AllComps = 1;
    }

    if($#CompOptionNames > 0){
        print "\n\n################## Checking Component Makefiles ##################\n";
        # If env option is not set, then check for loclist files.
        # Assign the latest loc_list variables into hash
        if($EnvOption || (1 == $Check4AllComps)){
           %LocListValues =  Check4LocListFile();
        }
        if(1 == $Check4AllComps){
            # Get all the component names that need to be tested.The 
            # component names are stored as key of hash LocListValues
            # Remove the names of the interfaces and store the values in
            # array
            @AllCompArray = (keys %LocListValues);
            my @temparray = ();
            foreach my $key (@AllCompArray) {
               if($key !~ m/_I(\S+)_DIR/){
                   $key =~ s/_DIR//g;
                   $key =~ s/^_//g;
                   push @temparray, $key;
               } 
            }
            @AllCompArray = @temparray;
            $ref2Array = \@AllCompArray;
         }
         else {
             $ref2Array = \@CompOptionNames
         }


        foreach my $CompName(@$ref2Array){
          my $comp = $CompName;
          if($comp ne ""){
            print "-" x 80,"\n";
            print"Checking component makefile : $CompName\n";
            print "-" x 80,"\n";
            my $string = "comps\/";
            # Get just the componenet name and see whether the value exists
            # in the loc_list file. and try to get the full path of the component
            $comp =~ s/$string//g;
            #Get the value from the hash
            my $CompCheck="_".$comp."_DIR";
            my $Skip = 0;
            if(exists ($LocListValues{$CompCheck})){
                # Check for the different values and validation of the 
                # component name
                if( !-d $LocListValues{$CompCheck}) {
                    print "ERROR: $LocListValues{$CompCheck}is not a component directory. Skipping test ....\n\n";
                    $Skip =1;
                    $TotalErrorCount++;
                }                
                elsif(!-f $LocListValues{$CompCheck}."/makefile") {
                     print "ERROR: makefile does not exist for $LocListValues{$CompCheck}. Skipping test ....\n\n";
                     $TotalErrorCount++;
                     $Skip =1;
                }
                elsif ($comp !~ /^[tm|ph]/){ 
                     print "WARNING: Component name ( $LocListValues{$CompCheck} ) doesn't start with 'tm' or 'ph'\n\n";
                     $TotalWarnCount++;
                }
                elsif ($comp =~ m/\_/  ){
                    print"ERROR: Underscore(_) found in component name $LocListValues{$CompCheck}\n\n";
                    $TotalErrorCount++;
                }
                elsif($comp =~ m/[^a-zA-Z0-9\_]/){
                    print"WARNING: Component name( $LocListValues{$CompCheck} ) consists of non-alphanumeric characters\n\n";
                    $TotalWarnCount++;
                }
                CheckWithinComponentMakefie($comp,$LocListValues{$CompCheck})  if (0 == $Skip);

            }
            else {
                if($CompName ne ""){
                   print "$CompName is not present in loc_list.mk. The component name is not valid. Please update prjlist.txt\n\n";
                }
            }
          } # end of if comp ne "" 
           

        } # end of for loop 
    
    } # end of if( $#CompOptionNames > 0)
}


########################################################################
# Subroutine       :  Check4OptionalEnvVarSetting                       
# Description      :  This subroutine prints the elements of the
#                  :  hash
#                  :  
#########################################################################
sub Check4OptionalEnvVarSetting {
    my ($refHash, $string2Display) = @_;
    my $string = qq(---------------------------------------------------------------- 
$string2Display .....
The following optional environment variables are set:
---------------------------------------------------------------- \n);
    print $string;
    
  
    foreach my $key (sort keys %$refHash) {
        # Check whether valid value is set from the list of possible values.
        if (defined $ENV{$key} ){
            print "$key = $ENV{$key}\n";
        }
    }
print "\n";
}

########################################################################
# Subroutine       :  ReadFile                       
# Description      :  This subroutine opens the file specified and
#                  :  reads the contents in a variable
#                  :  
#########################################################################
sub ReadFile {
    my $filename = shift;
    my $FileContents;

    local $/;
    if (open (FP,$filename)){ 
      $FileContents = <FP>;
      close FP;
    }  
    return $FileContents;
}


########################################################################
# Subroutine       :  ReadMultipleLineValues                       
# Description      :  This subroutine reads the mulitple lines of the string
#                  :  
#                  :  
#########################################################################
sub ReadMultipleLineValues {
    my ($startstring,$string) = @_;
    $string =~ s/$startstring  # Match for the starting of the string followed
        \s*[?:=]*                # by  0 or more spaces, with or without a =
        \s*((\w+[\/]*\s*)*     # with zero or more words and spaces combinations
        \\\s*)*                # with a continuation char \
        (\w+[\/]*\s*[\\]*)*/$1$2/x; # ending with a word or a \
    my $MatchedString = $&;
    $MatchedString =~ s/\s+/ /g;

    # Return the full string
    return $MatchedString; 
}


########################################################################
# Subroutine       :  Check4NoOfOccurrence                       
# Description      :  This subroutine reads the occurence of the substring 
#                  :  in the string
#                  :  
#########################################################################
sub Check4NoOfOccurrence  {
    my ($string,$substring) = @_;
    my $count = 0;
    $count = () = $string =~ /$substring/g;
    return $count;
}


########################################################################
# Subroutine       :  CheckWithinComponentMakefie                       
# Description      :  This subroutine opens the makefile and checks for 
#                  :  the DIR_LOCAL,configuration target,divery.mk 
#                  :  
#########################################################################
sub CheckWithinComponentMakefie {
    my ($ComponentName,$ComponentPath) = @_;
    
    my $CompMakefile = ${ComponentPath}."/makefile";

    my $MakefileContents = ReadFile($CompMakefile);

    open (MKFILE,$CompMakefile) or 
                        die "Cannot open ${ComponentPath}/makefile. $! ";

    # Local variables 
    my $LineNoOfDirInclude=0;
    my $DirLocalDef = 0;
    my $EnvMakeFound = 0;
    my $LineNoOfEnvInclude=0;
    my $AllTargetFound = 0;
    my $AllTargetName = "";
    my $LineNoOfAll = 0;
    my $AllTargetMakeFileNameInclude = 0;
    my $DiversityTargetInAll = 0;
    my $DiversityFileInc = 0;

    my $CompErrCount = 0 ;
    while(<MKFILE>){ 
        chomp; 
        #Ignore blank lines
        $_ =~ s/^\s+//g;
        #Ignore comment lines   
        next if(/^#/ || /^\n/);
       
        # Replace with the blanks if # is present 
        $_ =~ s/\#(.*)//g; 

        # Match for the existenceof DIR_LOCAL with 1 or more  spaces followed
        # by = , 0 or more spaces and comps/<name of the component>
        # The value contained in $1 is the name of the component
#        if(/DIR\_LOCAL\s+\=\s*comps\/(\w+)/){
         if(/\ADIR\_LOCAL\s*[\?\:]*\=/){
            my $DirlocalString = ReadMultipleLineValues("DIR_LOCAL",$MakefileContents);

            # The returned string will have DIR_LOCAL = details of component name
            # Strip all the details like comps, DIR_LOCAL,=,\
            $DirlocalString =~ s/comps\/|DIR\_LOCAL|\?|\:|\=|\\//g;
            # Strip all the remaining words and get only the component name
            $DirlocalString =~ s/(\w+)(\s*\w+)*/$1/g;
            
            # String 0 or more spaces    
            $DirlocalString =~ s/\s+//g;

            if($DirlocalString ne $ComponentName) {
                print "ERROR: Incorrect component name($DirlocalString) specified in DIR_LOCAL\n\n";
                $CompErrCount++ ;
            }
            $LineNoOfDirInclude = $.;
            $DirLocalDef = 1;
        }

        # Check for environment.mk file inclusion
        if(/include\s+\$[\(]*\_TMROOT[\)]*\/sde\/environment\.mk/){
            $LineNoOfEnvInclude = $. ;
            $EnvMakeFound = 1;
        }
        if(/all\:/){
            $AllTargetFound = 1;
            $LineNoOfAll = $.;

            # Following lines are commented out so that the 
            # checking is done for only the presence of all: and nothing else
            my $TargetString = ReadMultipleLineValues("all\:",$MakefileContents);
=head
            if($TargetString !~  m/configuration/){
                print"ERROR: 'configuration' target is not defined in all:\n\n";
                $CompErrCount++ ;
            }

            if($TargetString =~ m/lib|target|java/){
                $AllTargetName = $&;
            }
=cut
            $DiversityTargetInAll= 1 if($TargetString =~ m/diversity/);
        } #end of if (/all:/)
        # Check for makelib or maketarget or makejava.mk file existence
        if(/(include\s+\$[\(]*DIR_SDE[\)]*\/\$[\(]DIR_CONFIG[\)]\/make)((.)*)\.mk/){
=head
            # This checking is removed in 1.5 version
            if($2 !~m /$AllTargetName/){
                print"ERROR: Target '$AllTargetName' is specified in all: but make${2}.mk is included \n\n";
                $CompErrCount++ ;
            }
=cut
            $AllTargetMakeFileNameInclude = 1;
        }
        
        if(/(include\s+\$[\(]*DIR_SDE[\)]*\/make)((.)*)\.mk/){
=head
           # This checking is removed in 1.5 version
            if($2 !~m /$AllTargetName/){
                print"ERROR: Target '$AllTargetName' is specified in all: but make${2}.mk is included\n\n";
                $CompErrCount++ ;
            }
=cut
            $AllTargetMakeFileNameInclude = 1;
        }
        if(/\\(\s+)$/){ 
            print "ERROR: A whitespace character is found after '\\' at line no.$.\n\n";
            $CompErrCount++ ;
        }
        if(/include\s+diversity.mk/){
            $DiversityFileInc = 1;
        }
    
    } # end of while
    close MKFILE;

    if( 0 == $DirLocalDef ) {
        print "ERROR: DIR_LOCAL is not defined\n\n";
        $CompErrCount++ ;
    }
    if( 0 == $EnvMakeFound ) {
        print"ERROR: environment.mk file is not included\n\n";
        $CompErrCount++ ;
    }
    if( 0 == $AllTargetFound ) {
        print"ERROR: all: target is not specified\n\n";
        $CompErrCount++ ;
    }
    if ( Check4NoOfOccurrence($MakefileContents,"all\:") > 1 ){
        print "WARNING: Multiple declarations of all\: present\n";
        $TotalWarnCount++;
    }
  
    if( 0 == $AllTargetMakeFileNameInclude ) {
      my $string = qq(ERROR: makelib.mk (or) maketarget.mk (or) makejava.mk file is not included
Atleast one of these files should be included\n\n);
        print $string;
        $CompErrCount++ ;
    }

    if($LineNoOfEnvInclude < $LineNoOfDirInclude || $LineNoOfEnvInclude > $LineNoOfAll){
        my $string = qq(ERROR: environment.mk file is not included in correct place
It should be included after DIR_LOCAL and before all: definitions\n);
        print $string;

        $CompErrCount++ ;

    }
   
    if(1 == $DiversityTargetInAll && 0 == $DiversityFileInc ){
        print "WARNING: ${ComponentPath}/diversity.mk is not included in component makefile\n";
        $TotalWarnCount++;
    }

    if(0 == $DiversityTargetInAll && 1 == $DiversityFileInc ){
        print "WARNING: diversity is not specified in target all: in component makefile\n";
        $TotalWarnCount++;
    }

    if(1 == $DiversityFileInc || 1 == $DiversityTargetInAll){
         $CompErrCount += CheckDiversityFileContents($ComponentName,$ComponentPath);
    }
    if(0 == $CompErrCount){
         print "Component makefile for $ComponentPath is checked and found OK\n\n"; 
    }
    else {
        print "\nErrors found in $CompMakefile ( $CompErrCount )\n\n";
        $TotalErrorCount += $CompErrCount;
    }


}


########################################################################
# Subroutine       :  CheckDiversityFileContents                       
# Description      :  This subroutine checks for contents of diversity 
#                  :  makefile and prints appropriate error messages.
#                  :  
#########################################################################
sub CheckDiversityFileContents {
    my ($ComponentName,$ComponentPath) = @_;

    my $DiversityFileErrCount = 0;
    my $DiversityMakefile = ${ComponentPath}."/diversity.mk";

    local $/;
  if (open (DVR,$DiversityMakefile)){ 
    my $DiversityFileContents = <DVR>;
    close DVR;

    if($DiversityFileContents =~ m/[^\#]\s*LIB\_SUFFIX\s*=/){
        print "ERROR: LIB_SUFFIX should not be defined in $DiversityMakefile file\n\n";
        $DiversityFileErrCount++;
    }

    if($DiversityFileContents !~ m/[^\#](\_${ComponentName}\_)(SUFFIX|DIVERSITY|LOADED)\s*=/){
        my $string = qq(WARNING: _<CompName>_SUFFIX (or) _<CompName>_DIVERSITY (or) _<CompName>_LOADED is not defined
in $DiversityMakefile file.
Atleast one of the above should be defined.\n\n);
        print $string;
    }
  } #end of if stmt
    return $DiversityFileErrCount;

}

########################################################################
# Subroutine       :  ReadLocListFileContents                       
# Description      :  This subroutine opens the loc_list file and
#                  :  read the contents. Stores the values in the hash
#                  :  
#########################################################################
sub ReadLocListFileContents {
    my ($filename) = @_;
    my %temphash = ();
    local $/;
    open (FP, $filename) or 
        die "Error in opening $filename. $!\n"; 
    my $NewLocListContents= <FP>;
    close FP;

    #Remove the comment lines and blank spaces
    $NewLocListContents =~ s/\#(.)*//g;
    my @values = split("\n",$NewLocListContents);
    foreach my $key (@values) {
        $key =~ s/\s*//g;
        #Split on := and store the values in the hash
        my @data = split(":=", $key);
        $temphash{$data[0]}=$data[1];
    }
    return (%temphash);

}

########################################################################
# Subroutine       :  Check4LocListFile                       
# Description      :  This subroutine checks for the existence of loc_list files.
#                  :  If not present, the loc_list files are generated.
#                  :  
#########################################################################
sub Check4LocListFile {
    my %ExistingLocListValues = "";
    my %NewLocListValues = ();

    $ENV{_TMTGTBUILDROOT} = $ENV{_TMROOT} if( !defined $ENV{_TMTGTBUILDROOT});

    if(!-f "$ENV{_TMTGTBUILDROOT}/project/loc_list.mk"){
        # Regenerate the file if the loc_list.* files are not present
        print "File $ENV{_TMTGTBUILDROOT}/project/loc_list.mk is not found. Generating the file....\n";
        system ("$ENV{MAKE} -f $ENV{_TMROOT}/sde/environment.mk makelist");
        print "DONE\n";
        $TotalWarnCount++;

        if($#CompOptionNames > 0){
            # Read the contents of the file and place it in the hash
            %NewLocListValues = ReadLocListFileContents("$ENV{_TMTGTBUILDROOT}/project/loc_list.mk");
       }

    }
    else {
        # If loc_list.* files are present, check whether file contents
        # of the recently generated loc_list.mk and existing loc_list.mk
        # are same. If they differ then regenerate the loc_list.* files.

        #Read contents of _TMTGTBUILDROOT/project/loc_list.mk file
        local $/;
        open (IN, "$ENV{_TMTGTBUILDROOT}/project/loc_list.mk") or 
            die "Error in opening $ENV{_TMTGTBUILDROOT}/project/loc_list.mk. $!\n"; 
        my $ExistingLocListContents= <IN>;
        close IN;
        
        #Remove the comment lines and blank spaces
        $ExistingLocListContents =~ s/\#(.)*//g;
        my @values = split("\n",$ExistingLocListContents);
        foreach my $key (@values) {
            $key =~ s/\s*//g;
            #Split on := and store the values in the hash
            my @data = split(":=", $key);
            $ExistingLocListValues{$data[0]}=$data[1]
        }

       my $OrigTmtgtbuildrootVal = $ENV{_TMTGTBUILDROOT};
       # Value of TMTGTBUILDROOT is altered because makelist
       # generates loc_list.* files in the _TMTGTBUILDROOT/project path
       $ENV {_TMTGTBUILDROOT} = "$ENV{_TMROOT}/sde/scripts";
       my $TempLocListFile = "$ENV{_TMTGTBUILDROOT}/project";

       #Generate the loc_list.* files at the temp location
       system ("$ENV{MAKE} -f $ENV{_TMROOT}/sde/environment.mk makelist > ./temp_log.txt");
       unlink "./temp_log.txt";
       #Read contents of _TMTGTBUILDROOT/project/loc_list.mk file
       %NewLocListValues = ReadLocListFileContents("$ENV{_TMTGTBUILDROOT}/project/loc_list.mk");

=head
       local $/;
       open (NEW, "$ENV{_TMTGTBUILDROOT}/project/loc_list.mk") or 
            die "Error in opening $ENV{_TMTGTBUILDROOT}/project/loc_list.mk. $!\n"; 
       my $NewLocListContents= <NEW>;
       close NEW;

        #Remove the comment lines and blank spaces
        $NewLocListContents =~ s/\#(.)*//g;
        my @values = split("\n",$NewLocListContents);
        foreach my $key (@values) {
            $key =~ s/\s*//g;
            #Split on := and store the values in the hash
            my @data = split(":=", $key);
            $NewLocListValues{$data[0]}=$data[1]
        }
=cut
        # Re-store original value of _TMTGTBUILDROOT 
        $ENV{_TMTGTBUILDROOT} = $OrigTmtgtbuildrootVal;
        # Compare the contents of hash, if any of values differ then copy the
        # newcontents into the original _TMTGTBUILDROOT
        my $ExistingValsLength = scalar (keys %ExistingLocListValues);
  
        my $LoopHashReference = \%NewLocListValues;
        if ($ExistingValsLength > scalar(keys %NewLocListValues) ){ 
            $LoopHashReference = \%ExistingLocListValues;
        }
        
        my $CopyContents = 0;
        foreach my $key (sort keys %$LoopHashReference) {
            if($key ne ""){
                if($ExistingLocListValues{$key} ne $NewLocListValues{$key}){
                    $CopyContents = 1;
                    last;
                }
            }
            last if ($CopyContents);
        } 
       
        if ($CopyContents) {
          print "WARNING: $ENV{_TMTGTBUILDROOT}/project/loc_list.* files do not match with $ENV{_TMROOT}/project/prjlist.txt file contents\n";
          print "Overwriting $ENV{_TMTGTBUILDROOT}/project/loc_list.* files ......\n";
          move("${TempLocListFile}/loc_list.mk","$ENV{_TMTGTBUILDROOT}/project");
          move("${TempLocListFile}/loc_list.txt","$ENV{_TMTGTBUILDROOT}/project");
          $TotalWarnCount++;
          print "DONE\n"
        }
    }

    # Return the entire hash to the calling function
    return (%NewLocListValues);
}



########################################################################
# Subroutine       :  Check4GmakeVersion                       
# Description      :  This subroutine checks for the gmake version and prints
#                  :  error if the gmake version is less than the required 
#                  :  gmake version
#########################################################################
sub Check4GmakeVersion {
    $ENV{MAKE} = "gmake -r" if( !defined $ENV{MAKE} );
	my $Command = "$ENV{MAKE} --version";
	my $GmakeFileContents="";
    if (!open(GMAKE, "$Command 2>&1|"))
	{
		printf "Unable to run $Command\n";
	}
	else {
		local $/;
	    $GmakeFileContents = <GMAKE>;
		close GMAKE;
	}

    my $string = qq(------------------------------------------------
Checking for 'gmake' version
------------------------------------------------\n);
    print $string;

    #Get the version number from the GNU Make Version <versionnumber>
    $GmakeFileContents =~ m/GNU\s+Make\s+((.)*)/;
    my $GmakeVersion = $1;
    if( $GmakeVersion >= $MinimumGmakeVersion ) {
        print "gmake version ( $GmakeVersion ) is checked and found OK.\n\n";
    }else {
        print "ERROR: Wrong gmake version ($GmakeVersion) found.\n\n";
        $TotalErrorCount++;
    }
}

########################################################################
# Subroutine       :  Check4SedVersion                       
# Description      :  This subroutine checks for the gmake version and prints
#                  :  error if the gmake version is less than the required 
#                  :  gmake version
#########################################################################
sub Check4SedVersion {
	my $Command = "sed --version";
	my $SedFileContents="";
    if (!open(SED, "$Command 2>&1|"))
	{
		printf "Unable to run $Command\n";
	}
	else {
		local $/;
	    $SedFileContents = <SED>;
		close SED;
	}

    my $string = qq(------------------------------------------------
Checking for 'sed' version
------------------------------------------------\n);
    print $string;

    #Get the version number from the GNU sed version <versionnumber>
    $SedFileContents =~ m/GNU\s+sed\s+version\s+((.)*)/;
    my $SedVersion = $1;
    if( $SedVersion >= $MinimumSedVersion ) {
        print "sed version ( $SedVersion ) is checked and found OK.\n\n";
    }else {
        print "ERROR: Wrong sed version ($SedVersion) found.\n\n";
        $TotalErrorCount++;
    }
}

########################################################################
# Subroutine       :  Check4CygwinVariableSetting                       
# Description      :  This subroutine checks whether the uname variables 
#                  :  mentioned in the hash are present in the 
#                  :  _TMROOT/project/sites/_TMSITE/UNAME.mk file
#                  :
#########################################################################
sub Check4CygwinVariableSetting {
    my ($refHash) = @_;
    my $uname="";
    if (!defined $ENV{UNAME}){
	    $uname="Linux";
	    $uname="cygwin" if( $^O eq "MSWin32" );
	}
    else{
		$uname=$ENV{UNAME};
	}
    my $UnameFile = (defined $ENV{_TMPROJECT})? $ENV{_TMPROJECT}."/$uname.mk" 
                                              : $ENV{_TMROOT}."/project/$uname.mk";
    open(UNAME, $UnameFile) or die "Cannot open $UnameFile. $!";
    local $/;
    my $UnameFileContents = <UNAME>;
    close UNAME;

    foreach my $key (keys %$refHash){
        if($UnameFileContents !~ m/[^\#]\s*${key}\s*\=\s*(([\w+\/\$\(\).]*))/){
            print "ERROR: $key is not defined in $UnameFile\n";
            $TotalErrorCount++;
        }
	}
}



########################################################################
# Subroutine       :  CheckExistenceNValidityOfVars                       
# Description      :  This subroutine checks for the validy of each 
#                  :  value of the hash passed. 
#                  :                                                    
#########################################################################
sub CheckExistenceNValidityOfVars  {
    my ($refHash, $string2Display) = @_;
  
    foreach my $key (sort keys %$refHash) {
        if(!defined $ENV{$key} || $ENV{$key} eq ""){
            print "ERROR: Environment variable $key is not set\n";
            $TotalErrorCount++;
        }
        else { 
            # The variable exists. Check for the validity of the path specified
            if($key eq "_TMROOT" || $key eq "_TMTGTBUILDROOT"){
                print "ERROR: The path set for $key ($ENV{$key}) does not exist\n"  if(!-d $ENV{$key});
                $TotalErrorCount++ if(!-d $ENV{$key});
            }
            else {
                # Check whether valid value is set from the list of possible values.
                if ($refHash->{$key} ne "1"){
                    if($refHash->{$key} !~ m/$ENV{$key}/) {
                        print "ERROR: Invalid value set for $key ($ENV{$key})\n" ;
                        $TotalErrorCount++;
                    }
                }
            }
        }
    }
    if(!$ShowallOption){
        my $string = qq(----------------------------------------------------
$string2Display .....
---------------------------------------------------------------- \n);
        print $string;
        my @GetKeys = (sort keys %$refHash);
        foreach my $key(@GetKeys){
            print "$key = $ENV{$key}\n" if ($key !~ m/_TMTGTOSCLASS|_TMTGTCPUCLASS/);
        }
        
    }
       
}


########################################################################
# Subroutine       :  Check4EnvOption                       
# Description      :  This subroutine checks for only the environment
#                  :  variables. The correct configuration, cygwin/unix
#                  :  variables setting and loc_list.* are checked.
#                  :                                                    
#########################################################################
sub Check4EnvOption  {
    my ($refHash, $configContents) = @_;
    my %TempHash = %$refHash;
    my $ValidConfigurationPresent = 0;
	my $Command = "$ENV{MAKE} var=_TMTGTCPUCLASS var2=_TMTGTOSCLASS _sde_print_var_5 _TMECHO=";
	my $GmakeFileContents="";
    if (!open(GMAKE, "$Command 2>&1|")){
		printf "Unable to run $Command\n";
	}
	else{
		local $/;
	    $GmakeFileContents = <GMAKE>;
		close GMAKE;
	}
	$GmakeFileContents =~ /_TMTGTCPUCLASS\=((.)*)/;
    $CPUCLASS=$1;
	$GmakeFileContents =~ /_TMTGTOSCLASS\=((.)*)/;		
	$OSCLASS=$1;

	my $ConfigSetByUser = (defined $ENV{_TMTOOLCHAIN}) 
                     ? $CPUCLASS.$ENV{_TMTOOLCHAIN}."_".$OSCLASS
                     : $CPUCLASS."_".$OSCLASS;

    my $configToBePresent = "";

    # If the toolchain is  mentioned as default then the toolchain name need not be present in 
    # the configuration class.
    # Eg. for CPUCLASS=x86, OSCLASS=nt, and TOOLCHAIN=ms, the configuration is x86ms_nt
    # However, if TOOLCHAIN is declared as (default), then configurations  x86ms_nt and x86_nt
    # are treated as valid. 
    foreach my $toolChainName (keys %{$refHash->{$CPUCLASS}} ) {
        my $possibleOsNames = $refHash->{$CPUCLASS}{$toolChainName};
        if($toolChainName =~ m/default/){
            if($possibleOsNames =~ m/$OSCLASS/){
                $configToBePresent =  $CPUCLASS.$toolChainName."_".$OSCLASS;
                $configToBePresent =~ s/\(default\)//g;
                if($configToBePresent eq $ConfigSetByUser){
                    $ValidConfigurationPresent = 1;
                }
                else {
                    $configToBePresent = $CPUCLASS."_".$OSCLASS;
                    if($configToBePresent eq $ConfigSetByUser){
                        $ValidConfigurationPresent = 1;
                    }
                }
            }
        }
        else { 
            # toolchainname does not ahve a default declared beside it. Hence can safely assume 
            # the configuration name as cpuclass.toolchainname_osclass.
            if($possibleOsNames =~ m/$OSCLASS/){
                $configToBePresent = $CPUCLASS.$toolChainName."_".$OSCLASS;
                if($configToBePresent eq $ConfigSetByUser){
                    $ValidConfigurationPresent = 1;
                }
            }
        }
    }

    print "\n################# Checking Environment Variables ##################\n";
    if(!$ShowallOption){
        my $string = qq(Checking configuration class environment variables .....
---------------------------------------------------------------- 
_TMTGTOSCLASS = $OSCLASS
_TMTGTCPUCLASS = $CPUCLASS\n);
        print $string;
        print "_TMTOOLCHAIN = $ENV{_TMTOOLCHAIN}\n" if ($ENV{_TMTOOLCHAIN} ne "");

    }

    if(1 ==  $ValidConfigurationPresent){
#        print "\nThe configuration class is $ConfigSetByUser\n\n";
        CheckConfigSpecificEnv($configContents,$ConfigSetByUser,"Checking configuration specific environment variables");
    }
    else {
        print "\nERROR: Invalid configuration class\n\n";
        $TotalErrorCount++;
    }

}

#######################################################################
# Subroutine       :  CheckConfigSpecificEnv                       
# Description      :  This subroutine is used to get the entire contents
#                  :  of config_details. Each config details are stored 
#                  :  in the variable 
#                  :                                                    
#########################################################################
sub CheckConfigSpecificEnv{
    my($FileStringContents,$ValidConfig,$string2Display) =  @_;
    my @FileContents = split("\n",$FileStringContents);
   
 
    my %ConfigVarListing = ();
    my $ConfigDetailStart = 0;
    foreach my $key (@FileContents) { 
        $key =~ s/^\s+|\s+$//g;
        #Ignore comments and blank lines
        next if ($key =~ m/^#/) ;
        next if ($key =~ m/^\n/);
        next if ($key eq "");

        if($key =~ m/endm/){
           last if(1 == $ConfigDetailStart);
        }
        if($ConfigDetailStart){
            # Split the current line if there are more than one element present
            # on the single line
            my @data = split("=>",$key);
            $data[0] =~ s/\s*//g;
            $data[1] =~ s/\s*//g if ($data[1] ne "");
            $ConfigVarListing{$data[0]} = $data[1] ; 

        } # end of ConfigDetailStart

        if($key =~ m/config\_details\_${ValidConfig}/){
            $ConfigDetailStart = 1;
            next;
        }
    }

    # Check for the _TMTGTCPUTYPE to determine whether the 
    # configuration is valid or not.If valid CPUTYPE is not set then 
    # print message appropriately
    if($ConfigVarListing{_TMTGTCPUTYPE} !~ m/$ENV{_TMTGTCPUTYPE}/) {
        print "\nERROR: Invalid configuration class\n(Wrong value of _TMTGTCPUTYPE set)\n\n";
        $TotalErrorCount++;
    }
    else {
        print "\nThe configuration class is $ValidConfig \n\n";
    }

    if(!$ShowallOption){
  my $string = qq(---------------------------------------------------------------- 
$string2Display .....
---------------------------------------------------------------- \n);
        print $string;
    
        if(0 == $ConfigDetailStart){
            my $string = 
            qq (The configuration $ValidConfig does not require any additional configuration specific environment settings.
OR
The configuration values are not present in $AllEnvListingFile file.\n);
            print $string;
            $TotalErrorCount++;
        }
        else {

            PrintHash(\%ConfigVarListing);

            foreach my $key (sort keys %ConfigVarListing) {
                if (defined $ENV{$key} ){
                    # Check whether it matches for relevant values, if not print error message
                    # The path could be either a file or folder if there is no value associated for the key
                    if($ConfigVarListing{$key} eq ""){
                        if(!-e $ENV{$key}){
                            if($key =~ m/_TMBSL|_TMPSE/) {
                                print "WARNING: The path set for $key($ENV{$key}) is not valid.\n";
                                $TotalWarnCount++;
                            }
                            else {
                                print "ERROR: The path set for $key($ENV{$key}) is not valid.\n";
                                $TotalErrorCount++ ;
                            }
                        }
                    }
                    elsif($ConfigVarListing{$key} !~ m/$ENV{$key}/) {
                        if($key =~ m/_TMBSL|_TMPSE/) {
                            print "WARNING: Invalid value($ENV{$key}) set for $key. Valid values are $ConfigVarListing{$key}\n";
                            $TotalWarnCount++;
                        }
                        else{
                            print "ERROR: Invalid value($ENV{$key}) set for $key. Valid values are $ConfigVarListing{$key}\n";
                            $TotalErrorCount++;
                        }
                    }
                }
                else {
                    print "ERROR: $key is not defined\n";
                    $TotalErrorCount++;
                }
            } # end of foreach
        } # end of else ConfigDetailStart
    } #end of ShowallOption
}


#######################################################################
# Subroutine       :  GetConfigDetails                       
# Description      :  This subroutine is used to get the entire contents
#                  :  of config_details. Each config details are stored 
#                  :  in the variable 
#                  :                                                    
#########################################################################
sub GetConfigDetails{
    my ($FILEPOINTER,$currentLine) = @_;

    local $/;
    my $eachConfigDetails = $currentLine."\n".<$FILEPOINTER>;
    return $eachConfigDetails;   

}



#######################################################################
# Subroutine       :  GetAllSupportedConfgs                       
# Description      :  This subroutine is used to get all the configurations
#                  :  supported by SDE2. The configuration details are 
#                  :  stored in a hash
#                  :                                                    
#########################################################################
sub GetAllSupportedConfgs{
    my ($FILEPOINTER, $refHash) = @_;

    while(<$FILEPOINTER>){ 
        chomp; 
        #Ignore blank lines
        $_ =~ s/^\s+|\s+$//g;
        #Ignore comment lines   
        next if(/^#/ || /^\n/);
        last if(/endm/);
        next if(/^\s*$/);

        # Split the current line if there are more than one element present
        # on the single line
        
        my @data = split("=>",$_);
        my $arrayLength = scalar (@data);
        if ($arrayLength != $MaxVal4SupportedConfg ) {
            print "In-valid values specified in $AllEnvListingFile at line number $.\n";
            print "Provide correct information of all configurations supported by SDE2.\n";
            exit 1;
        }
        else {
            $data[0] =~ s/\s*//g; # cpuclass 
            $data[1] =~ s/\s*//g; # all possible os configurations
            $data[2] =~ s/\s*//g; # toolchain

            # Store the values in hash of hashes with cpuclass and toolchain as key
            # and all supported osclass names as key value
            # hash{cpuclass}{toolchain} = all supported osclass names
            $$refHash{$data[0]}{$data[2]} = $data[1];
        }
    } # end of while stmt

}




#######################################################################
# Subroutine       :  GetVarsFromFile                       
# Description      :  This subroutine is used to get the variables defined 
#                  :  defined from the start to the endm occurrence.  The 
#                  :  data will be stored in the hash passed.
#                  :                                                    
#########################################################################
sub GetVarsFromFile{
    my ($FILEPOINTER, $refHash) = @_;

    while(<$FILEPOINTER>){ 
        chomp; 
        #Ignore blank lines
        $_ =~ s/^\s+|\s+$//g;
        #Ignore comment lines   
        next if(/^#/ || /^\n/);
        last if(/endm/);

        # Split the current line if there are more than one element present
        my @data = split("=>",$_);
        my $arrayLength = scalar (@data);
        if($arrayLength == 1){
            $data[0] =~ s/\s*//g; # The variable name
            $$refHash{$data[0]} = 1;
        }
        else {
            $data[0] =~ s/\s*//g; # The variable name
            $data[1] =~ s/\s*//g; # The possible values for the variable
            $$refHash{$data[0]} = $data[1];
        
        }

    } # end of while stmt
    
}

########################################################################
# Subroutine       :  CheckForUnHandledCommandOption                       
# Description      :  This subroutine checks for unhandled commandline options
#                  :                                                    
#########################################################################
sub CheckForUnHandledCommandOption{
   my $option = $_[0];
   if($option =~ m/^\-comp\:/){
      my ($switch, $value) = (split(":",$_[0]))[0,1];
      $value =~ s#\\#\/#g;
      if ($value eq "") {
        print  "Wrong use of parameters. Specify component name after -comp:\n";
        DisplayUsage();
        exit 1;
      }
      else {
       push @CompOptionNames, $value;
      }
   }
   else{
       print  "Unkown parameter \"$_[0]\"  used in command line\n";
       DisplayUsage();
       exit 1;
   }
 
}

########################################################################
# Subroutine       :  DisplayUsage                                        
# Description      :  This subroutine gives the usage of script
#                  :                                                    
#########################################################################

sub DisplayUsage{
   my $string = qq (\nAuto detection script for checking environment and component makefile variables.
\nUsage : \n\t[perl] $0 -env | -comp:<component name> | -comp <component name> | -comp:all |-comp all [-h] [-showall] 
------------------------------------------------------------------------------------------------------------------
\n\t-env   : Check for only the environment Variables.
\t-comp <component name> | -comp:<component name> : Checks for only the component makefile variables of component specified in <component name>. 
\t\t\tAll component names should start with comps directory. 
\t\t\tEg: auto_det.pl -comp:comps/tmComp1
\t-comp all: Checks for all components specified in loc_list.mk file
\t-showall : Displays all messages which explain the script execution
\t-h       : Prints Help/Usage information
\n------------------------------------------------------------------------------------------------------------------
       \n);

   print $string;

}

#############End of Script
