# Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
# Front-end to routines checking that source matches filename policy constraints
# 
#

use FindBin;
use Cwd;
use Getopt::Long qw(:config posix_default);		#permits "+" in arguments, rather than as an option identifier
use lib $FindBin::Bin;
use CheckSource;
use Pathutl;

my $preprocessCall = "cpp.exe -w -undef -nostdinc -+ -dI";

my $verbose = 0;

my $preprocess = 0;
my $parsefile = 0;
my $metadata = 0;

GetOptions ('preprocess|pp' => \$preprocess, 'parsefile|pf' => \$parsefile, 'metadata|md' => \$metadata);

my %warnings;

$verbose = 1 if $ENV{CHECKSOURCE_VERBOSE};


if (!@ARGV)
	{
	print ("\nchecksource.pl --preprocess|--parsefile|--metadata args\n\n");
	}
elsif ($preprocess)
	{
	my $PREPROCESSPIPE;
	open PREPROCESSPIPE,"$preprocessCall @ARGV |" or die "ERROR: Can't invoke preprocessor for checksource processing.\n";

	my %processedIncludes;
	
	my %homelessInclude;
	$homelessInclude{REFERENCE} = "";

	my $lineNumber = 0;
	my $currentFile = "";

	print "Preprocessing file    : ".$ARGV[scalar(@ARGV)-1]."\n" if ($verbose);

	while (<PREPROCESSPIPE>)
		{
		if (/^\s*$/o)
			{
			$lineNumber++;
			next;
			}	
		elsif (/^# (\d+) "(.*)"( \d+)?/o)
			{
			$lineNumber = scalar $1;
			$currentFile=$2;
			$currentFile=~s-\\\\-\\-go;
			$currentFile=~s-\\\/-\\-go;
			$currentFile=~s-\/\\-\\-go;
			$currentFile=~s-\/\/-\\-go;
			$currentFile=~s/\//\\/g;
			$currentFile=~s/^\w://;
			}

		if ($homelessInclude{REFERENCE})
			{
			# Resolve #include references using "locating" comments in CPP output.  These may either follow the reference directly,
			# or may have appeared earlier in prior CPP processing
			if ($currentFile =~ /$homelessInclude{SEARCH}$/i)
				{
				CheckSource_Physical (%warnings, $homelessInclude{SOURCEFILE}, "#include", $homelessInclude{REFERENCE}, $homelessInclude{LINENUMBER}, $currentFile, $verbose);
				$processedIncludes{lc($currentFile)} = 1;
				}
			else
				{
				my @foundProcessedIncludes;
				foreach my $processedInclude (keys %processedIncludes)
					{
					push @foundProcessedIncludes, $processedInclude if ($processedInclude =~ /$homelessInclude{SEARCH}$/i);
					}
		
				if (@foundProcessedIncludes == 1)
					{
					CheckSource_Physical  (%warnings, $homelessInclude{SOURCEFILE}, "#include", $homelessInclude{REFERENCE}, $homelessInclude{LINENUMBER}, $foundProcessedIncludes[0], $verbose);
					}
				elsif ((@foundProcessedIncludes > 1) && $verbose)
					{
					print ("WARNING: Multiple matches for #include reference $homelessInclude{REFERENCE} : $homelessInclude{SOURCEFILE}($homelessInclude{LINENUMBER})\n");
					print "\t$_\n" foreach (@foundProcessedIncludes);
					}
				elsif ($verbose)
					{
					print ("WARNING: Couldn't find #include reference $homelessInclude{REFERENCE} : $homelessInclude{SOURCEFILE}($homelessInclude{LINENUMBER})\n");
					}
				}
			$homelessInclude{REFERENCE} = "";
			}

		if (/^\s*#include\s*[\"|\<]{1}(.*)[\"|\>]{1}/)
			{
			CheckSource_UnixSlash (%warnings, $currentFile, "#include", $1, $lineNumber, $verbose);

			$homelessInclude{SOURCEFILE} = $currentFile;
			$homelessInclude{REFERENCE} = $1;
			$homelessInclude{LINENUMBER} = $lineNumber;
			$homelessInclude{SEARCH} = "\\".$homelessInclude{REFERENCE};
			$homelessInclude{SEARCH} =~ s/\//\\/g;
			$homelessInclude{SEARCH} = quotemeta($homelessInclude{SEARCH});
			}

		$lineNumber++ if (!/^# (\d+) "(.*)"( \d+)?/o);
		}

	close PREPROCESSPIPE;
	}
elsif ($parsefile)
	{
	my $SOURCE_FILE = $ARGV[0];		
	open SOURCE_FILE, "< $SOURCE_FILE" or die "ERROR: Can't open $SOURCE_FILE for \"-checksource\".\n";

	print "Parsing include file  : $SOURCE_FILE\n" if ($verbose);

	my $lineNumber = 0;
	
	while (<SOURCE_FILE>)
		{
		$lineNumber++;

		if (/^\s*#include\s*[\"|\<]{1}(.*)[\"|\>]{1}/)
			{
			CheckSource_UnixSlash (%warnings, $SOURCE_FILE, "#include", $1, $lineNumber, $verbose);
			CheckSource_Lowercase (%warnings, $SOURCE_FILE, "#include", $1, $lineNumber, $verbose);
			}		
		}

	close SOURCE_FILE;
	}
elsif ($metadata)
	{
	my ($sourcefile, $item, $reference, $linenumber, $physical, $offset) = @ARGV;

	$physical = 0 if (!$physical);
	$offset = undef if (!$offset);

	CheckSource_UnixSlash (%warnings, $sourcefile, $item, $reference, $linenumber, $verbose);

	if ($physical)
		{
		CheckSource_Physical (%warnings, $sourcefile, $item, $reference, $linenumber, $offset, $verbose);
		}
	else
		{
		CheckSource_Lowercase (%warnings, $sourcefile, $item, $reference, $linenumber, $verbose);
		}
	}

print "$_\n" foreach (keys %warnings);
