sbsv1/abld/e32util/fixsource.bat
changeset 599 fa7a3cc6effd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv1/abld/e32util/fixsource.bat	Fri Jun 25 17:29:25 2010 +0800
@@ -0,0 +1,852 @@
+@rem
+@rem Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+@rem All rights reserved.
+@rem This component and the accompanying materials are made available
+@rem under the terms of "Eclipse Public License v1.0"
+@rem which accompanies this distribution, and is available
+@rem at the URL "http://www.eclipse.org/legal/epl-v10.html".
+@rem
+@rem Initial Contributors:
+@rem Nokia Corporation - initial contribution.
+@rem
+@rem Contributors:
+@rem
+@rem Description:
+@rem
+@rem = '--*-Perl-*--
+@echo off
+if "%OS%" == "Windows_NT" goto WinNT
+perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
+goto endofperl
+:WinNT
+perl -x -S "%0" %*
+if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
+if %errorlevel% == 9009 echo You do not have Perl in your PATH.
+goto endofperl
+@rem ';
+#!perl
+#line 14
+
+
+use Getopt::Long;
+use File::Spec;
+use File::Copy;
+use File::Path;
+use File::Basename;
+
+my $toolVersion = "2.1";
+
+# Example warnings:
+#
+# Incorrect slash
+#	\src\common\generic\comms-infras\commsfw\group\bld.inf:10: Incorrect slash in PRJ_EXPORTS - '..\inc\commschan.h'.
+#	\src\cedar\generic\base\f32\group\ecomp.mmp:14: Incorrect slash in SYSTEMINCLUDE - '..\inc'.
+#	\src\common\generic\syncml\framework\TransportProvision\HttpWsp\SmlHttpBase.cpp:13: Incorrect slash in #include - 'http\rhttpheaders.h'.
+#
+# Incorrect case for epoc32 tree
+#	\src\common\generic\syslibs\pwrcli\group\bld.inf:23: Incorrect case for epoc32 tree in PRJ_EXPORTS - '\epoc32\rom\include\PwrCli.IBY'.
+#	\src\common\generic\security\crypto\group\hash.mmp:8: Incorrect case for epoc32 tree in TARGET - 'hash.DLL'.
+#	\src\common\generic\syslibs\ecom\ongoing\Framework\frame\Discoverer.cpp:20: Incorrect case for epoc32 tree in #include - 'BaSPI.h'.
+#
+# Incorrect case versus filesystem
+#	\src\common\generic\comms-infras\commdb\commdbshim\group\BLD.INF:20: Incorrect case versus filesystem in PRJ_EXPORTS - '..\inc\cdblen.h' vs. \src\common\generic\comms-infras\commdb\commdbshim\INC\CDBLEN.H.
+#	\src\common\generic\syslibs\ecom\ongoing\Framework\MMPFiles\EComServer.mmp:45: Incorrect case versus filesystem in USERINCLUDE - '..\..\framework\inc' vs. \src\common\generic\syslibs\ecom\ongoing\Framework\inc.
+#	\src\common\generic\comms-infras\commdb\commdbshim\INC\CDBOVER.H:16: Incorrect case versus filesystem in #include - 'cdbpreftable.h' vs. \src\common\generic\comms-infras\commdb\commdbshim\INC\CDBPREFTABLE.H.
+#
+# Incorrect case for epoc32 tree from default export (i.e. source export case will replicated under \epoc32)
+#	\src\common\generic\application-protocols\http\group\bld.inf:22: Incorrect case for epoc32 tree from default export in PRJ_EXPORTS - '..\inc\HTTPSocketConstants.h'.
+#	\src\common\generic\messaging\email\smtpservermtm\group\bld.inf:11: Incorrect case for epoc32 tree from default export in PRJ_EXPORTS - '..\inc\smts.h' vs. \src\common\generic\messaging\email\smtpservermtm\inc\SMTS.H.
+#
+# Incorrect case versus exclusion list
+#	\src\common\generic\Multimedia\openmax\group\bld.inf:14: Incorrect case versus exclusion list in PRJ_EXPORTS - '\epoc32\include\openmax\il\OMX_Types.h' vs. OMX_TYPES.H.
+#	\src\common\generic\Multimedia\openmax\inc\openmax\il\OMX_Audio.h:41: Incorrect case versus exclusion list in #include - 'OMX_Types.h' vs. OMX_TYPES.H.
+#
+# Can't find physical file match for
+#	\src\common\generic\app-framework\conarc\group\BLD.INF:48: Can't find physical file match for PRJ_TESTMMPFILES MMP - '..\tsrc\tcon3_V2.mpp' on filesystem.
+#
+
+
+# 1. Check arguments, output help etc.
+
+my $analyse = 0;
+my $list = 0;
+my $update = 0;
+my $warnings = "";
+my $verbose = 0;
+my $debug = 0;
+my $debugUpdate = 0;
+GetOptions ('analyse|a' => \$analyse, 'list|l' => \$list, 'update|u' => \$update, 'warnings|w=s' => \$warnings,
+			'verbose|v' => \$verbose, 'debug|d' => \$debug, 'debugupdate|du' => \$debugUpdate);
+
+if (@ARGV == 0)
+	{
+	print (STDERR "\nFIXSOURCE.BAT - Version $toolVersion\n");
+
+	print STDERR << 'END_OF_HELP';
+
+Usage: fixsource.bat -analyse|-list|-update|-warnings buildlog_1.log [buildlog_n.log] 
+
+Parses the output from the specified build logs to locate warnings produced via
+"abld -checksource".  Provides the option to update source automatically to comply
+with Symbian's Filename Policy.
+
+-analyse | -a	             List and describe all warnings that cannot be addressed
+                             by this tool.
+-list    | -l	             List all source files that can be updated by this tool
+                             using "-update".
+-update  | -u	             Update source files, as output by "-list", to comply with
+                             Symbian's Filename Policy.
+-warnings| -w [all|fixable]  Output all unique "-checksource" warnings present in the
+                             specified logs:
+                                all     - every warning, regardless of whether this
+                                          tool can fix them.
+                                fixable - only warnings that this tool can fix.
+-verbose | -v                Additional verbose output for the "-update" option.
+
+NOTES:
+* The tool assumes that the original build source and layout is present on the drive
+  where it is being executed.
+* With the exception of the "-warnings all" output, any warnings for files under the
+  known release and build locations of %EPOCROOT%epoc32\include and
+  %EPOCROOT%epoc32\build are discarded by default.
+
+END_OF_HELP
+
+	}
+
+
+# 2. Parse the logs storing all GNU format warnings and errors
+
+
+my %ActionableFilenamePolicyWarnings;	# Hash Key (filename)
+										#	Hash Key (line number)
+										#		Hash Key (problematic text)
+										#			Hash Key ORIGINAL_WARNINGS
+										#				Hash Key (original warning)
+										#					1
+										#			Hash Key ITEM
+										#				item type that has generated the warning
+										#			Hash Key SEARCH_TEXT
+										#				quotemeta version of problematic text
+										#			Hash Key UNIX_SLASH
+										#				1
+										#			Hash Key LOWERCASE
+										#				1
+										#			Hash Key PHYSICAL
+										#				1
+										#			Hash Key EXCLUSION
+										#				1
+										#			Hash Key PHYSICAL_REALITY
+										#				Hash Key (physical reality)
+										#					1
+										#				fully pathed filesystem reality used in physical checking
+										#			Hash Key EXCLUSION_LISTING
+										#				required format of reference as dictated from an exclusion list
+										#			Hash Key ACTUAL_TEST
+										#				test used for check when this differed from that in actual source
+										#			Hash Key DEFAULT_EXPORT
+										#				special case - a PRJ_EXPORTS line without a destination will break
+										#				the filename policy if the source line is not lowercase
+my %NonActionableFilenamePolicyWarnings;
+my %AllFilenamePolicyWarnings;
+my %OtherWarningsAndErrors;
+
+foreach my $BUILD_LOG (@ARGV)
+	{
+	open BUILD_LOG, "< $BUILD_LOG" or die "\nCannot read \"$BUILD_LOG\"!\n\n";
+
+	while (<BUILD_LOG>)
+		{
+		chomp;
+			
+		if (/^\\\S+:.*: .+$/)
+			{
+			if (!/:\d+: (Incorrect case|Incorrect slash|Can\'t find) /)
+				{
+				$OtherWarningsAndErrors{$_} = 1 if (!/(unresolved api-item|unknown base class|unresolved xref|no image file|xm-replace_text)/);	# Ignore the noise of doc stuff...
+				next;					
+				}
+
+			$AllFilenamePolicyWarnings{$_} = 1;
+			
+			if (/: Can\'t find /)
+				{
+				$NonActionableFilenamePolicyWarnings{$_} = 1;
+				next;
+				}
+
+			my $originalWarning = $_;
+
+			/(^.*):(\d+): Incorrect (case for epoc32 tree|case versus filesystem|case versus exclusion list|slash|case for epoc32 tree from default export) in (.+) - \'(.+?)\'/;
+
+			my $filename = $1;
+			my $lineNumber = $2;
+			my $type = $3;
+			my $item = $4;
+			my $problematicText = $5;
+
+			$type =~ s/case for epoc32 tree from default export/defaultexport/;
+			$type =~ s/case for epoc32 tree/lowercase/;
+			$type =~ s/case versus filesystem/physical/;
+			$type =~ s/case versus exclusion list/exclusion/;
+
+			my $actualTest = "";
+			my $physicalReality = "";
+			my $exclusionListing = "";
+			$actualTest = $1 if (/\(actual test \'(.*)\'\)/);
+
+			if (/ vs\. (.*)\./)
+				{
+				$physicalReality = $1 if ($type eq "physical");
+				$exclusionListing = $1 if ($type eq "exclusion");
+				}
+
+			if ($debug)
+				{
+				print ("ORIGINAL WARNING   : $originalWarning\n");
+				print ("FILENAME           : $filename\n");
+				print ("LINENUMBER         : $lineNumber\n");
+				print ("TYPE               : $type\n");
+				print ("ITEM               : $item\n");
+				print ("PROBLEMATIC TEXT   : $problematicText\n");
+				print ("ACTUAL TEST        : $actualTest\n") if ($actualTest);
+				print ("PHYSICAL REALITY   : $physicalReality\n") if ($physicalReality);
+				print ("EXCLUSION LISTING  : $exclusionListing\n") if ($exclusionListing); 
+				print ("\n");
+				}
+
+			next if ($warnings =~ /all/i);
+
+	# Line Number
+
+			my $lineNumberHashRef;
+			if ($ActionableFilenamePolicyWarnings{$filename})
+				{
+				$lineNumberHashRef = $ActionableFilenamePolicyWarnings{$filename};
+				}
+			else
+				{
+				my %newHash;
+				$lineNumberHashRef = \%newHash;
+				$ActionableFilenamePolicyWarnings{$filename} = $lineNumberHashRef;
+				}
+
+	# Problematic Text
+
+			my $problematicTextHashRef;
+			if ($lineNumberHashRef->{$lineNumber})
+				{
+				$problematicTextHashRef = $lineNumberHashRef->{$lineNumber};
+				}
+			else
+				{
+				my %newHash;
+				$problematicTextHashRef = \%newHash;
+				$lineNumberHashRef->{$lineNumber} = $problematicTextHashRef;
+				}
+
+	# Attributes
+
+			my $attributesHashRef;
+			if ($problematicTextHashRef->{$problematicText})
+				{
+				$attributesHashRef = $problematicTextHashRef->{$problematicText};
+				}
+			else
+				{
+				my %newHash;
+				$attributesHashRef = \%newHash;
+				$problematicTextHashRef->{$problematicText} = $attributesHashRef;
+				}
+
+	# Attributes : Original Warnings
+
+			my $originalWarningsHashRef;
+			if ($attributesHashRef->{ORIGINAL_WARNINGS})
+				{
+				$originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+				}
+			else
+				{
+				my %newHash;
+				$originalWarningsHashRef = \%newHash;			
+				$attributesHashRef->{ORIGINAL_WARNINGS} = $originalWarningsHashRef;
+				}
+			$originalWarningsHashRef->{$originalWarning} = 1;
+
+	# Attributes : Item
+
+			$attributesHashRef->{ITEM} = $item;
+
+	# Attributes : Search Text
+
+			$attributesHashRef->{SEARCH_TEXT} = quotemeta ($problematicText);
+
+	# Attributes : Unix Slash
+
+			$attributesHashRef->{UNIX_SLASH} = 1 if ($type eq "slash");
+
+	# Attributes : Lowercase
+
+			$attributesHashRef->{LOWERCASE} = 1 if ($type eq "lowercase");
+
+	# Attributes : Physical
+
+			$attributesHashRef->{PHYSICAL} = 1 if ($type eq "physical");
+
+	# Attributes : Exclusion
+
+			$attributesHashRef->{EXCLUSION} = 1 if ($type eq "exclusion");
+
+	# Attributes : Physical Reality
+
+			my $physicalRealityHashRef;
+			if ($physicalReality)
+				{
+				if ($attributesHashRef->{PHYSICAL_REALITY})
+					{
+					$physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
+					}
+				else
+					{
+					my %newHash;
+					$physicalRealityHashRef = \%newHash;			
+					$attributesHashRef->{PHYSICAL_REALITY} = $physicalRealityHashRef;
+					}
+				$physicalRealityHashRef->{$physicalReality} = 1;
+				}
+
+	# Attributes : Actual Test
+
+			$attributesHashRef->{ACTUAL_TEST} = $actualTest if ($actualTest);
+
+	# Attributes : Exclusion Listing
+
+			$attributesHashRef->{EXCLUSION_LISTING} = $exclusionListing if ($exclusionListing);
+
+	# Attributes : Default Export
+
+			$attributesHashRef->{DEFAULT_EXPORT} = 1 if ($type eq "defaultexport");
+			}
+		}
+
+	close BUILD_LOG;
+	}
+
+
+# 3. Examine source and warnings and compile lists of files and warnings that we can/can't do anything about
+
+my %WarningsNotMatchingSource;
+my %WarningsWithMissingFiles;
+my %WarningsForBothLowercaseAndPhysicalOnSameReference;
+my %WarningsForMultiplePhysicalUpdates;
+
+
+if ($analyse || $list || $update || $debugUpdate || $warnings =~ /^fixable$/i)
+	{
+		
+	foreach my $SOURCE_FILE (sort keys %ActionableFilenamePolicyWarnings)
+		{
+			
+	# Discard anything in known release locations
+
+		if ($SOURCE_FILE =~ /\\epoc32\\(include|build)\\/i)
+			{
+			delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE});
+			next;
+			}
+
+		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$SOURCE_FILE};
+
+	# Discard warnings where source files cannot be found
+
+		if (!(open SOURCE_FILE, "< $SOURCE_FILE"))
+			{
+			foreach my $lineNumber (sort keys (%$lineNumbersHashRef))
+				{
+				my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
+
+				foreach my $problematicText (sort keys (%$problematicTextHashRef))
+					{
+					my $attributesHashRef = $problematicTextHashRef->{$problematicText};
+					my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+					
+					foreach my $originalWarning (keys (%$originalWarningsHashRef))
+						{
+						$WarningsWithMissingFiles{$originalWarning} = 1;
+						}					
+					}
+				}
+			delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE});
+			next;
+			}
+
+
+	# Identify and discard warnings where, for the same reference:
+	# (a) both lowercase and physical warnings are flagged and
+	# (b) multiple, different, filesystem matches have been found
+	# These will need to be resolved manually
+
+		foreach my $lineNumber (sort keys (%$lineNumbersHashRef))
+			{
+			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
+
+			foreach my $problematicText (sort keys (%$problematicTextHashRef))
+				{
+				my $attributesHashRef = $problematicTextHashRef->{$problematicText};
+				my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+
+				my $skipPhysicalUpdate = 0;
+				my $skipLowercaseUpdate = 0;
+				
+				if ($attributesHashRef->{LOWERCASE} && $attributesHashRef->{PHYSICAL})
+					{
+					$skipPhysicalUpdate = 1;
+					$skipLowercaseUpdate = 1;
+
+					foreach my $originalWarning (keys %{$originalWarningsHashRef})
+						{
+						next if ($originalWarning !~ /Incorrect case/);
+
+						$originalWarning =~ /\:(.*$)/;
+
+						my $lowercaseAndPhysicalWarningsHashRef;	
+						if ($WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE})
+							{
+							$lowercaseAndPhysicalWarningsHashRef = $WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE};
+							}
+						else
+							{
+							my %newHash;
+							$lowercaseAndPhysicalWarningsHashRef = \%newHash;			
+							$WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE} = $lowercaseAndPhysicalWarningsHashRef;
+							}
+						$lowercaseAndPhysicalWarningsHashRef->{$1} = 1;						
+						}
+					}
+
+				my $physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
+
+				if ($physicalRealityHashRef && ((keys %{$physicalRealityHashRef}) > 1))
+					{						
+					my $physicalMatchCheck;
+					if ($attributesHashRef->{ACTUAL_TEST})
+						{
+						$physicalMatchCheck = $attributesHashRef->{ACTUAL_TEST};
+						}
+					else
+						{
+						$physicalMatchCheck = $problematicText;
+						$physicalMatchCheck =~ s/\.\.[\\|\/]//g;
+						$physicalMatchCheck =~ s/\.[\\|\/]//g;
+						}
+
+					$physicalMatchCheck =~ s/\\\\/\\/g;		
+					$physicalMatchCheck =~ s/\/\//\//g;
+					$physicalMatchCheck =~ s/\//\\/g;
+					$physicalMatchCheck = quotemeta($physicalMatchCheck);
+					$physicalMatchCheck =~ s/\\\*/\\w\+/g;			# * -> \w+
+					$physicalMatchCheck =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
+
+					my %normalisedPhysicalReferences;
+	
+					foreach my $physicalReality (keys %{$physicalRealityHashRef})
+						{
+						$physicalReality =~ /($physicalMatchCheck)$/i;
+						$normalisedPhysicalReferences{$1} = 1;
+						}
+
+					if ((keys (%normalisedPhysicalReferences)) > 1)
+						{
+						foreach my $originalWarning (keys %{$originalWarningsHashRef})
+							{
+							next if ($originalWarning !~ /Incorrect case versus/);
+
+							$originalWarning =~ /\:(.*$)/;
+
+							my $multiplePhysicalWarningsHashRef;	
+							if ($WarningsForMultiplePhysicalUpdates{$SOURCE_FILE})
+								{
+								$multiplePhysicalWarningsHashRef = $WarningsForMultiplePhysicalUpdates{$SOURCE_FILE};
+								}
+							else
+								{
+								my %newHash;
+								$multiplePhysicalWarningsHashRef = \%newHash;			
+								$WarningsForMultiplePhysicalUpdates{$SOURCE_FILE} = $multiplePhysicalWarningsHashRef;
+								}
+							$multiplePhysicalWarningsHashRef->{$1} = 1;
+							}
+						$skipPhysicalUpdate = 1;
+						}
+					}
+
+				$attributesHashRef->{LOWERCASE} = 0 if ($skipLowercaseUpdate);
+				$attributesHashRef->{PHYSICAL} = 0 if ($skipPhysicalUpdate);
+
+				if (!$attributesHashRef->{LOWERCASE} && !$attributesHashRef->{PHYSICAL} &&
+					!$attributesHashRef->{UNIX_SLASH} && !$attributesHashRef->{DEFAULT_EXPORT} &&
+					!$attributesHashRef->{EXCLUSION})
+					{
+					delete ($problematicTextHashRef->{$problematicText});
+					}
+				}
+
+			delete ($lineNumbersHashRef->{$lineNumber}) if (!scalar (keys %{$problematicTextHashRef}));
+			}
+
+		my $lineNumber = 0;
+
+		while (my $line = <SOURCE_FILE>)
+			{
+			$lineNumber++;
+
+			next if (!($lineNumbersHashRef->{$lineNumber}));
+
+			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
+
+			foreach my $text (keys %{$problematicTextHashRef})
+				{
+				my $attributesHashRef = $problematicTextHashRef->{$text};				
+
+				chomp ($line);
+
+				if ($line !~ /(\"|\<|^|\s){1}$attributesHashRef->{SEARCH_TEXT}/)
+					{
+					# Put warning(s) onto the failed list, as we can't find the required text
+					# in the source present on the machine
+						
+					my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+					foreach my $originalWarning (keys %{$originalWarningsHashRef})
+						{
+						$WarningsNotMatchingSource{$originalWarning} = $line;
+						}
+						
+					delete ($problematicTextHashRef->{$text});
+					}
+				}
+
+			delete ($lineNumbersHashRef->{$lineNumber}) if (!scalar (keys %{$problematicTextHashRef}));
+			}
+
+		delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE}) if (!scalar (keys %{$lineNumbersHashRef}));
+		close SOURCE_FILE;
+		}
+	}
+
+
+# 4. Provide -warnings [all|fixable] output
+
+if ($warnings =~ /^all$/i)
+	{
+	foreach my $warning (sort keys %AllFilenamePolicyWarnings)
+		{
+		print ("$warning\n");
+		}
+	}
+elsif ($warnings =~ /^fixable$/i)
+	{
+	my %fixableWarnings;
+		
+	foreach my $sourceFile (keys %ActionableFilenamePolicyWarnings)
+		{
+		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$sourceFile};
+		
+		foreach my $lineNumber (keys (%$lineNumbersHashRef))
+			{
+			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
+
+			foreach my $text (keys %{$problematicTextHashRef})
+				{
+				my $attributesHashRef = $problematicTextHashRef->{$text};				
+				my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+
+				foreach my $originalWarning (keys %{$originalWarningsHashRef})
+					{						
+					$fixableWarnings{$originalWarning} = 1;
+					}
+				}
+			}
+		}
+
+	foreach my $fixableWarning (sort keys %fixableWarnings)
+		{
+		print ("$fixableWarning\n");
+		}		
+	}
+
+
+# 5. Provide -list output
+
+if ($list)
+	{
+	foreach my $sourceFile (sort keys %ActionableFilenamePolicyWarnings)
+		{
+		print ("$sourceFile\n");
+		}
+	}
+
+
+# 6. Provide -analyse output
+
+if ($analyse)
+	{
+	print ("\nFilename policy warnings with missing files\n".
+		     "-------------------------------------------\n\n");
+	foreach my $warningWithMissingFile (sort keys %WarningsWithMissingFiles)
+		{
+		print ("$warningWithMissingFile\n");
+		}
+	print ("NONE\n") if (!scalar (keys %WarningsWithMissingFiles));
+
+
+	print ("\n\nFilename policy warnings that don't match source\n".
+		       "------------------------------------------------\n\n");		
+	foreach my $warningNotMatchingSource (sort keys %WarningsNotMatchingSource)
+		{
+		print ("$warningNotMatchingSource\n");
+		print ("\tACTUAL LINE : \'$WarningsNotMatchingSource{$warningNotMatchingSource}\'\n");
+		}
+	print ("NONE\n") if (!scalar (keys %WarningsNotMatchingSource));
+
+	print ("\n\nFilename policy warnings with both lowercase and physical warnings for the same reference\n".
+		       "-----------------------------------------------------------------------------------------\n\n");		
+	foreach my $sourceFile (sort keys %WarningsForBothLowercaseAndPhysicalOnSameReference)
+		{
+		print ("$sourceFile\n");
+		foreach my $warning (sort keys %{$WarningsForBothLowercaseAndPhysicalOnSameReference{$sourceFile}})
+			{
+			print ("\t$warning\n");
+			}
+		}
+	print ("NONE\n") if (!scalar (keys %WarningsForBothLowercaseAndPhysicalOnSameReference));
+
+	print ("\n\nMultiple differing physical filename policy warnings for the same reference\n".
+		       "---------------------------------------------------------------------------\n\n");		
+	foreach my $sourceFile (sort keys %WarningsForMultiplePhysicalUpdates)
+		{
+		print ("$sourceFile\n");
+		foreach my $warning (sort keys %{$WarningsForMultiplePhysicalUpdates{$sourceFile}})
+			{
+			print ("\t$warning\n");
+			}
+		}
+	print ("NONE\n") if (!scalar (keys %WarningsForMultiplePhysicalUpdates));
+
+	print ("\n\nNon-actionable filename policy warnings\n".
+		     "---------------------------------------\n\n");		
+	foreach my $nonActionableWarning (sort keys %NonActionableFilenamePolicyWarnings)
+		{
+		print ("$nonActionableWarning\n");
+		}
+	print ("NONE\n") if (!scalar (keys %NonActionableFilenamePolicyWarnings));
+
+
+	print ("\n\nOther detected warnings unrelated to filename policy\n".
+		     "----------------------------------------------------\n\n");		
+	foreach my $otherWarningOrError (sort keys %OtherWarningsAndErrors)
+		{
+		print ("$otherWarningOrError\n");
+		}
+	print ("NONE\n") if (!scalar (keys %OtherWarningsAndErrors));
+
+	print ("\n\n");
+	}
+
+
+# 7. Perform -update function
+
+if ($update || $debugUpdate)
+	{
+	foreach my $SOURCE_FILE (sort keys %ActionableFilenamePolicyWarnings)
+		{
+		if (!(open SOURCE_FILE, "< $SOURCE_FILE"))
+			{				
+			print ("ERROR: Could not open $SOURCE_FILE to read.\n");
+			next;
+			}
+
+		print ("Updating \'$SOURCE_FILE\'...\n") unless ($debugUpdate);
+
+		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$SOURCE_FILE};
+		my $lineNumber = 0;
+		my @newSourceFile;
+
+		while (my $line = <SOURCE_FILE>)
+			{
+			$lineNumber++;
+
+			if ($lineNumbersHashRef->{$lineNumber})
+				{				
+				print ("\tOriginal : $line") if ($verbose);
+					
+				my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
+
+				# We need to order the updates on a per-line basis so that, for example,
+				# a search and update for 'nkern\arm\' occurs after one for 'include\nkern\arm\nk_plat.h'
+				# We can do this by length, making sure the longest updates are performed first
+				my @problematicTextOrderedHashKeys = sort {length $b <=> length $a} (keys %{$problematicTextHashRef});
+
+				foreach my $problematicText (@problematicTextOrderedHashKeys)
+					{
+					my $attributesHashRef = $problematicTextHashRef->{$problematicText};
+					my $revisedText = $problematicText;
+
+		# Physical
+
+					if ($attributesHashRef->{PHYSICAL})
+						{
+						my $physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
+
+						my $physicalReality = (keys %{$physicalRealityHashRef})[0];
+						my $physicalRealityUnixSlash = $physicalReality;
+						$physicalRealityUnixSlash =~ s/\\/\//g;						
+							
+						if ($physicalReality =~ /($attributesHashRef->{SEARCH_TEXT})$/i ||
+							$physicalRealityUnixSlash =~ /($attributesHashRef->{SEARCH_TEXT})$/i)
+							{
+							# Simple case - direct match with just case and slash differences
+							my $replacement = $1;
+							$replacement =~ s/\\/\//g;
+							$revisedText =~ s/$attributesHashRef->{SEARCH_TEXT}/$replacement/;
+							}
+						else
+							{
+							# What we're looking at in the source file doesn't map directly
+							# to what's physically on the file system.
+
+							my $modifiedSearchText = $problematicText;
+							$modifiedSearchText =~ s/\.\.[\\|\/]//g;
+							$modifiedSearchText =~ s/\.[\\|\/]//g;
+
+							my $physicalMatchCheck;
+							if ($attributesHashRef->{ACTUAL_TEST})
+								{
+								$physicalMatchCheck = $attributesHashRef->{ACTUAL_TEST};
+								}
+							else
+								{
+								$physicalMatchCheck = $modifiedSearchText;
+								}
+
+							# The physical match check needs to remove double-slashing...
+							$physicalMatchCheck =~ s/\\\\/\\/g;		
+							$physicalMatchCheck =~ s/\/\//\//g;
+							
+							$modifiedSearchText = quotemeta($modifiedSearchText);
+							$physicalMatchCheck = quotemeta($physicalMatchCheck);
+
+							$physicalMatchCheck =~ s/\\\*/\\w\+/g;			# * -> \w+
+							$physicalMatchCheck =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
+
+							if ($physicalReality =~ /($physicalMatchCheck)$/i ||
+								$physicalRealityUnixSlash =~ /($physicalMatchCheck)$/i )
+								{
+								my $replacement = $1;
+								$replacement =~ s/\\/\//g;
+								
+								if ($attributesHashRef->{ACTUAL_TEST} &&
+									($attributesHashRef->{ITEM} =~ /MMP$/ || $attributesHashRef->{ITEM} =~ /DEFFILE/))
+									{
+									# Both DEFFILE and PRJ_[TEST]MMPFILE entries may be specifed without extension
+									$replacement =~ s/\.\w+$// if ($problematicText !~ /\.\w+$/);
+
+									# DEFFILE entries may have eabi\bwins in the physical match and had a "u" inserted or appended 
+									if ($attributesHashRef->{ITEM} =~ /DEFFILE/ && $replacement !~ /$modifiedSearchText$/i)
+										{
+										$replacement =~ s/(eabi|bwins)\//~\//i if ($problematicText =~ /~[\\|\/]/);
+										$replacement =~ s/u(\.\w+)?$/$1/i if ($attributesHashRef->{ITEM} !~ /NOSTRICTDEF/);
+										}
+									}
+
+								$revisedText =~ s/$modifiedSearchText/$replacement/;
+								}
+							else
+								{
+								print ("ERROR: Can\'t perform physical consistency updates for:");
+								
+								my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
+								foreach my $originalWarning (keys %{$originalWarningsHashRef})
+									{
+									print ("\t$originalWarning") if ($originalWarning =~ /case versus/);
+									}
+
+								print ("\n");
+								}
+							}
+						}
+
+		# Exclusion
+
+					if ($attributesHashRef->{EXCLUSION})
+						{
+						my $exclusionListingSearch = quotemeta($attributesHashRef->{EXCLUSION_LISTING});						
+						$revisedText =~ s/$exclusionListingSearch/$attributesHashRef->{EXCLUSION_LISTING}/i;
+						}						
+
+		# Slash
+					if ($attributesHashRef->{UNIX_SLASH})
+						{
+						$revisedText =~ s/\\/\//g;
+						$revisedText =~ s/\/\//\//g;		# Don't allow replacements that lead to "//" in paths
+						}
+
+		# Lowercase
+
+					if ($attributesHashRef->{LOWERCASE})
+						{
+						$revisedText = lc ($revisedText);
+						}
+
+		# Default Export
+
+					if ($attributesHashRef->{DEFAULT_EXPORT})
+						{
+						my $exportedFilename = lc (basename ($problematicText));							
+						$revisedText .= " \/epoc32\/include\/".$exportedFilename;
+						}
+
+					$line =~ s/(\"|\<|^|\s){1}$attributesHashRef->{SEARCH_TEXT}/$1$revisedText/;
+					}
+
+				print ("\tUpdated  : $line") if ($verbose);
+				}
+				
+			push @newSourceFile, $line;
+			}
+
+		close SOURCE_FILE;
+
+		if ($debugUpdate)
+			{
+			# Don't touch the original source, but create two trees for easy comparison
+				
+			my $baseDir = dirname ($SOURCE_FILE);				
+			mkpath ("\\compare\\orig".$baseDir);
+			mkpath ("\\compare\\updated".$baseDir);
+			print ("Copying  \'\\compare\\orig".$SOURCE_FILE."\'...\n");
+			copy ($SOURCE_FILE, "\\compare\\orig".$SOURCE_FILE);
+			$SOURCE_FILE = "\\compare\\updated".$SOURCE_FILE;
+			print ("Updating \'$SOURCE_FILE\'...\n");
+			}
+
+		if (!(open SOURCE_FILE, "> $SOURCE_FILE"))
+			{				
+			print ("ERROR: Could not open $SOURCE_FILE to write.\n");
+			next;
+			}
+
+		foreach my $line (@newSourceFile)
+			{
+			print (SOURCE_FILE $line);
+			}
+
+		close SOURCE_FILE;
+		}
+
+	print ("\n") if ($verbose);
+	}
+
+__END__
+
+:endofperl