halservices/hal/halcfg.pl
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

# Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of the License "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:
# hal\halcfg.pl
# Check arguments and open files
# 
#

my $nargs=scalar(@ARGV);
my $xmode=0;
if ($nargs==0) {
	usage();
}
elsif ($nargs!=3 and $nargs!=4) {
	die "Invalid number of arguments.  Run with no arguments for help on usage.\n";
	exit;
}
my $arg=0;
if ($nargs==4) {
	if ($ARGV[$arg] eq '-x') {
		$xmode=1;
	} elsif ($ARGV[$arg] eq '-s') {
		$xmode=2;
	} elsif ($ARGV[$arg] eq '-h') {
		$xmode=3;
	} else {
		usage();
		die "Invalid 1st argument $ARGV[0]\n";
	}
	++$arg;
}
my $headerFileName=$ARGV[$arg++];
my @hdr = &read_file_strip_comments($headerFileName);

my $inputFileName=$ARGV[$arg++];
my @input = &read_file_strip_comments($inputFileName);

my $outputFileName=$ARGV[$arg++];

#
# Parse the header file
#
my $line=0;
my $state=0;
my $enumName;
my %enumValues=();
my $nextValue=0;
my $bitmask=0;
my %enumList=();
foreach (@hdr) {
	++$line;
	next if (/^\s*\#/);		# ignore preprocessor directives
	next if (/^\s*\/\//);	# ignore comments starting with //
	next if (/^\s*$/);		# ignore blank lines
	if ($state==0) {
		if (/^\s*class\s+HALData\s*$/) {
			$state=1;
		}
		if (/^\s*class\s+HALData\s*{/) {
			$state=2;
		}
		next;
	}
	if ($state==1) {
		if (/^\s*{/) {
			$state=2;
		}
		next;
	}
	if ($state==2) {
		if (/^\s*};/) {
			$state=3;
			last;
		}
		if (/^\s*enum\s+(\w+)(.*)/) {
			$enumName=$1;
			%enumValues=();
			$nextValue=0;
			$bitmask=0;
			if ($2=~/^\s+{/) {
				$state=5;
			} else {
				$state=4;
			}
		}
		if (/^\s*bitmask\s+(\w+)(.*)/) {
			$enumName=$1;
			%enumValues=();
			$nextValue=0;
			$bitmask=1;
			if ($2=~/^\s+{/) {
				$state=5;
			} else {
				$state=4;
			}
		}
		next;
	}
	if ($state==4) {
		if (/^\s*{/) {
			$state=5;
		}
		next;
	}
	if ($state==5) {
		if (/^\s*(\w+)(.*)/) {
			my $tag=$1;
			my $val=0;
			my $rest=$2;
#			print "$tag\n$rest\n";
			if ($rest=~/^\s*,/) {
				$val=$nextValue;
			} elsif ($rest=~/^\s*\=\s*(\d\w*)\s*\,/) {
				$val=$1;
				unless ($val=~/^\d*$/) {
					if ($val=~/^0x(\w+)$/i) {
						$val=hex $1;
					} else {
						undef $val;
					}
				}
			} elsif ($rest=~/^\s*$/) {	# ignore last one
				next;
			} else {
				undef $val;
			}
			unless (defined $val) {
				die "Syntax error at line $line in file $headerFileName\n";
			}
			$nextValue=$val+1;
			$enumValues{$tag}=$val;
#			print "$tag=$val\n";
		} elsif (/^\s*};/) {
			$state=2;
			if ($bitmask) {
				$enumValues{'__bitmask__'}=-1;
			}
			my %temp=%enumValues;
			$enumList{$enumName}=\%temp;
		}
		next;
	}
}
if ($state!=3) {
	die "Unexpected end of file in $headerFileName\n";

}

#	my @keys=keys %enumList;
#	foreach(@keys) {
#		print "enum $_\n\t{\n";
#		my $ref=$enumList{$_};
#		my @tags=keys(%$ref);
#		foreach(@tags) {
#			my $value=$$ref{$_};
#			print "\t$_=$value\n";
#		}
#		print "\t};\n";
#	}

#
# Build a list of properties for each attribute
#
my $attribref=$enumList{'TAttribute'};
unless ($attribref) {
	die "No TAttribute enum defined\n";
}
my @attribs=keys %$attribref;
my %attribList;
foreach (@attribs) {
	my %properties;
	$properties{'name'}=$_;
	$properties{'ordinal'}=$$attribref{$_};
	my $enum=$_;
	$enum=~s/^E/T/;			# change initial E to T
	if (defined $enumList{$enum}) {
		my $enumRef=$enumList{$enum};
		$properties{'enum'}=$enumRef;
		if (defined $$enumRef{'__bitmask__'}) {
			$properties{'bitmask'}=1;
		}
	}
	$attribList{$_}=\%properties;
}

my $attpropref=$enumList{'TAttributeProperty'};
my %PropTable;
if ($xmode) {
	unless ($attpropref) {
		die "No TAttributeProperty enum defined\n";
	}

	my @attprops=keys(%$attpropref);
	foreach (@attprops) {
		if (/^E(\w+)$/) {
			my $propname=lc $1;
			$PropTable{$propname}='HAL::'.$_;
		} else {
			die "Invalid attribute property $_\n";
		}
	}
}
my @PropTableKeys=keys %PropTable;


#
# Parse the input file
#
$line=0;
foreach (@input) {
	++$line;
	next if (/^\s*\/\//);	# ignore comments starting with //
	next if (/^\s*$/);		# ignore blank lines
	if (/^\s*(\w+)\s*(.*)/) {
		my $attrib=$1;
		my $rest=$2;
		my $propRef=$attribList{$attrib};
		unless (defined $propRef) {
			die "Unrecognised attribute at line $line in file $inputFileName\n";
		}
#		print "$rest\n";
		if ($rest=~/^\:\s*(.*)/) {	# attribute properties follow
			if (!$xmode) {
				die "Line $line: Properties not permitted without -x option\n";
			}
			$rest=$1;
#			print "$rest\n";
			while ($rest=~/^(\w+)\s*(.*)/) {
				my $prop=lc $1;
				$rest=$2;
#				print "$rest\n";
				my $error=matchabbrev(\$prop, \@PropTableKeys);
				if ($error) {
					die "$error property $prop at line $line in file $inputFileName\n";
				}
				$$propRef{$prop}=1;
				if ($rest=~/^,\s*(.*)/) {
					$rest=$1;
				} elsif ($rest=~/^=\s*(.*)/) {
					$rest=$1;
					last;
				} else {
					die "Syntax error at line $line in file $inputFileName\n";
				}
			}
		} elsif ($rest=~/^=\s*(.*)/) {
			$rest=$1				# attribute value follows
		} else {
			die "Invalid attribute specification at line $line in file $inputFileName\n";
		}
#		print "$rest\n";
		if ($xmode) {
#			print "$rest\n";
			if ($rest=~/^((\w|:)+)/) {
				$$propRef{'value'}=$1;
			} else {
				die "Invalid function name $rest at line $line in file $inputFileName\n";
			}
		} elsif (defined $$propRef{'bitmask'}) {		# bitmask value
			my $enumRef=$$propRef{'enum'};
			my @keys=keys %$enumRef;
			my $val=0;
			while ($rest=~/^(\w+)\s*(.*)/) {
				my $bitmaskKey=$1;
				$rest=$2;
				if ($bitmaskKey eq '0' or lc($bitmaskKey) eq 'none') {
					last if ($val==0);
					die "Inconsistent bit mask values at line $line in file $inputFileName\n";
				}
				my $error=matchabbrev(\$bitmaskKey,\@keys);
				if ($error) {
					die "$error bit value $bitmaskKey at line $line in file $inputFileName\n";
				}
				$val |= $$enumRef{$bitmaskKey};
				if ($rest=~/^\+\s*(.*)/) {
					$rest=$1;
				} elsif ($rest=~/^\s*$/) {
					last;
				} else {
					die "Syntax error at line $line in file $inputFileName\n";
				}
			}
			$$propRef{'value'}=$val;
		} elsif (defined $$propRef{'enum'} and $rest!~/^\d/) {	# enum value
			my $enumRef=$$propRef{'enum'};
			my @keys=keys %$enumRef;
			if ($rest=~/^(\w+)\s*$/) {
				my $enumKey=$1;
				my $error=matchabbrev(\$enumKey,\@keys);
				if ($error) {
					die "$error enumeration value $enumKey at line $line in file $inputFileName\n";
				}
				$$propRef{'value'}=$$enumRef{$enumKey};
			} else {
				die "Invalid enum value $rest at line $line in file $inputFileName\n";
			}
		} elsif ($rest=~/^(\-?\d\w*)\s*$/) {		# numeric value (decimal or hex) with optional -ve sign
			my $val=$1;
			unless ($val=~/^(\-?\d)\d*$/) {         # First character should be an optional -ve sign followed by only digits
				if ($val=~/^(\-?)0x(\w+)$/i) {       # First character should be an optional -ve sign followed by only alphanumerics 
					my $sign=$1;
					$val=hex $2;
					if ($sign  eq '-') {
					  $val=-$val;
					} 
				} else {
					undef $val;
				}
			}
			unless (defined $val) {
				die "Invalid attribute value $1 at line $line in file $inputFileName\n";
			}
			$$propRef{'value'}=$val;
		} else {								# invalid
			die "Invalid attribute value at line $line in file $inputFileName\n";
		}
	} else {
		die "Unrecognised attribute at line $line in file $inputFileName\n";
	}
}

#	foreach (@attribs) {
#		my $propRef=$attribList{$_};
#		if (defined $$propRef{'value'}) {
#			print "Attribute $_:\n";
#			my @keys=keys %$propRef;
#			foreach (@keys) {
#				print "\t$_=$$propRef{$_}\n";
#			}
#		}
#	}

#
# Sort attributes by ordinal
#
my @AttribsByOrdinal;
foreach (@attribs) {
	my $propRef=$attribList{$_};
	my $ordinal=$$propRef{'ordinal'};
	$AttribsByOrdinal[$ordinal]=$propRef;
}
my $nAttribs=scalar(@AttribsByOrdinal);

#
# Generate the output file
#

open OUT, ">$outputFileName" or die "Cannot open output file $outputFileName\n";

#	binmode OUT;
#	my $i=0;
#	while ($i<$nAttribs) {
#		my $value=0x80000000;
#		my $propRef=$AttribsByOrdinal[$i];
#		if (defined $$propRef{'value'}) {
#			$value=$$propRef{'value'};
#		}
#		++$i;
#		my $b3=($value>>24)&0xff;
#		my $b2=($value>>16)&0xff;
#		my $b1=($value>>8)&0xff;
#		my $b0=$value&0xff;
#		my $b0123=chr $b0;
#		$b0123.=chr $b1;
#		$b0123.=chr $b2;
#		$b0123.=chr $b3;
#		my $writeres=syswrite OUT, $b0123, 4;
#		if ($writeres != 4) {
#			die "Error writing output file $outputFileName\n";
#		}
#	}
#	exit;

my @splitName=split /(:|\\)/, $outputFileName;
my $rootName=pop @splitName;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
#print "\n$hour:$min:$sec $mday-$mon-$year wday=$wday, yday=$yday, isdst=$isdst\n\n";
$year+=1900;

print OUT "// $rootName\n";
print OUT "//\n";
print OUT "// Copyright (c) 1999-$year Nokia Corporation and/or its subsidiary(-ies).";
print OUT "// All rights reserved.\n";
print OUT "//\n";
if ($xmode!=2) {
	print OUT "// GENERATED FILE - DO NOT EDIT\n";
	print OUT "//\n";
}
print OUT "\n";
print OUT "#include <kernel/hal_int.h>\n";
if ($xmode==0) {
	print OUT <<EOF;
#ifdef __CW32__
// CodeWarrior requires EXPORT_C on the definiton here, as well as the declaration (in hal_int.h)
EXPORT_C const TInt HalInternal::InitialValue[]=
#else
EXPORT_D const TInt HalInternal::InitialValue[]=
#endif
	{
EOF

	my $i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $separator=($i<$nAttribs)?',':'';
		my $name=$$propRef{'name'};
		my $value=0;
		if (defined $$propRef{'value'}) {
			$value=$$propRef{'value'};
		}
		print OUT "\t$value$separator\t\t// $name\n";
	}
	print OUT "\t};\n";
} elsif ($xmode==1) {
	print OUT "\n";
	my $i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $name=$$propRef{'name'};
		my $imp=$$propRef{'value'};
		if ($imp=~/^\s*0\s*$/) {
			undef $imp;
		}
		if (defined $imp) {
			print OUT "GLREF_C TInt $imp(TInt, TInt, TBool, TAny*);\t// $name\n";
		}
	}
	print OUT "\n";
	print OUT "const TUint8 HalInternal::Properties[]=\n";
	print OUT "\t{\n";
	$i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $separator=($i<$nAttribs)?',':'';
		my $properties="";
		my $name=$$propRef{'name'};
		if (defined $$propRef{'value'}) {
			$properties=$PropTable{'valid'};
			my @keys=keys(%$propRef);
			foreach (@keys) {
				my $pConst=$PropTable{$_};
				if (defined $pConst) {
					$properties.="|$pConst";
				}
			}
		}
		if ($properties=~/^\s*$/) {
			$properties='0';
		}
		print OUT "\t$properties$separator\t\t// $name\n";
	}
	print OUT "\t};\n";
	print OUT "\n#if 0\n";
	print OUT "const TInt HalInternal::Offset[]=\n";
	print OUT "\t{\n";
	my $memOffset=0;
	$i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $separator=($i<$nAttribs)?',':'';
		my $name=$$propRef{'name'};
		my $imp=$$propRef{'value'};
		if ($imp=~/^\s*0\s*$/) {
			print OUT "\t$memOffset$separator\t\t// $name\n";
			$memOffset+=4;
		} else {
			print OUT "\t-1$separator\t\t// $name\n";
		}
	}
	print OUT "\t};\n";
	print OUT "\n#endif\n";
	print OUT "const TInt HalInternal::HalDataSize=$memOffset;\n";
	print OUT "\n";
	print OUT "const THalImplementation HalInternal::Implementation[]=\n";
	print OUT "\t{\n";
	$i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $separator=($i<$nAttribs)?',':'';
		my $name=$$propRef{'name'};
		my $imp=$$propRef{'value'};
		if (!defined $imp or $imp=~/^\s*0\s*$/) {
			$imp='NULL';
		}
		print OUT "\t$imp$separator\t\t// $name\n";
	}
	print OUT "\t};\n";
} elsif ($xmode==2) {
	print OUT "\n";
	$i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $name=$$propRef{'name'};
		my $imp=$$propRef{'value'};
		if ($imp=~/^\s*0\s*$/) {
			undef $imp;
		}
		my $setarg=' /*aSet*/';
		if (defined $$propRef{'settable'}) {
			$setarg=' aSet';
		}
		if (defined $imp) {
			print OUT "// $name\n";
			print OUT "TInt $imp(TInt /*aDeviceNumber*/, TInt /*aAttrib*/, TBool$setarg, TAny* aInOut)\n";
			print OUT "\t{\n";
			print OUT "\treturn KErrNone;\n";
			print OUT "\t}\n";
			print OUT "\n";
		}
	}
	print OUT "\n";
} elsif ($xmode==3) {
	my $hdrprot='__'.uc $rootName.'__';
	$hdrprot=~s/\./_/;
	print OUT "\n";
	print OUT "#ifndef $hdrprot\n";
	print OUT "#define $hdrprot\n";
	$i=0;
	while ($i<$nAttribs) {
		my $propRef=$AttribsByOrdinal[$i];
		++$i;
		my $name=$$propRef{'name'};
		my $imp=$$propRef{'value'};
		if ($imp=~/^\s*0\s*$/) {
			undef $imp;
		}
		if (defined $imp) {
			print OUT "GLREF_C TInt $imp(TInt, TInt, TBool, TAny*);\t// $name\n";
		}
	}
	print OUT "\n";
	print OUT "#endif\n";
}

print OUT "\n";

exit;

# END OF MAIN

sub matchabbrev($$) {
	my ($inref, $lref)=@_;
	my @matches=grep(/$$inref/i,@$lref);
	my $nmatches=scalar(@matches);
	if ($nmatches==0) {
		return "Unknown";
	} elsif ($nmatches>1) {
		my @xmatches=grep(/^$$inref$/i,@matches);
		if (scalar(@xmatches)!=1) {
			return "Ambiguous";
		} else {
			$$inref=$xmatches[0];
			return undef;
		}
	} else {
		$$inref=$matches[0];
		return undef;
	}
}

sub read_file_strip_comments($) {
	my ($filename) = @_;
	open IN, $filename or die "Cannot read file $filename\n";
	my $in;
	while (<IN>) {
		$in .= $_;
	}
	close IN;

	# Strip comments
	$in =~ s/\/\*(.*?)\*\//\n/gms;
	$in =~ s/\/\/(.*?)\n/\n/gms;

	return split(/(\n)/, $in);
}

sub usage() {
	print
		"\n",
		"halcfg.pl is a perl script that is used by the build system to generate the\n",
		"C++ source files from the Config and Values files.\n",
		"\n",
		"There are four modes in which the Perl script halcfg.pl can be used.\n",
		"\n",
		"\"perl halcfg.pl hal_data.h values.hda values.cpp\"\n",
		"\n",
		"takes the values.hda text file and generates a table of initial values for\n",
		"items stored by the HAL.\n",
		"\n",
		"\"perl halcfg.pl -x hal_data.h config.hcf config.cpp\"\n",
		"\n",
		"generates three tables:\n",
		"\n",
		"  - the properties, i.e. whether valid and/or writable, for each item\n",
		"\n",
		"  - the offset of each item within the DllGlobal block\n",
		"\n",
		"  - the function implementing each item, for derived attributes. ie. those\n",
		"    attributes that are not simply stored by the HAL.\n",
		"\n",
		"\"perl halcfg.pl -s hal_data.h config.hcf source.cpp\"\n",
		"\n",
		"generates a source file containing skeleton code for the implementation of the\n",
		"accessor function for each derived attribute\n",
		"\n",
		"\"perl halcfg.pl -h hal_data.h config.hcf header.h\"\n",
		"\n",
		"generates a header file containing prototypes for the accessor functions for\n",
		"each derived attribute\n",
		"\n",
		"Note that the header file hal_data.h containing the attributes and values used\n",
		"by the HAL is passed on all calls to the perl script.\n";

	exit;
}