sbsv1/abld/e32util/efreeze.pl
changeset 607 378360dbbdba
parent 606 30b30f9da0b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv1/abld/e32util/efreeze.pl	Wed Jun 30 11:35:58 2010 +0800
@@ -0,0 +1,337 @@
+#!/usr/bin/perl
+# Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# all variables called *Path* are set up to end with a backslash
+# all variables called *Path or *File are stored as absolute (file)paths
+# all variables called UpPath* are stored as relative paths
+# 
+#
+
+
+use FindBin;		# for FindBin::Bin
+use Getopt::Long;
+
+my $PerlLibPath;    # fully qualified pathname of the directory containing our Perl modules
+
+BEGIN {
+# check user has a version of perl that will cope
+	require 5.005_03;
+# establish the path to the Perl libraries: currently the same directory as this script
+	$PerlLibPath = $FindBin::Bin;	# X:/epoc32/tools
+# do not convert slashes for linux
+	if ($^O eq "MSWin32") {
+		$PerlLibPath =~ s/\//\\/g;	# X:\epoc32\tools
+		$PerlLibPath .= "\\";
+	}
+}
+
+# Version
+my $MajorVersion = 1;
+my $MinorVersion = 1;
+my $PatchVersion = 1;
+
+use lib $PerlLibPath;
+use Defutl;
+
+# THE MAIN PROGRAM SECTION
+##########################
+
+{
+	my %Options;
+
+	# process the command-line
+	unless (GetOptions(\%Options, 'compare', 'remove')) {
+		exit 1;
+	}
+	unless (@ARGV==2) {
+		&Usage;
+	}
+
+	my $FRZFILE;
+	my $GENFILE;
+
+	($FRZFILE,$GENFILE)=(@ARGV);
+	
+#	check the file exists
+	unless (-e $FRZFILE) {
+		warn "WARNING: $FRZFILE: File not found - OK if freezing for first time\n";
+	}
+	unless (-e $GENFILE) {
+		die "EFREEZE ERROR: $GENFILE: File not found\n";
+	}
+
+#	Read the Frozen .DEF file if it exists
+	my @FrzDataStruct;
+	my $FrzExportsOn=0;
+	if (-e $FRZFILE) {
+		eval { &Def_ReadFileL(\@FrzDataStruct, $FRZFILE, $FrzExportsOn); };
+		die $@ if $@;
+	}
+
+#	Read the New .DEF file
+	my @GenDataStruct;
+	my $Dummy;
+	if ($GENFILE) {
+		eval { &Def_ReadFileL(\@GenDataStruct, $GENFILE, $Dummy, ($Options{compare} or $Options{remove})); };
+	}
+	die $@ if $@;
+
+#	Compare the frozen .DEF data with the new .DEF file
+	my (@NewDataStruct, @MissingDataStruct, @BadDataStruct);
+	eval { &CompareFrzGenL (\@NewDataStruct, \@MissingDataStruct, \@BadDataStruct, \@FrzDataStruct, \@GenDataStruct, $Options{remove}); };
+	die $@ if $@;
+
+#	check for errors
+	my $NumRemoved;
+	my $Ref;
+	my @Errors;
+	my $Title='EFREEZE ERROR:';
+	if ($Options{compare}) {
+		$Title='EFREEZE:';
+	}
+	if (@MissingDataStruct and $Options{remove}) {
+#		Mark missing exports as ABSENT in DEF file
+		$NumRemoved=@MissingDataStruct;
+		if ($Options{compare}) {
+			print "EFREEZE: Marking $NumRemoved Export(s) as ABSENT :\n";
+		} else {
+			print "EFREEZE: Marking $NumRemoved Export(s) as ABSENT in $FRZFILE :\n";
+		}
+		foreach (@MissingDataStruct) {
+			$$_{Absent} = 1;
+			my $Comment='';
+			if ($$_{Comment}) {
+				$Comment=" ; $$_{Comment}";
+			}
+			my $r3unused = $$_{R3Unused} ? " R3UNUSED" : "";
+			print "  $$_{Name} \@ $$_{Ordinal} NONAME$r3unused$Comment\n";
+		}
+	}
+	elsif (@MissingDataStruct) {
+		my $Num=@MissingDataStruct;
+		push @Errors, "$Title $FRZFILE: $Num Frozen Export(s) missing from $GENFILE (POSSIBLE COMPATIBILITY BREAK):\n"; 
+		foreach $Ref (@MissingDataStruct) {
+			my $r3unused = $$Ref{R3Unused} ? " R3UNUSED" : "";
+			push @Errors, "  $$Ref{LineNum}: $$Ref{Name} \@ $$Ref{Ordinal} NONAME$r3unused\n";
+		}
+		push @Errors, "\n";
+	}
+	if (@BadDataStruct) {
+		my $Num=@BadDataStruct;
+		push @Errors, "$Title $GENFILE: $Num function(s) exported at wrong ordinal:\n";
+		foreach $Ref (@BadDataStruct) {
+			my $r3unused = $$Ref{R3Unused} ? " R3UNUSED" : "";
+			push @Errors, "  $$Ref{LineNum}: $$Ref{Name} \@ $$Ref{Ordinal} NONAME$r3unused\n";
+		}
+	}
+	if (@Errors) {
+		unless ($Options{compare}) {
+			die @Errors;
+		}
+		else {
+			print @Errors;
+		}
+	}
+
+#	Update the frozen .DEF file
+	eval { &UpdateFrzFileL(\@NewDataStruct, \@FrzDataStruct, $FRZFILE, $FrzExportsOn, $Options{compare}, $NumRemoved); };
+	die $@ if $@;
+	
+
+	exit;
+}
+
+#######################################################################
+# SUBROUTINES
+#######################################################################
+
+sub Usage () {
+
+	print(
+		"\n",
+		"EFREEZE - .DEF file maintenance utility V$MajorVersion.$MinorVersion.$PatchVersion\n",
+		"\n",
+		"EFREEZE {options} [frozen .DEF file] [new .DEF file]\n",
+		"\n",
+		"options:   (case-insensitive)\n",
+		"  -Compare\n",
+		"  -Remove\n",
+		"\n"
+	);
+	exit 1;
+}
+
+sub CompareFrzGenL ($$$$$$) {
+	my ($NewStructRef, $MissingStructRef, $BadStructRef, $FrzStructRef, $GenStructRef, $remove)=@_;
+
+#	compare the input export data with the frozen data
+
+#	take a copy of the frozen .DEF file structure that we can trash
+	my @TmpStruct=@$FrzStructRef;
+
+#	remove any entries not containing export data and get the highest ordinal value used
+	my $LastOrdinal=0;
+	foreach (@TmpStruct) {
+		if ($$_{Name}) {
+			if ($LastOrdinal<$$_{Ordinal}) {
+				$LastOrdinal=$$_{Ordinal};
+			}
+			next;
+		}
+		undef $_;
+	}
+
+	my $GenRef;
+	my $TmpRef;
+	GENLOOP: foreach $GenRef (@$GenStructRef) {
+		next unless $$GenRef{Name};		# ignore lines in the .DEF file not containing an export
+		foreach $TmpRef (@TmpStruct) {
+			next unless defined $TmpRef; # ignore nullified entries in the temporary array
+#			does the function name match?
+			if ($$GenRef{Name} eq $$TmpRef{Name}) {
+#				check the names have the same ordinals
+				if ($remove or $$GenRef{Ordinal}==$$TmpRef{Ordinal}) {
+					undef $TmpRef;
+					next GENLOOP;
+				}
+#				store exports with the wrong ordinals
+				push @$BadStructRef, $GenRef;
+				undef $TmpRef;
+				next GENLOOP;
+			}
+#			Absent export?
+			if ($$TmpRef{Absent} and $$TmpRef{Ordinal}==$$GenRef{Ordinal}) {
+				next GENLOOP;
+			}
+		}
+#		store new exports not found in the frozen .DEF file with the right ordinal value
+		$LastOrdinal++;
+		$$GenRef{Ordinal}=$LastOrdinal;
+		push @$NewStructRef, $GenRef;
+	}
+
+#	all the exports left in the frozen .DEF file weren't found
+	foreach $TmpRef (@TmpStruct) {
+		next unless defined $TmpRef; # ignore nullified entries in the temporary array
+		next if $$TmpRef{Absent};	# skip entries marked as ABSENT in the DEF file
+		push @$MissingStructRef, $TmpRef;
+	}
+}
+
+sub UpdateFrzFileL ($$$$$$) {
+	my ($NewStructRef, $FrzStructRef, $FILE, $ExportsOn, $Compare, $NumRemoved)=@_;
+
+#	add the exports to the frozen .DEF file text
+	unless (@$NewStructRef or $NumRemoved) {
+		print "EFREEZE: DEF file up to date\n";
+		return;
+	}
+
+	my $NumNewExports=@$NewStructRef;
+	unless ($Compare) {
+# 		abort the operation unless the frozen .DEF file is writeable
+		if (-e $FILE and not -w $FILE) {
+			die
+				"EFREEZE ERROR: Can't append $NumNewExports New Export(s) to $FILE\n",
+				"  as file is not writeable.  Check source code control system.\n"
+			;
+		}
+		print "EFREEZE: Appending $NumNewExports New Export(s) to $FILE:\n" if ($NumNewExports);
+	}
+	else {
+		print "EFREEZE: $NumNewExports New Export(s):\n" if ($NumNewExports);
+	}
+
+	my @Text;
+	my $ExportsDeclared;
+
+#	Process the frozen .DEF file
+	if (@$FrzStructRef) { # there is already a frozen .DEF file
+		my $FrzRef;
+
+#		get the lines of text from the frozen .DEF file
+		foreach $FrzRef (@$FrzStructRef) {
+			next if (!$FrzRef);
+			if (!defined($$FrzRef{Ordinal})) {
+				push @Text, $$FrzRef{Line};
+				$ExportsDeclared = 1 if ($$FrzRef{Line} =~ /^\s*EXPORTS\s*(\s+\S+.*)?$/io);
+				next;
+			}
+			my $Comment='';
+			if ($$FrzRef{Comment}) {
+				$Comment=" ; $$FrzRef{Comment}";
+			}
+			my $r3unused = $$FrzRef{R3Unused} ? " R3UNUSED" : "";
+			my $absent = $$FrzRef{Absent} ? " ABSENT" : "";
+
+			my $data = "";
+			if( !($$FrzRef{Name} =~ /^(_ZTI|_ZTV|_ZTT)/))
+			{
+#				A symbol name with the above pattern indicates that it is a Data symbol.
+#				Mark symbols as DATA only when it cannot be found from the name alone (i.e.,
+#				explicitly exported data symbols).
+
+				if(($$FrzRef{Data}) and ($$FrzRef{Size}) ){
+				$data = " DATA $$FrzRef{Size}";
+				}
+			}
+			push @Text, "\t$$FrzRef{Name} \@ $$FrzRef{Ordinal} NONAME$data$r3unused$absent$Comment\n";
+		}
+
+#		strip any blank lines at the end of the frozen .DEF file text
+		foreach (reverse @Text) {
+			if (/^\s*$/o) {
+				$_='';
+				next;
+			}
+			last;
+		}
+
+	}
+
+#	Add an EXPORTS section header if there aren't already exports
+	unshift @Text, "EXPORTS\n" unless ($ExportsDeclared);
+
+	my $NewRef;
+	foreach $NewRef (@$NewStructRef) {
+		my $Comment='';
+		if ($$NewRef{Comment}) {
+			$Comment=" ; $$NewRef{Comment}";
+		}
+		my $r3unused = $$NewRef{R3Unused} ? " R3UNUSED" : "";
+		my $absent = $$NewRef{Absent} ? " ABSENT" : "";
+
+		my $data = "";
+		if( !($$NewRef{Name} =~ /^(_ZTV|_ZTI|_ZTT)/)) {
+#				A symbol name with the above pattern indicates that it is a Data symbol.
+#				Mark symbols as DATA only when it cannot be found from the name alone (i.e.,
+#				explicitly exported data symbols).
+			if(($$NewRef{Data}) and ($$NewRef{Size}) ){
+			$data = " DATA $$NewRef{Size}";
+			}
+		}
+		print "  $$NewRef{Name} \@ $$NewRef{Ordinal} NONAME$r3unused$Comment\n";
+		push @Text, "\t$$NewRef{Name} \@ $$NewRef{Ordinal} NONAME$data$r3unused$absent$Comment\n";
+	}
+
+#	add a terminating newline
+	push @Text, "\n";
+
+	unless ($Compare) {
+#		write the new frozen .DEF file
+		eval { &Def_WriteFileL(\@Text, $FILE); };
+		die $@ if $@;
+	}
+}
+