Update featuredatabase.xml, taking care not to include "CoverDisplay" - Bug 2049, Bug 1924, Bug 1676
# 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;
}