bldsystemtools/commonbldutils/iprtool.pl
branchRCL_3
changeset 24 d90029decf65
parent 20 a9d4531388d0
child 33 54aa4a06a075
child 34 5e522efbae7b
equal deleted inserted replaced
20:a9d4531388d0 24:d90029decf65
     1 #!perl
       
     2 # Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 
       
    17 use strict;
       
    18 
       
    19 use Getopt::Long;
       
    20 use Cwd;
       
    21 use XML::Simple;
       
    22 use FindBin;
       
    23 use lib "$FindBin::Bin";
       
    24 
       
    25 my $Now = &Today;
       
    26 my $IncludesRestrictedSource = 0;
       
    27 my $ZippedCatA = 0;
       
    28 my $ZippedCatX = 0;
       
    29 
       
    30 my $WorkPath = uc cwd;
       
    31 $WorkPath =~s-/-\\-go;            # replace forward slash with backslash
       
    32 $WorkPath =~s/^(.:)(\S+)$/$2/o;   # remove drive letter
       
    33 my $WorkDrv = $1;
       
    34 $WorkPath =~s-^(.*[^\\])$-$1\\-o; # ensure it ends with a backslash
       
    35 
       
    36 my %HTMLFileErrors = ();
       
    37 my %ASCIIFileErrors = ();
       
    38 my %Components = ();
       
    39 my %ComponentsUsed = ();
       
    40 my @UnrepresentedComponents = ();
       
    41 
       
    42 my %Cmdopts = ();
       
    43 unless (GetOptions( \%Cmdopts, "cats|c=s", "dir|d=s", "export|e", "full|f:i",
       
    44         "genpkg|g=s", "help|h", "licensee|l=s", "manifest|m=s", "nosub|n", "overrideexpiry|o",
       
    45         "project|p=s", "report|r=s", "showfiles|s", "xclude|x=s", "zip|z=s",
       
    46         "outdir=s"))
       
    47   {
       
    48   print "For help, use -h option\n";
       
    49   exit 1;
       
    50   }
       
    51 
       
    52 if (@ARGV && ($ARGV[0]=~/help/io || $ARGV[0]=~/\?/io))
       
    53   {
       
    54   &Usage();
       
    55   }
       
    56   
       
    57 # Open Schedule12 File for Component name checking
       
    58 if ($Cmdopts{'report'})
       
    59 {
       
    60     my $Build = $Cmdopts{'report'};
       
    61     my $Version = $1 if ( $Build =~ /Symbian_OS_v(.*)/i );
       
    62     
       
    63     # Define the source root directory (assumes it's 3 levels up)
       
    64     my $sourcedir = Cwd::abs_path("$FindBin::Bin\\..\\..\\..");
       
    65     my $Schedule12File = "$sourcedir\\os\\deviceplatformrelease\\symbianosbld\\cedarutils\\Symbian_OS_v"."$Version"."_Schedule12.xml";
       
    66     my $xml = new XML::Simple;
       
    67     my $Schedule12 = $xml->XMLin($Schedule12File);
       
    68     
       
    69     my $CommonReplaceable = %$Schedule12->{'CR'};
       
    70     for (keys %$CommonReplaceable)
       
    71     {
       
    72         $Components{$_} = "Common Replaceable";
       
    73         $ComponentsUsed{$_} = 0;
       
    74     }
       
    75     
       
    76     my $CommonSymbian = %$Schedule12->{'CS'};
       
    77     for (keys %$CommonSymbian)
       
    78     {
       
    79         $Components{$_} = "Common Symbian";
       
    80         $ComponentsUsed{$_} = 0;
       
    81     }
       
    82     
       
    83     my $OptionalReplaceable = %$Schedule12->{'OR'};
       
    84     for (keys %$OptionalReplaceable)
       
    85     {
       
    86         $Components{$_} = "Optional Replaceable";
       
    87         $ComponentsUsed{$_} = 0;
       
    88     }
       
    89     
       
    90     my $OptionalSymbian = %$Schedule12->{'OS'};
       
    91     for (keys %$OptionalSymbian)
       
    92     {
       
    93         $Components{$_} = "Optional Symbian";
       
    94         $ComponentsUsed{$_} = 0;
       
    95     }
       
    96     
       
    97     my $ReferenceTest = %$Schedule12->{'REF'};
       
    98     for (keys %$ReferenceTest)
       
    99     {
       
   100         $Components{$_} = "Reference/Test";
       
   101         $ComponentsUsed{$_} = 0;
       
   102     }
       
   103     
       
   104     my $ReferenceTest = %$Schedule12->{'TEST'};
       
   105     for (keys %$ReferenceTest)
       
   106     {
       
   107         $Components{$_} = "Reference/Test";
       
   108         $ComponentsUsed{$_} = 0;
       
   109     }
       
   110     
       
   111     my $ReferenceTest = %$Schedule12->{'RT'};	# v9.1 style combined Ref/Test
       
   112     for (keys %$ReferenceTest)
       
   113     {
       
   114         $Components{$_} = "Reference/Test";
       
   115         $ComponentsUsed{$_} = 0;
       
   116     }
       
   117 }
       
   118 
       
   119 # Handle -h flag
       
   120 # --------------
       
   121 if ($Cmdopts{'help'})
       
   122   {
       
   123   &Usage();
       
   124   }
       
   125 
       
   126 # --------------
       
   127 # Handle -c flag
       
   128 # --------------
       
   129 my $Categories = 'EFGOT';
       
   130 if ($Cmdopts{'cats'})
       
   131   {
       
   132   if ($Cmdopts{'cats'} =~ /[^A-GIOTX]/i)
       
   133     {
       
   134     &NotifyError("Unrecognised category list \"$Cmdopts{'cats'}\" ignored");
       
   135     }
       
   136   else
       
   137     {
       
   138     $Categories = uc($Cmdopts{'cats'});
       
   139     }
       
   140   }
       
   141 
       
   142 # --------------
       
   143 # Handle -d flag
       
   144 # --------------
       
   145 my @TopDirs;
       
   146 if (!$Cmdopts{'dir'})
       
   147   {
       
   148   $TopDirs[0] = $WorkPath;
       
   149   }
       
   150 else
       
   151   {
       
   152   if (!(-e $Cmdopts{'dir'}))
       
   153     {
       
   154     die "$Cmdopts{'dir'} does not exist\n";
       
   155     }
       
   156   if (-d $Cmdopts{'dir'})
       
   157     {
       
   158     $TopDirs[0] = $Cmdopts{'dir'};
       
   159     }
       
   160   else
       
   161     {
       
   162     @TopDirs = &ReadDirFile($Cmdopts{'dir'});
       
   163     }
       
   164   @TopDirs = &MakeAbs($WorkPath, @TopDirs);
       
   165   foreach my $p (@TopDirs)
       
   166     {
       
   167     $p = &ValidateIncPath($p);
       
   168     }
       
   169   }
       
   170 
       
   171 # --------------
       
   172 # Handle -e flag
       
   173 # --------------
       
   174 my $ForceExport = $Cmdopts{'export'} ? 1 : 0;
       
   175 
       
   176 # --------------
       
   177 # Handle -f flag
       
   178 # --------------
       
   179 my $Full = $Cmdopts{'full'} || 0;
       
   180 
       
   181 
       
   182 # --------------
       
   183 # Handle -g flag
       
   184 # --------------
       
   185 my $PkgFile;
       
   186 my $GenPkg = $Cmdopts{'genpkg'} ? 1 : 0;
       
   187 if ($GenPkg)
       
   188   {
       
   189   $PkgFile = $Cmdopts{'genpkg'};
       
   190   if (index($PkgFile, "\.") < 0)
       
   191     {
       
   192     $PkgFile .= "\.xml";
       
   193     }
       
   194   if ((-e $PkgFile) and (-f $PkgFile))
       
   195     {
       
   196     unlink ($PkgFile) or die "Can't overwrite $PkgFile\n";
       
   197     }
       
   198   open PKGLIST, ">$PkgFile" or die "Can't open $PkgFile\n";
       
   199   }
       
   200 
       
   201 
       
   202 # --------------
       
   203 # Handle -l flag
       
   204 # --------------
       
   205 my $Recipient = 'generic';
       
   206 if ($Cmdopts{'licensee'})
       
   207   {
       
   208   $Recipient = lc($Cmdopts{'licensee'});
       
   209   }
       
   210 
       
   211 # --------------
       
   212 # Handle -m flag
       
   213 # --------------
       
   214 my $Manifest = $Cmdopts{'manifest'} ? 1 : 0;
       
   215 if ($Manifest)
       
   216   {
       
   217   my $MfsFile = $Cmdopts{'manifest'};
       
   218   if (index($MfsFile, "\.") < 0)
       
   219     {
       
   220     $MfsFile .= "\.txt";
       
   221     }
       
   222   if ((-e $MfsFile) and (-f $MfsFile))
       
   223     {
       
   224     unlink ($MfsFile) or die "Can't overwrite $MfsFile\n";
       
   225     }
       
   226   open MFSLIST, ">$MfsFile" or die "Can't open $MfsFile\n";
       
   227   }
       
   228 
       
   229 
       
   230 # --------------
       
   231 # Handle -n flag
       
   232 # --------------
       
   233 my $SubDirs = $Cmdopts{'nosub'} ? 0 : 1;
       
   234 
       
   235 # --------------
       
   236 # Handle -o flag
       
   237 # --------------
       
   238 my $OverrideExpiry = $Cmdopts{'overrideexpiry'} ? 1 : 0;
       
   239 
       
   240 # --------------
       
   241 # Handle -outdir flag
       
   242 # --------------
       
   243 my $outdir = $Cmdopts{'outdir'};
       
   244 
       
   245 # --------------
       
   246 # Handle -p flag
       
   247 # --------------
       
   248 my $Project = 'generic';
       
   249 if ($Cmdopts{'project'})
       
   250   {
       
   251   $Project = lc($Cmdopts{'project'});
       
   252   }
       
   253 
       
   254 # --------------
       
   255 # Handle -s flag
       
   256 # --------------
       
   257 my $ShowFiles = $Cmdopts{'showfiles'} ? 1 : 0;
       
   258 
       
   259 # --------------
       
   260 # Handle -x flag
       
   261 # --------------
       
   262 my @XDirs;
       
   263 if (!$Cmdopts{'xclude'})
       
   264   {
       
   265   $XDirs[0] = "";
       
   266   }
       
   267 else
       
   268   {
       
   269   if (!(-e $Cmdopts{'xclude'}))
       
   270     {
       
   271     die "Exclusion $Cmdopts{'xclude'} does not exist\n";
       
   272     }
       
   273   if (-d $Cmdopts{'xclude'})
       
   274     {
       
   275     $XDirs[0] = $Cmdopts{'xclude'};
       
   276     }
       
   277   else
       
   278     {
       
   279     @XDirs = &ReadDirFile($Cmdopts{'xclude'});
       
   280     }
       
   281   @XDirs = &MakeAbs($WorkPath, @XDirs);
       
   282   foreach my $p (@XDirs)
       
   283     {
       
   284     $p = &ValidateExcPath($p);
       
   285     }
       
   286   }
       
   287 
       
   288 # --------------
       
   289 # Handle -z flag
       
   290 # --------------
       
   291 my $ZipFile;
       
   292 my $ZipTmpFile;
       
   293 my $ZipLogFile;
       
   294 my $Zip = $Cmdopts{'zip'} ? 1 : 0;
       
   295 if ($Zip)
       
   296   {
       
   297    if ( &FindZip == 0 )
       
   298    {
       
   299       die "Cannot find zip.exe in path. $?\n";
       
   300    }
       
   301 
       
   302   $ZipFile = $Cmdopts{'zip'};
       
   303   if (index($ZipFile, "\.") < 0)
       
   304     {
       
   305     $ZipFile .= "\.zip";
       
   306     }
       
   307   $ZipLogFile = $ZipFile . "log";
       
   308   $ZipTmpFile = $ZipFile . "tmp";
       
   309   if ((-e $ZipFile) and (-f $ZipFile))
       
   310     {
       
   311     unlink ($ZipFile) or die "Can't overwrite $ZipFile\n";
       
   312     }
       
   313   if ((-e $ZipTmpFile) and (-f $ZipTmpFile))
       
   314     {
       
   315     unlink ($ZipTmpFile) or die "Can't overwrite $ZipTmpFile\n";
       
   316     }
       
   317   open ZIPLIST, ">$ZipTmpFile" or die "Can't open $ZipTmpFile\n";
       
   318   }
       
   319 
       
   320 
       
   321 
       
   322 # --------------
       
   323 # print Pkg header
       
   324 # --------------
       
   325 
       
   326   if ($GenPkg)
       
   327     {
       
   328     &PkgPrint ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
       
   329     &PkgPrint ("\n");
       
   330 
       
   331     &PkgPrint ("<packagedef version=\"1.0\">\n");
       
   332     &PkgPrint ("   <package name=\"$PkgFile\" major-version=\"0\" minor-version=\"0\">\n");
       
   333     &PkgPrint ("     <supplier>Symbian Ltd</supplier>\n");
       
   334     &PkgPrint ("     <sdk-version>7.0</sdk-version>\n");
       
   335     &PkgPrint ("   </package>\n");
       
   336     &PkgPrint ("\n");
       
   337     &PkgPrint ("   <manifest>\n");
       
   338     }
       
   339 
       
   340 
       
   341 #------ Do the report header ------
       
   342 my $temp ="IPR Report, ".&DateValToStr($Now);
       
   343 &DataPrint("$temp\n");
       
   344 $temp = '-' x length($temp);
       
   345 &DataPrint("$temp\n");
       
   346 
       
   347 &DataPrint ("Report type:                  ");
       
   348 if ($Full < 0)
       
   349   {
       
   350   &DataPrint ("No IPR data\n") ;
       
   351   }
       
   352 else
       
   353   {
       
   354   &DataPrint ($Full ? "Full IPR data\n" : "Reduced IPR data\n");
       
   355   }
       
   356 &DataPrint ("Recipient:                    ", ucfirst($Recipient), "\n");
       
   357 &DataPrint ("Include DTI restricted files: ", $ForceExport ? 'Yes' : 'No', "\n");
       
   358 &DataPrint ("Include time-expired files:   ", $OverrideExpiry ? 'Yes' : 'No', "\n");
       
   359 &DataPrint ("List selected files:          ", $ShowFiles ? 'Yes' : 'No', "\n");
       
   360 &DataPrint ("\n");
       
   361 
       
   362 #------ Do header for standard section ------
       
   363 $temp ="Standard source for ".ucfirst($Recipient);
       
   364 &DataPrint ("$temp\n");
       
   365 $temp = '-' x length($temp);
       
   366 &DataPrint ("$temp\n");
       
   367 &DataPrint ("Categories:                   $Categories\n");
       
   368 &DataPrint ("Include subdirectories:       ", $SubDirs ? 'Yes' : 'No', "\n");
       
   369 &DataPrint ("Top level directories:\n");
       
   370 foreach my $name (@TopDirs)
       
   371   {
       
   372   &DataPrint ("                              $name\n");
       
   373   }
       
   374 &DataPrint ("\n");
       
   375 
       
   376 &ProcessDir(@TopDirs, $SubDirs, 1, $Manifest);
       
   377 
       
   378 #------ Do optional header for extra section ------
       
   379 if (($Project ne 'generic') and (-e "$Project\.extra"))
       
   380   {
       
   381   my @ExtraDirs = ReadDirFile("$Project\.extra");
       
   382   @ExtraDirs = &MakeAbs($WorkPath, @ExtraDirs);
       
   383   foreach my $p (@ExtraDirs)
       
   384     {
       
   385     $p = &ValidateIncPath($p);
       
   386     }
       
   387   &DataPrint ("\n");
       
   388   $temp ="Extra source for ".ucfirst($Project);
       
   389   &DataPrint ("$temp\n");
       
   390   $temp = '-' x length($temp);
       
   391   &DataPrint ("$temp\n");
       
   392   $Categories = 'ABCDEFGIOTX';
       
   393   &DataPrint ("Categories:                   $Categories\n");
       
   394   &DataPrint ("Include subdirectories:       No\n");
       
   395   &DataPrint ("Additional directories:\n");
       
   396   foreach my $name (@ExtraDirs)
       
   397     {
       
   398     if ($name)
       
   399       {
       
   400       &DataPrint ("                              $name\n");
       
   401       }
       
   402     }
       
   403   &DataPrint ("\n");
       
   404 
       
   405   &ProcessDir(@ExtraDirs, 0, 0, 0); # Note, no extra directories in a product manifest
       
   406   }
       
   407 
       
   408 if ($Zip)
       
   409   {
       
   410    if ( &FindZip == 0 )
       
   411    {
       
   412       die "Cannot find zip.exe in path. $?\n";
       
   413    }
       
   414 
       
   415    close ZIPLIST;
       
   416    `zip -@ $ZipFile <$ZipTmpFile >$ZipLogFile`;
       
   417    unlink ($ZipTmpFile);
       
   418   }
       
   419 
       
   420 if ($Manifest)
       
   421   {
       
   422   close MFSLIST;
       
   423   }
       
   424 
       
   425 # --------------------------
       
   426 # print Pkg footer and close
       
   427 # --------------------------
       
   428 
       
   429 if ($GenPkg)
       
   430   {
       
   431   &PkgPrint ("   </manifest>\n");
       
   432   &PkgPrint ("</packagedef>\n");
       
   433   close PKGLIST;
       
   434   }
       
   435 
       
   436 #------ Do optional warning for restricted export source ------
       
   437 &ExportWarning() if ($IncludesRestrictedSource);
       
   438 &NotifyWarning("zip file contains Category A source\n") if ($ZippedCatA);
       
   439 &NotifyWarning("zip file contains uncategorised source\n") if ($ZippedCatX);
       
   440 
       
   441 if ($Cmdopts{'report'})
       
   442     {
       
   443     #------ Produce Distribution Policy File Error Report --------
       
   444     my ( $s, $min, $hour, $mday, $mon, $year, $w, $y, $i)= localtime(time);
       
   445     $year+= 1900;
       
   446     $mon++;
       
   447     
       
   448     my $builddir = $outdir;
       
   449     if (!defined $builddir)
       
   450     	{
       
   451     	# Assume default setup for Symbian build machines...
       
   452     	$builddir = Cwd::abs_path("$FindBin::Bin\\..\\..\\..\\..");
       
   453     	$builddir.= "\\logs\\cedar";
       
   454     	}
       
   455     open HTMLOUTFILE, ">> $builddir\\$Cmdopts{'report'}_Distribution_Policy_Report.html";
       
   456     open ASCIIOUTFILE, ">> $builddir\\$Cmdopts{'report'}_Distribution_Policy_Report.txt";
       
   457     
       
   458     foreach my $key (sort keys %ComponentsUsed)
       
   459     {
       
   460         push @UnrepresentedComponents, $key if ($ComponentsUsed{$key} == 0);
       
   461     }
       
   462     
       
   463     my $UnrepCKLComponents = @UnrepresentedComponents;
       
   464     my $NonCompliantFiles = scalar(keys %ASCIIFileErrors);
       
   465     
       
   466     print HTMLOUTFILE <<HEADING_EOF;
       
   467     <html><head><title>Distribution Policy File Report for $Cmdopts{'report'}</title></head>
       
   468     <body>
       
   469     <h1><center>Distribution Policy File Report<br>for<br>$Cmdopts{'report'}</center></h1>
       
   470     <h2><center>Created - $mday/$mon/$year</center></h2>
       
   471     <hr width=60% size=1 noshade> <p><p><p><p>
       
   472     
       
   473     <TABLE BORDER Align=center>
       
   474     <TH COLSPAN=2><font color=red>Report Summary</font></TH>
       
   475     <TR><TD>Total number of Non-compliant Files</TD><TD><b>$NonCompliantFiles</b></TD></TR>
       
   476     <TR><TD>Total number of Unrepresented CKL Components</TD><TD><b>$UnrepCKLComponents</b></TD></TR>
       
   477     </TABLE><p><p><p><p>
       
   478     
       
   479     <TABLE BORDER ALIGN=center>
       
   480     <TH COLSPAN=2>Non-Compliant Files</font></TH>
       
   481     <TR><TH>File Location</TH><TH>Errors</TH></TR>
       
   482 HEADING_EOF
       
   483     
       
   484     print ASCIIOUTFILE <<HEADING_EOF;
       
   485 Distribution Policy File Report for $Cmdopts{'report'}
       
   486 Created - $mday/$mon/$year
       
   487 ================================
       
   488     
       
   489 HEADING_EOF
       
   490 
       
   491     foreach my $key (sort keys %ASCIIFileErrors)
       
   492     {
       
   493         my $path = lc $key;
       
   494         $path =~ s/^.*?\\master\\.*?\\src\\/\\src\\/i;
       
   495         print HTMLOUTFILE "<TR><TD><font face=verdana size=4>$path</TD><TD>@{$HTMLFileErrors{$key}}</TD></TR>";
       
   496         print ASCIIOUTFILE "@{$ASCIIFileErrors{$key}}";
       
   497     }
       
   498     print HTMLOUTFILE "</TABLE><p><p><p><p>";
       
   499     
       
   500     if (@UnrepresentedComponents != 0)
       
   501     {
       
   502         print HTMLOUTFILE "<TABLE BORDER ALIGN=center>";
       
   503         print HTMLOUTFILE "<TR><TH>Unrepresented Components</TH></TR>";
       
   504         foreach my $component (@UnrepresentedComponents)
       
   505         {
       
   506             print HTMLOUTFILE "<TR><TD>Component '$component' as recorded in
       
   507                 Schedule 12 of the CKL has no representation in any of the source directories that are used to build this product</TD></TR>";
       
   508             
       
   509             print ASCIIOUTFILE "Unrepresented Component, Component '$component' as recorded in Schedule 12 of the CKL has no representation in any of the source directories that are used to build this product.\n";
       
   510         }
       
   511         print HTMLOUTFILE "</TABLE>";
       
   512     }
       
   513     
       
   514     close HTMLOUTFILE;
       
   515     close ASCIIOUTFILE;
       
   516     }
       
   517 
       
   518 
       
   519 
       
   520 sub ProcessDir
       
   521 {
       
   522 my $ForManifest = pop @_;
       
   523 my $ObeyExcludes = pop @_;
       
   524 my $Subdirs =  pop @_;
       
   525 my $Category = 'X';
       
   526 my $ExpiryDate = 0;
       
   527 my $NoExport = 0;
       
   528 my $Skip = 0;
       
   529 my $Name;
       
   530 my $FoundFile;
       
   531 my $FoundPol;
       
   532 my $PathName;
       
   533 my $Text;
       
   534 my @AllFiles;
       
   535 my @Recipients;
       
   536 my %LicExpDates;
       
   537 
       
   538 foreach $PathName (@_)
       
   539   {
       
   540   if (!$PathName) { next; }
       
   541   if ($ForManifest)
       
   542     {
       
   543     my $path = $PathName;
       
   544 #   $path =~ s/^\\//; # remove any leading backslash
       
   545     $path =~ s/\\$//; # remove any trailing backslash
       
   546     &MfsPrint ("COMPONENT\t$path\n");
       
   547     }
       
   548   if ($ObeyExcludes)
       
   549     {
       
   550     foreach my $exclude (@XDirs)
       
   551       {
       
   552       my $ex = $exclude;
       
   553       my $pn = $PathName;
       
   554       if (uc $ex eq uc $pn)
       
   555         {
       
   556         $Skip = 1;
       
   557         last;
       
   558         }
       
   559       }
       
   560     if ($Skip)
       
   561       {
       
   562       next;
       
   563       }
       
   564     }
       
   565   $FoundFile = 0;
       
   566   $FoundPol = 0;
       
   567   opendir(HERE, $PathName);
       
   568   @AllFiles = readdir(HERE);
       
   569   close(HERE);
       
   570   foreach my $Name (@AllFiles)
       
   571     {
       
   572     if (-d "$PathName$Name") { next; }
       
   573     if (lc($Name) eq 'distribution.policy')
       
   574       {
       
   575       $FoundPol = 1;
       
   576       ($Category, $ExpiryDate, $NoExport, $Text, %LicExpDates) = &IprStatus("$PathName$Name");
       
   577       
       
   578       if ($Cmdopts{'report'})
       
   579         {
       
   580         my ($HTMLErrors, $ASCIIErrors) = &CheckFileContents("$PathName$Name");
       
   581         @{$HTMLFileErrors{"$PathName"}} = @{$HTMLErrors} if (@{$HTMLErrors} > 0);
       
   582         @{$ASCIIFileErrors{"$PathName"}} = @{$ASCIIErrors} if (@{$ASCIIErrors} > 0);
       
   583         }
       
   584       }
       
   585     else
       
   586       {
       
   587       $FoundFile = 1;
       
   588       }
       
   589     }
       
   590   if ($FoundFile and (!$FoundPol)) { &NotifyError("no policy file in $PathName"); }
       
   591   if ((!$FoundFile) and $FoundPol)
       
   592     {
       
   593     &NotifyNote("unnecessary policy file in $PathName");
       
   594     $FoundFile = 1;    # Force a report of a directory containing only a policy file
       
   595     }
       
   596 
       
   597   &ConditionalRep($FoundFile, $PathName, $Category, $ExpiryDate, $NoExport, $Text, %LicExpDates);
       
   598 
       
   599   if ($Subdirs)
       
   600     {
       
   601     foreach my $Name (@AllFiles)
       
   602       {
       
   603       if (-d "$PathName$Name")
       
   604         {
       
   605         if ($Name eq '.') { next; }
       
   606         if ($Name eq '..') { next; }
       
   607         &ProcessDir("$PathName$Name\\", 1, $ObeyExcludes, 0);
       
   608         }
       
   609       }
       
   610     }
       
   611   }
       
   612 }
       
   613 
       
   614 sub CheckFileContents
       
   615 {
       
   616   my $Location = shift;
       
   617   $Location = lc $Location;
       
   618   
       
   619   my $path = $Location;
       
   620   $path =~ s/\\distribution.policy//;  # Remove file name from end of path
       
   621   
       
   622   my @HTMLFileErrors = ();
       
   623   my @ASCIIFileErrors = ();
       
   624   my $Category;
       
   625   my $OSDclass;
       
   626   my $ComponentName;
       
   627   
       
   628   my $CategoryLineFound = 0;
       
   629   my $OSClassLineFound = 0;
       
   630   
       
   631   open(DPFile, $Location);
       
   632   
       
   633   while (<DPFile>)
       
   634   {
       
   635     # Check Comment Lines
       
   636     if ($_ =~ /^\s*#(.*)$/)
       
   637     {
       
   638         if ($1 =~ /#/)
       
   639         {
       
   640             push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>Comment line contains # as part of the comment.</font><p>\n";
       
   641             push @ASCIIFileErrors, "$path, Comment line contains # as part of the comment.\n";
       
   642         }
       
   643         next;
       
   644     }
       
   645     
       
   646     # Check Source Category Line
       
   647     if ($_ =~ /^\s*Category.*$/i)
       
   648     {
       
   649         $CategoryLineFound++;
       
   650         if (!($_ =~ /^\s*Category\s+\w{1}\s*$/i))
       
   651         {
       
   652             push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>Line Syntax is incorrrect.</font><br>\n";
       
   653             push @ASCIIFileErrors, "$path, Category line syntax is incorrect.\n";
       
   654             
       
   655             if ($_ =~ /^\s*Category(.*?)\w{1}\s*(.*)$/i)
       
   656             {
       
   657                 if (!($1 =~ /^\s+$/))
       
   658                 {
       
   659                     push @HTMLFileErrors, "<font face=arial size=4 color=red>The word Category and the Source-Category should be seperated by a whitespace not '$1'.</font><br>\n";
       
   660                     push @ASCIIFileErrors, "$path, The word Category and the Source-Category should be seperated by a whitespace not '$1'.\n";
       
   661                 }
       
   662                 if ($2 ne "")
       
   663                 {
       
   664                     push @HTMLFileErrors, "<font face=arial size=4 color=red>Trailing characters '$2' after the Source-Category are not allowed.</font><br>\n";
       
   665                     push @ASCIIFileErrors, "$path, Trailing characters '$2' after the Source-Category are not allowed.\n";
       
   666                 }
       
   667                 
       
   668                 push @HTMLFileErrors, "<p>\n";
       
   669                 next;
       
   670             }
       
   671         }
       
   672         if ($_ =~ /^\s*Category\s+(\w{1})\s*$/)
       
   673         {
       
   674             $Category = uc $1;
       
   675             if ($Category !~ /[A-GIOT]/)
       
   676             {
       
   677                 push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>Category $Category is not a defined Source-Category.</font><p>\n";
       
   678                 push @ASCIIFileErrors, "$path, Category $Category is not a defined Source-Category.\n";
       
   679             }
       
   680             next;
       
   681         }
       
   682     }
       
   683     
       
   684     # Check OS Class Line
       
   685     if ($_ =~ /^\s*OSD.*$/i)
       
   686     {
       
   687         $OSClassLineFound++;
       
   688         if (!($_ =~ /\s*OSD:\s+\w+.?\w+\s+.*\s*$/i))
       
   689         {
       
   690             push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>OSD line syntax is incorrect</font><br>\n";
       
   691             push @ASCIIFileErrors, "$path, OSD line syntax is incorrect.\n";
       
   692             
       
   693             if (!($_ =~ /OSD:\s+/i))
       
   694             {
       
   695                 push @HTMLFileErrors, "<font face=arial size=4 color=red>OSD line does not begin with 'OSD: '</font><br>\n" ;
       
   696                 push @ASCIIFileErrors, "$path, OSD line does not begin with 'OSD: '.\n";
       
   697             }
       
   698             
       
   699             if ($_ =~ /OSD:\s+(.*)\s+(.*)/i)
       
   700             {
       
   701                 my $class = $1;
       
   702                 my $compname = lc $2;
       
   703                 $compname =~ s/\s+$//;
       
   704                 # Workaround for this particular string
       
   705                 if (($_ =~ /Optional:/)&&($_ =~ /Test/)&&($_ =~ /RTP/))
       
   706                 {
       
   707                     $class = "Optional: Test";
       
   708                     $compname = "rtp";
       
   709                 }
       
   710                 if ((!($class =~ /^Common Replaceable$/i))&&(!($class =~ /^Common Symbian$/i))&&(!($class =~ /^Optional Replaceable$/i))&&(!($class =~ /^Optional Symbian$/i))
       
   711                     &&(!($class =~ /^Reference\/Test$/i))&&(!($class =~ /^Reference\\Test$/i))&&(!($class =~ /^Test\/Reference$/i))&&(!($class =~ /^Test\\Reference$/i)))
       
   712                 {
       
   713                     push @HTMLFileErrors, "<font face=arial size=4 color=red>OSD Class '$class' is not a defined OSD Class.</font><br>\n" ;
       
   714                     push @ASCIIFileErrors, "$path, OSD Class '$class' is not a defined OSD Class.\n";                  
       
   715                 }
       
   716                 
       
   717                 if (!($compname =~ /[a-z]+/))
       
   718                 {
       
   719                     push @HTMLFileErrors, "<font face=arial size=4 color=red>No Component name specified on OSD line.</font><br>\n" ;
       
   720                     push @ASCIIFileErrors, "$path, No Component name specified on OSD line.\n";
       
   721                     
       
   722                 }
       
   723                 
       
   724                 foreach my $key (sort keys %ComponentsUsed)
       
   725                 {
       
   726                     my $lowercasename = lc $key;
       
   727                     $lowercasename =~ s/\s+$//;
       
   728                     if ($compname eq $lowercasename)
       
   729                     {
       
   730                         $ComponentsUsed{$key} = 1;
       
   731                         last;
       
   732                     }
       
   733                 }
       
   734             }
       
   735             push @HTMLFileErrors, "<p>\n";
       
   736             
       
   737             next;
       
   738         }
       
   739         if ($_ =~ /\s*OSD:\s+(\w+.?\w+)\s+(.*)\s*$/)
       
   740         {
       
   741             my $OSDclass = $1;
       
   742             my $ComponentName = $2;
       
   743             my $OSDLineError = 0;
       
   744             
       
   745             if ($OSDclass eq "")
       
   746             {
       
   747                 push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>OSD Class is not specified.</font><br>\n";
       
   748                 push @ASCIIFileErrors, "$path, OSD Class is not specified.\n";
       
   749                 $OSDLineError = 1;
       
   750             }
       
   751             if ($ComponentName eq "")
       
   752             {
       
   753                 if ($OSDLineError == 0)
       
   754                 {
       
   755                     push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>No Component Name specified on the OSD line.</font><br>\n";
       
   756                     push @ASCIIFileErrors, "$path, No Component Name specified on the OSD line.\n";
       
   757                     $OSDLineError = 1;
       
   758                 }
       
   759                 else
       
   760                 {
       
   761                     push @HTMLFileErrors, "<font face=arial size=4 color=red>No Component Name specified on the OSD line.</font><br>\n";
       
   762                     push @ASCIIFileErrors, "$path, No Component Name specified on the OSD line.\n";
       
   763                 }
       
   764             }
       
   765             if (($OSDclass ne "")&&(!($OSDclass =~ /^Common Replaceable$/i))&&(!($OSDclass =~ /^Common Symbian$/i))&&(!($OSDclass =~ /^Optional Replaceable$/i))&&(!($OSDclass =~ /^Optional Symbian$/i))
       
   766                     &&(!($OSDclass =~ /^Reference\/Test$/i))&&(!($OSDclass =~ /^Reference\\Test$/i))&&(!($OSDclass =~ /^Test\/Reference$/i))&&(!($OSDclass =~ /^Test\\Reference$/i)))
       
   767             {
       
   768                 if ($OSDLineError == 0)
       
   769                 {
       
   770                     push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>OSD Class '$OSDclass' is not a defined OSD Class.</font><br>\n";
       
   771                     push @ASCIIFileErrors, "$path, OSD Class '$OSDclass' is not a defined OSD Class.\n";
       
   772                     $OSDLineError = 1;
       
   773                 }
       
   774                 else
       
   775                 {
       
   776                     push @HTMLFileErrors, "<font face=arial size=4 color=red>OSD Class '$OSDclass' is not a defined OSD Class.</font><br>\n";
       
   777                     push @ASCIIFileErrors, "$path, OSD Class '$OSDclass' is not a defined OSD Class.\n";
       
   778                 }
       
   779             }
       
   780             if((defined $Category)&&($Category eq 'D')&&(!($OSDclass =~ /^Common Symbian$/i)))
       
   781             {
       
   782                 if ($OSDLineError == 0)
       
   783                 {
       
   784                     push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>All Category 'D' code must be assigned to a CKL component of OSD Class 'Common Symbian'.</font><br>\n";
       
   785                     push @ASCIIFileErrors, "$path, All Category 'D' code must be assigned to a CKL component of OSD Class 'Common Symbian'.\n";
       
   786                     $OSDLineError = 1;
       
   787                 }
       
   788                 else
       
   789                 {
       
   790                     push @HTMLFileErrors, "<font face=arial size=4 color=red>All Category 'D' code must be assigned to a CKL component of OSD Class 'Common Symbian'.</font><br>\n";
       
   791                     push @ASCIIFileErrors, "$path, All Category 'D' code must be assigned to a CKL component of OSD Class 'Common Symbian'.\n";
       
   792                 }
       
   793             }
       
   794             if((defined $Category)&&($OSDclass =~ /^Common Symbian$/i))
       
   795             {
       
   796                 if (($Category eq 'E'))
       
   797                 {
       
   798                     if ($OSDLineError == 0)
       
   799                     {
       
   800                         push @HTMLFileErrors, "<font face=verdana size=4><b>Line = </b>$_</font><br><font face=arial size=4 color=red>A 'Common Symbian' OSD Class component must not contain Source Category '$Category' code.</font><br>\n";
       
   801                         push @ASCIIFileErrors, "$path, A 'Common Symbian' OSD Class component must not contain Source Category '$Category' code.\n";
       
   802                         $OSDLineError = 1;
       
   803                     }
       
   804                     else
       
   805                     {
       
   806                         push @HTMLFileErrors, "<font face=arial size=4 color=red>A 'Common Symbian' OSD Class component must not contain Source Category '$Category' code.</font><br>\n";
       
   807                         push @ASCIIFileErrors, "$path, A 'Common Symbian' OSD Class component must not contain Source Category '$Category' code.\n";
       
   808                     }
       
   809                 }
       
   810             }
       
   811             
       
   812             push @HTMLFileErrors, "<p>\n" if ($OSDLineError != 0);
       
   813             
       
   814             #Check $ComponentName and OSD-Class against data in Schedule12 of the CKL
       
   815             if ($ComponentName ne "")
       
   816             {
       
   817                 my $componentmatch = 0;
       
   818                 my $OSDmatch = 0;
       
   819                 my $Schedule12OSDClass;
       
   820                 my $component = lc $ComponentName;
       
   821                 $component =~ s/\s+$//;
       
   822                 my $osdclass = lc $OSDclass;
       
   823                 $osdclass =~ s/\s+$//;
       
   824  
       
   825                 foreach my $Schedule12Component (sort keys %Components)
       
   826                 {
       
   827                     my $schedule12component = lc $Schedule12Component;
       
   828                     $schedule12component =~ s/\s+$//;
       
   829                     if ($component eq $schedule12component)
       
   830                     {
       
   831                         $componentmatch = 1;
       
   832                         $ComponentsUsed{$Schedule12Component} = 1;
       
   833                     }
       
   834                     if ($componentmatch == 1)
       
   835                     {
       
   836                         $Schedule12OSDClass = $Components{$Schedule12Component};
       
   837                         my $schedule12osdclass = lc $Schedule12OSDClass;
       
   838                         $schedule12osdclass =~ s/\s+$//;
       
   839                         $OSDmatch = 1 if ($schedule12osdclass eq $osdclass);
       
   840                         
       
   841                         if (($osdclass eq "reference\\test")||($osdclass eq "test\\reference")||($osdclass eq "test\/reference"))
       
   842                         {
       
   843                             $OSDmatch = 1 if ($schedule12osdclass eq "reference\/test");
       
   844                         }
       
   845                         last;
       
   846                     }
       
   847                 }
       
   848                 
       
   849                 if ($componentmatch == 0)
       
   850                 {
       
   851                     push @HTMLFileErrors, "<font face=arial size=4 color=red>Component '$ComponentName' is not listed in Schedule 12 of the CKL.</font><p>\n";
       
   852                     push @ASCIIFileErrors, "$path, Component '$ComponentName' is not listed in Schedule 12 of the CKL.\n";
       
   853                 }
       
   854                 if (($componentmatch == 1)&&($OSDmatch == 0))
       
   855                 {
       
   856                     if (($Category == 'T') && (($osdclass eq "reference\\test")||($osdclass eq "test\\reference")||($osdclass eq "test\/reference")||($osdclass eq "reference\/test")))
       
   857                     {
       
   858                         
       
   859                     }
       
   860                     else
       
   861                     {
       
   862                         push @HTMLFileErrors, "<font face=arial size=4 color=red>According to Schedule 12 of the CKL, component '$ComponentName' should be assigned to OSD Class '$Schedule12OSDClass' not '$OSDclass'.</font><p>\n";
       
   863                         push @ASCIIFileErrors, "$path, According to Schedule 12 of the CKL component '$ComponentName' should be assigned to OSD Class '$Schedule12OSDClass' not '$OSDclass'.\n";
       
   864                     }
       
   865                 }
       
   866             }
       
   867         }
       
   868     }
       
   869   }
       
   870   push @HTMLFileErrors, "<font face=arial size=4 color=red>Category Line is missing.</font><p>" if ($CategoryLineFound == 0);
       
   871   push @ASCIIFileErrors, "$path, Category Line is missing.\n" if ($CategoryLineFound == 0);
       
   872   push @HTMLFileErrors, "<font face=arial size=4 color=red>OSD Line is missing.</font><p>" if ($OSClassLineFound == 0);
       
   873   push @ASCIIFileErrors, "$path, OSD Line is missing.\n" if ($OSClassLineFound == 0);
       
   874   
       
   875   push @HTMLFileErrors, "<font face=arial size=4 color=red>File contains $CategoryLineFound Category Lines.</font><p>" if ($CategoryLineFound > 1);
       
   876   push @ASCIIFileErrors, "$path, File contains $CategoryLineFound Category Lines.\n" if ($CategoryLineFound > 1);
       
   877   push @HTMLFileErrors, "<font face=arial size=4 color=red>File contains $OSClassLineFound OSD Lines.</font><p>" if ($OSClassLineFound > 1);
       
   878   push @ASCIIFileErrors, "$path, File contains $OSClassLineFound OSD Lines.\n" if ($OSClassLineFound > 1);
       
   879   
       
   880   return \@HTMLFileErrors, \@ASCIIFileErrors;
       
   881 }
       
   882 
       
   883 sub IprStatus
       
   884 {
       
   885 my $Location = shift;
       
   886 my $ThisCategory = 'X';
       
   887 my $CatSet = 0;
       
   888 my $Expiry = 0;        # 0 represents no expiry date set
       
   889 my $Restricted = 0;
       
   890 my $ThisLine = 0;
       
   891 my $Description;
       
   892 my %ShipData;
       
   893 open(IPR, $Location);
       
   894 while (<IPR>)
       
   895   {
       
   896   $_ = lc $_;
       
   897   $ThisLine += 1;
       
   898 
       
   899   s/\s*#.*$//;                                        # ignore comments and blank lines
       
   900   if ($_ =~ /^$/) { next; }
       
   901 
       
   902   if ($_ =~ /category\s+(\w)/)                        # CATEGORY statements
       
   903     {
       
   904     my $aCat=uc($1);
       
   905     if (($aCat =~ /[^A-GIOT]/))
       
   906       {
       
   907       &ErrorLoc("illegal Category statement", $ThisLine, $Location);
       
   908       $ThisCategory = 'X';
       
   909       $CatSet = 1;
       
   910       next;
       
   911       }
       
   912     if ($CatSet)
       
   913       {
       
   914       &ErrorLoc("repeated Category statement", $ThisLine, $Location);
       
   915       if ($ThisCategory le $aCat) { next; }
       
   916       }
       
   917     $ThisCategory = uc($1);
       
   918     $CatSet = 1;
       
   919     next;
       
   920     }
       
   921 
       
   922   if ($_ =~ /authorized\s+(\w+)\s*(.*)/)              # AUTHORIZED statements
       
   923     {
       
   924     my $aRec = lc($1);
       
   925     my $Rest = $2;
       
   926     my $found = 0;
       
   927     my $ShipUntil = 0;
       
   928     my $Repeat = 0;
       
   929     my @Recipients = keys(%ShipData);
       
   930     foreach my $name (@Recipients)
       
   931       {
       
   932       if ($aRec eq $name)
       
   933         {
       
   934         $Repeat = 1;
       
   935         &ErrorLoc("repeated recipient \"$aRec\"", $ThisLine, $Location);
       
   936         last;
       
   937         }
       
   938       }
       
   939     if ($Rest =~ /until\s+(\d+)\W(\d+)\W(\d+)/) # UNTIL Authorized qualifier
       
   940       {
       
   941       my $D = $1;
       
   942       my $M = $2;
       
   943       my $Y = $3;
       
   944       $ShipUntil = $Y*10000 + $M*100 + $D;
       
   945       if (not &IsValidDate($D, $M, $Y))
       
   946         {
       
   947         &ErrorLoc("illegal date \"$D/$M/$Y\"", $ThisLine, $Location);
       
   948         $ShipUntil = $Now - 1;
       
   949         }
       
   950       }
       
   951     else
       
   952       {
       
   953       if ($Rest =~ /\w+/)
       
   954         {
       
   955         &ErrorLoc("unknown \"Authorized\" qualifier: \"$Rest\"", $ThisLine, $Location);
       
   956         $ShipUntil = $Now - 1;
       
   957         }
       
   958       }
       
   959     if ((!$ShipData{$aRec}) or ($ShipData{$aRec} > $ShipUntil))
       
   960       {
       
   961       $ShipData{$aRec} = $ShipUntil;
       
   962       }
       
   963     next;
       
   964     }
       
   965 
       
   966   if ($_ =~ /expires\s+(\d+)\W(\d+)\W(\d+)/)          # EXPIRES statements
       
   967     {
       
   968     my $D = $1;
       
   969     my $M = $2;
       
   970     my $Y = $3;
       
   971     my $E = $Y*10000 + $M*100 + $D;
       
   972     if (not &IsValidDate($D, $M, $Y))
       
   973       {
       
   974       &ErrorLoc("illegal date \"$D/$M/$Y\"", $ThisLine, $Location);
       
   975       $E = $Now - 1;
       
   976       next;
       
   977       }
       
   978     if ((!$Expiry) or ($Expiry > $E))
       
   979       {
       
   980       $Expiry = $E;
       
   981       }
       
   982     next;
       
   983     }
       
   984 
       
   985   if ($_ =~ /export\s+(\w*)restricted/)               # EXPORT statements
       
   986     {
       
   987     if ($1 ne 'un') { $Restricted = 1; }
       
   988     next;
       
   989     }
       
   990 
       
   991   if ($_ =~ /description\s+(.*)/)                     # DESCRIPTION statements
       
   992     {
       
   993     $Description = $1;
       
   994     next;
       
   995     }
       
   996 
       
   997   if ($_ =~ /^\s*osd/)                                # Ignore OSD: statements
       
   998     {
       
   999     next;
       
  1000     }
       
  1001 
       
  1002   if ($_ =~ /\S/)                                     # Anything else
       
  1003     {
       
  1004     $_ =~ /(.*)$/;
       
  1005     &ErrorLoc("unrecognised statement \"$1\"", $ThisLine, $Location);
       
  1006     }
       
  1007   }
       
  1008 close(IPR);
       
  1009 
       
  1010 if (!$CatSet)
       
  1011   {
       
  1012   &ErrorLoc("missing Category statement", $ThisLine, $Location);
       
  1013   }
       
  1014 else
       
  1015   {
       
  1016   if ((scalar keys %ShipData != 0) and ($ThisCategory =~ /[^B-C]/i))
       
  1017     {
       
  1018     &NotifyError("category $ThisCategory source should not name recipients"); 
       
  1019     }
       
  1020   }
       
  1021 return ($ThisCategory, $Expiry, $Restricted, $Description, %ShipData);
       
  1022 }
       
  1023 
       
  1024 sub Today
       
  1025 {
       
  1026 my ($Sec, $Min, $Hr, $Daym, $Mnth, $Yr, $Wkday, %YrDay, $IsDST) = localtime(time);
       
  1027 return (($Yr+1900)*10000+($Mnth+1)*100+$Daym);
       
  1028 }
       
  1029 
       
  1030 sub IsValidDate
       
  1031 {
       
  1032 my $Dy =  shift;
       
  1033 my $Mth = shift;
       
  1034 my $Yr =  shift;
       
  1035 if ($Yr < 1900) { return 0; }
       
  1036 if (($Mth < 1) or ($Mth > 12)) { return 0; }
       
  1037 if (($Dy <1) or ($Dy > &DayinMonth($Mth, &IsLeap($Yr)))) { return 0; }
       
  1038 return 1;
       
  1039 }
       
  1040 
       
  1041 sub IsLeap
       
  1042 {
       
  1043 my $aYear = shift;
       
  1044 return (!($aYear%4) && ($aYear%100 || !($aYear%400))) ? 1 : 0;
       
  1045 }
       
  1046 
       
  1047 sub DayinMonth
       
  1048 {
       
  1049 my @dim = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
       
  1050            31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
       
  1051 
       
  1052 my $Monthnum = shift;
       
  1053 my $Leap = shift;
       
  1054 return $dim[$Leap*12 + $Monthnum - 1];
       
  1055 }
       
  1056 
       
  1057 sub DateValToStr
       
  1058 {
       
  1059 my $Date = shift;
       
  1060 my $temp = $Date%100;
       
  1061 my $DatStr = "$temp\/";
       
  1062 $Date -= $temp;
       
  1063 $Date /= 100;
       
  1064 $temp = $Date%100;
       
  1065 $DatStr .="$temp\/";
       
  1066 $Date -= $temp;
       
  1067 $Date /= 100;
       
  1068 $DatStr .= "$Date";
       
  1069 }
       
  1070 
       
  1071 sub DataPrint
       
  1072 {
       
  1073 if ($Full >= -1)
       
  1074   {
       
  1075   print @_;
       
  1076   }
       
  1077 }
       
  1078 
       
  1079 sub PkgPrint
       
  1080 {
       
  1081 print PKGLIST @_;
       
  1082 }
       
  1083 
       
  1084 sub MfsPrint
       
  1085 {
       
  1086 my $mfsname = uc $_[0];
       
  1087 print MFSLIST "$mfsname";
       
  1088 }
       
  1089 
       
  1090 sub ErrorLoc
       
  1091 {
       
  1092 my $msg = shift;
       
  1093 my $line = shift;
       
  1094 my $loc = shift;
       
  1095 &NotifyError("$msg");
       
  1096 &ErrorPrint("       in line $line of $loc");
       
  1097 }
       
  1098 
       
  1099 sub NotifyError
       
  1100 {
       
  1101 my $msg = shift;
       
  1102 &ErrorPrint("ERROR: $msg");
       
  1103 }
       
  1104 
       
  1105 sub NotifyWarning
       
  1106 {
       
  1107 my $msg = shift;
       
  1108 &ErrorPrint("WARNING: $msg");
       
  1109 }
       
  1110 
       
  1111 sub NotifyNote
       
  1112 {
       
  1113 my $msg = shift;
       
  1114 &ErrorPrint("Note: $msg");
       
  1115 }
       
  1116 
       
  1117 sub ErrorPrint
       
  1118 {
       
  1119 my $msg = shift;
       
  1120 print STDERR "$msg\n";
       
  1121 }
       
  1122 
       
  1123 sub ExportWarning
       
  1124 {
       
  1125 print STDERR <<ENDEXPORTSTRING;
       
  1126 WARNING: The selected code contains export-restricted source.
       
  1127 Any external release must contain the following notice.
       
  1128 
       
  1129 "The delivery of this software is subject to UK Export Control and is made
       
  1130 under Open Individual Export Licence (OIEL) no OIEL I/006318/99, which covers
       
  1131 Sweden, USA, Japan, Finland and Hungary.  The recipient of this software agrees
       
  1132 that it will not export or re-export the software directly or indirectly to any
       
  1133 country which at the time of export requires an export licence or other
       
  1134 governmental approval, without first obtaining such licence or approval."
       
  1135 
       
  1136 ENDEXPORTSTRING
       
  1137 }
       
  1138 
       
  1139 sub ConditionalRep
       
  1140 {
       
  1141 my $Found = shift;
       
  1142 my $Path = shift;
       
  1143 my $Cat = shift;
       
  1144 my $Expire = shift;
       
  1145 my $NoExp = shift;
       
  1146 my $Description = shift;
       
  1147 my %LDates = @_;
       
  1148 
       
  1149 if (index($Categories, $Cat) < 0) { return; }
       
  1150 if ($NoExp and !$ForceExport) { return; }
       
  1151 if ($NoExp) { $IncludesRestrictedSource = 1; }
       
  1152 my $Printed = 0;
       
  1153 
       
  1154 if ($Full > 1)                    # write one line of tab-separated data per directory
       
  1155   {
       
  1156   if ($Found)
       
  1157     {
       
  1158     my @Recipients;
       
  1159     my $NamePrinted = 0;
       
  1160     &DataPrint ("$Path\t", "$Cat\t");          # directory and category
       
  1161     if ($NoExp) { &DataPrint ('Restricted'); } # export status
       
  1162     &DataPrint ("\t");
       
  1163     @Recipients = keys(%LDates);
       
  1164     foreach my $name (@Recipients)         # comma-separated list of recipients
       
  1165       {
       
  1166       if ($NamePrinted)
       
  1167         {
       
  1168         &DataPrint (', ');
       
  1169         }
       
  1170       &DataPrint ($name);
       
  1171       $NamePrinted = 1;
       
  1172       }
       
  1173     &DataPrint ("\t");
       
  1174     @Recipients = keys(%LDates);        # earliest of any expiry dates
       
  1175     foreach my $name (@Recipients)
       
  1176       {
       
  1177       my $Date = $LDates{$name};
       
  1178       if ($Date)
       
  1179         {
       
  1180         if (($Expire <= 0) or ($Date < $Expire))
       
  1181           {
       
  1182           $Expire = $Date;
       
  1183           }
       
  1184         }
       
  1185       }
       
  1186     if ($Expire > 0)
       
  1187       {
       
  1188       my $Str = &DateValToStr($Expire);
       
  1189       &DataPrint ("$Str");
       
  1190       }
       
  1191     &DataPrint ("\t");
       
  1192     &DataPrint ("$Description\n");             # show descriptive text, if it exists
       
  1193     }
       
  1194   }
       
  1195 
       
  1196 else                              # use a multi-line report format
       
  1197   {
       
  1198   if ($Found or ($Full >= 0))
       
  1199     {
       
  1200     &DataPrint ("Directory: $Path\n");
       
  1201     }
       
  1202 
       
  1203   if ($Full >= 0)
       
  1204     {
       
  1205     if (!$Found)
       
  1206       {
       
  1207       &DataPrint ("No files\n\n");
       
  1208       return;
       
  1209       }
       
  1210     &DataPrint ("Category $Cat\n");
       
  1211     $Printed = 1;
       
  1212     }
       
  1213   if (($Full > 0) or ($NoExp)) # Always report inclusion of export restricted code
       
  1214     {
       
  1215     my $Str = "Export ";
       
  1216     $Str .= $NoExp ? "restricted" : "unrestricted";
       
  1217     &DataPrint ("$Str\n");
       
  1218     }
       
  1219   if ($Full > 0)
       
  1220     {
       
  1221     if ($Expire > 0)
       
  1222       {
       
  1223       my $Str = &DateValToStr($Expire);
       
  1224       &DataPrint ("Expires on $Str\n");
       
  1225       $Printed = 1;
       
  1226       }
       
  1227     my @Recipients = keys(%LDates);
       
  1228     foreach my $name (@Recipients)
       
  1229       {
       
  1230       my $Str = "Can ship to ".ucfirst($name);
       
  1231       my $Date = $LDates{$name};
       
  1232       if ($Date)
       
  1233         {
       
  1234         $Str .= " until ";
       
  1235         $Str .= &DateValToStr($Date);
       
  1236         }
       
  1237       &DataPrint ("$Str\n");
       
  1238       $Printed = 1;
       
  1239       if ($name eq $Recipient) { $Expire = $LDates{$name}; }
       
  1240       }
       
  1241     }
       
  1242   }
       
  1243 if ($ShowFiles or $Zip or $GenPkg or $Manifest)
       
  1244   {
       
  1245   my @flist;
       
  1246   my $name;
       
  1247   my $shippable;
       
  1248 
       
  1249   return if (&HasExpired($Expire) and !$OverrideExpiry) ;
       
  1250 
       
  1251   if (!&CanShip($Recipient, keys(%LDates)))
       
  1252     {
       
  1253     if ($ShowFiles)
       
  1254       {
       
  1255       &DataPrint ("    Files not shippable to $Recipient\n\n");
       
  1256       }
       
  1257     return;
       
  1258     }
       
  1259 
       
  1260   opendir(HERE, $Path);
       
  1261   @flist = readdir(HERE);
       
  1262   close(HERE);
       
  1263   foreach my $name (@flist)
       
  1264     {
       
  1265     if (-d "$Path$name") { next; }
       
  1266     if ($ShowFiles)
       
  1267       {
       
  1268       &DataPrint ("    $Path$name\n");
       
  1269       $Printed = 1;
       
  1270       }
       
  1271 
       
  1272     if ($GenPkg)
       
  1273       {
       
  1274       # --------------------------
       
  1275       # print filespec to Pkg file
       
  1276       # --------------------------
       
  1277         &PkgPrint ("      <item src=\"$Path$name\"  dest=\"[sdkroot]$Path$name\"\/>\n");
       
  1278       }   
       
  1279 
       
  1280     if ($Manifest)
       
  1281       {
       
  1282       # --------------------------
       
  1283       # print filespec to manifest file
       
  1284       # --------------------------
       
  1285       &MfsPrint ("  $Path$name\n");
       
  1286       }   
       
  1287 
       
  1288     if ($Zip)
       
  1289       {
       
  1290       if ($Cat eq 'A')
       
  1291         {
       
  1292         $ZippedCatA = 1;
       
  1293         }
       
  1294       if ($Cat eq 'X')
       
  1295         {
       
  1296         $ZippedCatX = 1;
       
  1297         }
       
  1298       print ZIPLIST "$Path$name\n" or die "Can't write to $ZipTmpFile\n";
       
  1299       }
       
  1300     }
       
  1301   }
       
  1302 if ($Printed) { &DataPrint ("\n"); }
       
  1303 }
       
  1304 
       
  1305 sub CanShip
       
  1306 {
       
  1307 my $to = shift;
       
  1308 my @list = @_;
       
  1309 my $count;
       
  1310 my $name;
       
  1311 
       
  1312 return (1) if ($to eq 'all');
       
  1313 $count = @list;
       
  1314 if ($count)
       
  1315   {
       
  1316   return (0) if ($to eq 'generic');
       
  1317   foreach my $name (@list)
       
  1318     {
       
  1319     return(1) if ($to eq $name);
       
  1320     }
       
  1321   return(0);
       
  1322   }
       
  1323 return(1);
       
  1324 }
       
  1325 
       
  1326 sub ReadDirFile
       
  1327 {
       
  1328 my $filename = shift;
       
  1329 my @dlist;
       
  1330 
       
  1331 open(DIRLIST, $filename) or die "Can't open $filename\n";
       
  1332 while (<DIRLIST>)
       
  1333   {
       
  1334   $_ = lc $_;
       
  1335   s/\s*#.*$//;              # remove comments
       
  1336   s/\s*$//;                 # remove trailing whitespace
       
  1337   if ($_ =~ /^$/) { next; } # ignore blank lines
       
  1338   if (-d $_)                # entry is a valid directory
       
  1339     {
       
  1340     push(@dlist, $_);
       
  1341     next;
       
  1342     }
       
  1343   else
       
  1344     {
       
  1345     &NotifyError("Unrecognised directory \"$_\" in \"$filename\" ignored");
       
  1346     }
       
  1347   }
       
  1348 close DIRLIST;
       
  1349 @dlist;
       
  1350 }
       
  1351 
       
  1352 sub HasExpired
       
  1353 {
       
  1354 my $date = shift;
       
  1355 return ($date and ($date < $Now))
       
  1356 }
       
  1357 
       
  1358 sub Strip
       
  1359 {
       
  1360 # Remove excess occurrences of '..' and '.' from a path
       
  1361 return undef unless $_[0]=~m-^\\-o;     # Must start with backslash
       
  1362 my $P=$_[0];
       
  1363 $P=~s-^\\\.{2}$-\\-o;                   # Convert plain "\.." to "\"  We are at the root anyway; can't go any higher!
       
  1364 $P=~s-\\\.$-\\-o;                       # Remove backslash-dot from end of line
       
  1365 $P=~s-\\(?!\.{2}\\)[^\\]*\\\.{2}$-\\-o; # Catch dotdot at end of text. Remove last directory.
       
  1366 while ($P=~s-\\\.\\-\\-go) { }          # Convert backslash-dot-backslash to backslash
       
  1367 while ($P=~s-\\(?!\.{2}\\)[^\\]*\\\.{2}(?=\\)--go) { }  # Convert backslash-fname-backslash-dotdot-backslash to backslash
       
  1368 $P;
       
  1369 }
       
  1370 
       
  1371 sub Split
       
  1372 {
       
  1373 # return the section of a file path required - Path, Base, Ext or File
       
  1374 my ($Sect,$P)=@_;
       
  1375 $Sect=ucfirst lc $Sect;
       
  1376 if ($Sect eq 'Path')
       
  1377   {
       
  1378   if ($P=~/^(.*\\)/o)
       
  1379     {
       
  1380     return $1;
       
  1381     }
       
  1382   return '';
       
  1383   }
       
  1384 if ($Sect eq 'Base')
       
  1385   {
       
  1386   if ($P=~/\\?([^\\]*?)(\.[^\\\.]*)?$/o)
       
  1387     {
       
  1388     return $1;
       
  1389     }
       
  1390   return '';
       
  1391   }
       
  1392 if ($Sect eq 'Ext')
       
  1393   {
       
  1394   if ($P=~/(\.[^\\\.]*)$/o)
       
  1395     {
       
  1396     return $1;
       
  1397     }
       
  1398   return '';
       
  1399   }
       
  1400 if ($Sect eq 'File')
       
  1401   {
       
  1402   if ($P=~/([^\\]*)$/o)
       
  1403     {
       
  1404     return $1;
       
  1405     }
       
  1406   return '';
       
  1407   }
       
  1408 undef;
       
  1409 }
       
  1410 
       
  1411 sub ValidateExcPath
       
  1412 {
       
  1413 my $p = $_[0];
       
  1414 if ((!(-e $p)))
       
  1415   {
       
  1416   &NotifyWarning("Unrecognised exclusion directory \"$p\" will be ignored");
       
  1417   return undef;
       
  1418   }
       
  1419 $p=~s-^(.*[^\\])$-$1\\-o; # ensure it ends with a backslash
       
  1420 $p;
       
  1421 }
       
  1422 
       
  1423 sub ValidateIncPath
       
  1424 {
       
  1425 my $p = $_[0];
       
  1426 if ((!(-e $p)))
       
  1427   {
       
  1428   &NotifyWarning("Unrecognised inclusion directory \"$p\" will be ignored");
       
  1429   return undef;
       
  1430   }
       
  1431 $p=~s-^(.*[^\\])$-$1\\-o; # ensure it ends with a backslash
       
  1432 $p;
       
  1433 }
       
  1434 
       
  1435 sub MakeAbs
       
  1436 {
       
  1437 return undef unless $_[0]=~m-^\\-o;	# Ensure that $Path begins with backslash, i.e. starts from root
       
  1438 my ($Path,@List)=@_;
       
  1439 my $BasePath=&Split("Path",$Path);
       
  1440 undef $Path;
       
  1441 my $p;
       
  1442 foreach $p (@List)
       
  1443   {
       
  1444   if ($p=~m-^\.{1,2}-o)	# Directory == "." or ".."?
       
  1445     {
       
  1446     $p=&Strip($BasePath.$p);
       
  1447     next;
       
  1448     }
       
  1449   if ($p=~m-(^.:)-o)	# Directory starts with drive-letter:
       
  1450     {
       
  1451     if (uc $1 eq $WorkDrv) {next;};     # Allow current drive for backward compatability.
       
  1452     print "Drive specifications not supported\n";
       
  1453     exit 1;
       
  1454     }
       
  1455   if ($p=~m-^[^\.\\]-o)	# Directory does not start with dot or backslash
       
  1456     {
       
  1457     $p=$BasePath.$p;
       
  1458     next;
       
  1459     }
       
  1460   if ($p=~m-^\\-o)	    # Directory starts with a backslash
       
  1461     {
       
  1462     next;
       
  1463     }
       
  1464   if ($p=~m-^\.\\(.*)$-o)	# Directory starts with a dot, then a backslash. What's left becomes $1
       
  1465     {
       
  1466     $p=&Strip($BasePath.$1);
       
  1467     next;
       
  1468     }
       
  1469   return undef;			# None of the above
       
  1470   }
       
  1471 return @List;
       
  1472 }
       
  1473 
       
  1474 sub FindZip
       
  1475 {
       
  1476    my $PathList = $ENV{ 'PATH' };
       
  1477    my (@PathSplit) = split( ";",$PathList );
       
  1478 
       
  1479    if ( -e ( $WorkPath."zip.exe" ) )        # Check current directory first
       
  1480    {
       
  1481      return 1;
       
  1482    }
       
  1483    foreach my $p ( @PathSplit )
       
  1484    {
       
  1485       if ( -e ( $p."\\zip.exe" ) )
       
  1486       {
       
  1487          return 1;
       
  1488       }
       
  1489    }
       
  1490    return 0;
       
  1491 }
       
  1492 
       
  1493 sub Usage
       
  1494 {
       
  1495 print <<ENDHERESTRING;
       
  1496 IPRTOOL.PL   Version 1.41  Copyright (c) 2000, 2001 Symbian Ltd.
       
  1497                            All rights reserved
       
  1498 Usage:
       
  1499     perl iprtool.pl [options] [help|?]
       
  1500 
       
  1501 where options are:
       
  1502     -c[ats] ABCDEFGIOTX      report the listed categories (default: EFGOT)
       
  1503     -d[ir] <path>[<file>]    start scan at the specified directory; if a file
       
  1504                              specification, scan all directories listed in the
       
  1505                              file (defaults to the current working directory)
       
  1506     -e[xport]                include files subject to DTI export restrictions
       
  1507     -f[ull] [2|1|0|-1|-2]    set the extent of the summary of the content of
       
  1508                              the policy file for each directory:
       
  1509                                2  one line of tab-separated data per directory
       
  1510                                1  full policy data for each directory
       
  1511                                0  directory name and category (the default)
       
  1512                               -1  no IPR information
       
  1513                               -2  suppress all summary output, except errors
       
  1514     -g[enpkg] <pkgfile>      create an XML package file for the selected files
       
  1515     -l[icensee] <IDstr>      specify a recipient by name (not code name)
       
  1516     -m[anifest] <outfile>    write a file list in manifest format to <outfile>
       
  1517     -n[osub]                 do not include subdirectories in the report
       
  1518     -o[verrideexpiry]        include source whose expiry date is in the past
       
  1519     -p[roject] <prj>         include specific source directories listed in
       
  1520                              <prj>.extra (overrides any exclusions)
       
  1521     -r[eport] <product>      produces an ASCII and a HTML report on the syntax
       
  1522                              and semantics of all the distribution policy files
       
  1523     -s[howfiles]             list the files in each reported directory
       
  1524     -x[clude] <path>[<file>] specify head(s) of whole directory tree(s) to
       
  1525                              exclude from the scan (format as for the -d flag) 
       
  1526     -z[ip] <zipfile>         create a zipfile of the selected files
       
  1527 
       
  1528 -----------------------------------------------------------------------------
       
  1529 
       
  1530 This tool provides the ability to create zips of selected source and/or to 
       
  1531 construct reports, either for external distribution or for internal audit 
       
  1532 purposes.
       
  1533 
       
  1534 The types of report available include:
       
  1535 
       
  1536 ·	a full description of the IPR status of each directory
       
  1537 ·	a listing of all directories containing code of a specified category or set of categories
       
  1538 
       
  1539 In each case the report may refer to one or more specific directories, with or without their included subdirectories, or the whole source directory tree.
       
  1540 
       
  1541 Command line options are:
       
  1542 Option	Action	Default	See Note
       
  1543 -c[ats] <catIDs>	restrict report to the specified category or categories, where <catIDs> can be any combination  of one or more of A, B, C, D, E, F, G and X	report all categories	5
       
  1544 -d[ir] <path>[<file name>]	start scan at the specified directory or, if a file specification, scan all directories listed in the file	start scan at the current directory	2, 3
       
  1545 -e[xport]	include files that are subject to DTI export restrictions	don’t include export-restricted files	
       
  1546 -f[ull] 2|1|0|-1|-2	set extent of the summary of the content of the policy file for each directory:
       
  1547 	 2    one line of tab-separated
       
  1548 	       data per directory
       
  1549 	 1    full, multi-line
       
  1550 	 0    reduced (the default)
       
  1551 	-1    no IPR data, directory
       
  1552 	       names only
       
  1553 	-2   suppress all output other
       
  1554 	       than error reports	reduced - report the directory name and category	
       
  1555 -g[enpkg] <pkgfile>	create an XML package file for the selected files	don’t create an XML package file	
       
  1556 -l[icensee] <Idstr>	specify a particular recipient	assume a ‘generic’ recipient	1
       
  1557 -m[anifest] <outfile>	write a file list in manifest format to <outfile>	don’t create a manifest listing	
       
  1558 -n[osub]	do not include subdirectories in the report	include subdirectories	
       
  1559 -o[verrideexpiry]	include source whose expiry date is in the past	obey expiry dates	
       
  1560   -p[roject] <prjname>	  specify a particular project, to
       
  1561 	  enable the inclusion of
       
  1562 	  additional category D source	  no additional source	  4
       
  1563 -s[howfiles]	list the files in each reported directory	don’t list files	
       
  1564   -x[clude] <path>[<file name>]	exclude the specified directory  and its subdirectories or, if a file specification, exclude all directory trees headed by the directories listed in the file	 no exclusions	 2, 3
       
  1565 -z[ip] <zipfile name>	create a zipfile of the selected (reported) files	create a report without zipping	
       
  1566 
       
  1567 Notes
       
  1568 1) The convention is that true company names are to be used, not codenames. It is recommended that the name does not include spaces. Names are not validated.
       
  1569 Category B and C source code whose policy file contains Authorized statement(s) will not be included in a zip unless unless an Authorized statement name matches with the Licensee name specified by means of the -l flag.
       
  1570 Filtering of licensee-specific source may be overridden by specifying '-l all'. This should only be used for construction of internal deliveries which need to include source owned by multiple licensees.
       
  1571 
       
  1572 2) An example of the content of a directory list file for use with the -d or -x flags is:
       
  1573 
       
  1574  # Example directory listing for use with iprtool.pl
       
  1575 
       
  1576  \\hal
       
  1577  \\e32toolp
       
  1578 
       
  1579 Directories may be listed with absolute paths, as above, or relative paths. Paths are always interpreted with respect to the current working directory, regardless of the location af the directory list file. Do NOT include drive letter.
       
  1580 
       
  1581 3) Absolute paths used with the -d and -x flags, and within directory list files, may include drive letters, but their use is not recommended without good reason A valid reason to include a drive letter with the -d or -x flag is if a directory list file needs to be stored outside the drive that is being scanned. It is unlikely that there will ever be a valid reason to include drive letters in the paths listed in a directory listing file.
       
  1582 
       
  1583 4) If a project is specified with the -p flag, and a file with the name '<prjname>.extra' is found in the directory from which the tool is run, the report is extended to include the content of all directories listed in that file (reported as though the -n flag were set, so all subdirectories need to be listed). A source file zip will not include category B an C source that is excluded as described in Note 1. Otherwise, this mechanism unconditionally includes the content of all listed directories, regardless of their category, export status or expiry date, and overriding any directories excluded by means of the -x flag. The following is a fictitious example file 'calypso.extra'
       
  1584 
       
  1585  # Additional source directories for  Calypso project deliveries
       
  1586  
       
  1587  \\rcomp
       
  1588  \\rcomp\\group
       
  1589 
       
  1590 5) Category X is exceptional. Uncategorised code - ie source in a directory without a distribution.policy file, or with a policy file that does not contain a valid Category statement - is reported as being in category X. No source should be actively classified as category X; any attempt to do so will be reported as an error by the tool.
       
  1591 Errors and warnings
       
  1592 The tool reports (to STDERR) errors and warnings that are found while scanning source directories. The most significant error notification is of missing policy files but the tool also reports on a wide variety of errors in the content of the policy files. Such errors include unrecognised keywords, unexpected duplicate keywords and illegal dates.
       
  1593 
       
  1594 Warnings are also issued if a source zip includes source that is in category A or is uncategorised (cat X), or is subject to export restrictions.
       
  1595 
       
  1596 ENDHERESTRING
       
  1597 exit 1;
       
  1598 }