imgtools/buildrom/tools/romutl.pm
changeset 600 6d08f4a05d93
equal deleted inserted replaced
599:fa7a3cc6effd 600:6d08f4a05d93
       
     1 # Copyright (c) 2006-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 # Collection of utilitiy functions which is copied from Symbian OS perl modules. 
       
    15 # It provides platform related information to ROM Tools including buildrom, 
       
    16 # features.pl, etc.
       
    17 # 
       
    18 
       
    19 package romutl;
       
    20 
       
    21 require Exporter;
       
    22 @ISA=qw(Exporter);
       
    23 @EXPORT=qw(
       
    24   init_plat
       
    25   init_bsfs
       
    26   init_platwithbpabi
       
    27   
       
    28   get_epocroot
       
    29   get_drive
       
    30   get_epocdrive
       
    31   get_versionedname
       
    32   get_bpabiplatlist
       
    33   get_platlist
       
    34   get_platcustomizes
       
    35   get_platroot
       
    36   get_makeeabspath
       
    37   get_variantmacrolist  
       
    38   get_variantmacroHRHfile
       
    39   get_abiv2mode
       
    40   get_variantfullpath
       
    41   get_BVbinname
       
    42   get_variant
       
    43   
       
    44   is_existinpath
       
    45   
       
    46   set_verbose
       
    47   
       
    48   check_varfile
       
    49   split_path
       
    50   append_driveandquote  
       
    51   write_32bit
       
    52 );
       
    53 
       
    54 
       
    55 # EPOCROOT with proper format 
       
    56 my $epocroot;
       
    57 my $epocdrive = "";
       
    58 my $drive = "";
       
    59 
       
    60 BEGIN {
       
    61     require 5.005_03;       # check user has a version of perl that will cope
       
    62     
       
    63     $epocroot = $ENV{EPOCROOT};
       
    64     $epocroot = "\/" if (!$epocroot); # use "\" if EPOCROOT is not specified
       
    65     $epocroot =~ s/\\/\//g;
       
    66     $epocroot .= "\/" unless $epocroot =~ /\/$/;
       
    67 }
       
    68 
       
    69 use strict;
       
    70 use Cwd;
       
    71 use File::Spec;
       
    72 use romosvariant;
       
    73 
       
    74 my $verbose=0;
       
    75 
       
    76 ########################
       
    77 #Init
       
    78 #
       
    79 
       
    80 #die "ERROR: EPOCROOT must specify an existing directory." if (!-d $epocroot);
       
    81 #die "ERROR: EPOCROOT must not be a UNC path\n" if ($epocroot =~ /^\\\\/);
       
    82 
       
    83 $drive=$1 if (cwd =~ /^(.:)/);
       
    84 
       
    85 if ($epocroot =~ /^(.:)/)
       
    86 {
       
    87     $epocdrive=$1;
       
    88 }
       
    89 else
       
    90 {
       
    91 # current working directory is different to SDK's
       
    92     $epocdrive=$drive
       
    93 }
       
    94 
       
    95 #####################################
       
    96 # General functions
       
    97 #
       
    98 
       
    99 sub get_epocroot
       
   100 {
       
   101     return $epocroot;
       
   102 }
       
   103 
       
   104 sub get_epocdrive
       
   105 {
       
   106     return $epocdrive;
       
   107 }
       
   108 
       
   109 sub get_drive
       
   110 {
       
   111     return $drive;
       
   112 }
       
   113 
       
   114 sub set_verbose
       
   115 {
       
   116     $verbose = shift;
       
   117 }
       
   118 
       
   119 use constant QUIET_NOT_FOUND => 0; #  return 0 if file not found in the PATH
       
   120 use constant DIE_NOT_FOUND => 1; #  issue error and die if file not found in the PATH
       
   121 use constant ERROR_NOT_FOUND => 2; #  issue error and return 0 if file not found in the PATH
       
   122 
       
   123 # Simulate shell to locate executable file in the PATH
       
   124 #
       
   125 # WARNING: don't use this func in a deep loop because of the
       
   126 #          less efficient implementation
       
   127 #
       
   128 # usage:  is_existinpath <filename> [<flag>]
       
   129 #
       
   130 #   flag == DIE_NOT_FOUND    die and display error when not found
       
   131 #   flag == ERROR_NOT_FOUND  display error and return 0 when not found
       
   132 #   else return 0 when not found
       
   133 #   return 1 when found     
       
   134 
       
   135 sub is_existinpath
       
   136 {
       
   137     my ($filename, $flag)=@_;
       
   138     return 0 unless defined $filename;
       
   139     return 0 if ($filename =~ /\\/);
       
   140     return 0 if ($filename =~ /\//); 
       
   141     
       
   142     my @paths;
       
   143     my $delimiter = &env_delimiter;
       
   144  		@paths = split(/$delimiter/, $ENV{PATH});
       
   145     unshift @paths, "\.";
       
   146     
       
   147     foreach my $path (@paths)
       
   148     {
       
   149         next if ($path =~ /^\s*$/);
       
   150         chomp $path;
       
   151         $path =~ s/\\/\//g;
       
   152         $path .= "\/" unless ($path =~ /\/$/);
       
   153         $path = $path.$filename;
       
   154         foreach my $ext ("", ".bat", ".cmd", ".exe", ".com", ".pl", ".py")
       
   155         {
       
   156             return 1 if (-e $path.$ext);
       
   157         }
       
   158     }
       
   159     die "Error: Cannot found \"$filename\" in the PATH.\n" if ($flag == DIE_NOT_FOUND);
       
   160     print "Error: Cannot found \"$filename\" in the PATH.\n" if ($flag == ERROR_NOT_FOUND);
       
   161     return 0;
       
   162 } 
       
   163 
       
   164 #########################################
       
   165 # Symbian variant functions and variables
       
   166 # 
       
   167 # copy from e32variant.pm
       
   168 #
       
   169 
       
   170 my $toolspath = $epocroot . "epoc32\/tools\/";
       
   171 # SPPR begin
       
   172 # enable includation of spp_variant.cfg if it exist
       
   173 my $spp_cfgFile = $toolspath . "variant\/spp_variant.cfg";
       
   174 my $cfgFile = $toolspath . "variant\/variant.cfg"; # default location
       
   175 $cfgFile = $spp_cfgFile if -e $spp_cfgFile; # use spp_variant.cfg
       
   176 # SPPR End
       
   177 
       
   178 my $variantABIV2Keyword = &get_abiv2mode;    # if variant ABIv2 mode enabled
       
   179 
       
   180 my $hrhdrive = $epocdrive;   # variant hrh drive
       
   181 my $hrhfile;    # variant hrh file
       
   182 my @macros;     # variant macros
       
   183 
       
   184 if ($cfgFile =~ /^(.:)/i)
       
   185 {
       
   186    $hrhdrive = lc($1); 
       
   187 }
       
   188 
       
   189 # returns the variant specific macro definitions as a list
       
   190 sub get_variantmacrolist{
       
   191     
       
   192     return @macros if (@macros);
       
   193     
       
   194     my $vfile = get_variantmacroHRHfile();
       
   195     
       
   196     if($vfile)
       
   197     {
       
   198         my $VariantFilePath = split_path('Path',$vfile);
       
   199         chop( $VariantFilePath );
       
   200         $VariantFilePath = &append_driveandquote($VariantFilePath);
       
   201         $vfile = &append_driveandquote($vfile);
       
   202         my $e32Path = &append_driveandquote($epocroot."epoc32\/include");
       
   203         
       
   204         open CPPPIPE,"cpp -I $e32Path -I $VariantFilePath -undef -dM $vfile |" or die "ERROR: Can't invoke CPP.EXE\n";
       
   205         while(<CPPPIPE>){
       
   206             if($_ =~ /(\#define)(\s+)(.+)/){
       
   207                 push @macros, $3;
       
   208             }
       
   209         }
       
   210         close CPPPIPE;
       
   211     }
       
   212     return @macros;
       
   213 }
       
   214 
       
   215 # return hrh filename defined in variant cfg file
       
   216 # notice: abort if hrh file located in different drive to cfg file
       
   217 sub get_variantmacroHRHfile{
       
   218     
       
   219     return $hrhfile if ($hrhfile);
       
   220     if(-e $cfgFile){
       
   221         open(FILE, $cfgFile) || die "\nCould not open: " . $cfgFile ."\n";
       
   222         while (<FILE>) {
       
   223             # strip comments
       
   224             s/^([^#]*)#.*$/$1/o;
       
   225             # skip blank lines
       
   226             if (/^\s*$/o) {
       
   227                 next;
       
   228             }
       
   229             # get the hrh file
       
   230             if($_ =~ /\.hrh/xi){
       
   231                 $hrhfile = $_; 
       
   232                 last;
       
   233             }
       
   234         }
       
   235         close FILE;
       
   236         die "\nERROR: No variant file specified in $cfgFile!\n" unless $hrhfile;
       
   237         $hrhfile =~ s/\s+//g;
       
   238         $hrhfile=~s/^(.:)//io;    # remove drive letter
       
   239         my $paths_drive = lc($1);
       
   240         
       
   241         chomp $hrhfile;
       
   242         $hrhfile = get_makeeabspath($epocroot."epoc32\/", $epocroot, $hrhfile); # assume relative to EPOCROOT
       
   243         
       
   244         
       
   245         if($paths_drive){
       
   246             die "\nERROR: Variant file specified in $cfgFile is not on the same drive as \/epoc32\/\n" 
       
   247             unless ($paths_drive eq $hrhdrive);
       
   248         }
       
   249         die "\nERROR: $cfgFile specifies $hrhfile which doesn't exist!\n" unless (-e $hrhfile);
       
   250         
       
   251         # make sure it is in unix syntax
       
   252         $hrhfile=~ s/\\/\//g;
       
   253     }
       
   254     return $hrhfile;
       
   255 }
       
   256 
       
   257 # get status of EANBLE_ABIV2_MODE
       
   258 # 1=enabled 0=disabled
       
   259 sub get_abiv2mode{
       
   260 
       
   261     return $variantABIV2Keyword if (defined $variantABIV2Keyword);
       
   262 
       
   263     $variantABIV2Keyword=0;
       
   264     if(-e $cfgFile){
       
   265         open(FILE, $cfgFile) || die "\nCould not open: " . $cfgFile ."\n";
       
   266         while (<FILE>) {
       
   267             # strip comments
       
   268             s/^([^#]*)#.*$/$1/o;
       
   269             # skip blank lines
       
   270             if (/^\s*$/o) {
       
   271             next;
       
   272             }
       
   273             # get the hrh file
       
   274             if($_ =~ /^ENABLE_ABIV2_MODE$/xi){
       
   275                 $variantABIV2Keyword=1;
       
   276                 last;
       
   277             }
       
   278         }
       
   279         close FILE;
       
   280     }
       
   281 
       
   282     return $variantABIV2Keyword;
       
   283 }
       
   284 
       
   285 #############################
       
   286 # Path utilities
       
   287 #
       
   288 # copy from pathutl.pm
       
   289 #
       
   290 
       
   291 #args: $_[0] Start EPOCPath Abs FilePath/Path $_[1]... list of (Abs/Rel FilePath/Path)
       
   292 # Variant of MakAbs which also maps "+\\" to "${EPOCPath}"
       
   293 sub get_makeeabspath ($@) {    
       
   294     return undef unless $_[0]=~m-^(.:)?[\\\/]-o;
       
   295     my ($EPOCPath,$Path,@List)=@_;
       
   296     my $BasePath=&split_path("Path",$Path);
       
   297     undef $Path;
       
   298     my $p;
       
   299     foreach $p (@List) {
       
   300     		$p =~ s-\\-\/-g;
       
   301         if ($p=~m-^\/?epoc32\/(.*)$-io) {    # change - special case for existing \\epoc32 references
       
   302             $p=$EPOCPath.$1;
       
   303             next;
       
   304         }
       
   305         if ($p=~m-^\s*\+\/(.*)$-o) {
       
   306             $p=$EPOCPath.$1;
       
   307             next;
       
   308         }
       
   309         if ($p=~m-^\.{2}-o) {
       
   310             $p=&strip_path($BasePath.$p);
       
   311             next;
       
   312         }
       
   313         if ($p=~m-^[^\.\/]-o) {
       
   314             $p=$BasePath.$p unless ($p =~ m-^.:-o);
       
   315             next;
       
   316         }
       
   317         if ($p=~m-^(.:)?\/-o) {
       
   318             next;
       
   319         }
       
   320         if ($p=~m-^\.\/(.*)$-o) {
       
   321             $p=&strip_path($BasePath.$1);
       
   322             next;
       
   323         }
       
   324         return undef;
       
   325     }
       
   326     return wantarray ? @List : $List[0];
       
   327 }
       
   328 
       
   329 #args: $_[0] Abs FilePath/Path
       
   330 # Remove excess occurrences of '..' and '.' from a path
       
   331 sub strip_path ($) {   
       
   332     return undef unless $_[0]=~m-^(.:)?[\/\\]-o;
       
   333     my $P=$_[0];
       
   334     while ($P=~s-([\/\\])\.[\/\\]-$1-go) { }
       
   335     while ($P=~s-[\\](?!\.{2}\\)[^\\]*\\\.{2}(?=\\)--go) { }
       
   336     $P;
       
   337 }
       
   338 
       
   339 #args: $_[0] 'Path' or 'Base' or 'Ext' $_[1] Abs/Rel FilePath/Path
       
   340 # return the section of a file path required - Path, Base, Ext or File
       
   341 sub split_path ($$) { 
       
   342     my ($Sect,$P)=@_;
       
   343     
       
   344     return '' if !$P;    
       
   345     $Sect= ucfirst lc $Sect;
       
   346     if ($Sect eq 'Path') {
       
   347         if ($P=~/^(.*[\\\/])/o) {
       
   348             return $1;
       
   349         }
       
   350         return '';
       
   351     }
       
   352     undef;
       
   353 }
       
   354 
       
   355 sub append_driveandquote ($) {
       
   356 # Take a path, or list of paths, and prefix with drive based on 1. epocroot, 2.CWD.
       
   357 # Relative paths are just quoted.
       
   358     my @List=@_;
       
   359     my $Path;
       
   360 
       
   361     
       
   362     foreach $Path (@List) {
       
   363         next if ($Path !~ /^[\/\\]/); # skip prefix with drive letter or relative path
       
   364         $Path=$epocdrive.$Path;
       
   365     }
       
   366 
       
   367     foreach $Path (@List) {
       
   368         chomp $Path;
       
   369         $Path="\"".$Path."\"";
       
   370     }
       
   371     
       
   372     return wantarray ? @List : $List[0];
       
   373 }
       
   374 
       
   375 
       
   376 ###############################
       
   377 # General Utilities
       
   378 #
       
   379 # copy from genutl.pm
       
   380 #
       
   381 
       
   382 # return name with well formated version id in hex
       
   383 sub get_versionedname($) {
       
   384     my ($name) = @_;
       
   385     if ($name =~ /(.*)\{\s*(\d+)\s*\.\s*(\d+)\s*\}(.*?)$/i) {
       
   386         my $a = $1;
       
   387         my $b = $4;
       
   388         my $major = $2;
       
   389         my $minor = $3;
       
   390         return $a.sprintf("{%04x%04x}",$major,$minor).$b if ($major<32768 and $minor<32768);
       
   391     }
       
   392     return $name;
       
   393 }
       
   394 
       
   395 
       
   396 ###############################
       
   397 # BPABI Platform Utilities
       
   398 #
       
   399 # copy from bpabiutl.pm
       
   400 #
       
   401 
       
   402 my @BPABIPlats;
       
   403 
       
   404 
       
   405 # Identify the BPABI platforms to be supported based on the compiler configuration files
       
   406 # present in the location specified by the environment variable "SYMBIAN_COMPILATION_CONFIG_DIR"
       
   407 # and in the directory $EPOCROOT\epoc32\tools\compilation_config
       
   408 sub get_bpabiplatlist 
       
   409 {
       
   410     return @BPABIPlats if (scalar(@BPABIPlats));
       
   411     
       
   412     my @CompilerConfigPath;
       
   413 
       
   414     if (exists($ENV{'SYMBIAN_COMPILATION_CONFIG_DIR'})) 
       
   415     {
       
   416         my $Path = $ENV{SYMBIAN_COMPILATION_CONFIG_DIR};
       
   417         @CompilerConfigPath = split(/;/, $Path);
       
   418     }
       
   419 
       
   420     push @CompilerConfigPath, "${epocroot}epoc32\/tools\/compilation_config";
       
   421 
       
   422     my $ConfigDir;
       
   423 
       
   424     foreach $ConfigDir (@CompilerConfigPath)
       
   425     {
       
   426         opendir DIR, "$ConfigDir";
       
   427         my @Plats=grep /\.mk$/i, readdir DIR;
       
   428         my $Plat;
       
   429         foreach $Plat (@Plats) 
       
   430         {
       
   431 # The platform name will be same as the name of the configuration file <config.mk>
       
   432 # with the suffix '.mk' removed
       
   433             $Plat =~ s/\.mk//;
       
   434             if ($variantABIV2Keyword) {
       
   435                 if ($Plat =~ /^armv5_abiv2$/i) {
       
   436                     $Plat = "ARMV5";
       
   437                 }
       
   438             }
       
   439             else {
       
   440                 if ($Plat =~ /^armv5$/i) {
       
   441                     $Plat = "ARMV5_ABIV2";
       
   442                 }
       
   443             }
       
   444             unless (grep /$Plat$/i, @BPABIPlats) {
       
   445                 $Plat = uc $Plat;
       
   446                 push @BPABIPlats, $Plat;
       
   447             }
       
   448         }
       
   449     }
       
   450     closedir DIR;
       
   451     return @BPABIPlats;
       
   452 }
       
   453 
       
   454 #############################
       
   455 # Platform Utilities
       
   456 #
       
   457 # copy from e32plat.pm
       
   458 #
       
   459 my %Plat=(
       
   460     ARM4=>{
       
   461         ABI=>'ARM4',
       
   462         ASSP=>'MARM',
       
   463         ASSPABI=>'',
       
   464         Generic=>1,
       
   465     },
       
   466     ARM4SMP=>{
       
   467         ABI=>'ARM4',
       
   468         ASSP=>'MARM',
       
   469         ASSPABI=>'',
       
   470         Generic=>1,
       
   471         SMP=>1,
       
   472         StatLink=>'ARM4SMP',
       
   473     },
       
   474     ARM4T=>{
       
   475         ABI=>'ARM4T',
       
   476         ASSP=>'MARM',
       
   477         ASSPABI=>'',
       
   478         Generic=>1,
       
   479     },
       
   480     ARMI=>{
       
   481         ASSP=>'MARM',
       
   482         Generic=>1,
       
   483         ASSPABI=>'',
       
   484     },
       
   485     SARM4=>{
       
   486         ABI=>'ARM4',
       
   487         ASSP=>'MARM',
       
   488         ASSPABI=>'',
       
   489         Generic=>1,
       
   490         Single=>1,
       
   491     },
       
   492     SARMI=>{
       
   493         ASSP=>'MARM',
       
   494         ASSPABI=>'',
       
   495         Generic=>1,
       
   496         Single=>1,
       
   497     },
       
   498     STHUMB=>{
       
   499         ABI=>'THUMB',
       
   500         ASSP=>'MARM',
       
   501         ASSPABI=>'',
       
   502         Generic=>1,
       
   503         Single=>1,
       
   504     },
       
   505     THUMB=>{
       
   506         ABI=>'THUMB',
       
   507         ASSP=>'MARM',
       
   508         ASSPABI=>'',
       
   509         Generic=>1,
       
   510     },
       
   511     TOOLS=>{
       
   512         ABI=>'TOOLS',
       
   513         ASSPABI=>'',
       
   514         Compiler=>'VC32',
       
   515         CPU=>'TOOLS',
       
   516         OS=>'TOOLS',
       
   517         MakeMod=>'Cl_win',
       
   518         MakeCmd=>'nmake',
       
   519     },
       
   520     TOOLS2=>{
       
   521         ABI=>'TOOLS2',
       
   522         ASSPABI=>'',
       
   523         Compiler=>'GCC32',
       
   524         CPU=>'TOOLS2',
       
   525         OS=>'TOOLS2',
       
   526         MakeMod=>'Cl_mingw',
       
   527         MakeCmd=>'make',
       
   528     },
       
   529     CWTOOLS=>{
       
   530         ABI=>'TOOLS',
       
   531         ASSPABI=>'',
       
   532         Compiler=>'CW32',
       
   533         CPU=>'TOOLS',
       
   534         OS=>'TOOLS',
       
   535         MakeMod=>'Cl_tools',
       
   536         MakeCmd=>'make',
       
   537     },
       
   538     VC6TOOLS=>{
       
   539         ABI=>'TOOLS',
       
   540         ASSPABI=>'',
       
   541         Compiler=>'VC32',
       
   542         CPU=>'TOOLS',
       
   543         Ext=>'.DSP',
       
   544         MakeMod=>'Ide_vc6',
       
   545         MakeCmd=>'nmake',
       
   546         OS=>'TOOLS',
       
   547         Real=>'TOOLS',
       
   548         UsrHdrsOnly=>1,
       
   549     },
       
   550     WINS=>{
       
   551         ABI=>'WINS',
       
   552         ASSPABI=>'',
       
   553         Compiler=>'VC32',
       
   554         CPU=>'WINS',
       
   555         MakeMod=>'Cl_win',
       
   556         MakeCmd=>'nmake',
       
   557         OS=>'WINS',
       
   558     },
       
   559     VC6=>{
       
   560         ABI=>'WINS',
       
   561         ASSPABI=>'',
       
   562         Compiler=>'VC32',
       
   563         CPU=>'WINS',
       
   564         Ext=>'.DSP',
       
   565         MakeMod=>'Ide_vc6',
       
   566         MakeCmd=>'nmake',
       
   567         OS=>'WINS',
       
   568         Real=>'WINS',
       
   569         UsrHdrsOnly=>1,
       
   570     },
       
   571     WINSCW=>{
       
   572         ABI=>'WINSCW',
       
   573         ASSPABI=>'',
       
   574         Compiler=>'CW32',
       
   575         CPU=>'WINS',
       
   576         MakeMod=>'Cl_codewarrior',
       
   577         OS=>'WINS',
       
   578         DefFile=>'WINS',    # use the MSVC def files
       
   579     },
       
   580     CW_IDE=>{
       
   581         ABI=>'WINSCW',
       
   582         ASSPABI=>'',
       
   583         Compiler=>'CW32',
       
   584         CPU=>'WINS',
       
   585         Ext=>'.xml',
       
   586         MakeMod=>'Ide_cw',
       
   587         MakeCmd=>'make',
       
   588         OS=>'WINS',
       
   589         Real=>'WINSCW',
       
   590         DefFile=>'WINS',    # use the MSVC def files
       
   591         UsrHdrsOnly=>1,
       
   592         SupportsMultiplePlatforms=>1,   # supports more than one real platform
       
   593     },
       
   594     X86=>{
       
   595         ABI=>'X86',
       
   596         ASSPABI=>'',
       
   597         Compiler=>'VC32',
       
   598         CPU=>'X86',
       
   599         MakeMod=>'Cl_x86',
       
   600         MakeCmd=>'nmake',
       
   601         OS=>'EPOC32',
       
   602         DefFile=>'X86',
       
   603         Generic=>1,
       
   604     },
       
   605     X86SMP=>{
       
   606         ABI=>'X86',
       
   607         ASSPABI=>'',
       
   608         Compiler=>'VC32',
       
   609         CPU=>'X86',
       
   610         MakeMod=>'Cl_x86',
       
   611         MakeCmd=>'nmake',
       
   612         OS=>'EPOC32',
       
   613         DefFile=>'X86',
       
   614         Generic=>1,
       
   615         SMP=>1,
       
   616         StatLink=>'X86SMP',
       
   617     },
       
   618     X86GCC=>{
       
   619         ABI=>'X86gcc',
       
   620         ASSPABI=>'',
       
   621         Compiler=>'X86GCC',
       
   622         CPU=>'X86',
       
   623         MakeMod=>'Cl_x86gcc',
       
   624         OS=>'EPOC32',
       
   625         DefFile=>'x86gcc',
       
   626         Generic=>1,
       
   627     },  
       
   628     X86GMP=>{
       
   629         ABI=>'X86gcc',
       
   630         ASSPABI=>'',
       
   631         Compiler=>'X86GCC',
       
   632         CPU=>'X86',
       
   633         MakeMod=>'Cl_x86gcc',
       
   634         OS=>'EPOC32',
       
   635         DefFile=>'x86gcc',
       
   636         Generic=>1,
       
   637         SMP=>1,
       
   638         StatLink=>'X86GMP',
       
   639     },  
       
   640     ARMV4=>{
       
   641         ABI=>'ARMV4',
       
   642         ASSP=>'MARM',
       
   643         ASSPABI=>'',
       
   644         Generic=>1,
       
   645         MakeMod=>'Cl_arm',
       
   646         Compiler=>'ARMCC',
       
   647         DefFile=>'EABI',
       
   648         EABI=>1,
       
   649     },
       
   650     ARMV4SMP=>{
       
   651         ABI=>'ARMV4',
       
   652         ASSP=>'MARM',
       
   653         ASSPABI=>'',
       
   654         Generic=>1,
       
   655         MakeMod=>'Cl_arm',
       
   656         Compiler=>'ARMCC',
       
   657         DefFile=>'EABI',
       
   658         EABI=>1,
       
   659         SMP=>1,
       
   660         StatLink=>'ARMV4SMP',
       
   661     },
       
   662     ARMV5_ABIV1=>{
       
   663         ABI=>'ARMV5',
       
   664         ASSP=>'MARM',
       
   665         ASSPABI=>'',
       
   666         Generic=>1,
       
   667         MakeMod=>'Cl_arm',
       
   668         Compiler=>'ARMCC',
       
   669         DefFile=>'EABI',
       
   670         EABI=>1,
       
   671         SupportsFeatureVariants=>1,
       
   672     },
       
   673     ABIV2=>{
       
   674         ABI=>'ARMV5',
       
   675         ASSP=>'MARM',
       
   676         ASSPABI=>'',
       
   677         Generic=>1,
       
   678         MakeMod=>'Cl_bpabi',
       
   679         DefFile=>'EABI',
       
   680         EABI=>1,
       
   681         SupportsFeatureVariants=>1,
       
   682     },
       
   683     GCCXML=>{
       
   684         ABI=>'ARM4',
       
   685         ASSP=>'MARM',
       
   686         ASSPABI=>'',
       
   687         Generic=>1,
       
   688         MakeMod=>'cl_gccxml',
       
   689     },
       
   690     VS6=>{
       
   691         ABI=>'WINSCW',
       
   692         ASSPABI=>'',
       
   693         Compiler=>'CW32',
       
   694         CPU=>'WINS',
       
   695         MakeMod=>'Cl_vscw',
       
   696         OS=>'WINS',
       
   697         Real=>'WINSCW',
       
   698         DefFile=>'WINS',    # use the MSVC def files
       
   699         Ext=>'.mak'     
       
   700     },
       
   701     VS2003=>{
       
   702         ABI=>'WINSCW',
       
   703         ASSPABI=>'',
       
   704         Compiler=>'CW32',
       
   705         CPU=>'WINS',
       
   706         MakeMod=>'Cl_vscw',
       
   707         OS=>'WINS',
       
   708         Real=>'WINSCW',
       
   709         DefFile=>'WINS',    # use the MSVC def files
       
   710         Ext=>'.mak'
       
   711     },
       
   712     EDG=>{
       
   713         ABI=>'ARMV5',
       
   714         ASSP=>'MARM',
       
   715         ASSPABI=>'',
       
   716         Generic=>1,
       
   717         MakeMod=>'cl_edg',
       
   718     },
       
   719 
       
   720     # ASSP platforms should be described using .ASSP files
       
   721     # Do not add additional ASSP platforms to this file.
       
   722 );
       
   723 
       
   724 my $init_bsfs_done = 0;
       
   725 my $init_plat_done = 0;
       
   726 my @PlatList;       # Platlist returned by list_plat()
       
   727 
       
   728 # initialize BSF platforms into %Plat
       
   729 sub init_bsfs($) {
       
   730     return $init_bsfs_done if ($init_bsfs_done);
       
   731         
       
   732     my ($Path)=@_;  
       
   733 #   get a list of modules
       
   734     opendir DIR, $Path;
       
   735     my @BSFs=grep s/^([^\.].*)\.BSF$/$1/, map { uc $_ } sort readdir DIR;
       
   736     closedir DIR;
       
   737 
       
   738     my $BSF;
       
   739     foreach $BSF (@BSFs) {
       
   740         my $File=$Path.lc($BSF).'.bsf';
       
   741 #       check whether the assp is already defined
       
   742         if (defined %{$Plat{$BSF}}) {
       
   743             warn(
       
   744                 "$File : warning: Platform \"$BSF\" already defined\n",
       
   745                 " ... skipping this spec\n"
       
   746             );
       
   747             delete $Plat{$BSF};
       
   748             next;
       
   749         }
       
   750 #       open the module
       
   751         unless (open FILE, $File) {
       
   752             delete $Plat{$BSF};
       
   753             warn "warning: Can't open BSF specification \"$File\"\n";
       
   754             next;
       
   755         }
       
   756         my $line1 = <FILE>;
       
   757         $line1 = uc($line1);
       
   758         unless ($line1 =~ /^\#\<BSF\>\#/) {
       
   759             warn "warning: \"$File\" Invalid BSF specification - missing #<bsf>#\n";
       
   760             delete $Plat{$BSF};
       
   761             close FILE;
       
   762                   next;
       
   763         }
       
   764         my $custom;
       
   765         while ($custom = <FILE>) {
       
   766             #skip blank lines and comments
       
   767             delete $Plat{$BSF};
       
   768             last unless ($custom =~ /^$|^\#/);
       
   769         }
       
   770         $custom = uc $custom;
       
   771         unless ($custom =~ /^\s*CUSTOMIZES\s+(\S+)/) {
       
   772             warn "warning: \"$File\" Invalid BSF specification - 'customizes' missing\n";
       
   773             delete $Plat{$BSF};
       
   774             close FILE;
       
   775             next;
       
   776         }
       
   777         my $root = $1;
       
   778         my $platname = '';
       
   779         my $CustomizedPlatName = '';        
       
   780 
       
   781         # In v1 mode, ARMV5 platform implies ARMV5_ABIV1 platform listed in the platlist        
       
   782         my $Armv5Flag = 0;
       
   783         if (!$variantABIV2Keyword && $root =~ /^ARMV5$/i) {
       
   784             $Armv5Flag = 1;
       
   785         }
       
   786 
       
   787         # Support for Hierarchy of Customizations (BSF file customization of another BSF file)
       
   788         # 1. Check whether the BSF file customizes another BSF file.
       
   789         # 2. If so, check whether the root BSF file has already been read.
       
   790         # 3. If not read, then defer the current BSF file reading until the root file is read.
       
   791         my $rootPlatFound = 0;
       
   792         if (defined %{$Plat{$root}} || $Armv5Flag) 
       
   793         {
       
   794             # BSF platform customizes another valid BSF platform
       
   795             if (defined $Plat{$root}{'CUSTOMIZES'}) 
       
   796             {
       
   797                 $rootPlatFound = 1;
       
   798                 $platname = $root;
       
   799                 $CustomizedPlatName = $root;
       
   800 
       
   801                 # Set the root platform name which is same as of customizes platform
       
   802                 $Plat{$BSF}{'ROOTPLATNAME'} = $Plat{$root}{'ROOTPLATNAME'};
       
   803             }
       
   804             # BSF platform customizes to one of the existing ABI platforms
       
   805             else
       
   806             {
       
   807                 # All BPABI platforms inherits from ABIV2 platform listed in the platlist
       
   808                 if (grep /^$root$/i, @BPABIPlats) {
       
   809                     $platname = "ABIV2";
       
   810                 }
       
   811                 elsif ($Armv5Flag) {
       
   812                 # In v1 mode, ARMV5 platform implies ARMV5_ABIV1 platform listed in the platlist
       
   813                     $platname = "ARMV5_ABIV1";  
       
   814                 }
       
   815                 else {
       
   816                     $platname = $root;
       
   817                 }
       
   818                 
       
   819                 $CustomizedPlatName=$root;
       
   820 
       
   821                 # BSF File check Begins 
       
   822                 # The following check is included to handle the existing BSF files which has to behave in different manner
       
   823                 # in default v1 mode and v2 mode. The following code changes the BSF name and the custmoized platform name
       
   824                 # to the implied names. This is done to support switching between v1 and v2 modes by enabling the keyword in
       
   825                 # the variant configuration file.
       
   826                 # In v1 mode, the ARMV6_ABIV1 => ARMV6 platform and ARMV6 => ARMV6_ABIV2 platform.
       
   827                 if (!$variantABIV2Keyword) {
       
   828                     if ($BSF =~ /^ARMV6_ABIV1$/i) {
       
   829                         $BSF = "ARMV6"; 
       
   830                         $CustomizedPlatName = "ARMV5";  
       
   831                     }
       
   832                     elsif ($BSF =~ /^ARMV6$/i) {
       
   833                         $BSF = "ARMV6_ABIV2";   
       
   834                         $CustomizedPlatName = "ARMV5_ABIV2";
       
   835                         $platname = "ABIV2";
       
   836                     }
       
   837                 }
       
   838                 # BSF File check Ends
       
   839 
       
   840                 # Set the root platform name
       
   841                 $Plat{$BSF}{'ROOTPLATNAME'} = $CustomizedPlatName;
       
   842             }           
       
   843         }
       
   844         else
       
   845         {
       
   846             my $rootbsf = $Path.$root.".bsf";           
       
   847             if ( -e $rootbsf ) {
       
   848                 # BSF file customizes another BSF file which has not been read yet.
       
   849                 # So defer current BSF file reading until the root BSF file is read.                
       
   850                 delete $Plat{$BSF};
       
   851                 push(@BSFs, $BSF);
       
   852                 next;       
       
   853             }
       
   854         }
       
   855         # If the customizes platform is not a valid BSF platform or BPABI platorm or ARMV5 or ARMV5_ABIV1,
       
   856         # then throw warning.
       
   857         unless ($rootPlatFound || $root =~ /^ARMV5(_ABIV1)?$/ || (grep /^$root$/i, @BPABIPlats)) {
       
   858             warn "warning: \"$File\" Invalid BSF specification - customization restricted to ARMV5, ABIv2 and valid BSF platforms\n";
       
   859             close FILE;
       
   860             delete $Plat{$BSF};
       
   861             next;
       
   862         }
       
   863             
       
   864         my ( $key, $value);
       
   865         while (($key, $value) = each %{$Plat{$platname}}) {
       
   866             $Plat{$BSF}{$key}=$value;
       
   867         }
       
   868         
       
   869         push @{$Plat{$CustomizedPlatName}{'CUSTOMIZATIONS'}}, $BSF;
       
   870         $Plat{$BSF}{'CUSTOMIZES'} = $CustomizedPlatName;
       
   871         while (<FILE>) {
       
   872             next if (/^$|^\#/);
       
   873             if (/^\s*SMP\s*$/i) {
       
   874                 $Plat{$BSF}{'SMP'} = 1;
       
   875                 $Plat{$BSF}{'StatLink'} = lc $BSF;
       
   876                 next;
       
   877             }
       
   878             $Plat{$BSF}{'CUSTOMIZATION_DATA'} .= $_;
       
   879         }
       
   880         # BSF file statements will have newline character("\n") at the end, except for the last statement.
       
   881         # So append "\n" for the last BSF file statement.
       
   882         # "\n" will be used to split BSF statements to support hierarchy of customizations.
       
   883         $Plat{$BSF}{'CUSTOMIZATION_DATA'} .= "\n";
       
   884         close FILE;
       
   885     }
       
   886     $init_bsfs_done = 1;
       
   887 }
       
   888 
       
   889 # setup Plat with bpabi platforms
       
   890 sub init_platwithbpabi() 
       
   891 {
       
   892     foreach my $Candidate (&get_bpabiplatlist)
       
   893     {
       
   894 # All BPABI platforms inherit from ABIV2 properties as listed in the platlist
       
   895 # and Platlist is updated to include the BPABI platforms.
       
   896         my ( $key, $value);
       
   897         while (($key, $value) = each %{$Plat{ABIV2}}) {
       
   898             $Plat{$Candidate}{$key}=$value;
       
   899         }
       
   900     }
       
   901 }
       
   902 
       
   903 # initialize %Plat with BSF/Bpabi/ASSP
       
   904 sub init_plat ($) { # takes path to ASSP modules
       
   905     
       
   906     return $init_plat_done if ($init_plat_done);
       
   907     
       
   908     my ($Path)=@_;
       
   909 
       
   910     my %PlatHashKeys=(
       
   911         ABI=>1,
       
   912         ASSPABI=>1,
       
   913         SINGLE=>1,
       
   914         Compiler=>1,
       
   915         CPU=>1,
       
   916         MakeMod=>1,
       
   917         MakeCmd=>1,
       
   918         OS=>1,
       
   919         DefFile=>1,
       
   920         ASSP=>1,
       
   921     );
       
   922 
       
   923 #   Include the list of BPABI platforms
       
   924     &init_platwithbpabi;
       
   925 
       
   926     init_bsfs($Path);
       
   927 
       
   928 #   get a list of modules
       
   929     opendir DIR, $Path;
       
   930     my @_ASSPs=grep s/^([^\.].*)\.ASSP$/$1/, map { uc $_ } readdir DIR;
       
   931     closedir DIR;
       
   932 
       
   933     my @ASSPs;
       
   934     foreach (@_ASSPs) {
       
   935         next if (!$ENV{USEARMCC} and /EDG$/i);
       
   936         push @ASSPs, $_;
       
   937     }
       
   938 
       
   939 #   open each module in turn, and add it to the array
       
   940     my $ASSP;
       
   941     foreach $ASSP (@ASSPs) {
       
   942         my $File=$Path.$ASSP.'.assp';
       
   943 #       check whether the assp is already defined
       
   944         if (defined %{$Plat{$ASSP}}) {
       
   945             warn(
       
   946                 "$File : warning: ASSP \"$ASSP\" already defined\n",
       
   947                 " ... skipping this module\n"
       
   948             );
       
   949 
       
   950             next;
       
   951         }
       
   952 #       open the module
       
   953         unless (open FILE, $File) {
       
   954             warn "warning: Can't open assp module \"$File\"\n";
       
   955             next;
       
   956         }
       
   957         my %Data=();
       
   958         my %SingleData=();
       
   959         my $MatchingSingle="";
       
   960         my @Errors=();
       
   961         while (<FILE>) {
       
   962 #           strip comments
       
   963             s/^([^#]*)#.*$/$1/o;
       
   964 #           skip blank lines
       
   965             if (/^\s*$/o) {
       
   966                 next;
       
   967             }
       
   968 #           get the key-value pair
       
   969             unless (/^\s*(\w+)\s+(\w+)\s*$/o) {
       
   970                 push @Errors, "$File($.) : warning: syntax error - only key-value pairs allowed\n";
       
   971                 next;
       
   972             }
       
   973             my ($Key, $Val)=($1, $2);
       
   974             if ($PlatHashKeys{$Key}!=1) {
       
   975                 push @Errors, "$File($.) : warning: unrecognized keyword - $Key\n";
       
   976                 next;
       
   977             }
       
   978             if ($Key eq "SINGLE") {
       
   979                 $SingleData{Single} = 1;
       
   980                 $SingleData{ASSP} = $ASSP;
       
   981                 $MatchingSingle = uc $2;
       
   982             } else {
       
   983                 $Data{$Key}=$Val;
       
   984                 $SingleData{$Key}=$Val;
       
   985             }
       
   986         }
       
   987         close FILE;
       
   988         if (@Errors) {
       
   989             warn(
       
   990                 @Errors,
       
   991                 " ... skipping this module\n"
       
   992             );
       
   993             next;
       
   994         }
       
   995 # change -  Allow ASSPs to pick up all the options of the ABI they specify, 
       
   996 # in particular the compiler they need.
       
   997             $Data{'ASSP'} = $ASSP unless $Data{'ASSP'};
       
   998             if ($Plat{$Data{'ABI'}}) {
       
   999             foreach (keys %{$Plat{$Data{'ABI'}}}) {
       
  1000             $Data{$_} = $Plat{$Data{'ABI'}}{$_} unless ($_ =~ /^GENERIC$/i) or $Data{$_};
       
  1001             }
       
  1002         }
       
  1003 
       
  1004         %{$Plat{$ASSP}}=%Data;
       
  1005         if ($MatchingSingle ne "") {
       
  1006             foreach (keys %Data) {
       
  1007             $SingleData{$_} = $Data{$_} unless ($_ =~ /^GENERIC$/i) or $SingleData{$_};
       
  1008             }
       
  1009             %{$Plat{$MatchingSingle}}=%SingleData;
       
  1010         }           
       
  1011     }
       
  1012     $init_plat_done=1;
       
  1013 }
       
  1014 
       
  1015 #   return list of supported platforms
       
  1016 #   should be invoked atfer init_plat
       
  1017 sub get_platlist () {
       
  1018 
       
  1019     return @PlatList if (scalar(@PlatList));
       
  1020 
       
  1021     &init_plat;
       
  1022 
       
  1023     my $Key;
       
  1024     foreach $Key (keys %Plat) {
       
  1025         if (!$variantABIV2Keyword && $Key =~ /^armv5_abiv1$/i) {
       
  1026             $Key = 'ARMV5';
       
  1027         }
       
  1028         unless (grep /^$Key$/i, @PlatList) {
       
  1029             push @PlatList, $Key;
       
  1030         }
       
  1031     }
       
  1032     return @PlatList
       
  1033 }
       
  1034 
       
  1035 # return customizes BSF plat if any
       
  1036 sub get_platcustomizes($) {
       
  1037     my ($plat) = @_;
       
  1038     return $Plat{$plat}{'CUSTOMIZES'} ? $Plat{$plat}{'CUSTOMIZES'} : "";
       
  1039 }
       
  1040 
       
  1041 # return root of a specific plat
       
  1042 sub get_platroot($) {
       
  1043     my ($plat) = @_;
       
  1044 
       
  1045     my $RootName = $Plat{$plat}{'ROOTPLATNAME'};
       
  1046 
       
  1047     if ($RootName) {
       
  1048         return $RootName;
       
  1049     }
       
  1050     else {
       
  1051         # A non-BSF platform is its own root.
       
  1052         return $plat;
       
  1053     }
       
  1054 }
       
  1055 
       
  1056 #################################
       
  1057 # featurevariant map functions
       
  1058 #
       
  1059 # copy from featurevariantmap.pm
       
  1060 
       
  1061 my $featureListDir = "${epocroot}epoc32\/include\/variant\/featurelists";
       
  1062 
       
  1063 # Usage:    get_BVbinname("my.dll", "myvar")
       
  1064 #
       
  1065 # Look for a binary using its "final" name. We will use the feature
       
  1066 # variant map and the feature variant name to deduce the "variant"
       
  1067 # binary name and test for its existence.
       
  1068 #
       
  1069 # "my.dll"  - the final target (full path)
       
  1070 # "myvar"   - the feature variant name
       
  1071 #
       
  1072 # returns the file name if found, or "" otherwise.
       
  1073 
       
  1074 sub get_BVbinname
       
  1075 {
       
  1076     my $binName = shift;
       
  1077     my $varName = shift;
       
  1078 
       
  1079     # look for the vmap file
       
  1080     my $vmapFile = "$binName.$varName.vmap";
       
  1081     
       
  1082     if (! -e $vmapFile)
       
  1083     {
       
  1084     	# compatible to old BV
       
  1085     	$vmapFile = "$binName.vmap";
       
  1086     }
       
  1087     
       
  1088     if (-e $vmapFile)
       
  1089     {
       
  1090         my $key = get_vmapkey($varName, $vmapFile);
       
  1091 
       
  1092         if ($key)
       
  1093         {
       
  1094             $binName =~ /^(.*)\.([^\.]*)$/;
       
  1095             $binName = "$1.$key.$2";
       
  1096         }
       
  1097         else
       
  1098         {
       
  1099             print "ERROR: No \'$varName\' variant for $binName in $vmapFile\n";
       
  1100             return "";  # file not found
       
  1101         }
       
  1102     }
       
  1103 
       
  1104     # check that the actual binary exists
       
  1105     if (-e $binName)
       
  1106     {
       
  1107         return $binName;
       
  1108     }
       
  1109     return "";  # file not found
       
  1110 }
       
  1111 
       
  1112 # internal functions
       
  1113 sub get_vmapkey
       
  1114 {
       
  1115     my @res = get_vmapdata(@_);
       
  1116     return $res[0];
       
  1117 }
       
  1118 
       
  1119 # Usage:    featurevariantmap->GetDataFromVMAP("myvar", "mydll.vmap")
       
  1120 #
       
  1121 # Opens the vmap file indicated and returns the data for the requested variant
       
  1122 #
       
  1123 # "myvar"   - the feature variant name
       
  1124 # "my.vmap" - the final target vmap file (full path)
       
  1125 #
       
  1126 # Returns a list ( hash, features ) for the variant in the vmap or undef if not found
       
  1127 
       
  1128 sub get_vmapdata
       
  1129 {
       
  1130     my $varName = shift;
       
  1131     my $fileName = shift;
       
  1132 
       
  1133     if (!open(VMAP, $fileName))
       
  1134     {
       
  1135         print "ERROR: Could not read VMAP from $fileName\n";
       
  1136         return "";
       
  1137     }
       
  1138     while (<VMAP>)
       
  1139     {
       
  1140         chomp;
       
  1141         if (/(\w{32})\s+$varName\s+(.*)$/i or /(\w{32})\s+$varName$/i)
       
  1142         {
       
  1143             my ( $hash, $features ) = ( $1, $2 ? $2 : '' );
       
  1144             close(VMAP);
       
  1145             return ( $hash, $features );
       
  1146         }
       
  1147     }
       
  1148     close(VMAP);
       
  1149     return;
       
  1150 }
       
  1151 
       
  1152 ######################################
       
  1153 # Feature variant parser
       
  1154 #
       
  1155 # copy from featurevariantparser.pm
       
  1156 #
       
  1157 
       
  1158 
       
  1159 # Parses .VAR files and returns key variables.
       
  1160 # The following hashes can be used with this module:
       
  1161 # NAME              -> Returns the name of the variant file (without the extension)
       
  1162 # FULLPATH          -> Returns the full path of the variant file (including the extension)
       
  1163 # VALID             -> Set to 1 if the variant file is valid, otherwise set to 0
       
  1164 # VIRTUAL           -> Set to 1 if the variant is a grouping node, otherwise set to 0
       
  1165 # ROM_INCLUDES      -> Returns a pointer to the list of ROM_INCLUDES (including Parent nodes).
       
  1166 # VARIANT_HRH       -> Returns the full VARIANT_HRH file path used by the VAR file.
       
  1167 
       
  1168 
       
  1169 my $defaultDir = "${epocroot}epoc32\/tools\/variant";
       
  1170 my $pathregex = '.+[^\s]'  ;   # Regex to match all characters (including \ or /), excluding whitespaces.
       
  1171 
       
  1172 my @rominclude;
       
  1173 my @parents;
       
  1174 my @childNodes;
       
  1175 my $virtual;
       
  1176 my $childNodeStatus;
       
  1177 my $varianthrh;
       
  1178 
       
  1179 my $dir;        #var directory
       
  1180 my $fullpath;   #full path of var file
       
  1181 my $fulldir;    #
       
  1182 
       
  1183 # Wrapper function to return all the correct variables
       
  1184 # Arguments : (Variant Name, Variant Directory(optional))
       
  1185 # Returns a Hash.
       
  1186 sub get_variant
       
  1187 {
       
  1188     @rominclude      = ();
       
  1189     @parents         = ();
       
  1190     @childNodes      = ();
       
  1191     $dir             = "";
       
  1192     $fullpath        = "";
       
  1193     $varianthrh      = "";
       
  1194     $virtual         = 0;
       
  1195     $childNodeStatus = 0;
       
  1196     
       
  1197     
       
  1198     my %data;
       
  1199     my $romincs   = "";
       
  1200     
       
  1201     $data{'VALID'} = 0;
       
  1202 
       
  1203     my ( $varname, $dirname ) = @_;
       
  1204 
       
  1205     my $fullvarpath = get_variantfullpath( $varname, $dirname );
       
  1206 
       
  1207     if ( $dirname )
       
  1208     {
       
  1209         $fulldir = $dirname;
       
  1210     }
       
  1211     else
       
  1212     {
       
  1213         $fulldir = $defaultDir;
       
  1214     }
       
  1215 
       
  1216     $data{'FULLPATH'} = "$fullvarpath";
       
  1217     $data{'NAME'}     = "$varname";
       
  1218 
       
  1219     # If the variant file exists, check the syntax and setup variables.
       
  1220     if ( -e $fullvarpath )
       
  1221     {
       
  1222         if ( check_varfile( $fullvarpath, $varname ) )
       
  1223         {
       
  1224             $data{'VALID'} = 1;
       
  1225         }
       
  1226     }
       
  1227     else
       
  1228     {
       
  1229         print "ERROR: $fullvarpath" . " does not exist\n";
       
  1230     }
       
  1231 
       
  1232     my $count = 0;
       
  1233 
       
  1234     # If VAR file is valid, setup all other variables.
       
  1235     if ( $data{'VALID'} )
       
  1236     {
       
  1237 
       
  1238         $romincs   = find_varrominc($fullvarpath);
       
  1239         
       
  1240         # Remove empty elements from the ROM_INCLUDE list
       
  1241         @$romincs = grep /\S/, @$romincs;
       
  1242 
       
  1243         # Fix paths for all ROM_INCLUDES
       
  1244         for ( my $i = 0 ; $i < scalar(@$romincs) ; $i++ )
       
  1245         {
       
  1246             @$romincs[$i] = get_fixpath( @$romincs[$i] );
       
  1247         }
       
  1248 
       
  1249         $data{'ROM_INCLUDES'}   = clone_list($romincs);
       
  1250         $data{'VARIANT_HRH'}    = $varianthrh;
       
  1251         $data{'VIRTUAL'}        = $virtual;
       
  1252     }
       
  1253 
       
  1254     # If variant file is not valid, return reference to a blank array
       
  1255     else
       
  1256     {
       
  1257         $data{'ROM_INCLUDES'}   = [];
       
  1258         $data{'VARIANT_HRH'}    = "";
       
  1259     }
       
  1260 
       
  1261     return %data;
       
  1262 }
       
  1263 
       
  1264 # Method to construct a full variant path from the variant file and directory
       
  1265 sub get_variantfullpath
       
  1266 {
       
  1267 
       
  1268     my $vardirectory = $_[1];
       
  1269     my $varname      = $_[0];
       
  1270     
       
  1271     my $dir;
       
  1272     
       
  1273     # Check if a directory is supplied
       
  1274     if ($vardirectory)
       
  1275     {
       
  1276         $dir = "$vardirectory";
       
  1277     }
       
  1278 
       
  1279     else
       
  1280     {
       
  1281         $dir = $defaultDir;
       
  1282     }
       
  1283     my $filename = "$varname" . "\.var";
       
  1284     $fullpath = File::Spec->catfile( File::Spec->rel2abs($dir), $filename );
       
  1285 
       
  1286     if ( !File::Spec->file_name_is_absolute($fullpath) )
       
  1287     {
       
  1288         $fullpath = File::Spec->rel2abs($fullpath);
       
  1289     }
       
  1290 
       
  1291     return $fullpath;
       
  1292 }
       
  1293 
       
  1294 # Checks the variant file for the correct syntax and reports any errors
       
  1295 # Also sets up some variables(VIRTUAL ,VARIANT_HRH and VARIANT) whilst file is being parsed.
       
  1296 
       
  1297 # Usage: check_varfile(<fullpath>,<varfile>) . Note: <varfile> without .var
       
  1298 sub check_varfile
       
  1299 {
       
  1300 
       
  1301     my $fullpath          = $_[0];
       
  1302     my $varname           = $_[1];
       
  1303     my $varianthrhpresent = 0;
       
  1304 
       
  1305     open( READVAR, "<$fullpath" );
       
  1306     my $exp  = "#";
       
  1307     my $line = "";
       
  1308 
       
  1309     while (<READVAR>)
       
  1310     {
       
  1311         s/\r\n/\n/g;
       
  1312 
       
  1313         $line = $.;
       
  1314 
       
  1315     # Checks for a valid argument supplied to EXTENDS keyword. Checks for one and only one argument supplied.
       
  1316         if (/^EXTENDS/)
       
  1317         {
       
  1318             if ( !m/^EXTENDS\s+./ )
       
  1319             {
       
  1320                 print "\nERROR: Invalid format supplied to argument EXTENDS on line "
       
  1321                   . "$."
       
  1322                   . " in file "
       
  1323                   . "$fullpath";
       
  1324                 return 0;
       
  1325             }
       
  1326             my $str = get_extends($_);
       
  1327             if ( $str =~ /\s+/ )
       
  1328             {
       
  1329                 print "\nERROR: Cannot extend from two nodes. Error in line "
       
  1330                   . "$."
       
  1331                   . " in file "
       
  1332                   . "$fullpath";
       
  1333                 return 0;
       
  1334             }
       
  1335 
       
  1336             $childNodeStatus = 1;
       
  1337         }
       
  1338 
       
  1339         # Checks for the grammar of BUILD_INCLUDE, i.e. KEYWORD MODIFIER VALUE
       
  1340         elsif (/^BUILD_INCLUDE/)
       
  1341         {
       
  1342             # skip build inc checking
       
  1343         }
       
  1344 
       
  1345         # Checks for the grammar of ROM_INCLUDE, i.e. KEYWORD MODIFIER VALUE
       
  1346         elsif (/^ROM_INCLUDE/)
       
  1347         {
       
  1348 
       
  1349             if (!m/^ROM_INCLUDE\s+(append|prepend|set)\s+$pathregex/)
       
  1350             {
       
  1351                 print "\nERROR: Invalid syntax supplied to keyword ROM_INCLUDE on line "
       
  1352                   . "$."
       
  1353                   . " in file "
       
  1354                   . "$fullpath";
       
  1355                 return 0;
       
  1356             }
       
  1357 
       
  1358             if (m/^ROM_INCLUDE\s+(append|prepend|set)\s+$pathregex\s+$pathregex/)
       
  1359             {
       
  1360                 print "\nERROR: Too many arguments supplied to keyword ROM_INCLUDE on line "
       
  1361                   . "$."
       
  1362                   . " in file "
       
  1363                   . "$fullpath";
       
  1364                 return 0;
       
  1365             }
       
  1366         }
       
  1367 
       
  1368         # Checks for a valid VARIANT name
       
  1369         elsif (/^VARIANT[^_HRH]/)
       
  1370         {
       
  1371             if ( !m/^VARIANT\s+\w+/ )
       
  1372             {
       
  1373                 print "\nERROR: VARIANT name not specified on line " . "$."
       
  1374                   . " in file "
       
  1375                   . "$fullpath";
       
  1376                 return 0;
       
  1377             }
       
  1378             if ( uc("$varname") ne uc( get_variantname($_) ) )
       
  1379             {
       
  1380                 print "\nERROR: VARIANT filename does not match variant name specified on line "
       
  1381                   . "$line"
       
  1382                   . " in file "
       
  1383                   . "$fullpath"
       
  1384                   . "\nVariant value extracted from the VAR file is " . "$_";
       
  1385             }
       
  1386 
       
  1387         }
       
  1388 
       
  1389         # Checks that keyword VIRTUAL is declared correctly
       
  1390         elsif (/^VIRTUAL/)
       
  1391         {
       
  1392             if (m/^VIRTUAL\s+\w+/)
       
  1393             {
       
  1394                 print "\nERROR: Invalid declaration of VIRTUAL on line " . "$."
       
  1395                   . " in file "
       
  1396                   . "$fullpath";
       
  1397                 return 0;
       
  1398             }
       
  1399 
       
  1400             $virtual = 1;
       
  1401         }
       
  1402 
       
  1403         # Checks if VARIANT_HRH is declared correctly.
       
  1404         elsif (/^VARIANT_HRH/)
       
  1405         {
       
  1406             $varianthrhpresent = 1;
       
  1407             my $lineno = $.;
       
  1408             if ( !m/^VARIANT_HRH\s+./ )
       
  1409             {
       
  1410                 print "\nERROR: Invalid format supplied to argument VARIANT_HRH on line "
       
  1411                   . "$lineno"
       
  1412                   . " in file "
       
  1413                   . "$fullpath";
       
  1414                 return 0;
       
  1415             }
       
  1416 
       
  1417             my $str = get_hrhname($_);
       
  1418             if ( $str =~ /\s+/ )
       
  1419             {
       
  1420                 print "\nERROR: Cannot have 2 or more hrh files. Error in line "
       
  1421                   . "$lineno"
       
  1422                   . " in file "
       
  1423                   . "$fullpath";
       
  1424                 return 0;
       
  1425             }
       
  1426 
       
  1427             unless( -e get_fixpath($str) )
       
  1428             {
       
  1429                 print "\nERROR: VARIANT HRH file : "
       
  1430                   . get_fixpath($str)
       
  1431                   . " specified on line "
       
  1432                   . "$lineno"
       
  1433                   . " does not exist";
       
  1434                 return 0;
       
  1435             }
       
  1436 
       
  1437             $varianthrh = get_fixpath( get_hrhname($_) );
       
  1438 
       
  1439         }
       
  1440         
       
  1441         # If none of the valid keywords are found
       
  1442         else
       
  1443         {
       
  1444 
       
  1445             # Do nothing if a comment or blank line is found
       
  1446             if ( (m/$exp\s+\S/) || (m/$exp\S/) || ( !m/./ ) || (m/^\n/) )
       
  1447             {
       
  1448             }
       
  1449 
       
  1450             # Unsupported keyword
       
  1451             else
       
  1452             {
       
  1453 
       
  1454                 print "\nERROR: Invalid keyword " . '"' . "$_" . '"'
       
  1455                   . " found on line " . "$."
       
  1456                   . " in file "
       
  1457                   . "$fullpath";
       
  1458                 return 0;
       
  1459             }
       
  1460         }
       
  1461     }
       
  1462 
       
  1463     close(READVAR);
       
  1464 
       
  1465     # If no HRH file defined, check if the default one exists
       
  1466     if ( !$varianthrhpresent )
       
  1467     {
       
  1468         print "\nINFO: No VARIANT_HRH defined in VAR file, using ${epocroot}epoc32\/include\/variant\/$varname\.hrh" if ($verbose);
       
  1469         my $str =
       
  1470           get_hrhname(
       
  1471             "VARIANT_HRH ${epocroot}epoc32\/include\/variant\/$varname\.hrh"
       
  1472           );
       
  1473 
       
  1474         if ( ! -e $str )
       
  1475         {
       
  1476             print "\nERROR: VARIANT HRH file : " . "$str " . "does not exist\n";
       
  1477             return 0;
       
  1478         }
       
  1479         else
       
  1480         {
       
  1481             $varianthrh = $str;
       
  1482         }
       
  1483     }
       
  1484     return 1;
       
  1485 }
       
  1486 
       
  1487 # Extract the value of the VARIANT keyword
       
  1488 sub get_variantname
       
  1489 {
       
  1490 
       
  1491     $_[0] =~ m/^VARIANT\s+(\w+)/i;
       
  1492     return $1;
       
  1493 }
       
  1494 
       
  1495 # Extracts the value of the HRH file from the VARIANT_HRH line supplied
       
  1496 sub get_hrhname
       
  1497 {
       
  1498 
       
  1499     $_[0] =~ m/^VARIANT_HRH\s+($pathregex)/;
       
  1500     return $1;
       
  1501 
       
  1502 }
       
  1503 
       
  1504 # Method to find the immediate parent node of a child node
       
  1505 sub get_extends
       
  1506 {
       
  1507 
       
  1508     $_[0] =~ m/^EXTENDS\s+(\w+)/;
       
  1509     return $1;
       
  1510 }
       
  1511 
       
  1512 
       
  1513 # Method to correct all the slashes, and also append EPOCROOT if the path begins with a \ or /
       
  1514 # If path doesn't start with \ or /, returns an abosulte canonical path
       
  1515 sub get_fixpath
       
  1516 {
       
  1517 
       
  1518     my $arr = $_[0];
       
  1519 
       
  1520     if ( $arr =~ m/^\// )
       
  1521     {
       
  1522        $arr =~ s/^\/?//;
       
  1523         return File::Spec->canonpath( "$epocroot" . "$arr" );
       
  1524     }
       
  1525 
       
  1526     elsif ( $arr =~ m/^\\/ )
       
  1527     {
       
  1528         $arr =~ s/^\\?//;
       
  1529         return File::Spec->canonpath( "$epocroot" . "$arr" );
       
  1530     }
       
  1531 
       
  1532     else
       
  1533     {
       
  1534         return File::Spec->rel2abs( File::Spec->canonpath("$arr") );
       
  1535     }
       
  1536 
       
  1537 }
       
  1538 
       
  1539 # Method to find the ROMINCLUDE values of the VAR file.
       
  1540 sub find_varrominc
       
  1541 {
       
  1542 
       
  1543     my $filename = $_[0];
       
  1544 
       
  1545     my $parentNodes;
       
  1546 
       
  1547     # Construct a list of parent nodes if node is a child
       
  1548     if ($childNodeStatus)
       
  1549     {
       
  1550         $parentNodes = find_varparentnode("$filename");
       
  1551     }
       
  1552 
       
  1553     if ($parentNodes)
       
  1554     {
       
  1555 
       
  1556         # Go through and build the list of all parent ROM_INCLUDES
       
  1557         for ( my $i = scalar(@$parentNodes) - 1 ; $i >= 0 ; $i-- )
       
  1558         {
       
  1559             my $t = get_variantfullpath( @$parentNodes[$i], $fulldir );
       
  1560             open( NEWHANDLE, "<$t" );
       
  1561 
       
  1562             while (<NEWHANDLE>)
       
  1563             {
       
  1564                 if (/ROM_INCLUDE/)
       
  1565                 {
       
  1566                     get_varrominc($_);
       
  1567                 }
       
  1568             }
       
  1569             close(NEWHANDLE);
       
  1570         }
       
  1571     }
       
  1572 
       
  1573     # Append the ROM_INCLUDES of the VAR file in the end
       
  1574     open( NEWHANDLE, "<$filename" );
       
  1575 
       
  1576     while (<NEWHANDLE>)
       
  1577     {
       
  1578         if (/ROM_INCLUDE/)
       
  1579         {
       
  1580             get_varrominc($_);
       
  1581         }
       
  1582     }
       
  1583 
       
  1584     undef(@parents);    # Flush out parent array;
       
  1585     return \@rominclude;
       
  1586 
       
  1587 }
       
  1588 
       
  1589 # Constructs a list of Parent nodes for a given Child node.
       
  1590 sub find_varparentnode
       
  1591 {
       
  1592 
       
  1593     my $filename   = $_[0];
       
  1594     my $hasparents = 0;
       
  1595 
       
  1596     open( READHANDLE, "<$filename" );
       
  1597     while (<READHANDLE>)
       
  1598     {
       
  1599         if (/EXTENDS/)
       
  1600         {
       
  1601             $hasparents = 1;
       
  1602             push( @parents, get_extends($_) );
       
  1603 
       
  1604         }
       
  1605     }
       
  1606 
       
  1607     close(READHANDLE);
       
  1608 
       
  1609     if ( $hasparents == 1 )
       
  1610     {
       
  1611         find_varparentnode(
       
  1612             get_variantfullpath( @parents[ scalar(@parents) - 1 ], $fulldir )
       
  1613         );
       
  1614     }
       
  1615     else
       
  1616     {
       
  1617         return \@parents;
       
  1618     }
       
  1619 
       
  1620 }
       
  1621 
       
  1622 # Method to extract the ROM_INCLUDE value of a node.
       
  1623 sub get_varrominc
       
  1624 {
       
  1625 
       
  1626 # If modifier append is found, push the rominclude to the end of the array list.
       
  1627     if (/^ROM_INCLUDE\s+append\s+($pathregex)/)
       
  1628     {
       
  1629         push( @rominclude, ($1) );
       
  1630     }
       
  1631 
       
  1632 # If modifier prepend is found, push the rominclude to the beginning of the array list.
       
  1633     if (/^ROM_INCLUDE\s+prepend\s+($pathregex)/)
       
  1634     {
       
  1635         unshift( @rominclude, ($1) );
       
  1636     }
       
  1637 
       
  1638 # If keyword set is found, then empty the rominclude variable and push the new value
       
  1639     if (/^ROM_INCLUDE\s+set\s+($pathregex)/)
       
  1640     {
       
  1641         undef(@rominclude);
       
  1642         push( @rominclude, ($1) );
       
  1643     }
       
  1644 
       
  1645 }
       
  1646 
       
  1647 # Helper method that clones a reference to a simple list
       
  1648 sub clone_list
       
  1649     {
       
  1650     my $ref = shift;
       
  1651     
       
  1652     # Check the reference is a list
       
  1653     die "Not a list ref" if ref($ref) ne 'ARRAY';
       
  1654     
       
  1655     # Create a new list object
       
  1656     my @list;
       
  1657     foreach my $entry ( @$ref )
       
  1658         {
       
  1659         # Only clone lists of scalars
       
  1660         die "Not a scalar" if ref($entry);
       
  1661         
       
  1662         # Add the entry to the new list
       
  1663         push @list, $entry;
       
  1664         }
       
  1665     
       
  1666     # return a reference to the copy    
       
  1667     return \@list;
       
  1668     }
       
  1669     
       
  1670 ##############################
       
  1671 #  write helper
       
  1672 #
       
  1673 # copy from writer.pm
       
  1674 sub write_32bit # little-endian
       
  1675 {
       
  1676     my $fileHandle=shift;
       
  1677     my $integer=shift;
       
  1678     &write_8bit($fileHandle, $integer&0x000000ff);
       
  1679     &write_8bit($fileHandle, ($integer>>8)&0x000000ff);
       
  1680     &write_8bit($fileHandle, ($integer>>16)&0x000000ff);
       
  1681     &write_8bit($fileHandle, ($integer>>24)&0x000000ff);
       
  1682 }
       
  1683 
       
  1684 sub write_8bit
       
  1685 {
       
  1686     my $fileHandle=shift;
       
  1687     my $integer=shift;
       
  1688     if ($integer&0xffffff00)
       
  1689     {
       
  1690         die("Error: the integer ".sprintf("0x%08x", $integer)." is too large to write into 8 bits\n");
       
  1691     }
       
  1692     printf $fileHandle "%c", $integer;
       
  1693 }
       
  1694 
       
  1695 
       
  1696 1;
       
  1697