releasing/cbrtools/perl/IniData.pm
changeset 602 3145852acc89
equal deleted inserted replaced
600:6d08f4a05d93 602:3145852acc89
       
     1 # Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of the License "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 # 
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 # 
       
    11 # Contributors:
       
    12 # 
       
    13 # Description:
       
    14 # 
       
    15 #
       
    16 
       
    17 package IniData;
       
    18 
       
    19 use strict;
       
    20 use FindBin;
       
    21 use File::Path;
       
    22 use File::Spec;
       
    23 use Utils;
       
    24 use PathData;
       
    25 
       
    26 our $cache = {}; # Persistent (private) cache
       
    27 
       
    28 $|++;
       
    29 
       
    30 #
       
    31 # Constants.
       
    32 #
       
    33 
       
    34 my $iniName = \ 'reltools.ini';
       
    35 my $envDir = undef; # only filled in when we do New()
       
    36 my $binDir = \ "$FindBin::Bin\\";
       
    37 my @standardIgnores = ('\\epoc32\\build\\*',
       
    38            '\\epoc32\\wins\\c\\*',
       
    39            '\\epoc32\\winscw\\c\\*',
       
    40            '\\epoc32\\release\\*.ilk',
       
    41            '\\epoc32\\release\\*.bsc',
       
    42            '\\epoc32\\data\\emulator\\*.sys.ini',
       
    43            '\\epoc32\\release\\tools\\*',
       
    44            '\\epoc32\\release\\tools2\\*'
       
    45           );
       
    46 
       
    47 # Support for target alias file
       
    48 use constant CBR_TARGET_ALIAS_LOCATION => scalar "\\epoc32\\tools\\variant\\";
       
    49 
       
    50 #
       
    51 # Constructor
       
    52 #
       
    53 
       
    54 sub New {
       
    55   my $pkg = shift;  
       
    56   my $filename = shift;
       
    57   my $ignoreepocroot = shift;
       
    58 
       
    59   if ( defined ($ENV{EPOCROOT}) or ! $ignoreepocroot ){
       
    60      $envDir = \ Utils::PrependEpocRoot("\\epoc32\\relinfo\\");
       
    61   }
       
    62   
       
    63   my $self = {};
       
    64   
       
    65   $self->{warnIniLocation} = 0;
       
    66   # Support for target alias file
       
    67   # This is a persistant flag.
       
    68   # If set then a warning must be printed if either HasTargetPlatforms()
       
    69   # or TargetPlatforms() is used. The flag is then cleared thus the warning is a one off.
       
    70   # If clear this is because the cbrtargetsalias.cfg file has been found
       
    71   # or the no_target_alias_warning flag is set in reltools.ini
       
    72   $self->{mustWarnTargetAliasLocation} = 1;
       
    73   if (defined $filename and -e $filename ) {
       
    74     $self->{iniFileName} = $filename;
       
    75   } elsif (defined $$envDir and -e "$$envDir$$iniName" ) {
       
    76     $self->{iniFileName} = "$$envDir$$iniName";
       
    77   } elsif (-e "$$binDir$$iniName") {
       
    78     $self->{warnIniLocation} = 1;
       
    79     $self->{iniFileName} = "$$binDir$$iniName";
       
    80   } else {
       
    81     my $msg = "Error: \"$$iniName\" not found in ";
       
    82     $msg = $msg."either \"$$envDir\" or " if ( defined ($$envDir));
       
    83     $msg = $msg."\"$$binDir\"\n";
       
    84     die $msg;
       
    85   }
       
    86 
       
    87   if ($cache->{lc($self->{iniFileName})}) {           
       
    88     return $cache->{lc($self->{iniFileName})};
       
    89   }
       
    90 
       
    91   foreach my $thisIgnore (@standardIgnores) {
       
    92     push (@{$self->{binIgnore}}, $thisIgnore);
       
    93   }
       
    94 
       
    95   bless $self, $pkg; # $self isn't blessed until we know we need it
       
    96 
       
    97   $self->ReadIni();
       
    98 
       
    99   # Support for target alias file
       
   100   if (!$ignoreepocroot) {
       
   101     $self->{targetAliasName} = Utils::PrependEpocRoot(CBR_TARGET_ALIAS_LOCATION).'cbrtargetalias.cfg';
       
   102 
       
   103     if ($self->ReadTargetAliasFile == 1) {
       
   104       # Successful read so clear the warning flag
       
   105       $self->{mustWarnTargetAliasLocation} = 0;
       
   106     }
       
   107   }
       
   108 
       
   109   $cache->{lc($self->{iniFileName})} = $self;
       
   110 
       
   111   return $self;
       
   112 }
       
   113 
       
   114 #
       
   115 # Public
       
   116 #
       
   117 
       
   118 sub DiffTool {
       
   119   my $self = shift;
       
   120   unless (exists $self->{diff_tool}) {
       
   121     return undef;
       
   122   }
       
   123   return $self->{diff_tool};
       
   124 }
       
   125 
       
   126 sub RequireInternalVersions {
       
   127   my $self = shift;
       
   128   if (exists $self->{require_internal_versions}) {
       
   129     return 1;
       
   130   }
       
   131   return 0;
       
   132 }
       
   133 
       
   134 sub IgnoreSourceFilterErrors {
       
   135   my $self = shift;
       
   136   if (exists $self->{ignore_source_filter_errors}) {
       
   137     return 1;
       
   138   }
       
   139   return 0;
       
   140 }
       
   141 
       
   142 sub RemoteSiteType {
       
   143   my $self = shift;
       
   144 
       
   145   unless (exists $self->{remote_site_type}) {
       
   146     $self->{remote_site_type} = 'FTP';
       
   147   }
       
   148   elsif ($self->{remote_site_type} =~ /(network|drive)/i) {
       
   149     $self->{remote_site_type} = 'NetDrive';
       
   150   }
       
   151   elsif ($self->{remote_site_type} =~ /experimentalproxy/i) {
       
   152     $self->{remote_site_type} = 'FTP::Proxy::Experimental';
       
   153   }
       
   154   elsif ($self->{remote_site_type} =~ /experimentalftp/i) {
       
   155     $self->{remote_site_type} = 'FTP::Experimental';
       
   156   }
       
   157   elsif ($self->{remote_site_type} =~ /multivolumeexport/i) {
       
   158     $self->{remote_site_type} = 'NetDrive::MultiVolumeExport';
       
   159   }
       
   160   elsif ($self->{remote_site_type} =~ /multivolumeimport/i) {
       
   161     $self->{remote_site_type} = 'NetDrive::MultiVolumeImport';
       
   162   }
       
   163   elsif ($self->{remote_site_type} =~ /proxy/i) {
       
   164     $self->{remote_site_type} = 'FTP::Proxy';
       
   165   }  
       
   166   else {
       
   167     $self->{remote_site_type} = 'FTP';
       
   168   }
       
   169   return $self->{remote_site_type};
       
   170 }
       
   171 
       
   172 sub RemoteHost {
       
   173   my $self = shift;
       
   174   unless (exists $self->{remote_host}) {
       
   175     return undef;
       
   176   }
       
   177   return $self->{remote_host};
       
   178 }
       
   179 
       
   180 sub RemoteUsername {
       
   181   my $self = shift;
       
   182   unless (exists $self->{remote_username}) {
       
   183     return undef;
       
   184   }
       
   185   return $self->{remote_username};
       
   186 }
       
   187 
       
   188 sub RemotePassword {
       
   189   my $self = shift;
       
   190   unless (exists $self->{remote_password}) {
       
   191     return undef;
       
   192   }
       
   193   return $self->{remote_password};
       
   194 }
       
   195 
       
   196 sub RemoteLogsDir {
       
   197   my $self = shift;
       
   198   unless (exists $self->{remote_logs}) {
       
   199     return undef;
       
   200   }
       
   201   return $self->{remote_logs};
       
   202 }
       
   203 
       
   204 sub Proxy {
       
   205   my $self = shift;
       
   206   unless (exists $self->{proxy}) {
       
   207     return undef;
       
   208   }
       
   209   return $self->{proxy};
       
   210 }
       
   211 
       
   212 sub ProxyUsername {
       
   213   my $self = shift;
       
   214   unless (exists $self->{proxy_username}) {
       
   215     return undef;
       
   216   }
       
   217   return $self->{proxy_username};
       
   218 }
       
   219 
       
   220 sub ProxyPassword {
       
   221   my $self = shift;
       
   222   unless (exists $self->{proxy_password}) {
       
   223     return undef;
       
   224   }
       
   225   return $self->{proxy_password};
       
   226 }
       
   227 
       
   228 sub PasvTransferMode {
       
   229   my $self = shift;
       
   230   if (exists $self->{pasv_transfer_mode}) {
       
   231     return 1;
       
   232   }
       
   233   return 0;
       
   234 }
       
   235 
       
   236 sub FtpServerSupportsResume {
       
   237   my $self = shift;
       
   238   if (defined $_[0]) {
       
   239     $self->{ftp_server_supports_resume} = $_[0];
       
   240   }
       
   241   if (exists $self->{ftp_server_supports_resume}) {
       
   242     return $self->{ftp_server_supports_resume} ? 1 : 0;
       
   243   }
       
   244   return 0;
       
   245 }
       
   246 
       
   247 sub FtpTimeout {
       
   248   my $self = shift;
       
   249   unless (exists $self->{ftp_timeout}) {
       
   250     return undef;
       
   251   }
       
   252   return $self->{ftp_timeout};
       
   253 }
       
   254 
       
   255 sub FtpReconnectAttempts {
       
   256   my $self = shift;
       
   257   unless (exists $self->{ftp_reconnect_attempts}) {
       
   258     return undef;
       
   259   }
       
   260   return $self->{ftp_reconnect_attempts};
       
   261 }
       
   262 
       
   263 sub TempDir {
       
   264   my $self = shift;
       
   265   if (exists $self->{temp_dir}) {
       
   266     return $self->{temp_dir};
       
   267   }
       
   268   return undef;
       
   269 }
       
   270 
       
   271 sub MaxExportVolumeSize {
       
   272   my $self = shift;
       
   273   if (exists $self->{max_export_volume_size}) {
       
   274     return $self->{max_export_volume_size};
       
   275   }
       
   276   else {
       
   277     return 639 * 1024 * 1024;
       
   278   }
       
   279 }
       
   280 
       
   281 sub PgpTool {
       
   282   my $self = shift;
       
   283 
       
   284   unless (exists $self->{pgp_tool}) {
       
   285     $self->{pgp_tool} = 'PGP';
       
   286   }
       
   287   elsif ($self->{pgp_tool} =~ /(gpg|gnupg)/i) {
       
   288     $self->{pgp_tool} = 'GPG';
       
   289   }
       
   290   else {
       
   291     $self->{pgp_tool} = 'PGP';
       
   292   }
       
   293   return $self->{pgp_tool};
       
   294 }
       
   295 
       
   296 sub PgpEncryptionKeys {
       
   297   my $self = shift;
       
   298   unless (exists $self->{pgp_encryption_keys}) {
       
   299     return [];
       
   300   }
       
   301   return $self->{pgp_encryption_keys};
       
   302 }
       
   303 
       
   304 sub PgpConfigPath {
       
   305   my $self = shift;
       
   306   unless (exists $self->{pgp_config_path}) {
       
   307     return undef;
       
   308   }
       
   309   return $self->{pgp_config_path};
       
   310 }
       
   311 
       
   312 sub ExportDataFile {
       
   313   my $self = shift;
       
   314   unless (exists $self->{export_data_file}) {
       
   315     die "Error: export_data_file keyword not specified in reltools.ini\n";
       
   316   }
       
   317   return $self->{export_data_file};
       
   318 }
       
   319 
       
   320 sub PathData {
       
   321   my $self = shift;
       
   322   unless (defined $self->{pathData}) {
       
   323     $self->{pathData} = PathData->New($self->{verbose});
       
   324   }
       
   325   return $self->{pathData};
       
   326 }
       
   327 
       
   328 sub HtmlNotes {
       
   329   my $self = shift;
       
   330   return (exists $self->{html_notes});
       
   331 }
       
   332 
       
   333 sub FromMapping {
       
   334   my $self = shift;
       
   335   my @fromMapping;
       
   336 
       
   337   if(defined @{$self->{from_mapping}}){
       
   338     @fromMapping = @{$self->{from_mapping}};
       
   339   }
       
   340 
       
   341   return @fromMapping;
       
   342 }
       
   343 
       
   344 sub ToMapping {
       
   345   my $self = shift;
       
   346   my @toMapping;
       
   347 
       
   348   if(defined @{$self->{to_mapping}}){
       
   349     @toMapping = @{$self->{to_mapping}};
       
   350   }
       
   351 
       
   352   return @toMapping;
       
   353 }
       
   354 
       
   355 sub HasMappings {
       
   356   my $self = shift;
       
   357   my $result = 0;
       
   358 
       
   359   if(defined @{$self->{from_mapping}} && defined @{$self->{to_mapping}} && Utils::SourceRoot() eq "\\"){
       
   360     $result = 1;
       
   361   }
       
   362 
       
   363   return $result;
       
   364 }
       
   365 
       
   366 sub PerformMapOnFileName {
       
   367   my $self = shift;
       
   368   my $operand = shift;
       
   369 
       
   370   my @fromMapping = $self->FromMapping();
       
   371   my @toMapping  = $self->ToMapping();
       
   372   my $fromMappingSize = @fromMapping;
       
   373 
       
   374   unless($operand =~ /^\\.*/) {
       
   375     $operand = "\\"."$operand";  # Add a \\ to the beginning, which is equal to srcroot.
       
   376   }
       
   377 
       
   378   if(@fromMapping) {
       
   379     for(my $position = 0; $position<$fromMappingSize; $position++) {
       
   380       if($operand =~ /^\Q$fromMapping[$position]\E/i){
       
   381         $operand =~ s/^\Q$fromMapping[$position]\E/$toMapping[$position]/i;
       
   382         last;
       
   383       }
       
   384     }
       
   385   }
       
   386 
       
   387   return $operand;
       
   388 }
       
   389 
       
   390 sub PerformReverseMapOnFileName {
       
   391   my $self = shift;
       
   392   my $operand = shift;
       
   393 
       
   394   my @fromMapping = $self->FromMapping();
       
   395   my @toMapping  = $self->ToMapping();
       
   396   my $toMappingSize = @toMapping;
       
   397 
       
   398   unless($operand =~ /^\\(.*)/) {
       
   399     $operand = "\\"."$operand";  # Add a \\ to the beginning, which is equal to srcroot.
       
   400   }
       
   401 
       
   402   if(@toMapping) {
       
   403     for(my $position = 0; $position<$toMappingSize; $position++) {
       
   404       if($operand =~ /^\Q$toMapping[$position]\E/i){
       
   405         $operand =~ s/^\Q$toMapping[$position]\E/$fromMapping[$position]/i;
       
   406         last;
       
   407       }
       
   408     }
       
   409   }
       
   410 
       
   411   return $operand;
       
   412 }
       
   413 
       
   414 sub CheckFileNameForMappingClash {
       
   415   my $self = shift;
       
   416   my $fileName = shift;
       
   417 
       
   418   my @toMapping  = $self->ToMapping();
       
   419   my $dirName;
       
   420 
       
   421   if($fileName =~ /^(.*)\\/) {
       
   422     $dirName = $1;
       
   423   }
       
   424 
       
   425   if(@toMapping) {
       
   426     foreach my $toMap (@toMapping) {
       
   427       if($dirName =~ /^\Q$toMap\E/i) {
       
   428         die "ERROR: Clash in mappings. The local mapping $toMap clashes with the source directory $dirName.\n";
       
   429       }
       
   430     }
       
   431   }
       
   432 }
       
   433 
       
   434 sub RemoteSite {
       
   435   my $self = shift;
       
   436   my $verbose = shift;
       
   437   unless (defined $self->{remoteSite}) {
       
   438     my $module = 'RemoteSite::'.$self->RemoteSiteType();
       
   439     eval "require $module";
       
   440     $self->{remoteSite} = $module->New(host => $self->RemoteHost(),
       
   441                username => $self->RemoteUsername(),
       
   442                password => $self->RemotePassword(),
       
   443                passive_mode => $self->PasvTransferMode(),
       
   444                resume_mode => $self->FtpServerSupportsResume(),
       
   445                proxy => $self->Proxy(),
       
   446                proxy_username => $self->ProxyUsername(),
       
   447                proxy_password => $self->ProxyPassword(),
       
   448                max_export_volume_size => $self->MaxExportVolumeSize(),
       
   449                verbose => $verbose);
       
   450     die "Failed to create remote site object" unless ref $self->{remoteSite};
       
   451   }
       
   452   return $self->{remoteSite};
       
   453 }
       
   454 
       
   455 sub LocalArchivePath {
       
   456   require Carp;
       
   457   Carp->import;
       
   458   confess ("Obsolete method called");
       
   459 }
       
   460 
       
   461 sub RemoteArchivePath {
       
   462   require Carp;
       
   463   Carp->import;
       
   464   confess ("Obsolete method called");
       
   465 }
       
   466 
       
   467 sub ArchivePathFile {
       
   468   require Carp;
       
   469   Carp->import;
       
   470   confess ("Obsolete method called");
       
   471 }
       
   472 
       
   473 sub ListArchiveComponents {
       
   474   require Carp;
       
   475   Carp->import;
       
   476   confess ("Obsolete method called");
       
   477 }
       
   478 
       
   479 sub BinariesToIgnore {
       
   480   my $self = shift;
       
   481   if (exists $self->{binIgnore}) {
       
   482     return $self->{binIgnore};
       
   483   }
       
   484   return [];
       
   485 }
       
   486 
       
   487 sub DisallowUnclassifiedSource {
       
   488   my $self = shift;
       
   489   if (exists $self->{disallow_unclassified_source}) {
       
   490     return 1;
       
   491   }
       
   492   return 0;
       
   493 }
       
   494 
       
   495 sub Win32ExtensionsDisabled {
       
   496   my $self = shift;
       
   497   
       
   498   if (exists $self->{disable_win32_extensions}) {
       
   499     return 1;
       
   500   }
       
   501   return 0;
       
   502 }
       
   503 
       
   504 sub CategoriseBinaries {
       
   505   my $self = shift;
       
   506   if (exists $self->{categorise_binaries}) {
       
   507     return 1;
       
   508   }
       
   509   return 0;
       
   510 }
       
   511 
       
   512 sub CategoriseExports {
       
   513   my $self = shift;
       
   514   if (exists $self->{categorise_exports}) {
       
   515     return 1;
       
   516   }
       
   517   return 0;
       
   518 }
       
   519 
       
   520 sub RequiredBinaries {
       
   521   my $self = shift;
       
   522   my $component = lc(shift);
       
   523   if (exists $self->{required_binaries}->{$component}) {
       
   524     return $self->{required_binaries}->{$component};
       
   525   }
       
   526   elsif (exists $self->{required_binaries}->{default}) {
       
   527     return $self->{required_binaries}->{default};
       
   528   }
       
   529   return undef;
       
   530 }
       
   531 
       
   532 sub TableFormatter {
       
   533   my $self = shift;
       
   534   require TableFormatter;
       
   535   require POSIX;
       
   536   # Not 'use' because not many commands draw tables so that would be a waste
       
   537 
       
   538   if (!POSIX::isatty('STDOUT')) {
       
   539     $self->{table_format} = "text";
       
   540     $self->{table_format_args} = "";
       
   541   }
       
   542 
       
   543   unless (defined $self->{table_formatter}) {
       
   544     my $format = $self->{table_format} || "text";
       
   545     $self->{table_formatter} = TableFormatter::CreateFormatter($format, $self, $self->{table_format_args});
       
   546   }
       
   547 
       
   548   return $self->{table_formatter};
       
   549 }
       
   550 
       
   551 sub LatestVerFilter {
       
   552   my $self = shift;
       
   553   unless (exists $self->{latestver_filter}) {
       
   554     return undef;
       
   555   }
       
   556   return $self->{latestver_filter};
       
   557 }
       
   558 
       
   559 sub IllegalWorkspaceVolumes {
       
   560   my $self = shift;
       
   561   if (defined $self->{illegal_workspace_volumes}) {
       
   562     return @{$self->{illegal_workspace_volumes}};
       
   563   }
       
   564   return ();
       
   565 }
       
   566 
       
   567 #
       
   568 # Private
       
   569 #
       
   570 
       
   571 sub CheckMappingPath {
       
   572   my $self = shift;
       
   573   my $operand = shift;
       
   574 
       
   575   # Is used to clean up the mapping path.
       
   576 
       
   577   $operand =~ s/\//\\/g;
       
   578 
       
   579   die "Error: The source_map path $operand must not include a drive letter.\n" if ($operand =~ /^.:/);
       
   580   die "Error: The source_map path $operand must be an absolute path without a drive letter.\n" if ($operand !~ /^\\/);
       
   581   die "Error: The source_map path $operand must not be a UNC path.\n" if ($operand =~ /^\\\\/);
       
   582 
       
   583   #Remove any \\ at the end of the path.
       
   584   if($operand =~ /(.*)\\$/){
       
   585     $operand = $1;
       
   586   }
       
   587 
       
   588   return $operand;
       
   589 }
       
   590 
       
   591 sub BuildSystemVersion {
       
   592   my $self = shift;
       
   593   my $verbose = shift;
       
   594   
       
   595   if (exists $self->{sbs_version}) {
       
   596   	print "User set the value of sbs_version to $self->{sbs_version}\n" if($verbose);
       
   597     return $self->{sbs_version};
       
   598   }
       
   599   return "0";
       
   600 }
       
   601 
       
   602 sub ExtractMapping {
       
   603   my $self = shift;
       
   604   my $operand = shift;
       
   605   my $epoc32dir = Utils::EpocRoot()."epoc32";
       
   606 
       
   607   $operand =~ s/\s+$//;
       
   608 
       
   609   if ($operand =~ /^(\S+)\s+(\S+)$/) {
       
   610     my $archivePath = $self->CheckMappingPath($1);
       
   611     my $localPath = $self->CheckMappingPath($2);
       
   612 
       
   613     if($archivePath =~ /^\Q$epoc32dir\E/i){
       
   614       die "ERROR: Archive path $epoc32dir... in source mapping is not allowed.\n";
       
   615     }
       
   616     elsif($localPath =~ /^\Q$epoc32dir\E/i){
       
   617       die "ERROR: Local path $epoc32dir... in source mapping is not allowed.\n";
       
   618     }
       
   619 
       
   620     # Need to check whether the from location is already present in from_mapping array
       
   621     if(defined @{$self->{from_mapping}}){
       
   622       foreach my $fromMap (@{$self->{from_mapping}}) {
       
   623         if(($archivePath =~ /^\W*\Q$fromMap\E\W*$/i) || ($fromMap =~ /^\W*\Q$archivePath\E\W*$/i)){
       
   624           die "ERROR: Duplicate <archive_source_directory> $fromMap, <archive_source_directory> $archivePath found in source mappings.\n";
       
   625   }
       
   626       }
       
   627     }
       
   628 
       
   629     # Need to check whether the to location is already present in to_mapping array
       
   630     if(defined @{$self->{to_mapping}}){
       
   631       foreach my $toMap (@{$self->{to_mapping}}) {
       
   632         if(($localPath =~ /^\W*\Q$toMap\E\W*$/i) || ($toMap =~ /^\W*\Q$localPath\E\W*$/i)){
       
   633           die "ERROR: Duplicate <local_source_directory> $toMap, <local_source_directory> $localPath found in source mappings.\n";
       
   634     }
       
   635       }
       
   636     }
       
   637 
       
   638     push @{$self->{from_mapping}}, $archivePath;
       
   639     push @{$self->{to_mapping}}, $localPath;
       
   640   }
       
   641   else{
       
   642     die "ERROR: Incorrect usage of source_map keyword in reltools.ini. Expected input is source_map <archive_source_directory> <local_source_directory>\n";
       
   643   }
       
   644 }
       
   645 
       
   646 sub ReadIni {
       
   647   my $self = shift;
       
   648 
       
   649   open (INI, $self->{iniFileName}) or die "Unable to open \"$self->{iniFileName}\" for reading: $!\n";
       
   650 
       
   651   while (local $_ = <INI>) {
       
   652     # Remove line feed, white space and comments.
       
   653     chomp;
       
   654     s/^\s*$//;
       
   655     
       
   656     # INC105677 - Warn user if remote_password contains an unescaped #
       
   657     if (/remote_password\s+\S*[^\\\s]\#/) {
       
   658       warn "Warning: remote_password appears to contain a comment (# characters need to be escaped)\n";
       
   659     }
       
   660     
       
   661     s/(?<!\\)#.*//; # remove comments unless they are immediately preceded by \ (negative lookbehind assertion)
       
   662     s/\\#/#/g; # now remove backslashes before # signs
       
   663     
       
   664     if ($_ eq '') {
       
   665       # Nothing left.
       
   666       next;
       
   667     }
       
   668 
       
   669     my $keyWord;
       
   670     my $operand;
       
   671     if (/^(\w+)\s+(.*)/) {
       
   672       $keyWord = $1;
       
   673       $operand = $2;
       
   674     }
       
   675     else {
       
   676       # Must be a line with no operand.
       
   677       $keyWord = $_;
       
   678     }
       
   679 
       
   680     unless (defined $keyWord) {
       
   681       die "Error: Invalid line in \"$self->{iniFileName}\":\n\t$_\n";
       
   682       next;
       
   683     }
       
   684 
       
   685     if ($keyWord =~ /^diff_tool$/i) {
       
   686       Utils::StripWhiteSpace(\$operand);
       
   687       $self->{diff_tool} = $operand;
       
   688     }
       
   689     elsif ($keyWord =~ /^require_internal_versions$/) {
       
   690       $self->{require_internal_versions} = 1;
       
   691     }
       
   692     elsif ($keyWord =~ /^ignore_source_filter_errors$/) {
       
   693       $self->{ignore_source_filter_errors} = 1;
       
   694     }
       
   695     elsif ($keyWord =~ /^html_notes$/) {
       
   696       $self->{html_notes} = 1;
       
   697     }
       
   698     elsif ($keyWord =~ /^temp_dir$/) {
       
   699       Utils::StripWhiteSpace(\$operand);
       
   700       $operand = File::Spec->catdir($operand);
       
   701       $operand =~ s/[\\\/]$//;
       
   702       if (!-d $operand  && length $operand) {
       
   703         die "Error: Invalid line in \"$self->{iniFileName}\":\n\t$_\n$operand does not exist or is an invalid directory name\n";
       
   704       }
       
   705       $self->{temp_dir} = $operand;
       
   706     }   
       
   707     elsif ($keyWord =~ /^remote_site_type$/) {
       
   708       Utils::StripWhiteSpace(\$operand);
       
   709       $self->{remote_site_type} = $operand;
       
   710     }
       
   711     elsif ($keyWord =~ /^remote_host$/) {
       
   712       Utils::StripWhiteSpace(\$operand);
       
   713       $self->{remote_host} = $operand;
       
   714     }
       
   715     elsif ($keyWord =~ /^remote_username$/) {
       
   716       Utils::StripWhiteSpace(\$operand);
       
   717       $self->{remote_username} = $operand;
       
   718     }
       
   719     elsif ($keyWord =~ /^remote_password$/) {
       
   720       Utils::StripWhiteSpace(\$operand);
       
   721       $self->{remote_password} = $operand;
       
   722     }
       
   723     elsif ($keyWord =~ /^remote_logs_dir$/) {
       
   724       Utils::StripWhiteSpace(\$operand);
       
   725       $self->{remote_logs} = $operand;
       
   726     }
       
   727     elsif ($keyWord =~ /^pgp_tool$/) {
       
   728       Utils::StripWhiteSpace(\$operand);
       
   729       $self->{pgp_tool} = $operand;
       
   730     }
       
   731     elsif ($keyWord =~ /^pgp_encryption_key$/) {
       
   732       Utils::StripWhiteSpace(\$operand);
       
   733       push @{$self->{pgp_encryption_keys}}, $operand;
       
   734     }
       
   735     elsif ($keyWord =~ /^pgp_config_path$/) {
       
   736       Utils::StripWhiteSpace(\$operand);
       
   737       $self->{pgp_config_path} = $operand;
       
   738     }
       
   739     elsif ($keyWord =~ /^export_data_file$/) {
       
   740       Utils::StripWhiteSpace(\$operand);
       
   741       $self->{export_data_file} = $operand;
       
   742     }
       
   743     elsif ($keyWord =~ /^archive_path_file$/) {
       
   744       $self->PathData->ProcessLine(\$keyWord, \$operand);
       
   745     }
       
   746     elsif ($keyWord =~ /^archive_path$/) {
       
   747       $self->PathData->ProcessLine(\$keyWord, \$operand);
       
   748     }
       
   749     elsif ($keyWord =~ /^source_map$/) {
       
   750        $self->ExtractMapping($operand);
       
   751     }
       
   752     elsif ($keyWord =~ /^no_ini_location_warning$/) {
       
   753       $self->{warnIniLocation} = 0;
       
   754     }
       
   755     elsif ($keyWord =~ /^ignore_binary$/) {
       
   756       Utils::StripWhiteSpace(\$operand);
       
   757       push (@{$self->{binIgnore}}, $operand);
       
   758     }
       
   759     elsif ($keyWord =~ /^proxy$/) {
       
   760       Utils::StripWhiteSpace(\$operand);
       
   761       $self->{proxy} = $operand;
       
   762     }
       
   763     elsif ($keyWord =~ /^proxy_username$/) {
       
   764       Utils::StripWhiteSpace(\$operand);
       
   765       $self->{proxy_username} = $operand;
       
   766     }
       
   767     elsif ($keyWord =~ /^proxy_password$/) {
       
   768       Utils::StripWhiteSpace(\$operand);
       
   769       $self->{proxy_password} = $operand;
       
   770     }
       
   771     elsif ($keyWord =~ /^pasv_transfer_mode$/) {
       
   772       $self->{pasv_transfer_mode} = 1;
       
   773     }
       
   774     elsif ($keyWord =~ /^ftp_server_supports_resume$/) {
       
   775       $self->{ftp_server_supports_resume} = 1;
       
   776     }
       
   777     elsif ($keyWord =~ /^ftp_timeout$/) {
       
   778       Utils::StripWhiteSpace(\$operand);
       
   779       $self->{ftp_timeout} = $operand;
       
   780     }
       
   781     elsif ($keyWord =~ /^ftp_reconnect_attempts$/) {
       
   782       Utils::StripWhiteSpace(\$operand);
       
   783       $self->{ftp_reconnect_attempts} = $operand;
       
   784     }
       
   785     elsif ($keyWord =~ /^max_export_volume_size$/) {
       
   786       Utils::StripWhiteSpace(\$operand);
       
   787       $self->{max_export_volume_size} = $operand;
       
   788     }
       
   789     elsif ($keyWord =~ /^disallow_unclassified_source$/) {
       
   790       $self->{disallow_unclassified_source} = 1;
       
   791     }
       
   792     elsif ($keyWord =~ /^disable_win32_exten[ts]ions$/) {
       
   793       $self->{disable_win32_extensions} = 1;
       
   794     }
       
   795     elsif ($keyWord =~ /^categori[sz]e_binaries$/) {
       
   796       $self->{categorise_binaries} = 1;
       
   797     }
       
   798     elsif ($keyWord =~ /^categori[sz]e_exports$/) {
       
   799       $self->{categorise_exports} = 1;
       
   800     }
       
   801     elsif ($keyWord =~ /^latestver_filter$/) {
       
   802       Utils::StripWhiteSpace(\$operand);
       
   803       require Text::Glob;
       
   804       $self->{latestver_filter} = Text::Glob::glob_to_regex($operand);;
       
   805     }    
       
   806     elsif ($keyWord =~ /^required_binaries$/) {
       
   807       Utils::StripWhiteSpace(\$operand);
       
   808       (my $component, my $required, my $dummy) = split (/\s+/, $operand);
       
   809       if ($dummy or not ($component and $required)) {
       
   810         die "Error: Invalid line in \"$self->{iniFileName}\":\n\t$_\n";
       
   811         next;
       
   812       }
       
   813       push (@{$self->{required_binaries}->{lc($component)}}, lc($required));
       
   814     }
       
   815     #Support for target alias file
       
   816     elsif ($keyWord =~ /^no_target_alias_warning$/) {
       
   817       $self->{mustWarnTargetAliasLocation} = 0;
       
   818     }
       
   819     elsif ($keyWord =~ /^table_format$/) {
       
   820       Utils::StripWhiteSpace(\$operand);
       
   821       (my $format, my $args) = $operand =~ m/^(\w+)(.*)$/;
       
   822       Utils::StripWhiteSpace(\$args);
       
   823       $self->{table_format} = $format;
       
   824       $self->{table_format_args} = $args;
       
   825     }
       
   826     elsif ($keyWord =~ /^illegal_workspace_volumes$/) {
       
   827       Utils::StripWhiteSpace(\$operand);
       
   828       if ($operand !~ /^[a-z\s,]+$/i) {
       
   829         die "Error: Invalid line in \"$self->{iniFileName}\":\n\t$_\n";
       
   830       }
       
   831       @{$self->{illegal_workspace_volumes}} = split /\s*,\s*/,$operand;
       
   832     }
       
   833     elsif ($keyWord =~ /^use_distribution_policy_files_first/) {
       
   834       $self->{use_distribution_policy_files_first} = 1;
       
   835     }
       
   836     elsif ($keyWord =~ /^csv_separator$/) {
       
   837       Utils::StripWhiteSpace(\$operand);
       
   838       $self->{csv_separator} = $operand;
       
   839     }
       
   840     elsif ($keyWord =~ /^sbs_version$/) {
       
   841       Utils::StripWhiteSpace(\$operand);
       
   842       $self->{sbs_version} = $operand;
       
   843     }
       
   844     else {
       
   845       die "Error: Unknown keyword \"$keyWord\" in \"$self->{iniFileName}\"\n";
       
   846     }
       
   847   }
       
   848   
       
   849   close (INI);
       
   850 
       
   851   if ($self->{warnIniLocation}) {
       
   852     if (defined $$envDir){
       
   853        print "Warning: \"$$iniName\" not found in \"$$envDir\", using version found in \"$$binDir\"\n";
       
   854     } else {
       
   855        print "Warning: Using \"$$iniName\" version found in \"$$binDir\"\n";
       
   856     }
       
   857     print "         Use the keyword \"no_ini_location_warning\" to disable this warning.\n";
       
   858   }
       
   859 }
       
   860 
       
   861 sub ReadTargetAliasFile {
       
   862   my $self = shift;
       
   863   
       
   864   if (-e $self->{targetAliasName}) {
       
   865     open (ALIAS, $self->{targetAliasName}) or die "Unable to open \"$self->{targetAliasName}\" for reading: $!\n";
       
   866     # %allValuesSeenSoFar is a temporary hash of all the values seen so far
       
   867     my %allValuesSeenSoFar = ();
       
   868     # %aliasMap is the final hash of keys to values with all aliases expanded out
       
   869     my %aliasMap = ();
       
   870     $self->{alias_map} = {};
       
   871     while (local $_ = <ALIAS>) {
       
   872       # Remove line feed, white space and comments.
       
   873       chomp;
       
   874       s/^\s*$//;
       
   875       s/(?<!\\)#.*//; # remove comments unless they are immediately preceded by \ (negative lookbehind assertion)
       
   876       s/\\#/#/g; # now remove backslashes before # signs
       
   877       if ($_ eq '') {
       
   878         # Nothing left.
       
   879         next;
       
   880       }
       
   881       my $keyWord;        # The key field
       
   882       my @valueList;      # The list of values as read from the line.
       
   883       my %seen = ();      # Temporary hash for making values on the line unique
       
   884       if (/^\s*(\S+)\s+(.+)/) {
       
   885         # Uppercase significant
       
   886         $keyWord = uc($1);
       
   887         @valueList = split /\s+/, uc($2);
       
   888         # Check the key for:
       
   889         # A key that has been seen as already as a value i.e. a forward reference - fatal error
       
   890         # A key that has been seen as already as a key i.e. a duplicate key - fatal error
       
   891         if (exists $allValuesSeenSoFar{$keyWord}) {
       
   892           die "Fatal error: Line \"$_\" in $self->{targetAliasName} has forward reference to \"$keyWord\"\n";
       
   893         }
       
   894         elsif (exists $self->{alias_map}->{$keyWord}) {
       
   895           die "Fatal error: Line \"$_\" in $self->{targetAliasName} has duplicate key \"$keyWord\"\n";
       
   896         }
       
   897         # Check for:
       
   898         # Circular references - fatal error
       
   899         # Duplicates in the value list - warn and ignore
       
   900         foreach my $value (@valueList) {
       
   901           if ($value eq $keyWord) {
       
   902             die "Fatal error: Line \"$_\" in $self->{targetAliasName} has circular reference in \"$keyWord\"\n"
       
   903           }
       
   904           elsif (exists $seen{$value}) {
       
   905             print "Warning Line \"$_\" in $self->{targetAliasName} has duplicate value entry \"$value\" in key $keyWord\n";
       
   906           }
       
   907           else {
       
   908             # Add to seen map and uniqueList
       
   909             $seen{$value} = 1;
       
   910             $allValuesSeenSoFar{$value} = 1;
       
   911           }
       
   912         }
       
   913         my @resolvedList = ();  # Resolved aliases
       
   914         # Check for the special use of the value '<EMPTY>'
       
   915         # If this is present then there must be no other values.
       
   916         if (exists $seen{"<EMPTY>"}) {
       
   917           if (scalar (keys %seen) > 1) {
       
   918             die "Fatal error: Multiple targets in list declared \"<EMPTY>\" for alias \"$keyWord\"\n";
       
   919           }
       
   920         } else {
       
   921           # Now can expand the unique list by resolving aliases against existing keys
       
   922           foreach my $uniqueLine (keys %seen) {
       
   923             if (exists $self->{alias_map}->{$uniqueLine}) {
       
   924               # Expand the list to resolve the aliases
       
   925               push(@resolvedList, @{$self->{alias_map}->{$uniqueLine}});
       
   926             }
       
   927             else {
       
   928               # No alias resolution required, just add it
       
   929               push(@resolvedList, $uniqueLine);
       
   930             }
       
   931           }
       
   932         }
       
   933         # Add the resolved list to the aliasMap
       
   934         push( @{$self->{alias_map}->{$keyWord}}, @resolvedList);
       
   935       }
       
   936       else {
       
   937         # A line with no value is illegal.
       
   938         # Grab the key word
       
   939         if (/^\s*(\S+)/) {
       
   940           # Make uppercase as HasTargetPlatforms(), TargetPlatforms()
       
   941           # expects uppercase keys
       
   942           $keyWord = uc($1);
       
   943         } else {
       
   944           die "Fatal error: Fatal parser error.\n"
       
   945         }
       
   946         die "Fatal error: No targets detected for \"$keyWord\"\n"
       
   947       }
       
   948     unless (defined $keyWord) {
       
   949       die "Error: Invalid line in \"$self->{targetAliasName}\":\n\t$_\n";
       
   950       next;
       
   951     }
       
   952   }
       
   953   close (ALIAS);
       
   954   } else {
       
   955     # Failed to find target alias file
       
   956     return 0;
       
   957   }
       
   958   return 1; # Success at reading the file
       
   959 }
       
   960 
       
   961 # Support for target alias file
       
   962 # Returns 1 if target platforms exist for a given alias
       
   963 # or 0 if no target platforms exist for a given alias
       
   964 sub HasTargetPlatforms {
       
   965   my $self = shift;
       
   966   my $alias = shift;
       
   967   $alias = uc($alias);
       
   968   $self->CheckAliasWarning();
       
   969   if (exists $self->{alias_map}) {
       
   970     if (exists $self->{alias_map}->{$alias}) {
       
   971       return 1;
       
   972     }
       
   973   }
       
   974   return 0;
       
   975 }
       
   976 
       
   977 # Support for target alias file
       
   978 # Returns the arrary of target platforms for a given alias
       
   979 # or undef if no target platforms for a given alias
       
   980 sub TargetPlatforms {
       
   981   my $self = shift;
       
   982   my $alias = shift;
       
   983   $self->CheckAliasWarning();
       
   984   $alias = uc($alias);
       
   985   if (exists $self->{alias_map}) {
       
   986     if (exists $self->{alias_map}->{$alias}) {
       
   987       return $self->{alias_map}->{$alias};
       
   988     }
       
   989   }
       
   990   # Nothing found so return the callers argument
       
   991   return [$alias];
       
   992 }
       
   993 
       
   994 sub CheckAliasWarning {
       
   995   my $self = shift;
       
   996   if ($self->{mustWarnTargetAliasLocation} == 1) {
       
   997     print "Warning: \"$self->{targetAliasName}\" not found.\n";
       
   998     print "         Use the keyword \"no_target_alias_warning\" to disable this warning.\n";
       
   999    }
       
  1000   $self->{mustWarnTargetAliasLocation} = 0;
       
  1001 }
       
  1002 
       
  1003 sub UseDistributionPolicyFilesFirst {
       
  1004   my $self = shift;
       
  1005   return !!$self->{use_distribution_policy_files_first};
       
  1006 }
       
  1007 
       
  1008 sub CsvSeparator {
       
  1009   my $self = shift;
       
  1010   
       
  1011   if (defined $self->{csv_separator}) {
       
  1012     return $self->{csv_separator};
       
  1013   }
       
  1014   
       
  1015   return ',';
       
  1016 }
       
  1017 
       
  1018 1;
       
  1019 
       
  1020 __END__
       
  1021 
       
  1022 =head1 NAME
       
  1023 
       
  1024 IniData.pm - Provides an interface to the data contained in reltools.ini.
       
  1025 
       
  1026 =head1 INTERFACE
       
  1027 
       
  1028 =head2 New
       
  1029 
       
  1030 Expects to find a file named F<reltools.ini> in the release tools directory, dies if it can't. Parses this file according to the following keywords / value pairs:
       
  1031 
       
  1032  require_internal_versions
       
  1033  ignore_source_filter_errors
       
  1034  no_ini_location_warning
       
  1035  disallow_unclassified_source
       
  1036  categorise_binaries
       
  1037  categorise_exports
       
  1038  html_notes
       
  1039  archive_path                <archive_name> <archive_path> [<remote_archive_path>]
       
  1040  diff_tool                   <tool_name>
       
  1041  export_data_file            <file_name>
       
  1042  archive_path_file           <file_name>
       
  1043  source_map                  <archive_source_directory> <local_source_directory>
       
  1044  remote_site_type            <server_type>
       
  1045  remote_host                 <host_name>
       
  1046  remote_username             <user_name>
       
  1047  remote_password             <pass_word>
       
  1048  remote_logs_dir             <path>
       
  1049  pasv_transfer_mode
       
  1050  ftp_server_supports_resume
       
  1051  ftp_timeout                 <time_in_seconds>
       
  1052  ftp_reconnect_attempts      <positive_integer>
       
  1053  proxy                       <host_name>
       
  1054  proxy_username              <user_name>
       
  1055  proxy_password              <pass_word>
       
  1056  pgp_tool                    <tool_name>
       
  1057  pgp_encryption_key          <keyid>
       
  1058  pgp_config_path             <dir_name>
       
  1059  ignore_binary               <wild_file_name>
       
  1060  required_binaries           default wins_udeb
       
  1061  required_binaries           default thumb_urel
       
  1062  table_format                <table_format module>
       
  1063  csv_separator               <csv_separator_character>
       
  1064  sbs_version                 <symbian_build_system>
       
  1065 
       
  1066 It assumes # indicates the start of a comment, unless it is preceded by \.
       
  1067 
       
  1068 =head2 DiffTool
       
  1069 
       
  1070 Returns the name of the differencing tool specified with the C<diff_tool> keyword.
       
  1071 
       
  1072 =head2 RequireInternalVersions
       
  1073 
       
  1074 Returns true or false depending on whether the C<require_internal_versions> keyword has been specified.
       
  1075 
       
  1076 =head2 IgnoreSourceFilterErrors
       
  1077 
       
  1078 Returns true or false depending on whether the C<ignore_source_filter_errors> keyword has been specified.
       
  1079 
       
  1080 =head2 RemoteSiteType
       
  1081 
       
  1082 Returns the type of server hosting the projects remote release archive. Currently this will return either C<'FTP'>, C<'FTP::Proxy'>, C<'NetDrive'>, C<'NetDrive::MultiVolumeExport'> or C<'NetDrive::MultiVolumeImport'>. The default return value is C<'FTP'> if not set.
       
  1083 
       
  1084 =head2 RemoteHost
       
  1085 
       
  1086 Returns the host address of the project's remote site. If the remote site is an ftp server this will be an ftp address; if it is a network drive then the return value will be a UNC path.
       
  1087 
       
  1088 =head2 RemoteUsername
       
  1089 
       
  1090 Returns the username for the project's remote site.
       
  1091 
       
  1092 =head2 RemotePassword
       
  1093 
       
  1094 Returns the password for the project's remote site.
       
  1095 
       
  1096 =head2 RemoteLogsDir
       
  1097 
       
  1098 Returns the directory on the project's remote site where release notification logs are to be written.
       
  1099 
       
  1100 =head2 PasvTransferMode
       
  1101 
       
  1102 Returns true or false depending on whether the C<pasv_transfer_mode> keyword has been specified.
       
  1103 
       
  1104 =head2 FtpServerSupportsResume
       
  1105 
       
  1106 Returns true or false depending on whether the C<ftp_server_supports_resume> keyword has been specified.
       
  1107 
       
  1108 =head2 FtpTimeout
       
  1109 
       
  1110 Returns the timeout in seconds allowed before dropping the connection to the FTP server
       
  1111 
       
  1112 =head2 FtpReconnectAttempts
       
  1113 
       
  1114 Returns the number of attempts to reconnect to the FTP site if the connection is dropped
       
  1115 
       
  1116 =head2 Proxy
       
  1117 
       
  1118 Returns the FTP address of a proxy server used to connect to the project's FTP site.
       
  1119 
       
  1120 =head2 ProxyUsername
       
  1121 
       
  1122 Returns the username for a proxy server used to connect to the project's FTP site.
       
  1123 
       
  1124 =head2 ProxyPassword
       
  1125 
       
  1126 Returns the password for a proxy server used to connect to the project's FTP site.
       
  1127 
       
  1128 =head2 RemoteSite
       
  1129 
       
  1130 Tries to create a RemoteSite object appropriate to the data in the iniData, and return it. Caches the RemoteSite object so that it is only created once.
       
  1131 
       
  1132 =head2 MaxExportVolumeSize
       
  1133 
       
  1134 Returns the value specified by the keyword C<max_export_volume_size>. If this has not been specified, returns 639 * 1024 * 1024.
       
  1135 
       
  1136 =head2 PgpTool
       
  1137 
       
  1138 Returns the command line PGP client used to encrypt and decrypt releases.
       
  1139 Currently this will return either C<'PGP'> for NAI Inc. PGP or C<'GPG'> for GNU Privacy Guard. The default return value is C<'PGP'> if not set.
       
  1140 
       
  1141 =head2 PgpEncryptionKeys
       
  1142 
       
  1143 Returns a reference to an array of PGP key ids (an 8 digit hexadecimal number) used to encrypt all release files before exporting to the remote site. Typically these values will correspond to the local sites project PGP keys so that the user may decrypt their own releases.
       
  1144 
       
  1145 =head2 PgpConfigPath
       
  1146 
       
  1147 Returns the directory where the users PGP configuration and keyring files are stored.
       
  1148 
       
  1149 =head2 ArchivePathFile
       
  1150 
       
  1151 Returns the name of the archive path file.
       
  1152 
       
  1153 =head2 ExportDataFile
       
  1154 
       
  1155 Returns the name of the export data file.
       
  1156 
       
  1157 =head2 LocalArchivePath
       
  1158 
       
  1159 Expects to be passed a component name. Returns the path to the component's local archive (generally on a LAN share).
       
  1160 
       
  1161 =head2 RemoteArchivePath
       
  1162 
       
  1163 Expects to be passed a component name. Returns the path to the component's remote archive (may be either on a Network share or an FTP site).
       
  1164 
       
  1165 =head2 ListArchiveComponents
       
  1166 
       
  1167 Returns a list of component names specified in the archive path file. One of these may be 'default' (if this has been specified). The directories pointed to by this may contain multiple components.
       
  1168 
       
  1169 =head2 BinariesToIgnore
       
  1170 
       
  1171 Returns a reference to a list of binaries to be ignored when scanning the F<\epoc32> tree. These may contain the C<*> wild character.
       
  1172 
       
  1173 =head2 DisallowUnclassifiedSource
       
  1174 
       
  1175 Returns false unless the C<disallow_unclassified_source> keyword has been specified.
       
  1176 
       
  1177 =head2 Win32ExtensionsDisabled
       
  1178 
       
  1179 Returns false unless the C<disable_win32_extensions> keyword has been specified. (Spelling C<disable_win32_extentions> also OK!)
       
  1180 
       
  1181 =head2 CategoriseBinaries
       
  1182 
       
  1183 Returns false unless the C<categorise_binaries> keyword has been specified.
       
  1184 
       
  1185 =head2 CategoriseExports
       
  1186 
       
  1187 Returns false unless the C<categorise_exports> keyword has been specified.
       
  1188 
       
  1189 =head2 TableFormatter
       
  1190 
       
  1191 Returns a TableFormatter object, which can be used to print a table.
       
  1192 
       
  1193 =head2 RequiredBinaries
       
  1194 
       
  1195 Expects to be passed a component name. Returns the required binaries for that component if any were specified using the C<required_binaries> keyword. If none were, then those specified using C<required_binaries default> are returned. If there are none of those either, then C<undef> is returned - this means that all binaries should be used.
       
  1196 
       
  1197 =head2 PathData
       
  1198 
       
  1199 Returns a PathData object appropriate to the path configuration data in the ini file. This may be a PathData::ProjectBased or a PathData::ComponentBased object.
       
  1200 
       
  1201 =head2 FromMapping
       
  1202 
       
  1203 Returns an array of <archive_source_directory> mappings. If there are no mappings defined an undefined value is returned.
       
  1204 
       
  1205 =head2 ToMapping
       
  1206 
       
  1207 Returns an array of <local_source_directory> mappings. If there are no mappings defined an undefined value is returned.
       
  1208 
       
  1209 =head2 HasMappings
       
  1210 
       
  1211 Returns false if no mappings are defined. Otherwise returns true.
       
  1212 
       
  1213 =head2 PerformMapOnFileName
       
  1214 
       
  1215 Reads a filename and takes all mappings defined into consideration with <archive_source_directory> being mapped to <local_source_directory>. Returns the new filename, with the mappings processed.
       
  1216 
       
  1217 =head2 PerformReverseMapOnFileName
       
  1218 
       
  1219 Reads a filename and takes all mappings defined into consideration with <local_source_directory> being mapped to <archive_source_directory>. Returns the new filename, with the mappings processed.
       
  1220 
       
  1221 =head2 CheckMappingPath
       
  1222 
       
  1223 Expects a mapping path which is checked. Any problems with the path are reported and the program exits. Otherwise returns the checked mapping path.
       
  1224 
       
  1225 =head2 ExtractMapping
       
  1226 
       
  1227 Is used to extract and store the local and archive mappings directories as defined. If an usage error is encountered, an error message is displayed and the program exits.
       
  1228 
       
  1229 =head2 CheckFileNameForMappingClash
       
  1230 
       
  1231 Is used to check if any of the mappings defined clash with the filename passed. If there is a clash an error message is shown and the program exits.
       
  1232 
       
  1233 =head2 HasTargetPlatforms
       
  1234 
       
  1235 Returns true if there is are any target platforms for a given alias. False otherwise.
       
  1236 
       
  1237 =head2 TargetPlatforms
       
  1238 
       
  1239 Returns a reference to a list containing either the platforms for a given alias or the alias itself (i.e. not an alias but a platform name).
       
  1240 
       
  1241 =head2 CsvSeparator
       
  1242 
       
  1243 Returns the separator to be used for CSV files, which by default is a comma ','.  Depending on the locale, the separator may be different.  The user can specify the separator required by using the C<csv_separator> keyword.
       
  1244 
       
  1245 
       
  1246 =head1 KNOWN BUGS
       
  1247 
       
  1248 None.
       
  1249 
       
  1250 =head1 COPYRIGHT
       
  1251 
       
  1252  Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
  1253  All rights reserved.
       
  1254  This component and the accompanying materials are made available
       
  1255  under the terms of the License "Eclipse Public License v1.0"
       
  1256  which accompanies this distribution, and is available
       
  1257  at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
  1258  
       
  1259  Initial Contributors:
       
  1260  Nokia Corporation - initial contribution.
       
  1261  
       
  1262  Contributors:
       
  1263  
       
  1264  Description:
       
  1265  
       
  1266 
       
  1267 =cut