--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bldsystemtools/commonbldutils/SFUpdateLicenceHeader.pl Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,2634 @@
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# This component and the accompanying materials are made available
+# under the terms of the License "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: Replace S60 header with Symbian Foundation license header.
+# Output file (results) is compatibe for SFMakeLxrLinks.pl as input.
+#
+use strict;
+use File::Find;
+use File::Basename;
+use Getopt::Long;
+use IO::Handle;
+use FindBin qw($Bin);
+use FileHandle;
+
+####################
+# Constants
+####################
+
+# Tool version
+use constant VERSION => '2.1';
+# Version history: 0.8 Added copyright year pick-up
+# Version history: 0.9- Bug fixesg
+# Version history: 0.95- EPL header support added
+# Version history: 0.96 Minor script adjustments
+# Version history: 0.97 Assembly files (.s, .cia, .asm) checked as well
+# Version history: 0.98 Support for -oem added. Also @file tag removed from template
+# Version history: 0.99 Testing -oem option
+# Version history: 1.0 Comment column added for PostProcess script
+# Version history: 1.01 Modify option bug fixed
+# Version history: 1.1 Description bug fixed
+# Version history: 1.2 Digia copyrights moved to SF as well. Also R/O attribute removed only for files modified
+# Version history: 1.3 Distribution policy files handled as well. With -create also created
+# Version history: 1.31 Fixes to distribution file handling (only non-empty directories acknowledged)
+# Version history: 1.32 .pm files checked as well
+# Version history: 1.4 Bug fixes and "ignorefile" agrument added
+# Version history: 1.41 Bug fix in Description pick-up
+# Version history: 1.42 Bug fix in -ignore option (also missing .s60 file creation need to be ignored). Default value set to ignore option
+# Version history: 1.43 Description statistics fixed, .hpp added, description pick-up improved
+# Version history: 1.5 -verify option implemented, ignorefile default value extended, statistics go to log
+# Version history: 1.51 Copyright year pick-up bug fixed, ignorefilepattern comparison case-insensitive
+# Version history: 1.52 current s60 dumped to result
+# Version history: 1.53 abld.bat added ti ignorefile default
+# Version history: 1.54 -verify statistics improved
+# Version history: 1.55 -eula option added
+# Version history: 1.56 .mmh files added, extra Non-Nokia check added for "No Copyright" case for weired headers
+# Version history: 1.57 Changes to -verify
+# Version history: 1.58 @echo on ... @echo off added to .cmd and .bat headers
+# Version history: 1.59 EPL warning log entry --> info
+# Version history: 1.60 and 1.61 -ignorelist option added
+# Version history: 1.62 Uppercase REM text allowed
+# Version history: 1.63 Internal directory check added to -verify
+# Version history: 1.64 Symbian --> Symbian.*Ltd in $ExternalToNokiaCopyrPattern
+# Version history: 1.65 Bug fixed in normalizeCppComment
+# Version history: 1.70 Changes to better cope with ex-Symbian sources,
+# Pasi's better "@rem" taken into use for .bat and .cmd files
+# Version history: 1.71 Config file support added (option -config) for non 3/7 IDs
+# Version history: 1.72 handleVerify checks improved to include also file start
+# Version history: 1.73 \b added to Copyright word to reduce if "wrong" alarms
+# Version history: 1.74 incomplete copyright check added to -verify
+# Version history: 1.75 Support for ignoring generated headers (@sfGeneratedPatternArray) added
+# Version history: 1.76 .script extension added (using Cpp comments e.g. // Text)
+# Version history: 1.77 Reporting and logging improvements for wk19 checks (need to check / patch single files)
+# Version history: 1.80 Few Qt specific file extensions added, -lgpl option added,
+# C++ comment fix in handleOem
+# Version history: 1.90 checkNoMultipleLicenses function added, and call to handleVerify* added
+# Version history: 2.0 handleDistributionValue() changes IDs 0-->3/7 and 3-->7,
+# isGeneratedHeader() checks for file content added.
+# Version history: 2.01 checkPortionsCopyright implemented and applied
+# Version history: 2.02 Extra license word taken out from EPL header
+# Version history: 2.1 -verify -epl support added and switchLicense() tried first for SFL --> EPL switching
+
+my $IGNORE_MAN ='Ignore-manually';
+my $IGNORE ='Ignore';
+my $INTERNAL = 'internal';
+use constant KEEP_SYMBIAN => 0;
+use constant REMOVE_SYMBIAN => 1;
+
+
+#file extention list that headers should be replace
+my @extlist = ('.cpp', '.c', '.h', '.mmp', '.mmpi', '.rss', '.hrh', '.inl', '.inf', '.iby', '.oby',
+ '.loc', '.rh', '.ra', '.java', '.mk', '.bat', '.cmd', '.pkg', '.rls', '.rssi', '.pan', '.py', '.pl', '.s', '.asm', '.cia',
+ '.s60', '.pm', '.hpp', '.mmh', '.script',
+ '.pro', '.pri'); # Qt specific
+
+# Various header comment styles
+my @header_regexps =
+(
+'^\s*(\#.*?\n)*', # Perl, Python
+'^\s*(\@echo\s*off\s*\n)?\n*(@?(?i)rem.*?\n)*(\@echo\s*on\s*)?', # Windows command script
+'^\s*(\;.*?\n)*', # SIS package file
+'\s*\/\*[\n\s\*-=].*?\*\/', # C comment block
+'(\s*\/\/.*\n)+', # C++ comment block (do not use /s in regexp evaluation !!!)
+'^\s*((\/\/|\#).*?\n)*' # Script file comment
+);
+
+# Comment regular expression (Indeces within @header_regexps)
+use constant COMMENT_PERL => 0;
+use constant COMMENT_CMD => 1;
+use constant COMMENT_SIS_ASM => 2;
+use constant COMMENT_C => 3;
+use constant COMMENT_CPP => 4;
+use constant COMMENT_SCRIPT => 5;
+
+my $descrTemplateOnly = '\?Description';
+my $linenumtext = "1"; # Use this linenumer in LXR links
+
+# Copyright patterns
+my $copyrYearPattern = 'Copyright\b.*\d{4}\s*([,-]\s*\d{4})*';
+my $copyrYearPattern2 = '\d{4}(\s*[,-]\s*\d{4})*';
+use constant DEFCOPYRIGHTYEAR => "2009"; # For error cases
+
+my $NokiaCopyrPattern = '\bCopyright\b.*Nokia.*(All Rights)?';
+my $NonNokiaCopyrPattern = '\bCopyright\b.*(?!Nokia).*(All Rights)?';
+my $CopyrPattern = '\bCopyright\b';
+my $RemoveS60TextBlockPattern = 'This material.*Nokia';
+my $CC = 'CCHAR';
+my $BeginLicenseBlockPattern = 'BEGIN LICENSE BLOCK';
+my $OldNokiaPattern = 'Nokia\s*Corporation[\.\s]*\n';
+my $NewNokiaText = "Nokia Corporation and/or its subsidiary(-ies).\n"; # Used in substitu to text
+my $NewNokiaPattern = "Nokia Corporation and/or its subsidiary";
+my $OldNokiaPattern2 = "This material.*including documentation and any related.*protected by copyright controlled.*Nokia";
+my $PortionsNokiaCopyrPattern = 'Portions.*Copyright\b.*Nokia.*(All Rights)?';
+my $NewPortionsNokiaCopyrPattern = 'Portions\s*Copyright\b.*' . $NewNokiaPattern;
+
+# Move these copyrights to Nokia !!!
+my $ExternalToNokiaCopyrPattern = 'Copyright\b.*(Symbian\sLtd|Symbian\s*Software\s*Ltd|Digia|SysopenDigia).*(All\s+Rights|All\s+rights)?';
+my $PortionsSymbianCopyrPattern = 'Portions\s*Copyright\b.*(Symbian\sLtd|Symbian\s*Software\s*Ltd).*(All\s+Rights|All\s+rights)?';
+
+###############
+# SFL headers
+###############
+# SFL C/C++ style
+#
+my $SFLicenseHeader =
+'/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Symbi'.'an Foundation License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.symbi'.'anfoundation.org/legal/sf'.'l-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/'. "\n";
+
+# Test string to test header have been changed
+my $SFLHeaderTest = 'Symbian\s*Foundation\s*License.*www\.symbianfoundation\.org\/legal\/sfl';
+
+# Partial SFL header template (# will be replaced by actual comment syntax char)
+# Prepare for cases where someone adds spaces to string.
+my $SFLicenseHeaderPartial_template =
+$CC . '\s*This\s*component\s*and\s*the\s*accompanying\s*materials\s*are\s*made\s*available\s*\n' .
+$CC . '\s*under\s*the\s*terms\s*of\s*the\s*License\s*\"Symbian\s*Foundation\s*License\s*v1\.0\"\s*\n' .
+$CC . '\s*which\s*accompanies\s*this\s*distribution\,\s*and\s*is\s*available\s*\n' .
+$CC . '\s*at\s*the\s*URL\s*\"http\:\/\/www\.symbianfoundation\.org\/legal\/sfl\-v10\.html\"\s*\.';
+
+# SFL other comment styles (replace # with actual comment starter)
+#
+my $SFLicenseHeader_other_template =
+'#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Symbi'.'an Foundation License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.symbi','anfoundation.org/legal/sf'.'l-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+';
+
+
+
+###############
+# EPL headers
+###############
+# C/C++ style
+my $EPLLicenseHeader =
+'/*
+* Copyright (c) 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:
+*
+*/' . "\n";
+
+# Test string to test header have been changed
+my $EPLHeaderTest = 'Eclipse\s*Public\s*License.*www\.eclipse\.org\/legal\/epl';
+
+# Partial EPL header (replace # with actual comment starter)
+# Prepare for cases where someone adds spaces to string.
+my $EPLLicenseHeaderPartial_template =
+$CC . '\s*This\s*component\s*and\s*the\s*accompanying\s*materials\s*are\s*made\s*available\s*\n' .
+$CC . '\s*under\s*the\s*terms\s*of\s*\"Eclipse\s*Public\s*License\s*v1\.0\"\s*\n' .
+$CC . '\s*which\s*accompanies\s*this\s*distribution,\s*and\s*is\s*available\s*\n' .
+$CC . '\s*at\s*the\s*URL\s*\"http\:\/\/www\.eclipse\.org\/legal\/epl\-v10\.html\"\s*\.';
+
+
+# EPL other comment styles (replace # with comment starter)
+#
+my $EPLLicenseHeader_other_template =
+'#
+# Copyright (c) 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:
+#
+';
+
+##############
+# LGPL headers
+##############
+my $LGPLLicenseHeader =
+'/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, version 2.1 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program. If not,
+* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+*
+* Description:
+*
+*/';
+
+# Test string to test header have been changed
+my $LGPLHeaderTest = 'GNU\s*Lesser\s*General\s*Public\s*License.*www\.gnu\.org\/licenses/old-licenses\/lgpl-2\.1\.html';
+
+# Partial LGPL header (replace $CC with actual comment starter)
+my $LGPLLicenseHeaderPartial_template =
+$CC . '\s*This\s*program\s*is\s*free\s*software\:\s*you\s*can\s*redistribute\s*it\s*and\/or\s*modify\n' .
+$CC . '\s*it\s*under\s*the\s*terms\s*of\s*the\s*GNU\s*Lesser\s*General\s*Public\s*License\s*as\s*published\s*by\n' .
+$CC . '\s*the\s*Free\s*Software\s*Foundation\,\s*version\s*2\.1\s*of\s*the\s*License\n';
+
+
+# LGPL other comment styles (replace # with comment starter)
+#
+my $LGPLLicenseHeader_other_template =
+'#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, version 2.1 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not,
+# see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+#
+# Description:
+#
+';
+
+
+###############
+# S60 headers
+###############
+# C/C++ style
+my $S60HeaderPartial_template =
+$CC . " This material, including documentation and any related computer\n" .
+$CC . " programs, is protected by copyright controlled by Nokia. All\n" .
+$CC . " rights are reserved. Copying, including reproducing, storing\n" .
+$CC . " adapting or translating, any or all of this material requires the\n" .
+$CC . " prior written consent of Nokia. This material also contains\n" .
+$CC . " confidential information which may not be disclosed to others\n" .
+$CC . " without the prior written consent of Nokia.";
+
+# Test string to test header have been changed
+my $S60HeaderTest = 'is\s*protected\s*by\s*copyright\s*controlled\s*by\s*Nokia';
+
+
+my @SflHeaders = (\$SFLicenseHeader, \$SFLicenseHeader_other_template, \$SFLicenseHeaderPartial_template, \$SFLHeaderTest); # contains refs
+my @EplHeaders = (\$EPLLicenseHeader, \$EPLLicenseHeader_other_template, \$EPLLicenseHeaderPartial_template, \$EPLHeaderTest); # contains refs
+my @S60Headers = (undef,undef,\$S60HeaderPartial_template, \$S60HeaderTest); # contains refs
+my @LgplHeaders = (\$LGPLLicenseHeader, \$LGPLLicenseHeader_other_template, \$LGPLLicenseHeaderPartial_template, \$LGPLHeaderTest); # contains refs
+
+# Header styles (indeces within @SflHeaders and @EplHeaders)
+use constant CPP_HEADER => 0;
+use constant OTHER_HEADER => 1;
+
+# switchLicense related values
+use constant SFL_LICENSE => 3;
+use constant EPL_LICENSE => 7;
+use constant S60_LICENSE => 0;
+use constant LGPL_LICENSE => 4;
+use constant LICENSE_CHANGED => 1;
+use constant LICENSE_NONE => 0;
+use constant LICENSE_ERROR => -1;
+use constant LICENSE_NOT_SUPPORTED => -2;
+
+# Distribution policy file values
+use constant INTERNAL_DISTRIBUTION_VALUE => "1";
+use constant ZERO_DISTRIBUTION_VALUE => "0";
+use constant SFL_DISTRIBUTION_VALUE => "3";
+use constant EPL_DISTRIBUTION_VALUE => "7"; # option -epl
+use constant TSRC_DISTRIBUTION_VALUE => "950"; #
+use constant NONSF_DISTRIBUTION_VALUE => "Other"; #
+use constant DISTRIBUTION_FILENAME => "distribution.policy.s60";
+
+my $usage = 'SFUpdateLicenHeader.pl tool, version: ' . VERSION .
+'
+Usages:
+ perl SFUpdateLicenceHeader.pl [-modify] [-epl] [-oem] [-create] [-ignorefile pattern]
+ [-output csv-file] [-log logfile] [-verbose level] [-verify] [-append]
+ [-oldoutput old-csv-file] DIRECTORY|FILE
+
+ Check switch to SFL header in a directory (and subdirectories under that):
+ perl SFUpdateLicenceHeader.pl -output csv-file -log logfile DIRECTORY
+ Switch to SFL header and modify .policy.s60 files in a directory (and subdirectories under that):
+ perl SFUpdateLicenceHeader.pl -modify -output csv-file -log logfile DIRECTORY
+ Switch to SFL header and modify .policy.s60 files in a single file:
+ perl SFUpdateLicenceHeader.pl -modify -output csv-file -log logfile FILE
+ Switch to EPL header and modify .policy.s60 files:
+ perl SFUpdateLicenceHeader.pl -modify -epl -output csv-file -log logfile DIRECTORY
+ Switch to SFL header and modify/create missing .policy.s60 files:
+ perl SFUpdateLicenceHeader.pl -modify -create -output csv-file -log logfile DIRECTORY
+ Switch to SFL header and ignore files matching CCM file pattern:
+ perl SFUpdateLicenceHeader.pl -modify -ignore "_ccmwaid.inf" -output csv-file -log logfile DIRECTORY
+ Switch to SFL header and ignore files matching CCM or SVN file patterns:
+ perl SFUpdateLicenceHeader.pl -modify -ignore "(_ccm|.svn)" -output csv-file -log logfile DIRECTORY
+ Switch back to Nokia header (for OEM delivery team):
+ perl SFUpdateLicenceHeader.pl -modify -oem -output csv-file -log logfile DIRECTORY
+ Verify file header changes
+ perl SFUpdateLicenceHeader.pl -verify -output csv-file -log logfile DIRECTORY
+ Verify and append logs and results to single file
+ perl SFUpdateLicenceHeader.pl -verify -append -output AllResults.csv -log AllLogs.log DIRECTORY
+ Verify file header changes and use old result file as add-on configuation (used by -verbose only)
+ perl SFUpdateLicenceHeader.pl -verify -oldoutput old-csv-file -output csv-file -log logfile DIRECTORY
+
+For more info, see http://s60wiki.nokia.com/S60Wiki/SFDG-File-Header#SFUpdateLicenceHeader.pl
+';
+
+# Logging constants
+use constant LOG_ALWAYS => 0;
+use constant LOG_INFO => 3;
+use constant LOG_ERROR => 1;
+use constant LOG_WARNING => 2;
+use constant LOG_DEBUG => 4;
+my @LOGTEXTS = ("", "ERROR: ", "Warning: ", "Info: ", "DEBUG: ");
+my $sep = ",";
+my $logFile = "";
+
+# Issue categories in result CSV formatted file
+use constant HEADER_CONTEXT => 'header-issue';
+use constant DISTRIBUTION_CONTEXT => 'distribution-issue';
+
+
+####################
+# Global variables
+####################
+
+# Command line options
+my $help = 0;
+my $outputfile;
+my $ignorefilepattern; # File patterns to ignore
+# my $optSfl = 1; # By default sfl is on
+my $optEpl = 0; # Use EPL headers
+my $optLgpl = 0; # Use LGPL v2.1 headers
+my $optLogLevel = LOG_INFO;
+my $optModify = 0; # (default mode is check)
+my $optCreate = 0; # (create missing files)
+my $optOem = 0; # OEM delivery to S60 license
+my $optAppend = 0; # Append results
+my $optVerify = 0; # Verify option
+my $oldOutputFile; # Version 1.60 old output file in CSV format
+my %manualIgnoreFileHash; # Hash of files ignored
+my $optDescription = 0; # Output also missing description
+my $optOutputOK = 0; # Output also OK issues for -verify
+
+# The last distribution ID
+my $lastDistributionValue = "";
+
+# Config file specific gllobals
+my $configFile;
+my $configVersion = "";
+my @sfDistributionIdArray = (); # Distribution ID array
+my @sfGeneratedPatternArray = (); # Distribution ID array
+
+#
+# Statistics variables
+#
+my $fileCount = 0;
+my $modifiedFileCount = 0;
+my $willModifiedFileCount = 0;
+my $noDescrcount = 0;
+my $otherCopyrCount=0;
+my $ExternalToNokiaCopyrCount=0;
+my $NokiaCopyrCount=0;
+my $NoCopyrCount=0;
+my $UnclearCopyrCount=0;
+my $SflToS60Changes = 0;
+my $EplToS60Changes = 0;
+my $SflToEplChanges = 0;
+my $EplToSflChanges = 0;
+my $LicenseChangeErrors = 0;
+my $ignoreCount = 0;
+my $unrecogCount = 0;
+my $createCount = 0;
+my @verifyFailedCount = (0,0,0,0,0,0,0,0,0,0,0);
+my @verifyFailedCountMsgs = ("Distribution file missing", # Index 0
+ "SFL or EPL distribution ID missing", #1
+ "SFL or EPL header missing", #2
+ "Proper copyright missing", #3
+ "Header vs. distribution ID mismatch", #4
+ "Internal directory going to SF", #5
+ "Old Nokia file header used", #6
+ "Unclear Non-Nokia copyright", #7
+ "Incomplete copyright", #8
+ "OK", #9
+ "OK (Non-Nokia)", #10
+ "Multiple license" #11
+ );
+use constant VERI_MISSING_FILE => 0;
+use constant VERI_MISSING_ID => 1;
+use constant VERI_MISSING_HEADER => 2;
+use constant VERI_PROPER_COPYRIGHT => 3;
+use constant VERI_ID_HEADER_MISMATCH => 4;
+use constant VERI_INTERNAL_TO_SF => 5;
+use constant VERI_OLD_NOKIA_HEADER => 6;
+use constant VERI_UNCLEAR_COPYR => 7;
+use constant VERI_INCOMPLETE_COPYR => 8;
+use constant VERI_OK => 9;
+use constant VERI_OK_NON_NOKIA => 10;
+use constant VERI_MULTIPLE_LICENSES => 11;
+
+
+##################################
+# Callback for the find function
+# (wanted)
+# Note ! "no_chdir" not used
+##################################
+sub process_file
+{
+
+ my $full_filename = $File::Find::name; # Full name needed for result and logs !
+ $full_filename =~ s/\\/\//g; # Standardize name
+ my $filename = $_; # This in filename in the current working directory !
+
+ #Skip all directory entries
+ return if -d;
+
+ if ($ignorefilepattern && $full_filename =~ m/$ignorefilepattern/i)
+ {
+ printLog(LOG_DEBUG, "File ignored by pattern: ". $full_filename . "\n");
+ $ignoreCount++;
+ return;
+ }
+
+ # Set initial value from options, turn off later if needed
+ my $modify = $optModify;
+ my $willmodify = 1; # For statistics only
+
+ #skip non-source code files
+ my ($name, $path, $suffix)=fileparse($_, qr/\.[^.]*/);
+
+ my $match = grep {$_ eq lc($suffix)} @extlist;
+ if (!$match)
+ {
+ printLog(LOG_DEBUG, "File ignored: ". $full_filename . "\n");
+ $ignoreCount++;
+ return;
+ }
+
+ # As there have been cased where e.g. .pkg file has been saved as Unicode format
+ # Check that we can really modify file (e.g. Unicode files not supported)
+ if (! (-T $filename)) # Text file only !
+ {
+ printLog(LOG_WARNING, "File not in text format: $full_filename\n");
+ return;
+ }
+
+
+ printLog(LOG_DEBUG, "Handling ". $full_filename . "\n");
+
+ local($/, *FH);
+
+ # Open file for reading here, re-open later if modified
+ open(FH, "<$filename") or return printLog(LOG_ERROR, "Failed to open file for reading: $full_filename\n");
+
+ my $filecontent = <FH>; # read whole content into buffer
+ # Standardize the new-line handling in files by replacing \r with \n
+ # Some files may be using only \r and it causes problems
+ $filecontent =~ s/\r/\n/g;
+
+ my $modifiedFilecontent;
+ my $description = "";
+ my $contributors = "";
+
+ #comment mark
+ my $cm = '\*';
+ my $cm2 = '*';
+ my $newheader = "";
+ my $oldheader = "";
+ my $oldheader2;
+ my $header_regexp = "";
+ my $header_regexp2;
+ my $isCcomment = 0;
+ my $isCPPcomment = 0;
+ my $oldCopyrightYear;
+ my $matchPos1;
+ my $matchPos2;
+ my $unrecog=0;
+
+
+ # For statisctics....
+ $fileCount++;
+
+ ###################
+ # Prepare regular expressions
+ # based on file extensions
+ ###################
+
+ if (lc($suffix) eq ".s60")
+ {
+ #
+ # Alter exisring distribution policy file
+ #
+ my $stat = LICENSE_NONE;
+ $stat = &handleDistributionValue(\$filecontent, $full_filename);
+ if ($stat eq LICENSE_CHANGED)
+ {
+ $willModifiedFileCount++;
+ if ($modify)
+ {
+ close(FH); # Close null
+ writeFile(\$filecontent, $filename, $full_filename);
+ }
+ }
+ return; # All done
+ }
+
+ elsif ( (lc($suffix) eq ".mk" ) or
+ (lc($suffix) eq ".pl") or (lc($suffix) eq ".py") or (lc($suffix) eq ".pm") or # script
+ (lc($suffix) eq ".pro") or (lc($suffix) eq ".pri") ) # Qt specific
+ {
+ # Makefile, Perl or Python script (# comment)
+ $cm = '#';
+ $cm2 = '#';
+ $newheader = &headerOf(OTHER_HEADER());
+ $header_regexp = $header_regexps[COMMENT_PERL];
+ }
+ elsif ((lc($suffix) eq ".bat" ) or (lc($suffix) eq ".cmd" ))
+ {
+ # Windows command script (@rem comment)
+ $cm = '@rem';
+ $cm2 = '@rem';
+ $newheader = &headerOf(OTHER_HEADER());
+ $newheader =~ s/\#/\@rem/g; # use rem as comment start, not #
+ #$newheader = "\@echo off\n" . $newheader; # Disable std output, otherwise rem statements are shown
+ #$newheader = $newheader . "\@echo on\n"; # Enable std output
+ $header_regexp = $header_regexps[COMMENT_CMD];
+ }
+ elsif (lc($suffix) eq ".pkg" or lc($suffix) eq ".asm")
+ {
+ # SIS package file or Assembly file (; comment)
+ $cm = ';';
+ $cm2 = ';';
+ $newheader = &headerOf(OTHER_HEADER());
+ $newheader =~ s/\#/\;/g; # use ; as comment start
+ $header_regexp = $header_regexps[COMMENT_SIS_ASM];
+ }
+ elsif (lc($suffix) eq ".s")
+ {
+ # Not all .s files are assemby files !!!
+ #
+ if ($filecontent =~ m/\#include\s*\"armasmdef\.h\"/s)
+ {
+ # ARM assembly file (C comment)
+ $newheader = &headerOf(CPP_HEADER());
+ # Match both C and C++ comment syntaxes
+ $isCcomment = 1;
+ $header_regexp = $header_regexps[COMMENT_C];
+ $header_regexp2 = $header_regexps[COMMENT_CPP]; # Use without /s in regexp eval !
+ }
+ elsif ($filecontent =~ m/[\s\t]+AREA[\s\t]+/s) # AREA statement
+ {
+ # RVCT assembly file (; comment)
+ $cm = ';';
+ $cm2 = ';';
+ $newheader = &headerOf(OTHER_HEADER());
+ $newheader =~ s/\#/\;/g; # use ; as comment start
+ $header_regexp = $header_regexps[COMMENT_SIS_ASM];
+ }
+ else
+ {
+ # Not recognized
+ $unrecog = 1;
+ printLog(LOG_WARNING, "Assembly file content not recognized, ignored ". $full_filename . "\n");
+ }
+ }
+ elsif (lc($suffix) eq ".script" )
+ {
+ # Test scipt (// comment)
+ $cm = '//';
+ $cm2 = '//';
+ $newheader = &headerOf(OTHER_HEADER());
+ $newheader =~ s/\#/\/\//g; # use // as comment start
+ $header_regexp = $header_regexps[COMMENT_SCRIPT];
+ }
+ else
+ {
+ # C/C++ syntaxed file
+ $newheader = &headerOf(CPP_HEADER());
+ # Match both C and C++ comment syntaxes
+ $isCcomment = 1;
+ $header_regexp = $header_regexps[COMMENT_C];
+ $header_regexp2 = $header_regexps[COMMENT_CPP]; # Use without /s in regexp eval !
+ }
+
+ if ($unrecog)
+ {
+ close(FH);
+ $unrecogCount++;
+ return;
+ }
+
+ ###################
+ # Pick up old header in the very first comment block.
+ # If the actual license text is in the later comment block, it may generate
+ # UNCLEAR COPYRIGHT CASE (See Consistency checks)
+ ###################
+ #
+ if ($header_regexp2)
+ {
+ if ($filecontent =~ m/$header_regexp2/) # Note /s not used by purpose !
+ {
+ $oldheader = $&;
+ $oldheader2 = $&;
+ $matchPos2 = $-[0];
+ $isCPPcomment = 1;
+ printLog(LOG_DEBUG, "Orig C++ header:$matchPos2=($oldheader)\n");
+ }
+ }
+
+ if ($filecontent =~ m/$header_regexp/s)
+ {
+ $oldheader = $&;
+ $matchPos1 = $-[0];
+ $isCPPcomment = 0;
+ if ($oldheader2 && ($matchPos2 < $matchPos1))
+ {
+ $oldheader = $oldheader2; # C++ header was earlier
+ $isCPPcomment = 1; # revert back
+ }
+ else
+ {
+ printLog(LOG_DEBUG, "Orig C or other header:$header_regexp,$matchPos1\n");
+ printLog(LOG_DEBUG, "Orig C or other header:($oldheader)\n");
+ }
+ }
+
+ #
+ ###################
+ # Process old header
+ ###################
+
+ # Handle -verify option
+ if ($optVerify)
+ {
+ if ($optLgpl)
+ {
+ &handleVerifyLgpl(\$filecontent, \$oldheader, $cm, $full_filename, $File::Find::dir);
+ }
+ elsif ($optEpl)
+ {
+ &handleVerifyEpl(\$filecontent, \$oldheader, $cm, $full_filename, $File::Find::dir);
+ }
+ else
+ {
+ &handleVerify(\$filecontent, \$oldheader, $cm, $full_filename, $File::Find::dir);
+ }
+
+ close(FH);
+ return; # All done
+ }
+
+ #
+ # Try switch license from SFL to EPL / S60-OEM release
+ #
+ my $switchStat = LICENSE_NONE;
+ $switchStat = &switchLicense(\$filecontent, \$oldheader, $cm, $full_filename, $isCPPcomment);
+ if ($switchStat eq LICENSE_CHANGED)
+ {
+ # OK the switch was sucessful
+ $willModifiedFileCount++;
+ if ($modify)
+ {
+ close(FH);
+ writeFile(\$filecontent, $filename, $full_filename);
+ }
+ close(FH);
+ return; # All done
+ }
+ elsif ($switchStat eq LICENSE_NOT_SUPPORTED)
+ {
+ close(FH);
+ return; # No worth continue
+ }
+
+
+ # Otherwise (error or no license) continue to create new header
+
+ ###################
+ # Consistency checks
+ ###################
+ if ( (!($oldheader =~ m/$CopyrPattern/is)) && ($filecontent =~ m/$BeginLicenseBlockPattern/s))
+ {
+ # Looks like header is something weired going on. First comment block contains no copyright,
+ # and still there is "BEGIN LICENSE" block in the file
+ $UnclearCopyrCount++;
+ printLog(LOG_INFO, "Non-Nokia copyright (#1) ". $full_filename . "\n");
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia copyright $sep$sep"."BEGIN LICENSE BLOCK$sep$full_filename$sep$linenumtext\n");
+ close(FH);
+ return;
+ }
+
+ #
+ # Switch license from S60 to SFL/EPL according to options
+ #
+
+ my $otherCopyr = 0;
+ my $noCopyr = 0;
+ my $ExternalToNokiaCopyr = 0;
+ my $s60header = 0;
+
+ # First remove all "Nokia copyright" texts + weired "Copyright known-words" from header
+ # This because, the header can contain both Nokia and other company copyright statements
+ my $testheader = makeTestHeader(\$oldheader, 0, REMOVE_SYMBIAN);
+ printLog(LOG_DEBUG, "Cleaned header=($testheader)\n");
+
+ # Now test whether it contain non-Nokia (=Nokia+Symbian) copyright statements
+ # The rule is: If this hits, do not touch the header
+
+ if ($testheader =~ m/$NonNokiaCopyrPattern/is)
+ {
+ # Some other than Nokia & Symbian copyright exist in header
+ $otherCopyr = 1;
+ $modify = 0; # !!! Do not modify file !!!
+ $willmodify = 0;
+ $otherCopyrCount++;
+ my $failReason = "";
+ if (!checkPortionsCopyright(\$oldheader, 0, \$failReason))
+ {
+ printLog(LOG_WARNING, "Non-Nokia copyright (#2) ". $full_filename . "\n");
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia copyright$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+ else
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia (portions Nokia) copyright$sep$sep$sep$full_filename$sep$linenumtext\n");
+ printLog(LOG_INFO, "Non-Nokia (portions Nokia) copyright ". $full_filename . "\n");
+ }
+
+ close(FH);
+ return; # Quit
+ }
+
+ # Test header has Nokia or Symbian copyright statement or it could be some other comment
+ # Check the rest of file
+ my $wholefile = makeTestHeader(\$filecontent, 1, REMOVE_SYMBIAN); # Check the rest of file
+ if ($wholefile =~ m/$NonNokiaCopyrPattern/is)
+ {
+ # The header might be empty due to weired file header style.
+ # Check the whole file content, it could be non-nokia file?
+ $modify = 0; # !!! Do not modify file !!!
+ $willmodify = 0;
+ my $failReason = "";
+ if (!checkPortionsCopyright(\$filecontent, 1, \$failReason))
+ {
+ $UnclearCopyrCount++;
+ printLog(LOG_INFO, "Non-Nokia copyright (#2) ". $full_filename . "\n");
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia copyright$failReason$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+ else
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia (portions Nokia) copyright$sep$sep$sep$full_filename$sep$linenumtext\n");
+ printLog(LOG_INFO, "Non-Nokia (portions Nokia) copyright ". $full_filename . "\n");
+ }
+ close(FH);
+ return; # Quit
+ }
+
+ # Check if header is already OK.
+ # This is needed to keep Ex-Symbian C++ comment syntaxes.
+ # Also, this avoid unncessary changes in headers.
+ # NOTE ! If header need to be converted to a new format the check must return FALSE !!!
+ my $license = licenceIdForOption();
+ if (checkHeader(\$filecontent, \$oldheader, $cm, $full_filename, $File::Find::dir, \$license))
+ {
+ if (!checkNoMultipleLicenses(\$filecontent, \$oldheader, $cm, $full_filename, $File::Find::dir))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Multiple licenses$sep$sep$sep$full_filename$sep" ."1\n");
+ printLog(LOG_ERROR, "Multiple licenses:". $full_filename . "\n");
+ close(FH);
+ return; # Failed
+ }
+ else
+ {
+ # Quit here, header OK
+ printLog(LOG_INFO, "Header already OK ($license): $full_filename\n");
+ close(FH);
+ return; # Quit
+ }
+ }
+
+ # Check if Ex-Symbian file
+ my $testheader = makeTestHeader(\$oldheader, 0, KEEP_SYMBIAN);
+ if ($testheader =~ m/$ExternalToNokiaCopyrPattern/is)
+ {
+ # External copyright moved to Nokia
+ my $txt = $1;
+ $txt =~ s/,//;
+ $ExternalToNokiaCopyr = 1;
+ $ExternalToNokiaCopyrCount++;
+ if ($isCPPcomment)
+ {
+ # Normalize the C++ header syntax back to C comment
+ $modifiedFilecontent = &normalizeCppComment($header_regexp2,$filecontent, \$oldheader);
+ printLog(LOG_DEBUG, "Normalized External header=($oldheader)\n");
+ }
+ if ($testheader =~ /$copyrYearPattern/)
+ {
+ if ($& =~ /$copyrYearPattern2/)
+ {
+ $oldCopyrightYear = $&;
+ }
+ printLog(LOG_DEBUG, "Old copyright=($oldCopyrightYear)\n");
+ }
+ printLog(LOG_INFO, "Copyright will be converted to Nokia: $full_filename\n");
+ printResult(HEADER_CONTEXT() . "$sep"."Converted copyright$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+
+ elsif ($oldheader =~ m/$NokiaCopyrPattern/is)
+ {
+ # Consider it to be Nokia copyright
+ $s60header = 1;
+ $NokiaCopyrCount++;
+ printLog(LOG_DEBUG, "Nokia header=($full_filename)\n");
+ if ($isCPPcomment)
+ {
+ # Normalize the C++ header syntax back to C comment
+ $modifiedFilecontent = &normalizeCppComment($header_regexp2, $filecontent, \$oldheader);
+ printLog(LOG_DEBUG, "Normalized Nokia header=($oldheader)\n");
+ }
+ if ($oldheader =~ /$copyrYearPattern/)
+ {
+ if ($& =~ /$copyrYearPattern2/)
+ {
+ $oldCopyrightYear = $&;
+ }
+ printLog(LOG_DEBUG, "Old copyright2=($oldCopyrightYear)\n");
+ }
+ }
+ elsif (! ($testheader =~ m/$CopyrPattern/is) )
+ {
+ # No copyright in the header.
+ $NoCopyrCount++;
+ $noCopyr = 1;
+ # printResult(HEADER_CONTEXT() . "$sep"."No Copyright$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+ else
+ {
+ $UnclearCopyrCount++;
+ $modify = 0; # !!! Do not modify file !!!
+ $willmodify = 0;
+ printLog(LOG_ERROR, "UNCLEAR copyright ". $full_filename . "\n");
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR COPYRIGHT CASE$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+
+
+ # Get description from current header
+ if ($oldheader =~ m/$cm\s*Description\s*\:(.*?)$cm\s*(Version)/s)
+ {
+ # Description followed by Version
+ $description = $1;
+ printLog(LOG_DEBUG, "Old description followed by version ($description)\n");
+ } else
+ {
+ # Description without Version
+ # ORIG if ($oldheader =~ m/$cm?\s*Description\s*\:(.*?)$cm\s*(\n)/s)
+ if ($oldheader =~ m/$cm?\s*Description\s*\:(.*?)($cm|$cm\/|\n)\s*\n/s)
+ {
+ $description = $1;
+ printLog(LOG_DEBUG, "Old description not followed by version ($description)\n");
+ }
+ }
+
+ if ($isCcomment)
+ {
+ $description =~ s/\/\*.*//; # Remove possible /*
+ $description =~ s/\*\/.*//; # Remove possible */
+ $description =~ s/\=//g; # Remove possible =/
+ }
+
+ # Get contributors from old header
+ if ( $oldheader =~ m/$cm\s*Contributors\s*\:(.*?)$cm\s*Description\s*\:/s)
+ {
+ $contributors = $1;
+ printLog(LOG_DEBUG, "Old contributors ($contributors)\n");
+ }
+
+ # Keep description text
+ if($description)
+ {
+ $newheader =~ s/Description:[ \t]*\n/Description: $description/s;
+ }
+
+
+ #Keep contributor list
+ if ($contributors)
+ {
+ $newheader =~ s/$cm[ \t]*Contributors:[ \t]*\n$cm[ \t]*\n/$cm2 Contributors:$contributors/s;
+ }
+
+
+ ###################
+ # Modify the header
+ ###################
+ if($oldheader)
+ {
+ {
+ # Update the old header to new one
+ # Old header may be just a description comment, e.g. in script
+ #
+
+ if ($otherCopyr)
+ {
+ # Other copyright statement, do not touch !
+ printLog(LOG_DEBUG, "Non-Nokia file not modified: $full_filename\n");
+ }
+ elsif ($noCopyr)
+ {
+
+ # No copyright statement
+ if (!isGeneratedHeader(\$oldheader))
+ {
+ # Just add new header
+ $filecontent = $newheader . $filecontent;
+ printLog(LOG_INFO, "New header will be added: $full_filename\n");
+ }
+ else
+ {
+ printLog(LOG_INFO, "Generated file ignored: $full_filename\n");
+ }
+ }
+ else
+ {
+ # Replace the old external / S60 header
+ my $newHeaderCopyrYear;
+ if ($newheader =~ /$copyrYearPattern2/)
+ {
+ # This is picked up from newheader template in this script, so should work always !
+ $newHeaderCopyrYear = $&; # Pick up year from new header
+ printLog(LOG_DEBUG, "Template header copyright=($newHeaderCopyrYear)\n");
+ }
+ if (!$newHeaderCopyrYear)
+ {
+ # Anyway, some weired error happended
+ $newHeaderCopyrYear = DEFCOPYRIGHTYEAR;
+ }
+
+ # Create new copyright years
+ if ($oldCopyrightYear && !($oldCopyrightYear =~ /$newHeaderCopyrYear/))
+ {
+ # Keep the old copyright !!!
+ # !!! If adding new copyright year to old header, uncomment the next line !!!
+ # $oldCopyrightYear .= ",$newHeaderCopyrYear";
+ }
+ if (!$oldCopyrightYear)
+ {
+ # Nothing found
+ $oldCopyrightYear = $newHeaderCopyrYear;
+ }
+ printLog(LOG_DEBUG, "New header copyright:$oldCopyrightYear\n");
+ $newheader =~ s/$newHeaderCopyrYear/$oldCopyrightYear/;
+ printLog(LOG_DEBUG, "New header:$full_filename,($newheader)\n");
+ if ($modifiedFilecontent)
+ {
+ $filecontent = $modifiedFilecontent; # Use the already modified content as basis
+ }
+
+ #
+ # SET THE NEW HEADER
+ #
+ if (!($filecontent =~ s/$header_regexp/$newheader/s))
+ {
+ printLog(LOG_ERROR, "FAILED to change file header: ". $full_filename . "\n");
+ $LicenseChangeErrors++;
+ $modify = 0; # Can not modify on failure
+ $willmodify = 0;
+ }
+ else
+ {
+ printLog(LOG_INFO, "File header will be changed: $full_filename\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!isGeneratedHeader(\$filecontent)) # Ensure file is not generated
+ {
+ # Missing old header, add new header as such
+ printLog(LOG_INFO, "Missing header will be added: $full_filename\n");
+ $filecontent = $newheader."\n".$filecontent;
+ }
+ else
+ {
+ printLog(LOG_INFO, "Generated file ignored: $full_filename\n");
+ }
+ }
+
+ if ($description =~ m/^\s*$/g || $description =~ m/$descrTemplateOnly/)
+ {
+ $noDescrcount++;
+ if ($optDescription)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Description missing$sep$sep$sep$full_filename$sep$linenumtext\n");
+ }
+ }
+
+ close(FH);
+
+ if ($modify)
+ {
+ # Re-open the file for modifications
+ chmod 0777, $filename if !-w; # remove first R/O
+ open(FH, "+<$filename") or return printLog(LOG_ERROR, "Failed to open file for modifying: $full_filename\n");
+ print FH $filecontent or printLog(LOG_ERROR, "Failed to modify file: $full_filename\n");
+ truncate(FH, tell(FH));
+ $modifiedFileCount++;
+ close(FH);
+ }
+
+ if ($willmodify)
+ {
+ # Only for statistics
+ $willModifiedFileCount++;
+ }
+
+}
+
+
+
+##################################
+# Callback for the find function
+# (postprocess)
+# Note ! "no_chdir" not used
+##################################
+sub postprocess
+{
+ my $dir = $File::Find::dir;
+ printLog(LOG_DEBUG, "postprocess $dir\n");
+
+ return if (-e DISTRIBUTION_FILENAME); # Already exists ?
+
+ my $full_filename = $dir . "/" . DISTRIBUTION_FILENAME; # Full name needed for results and log
+ my $filename = DISTRIBUTION_FILENAME;
+
+ if ($ignorefilepattern && $full_filename =~ m/$ignorefilepattern/i)
+ {
+ printLog(LOG_DEBUG, "Missing file ignored by pattern: ". $full_filename . "\n");
+ $ignoreCount++;
+ return;
+ }
+
+ my $filecontent = "";
+ my $stat = LICENSE_NONE;
+ $stat = &handleDistributionValue(\$filecontent, $full_filename);
+ if ($stat eq LICENSE_CHANGED && $optCreate && isDirectoryNonEmpty('.'))
+ {
+ # Create new distribution file to non-empty directory
+ printResult(DISTRIBUTION_CONTEXT() . "$sep"."New file$sep$sep$sep$full_filename$sep$linenumtext\n");
+ if ($optModify)
+ {
+ # Without -modify it is possible to see what new files will created
+ createAndWriteFile(\$filecontent, $filename, $full_filename);
+ }
+ $createCount++; # For statistics
+ }
+
+
+}
+
+
+##################################
+# Callback for the find function
+# (preprocess). Used by option -verify
+# Note ! "no_chdir" not used
+##################################
+sub preprocess
+{
+ my $dir = $File::Find::dir;
+ printLog(LOG_DEBUG, "preprocess $dir\n");
+ $lastDistributionValue = ""; # Empty first
+
+ if (!isDirectoryNonEmpty('.'))
+ {
+ # Ignore empty dirs
+ return @_; # Return input args
+ }
+ if (!$optVerify)
+ {
+ return @_; # Return input args
+ }
+
+ #
+ # Currently option -verify required !!!
+ #
+
+ my $full_filename = $dir . "/" . DISTRIBUTION_FILENAME; # Full name needed for results and log
+ $full_filename =~ s/\\/\//g; # Standardize name
+
+ my $filename = DISTRIBUTION_FILENAME;
+ if ($ignorefilepattern && $full_filename =~ m/$ignorefilepattern/i)
+ {
+ if (! ($dir =~ m/$INTERNAL/i) )
+ {
+ return @_;
+ }
+ }
+
+ # Check existency of the file
+ if (!open(FH, "<$filename"))
+ {
+ printResult(DISTRIBUTION_CONTEXT() . "$sep"."Distribution policy file missing$sep$sep$sep$full_filename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_MISSING_FILE]++;
+ return @_; # Return input args
+ }
+
+ my $content = <FH>; # IF CONTENT CHECKS
+ close FH;
+
+ $content =~ s/\n//g; # Remove all new-lines
+ $content =~ s/^\s+//g; # trim left
+ $content =~ s/\s+$//g; # trim right
+ $lastDistributionValue = $content; # Save to global variable for the sub handleVerify
+
+ printLog(LOG_DEBUG, "$full_filename content=$content\n");
+
+ if ($dir =~ m/$INTERNAL/i)
+ {
+ if ( ($content eq SFL_DISTRIBUTION_VALUE) || ($content eq EPL_DISTRIBUTION_VALUE) )
+ {
+ # Internal directory has SFL or EPL distribution value, something is wrong !
+ my $comment = ""; # Leave it just empty
+ printResult(DISTRIBUTION_CONTEXT() . "$sep"."Internal directory going to SF (current value $content)$sep$comment$sep$sep$full_filename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_INTERNAL_TO_SF]++;
+ }
+ }
+ elsif (! (($content eq SFL_DISTRIBUTION_VALUE) || ($content eq EPL_DISTRIBUTION_VALUE)))
+ {
+ # Neither SFL nor EPL value
+ my $comment = getCommentText($content,0,"0,3,7,950", $full_filename);
+ my $isSFId = &isSFDistribution($content);
+ if (!$isSFId)
+ {
+ printResult(DISTRIBUTION_CONTEXT() . "$sep"."SFL or EPL value missing (current value $content)$sep$comment$sep$sep$full_filename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_MISSING_ID]++;
+ }
+ }
+
+ return @_; # Return input args
+
+}
+
+##################################################
+# Read distribution file from given directory
+##################################################
+sub readDistributionValue
+{
+
+ my $dir = shift;
+
+ my $filename = DISTRIBUTION_FILENAME;
+ my $content = "";
+
+ if (open(FH, "<$filename"))
+ {
+ $content = <FH>;
+ close FH;
+ }
+
+ $content =~ s/\n//g; # Remove all new-lines
+ $content =~ s/^\s+//g; # trim left
+ $content =~ s/\s+$//g; # trim right
+
+ return $content;
+}
+
+
+##################################################
+# Make test header from given input text
+##################################################
+sub makeTestHeader
+{
+ my $ref = shift; # Input text reference
+ my $isWholeFile = shift; # $ref is the file content
+ my $removeExternalToNokia = shift; # Remove to Nokia transferreable copyright texts
+
+ my $tstheader = "";
+
+ if (!$isWholeFile)
+ {
+ $tstheader = $$ref;
+ }
+ else
+ {
+ # To optimize, whole file == 10k !!!
+ # The proper header should be included in that amount of data.
+ $tstheader = substr($$ref, 0, 10*1024);
+ }
+ $tstheader =~ s/$NokiaCopyrPattern//gi;
+ $tstheader =~ s/$PortionsNokiaCopyrPattern//gi;
+ $tstheader =~ s/$RemoveS60TextBlockPattern//si;
+ if ($removeExternalToNokia)
+ {
+ $tstheader =~ s/$ExternalToNokiaCopyrPattern//gi;
+ $tstheader =~ s/$PortionsSymbianCopyrPattern//gi;
+ }
+
+ # Take out special texts containing copyright word
+ $tstheader =~ s/Copyright\s*\(c\)\s*\.//gi;
+ $tstheader =~ s/COPYRIGHT[\s\n\*\#+;]*(HOLDER|OWNER|notice)//gi;
+
+ return $tstheader;
+}
+
+
+##################################################
+# Check whether portions copyright is OK
+# Call this for non Nokia cases only !
+##################################################
+sub checkPortionsCopyright
+{
+ my $ref = shift; # Input text reference
+ my $isWholeFile = shift; # $ref is the file content
+ my $failReason_ref = shift; # check failure reason (OUT)
+
+ my $tstheader = "";
+
+ if (!$isWholeFile)
+ {
+ $tstheader = $$ref;
+ }
+ else
+ {
+ # The portions info should be included within first 10 Kb of file
+ $tstheader = substr($$ref, 0, 10*1024);
+ }
+
+ if ($tstheader =~ m/$PortionsSymbianCopyrPattern/is)
+ {
+ # Symbian portions copyright should be converted to Nokia one
+ if (!($tstheader =~ m/$PortionsNokiaCopyrPattern/is))
+ {
+ $$failReason_ref = "(portions Symbian copyright)";
+ }
+ else
+ {
+ $$failReason_ref = "(portions Nokia+Symbian copyright)";
+ }
+ return 0;
+ }
+
+ if (!($tstheader =~ m/$NewPortionsNokiaCopyrPattern/is))
+ {
+ # No portions copyright present
+ $$failReason_ref = "";
+ return 0;
+ }
+
+ return 1; # Should be OK
+}
+
+
+##################################################
+# Get comment text by ID or filename
+# Returns currently empty or value of the $IGNORE
+##################################################
+sub getCommentText
+{
+ my $distributionValue = shift;
+ my $contains = shift;
+ my $pattern = shift;
+ my $fullfilename = shift;
+
+ if ($contains)
+ {
+ if ($pattern =~ m/$distributionValue/)
+ {
+ return $IGNORE;
+ }
+ }
+ else
+ {
+ # Not contains
+ if (!($pattern =~ m/$distributionValue/))
+ {
+ return $IGNORE;
+ }
+ }
+
+ my $ignoreThis = $manualIgnoreFileHash{lc($fullfilename)};
+ if (defined $ignoreThis)
+ {
+ printLog(LOG_DEBUG, "$IGNORE_MAN 2: $fullfilename\n");
+ return $IGNORE_MAN;
+ }
+
+ return "";
+}
+
+
+##################################################
+# Write content to file
+##################################################
+sub writeFile
+{
+ my $filecontent_ref = shift;
+ my $filename = shift;
+ my $full_filename = shift;
+
+ my $fh;
+
+ chmod 0777, $filename if !-w; # remove first R/O
+ open($fh, "+<$filename") or return printLog(LOG_ERROR, "Failed to open file for modifying: $full_filename\n");
+ print $fh $$filecontent_ref or printLog(LOG_ERROR, "Failed to modify file: $full_filename\n");
+ truncate($fh, tell($fh));
+ close($fh);
+
+ $modifiedFileCount++;
+}
+
+##################################################
+# Create file and write content to file
+##################################################
+sub createAndWriteFile
+{
+ my $filecontent_ref = shift;
+ my $filename = shift;
+ my $full_filename = shift;
+
+ my $fh;
+
+ open($fh, ">$filename") or return printLog(LOG_ERROR, "Failed to create file: $full_filename\n");
+ print $fh $$filecontent_ref or printLog(LOG_ERROR, "Failed to write file: $full_filename\n");
+ close($fh);
+}
+
+##################################
+# Check if current directory is empty
+##################################
+sub isDirectoryNonEmpty
+{
+ my ($dir) = @_;
+ opendir (DIR,$dir) or printLog(LOG_ERROR, "Can't opendir $dir\n");
+ for(readdir DIR)
+ {
+ if (-f $_)
+ {
+ closedir DIR;
+ return 1;
+ };
+ }
+ closedir DIR;
+ return 0;
+}
+
+
+##################################################
+# Change SFL back to S60, or
+# Change SFl to EPL
+# Returns LICENSE_CHANGED if function switched the license succesfully
+##################################################
+# Switch only license text and URL
+my $sflText = '"Symbian Foundation License v1.0"';
+my $sflTextPattern = '(the\s*License\s*)?\"Symbian\s*Foundation\s*License\s*v1\.0\"';
+my $sflUrlPattern = 'http\:\/\/www\.symbianfoundation\.org\/legal\/sfl\-v10\.html';
+my $sflUrl = 'http://www.symbianfoundation.org/legal/sf'.'l-v10.html';
+my $eplText = '"Eclipse Public License v1.0"';
+my $eplUrl = 'http://www.eclipse.org/legal/epl-v10.html';
+my $eplUrlPattern = 'http\:\/\/www\.eclipse\.org\/legal\/epl\-v10\.html';
+my $eplTextPattern = '"Eclipse\s*Public\s*License\s*v1\.0"';
+my $oldEplTextPattern = 'the\s*License\s*"Eclipse\s*Public\s*License\s*v1\.0'; # "the License" is unncessary
+
+sub switchLicense
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $isCPPcomment = shift;
+
+ my $testValueSfl = "";
+ my $testValueEpl = "";
+ my $testValueS60 = "";
+
+ if ($isCPPcomment)
+ {
+ # xSymbian files use this style
+ $commentChar = '//';
+ # in xSymbian files there are comments like, /// some text
+ $$filecontent_ref =~ s/(\/){3,}/\/\//g; # replace ///+ back to //
+ }
+
+
+ # In from value \* need to be escaped.
+ my $FromSFLText = &partialHeaderOf(SFL_LICENSE,$commentChar, \$testValueSfl);
+ my $FromEPLText = &partialHeaderOf(EPL_LICENSE,$commentChar, \$testValueEpl);
+
+ $commentChar =~ s/\\//; # Remove \ from possible \*
+ my $ToS60Text = &partialHeaderOf(S60_LICENSE,$commentChar, \$testValueS60);
+
+ # Note that partial headers are manually quoted in the declaration
+ # Otherwise \Q$SFLText\E and \Q$EPLText\E would be needed around those ones
+ # because plain text contains special chars, like .
+
+ printLog(LOG_DEBUG, "switchLicense: $fullfilename, $testValueEpl\n");
+
+ if ($$filecontent_ref =~ m/$testValueSfl/s)
+ {
+ # SFL license
+
+ if ($optOem)
+ {
+ # Switch from SFL to S60
+ if (!($$filecontent_ref =~ s/$FromSFLText/$ToS60Text/s))
+ {
+ printLog(LOG_ERROR, "FAILED to change SFL license to S60: ". $fullfilename . "\n");
+ $LicenseChangeErrors++;
+ return LICENSE_ERROR;
+ }
+ printLog(LOG_WARNING, "License will be swicthed from SFL to S60: ". $fullfilename . "\n");
+ $SflToS60Changes++;
+ return LICENSE_CHANGED;
+ }
+ elsif ($optEpl)
+ {
+ # Switch from SFL to EPL
+ if (! ( ($$filecontent_ref =~ s/$sflTextPattern/$eplText/s) && ($$filecontent_ref =~ s/$sflUrlPattern/$eplUrl/s) ) )
+ {
+ printLog(LOG_ERROR, "FAILED to change SFL to EPL: ". $fullfilename . "\n");
+ $LicenseChangeErrors++;
+ return LICENSE_ERROR;
+ }
+ else
+ {
+ printLog(LOG_INFO, "License will be switched from SFL to EPL: ". $fullfilename . "\n");
+ }
+ $SflToEplChanges++;
+ return LICENSE_CHANGED;
+ }
+ }
+
+ if ($$filecontent_ref =~ m/$testValueEpl/s)
+ {
+ if ($optOem)
+ {
+ printLog(LOG_ERROR, "Not supported to change EPL to S60: ". $fullfilename . "\n");
+ return LICENSE_NOT_SUPPORTED;
+ }
+ elsif (!$optEpl)
+ {
+ # Switch from EPL to SFL
+ if (! ( ($$filecontent_ref =~ s/$eplTextPattern/$sflText/s) && ($$filecontent_ref =~ s/$eplUrlPattern/$sflUrl/s) ) )
+ {
+ printLog(LOG_ERROR, "FAILED to change EPL to SFL: ". $fullfilename . "\n");
+ $LicenseChangeErrors++;
+ return LICENSE_ERROR;
+ }
+ else
+ {
+ printLog(LOG_WARNING, "License will be switched from EPL to SFL: ". $fullfilename . "\n");
+ }
+ $EplToSflChanges++;
+ return LICENSE_CHANGED;
+ }
+
+ # EPL text cleanup (remove unncessary "the License")
+ if ($$filecontent_ref =~ m/$oldEplTextPattern/s)
+ {
+ # EPL header contains extra words, get rid of them (allow script replace old header)
+ if ($$filecontent_ref =~ s/$oldEplTextPattern/$eplText/s)
+ {
+ # Not error if fails
+ printLog(LOG_INFO, "Unnecessary \"the License\" will be removed: $fullfilename\n");
+ return LICENSE_CHANGED;
+ }
+ }
+
+ }
+ else
+ {
+ return LICENSE_NONE; # Allow caller decide
+ }
+
+}
+
+##################################################
+# Verify changes
+##################################################
+sub handleVerify
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $directory = shift;
+
+ my $testValueSfl = "";
+ my $testValueEpl = "";
+ my $FromSFLText = &partialHeaderOf(SFL_LICENSE,$commentChar, \$testValueSfl);
+ my $FromEPLText = &partialHeaderOf(EPL_LICENSE,$commentChar, \$testValueEpl);
+
+ if ($lastDistributionValue eq "")
+ {
+ # Distribution file may be empty if giving single file as input
+ # Read it
+ $lastDistributionValue = readDistributionValue($directory);
+ }
+
+ printLog(LOG_DEBUG, "handleVerify $fullfilename, $$header_ref\n");
+
+ # First check Non-Nokia copyright files
+ my $testheader = makeTestHeader($header_ref, 0, REMOVE_SYMBIAN);
+ if (($testheader =~ m/$NonNokiaCopyrPattern/is))
+ {
+ printLog(LOG_DEBUG, "DEBUG:Extra check1 $&\n");
+ if (!($testheader =~ m/$ExternalToNokiaCopyrPattern/si))
+ {
+ # Non-nokia file
+ if ($testheader =~ m/$copyrYearPattern/si)
+ {
+ # Looks like copyright statement
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia copyright$sep" . "$IGNORE$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $otherCopyrCount++;
+ $verifyFailedCount[VERI_OK_NON_NOKIA]++;
+ return 1; # OK
+ }
+ else
+ {
+ # Incomplete copyright ?
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia incomplete copyright$sep" . "$IGNORE?$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_OK]++;
+ return 0;
+ }
+ }
+ }
+
+ # The header might be empty due to weired file header style.
+ # Check the whole file content, it could be non-nokia file?
+ my $filestart = makeTestHeader($filecontent_ref, 1, REMOVE_SYMBIAN);
+
+ if ($filestart =~ m/$NonNokiaCopyrPattern/is)
+ {
+ # There is Non-Nokia copyright statement in the file
+ if (($filestart =~ m/$testValueSfl/is) || ($filestart =~ m/$testValueEpl/is))
+ {
+ # Non-Nokia file, but still SFL or EPL header
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Non-Nokia copyright with SFL/EPL$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_UNCLEAR_COPYR]++;
+ return 0;
+ }
+ elsif ($$filecontent_ref =~ m/$OldNokiaPattern2/is)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Old Nokia copyright$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_OLD_NOKIA_HEADER]++;
+ return 0;
+ }
+ else
+ {
+ # Non-Nokia file
+ my $failReason = "";
+ if (!checkPortionsCopyright($filecontent_ref, 1, \$failReason))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Non-Nokia copyright$failReason$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_UNCLEAR_COPYR]++;
+ return 0;
+ }
+ else
+ {
+ # Contains portions copyright
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia (portions Nokia) copyright$sep" . "$IGNORE$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ return 1;
+ }
+ }
+ }
+
+ #
+ # OK, it should be Nokia copyrighted file
+ #
+
+ # Note that partial headers are manually quoted in the declaration
+ # Otherwise \Q$SFLText\E and \Q$EPLText\E would be needed around those ones
+ # because plain text contains special chars, like .
+ printLog(LOG_DEBUG, "handleVerify testheaders: $testValueSfl,$testValueEpl,$$header_ref\n");
+
+ if ( !( ($$header_ref =~ m/$testValueSfl/s) || ($$header_ref =~ m/$testValueEpl/s) ||
+ ($$filecontent_ref =~ m/$testValueSfl/s) || ($$filecontent_ref =~ m/$testValueEpl/s)
+ ) )
+ {
+ # Header not found from header or whole file
+ if (isGeneratedHeader($header_ref) || isGeneratedHeader($filecontent_ref))
+ {
+ # OK, it is generated header
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "Generated header$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_OK]++;
+ return 1; # OK
+ }
+
+ my $comment = getCommentText($lastDistributionValue, 0, "0,3,7", $fullfilename);
+ if (($$header_ref =~ m/$OldNokiaPattern2/is) || ($$filecontent_ref =~ m/$OldNokiaPattern2/is))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."SFL or EPL header missing (old Nokia copyright)$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ else
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."SFL or EPL header missing$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_MISSING_HEADER]++;
+ return 0;
+ }
+
+ # Cross header versus distribution ID
+ if ($lastDistributionValue ne "")
+ {
+ # Also other than 3 or 7 may be OK based on the config file
+ my $isSFId = &isSFDistribution($lastDistributionValue);
+ printLog(LOG_DEBUG, "DEBUG:handleVerify:Other ID OK=$isSFId\n");
+ if ( (($$header_ref =~ m/$testValueSfl/s) || ($$filecontent_ref =~ m/$testValueSfl/s)) && !$isSFId)
+ {
+ my $comment = getCommentText($lastDistributionValue, 0, "0,3,7", $fullfilename);
+ printResult(HEADER_CONTEXT() . "$sep"."SFL header vs. distribution id ($lastDistributionValue) mismatch$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_ID_HEADER_MISMATCH]++;
+ return 0;
+ }
+ if ( (($$header_ref =~ m/$testValueEpl/s) || ($$filecontent_ref =~ m/$testValueEpl/s)) && !$isSFId )
+ {
+ my $comment = getCommentText($lastDistributionValue, 0, "0,3,7", $fullfilename);
+ printResult(HEADER_CONTEXT() . "$sep"."EPL header vs. distribution id ($lastDistributionValue) mismatch$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_ID_HEADER_MISMATCH]++;
+ return 0;
+ }
+ }
+
+ if (!checkNoMultipleLicenses($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Multiple licenses$sep$sep$sep$fullfilename$sep" ."1\n");
+ printLog(LOG_ERROR, "Multiple licenses:". $fullfilename . "\n");
+ $verifyFailedCount[VERI_MULTIPLE_LICENSES]++;
+ return 0; # Failed
+ }
+
+
+ # We should have proper header in place
+
+ printLog(LOG_DEBUG, "handleVerify: $$filecontent_ref\n");
+ # Check New Nokia copyright pattern (added one sentence to the old one)
+ if (! (($$header_ref =~ m/$NewNokiaPattern/s) || ($$filecontent_ref =~ m/$NewNokiaPattern/s)) )
+ {
+ my $comment = getCommentText($lastDistributionValue, 0, "0,3,7,950", $fullfilename);
+ printResult(HEADER_CONTEXT() . "$sep"."Proper Nokia copyright statement missing$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_PROPER_COPYRIGHT]++;
+ return 0; # Failed
+ }
+
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "OK$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_OK]++;
+
+ return 1;
+
+}
+
+
+##################################################
+# Verify changes
+##################################################
+sub handleVerifyEpl
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $directory = shift;
+
+ my $testValueSfl = "";
+ my $testValueEpl = "";
+ my $FromSFLText = &partialHeaderOf(SFL_LICENSE,$commentChar, \$testValueSfl);
+ my $FromEPLText = &partialHeaderOf(EPL_LICENSE,$commentChar, \$testValueEpl);
+
+ if ($lastDistributionValue eq "")
+ {
+ # Distribution file may be empty if giving single file as input
+ # Read it
+ $lastDistributionValue = readDistributionValue($directory);
+ }
+
+ printLog(LOG_DEBUG, "handleVerifyEpl $fullfilename, $$header_ref\n");
+
+ # First check Non-Nokia copyright files
+ my $testheader = makeTestHeader($header_ref, 0, REMOVE_SYMBIAN);
+ if (($testheader =~ m/$NonNokiaCopyrPattern/is))
+ {
+ printLog(LOG_DEBUG, "DEBUG:Extra check1 $&\n");
+ if (!($testheader =~ m/$ExternalToNokiaCopyrPattern/si))
+ {
+ # Non-nokia file
+ if ($testheader =~ m/$copyrYearPattern/si)
+ {
+ # Looks like copyright statement
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia copyright$sep" . "$IGNORE$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $otherCopyrCount++;
+ $verifyFailedCount[VERI_OK_NON_NOKIA]++;
+ return 1; # OK
+ }
+ else
+ {
+ # Incomplete copyright ?
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia incomplete copyright$sep" . "$IGNORE?$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_OK]++;
+ return 0;
+ }
+ }
+ }
+
+ # The header might be empty due to weired file header style.
+ # Check the whole file content, it could be non-nokia file?
+ my $filestart = makeTestHeader($filecontent_ref, 1, REMOVE_SYMBIAN);
+
+ if ($filestart =~ m/$NonNokiaCopyrPattern/is)
+ {
+ # There is Non-Nokia copyright statement in the file
+ if ($filestart =~ m/$testValueEpl/is)
+ {
+ # Non-Nokia file, but still EPL header
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Non-Nokia copyright with EPL$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_UNCLEAR_COPYR]++;
+ return 0;
+ }
+ elsif ($$filecontent_ref =~ m/$OldNokiaPattern2/is)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Old Nokia copyright$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_OLD_NOKIA_HEADER]++;
+ return 0;
+ }
+ else
+ {
+ # Non-Nokia file
+ my $failReason = "";
+ if (!checkPortionsCopyright($filecontent_ref, 1, \$failReason))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."UNCLEAR Non-Nokia copyright$failReason$sep" . "$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_UNCLEAR_COPYR]++;
+ return 0;
+ }
+ else
+ {
+ # Contains portions copyright
+ printResult(HEADER_CONTEXT() . "$sep"."Non-Nokia (portions Nokia) copyright$sep" . "$IGNORE$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ return 1;
+ }
+ }
+ }
+
+ #
+ # OK, it should be Nokia copyrighted file
+ #
+
+ # Note that partial headers are manually quoted in the declaration
+ # Otherwise \Q$EPLText\E would be needed around those ones
+ # because plain text contains special chars, like .
+ printLog(LOG_DEBUG, "handleVerify testheaders: $testValueEpl,$$header_ref\n");
+
+ if ( !( ($$header_ref =~ m/$testValueEpl/s) || ($$filecontent_ref =~ m/$testValueEpl/s) ) )
+ {
+ # Header not found from header or whole file
+ if (isGeneratedHeader($header_ref) || isGeneratedHeader($filecontent_ref))
+ {
+ # OK, it is generated header
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "Generated header$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_OK]++;
+ return 1; # OK
+ }
+
+ if (($$header_ref =~ m/$testValueSfl/s) || ($$filecontent_ref =~ m/$testValueSfl/s))
+ {
+ # Still SFL header in place
+ printResult(HEADER_CONTEXT() . "$sep"."EPL header missing (SFL header used)$sep$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ elsif (($$header_ref =~ m/$OldNokiaPattern2/is) || ($$filecontent_ref =~ m/$OldNokiaPattern2/is))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."EPL header missing (old Nokia copyright)$sep$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ else
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."EPL header missing$sep$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_MISSING_HEADER]++;
+ return 0;
+ }
+
+ # Cross header versus distribution ID
+ if ($lastDistributionValue ne "")
+ {
+ # Also other than 7 may be OK based on the config file
+ my $isSFId = &isSFDistribution($lastDistributionValue);
+ printLog(LOG_DEBUG, "DEBUG:handleVerify:Other ID OK=$isSFId\n");
+ if ( ($$filecontent_ref =~ m/$testValueEpl/s) && ($lastDistributionValue ne EPL_DISTRIBUTION_VALUE) )
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."EPL header vs. distribution id ($lastDistributionValue) mismatch$sep$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_ID_HEADER_MISMATCH]++;
+ return 0;
+ }
+ }
+
+ if (!checkNoMultipleLicenses($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Multiple licenses$sep$sep$sep$fullfilename$sep" ."1\n");
+ printLog(LOG_ERROR, "Multiple licenses:". $fullfilename . "\n");
+ $verifyFailedCount[VERI_MULTIPLE_LICENSES]++;
+ return 0; # Failed
+ }
+
+
+ # We should have proper header in place
+
+ printLog(LOG_DEBUG, "handleVerify: $$filecontent_ref\n");
+ # Check New Nokia copyright pattern (added one sentence to the old one)
+ if (! (($$header_ref =~ m/$NewNokiaPattern/s) || ($$filecontent_ref =~ m/$NewNokiaPattern/s)) )
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Proper Nokia copyright statement missing$sep$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ $verifyFailedCount[VERI_PROPER_COPYRIGHT]++;
+ return 0; # Failed
+ }
+
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "OK$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_OK]++;
+
+ return 1;
+
+}
+
+
+
+##################################################
+# Verify changes for LGPL headers
+##################################################
+sub handleVerifyLgpl
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $directory = shift;
+
+ my $testValueLgpl = "";
+ my $FromLgplText = &partialHeaderOf(LGPL_LICENSE,$commentChar, \$testValueLgpl);
+
+ if ($lastDistributionValue eq "")
+ {
+ # Distribution file may be empty if giving single file as input
+ # Read it
+ $lastDistributionValue = readDistributionValue($directory);
+ }
+
+ printLog(LOG_DEBUG, "handleVerifyLgpl $fullfilename, $$header_ref\n");
+
+ # Note that partial headers are manually quoted in the declaration
+ # Otherwise \Q$SFLText\E and \Q$EPLText\E would be needed around those ones
+ # because plain text contains special chars, like .
+ printLog(LOG_DEBUG, "handleVerifyLgpl testheaders: $testValueLgpl,$$header_ref\n");
+
+ if ( !( ($$header_ref =~ m/$testValueLgpl/s) || ($$filecontent_ref =~ m/$testValueLgpl/s) ) )
+ {
+ # Header not found from header or whole file
+ if (isGeneratedHeader($header_ref) || isGeneratedHeader($filecontent_ref))
+ {
+ # OK, it is generated header
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "Generated header$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_OK]++;
+ return 1; # OK
+ }
+
+ my $comment = getCommentText($lastDistributionValue, 0, "0,3,7", $fullfilename);
+ if (($$header_ref =~ m/$OldNokiaPattern2/is) || ($$filecontent_ref =~ m/$OldNokiaPattern2/is))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."LGPL header missing (old Nokia copyright)$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ else
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."LGPL header missing$sep$comment$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+ $verifyFailedCount[VERI_MISSING_HEADER]++;
+ return 0;
+ }
+
+ if (!checkNoMultipleLicenses($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory))
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."Multiple licenses$sep$sep$sep$fullfilename$sep" ."1\n");
+ printLog(LOG_ERROR, "Multiple licenses:". $fullfilename . "\n");
+ $verifyFailedCount[VERI_MULTIPLE_LICENSES]++;
+ return 0; # Failed
+ }
+
+
+ if ($optOutputOK)
+ {
+ printResult(HEADER_CONTEXT() . "$sep"."OK$sep" . "OK$sep$lastDistributionValue$sep$fullfilename$sep$linenumtext\n");
+ }
+
+ $verifyFailedCount[VERI_OK]++;
+
+ return 1;
+
+}
+
+
+##################################################
+# Test if header is already OK
+# NOTE ! If header need to be converted to a new format, the
+# check must return FALSE !!!
+##################################################
+sub checkHeader
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $directory = shift;
+ my $req_license_ref = shift; # in/out !!!
+
+ my $testValueSfl = "";
+ my $testValueEpl = "";
+ my $testValueLgpl = "";
+
+ my $FromSFLText = &partialHeaderOf(SFL_LICENSE,$commentChar, \$testValueSfl);
+ my $FromEPLText = &partialHeaderOf(EPL_LICENSE,$commentChar, \$testValueEpl);
+ my $FromLGPLText = &partialHeaderOf(LGPL_LICENSE,$commentChar, \$testValueLgpl);
+
+ # Note that partial headers are manually quoted in the declaration
+ # Otherwise \Q$SFLText\E and \Q$EPLText\E would be needed around those ones
+ # because plain text contains special chars, like .
+
+ my $retLicense = SFL_LICENSE; # default
+ my $testValue = $testValueSfl;
+
+ if ($$req_license_ref == EPL_LICENSE)
+ {
+ $testValue = $testValueEpl;
+ $retLicense = EPL_LICENSE;
+ }
+ elsif ($$req_license_ref == LGPL_LICENSE)
+ {
+ $testValue = $testValueLgpl;
+ $retLicense = LGPL_LICENSE;
+ }
+
+ my $ret = 0;
+ $ret = ($$header_ref =~ m/$testValue/s);
+ if (!$ret)
+ {
+ # Check the rest of file
+ $ret = ($$filecontent_ref =~ m/$testValue/s);
+ }
+
+ printLog(LOG_DEBUG, "checkHeader return=$ret\n");
+
+ if ($ret)
+ {
+ $$req_license_ref = $retLicense;
+ }
+
+ return $ret;
+}
+
+
+##################################################
+# Test if file does not contain multiple licenses
+# Returns 0 if test failed
+##################################################
+sub checkNoMultipleLicenses
+{
+ my $filecontent_ref = shift;
+ my $header_ref = shift;
+ my $commentChar = shift;
+ my $fullfilename = shift;
+ my $directory = shift;
+
+ my $usedLicense = SFL_LICENSE;
+ my $licenseCnt = 0;
+ if (checkHeader($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory, \$usedLicense))
+ {
+ printLog(LOG_DEBUG, "checkNoMultipleLicenses SFL: $fullfilename\n");
+ $licenseCnt++;
+ }
+
+ $usedLicense = EPL_LICENSE;
+ if (checkHeader($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory, \$usedLicense))
+ {
+ printLog(LOG_DEBUG, "checkNoMultipleLicenses EPL: $fullfilename\n");
+ $licenseCnt++;
+ }
+
+ $usedLicense = LGPL_LICENSE;
+ if (checkHeader($filecontent_ref, $header_ref, $commentChar, $fullfilename, $directory, \$usedLicense))
+ {
+ printLog(LOG_DEBUG, "checkNoMultipleLicenses LGPL: $fullfilename\n");
+ $licenseCnt++;
+ }
+
+ if ($licenseCnt > 1)
+ {
+ return 0; # check failed
+ }
+ return 1;
+}
+
+##################################################
+# Change distribution value
+# Can also be called with empty file content
+##################################################
+sub handleDistributionValue
+{
+ my $filecontent_ref = shift;
+ my $filename = shift;
+ my $content = $$filecontent_ref;
+
+ if ($optVerify)
+ {
+ # Ignored
+ return LICENSE_NONE;
+ }
+
+ $content =~ s/\n//g; # Remove all new-lines
+ $content =~ s/^\s+//g; # trim left
+ $content =~ s/\s+$//g; # trim right
+
+ if ($content ne "" && $content ne ZERO_DISTRIBUTION_VALUE)
+ {
+ if ($optEpl && ($content eq SFL_DISTRIBUTION_VALUE ))
+ {
+ # Allow switching SFL to EPL
+ $$filecontent_ref = EPL_DISTRIBUTION_VALUE;
+ printLog(LOG_INFO, "Distribution value changed from $content to $$filecontent_ref: $filename\n");
+ return LICENSE_CHANGED;
+ }
+ else
+ {
+ # Otheriwise do not touch non-zero files ! (agreed with build team)
+ $ignoreCount++;
+ return LICENSE_NONE;
+ }
+ }
+
+ if ($optOem)
+ {
+ # Leave existing (or missing) value as it was
+ return LICENSE_NONE;
+ }
+ elsif ($optEpl)
+ {
+ $$filecontent_ref = EPL_DISTRIBUTION_VALUE;
+ printLog(LOG_INFO, "Distribution value changed from $content to $$filecontent_ref: $filename\n");
+ return LICENSE_CHANGED;
+ }
+ else # SFL
+ {
+ $$filecontent_ref = SFL_DISTRIBUTION_VALUE;
+ printLog(LOG_INFO, "Distribution value changed from $content to $$filecontent_ref: $filename\n");
+ return LICENSE_CHANGED;
+ }
+
+ return LICENSE_NONE;
+
+}
+
+##################################################
+# Select proper
+##################################################
+sub licenceIdForOption
+{
+ if ($optEpl)
+ {
+ return EPL_LICENSE;
+ }
+ elsif ($optLgpl)
+ {
+ return LGPL_LICENSE;
+ }
+ else # Must be
+ {
+ return SFL_LICENSE;
+ }
+}
+
+
+##################################################
+# Select proper header
+##################################################
+sub headerOf
+{
+ my $style = shift;
+
+ if ($style < 0 || $style > 1)
+ {
+ printLog(LOG_ALWAYS, "INTERNAL ERROR: Header index out of bounds:$style. Exiting.\n");
+ exit 1;
+ }
+
+ my $ref;
+ if ($optEpl)
+ {
+ $ref = $EplHeaders[$style];
+ }
+ elsif ($optLgpl)
+ {
+ $ref = $LgplHeaders[$style];
+ }
+ else # SFL
+ {
+ $ref = $SflHeaders[$style];
+ }
+
+ # Return the actual value
+ return $$ref;
+}
+
+##################################################
+# Select proper partial header
+##################################################
+sub partialHeaderOf
+{
+ my $license = shift;
+ my $commentChar = shift;
+ my $testValue_ref = shift;
+
+ my $ref;
+ my $ref2;
+ if ($license eq EPL_LICENSE)
+ {
+ $ref = $EplHeaders[2];
+ $ref2 = $EplHeaders[3];
+ }
+ elsif ($license eq S60_LICENSE)
+ {
+ $ref = $S60Headers[2];
+ $ref2 = $S60Headers[3];
+ }
+ elsif ($license eq LGPL_LICENSE)
+ {
+ $ref = $LgplHeaders[2];
+ $ref2 = $LgplHeaders[3];
+ }
+ elsif ($license eq SFL_LICENSE)
+ {
+ # SFL License
+ $ref = $SflHeaders[2];
+ $ref2 = $SflHeaders[3]; # return value
+ }
+ else
+ {
+ printLog(LOG_ALWAYS, "INTERNAL ERROR: Invalid license parameter :$license. Exiting.\n");
+ exit 1;
+ }
+
+ # Switch to proper comment char
+ my $ret = $$ref;
+ $ret =~ s/$CC/$commentChar/g; # Replace the proper comment starter character
+
+ # Return values
+ $$testValue_ref = $$ref2;
+ return $ret;
+}
+
+
+##################################################
+# Print result line
+##################################################
+sub normalizeCppComment
+{
+ my $header_regexp2 = shift;
+ my $filecontent = shift;
+ my $oldheader_ref = shift; # in/out
+
+
+ # Normalize the C++ header syntax back to C++ in the file content
+ # in order to standardize stuff later on
+ $$oldheader_ref =~ s/(\/){3,}/\/\//g; # replace ///+ back to //
+ $$oldheader_ref =~ s/\/\//*/g; # Replace now // with *
+ $$oldheader_ref = "/*\n" . $$oldheader_ref . "*/\n"; # Add /* and */ markers
+
+ # Created saved modified file content into memory
+ # This is the best way to do this.
+ my $ret = $filecontent;
+ $ret =~ s/$header_regexp2/$$oldheader_ref/; # Note /s not used by purpose !
+ return $ret;
+}
+
+
+
+##################################################
+# Print result line
+##################################################
+sub printResult
+{
+ my $text = shift;
+
+ if ($outputfile)
+ {
+ print OUTPUT $text;
+ }
+ else
+ {
+ print $text;
+ }
+
+ printLog(LOG_DEBUG(), $text);
+
+}
+
+##################################################
+# Print log line
+##################################################
+sub printLog
+{
+ my $loglevel = shift;
+ my $text = shift;
+
+ if ($loglevel > $optLogLevel)
+ {
+ return; # No logging
+ }
+ if ($logFile)
+ {
+ print LOG $LOGTEXTS[$loglevel] . $text;
+ }
+
+ return 0;
+}
+
+
+##################################################
+# Print log line
+##################################################
+sub printLogStatisticNumber
+{
+ my $number = shift;
+ my $loglevel = shift;
+ my $text = shift; # Should contains %d where to put the number
+
+ if ($number == 0)
+ {
+ return; # No logging
+ }
+
+ if ($text =~ m/\%d/)
+ {
+ $text =~ s/\%d/$number/;
+ }
+ else
+ {
+ # Add number to the beginning of text
+ $text = $number . " " . $text;
+ }
+
+ if ($loglevel > $optLogLevel)
+ {
+ return; # No logging
+ }
+ if ($logFile)
+ {
+ print LOG $LOGTEXTS[$loglevel] . $text;
+ }
+
+ return 0;
+}
+
+
+##################################################
+# Read the content of old output
+##################################################
+sub readOldOutput
+{
+ my($filename) = shift;
+ my $fh = new FileHandle "<$filename";
+ if (!defined($fh))
+ {
+ printLog(LOG_ERROR, "Could not open file $filename for read\n");
+ return;
+ }
+
+ my @lines = <$fh>;
+ my $line;
+ foreach $line (@lines)
+ {
+ my (@parts) = split(/\,/,$line); # Split line with "," separator
+ if ($parts[2] =~ m/$IGNORE_MAN/i)
+ {
+ my $fullfilename = lc($parts[4]);
+ $fullfilename =~ s/\\/\//g; # Standardize name
+ $manualIgnoreFileHash{$fullfilename} = "1" ; # Just some value
+ printLog(LOG_DEBUG, "Manually ignoring file:$fullfilename\n");
+ }
+ }
+
+ close ($fh);
+}
+
+##################################################
+# Read configuation file which has the format:
+# sf-update-licence-header-config-1.0
+##################################################
+sub readConfig
+{
+ my ($fname) = @_;
+
+ open(IN,$fname) || die "Unable to open file: \"$fname\" for reading.";
+ LINE:
+ while(<IN>)
+ {
+ chomp;
+ # tr/A-Z/a-z/; # Do not lowercase pattern
+ my $line = $_;
+ $line =~ s/^\s+//; # trim left
+ $line =~ s/\s+$//; # trim right
+
+ next LINE if length($line) == 0; # # Skip empty lines
+ next LINE if ($line =~ /^\#.*/); # Skip comments;
+
+ if ($line =~ /^sf-update-licence-header-config.*/i)
+ {
+ my ($tmp1, $tmp2) = split(/sf-update-licence-header-config-/,$line); # Get version
+ $configVersion = $tmp2;
+ }
+ elsif ($line =~ /^sf-distribution-id/i)
+ {
+ my ($tmp, @parts) = split(/[\s\t]+/,$line); # space as separator
+ my $cnt = @parts;
+ push(@sfDistributionIdArray, @parts);
+ my $cnt = @sfDistributionIdArray;
+ printLog(LOG_DEBUG, "readConfig:sfDistributionIdArray count:$cnt\n");
+ }
+ elsif ($line =~ /^sf-generated-header/i)
+ {
+ my ($tmp, @parts) = split(/[\s\t]+/,$line); # space as separator
+ my $cnt = @parts;
+ push(@sfGeneratedPatternArray, @parts);
+ my $cnt = @sfGeneratedPatternArray;
+ printLog(LOG_DEBUG, "readConfig:sfGeneratedPatternArray count:$cnt\n");
+ }
+ }
+
+ # Pre-compile here the source line pattern
+ close (IN);
+}
+
+
+##################################################
+# Test ID is under SF distribution
+##################################################
+sub isSFDistribution
+{
+ my $id = shift;
+
+ if (($id == SFL_DISTRIBUTION_VALUE) || ($id == EPL_DISTRIBUTION_VALUE))
+ {
+ # Implicit case
+ return 1;
+ }
+
+ my $otherOkId = grep { $_ eq $id } @sfDistributionIdArray; # Use exact match
+ return $otherOkId;
+}
+
+##################################################
+# Test header contains generated file pattern
+##################################################
+sub isGeneratedHeader
+{
+ my $header_ref = shift;
+
+ my $count = grep { $$header_ref =~ m/$_/is } @sfGeneratedPatternArray;
+ return $count;
+}
+
+
+##################################################
+# MAIN
+##################################################
+
+GetOptions(
+ 'h|help' => \$help, #print help message
+ 'm|modify' => \$optModify, #Allow modifications
+ 'c|create' => \$optCreate, #Create missing file
+ 'output:s' => \$outputfile, #Output (result) file
+ 'ignorefile:s' => \$ignorefilepattern, #Ignore file pattern
+ 'oldoutput:s' => \$oldOutputFile, #Old output file
+ 'log:s' => \$logFile, # Log file
+ 'verbose:i' => \$optLogLevel, # Logging level
+ 'epl' => \$optEpl, # Switch file header to EPL one
+ 'lgpl' => \$optLgpl, # Switch file header LGPL v2.1
+ 'oem' => \$optOem, # Switch back S60 header for OEM release.
+ 'eula' => \$optOem, # Switch back S60 header for EULA (End-User License Agreement) release. Same as OEM
+ 'append' => \$optAppend, # Append result files
+ 'verify' => \$optVerify, # Verifies files has correct header
+ 'configfile:s' => \$configFile,
+ 'description!' => \$optDescription, # output missing description
+ 'okoutput!' => \$optOutputOK # output also OK entries
+ );
+
+die $usage if $#ARGV<0;
+die $usage if $help;
+
+if ($logFile)
+{
+ my $openmode = ">" . ($optAppend ? ">" : "");
+ open (LOG, "$openmode$logFile") || die "Couldn't open $openmode$logFile\n"; # Can not call printLog
+ LOG->autoflush(1); # Force flush
+}
+
+printLog(LOG_INFO, "========================\n");
+
+if ($oldOutputFile && $optVerify)
+{
+ readOldOutput($oldOutputFile);
+}
+
+if (!$configFile)
+{
+ $configFile = "$Bin/SFUpdateLicenceHeader.cfg";
+}
+
+if ($configFile && -e $configFile)
+{
+ &readConfig($configFile);
+}
+
+if (!$ignorefilepattern)
+{
+ # Set decent default value
+ if ($optOem)
+ {
+ # Scan through internal stuff all source dirs just in case
+ $ignorefilepattern = "(_ccmwaid\.inf|\.svn)";
+ }
+ else
+ {
+ $ignorefilepattern = "(abld\.bat|_ccmwaid\.inf|\.svn|/docs/|/internal/|/doc/)";
+ }
+}
+
+if ($optEpl)
+{
+ printLog(LOG_INFO, "Option -epl used\n");
+}
+if ($optLgpl)
+{
+ printLog(LOG_INFO, "Option -lgpl used\n");
+}
+if ($optOem)
+{
+ printLog(LOG_INFO, "Option -oem used\n");
+ # Modify ignore to contain also internal dirs just in case
+}
+if ($optModify)
+{
+ printLog(LOG_INFO, "Option -modify used\n");
+}
+if ($optVerify)
+{
+ printLog(LOG_INFO, "Option -verify used\n");
+}
+if ($optCreate)
+{
+ printLog(LOG_INFO, "Option -create used\n");
+}
+
+if ($ignorefilepattern)
+{
+ printLog(LOG_INFO, "Option -ignorefile has value: $ignorefilepattern\n");
+}
+
+my $startTime = time;
+
+if ($outputfile)
+{
+ my $openmode = ">" . ($optAppend ? ">" : "");
+ open (OUTPUT, "$openmode$outputfile") || die "Couldn't open $outputfile\n";
+ OUTPUT->autoflush(1); # Force flush
+}
+
+if (! -e $ARGV[0] )
+{
+ printLog(LOG_ERROR, "$ARGV[0] not found\n");
+ if ($logFile)
+ {
+ close LOG;
+ }
+ exit(1);
+}
+
+printLog(LOG_INFO,"SFUpdateLicenceHeader.pl version " . VERSION . " statistics:\n");
+printLog(LOG_INFO, "Directory/file=@ARGV\n");
+
+#
+# Process files in the given directory recursively
+#
+# NOTE : "no_chdir" option not used --> find changes the current working directory
+find({ wanted => \&process_file, postprocess => \&postprocess, preprocess => \&preprocess }, @ARGV);
+
+if ($outputfile)
+{
+ close OUTPUT;
+}
+
+my $elapsedTime = time - $startTime;
+
+printLogStatisticNumber($fileCount, LOG_INFO, "%d files checked\n") ;
+if ($optModify)
+{
+ printLogStatisticNumber($modifiedFileCount, LOG_INFO, "%d files modified \n") ;
+}
+else
+{
+ printLogStatisticNumber($willModifiedFileCount, LOG_INFO, "%d will be modified \n") ;
+}
+printLogStatisticNumber($ignoreCount, LOG_INFO, "%d files ignored.\n") ;
+printLogStatisticNumber($unrecogCount, LOG_INFO, "%d files not recognized.\n") ;
+if ($optVerify)
+{
+ for (my $i=0; $i < @verifyFailedCountMsgs; $i++)
+ {
+ printLogStatisticNumber($verifyFailedCount[$i], LOG_INFO, "Verify statistics:$verifyFailedCountMsgs[$i]=%d.\n") ;
+ }
+}
+elsif (!$optOem)
+{
+ printLogStatisticNumber($noDescrcount, LOG_INFO, "%d files has no Description.\n") ;
+ printLogStatisticNumber($NokiaCopyrCount, LOG_INFO, "%d files has Nokia copyright.\n") ;
+ printLogStatisticNumber($ExternalToNokiaCopyrCount, LOG_INFO, "%d files moved also to Nokia.\n") ;
+ printLogStatisticNumber($otherCopyrCount, LOG_INFO, "%d files has non-nokia copyright.\n") ;
+ printLogStatisticNumber($NoCopyrCount, LOG_INFO, "%d files has no copyright.\n") ;
+ printLogStatisticNumber($UnclearCopyrCount, LOG_INFO, "%d files has UNCLEAR copyright.\n") ;
+ printLogStatisticNumber($createCount, LOG_INFO, "%d new files.\n") ;
+ if ($optEpl)
+ {
+ printLogStatisticNumber($SflToEplChanges, LOG_INFO, "%d files changes from SFL to EPL license.\n") ;
+ }
+ else
+ {
+ printLogStatisticNumber($EplToSflChanges, LOG_INFO, "%d files changes from SFL to EPL license.\n") ;
+ }
+}
+else
+{
+ printLogStatisticNumber($SflToS60Changes, LOG_INFO, "%d files changes from SFL to S60 license.\n") ;
+ # printLog($EplToS60Changes, LOG_INFO, "%d files changes from EPL to S60 license.\n") ;
+ printLogStatisticNumber($LicenseChangeErrors, LOG_INFO, "%d errors upon license change.\n") ;
+}
+
+printLog(LOG_INFO,"Time elapsed $elapsedTime.\n") ;
+
+if ($logFile)
+{
+ close LOG;
+}
+