sbsv1_os/e32toolp/e32util/fixsource.bat
changeset 0 83f4b4db085c
child 1 d4b442d23379
equal deleted inserted replaced
-1:000000000000 0:83f4b4db085c
       
     1 @rem
       
     2 @rem Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 @rem All rights reserved.
       
     4 @rem This component and the accompanying materials are made available
       
     5 @rem under the terms of "Eclipse Public License v1.0"
       
     6 @rem which accompanies this distribution, and is available
       
     7 @rem at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 @rem
       
     9 @rem Initial Contributors:
       
    10 @rem Nokia Corporation - initial contribution.
       
    11 @rem
       
    12 @rem Contributors:
       
    13 @rem
       
    14 @rem Description:
       
    15 @rem
       
    16 @rem = '--*-Perl-*--
       
    17 @echo off
       
    18 if "%OS%" == "Windows_NT" goto WinNT
       
    19 perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
       
    20 goto endofperl
       
    21 :WinNT
       
    22 perl -x -S "%0" %*
       
    23 if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
       
    24 if %errorlevel% == 9009 echo You do not have Perl in your PATH.
       
    25 goto endofperl
       
    26 @rem ';
       
    27 #!perl
       
    28 #line 14
       
    29 
       
    30 
       
    31 use strict;
       
    32 use Getopt::Long;
       
    33 use File::Spec;
       
    34 use File::Copy;
       
    35 use File::Path;
       
    36 use File::Basename;
       
    37 
       
    38 my $toolVersion = "2.1";
       
    39 
       
    40 # Example warnings:
       
    41 #
       
    42 # Incorrect slash
       
    43 #	\src\common\generic\comms-infras\commsfw\group\bld.inf:10: Incorrect slash in PRJ_EXPORTS - '..\inc\commschan.h'.
       
    44 #	\src\cedar\generic\base\f32\group\ecomp.mmp:14: Incorrect slash in SYSTEMINCLUDE - '..\inc'.
       
    45 #	\src\common\generic\syncml\framework\TransportProvision\HttpWsp\SmlHttpBase.cpp:13: Incorrect slash in #include - 'http\rhttpheaders.h'.
       
    46 #
       
    47 # Incorrect case for epoc32 tree
       
    48 #	\src\common\generic\syslibs\pwrcli\group\bld.inf:23: Incorrect case for epoc32 tree in PRJ_EXPORTS - '\epoc32\rom\include\PwrCli.IBY'.
       
    49 #	\src\common\generic\security\crypto\group\hash.mmp:8: Incorrect case for epoc32 tree in TARGET - 'hash.DLL'.
       
    50 #	\src\common\generic\syslibs\ecom\ongoing\Framework\frame\Discoverer.cpp:20: Incorrect case for epoc32 tree in #include - 'BaSPI.h'.
       
    51 #
       
    52 # Incorrect case versus filesystem
       
    53 #	\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.
       
    54 #	\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.
       
    55 #	\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.
       
    56 #
       
    57 # Incorrect case for epoc32 tree from default export (i.e. source export case will replicated under \epoc32)
       
    58 #	\src\common\generic\application-protocols\http\group\bld.inf:22: Incorrect case for epoc32 tree from default export in PRJ_EXPORTS - '..\inc\HTTPSocketConstants.h'.
       
    59 #	\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.
       
    60 #
       
    61 # Incorrect case versus exclusion list
       
    62 #	\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.
       
    63 #	\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.
       
    64 #
       
    65 # Can't find physical file match for
       
    66 #	\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.
       
    67 #
       
    68 
       
    69 
       
    70 # 1. Check arguments, output help etc.
       
    71 
       
    72 my $analyse = 0;
       
    73 my $list = 0;
       
    74 my $update = 0;
       
    75 my $warnings = "";
       
    76 my $verbose = 0;
       
    77 my $debug = 0;
       
    78 my $debugUpdate = 0;
       
    79 GetOptions ('analyse|a' => \$analyse, 'list|l' => \$list, 'update|u' => \$update, 'warnings|w=s' => \$warnings,
       
    80 			'verbose|v' => \$verbose, 'debug|d' => \$debug, 'debugupdate|du' => \$debugUpdate);
       
    81 
       
    82 if (@ARGV == 0)
       
    83 	{
       
    84 	print (STDERR "\nFIXSOURCE.BAT - Version $toolVersion\n");
       
    85 
       
    86 	print STDERR << 'END_OF_HELP';
       
    87 
       
    88 Usage: fixsource.bat -analyse|-list|-update|-warnings buildlog_1.log [buildlog_n.log] 
       
    89 
       
    90 Parses the output from the specified build logs to locate warnings produced via
       
    91 "abld -checksource".  Provides the option to update source automatically to comply
       
    92 with Symbian's Filename Policy.
       
    93 
       
    94 -analyse | -a	             List and describe all warnings that cannot be addressed
       
    95                              by this tool.
       
    96 -list    | -l	             List all source files that can be updated by this tool
       
    97                              using "-update".
       
    98 -update  | -u	             Update source files, as output by "-list", to comply with
       
    99                              Symbian's Filename Policy.
       
   100 -warnings| -w [all|fixable]  Output all unique "-checksource" warnings present in the
       
   101                              specified logs:
       
   102                                 all     - every warning, regardless of whether this
       
   103                                           tool can fix them.
       
   104                                 fixable - only warnings that this tool can fix.
       
   105 -verbose | -v                Additional verbose output for the "-update" option.
       
   106 
       
   107 NOTES:
       
   108 * The tool assumes that the original build source and layout is present on the drive
       
   109   where it is being executed.
       
   110 * With the exception of the "-warnings all" output, any warnings for files under the
       
   111   known release and build locations of %EPOCROOT%epoc32\include and
       
   112   %EPOCROOT%epoc32\build are discarded by default.
       
   113 
       
   114 END_OF_HELP
       
   115 
       
   116 	}
       
   117 
       
   118 
       
   119 # 2. Parse the logs storing all GNU format warnings and errors
       
   120 
       
   121 
       
   122 my %ActionableFilenamePolicyWarnings;	# Hash Key (filename)
       
   123 										#	Hash Key (line number)
       
   124 										#		Hash Key (problematic text)
       
   125 										#			Hash Key ORIGINAL_WARNINGS
       
   126 										#				Hash Key (original warning)
       
   127 										#					1
       
   128 										#			Hash Key ITEM
       
   129 										#				item type that has generated the warning
       
   130 										#			Hash Key SEARCH_TEXT
       
   131 										#				quotemeta version of problematic text
       
   132 										#			Hash Key UNIX_SLASH
       
   133 										#				1
       
   134 										#			Hash Key LOWERCASE
       
   135 										#				1
       
   136 										#			Hash Key PHYSICAL
       
   137 										#				1
       
   138 										#			Hash Key EXCLUSION
       
   139 										#				1
       
   140 										#			Hash Key PHYSICAL_REALITY
       
   141 										#				Hash Key (physical reality)
       
   142 										#					1
       
   143 										#				fully pathed filesystem reality used in physical checking
       
   144 										#			Hash Key EXCLUSION_LISTING
       
   145 										#				required format of reference as dictated from an exclusion list
       
   146 										#			Hash Key ACTUAL_TEST
       
   147 										#				test used for check when this differed from that in actual source
       
   148 										#			Hash Key DEFAULT_EXPORT
       
   149 										#				special case - a PRJ_EXPORTS line without a destination will break
       
   150 										#				the filename policy if the source line is not lowercase
       
   151 my %NonActionableFilenamePolicyWarnings;
       
   152 my %AllFilenamePolicyWarnings;
       
   153 my %OtherWarningsAndErrors;
       
   154 
       
   155 foreach my $BUILD_LOG (@ARGV)
       
   156 	{
       
   157 	open BUILD_LOG, "< $BUILD_LOG" or die "\nCannot read \"$BUILD_LOG\"!\n\n";
       
   158 
       
   159 	while (<BUILD_LOG>)
       
   160 		{
       
   161 		chomp;
       
   162 			
       
   163 		if (/^\\\S+:.*: .+$/)
       
   164 			{
       
   165 			if (!/:\d+: (Incorrect case|Incorrect slash|Can\'t find) /)
       
   166 				{
       
   167 				$OtherWarningsAndErrors{$_} = 1 if (!/(unresolved api-item|unknown base class|unresolved xref|no image file|xm-replace_text)/);	# Ignore the noise of doc stuff...
       
   168 				next;					
       
   169 				}
       
   170 
       
   171 			$AllFilenamePolicyWarnings{$_} = 1;
       
   172 			
       
   173 			if (/: Can\'t find /)
       
   174 				{
       
   175 				$NonActionableFilenamePolicyWarnings{$_} = 1;
       
   176 				next;
       
   177 				}
       
   178 
       
   179 			my $originalWarning = $_;
       
   180 
       
   181 			/(^.*):(\d+): Incorrect (case for epoc32 tree|case versus filesystem|case versus exclusion list|slash|case for epoc32 tree from default export) in (.+) - \'(.+?)\'/;
       
   182 
       
   183 			my $filename = $1;
       
   184 			my $lineNumber = $2;
       
   185 			my $type = $3;
       
   186 			my $item = $4;
       
   187 			my $problematicText = $5;
       
   188 
       
   189 			$type =~ s/case for epoc32 tree from default export/defaultexport/;
       
   190 			$type =~ s/case for epoc32 tree/lowercase/;
       
   191 			$type =~ s/case versus filesystem/physical/;
       
   192 			$type =~ s/case versus exclusion list/exclusion/;
       
   193 
       
   194 			my $actualTest = "";
       
   195 			my $physicalReality = "";
       
   196 			my $exclusionListing = "";
       
   197 			$actualTest = $1 if (/\(actual test \'(.*)\'\)/);
       
   198 
       
   199 			if (/ vs\. (.*)\./)
       
   200 				{
       
   201 				$physicalReality = $1 if ($type eq "physical");
       
   202 				$exclusionListing = $1 if ($type eq "exclusion");
       
   203 				}
       
   204 
       
   205 			if ($debug)
       
   206 				{
       
   207 				print ("ORIGINAL WARNING   : $originalWarning\n");
       
   208 				print ("FILENAME           : $filename\n");
       
   209 				print ("LINENUMBER         : $lineNumber\n");
       
   210 				print ("TYPE               : $type\n");
       
   211 				print ("ITEM               : $item\n");
       
   212 				print ("PROBLEMATIC TEXT   : $problematicText\n");
       
   213 				print ("ACTUAL TEST        : $actualTest\n") if ($actualTest);
       
   214 				print ("PHYSICAL REALITY   : $physicalReality\n") if ($physicalReality);
       
   215 				print ("EXCLUSION LISTING  : $exclusionListing\n") if ($exclusionListing); 
       
   216 				print ("\n");
       
   217 				}
       
   218 
       
   219 			next if ($warnings =~ /all/i);
       
   220 
       
   221 	# Line Number
       
   222 
       
   223 			my $lineNumberHashRef;
       
   224 			if ($ActionableFilenamePolicyWarnings{$filename})
       
   225 				{
       
   226 				$lineNumberHashRef = $ActionableFilenamePolicyWarnings{$filename};
       
   227 				}
       
   228 			else
       
   229 				{
       
   230 				my %newHash;
       
   231 				$lineNumberHashRef = \%newHash;
       
   232 				$ActionableFilenamePolicyWarnings{$filename} = $lineNumberHashRef;
       
   233 				}
       
   234 
       
   235 	# Problematic Text
       
   236 
       
   237 			my $problematicTextHashRef;
       
   238 			if ($lineNumberHashRef->{$lineNumber})
       
   239 				{
       
   240 				$problematicTextHashRef = $lineNumberHashRef->{$lineNumber};
       
   241 				}
       
   242 			else
       
   243 				{
       
   244 				my %newHash;
       
   245 				$problematicTextHashRef = \%newHash;
       
   246 				$lineNumberHashRef->{$lineNumber} = $problematicTextHashRef;
       
   247 				}
       
   248 
       
   249 	# Attributes
       
   250 
       
   251 			my $attributesHashRef;
       
   252 			if ($problematicTextHashRef->{$problematicText})
       
   253 				{
       
   254 				$attributesHashRef = $problematicTextHashRef->{$problematicText};
       
   255 				}
       
   256 			else
       
   257 				{
       
   258 				my %newHash;
       
   259 				$attributesHashRef = \%newHash;
       
   260 				$problematicTextHashRef->{$problematicText} = $attributesHashRef;
       
   261 				}
       
   262 
       
   263 	# Attributes : Original Warnings
       
   264 
       
   265 			my $originalWarningsHashRef;
       
   266 			if ($attributesHashRef->{ORIGINAL_WARNINGS})
       
   267 				{
       
   268 				$originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   269 				}
       
   270 			else
       
   271 				{
       
   272 				my %newHash;
       
   273 				$originalWarningsHashRef = \%newHash;			
       
   274 				$attributesHashRef->{ORIGINAL_WARNINGS} = $originalWarningsHashRef;
       
   275 				}
       
   276 			$originalWarningsHashRef->{$originalWarning} = 1;
       
   277 
       
   278 	# Attributes : Item
       
   279 
       
   280 			$attributesHashRef->{ITEM} = $item;
       
   281 
       
   282 	# Attributes : Search Text
       
   283 
       
   284 			$attributesHashRef->{SEARCH_TEXT} = quotemeta ($problematicText);
       
   285 
       
   286 	# Attributes : Unix Slash
       
   287 
       
   288 			$attributesHashRef->{UNIX_SLASH} = 1 if ($type eq "slash");
       
   289 
       
   290 	# Attributes : Lowercase
       
   291 
       
   292 			$attributesHashRef->{LOWERCASE} = 1 if ($type eq "lowercase");
       
   293 
       
   294 	# Attributes : Physical
       
   295 
       
   296 			$attributesHashRef->{PHYSICAL} = 1 if ($type eq "physical");
       
   297 
       
   298 	# Attributes : Exclusion
       
   299 
       
   300 			$attributesHashRef->{EXCLUSION} = 1 if ($type eq "exclusion");
       
   301 
       
   302 	# Attributes : Physical Reality
       
   303 
       
   304 			my $physicalRealityHashRef;
       
   305 			if ($physicalReality)
       
   306 				{
       
   307 				if ($attributesHashRef->{PHYSICAL_REALITY})
       
   308 					{
       
   309 					$physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
       
   310 					}
       
   311 				else
       
   312 					{
       
   313 					my %newHash;
       
   314 					$physicalRealityHashRef = \%newHash;			
       
   315 					$attributesHashRef->{PHYSICAL_REALITY} = $physicalRealityHashRef;
       
   316 					}
       
   317 				$physicalRealityHashRef->{$physicalReality} = 1;
       
   318 				}
       
   319 
       
   320 	# Attributes : Actual Test
       
   321 
       
   322 			$attributesHashRef->{ACTUAL_TEST} = $actualTest if ($actualTest);
       
   323 
       
   324 	# Attributes : Exclusion Listing
       
   325 
       
   326 			$attributesHashRef->{EXCLUSION_LISTING} = $exclusionListing if ($exclusionListing);
       
   327 
       
   328 	# Attributes : Default Export
       
   329 
       
   330 			$attributesHashRef->{DEFAULT_EXPORT} = 1 if ($type eq "defaultexport");
       
   331 			}
       
   332 		}
       
   333 
       
   334 	close BUILD_LOG;
       
   335 	}
       
   336 
       
   337 
       
   338 # 3. Examine source and warnings and compile lists of files and warnings that we can/can't do anything about
       
   339 
       
   340 my %WarningsNotMatchingSource;
       
   341 my %WarningsWithMissingFiles;
       
   342 my %WarningsForBothLowercaseAndPhysicalOnSameReference;
       
   343 my %WarningsForMultiplePhysicalUpdates;
       
   344 
       
   345 
       
   346 if ($analyse || $list || $update || $debugUpdate || $warnings =~ /^fixable$/i)
       
   347 	{
       
   348 		
       
   349 	foreach my $SOURCE_FILE (sort keys %ActionableFilenamePolicyWarnings)
       
   350 		{
       
   351 			
       
   352 	# Discard anything in known release locations
       
   353 
       
   354 		if ($SOURCE_FILE =~ /\\epoc32\\(include|build)\\/i)
       
   355 			{
       
   356 			delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE});
       
   357 			next;
       
   358 			}
       
   359 
       
   360 		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$SOURCE_FILE};
       
   361 
       
   362 	# Discard warnings where source files cannot be found
       
   363 
       
   364 		if (!(open SOURCE_FILE, "< $SOURCE_FILE"))
       
   365 			{
       
   366 			foreach my $lineNumber (sort keys (%$lineNumbersHashRef))
       
   367 				{
       
   368 				my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
       
   369 
       
   370 				foreach my $problematicText (sort keys (%$problematicTextHashRef))
       
   371 					{
       
   372 					my $attributesHashRef = $problematicTextHashRef->{$problematicText};
       
   373 					my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   374 					
       
   375 					foreach my $originalWarning (keys (%$originalWarningsHashRef))
       
   376 						{
       
   377 						$WarningsWithMissingFiles{$originalWarning} = 1;
       
   378 						}					
       
   379 					}
       
   380 				}
       
   381 			delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE});
       
   382 			next;
       
   383 			}
       
   384 
       
   385 
       
   386 	# Identify and discard warnings where, for the same reference:
       
   387 	# (a) both lowercase and physical warnings are flagged and
       
   388 	# (b) multiple, different, filesystem matches have been found
       
   389 	# These will need to be resolved manually
       
   390 
       
   391 		foreach my $lineNumber (sort keys (%$lineNumbersHashRef))
       
   392 			{
       
   393 			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
       
   394 
       
   395 			foreach my $problematicText (sort keys (%$problematicTextHashRef))
       
   396 				{
       
   397 				my $attributesHashRef = $problematicTextHashRef->{$problematicText};
       
   398 				my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   399 
       
   400 				my $skipPhysicalUpdate = 0;
       
   401 				my $skipLowercaseUpdate = 0;
       
   402 				
       
   403 				if ($attributesHashRef->{LOWERCASE} && $attributesHashRef->{PHYSICAL})
       
   404 					{
       
   405 					$skipPhysicalUpdate = 1;
       
   406 					$skipLowercaseUpdate = 1;
       
   407 
       
   408 					foreach my $originalWarning (keys %{$originalWarningsHashRef})
       
   409 						{
       
   410 						next if ($originalWarning !~ /Incorrect case/);
       
   411 
       
   412 						$originalWarning =~ /\:(.*$)/;
       
   413 
       
   414 						my $lowercaseAndPhysicalWarningsHashRef;	
       
   415 						if ($WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE})
       
   416 							{
       
   417 							$lowercaseAndPhysicalWarningsHashRef = $WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE};
       
   418 							}
       
   419 						else
       
   420 							{
       
   421 							my %newHash;
       
   422 							$lowercaseAndPhysicalWarningsHashRef = \%newHash;			
       
   423 							$WarningsForBothLowercaseAndPhysicalOnSameReference{$SOURCE_FILE} = $lowercaseAndPhysicalWarningsHashRef;
       
   424 							}
       
   425 						$lowercaseAndPhysicalWarningsHashRef->{$1} = 1;						
       
   426 						}
       
   427 					}
       
   428 
       
   429 				my $physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
       
   430 
       
   431 				if ($physicalRealityHashRef && ((keys %{$physicalRealityHashRef}) > 1))
       
   432 					{						
       
   433 					my $physicalMatchCheck;
       
   434 					if ($attributesHashRef->{ACTUAL_TEST})
       
   435 						{
       
   436 						$physicalMatchCheck = $attributesHashRef->{ACTUAL_TEST};
       
   437 						}
       
   438 					else
       
   439 						{
       
   440 						$physicalMatchCheck = $problematicText;
       
   441 						$physicalMatchCheck =~ s/\.\.[\\|\/]//g;
       
   442 						$physicalMatchCheck =~ s/\.[\\|\/]//g;
       
   443 						}
       
   444 
       
   445 					$physicalMatchCheck =~ s/\\\\/\\/g;		
       
   446 					$physicalMatchCheck =~ s/\/\//\//g;
       
   447 					$physicalMatchCheck =~ s/\//\\/g;
       
   448 					$physicalMatchCheck = quotemeta($physicalMatchCheck);
       
   449 					$physicalMatchCheck =~ s/\\\*/\\w\+/g;			# * -> \w+
       
   450 					$physicalMatchCheck =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
       
   451 
       
   452 					my %normalisedPhysicalReferences;
       
   453 	
       
   454 					foreach my $physicalReality (keys %{$physicalRealityHashRef})
       
   455 						{
       
   456 						$physicalReality =~ /($physicalMatchCheck)$/i;
       
   457 						$normalisedPhysicalReferences{$1} = 1;
       
   458 						}
       
   459 
       
   460 					if ((keys (%normalisedPhysicalReferences)) > 1)
       
   461 						{
       
   462 						foreach my $originalWarning (keys %{$originalWarningsHashRef})
       
   463 							{
       
   464 							next if ($originalWarning !~ /Incorrect case versus/);
       
   465 
       
   466 							$originalWarning =~ /\:(.*$)/;
       
   467 
       
   468 							my $multiplePhysicalWarningsHashRef;	
       
   469 							if ($WarningsForMultiplePhysicalUpdates{$SOURCE_FILE})
       
   470 								{
       
   471 								$multiplePhysicalWarningsHashRef = $WarningsForMultiplePhysicalUpdates{$SOURCE_FILE};
       
   472 								}
       
   473 							else
       
   474 								{
       
   475 								my %newHash;
       
   476 								$multiplePhysicalWarningsHashRef = \%newHash;			
       
   477 								$WarningsForMultiplePhysicalUpdates{$SOURCE_FILE} = $multiplePhysicalWarningsHashRef;
       
   478 								}
       
   479 							$multiplePhysicalWarningsHashRef->{$1} = 1;
       
   480 							}
       
   481 						$skipPhysicalUpdate = 1;
       
   482 						}
       
   483 					}
       
   484 
       
   485 				$attributesHashRef->{LOWERCASE} = 0 if ($skipLowercaseUpdate);
       
   486 				$attributesHashRef->{PHYSICAL} = 0 if ($skipPhysicalUpdate);
       
   487 
       
   488 				if (!$attributesHashRef->{LOWERCASE} && !$attributesHashRef->{PHYSICAL} &&
       
   489 					!$attributesHashRef->{UNIX_SLASH} && !$attributesHashRef->{DEFAULT_EXPORT} &&
       
   490 					!$attributesHashRef->{EXCLUSION})
       
   491 					{
       
   492 					delete ($problematicTextHashRef->{$problematicText});
       
   493 					}
       
   494 				}
       
   495 
       
   496 			delete ($lineNumbersHashRef->{$lineNumber}) if (!scalar (keys %{$problematicTextHashRef}));
       
   497 			}
       
   498 
       
   499 		my $lineNumber = 0;
       
   500 
       
   501 		while (my $line = <SOURCE_FILE>)
       
   502 			{
       
   503 			$lineNumber++;
       
   504 
       
   505 			next if (!($lineNumbersHashRef->{$lineNumber}));
       
   506 
       
   507 			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
       
   508 
       
   509 			foreach my $text (keys %{$problematicTextHashRef})
       
   510 				{
       
   511 				my $attributesHashRef = $problematicTextHashRef->{$text};				
       
   512 
       
   513 				chomp ($line);
       
   514 
       
   515 				if ($line !~ /(\"|\<|^|\s){1}$attributesHashRef->{SEARCH_TEXT}/)
       
   516 					{
       
   517 					# Put warning(s) onto the failed list, as we can't find the required text
       
   518 					# in the source present on the machine
       
   519 						
       
   520 					my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   521 					foreach my $originalWarning (keys %{$originalWarningsHashRef})
       
   522 						{
       
   523 						$WarningsNotMatchingSource{$originalWarning} = $line;
       
   524 						}
       
   525 						
       
   526 					delete ($problematicTextHashRef->{$text});
       
   527 					}
       
   528 				}
       
   529 
       
   530 			delete ($lineNumbersHashRef->{$lineNumber}) if (!scalar (keys %{$problematicTextHashRef}));
       
   531 			}
       
   532 
       
   533 		delete ($ActionableFilenamePolicyWarnings{$SOURCE_FILE}) if (!scalar (keys %{$lineNumbersHashRef}));
       
   534 		close SOURCE_FILE;
       
   535 		}
       
   536 	}
       
   537 
       
   538 
       
   539 # 4. Provide -warnings [all|fixable] output
       
   540 
       
   541 if ($warnings =~ /^all$/i)
       
   542 	{
       
   543 	foreach my $warning (sort keys %AllFilenamePolicyWarnings)
       
   544 		{
       
   545 		print ("$warning\n");
       
   546 		}
       
   547 	}
       
   548 elsif ($warnings =~ /^fixable$/i)
       
   549 	{
       
   550 	my %fixableWarnings;
       
   551 		
       
   552 	foreach my $sourceFile (keys %ActionableFilenamePolicyWarnings)
       
   553 		{
       
   554 		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$sourceFile};
       
   555 		
       
   556 		foreach my $lineNumber (keys (%$lineNumbersHashRef))
       
   557 			{
       
   558 			my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
       
   559 
       
   560 			foreach my $text (keys %{$problematicTextHashRef})
       
   561 				{
       
   562 				my $attributesHashRef = $problematicTextHashRef->{$text};				
       
   563 				my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   564 
       
   565 				foreach my $originalWarning (keys %{$originalWarningsHashRef})
       
   566 					{						
       
   567 					$fixableWarnings{$originalWarning} = 1;
       
   568 					}
       
   569 				}
       
   570 			}
       
   571 		}
       
   572 
       
   573 	foreach my $fixableWarning (sort keys %fixableWarnings)
       
   574 		{
       
   575 		print ("$fixableWarning\n");
       
   576 		}		
       
   577 	}
       
   578 
       
   579 
       
   580 # 5. Provide -list output
       
   581 
       
   582 if ($list)
       
   583 	{
       
   584 	foreach my $sourceFile (sort keys %ActionableFilenamePolicyWarnings)
       
   585 		{
       
   586 		print ("$sourceFile\n");
       
   587 		}
       
   588 	}
       
   589 
       
   590 
       
   591 # 6. Provide -analyse output
       
   592 
       
   593 if ($analyse)
       
   594 	{
       
   595 	print ("\nFilename policy warnings with missing files\n".
       
   596 		     "-------------------------------------------\n\n");
       
   597 	foreach my $warningWithMissingFile (sort keys %WarningsWithMissingFiles)
       
   598 		{
       
   599 		print ("$warningWithMissingFile\n");
       
   600 		}
       
   601 	print ("NONE\n") if (!scalar (keys %WarningsWithMissingFiles));
       
   602 
       
   603 
       
   604 	print ("\n\nFilename policy warnings that don't match source\n".
       
   605 		       "------------------------------------------------\n\n");		
       
   606 	foreach my $warningNotMatchingSource (sort keys %WarningsNotMatchingSource)
       
   607 		{
       
   608 		print ("$warningNotMatchingSource\n");
       
   609 		print ("\tACTUAL LINE : \'$WarningsNotMatchingSource{$warningNotMatchingSource}\'\n");
       
   610 		}
       
   611 	print ("NONE\n") if (!scalar (keys %WarningsNotMatchingSource));
       
   612 
       
   613 	print ("\n\nFilename policy warnings with both lowercase and physical warnings for the same reference\n".
       
   614 		       "-----------------------------------------------------------------------------------------\n\n");		
       
   615 	foreach my $sourceFile (sort keys %WarningsForBothLowercaseAndPhysicalOnSameReference)
       
   616 		{
       
   617 		print ("$sourceFile\n");
       
   618 		foreach my $warning (sort keys %{$WarningsForBothLowercaseAndPhysicalOnSameReference{$sourceFile}})
       
   619 			{
       
   620 			print ("\t$warning\n");
       
   621 			}
       
   622 		}
       
   623 	print ("NONE\n") if (!scalar (keys %WarningsForBothLowercaseAndPhysicalOnSameReference));
       
   624 
       
   625 	print ("\n\nMultiple differing physical filename policy warnings for the same reference\n".
       
   626 		       "---------------------------------------------------------------------------\n\n");		
       
   627 	foreach my $sourceFile (sort keys %WarningsForMultiplePhysicalUpdates)
       
   628 		{
       
   629 		print ("$sourceFile\n");
       
   630 		foreach my $warning (sort keys %{$WarningsForMultiplePhysicalUpdates{$sourceFile}})
       
   631 			{
       
   632 			print ("\t$warning\n");
       
   633 			}
       
   634 		}
       
   635 	print ("NONE\n") if (!scalar (keys %WarningsForMultiplePhysicalUpdates));
       
   636 
       
   637 	print ("\n\nNon-actionable filename policy warnings\n".
       
   638 		     "---------------------------------------\n\n");		
       
   639 	foreach my $nonActionableWarning (sort keys %NonActionableFilenamePolicyWarnings)
       
   640 		{
       
   641 		print ("$nonActionableWarning\n");
       
   642 		}
       
   643 	print ("NONE\n") if (!scalar (keys %NonActionableFilenamePolicyWarnings));
       
   644 
       
   645 
       
   646 	print ("\n\nOther detected warnings unrelated to filename policy\n".
       
   647 		     "----------------------------------------------------\n\n");		
       
   648 	foreach my $otherWarningOrError (sort keys %OtherWarningsAndErrors)
       
   649 		{
       
   650 		print ("$otherWarningOrError\n");
       
   651 		}
       
   652 	print ("NONE\n") if (!scalar (keys %OtherWarningsAndErrors));
       
   653 
       
   654 	print ("\n\n");
       
   655 	}
       
   656 
       
   657 
       
   658 # 7. Perform -update function
       
   659 
       
   660 if ($update || $debugUpdate)
       
   661 	{
       
   662 	foreach my $SOURCE_FILE (sort keys %ActionableFilenamePolicyWarnings)
       
   663 		{
       
   664 		if (!(open SOURCE_FILE, "< $SOURCE_FILE"))
       
   665 			{				
       
   666 			print ("ERROR: Could not open $SOURCE_FILE to read.\n");
       
   667 			next;
       
   668 			}
       
   669 
       
   670 		print ("Updating \'$SOURCE_FILE\'...\n") unless ($debugUpdate);
       
   671 
       
   672 		my $lineNumbersHashRef = $ActionableFilenamePolicyWarnings{$SOURCE_FILE};
       
   673 		my $lineNumber = 0;
       
   674 		my @newSourceFile;
       
   675 
       
   676 		while (my $line = <SOURCE_FILE>)
       
   677 			{
       
   678 			$lineNumber++;
       
   679 
       
   680 			if ($lineNumbersHashRef->{$lineNumber})
       
   681 				{				
       
   682 				print ("\tOriginal : $line") if ($verbose);
       
   683 					
       
   684 				my $problematicTextHashRef = $lineNumbersHashRef->{$lineNumber};
       
   685 
       
   686 				# We need to order the updates on a per-line basis so that, for example,
       
   687 				# a search and update for 'nkern\arm\' occurs after one for 'include\nkern\arm\nk_plat.h'
       
   688 				# We can do this by length, making sure the longest updates are performed first
       
   689 				my @problematicTextOrderedHashKeys = sort {length $b <=> length $a} (keys %{$problematicTextHashRef});
       
   690 
       
   691 				foreach my $problematicText (@problematicTextOrderedHashKeys)
       
   692 					{
       
   693 					my $attributesHashRef = $problematicTextHashRef->{$problematicText};
       
   694 					my $revisedText = $problematicText;
       
   695 
       
   696 		# Physical
       
   697 
       
   698 					if ($attributesHashRef->{PHYSICAL})
       
   699 						{
       
   700 						my $physicalRealityHashRef = $attributesHashRef->{PHYSICAL_REALITY};
       
   701 
       
   702 						my $physicalReality = (keys %{$physicalRealityHashRef})[0];
       
   703 						my $physicalRealityUnixSlash = $physicalReality;
       
   704 						$physicalRealityUnixSlash =~ s/\\/\//g;						
       
   705 							
       
   706 						if ($physicalReality =~ /($attributesHashRef->{SEARCH_TEXT})$/i ||
       
   707 							$physicalRealityUnixSlash =~ /($attributesHashRef->{SEARCH_TEXT})$/i)
       
   708 							{
       
   709 							# Simple case - direct match with just case and slash differences
       
   710 							my $replacement = $1;
       
   711 							$replacement =~ s/\\/\//g;
       
   712 							$revisedText =~ s/$attributesHashRef->{SEARCH_TEXT}/$replacement/;
       
   713 							}
       
   714 						else
       
   715 							{
       
   716 							# What we're looking at in the source file doesn't map directly
       
   717 							# to what's physically on the file system.
       
   718 
       
   719 							my $modifiedSearchText = $problematicText;
       
   720 							$modifiedSearchText =~ s/\.\.[\\|\/]//g;
       
   721 							$modifiedSearchText =~ s/\.[\\|\/]//g;
       
   722 
       
   723 							my $physicalMatchCheck;
       
   724 							if ($attributesHashRef->{ACTUAL_TEST})
       
   725 								{
       
   726 								$physicalMatchCheck = $attributesHashRef->{ACTUAL_TEST};
       
   727 								}
       
   728 							else
       
   729 								{
       
   730 								$physicalMatchCheck = $modifiedSearchText;
       
   731 								}
       
   732 
       
   733 							# The physical match check needs to remove double-slashing...
       
   734 							$physicalMatchCheck =~ s/\\\\/\\/g;		
       
   735 							$physicalMatchCheck =~ s/\/\//\//g;
       
   736 							
       
   737 							$modifiedSearchText = quotemeta($modifiedSearchText);
       
   738 							$physicalMatchCheck = quotemeta($physicalMatchCheck);
       
   739 
       
   740 							$physicalMatchCheck =~ s/\\\*/\\w\+/g;			# * -> \w+
       
   741 							$physicalMatchCheck =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
       
   742 
       
   743 							if ($physicalReality =~ /($physicalMatchCheck)$/i ||
       
   744 								$physicalRealityUnixSlash =~ /($physicalMatchCheck)$/i )
       
   745 								{
       
   746 								my $replacement = $1;
       
   747 								$replacement =~ s/\\/\//g;
       
   748 								
       
   749 								if ($attributesHashRef->{ACTUAL_TEST} &&
       
   750 									($attributesHashRef->{ITEM} =~ /MMP$/ || $attributesHashRef->{ITEM} =~ /DEFFILE/))
       
   751 									{
       
   752 									# Both DEFFILE and PRJ_[TEST]MMPFILE entries may be specifed without extension
       
   753 									$replacement =~ s/\.\w+$// if ($problematicText !~ /\.\w+$/);
       
   754 
       
   755 									# DEFFILE entries may have eabi\bwins in the physical match and had a "u" inserted or appended 
       
   756 									if ($attributesHashRef->{ITEM} =~ /DEFFILE/ && $replacement !~ /$modifiedSearchText$/i)
       
   757 										{
       
   758 										$replacement =~ s/(eabi|bwins)\//~\//i if ($problematicText =~ /~[\\|\/]/);
       
   759 										$replacement =~ s/u(\.\w+)?$/$1/i if ($attributesHashRef->{ITEM} !~ /NOSTRICTDEF/);
       
   760 										}
       
   761 									}
       
   762 
       
   763 								$revisedText =~ s/$modifiedSearchText/$replacement/;
       
   764 								}
       
   765 							else
       
   766 								{
       
   767 								print ("ERROR: Can\'t perform physical consistency updates for:");
       
   768 								
       
   769 								my $originalWarningsHashRef = $attributesHashRef->{ORIGINAL_WARNINGS};
       
   770 								foreach my $originalWarning (keys %{$originalWarningsHashRef})
       
   771 									{
       
   772 									print ("\t$originalWarning") if ($originalWarning =~ /case versus/);
       
   773 									}
       
   774 
       
   775 								print ("\n");
       
   776 								}
       
   777 							}
       
   778 						}
       
   779 
       
   780 		# Exclusion
       
   781 
       
   782 					if ($attributesHashRef->{EXCLUSION})
       
   783 						{
       
   784 						my $exclusionListingSearch = quotemeta($attributesHashRef->{EXCLUSION_LISTING});						
       
   785 						$revisedText =~ s/$exclusionListingSearch/$attributesHashRef->{EXCLUSION_LISTING}/i;
       
   786 						}						
       
   787 
       
   788 		# Slash
       
   789 					if ($attributesHashRef->{UNIX_SLASH})
       
   790 						{
       
   791 						$revisedText =~ s/\\/\//g;
       
   792 						$revisedText =~ s/\/\//\//g;		# Don't allow replacements that lead to "//" in paths
       
   793 						}
       
   794 
       
   795 		# Lowercase
       
   796 
       
   797 					if ($attributesHashRef->{LOWERCASE})
       
   798 						{
       
   799 						$revisedText = lc ($revisedText);
       
   800 						}
       
   801 
       
   802 		# Default Export
       
   803 
       
   804 					if ($attributesHashRef->{DEFAULT_EXPORT})
       
   805 						{
       
   806 						my $exportedFilename = lc (basename ($problematicText));							
       
   807 						$revisedText .= " \/epoc32\/include\/".$exportedFilename;
       
   808 						}
       
   809 
       
   810 					$line =~ s/(\"|\<|^|\s){1}$attributesHashRef->{SEARCH_TEXT}/$1$revisedText/;
       
   811 					}
       
   812 
       
   813 				print ("\tUpdated  : $line") if ($verbose);
       
   814 				}
       
   815 				
       
   816 			push @newSourceFile, $line;
       
   817 			}
       
   818 
       
   819 		close SOURCE_FILE;
       
   820 
       
   821 		if ($debugUpdate)
       
   822 			{
       
   823 			# Don't touch the original source, but create two trees for easy comparison
       
   824 				
       
   825 			my $baseDir = dirname ($SOURCE_FILE);				
       
   826 			mkpath ("\\compare\\orig".$baseDir);
       
   827 			mkpath ("\\compare\\updated".$baseDir);
       
   828 			print ("Copying  \'\\compare\\orig".$SOURCE_FILE."\'...\n");
       
   829 			copy ($SOURCE_FILE, "\\compare\\orig".$SOURCE_FILE);
       
   830 			$SOURCE_FILE = "\\compare\\updated".$SOURCE_FILE;
       
   831 			print ("Updating \'$SOURCE_FILE\'...\n");
       
   832 			}
       
   833 
       
   834 		if (!(open SOURCE_FILE, "> $SOURCE_FILE"))
       
   835 			{				
       
   836 			print ("ERROR: Could not open $SOURCE_FILE to write.\n");
       
   837 			next;
       
   838 			}
       
   839 
       
   840 		foreach my $line (@newSourceFile)
       
   841 			{
       
   842 			print (SOURCE_FILE $line);
       
   843 			}
       
   844 
       
   845 		close SOURCE_FILE;
       
   846 		}
       
   847 
       
   848 	print ("\n") if ($verbose);
       
   849 	}
       
   850 
       
   851 __END__
       
   852 
       
   853 :endofperl