#!/usr/bin/perl

use Getopt::Long;
use Mysql;

use Env qw(LSBUSER LSBDBPASSWD LSBDB LSBDBHOST);

# Uncomment to trace SQL statments
#$trace=1;

$nameonly=0;

# Variable to fix Function pointer hack.
$typefuncptr=0;
$funcPtrName="";
$className="";

# variable to resolve typedef stuct/union definition
$typeflag=0;
$semicolonNeeded=0;

%prototyped = {};

sub
usage()
{
die "mkheader -h <headername> -a <archname> -v <lsbversion>";
}

sub
getBaseTypeID($)
{
	local ($param) = @_;
	if( $$param{'ATbasetype'} != '' ) {
		$basetype = $$param{'ATbasetype'};
	}
	else {
		$selectBase = "SELECT ATbasetype FROM ArchType ";
		$selectBase.= "WHERE ATtid=".$$param{'Tid'}." ";
		$selectBase.= "GROUP BY ATbasetype";
		$sthBase = $Dbh->query($selectBase) || die $Dbh->errmsg();
		if($sthBase->numrows != 1) {
			die "Couldn't determine basetype for type ".$$param{'Tid'}." on $Aid architecture";
		}

		%base=$sthBase->fetchhash;
		$basetype = $base{'ATbasetype'};
	}

	return $basetype;
}

sub
getBaseTypeRecord($)
{
 	local ($basetype) = @_;
    $select = "SELECT * FROM Type ";
    $select.= "LEFT JOIN ArchType ON ATtid=Tid ";
    $select.= "WHERE Tid=".$basetype;
    $select.= " AND ATaid IN (1,$Aid,0)"; # Note that even if there are two records here only first one will be processed
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	if( !$sth->numrows ) {
		# Hmm... Failed to get basetype on the current or generic architecture -
		#  let's try to get basetype on any architecture (not a good practice, but it's a usual situation
		#  in the current db)
		$select = "SELECT * FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid=".$basetype;
# 		$select.= " GROUP BY ATtid ";
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
	}
	return $sth;
}

sub
displaytype($)
{
local ($type) = @_;
local (*entry,*tentry,*tmentry);
local($th);
local($tmh);

# handle opaque types better ...
if ($nameonly && $$type{'Ttype'} eq "") {
	print $$type{'Tname'};
	return;
}
if( $$type{'Ttype'} eq "Intrinsic" ) {
	print $$type{'Tname'}."\t";
	return;
	}

if( $$type{'Ttype'} eq "Literal" ) {
	print $$type{'Tname'};
	return;
	}

if( $$type{'Ttype'} eq "Volatile" ) {
	$basetype = getBaseTypeID($type);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
    if( $type{'Ttype'} eq "Pointer" ) {
	    displaytype(\%type);
        print "volatile ";
	} else {
       	print "volatile ";
	    displaytype(\%type);
	}
    return;
 }

if( $$type{'Ttype'} eq "Const" ) {
	$basetype = getBaseTypeID($type);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	if( $type{'Ttype'} eq "Pointer" ) {
		displaytype(\%type);
		print "const ";
	} else {
		print "const ";
		displaytype(\%type);
	}
	return;
	}

if( $$type{'Ttype'} eq "Typedef" ) {
	if (!$nameonly && !$typeflag) {
		print "typedef ";
		$typefuncptr=0;
	}
	$basetype = getBaseTypeID($type);
 	$sth = getBaseTypeRecord($basetype);
	%entry=$sth->fetchhash;

	if($entry{'Ttype'} eq "FuncPtr" && !$nameonly){
		$typefuncptr=1;
	}
# Something about anon or not & wether to set nameonly
	if ($typeflag) {
		if($entry{'Ttype'} eq 'Struct' || $entry{'Ttype'} eq 'Union'){
			if( !($entry{'Tname'} =~ "anon" )) {
				if(!($entry{'Theadgroup'} != $HGid )) {
# 					$old_sth = $sth;
# 					for( $i=0; $i < $old_sth->numrows; $i++ ) {
						displaytype(\%entry);
# 						%entry=$old_sth->fetchhash;
# 					}
				}
			}
		} else {
			return;
		}

	} elsif (!$nameonly) {
		if( ( $entry{'Ttype'} eq 'Typedef' || $entry{'Ttype'} eq 'FuncPtr' ||
				$entry{'Ttype'} eq 'Function' ) || $entry{'Theadgroup'} != $HGid ) {
			if($entry{'Ttype'} eq 'FuncPtr' || $entry{'Ttype'} eq 'Function') {
				$funcPtrName = $$type{'Tname'};
			}
			$nameonly=1;
			displaytype(\%entry);
			$nameonly=0;
		} elsif( ($entry{'Ttype'} eq 'Struct' ||
			$entry{'Ttype'} eq 'Union' )
			&& $entry{'Theadgroup'} == $HGid  ) {
				if( !($entry{'Tname'} =~ "anon" )) {
					$nameonly=1;
					displaytype(\%entry);
					$nameonly=0;
				} else {
					displaytype(\%entry);
				}
		} else {
			displaytype(\%entry);
		}
	}
	if( ($entry{'Ttype'} ne 'FuncPtr' &&
		$entry{'Ttype'} ne 'Function') || $nameonly ) {
		if(!$typeflag){
			$typedef_name = $$type{'Tunmangled'} ? $$type{'Tunmangled'} : $$type{'Tname'};

			if( $typedef_name =~ /$className\:\:(.+)/ ) {
				$typedef_name = $1;
			}

			print $typedef_name."\t";
		}
	}
	if( $entry{'Ttype'} eq 'Array' && $nameonly==0) {
		print "[".$entry{'ATsize'}."]";
	}
	if( !$nameonly && $$type{'ATattribute'} && !$typeflag ) {
		print "__attribute__ (".$$type{'ATattribute'}.")";
	}
	if (!$nameonly) {
		print $$type{'Tdescription'}."\n";
	}
	return;
}

if( $$type{'Ttype'} eq "Pointer" or $$type{'Ttype'} eq "Ref" ) {
	$basetype = getBaseTypeID($type);
 	$tth = getBaseTypeRecord($basetype);
 	%entry=$tth->fetchhash;
	if (!$nameonly) {
		if( $entry{'Ttype'} eq 'Typedef' ||
		    $entry{'Ttype'} eq 'FuncPtr' ) {
			$nameonly=1;
			displaytype(\%entry);
			$nameonly=0;
		}else {
            if (($entry{'Ttype'} eq 'Struct' || $entry{'Ttype'} eq 'Union') && !$typeflag ) {
               $nameonly=1;
               displaytype(\%entry);
               $nameonly=0;
			}else {
				displaytype(\%entry);
			}
		}
	} else {
		displaytype(\%entry);
	}

	if( $$type{'Ttype'} eq "Ref" ) {
		print "& ";
	}
	else {
		print "* ";
	}
	return;
	}

if( $$type{'Ttype'} eq "Struct" and ($$type{'Tclass'} == 0 or $$type{'Tunmangled'} =~ "::") ) {
	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}
	$struct_name = $$type{'Tunmangled'} ? $$type{'Tunmangled'} : $$type{'Tname'};

	if( $struct_name =~ /$className\:\:(.+)/ ) {
		$struct_name = $1;
	}

	if (!$typeflag){
		print "struct ".$struct_name."\t";
	}
	if( $nameonly ) { return; }
	$Tid=$$type{'Tid'};
	#print $$type{'Tdescription'}."\n";

	$tmselect = "SELECT * FROM TypeMember ";
	$tmselect.= "WHERE TMmemberof=$Tid AND TMaid IN (1,$TMaid) ";
	$tmselect.= "ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	if ($tmh->numrows ) {
		if ($typeflag){
	  		print "\nstruct ".$$type{'Tname'}."\t";
			$semicolonNeeded=1;
		 	}
		print "{\n"; }
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		$TMtypeid=$tmentry{'TMtypeid'};
		#joining Type table with ArchType to get ATsize value for Array bounds.
		$tselect = "SELECT * FROM Type ";
		$tselect.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$tselect.= "WHERE Tid=$TMtypeid ";
# 		$tselect.= "AND ATaid=$Aid";
# 		print $tselect."\n";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$nameonly=1;
		if($typeflag){
			$typeflag=0;
			$sflag=1;
			}
		$funcPtrName = $tmentry{'TMname'};

		#if( $tmentry{'Aid'} && $tmentry{'Aname'} ne "All" ) {
		#	print "#if defined(".$tmentry{'Asymbol'}.")\n";
		#	}
		displaytype(\%entry);
		if( $entry{'Ttype'} ne 'FuncPtr' ) {
			print $tmentry{'TMname'};
			}
		# Adding code to support both values from TMarray and ATsize for Array bounds.
		# TMarray condition should be removed once we deprecate it.
		if( $entry{'Ttype'} eq 'Array' ) {
			if($tmentry{'TMarray'}){
				print "[".$tmentry{'TMarray'}."]";
			}else {
				# check the basetype of this array
				$tselect ="SELECT * FROM Type ";
				$tselect.= "LEFT JOIN ArchType ON ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'ATbasetype'} ";
				$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
				%bentry=$tth->fetchhash;
				if ($bentry{'Ttype'} eq 'Array') {
					print "[".$bentry{'ATsize'}."]"."[".$entry{'ATsize'}."]";
				} else {
					print "[".$entry{'ATsize'}."]";
				}
				}
			}
		if( $tmentry{'TMbitfield'} != 0 ) {
			print ":".$tmentry{'TMbitfield'};
			}
		print ";\t";
		if( $tmentry{'TMdescription'} ) {
			print "/* ".$tmentry{'TMdescription'}." */";
			}
		print "\n";
		#if( $tmentry{'Aid'} && $tmentry{'Aname'} ne "All" ) {
		#	print "#endif /* ".$tmentry{'Asymbol'}." */\n";
		#	}
		$nameonly=0;
		if($sflag){$typeflag=1;
			 $sflag=0;
	 		}
		}
	if ($tmh->numrows ) { print "}\n"; }
	if( $$type{'ATattribute'} ) {
		print "__attribute__ (".$$type{'ATattribute'}.")";
		}
#	print "\n";
	return;
	}

if( $$type{'Ttype'} eq "Union" ) {

	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}

	$union_name = $$type{'Tunmangled'} ? $$type{'Tunmangled'} : $$type{'Tname'};

	if( $union_name =~ /$className\:\:(.+)/ ) {
		$union_name = $1;
	}

	if(!$typeflag) {
		print "union ".$union_name."\t";
	}

	$Tid=$$type{'Tid'};
	if( $nameonly ) { return; }
	#print $$type{'Tdescription'}."\n";

	$tmselect = "SELECT * FROM TypeMember WHERE TMmemberof=$Tid AND TMaid IN(1,$TMaid) ";
	$tmselect.= "ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	if ($tmh->numrows ) {
		if($typeflag){
			print "union ".$$type{'Tname'}."\t";
			$semicolonNeeded=1;
			}
		print "{\n"; }
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		$TMtypeid=$tmentry{'TMtypeid'};
		$tselect="SELECT * FROM Type ";
		$tselect.="LEFT JOIN ArchType ON ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid ";
# 		$tselect.= "AND ATaid=$Aid";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$nameonly=1;
		if($typeflag){
			$typeflag=0;
			$uflag=1;}
		$funcPtrName = $tmentry{'TMname'};

		displaytype(\%entry);
		if( $entry{'Ttype'} ne 'FuncPtr' ) {
			print $tmentry{'TMname'};
			}
		if( $entry{'Ttype'} eq 'Array' ) {
			if($tmentry{'TMarray'}){
				print "[".$tmentry{'TMarray'}."]";
			}else{
				# check the basetype of this array
				$tselect="SELECT * FROM Type ";
				$tselect.= "LEFT JOIN ArchType ON ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'ATbasetype'} ";
# 				$tselect.= "AND ATaid=$Aid";
				$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
				%bentry=$tth->fetchhash;
				if ($bentry{'Ttype'} eq 'Array') {
					print "[".$bentry{'ATsize'}."]"."[".$entry{'ATsize'}."]";
				} else {
					print "[".$entry{'ATsize'}."]";
				}

			}
		 }
		print ";\t";
		if( $tmentry{'TMdescription'} ) {
			print "/* ".$tmentry{'TMdescription'}." */";
			}
		print "\n";
		if($uflag){$typeflag=1;
			$uflag=0;
			}
		$nameonly=0;
		}
	if ($tmh->numrows ) { print "}\n"; }
	return;
	}

if( $$type{'Ttype'} eq "Enum" ) {
	print "enum ";
	$Tid=$$type{'Tid'};
	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
	}

	$enum_name = $$type{'Tunmangled'} ? $$type{'Tunmangled'} : $$type{'Tname'};

	if( $enum_name =~ /$className\:\:(.+)/ ) {
		$enum_name = $1;
	}

	print $enum_name."\t";
	if( $nameonly ) { return; }
	print $$type{'Tdescription'}."\n";

	$tmselect = "SELECT * FROM TypeMember WHERE TMmemberof=$Tid AND TMaid IN (1,$TMaid) ";
	$tmselect.= "ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();

	# Is it enum with arch specific contents?
	if (!$tmh->numrows ) {
		$tmselect = "SELECT * FROM TypeMember ";
		$tmselect.= "LEFT JOIN Architecture ON Aid=TMaid ";
		$tmselect.= "WHERE TMmemberof=$Tid ";
		$tmselect.= "ORDER BY TMaid,TMposition ";
		$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	}

	if ($tmh->numrows ) { print "{\n"; }

	$prevArch=0;

	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;

		if( ($TMaid == 1) and ($tmentry{'TMaid'} != 1) ) {
			if( $prevArch != $tmentry{'TMaid'} ) {
				if( $prevArch != 0 ) {
					print "#endif\n";
				}
				print "#if ".$tmentry{'Asymbol'}."\n";
				print "/* ".$tmentry{'Aname'}." */\n";
				$prevArch = $tmentry{'TMaid'};
			}
		}

		# It's an enum, don't print out the types, just the names
		print $tmentry{'TMname'};

		# An array doesn't make sense for an enum, so use this to
		# specify a fixed value.
# 		if( $tmentry{'TMarray'} ne '' ) {
# 			print " = ".$tmentry{'TMarray'};
# 		}
		if( $tmentry{'TMvalue'} ne '' ) {
			print " = ".$tmentry{'TMvalue'};
		}
		if( $_ != $tmh->numrows ) {
			print ",\t";
		}
		if( $tmentry{'TMdescription'} ) {
			print "/* ".$tmentry{'TMdescription'}."*/";
		}
		print "\n";
		$nameonly=0;

	}
	if( $prevArch != 0 ) {
		print "#endif\n";
	}
	if ($tmh->numrows ) { print "}\n"; }
	return;
	}

if( $$type{'Ttype'} eq "FuncPtr" || $$type{'Ttype'} eq "Function" ) {
	$basetype = getBaseTypeID($type);
 	$sth = getBaseTypeRecord($basetype);
 	%entry=$sth->fetchhash;
	if( !$nameonly ) {
		$nameonly=1;
		displaytype(\%entry);
		$nameonly=0;
	} else {
		displaytype(\%entry);
	}
	print "(*" if ($$type{'Ttype'} eq "FuncPtr");
	$Tid=$$type{'Tid'};
	print $funcPtrName;
	print ")" if ($$type{'Ttype'} eq "FuncPtr");
	print $$type{'Tdescription'}."(";

	$tmselect = "SELECT * FROM TypeMember WHERE TMmemberof=$Tid AND TMaid IN (1,$TMaid) ";
	$tmselect.= "ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	if($tmh->numrows == 0) {
		print "void";
	}
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		$TMtypeid=$tmentry{'TMtypeid'};
		$tselect="SELECT * FROM Type ";
		$tselect.="LEFT JOIN ArchType ON ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid ";
# 		$tselect.= "AND ATaid=$Aid";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$nameonly=1;
		displaytype(\%entry);
		print $tmentry{'TMname'};
		if( $tmentry{'Ttype'} eq 'Array' ) {
			if( $tmentry{'TMarray'} ) {
				print "[".$tmentry{'TMarray'}."]";
			}elsif($entry{'ATsize'}){
				# check the basetype of this array
				$tselect="SELECT * FROM Type ";
				$tselect.= "LEFT JOIN ArchType ON ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'ATbasetype'} ";
# 				$tselect.= "AND ATaid=$Aid";
				$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
				%bentry=$tth->fetchhash;
				if ($bentry{'Ttype'} eq 'Array') {
					print "[".$bentry{'ATsize'}."]"."[".$entry{'ATsize'}."]";
				} else {
				      print "[".$entry{'ATsize'}."]";
				}
			}
		}
		if( $_ != $tmh->numrows ) {
			print ",";
		}
		$nameonly=0;
	}
	print ")";
	return;
	}

if( $$type{'Ttype'} eq "Array" ) {
	$basetype = getBaseTypeID($type);
 	$sth = getBaseTypeRecord($basetype);
 	%entry=$sth->fetchhash;
	if( !$nameonly ) {
		$nameonly=1;
 		displaytype(\%entry);
		$nameonly=0;
	} else {
		displaytype(\%entry);
	}
# We don't have any Ttype=Array with Tname=~"fptr".
# # Should we need below commented code #
#
#	if( $$type{'Tname'} =~ "fptr" ) {
#		$$type{'Tname'} =~ s/fptr-//;
#		}
	#print $$type{'Tname'};
	#print "[".$$type{'Tsize'}."]";
	return;
}

# structures in cpp can also have methods; such structures are stored as classes, not like usual classes
if( ( $$type{'Ttype'} eq "Struct" and $$type{'Tclass'} != 0 and $$type{'Tunmangled'} !~ "::" ) or ( $$type{'Ttype'} eq "Class" ) ) {
# if( $$type{'Ttype'} eq "Class" ) {
	$cselect ="SELECT * FROM ClassInfo ";
	$cselect.="WHERE CItid=".$$type{'Tid'};
# 		$tselect.= "AND ATaid=$Aid";
	$cth = $Dbh->query($cselect) || die $Dbh->errmsg();
	%entry=$cth->fetchhash;
	if( !$cth->numrows ) {
		print STDERR "No ClassInfo record found for Type ".$$type{'Tid'}."\n";
		return;
	}
	$CIid=$entry{'CIid'};

	$name = $$type{'Tunmangled'} ? $$type{'Tunmangled'} : $$type{'Tname'};

	if( $nameonly ) {
		print "$name ";
		return;
	}

	if( $$type{'Ttype'} eq 'Class' ) {
		print "class $name";
	}
	else {
		print "struct $name";
	}
# 	if( $nameonly ) {
# 		return;
# 	}

	if( $entry{'CInumvmitypes'} ) {
		$selectVMI = "SELECT Iunmangled,VBTaccess FROM VMIBaseTypes ";
		$selectVMI.= "LEFT JOIN Interface ON Iid=VBTbasetype ";
		$selectVMI.= "WHERE VBTcid=".$entry{'CIid'}." GROUP BY Iunmangled";
		$vmi = $Dbh->query($selectVMI) || die $Dbh->errmsg();;

		$printed=0;
		for(1..$vmi->numrows) {
			%rowVMI = $vmi->fetchhash;

			$rowVMI{'Iunmangled'} =~ s/typeinfo for //;
			$Name = $rowVMI{'Iunmangled'};
			$access = $rowBase{'VBTaccess'};

			if( $printed ) {
				print(", ");
			}
			else {
				print( " : " );
				$printed = 1 ;
			}

			if( $Name ) {
				print( $access." ".$Name );
			}
		}
	}
	elsif( $entry{'CInumbasetype'} == 1 ) {
		$selectBase = "SELECT Iunmangled,BTaccess FROM BaseTypes ";
		$selectBase.= "LEFT JOIN Interface ON Iid=BTrttiid ";
		$selectBase.= "WHERE BTcid=".$entry{'CIid'};
		$base = $Dbh->query($selectBase) || die $Dbh->errmsg();;
		%rowBase = $base->fetchhash;
		$rowBase{'Iunmangled'} =~ s/typeinfo for //;
		$Name = $rowBase{'Iunmangled'};
		$access = $rowBase{'BTaccess'};
		print( " : $access ".$Name );
	}

	print "\n";
	print "{\n";

	$old_access="";

	# declare members; there is no 'member access type' support in the db schema now, so all
	# struct members will be public and class members will be private
	if( $$type{'Ttype'} eq 'Class' ) {
		$old_access="private";
		print "private:\n";
	}
	else { # struct
		$old_access="public";
		print "public:\n";
	}

	$select = "SELECT * FROM TypeMember ";
	$select.= "LEFT JOIN Type ON TMtypeid=Tid ";
	$select.= "WHERE TMmemberof=".$$type{'Tid'};
	print $select,"\n" if $trace;
	$tmh = $Dbh->query($select) || die $Dbh->errmsg();
	print $tmh->numrows," rows\n" if $trace;
	for(1..$tmh->numrows) {
		$typeflag=0;
		%tmentry=$tmh->fetchhash;
		$nameonly = 1;
		print "    ";
		$old_CIid = $CIid;
		$old_name = $name;
		displaytype(\%tmentry);
		$name = $old_name;
		$CIid = $old_CIid;
		print " ".$tmentry{'TMname'}.";\n";
		$nameonly = 0;
	}

	# all types declared here will be in public section
	if( $$type{'Ttype'} eq 'Class' ) {
		$old_access="public";
		print "public:\n";
	}

	# Display class internal types
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	$select.= "LEFT JOIN Architecture ON ATaid=Aid ";
	$select.= "WHERE Tclass=$CIid ";
	# skip classes themselves
	if( $$type{'Ttype'} eq 'Class' ) {
		$select.= "AND Ttype<>'Class' ";
	}
	else {
		$select.= "AND Ttype<>'Struct' ";
	}
	$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
 	$select.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
#  	$select.= "AND Aid = $Aid ";
	$select.= "ORDER BY Tid";
	print $select,"\n" if $trace;

	$th = $Dbh->query($select) || die $Dbh->errmsg();
	print $th->numrows," rows\n" if $trace;
	for(1..$th->numrows) {
		$typeflag=0;
		%tentry=$th->fetchhash;
		if( $tentry{'Aname'} ne "All" ) {
			$selectArchSpec = "SELECT * FROM ArchType ";
			$selectArchSpec.= "LEFT JOIN Type ON Tid=ATtid ";
			$selectArchSpec.= "WHERE ATtid = ".$tentry{'Tid'};
			$selectArchSpec.= " AND ATaid = 1 ";
			$selectArchSpec.= "AND ( (ATappearedin <= '$lsbversion' and ATappearedin<>'' ";
			$selectArchSpec.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
		 	$selectArchSpec.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
			print $selectArchSpec,"\n" if $trace;
			$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
			if( $thArchSpec->numrows ) {
				# Generic records present - skip arch specific
				next;
			}
		}

		if( $tentry{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }

		$old_CIid = $CIid;
		$old_name = $name;
		$className = $name;
		$TMaid = $tentry{'Aid'} ? $tentry{'Aid'} : $Aid;
		if( $tentry{'Aid'} && $tentry{'Aname'} ne "All" ) {
			print "#if ".$tentry{'Asymbol'}."\n";
			print "/* ".$tentry{'Aname'}." */\n";
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
			print "#endif\n";
		} else {
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
		}
		$name = $old_name;
		$CIid = $old_CIid;
	}

	# Display class interfaces
	$iselect = "SELECT * FROM Interface ";
	$iselect.= "LEFT JOIN Type ON Ireturn=Tid ";
	$iselect.= "LEFT JOIN ArchInt ON Iid=AIint ";
	$iselect.= "LEFT JOIN Architecture ON AIarch=Aid ";
	$iselect.= "LEFT JOIN ArchType ON ATtid=Tid AND ATaid=AIarch ";
	$iselect.= "WHERE Iclass=".$$type{'Tid'}." ";
	$iselect.= "AND Iunmangled not like '%thunk%' ";
 	$iselect.= "AND (Isrcbin='SrcOnly' OR (";
 	$iselect.= "(AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
 	$iselect.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ) ";
	$iselect.=" ORDER BY Iaccess";
	print $iselect,"\n" if $trace;

	%processed = ();
	$ith = $Dbh->query($iselect) || die $Dbh->errmsg();
	for(1..$ith->numrows) {
		%int = $ith->fetchhash;

		if( $int{'Aid'} != 1 ) {
			$selectGeneric = "SELECT Iid FROM Interface ";
			$selectGeneric.= "LEFT JOIN ArchInt ON Iid=AIint ";
			$selectGeneric.= "WHERE AIarch=1 AND Iname='$int{'Iname'}'";
			$selectGeneric.= "AND (Isrcbin='SrcOnly' OR (";
			$selectGeneric.= "(AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
			$selectGeneric.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ) ";
			$sthGeneric = $Dbh->query($selectGeneric) || die $Dbh->errmsg();
			if( $sthGeneric->numrows ) {
				next;
			}
		}

		$Iid = $int{'Iid'};
		$Itype = $int{'Itype'};
		$Iaccess = $int{'Iaccess'};
		$Istatic = $int{'Istatic'};
		$Ivirtual = $int{'Ivirtual'};

		if( $$type{'Ttype'} eq 'Class' and $Iaccess ne $old_access ) {
			print $Iaccess.":\n";
			$old_access = $Iaccess;
		}

		if( $Itype eq 'Data' ) {
			$unmangled = $int{'Iunmangled'};
 			if( $unmangled =~ /$name\:\:(.+)/ ) {
 				$unmangled = $1;
 			}

			$rselect = "SELECT * FROM Type LEFT JOIN ArchType ON ATtid=Tid WHERE Tid = ".$int{'Ireturn'};
			$rth = $Dbh->query($rselect) || die $Dbh->errmsg();
			if($rth->numrows) {
				%ret = $rth->fetchhash;
				$old_name = $name;
				$nameonly = 1;
				print "    ";
				displaytyperef(\%ret);
				$nameonly = 0;
				$name = $old_name;
			}

			print " $unmangled;\n";
			next;
		}

# 		$Iname = $int{'Ishortname'};
# 		if( !$Iname ) {
# 			print STDERR "Please set Ishortname for interface with Iid=".$int{'Iid'}."\n";
# 			$Iname = $int{'Iunmangled'} ? $int{'Iunmangled'} : $int{'Iname'};
# 		}

		if( $int{'Iunmangled'} ) {
			$unmangled = $int{'Iunmangled'};
 			if( $unmangled =~ /$name\:\:(.+)/ ) {
 				$unmangled = $1;
 			}

			# On binary level, there can be several contructors and destructors, coming
			# from the same source level interface
			if( $processed{"$unmangled"} ) {
				next;
			}
			$processed{"$unmangled"} = 1;

 			print "    ";
 			if( $Ivirtual eq 'Yes' ) {
  				print "virtual ";
 			}
 			if( $Istatic eq 'Yes' ) {
 				print "static ";
 			}
 			$old_name = $name;
 			displaytyperef(\%int);
 			$name = $old_name;
 			print " ";
			print $unmangled.";\n";
		}
		else {
			print STDERR "Couldn't find unmangled name for Interface ".$int{'Iid'}."\n";
		}
	}

	print "}";
	return;
}

if( $$type{'Ttype'} eq "TemplateInstance" ) {
	print $$type{'Tunmangled'};
	return;
}

print "Unknown Type: \".$$type{'Ttype'}.\"\n";
}

sub
displaytyperef($)
{
local ($param) = @_;
local(%select,$sth,%type);

if( $$param{'Ttype'} eq "Intrinsic" ) {
	print $$param{'Tname'};
	return;
	}

if( $$param{'Ttype'} eq "Literal" ) {
	print $$param{'Tname'};
	return;
	}

if( $$param{'Ttype'} eq "Volatile" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
    if( $type{'Ttype'} eq "Pointer" || $type{'Ttype'} eq "Array") {
	    displaytyperef(\%type);
        print " volatile ";
	} else {
       	print "volatile ";
	    displaytyperef(\%type);
	}
    return;
 }

if( $$param{'Ttype'} eq "Const" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	if( $type{'Ttype'} eq "Pointer" || $type{'Ttype'} eq "Array") {
		displaytyperef(\%type);
		print " const ";
	} else {
		print "const ";
		displaytyperef(\%type);
	}
	return;
	}

if( $$param{'Ttype'} eq "Pointer" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	displaytyperef(\%type);
	print " *";
	return;
	}

if( $$param{'Ttype'} eq "Struct" ) {
	$struct_name = $$param{'Tunmangled'} ? $$param{'Tunmangled'} : $$param{'Tname'};

	if( $struct_name =~ /$className\:\:(.+)/ ) {
		$struct_name = $1;
	}

	print "struct ".$struct_name;
	return;
	}

if( $$param{'Ttype'} eq "Typedef" ) {
	print $$param{'Tname'};
	return;
	}

if( $$param{'Ttype'} eq "Union" ) {
	print "union ".$$param{'Tname'};
	return;
	}

if( $$param{'Ttype'} eq "Enum" ) {
	print "enum ".$$param{'Tname'};
	return;
	}

if( $$param{'Ttype'} eq "Array" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	if( !$nameonly ) {
		$nameonly=1;
		displaytyperef(\%type);
		$nameonly=0;
	} else {
		displaytyperef(\%type);
		}
#	if( $$param{'Tname'} =~ "fptr" ) {
#		$$param{'Tname'} =~ s/fptr-//;
#		}
	return;
	}

if( $$param{'Ttype'} eq "FuncPtr" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	$Tid=$$param{'Tid'};
	displaytyperef(\%type);
	print "(*";
	# commenting below code as $$param{'Tname'} is not printed/commented
#	if( $$param{'Tname'} =~ "fptr" ) {
#		$$param{'Tname'} =~ s/fptr-//;
#		}
	#print $$param{'Tname'};
	print ")";

	print "(";

	$tmselect = "SELECT * FROM TypeMember WHERE TMmemberof=$Tid AND TMaid IN (1,$TMaid) ";
	$tmselect.= "ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	if($tmh->numrows == 0) {
		print "void";
		}
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		$TMtypeid=$tmentry{'TMtypeid'};
		$tselect="SELECT * FROM Type ";
		$tselect.="LEFT JOIN ArchType ON ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid ";
		$tselect.="AND ATaid=$Aid";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$nameonly=1;
		displaytype(\%entry);
		#print $tmentry{'TMname'};
		if($entry{'Ttype'} eq 'Array') {
			if( $tmentry{'TMarray'} ) {
				print "[".$tmentry{'TMarray'}."]";
			}else{
				print "[".$entry{'ATsize'}."]";
				}
			}
		if( $_ != $tmh->numrows ) {
			print ",";
			}
		$nameonly=0;
		}

	print ")\n";
	return;
	}

if( $$param{'Ttype'} eq "Class" ) {
	$name = $$param{'Tunmangled'} ? $$param{'Tunmangled'} : $$param{'Tname'};
	print $name;
	return;
}

if( $$param{'Ttype'} eq "Ref" ) {
	$basetype = getBaseTypeID($param);
 	$sth = getBaseTypeRecord($basetype);
 	%type=$sth->fetchhash;
	displaytyperef(\%type);
	print " &";
	return;
	}


print $$param{'Ttype'};
}

sub
displayconstant($)
{
local ($const) = @_;

$selectConditions = "SELECT CAvalue FROM ConstantAttribute WHERE CAcid=".$$const{'Cid'}." AND CAtype='Condition'";
$scth = $Dbh->query($selectConditions);
for(1..$scth->numrows) {
        %scentry=$scth->fetchhash;
	print $scentry{'CAvalue'}."\n";
}

print "#define ";
print $$const{'Cname'};
print "\t";
if( $$const{'Ctype'} eq 'string' ) {
	print "\"".$$const{'ACvalue'}."\"";
} else {
	print $$const{'ACvalue'};
}
print "\t";
if( $const{'Cdescription'} ) {
	print "/* ".$const{'Cdescription'}." */\n";
	}
print "\n";

for(1..$scth->numrows) {
    print "#endif\n";
}
}

GetOptions("h=s" => \$headname,
		"v=s" => \$lsbversion,
		"a=s" => \$archname);

if( !$headname ) { usage(); }
if( !$archname ) { usage(); }
if( !$lsbversion ) { usage(); }

$headname =~ s/^\.\///;
$protect = "_".$headname."_";
$protect =~ tr/[a-z]\.\/[\-]/[A-Z]__[_]/;

$Dbh = Mysql->connect($LSBDBHOST,$LSBDB,$LSBUSER, $LSBDBPASSWD) || die $Mysql::db_errstr;

#
# Get the Architecture id
#
$select = "SELECT Aid FROM Architecture WHERE Aname='$archname'";
print $select,"\n" if $trace;
$sth = $Dbh->query($select) || die $Dbh->errmsg();

if( !$sth->numrows ) { exit 0; }
%entry=$sth->fetchhash;
$Aid=$entry{'Aid'};
$TMaid=$Aid;

#
# Get the Header id
#
$select = "SELECT Hid,Hsrconly,Hsrcerror FROM Header WHERE Hname='$headname'";
print $select,"\n" if $trace;
$sth = $Dbh->query($select) || die $Dbh->errmsg();

if( !$sth->numrows ) { exit 0; }
%entry=$sth->fetchhash;
$Hid=$entry{'Hid'};
$Hsrconly=$entry{'Hsrconly'};
$Hsrcerror=$entry{'Hsrcerror'};

sub get_typelist {
	my $sth, %entry, %type, $typelist = '';
	undef %type;
	my $Query_Hid = $_[0];

	#
	# This next section, which tries to determine all of the types for which
	# a dependency exists could probably be replaced by a loop that repeats until
	# no more new type s are added during a pass.
	#

	#
	# Get the return types
	#
	$select = "SELECT DISTINCT Ireturn FROM Interface ";
	$select.= "LEFT JOIN ArchInt ON Iid=AIint ";
	$select.= "WHERE Iheader=$Query_Hid ";
	$select.= "AND AIappearedin <= '$lsbversion' and AIappearedin<>'' ";
	$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion')  ";
	$select.= "AND AIarch=$Aid AND Isrcbin<>'BinOnly' ";
	if( $Aid!=1 ) {
		$select.= "AND Iid NOT IN ";
		$select.= "(SELECT Iid FROM Interface";
		$select.= " LEFT JOIN ArchInt ON Iid=AIint";
		$select.= " WHERE AIarch=1 ";
		$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
		$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ";
	}

	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if ($entry{'Ireturn'}) {
			$type{$entry{'Ireturn'}}=1;
			}
		}

	#
	# Get the parameter types
	#
	$select = "SELECT DISTINCT Ptype FROM Parameter, Interface ";
	$select.= "LEFT JOIN ArchInt ON Iid=AIint ";
	$select.= "WHERE Iheader=$Query_Hid ";
	$select.= "AND Pint=Iid ";
	$select.= "AND AIappearedin <= '$lsbversion' and AIappearedin<>'' ";
	$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ";
	$select.= "AND AIarch=$Aid AND Isrcbin <>'BinOnly' ";
	if( $Aid!=1 ) {
		$select.= "AND Iid NOT IN ";
		$select.= "(SELECT Iid FROM Interface";
		$select.= " LEFT JOIN ArchInt ON Iid=AIint";
		$select.= " WHERE AIarch=1 ";
		$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
		$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ";
	}

	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if ($entry{'Ptype'}) {
			$type{$entry{'Ptype'}}=1;
			}
		}

	#
	# Get any other type that is assigned to this header
	#
	$select = "SELECT Tid,Tname FROM Type ";
	$select.= "LEFT JOIN HeaderGroup ON Theadgroup=HGid ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	$select.= "WHERE HGheader=$Query_Hid ";
	$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
	$select.= "OR Tindirect='Yes' OR Tsrconly='Yes' OR Tconly='Yes' ) ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if ($entry{'Tid'}) {
			$type{$entry{'Tid'}}=1;
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Typedefs
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		$select.= "AND Ttype = 'Typedef' ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Pointers
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		$select.= "AND Ttype = 'Pointer' ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print "Pointer ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Struct/Union/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT TMtypeid,TMname FROM TypeMember ";
		$select.= "WHERE TMmemberof IN ($typelist) "; # here we should process all type members on all archs
		$select.= "AND TMtypeid NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'TMtypeid'}}=1;
			#print STDERR "TypeMember ".$entry{'TMname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Pointers found in Struct/Union/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		$select.= "AND Ttype = 'Pointer' ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print STDERR "Pointer ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Typedefs found in Struct/Union/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		$select.= "AND Ttype = 'Typedef' ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print "Typedef ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);


	#
	# Get the base types of type we have picked up in the Struct/Union/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print STDERR "Type ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);
	#
	# Do this once more to get nested Struct/Unions/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT TMtypeid,TMname FROM TypeMember ";
		$select.= "WHERE TMmemberof IN ($typelist)";
		$select.= "AND TMtypeid NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'TMtypeid'}}=1;
			#print STDERR "TypeMember ".$entry{'TMname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of type we have picked up in the Struct/Union/Fptr members
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print STDERR "Type2 ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print STDERR "Type3 ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	#
	# Get the base types of Const
	#

	if( $typelist ne "" ) {
		$select = "SELECT ATbasetype,Tname FROM Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Tid IN ($typelist) ";
		$select.= "AND Ttype = 'Const' ";
		$select.= "AND ATbasetype NOT IN ($typelist) ";
		print $select,"\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();
		for(1..$sth->numrows) {
			%entry=$sth->fetchhash;
			$type{$entry{'ATbasetype'}}=1;
			#print "Pointer ".$entry{'Tname'}."\n";
			}
		}

	$typelist=join ',', keys(%type);

	return $typelist;
}

$typelist = get_typelist($Hid);

# Get Class list

$select = "SELECT * FROM Type ";
$select.= "LEFT JOIN ArchType ON Tid=ATtid ";
$select.= "LEFT JOIN HeaderGroup ON Theadgroup=HGid ";
$select.= "WHERE HGheader=$Hid ";
$select.= "AND (Ttype='Class' ";
$select.= "OR (Ttype='Struct' AND Tclass<>0 AND Tunmangled NOT LIKE '%::%') ) ";
$select.= "AND ( ( ATappearedin <> '' AND ATappearedin <='$lsbversion' ";
$select.= "  AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ";
$select.= " ) OR Tsrconly='Yes' ) ";
print $select,"\n" if $trace;
$sth = $Dbh->query($select) || die $Dbh->errmsg();
for(1..$sth->numrows) {
	%entry=$sth->fetchhash;
	if( $entry{'Tid'} ) {
		$class{$entry{'Tid'}}=1;
	}
}
$classlist=join ',', keys(%class);

if( $classlist ne "" ) {
	$select = "SELECT TMtypeid FROM TypeMember ";
	$select.= "WHERE TMmemberof in ($classlist)";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if( $entry{'TMtypeid'} ) {
			$class_member{$entry{'TMtypeid'}}=1;
		}
	}
	$typelist=join ',', keys(%class_member);
}

# Get Constant list

$select = "SELECT * FROM Constant ";
$select.= "LEFT JOIN ArchConst ON Cid=ACcid ";
$select.= "LEFT JOIN HeaderGroup ON Cheadgroup=HGid ";
$select.= "WHERE HGheader=$Hid ";
$select.= "AND Ctype='header_depend' ";
$select.= "AND ( ( ACappearedin <> '' AND ACappearedin <='$lsbversion' ";
$select.= "  AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
$select.= " ) OR Csrconly='Yes' ) ";
print $select,"\n" if $trace;
$sth = $Dbh->query($select) || die $Dbh->errmsg();
for(1..$sth->numrows) {
	%entry=$sth->fetchhash;
	$header{$entry{'ACvalue'}}=1;
}
$constlist=join '\',\'', keys(%const);


#
# Set up multiple inclusion protection
#
print "#ifndef $protect\n";
print "#define $protect\n";
print "\n";

#
# Get the headers containing referenced types
#

if( $typelist ne "" ) {
	$select = "SELECT DISTINCT Hid FROM Type ";
	$select.= "LEFT JOIN HeaderGroup ON HGid=Theadgroup ";
	$select.= "LEFT JOIN Header ON Hid=HGheader ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
 	$select.= "OR Tindirect='Yes' OR Tsrconly='Yes' OR Tconly='Yes' )";
	$select.= "AND Hid != $Hid ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		$header{$entry{'Hid'}}=1;
		}
	}

#
# Get the headers referenced by 'header_depend' constants values
#

if( $constlist ne "" ) {
	$select = "SELECT DISTINCT Hid FROM Constant ";
	$select.= "LEFT JOIN HeaderGroup ON HGid=Cheadgroup ";
	$select.= "LEFT JOIN Header ON Hid=HGheader ";
	$select.= "LEFT JOIN ArchConst ON ACcid=Cid ";
	$select.= "WHERE Hid IN (\'$constlist\') ";
	$select.= "AND ( ( ACappearedin <> '' AND ACappearedin <='$lsbversion' ";
	$select.= "  AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
	$select.= " ) OR Csrconly='Yes' ) ";
	$select.= "AND Hid != $Hid ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		$header{$entry{'Hid'}}=1;
	}
}

$hdrlist=join ',', keys(%header);

#
# Output the headers this header needs to include
#
if( $hdrlist ne "" ) {
	$select = "SELECT DISTINCT Hname, Hid FROM Header ";
	$select.= "WHERE Hid IN ($hdrlist) ";
	$select.= "AND Hid != $Hid ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if( $entry{'Hname'} ) {
# 			print "#include <".$entry{'Hname'}.">\n";
			my $header_name = $entry{'Hname'};

			#
			# determine if this header depends on
			# any types we are about to declare in this
			# header.
			#
			$header_typelist = get_typelist($entry{'Hid'});
			if ($header_typelist) {
				$select = "SELECT DISTINCT Tid FROM Type ";
				$select.= "LEFT JOIN HeaderGroup ON HGid=Theadgroup ";
				$select.= "LEFT JOIN Header ON Hid=HGheader ";
				$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
				$select.= "WHERE Tid IN ($header_typelist) ";
				$select.= "AND ( (ATappearedin <> '' AND ATappearedin <= '$lsbversion' ";
				$select.= " AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion' ) )";
				$select.= "OR Tsrconly='Yes' ) ";
				$select.= "AND Hid = $Hid ";
				print $select,"\n" if $trace;
				$sth2 = $Dbh->query($select) || die $Dbh->errmsg();
				if ($sth2->numrows) {
					for(1..$sth2->numrows) {

						%header_entry=$sth2->fetchhash;
						my $tid = $header_entry{'Tid'};

						$$header_name{$tid} = 1;
						$$tid{$header_name} = 1;
					}
				} else {
					print "#include <".$header_name.">\n";
				}
			} else {
				print "#include <".$header_name.">\n";
			}

		}
	}
}

if( $classlist ne "" ) {
	$select = "SELECT Tname,Tunmangled,Ttype FROM Type ";
	$select.= "WHERE Tid IN (\'$classlist\') ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		$name = $entry{'Tunmangled'} ? $entry{'Tunmangled'} : $entry{'Tname'};
		$type = ( $entry{'Ttype'} eq 'Class' ) ? "class" : "struct";
		print "$type $name;\n";
	}
}

if( !$classlist ) {
	print "\n#ifdef __cplusplus\n";
	print "extern \"C\" {\n";
	print "#endif\n\n";
}
else {
	print "// *INDENT-OFF*\n";
}

if( $Hsrcerror eq 'Yes' ) {
	print "#error \"This header not permitted by the LSB\"\n\n";
}

# dump AbiApi records
$select = "SELECT AAvalue FROM AbiApi ";
$select.= "LEFT JOIN Interface ON Iid=AAbinint ";
$select.= "WHERE Iheader=$Hid";
print $select,"\n" if $trace;
my $sth = $Dbh->query($select) || die $Dbh->errmsg();
print "\n";
for( 1..$sth->numrows ) {
    my %aavalue=$sth->fetchhash;
    print $aavalue{'AAvalue'}."\n";
}
if( $sth->numrows ) {
    print "\n";
}

#
# Get the info from the types in the $type hash
#
# Use the algorithm from admin/headers.php3

$select = "SELECT HGid,HGdescription,HGorder FROM HeaderGroup ";
$select.= "WHERE HGheader=$Hid ";
$select.= "ORDER BY HGorder";
print $select,"\n" if $trace;
$hgh = $Dbh->query($select) || die $Dbh->errmsg();
for(1..$hgh->numrows) {
	%entry=$hgh->fetchhash;
	$HGid=$entry{'HGid'};
	$HGdesc=$entry{'HGdescription'};
	$HGorder=$entry{'HGorder'};
	# Make sure a blank line is present between every group
	print "\n";

	# Since it's a header, document it
	if( $HGorder != 0 && $HGdesc ne "" ) {
		print "/* ".$HGdesc."*/\n";
		}

	# Display the Constants
	#
	# Display the Constants excluding the generated header
	# dependency constants
	#
	$select = "SELECT * FROM Constant ";
	$select.= "LEFT JOIN ArchConst ON Cid=ACcid ";
	$select.= "LEFT JOIN Architecture ON Aid=ACaid ";
	$select.= "WHERE Cheadgroup=$HGid ";
	$select.= "AND ( (ACappearedin is not NULL and ACappearedin <= '$lsbversion' and ACappearedin<>'') ";
	$select.= "AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
 	$select.= "OR Csrconly ='Yes' )";
 	$select.= "AND Ctype != 'header_depend'";
	$select.=" ORDER BY ACvalue, Cname, Aid";
	$ch = $Dbh->query($select) || die $Dbh->errmsg();
	print $ch->numrows," rows\n" if $trace;
	for(1..$ch->numrows) {
		%centry=$ch->fetchhash;
		# If it's architecture sensitive, add the #if's to
		# make it work correctly.
		if( $centry{'Aid'} && $centry{'Aname'} ne "All" ) {
			print "#if ".$centry{'Asymbol'}."\n";
			#print "/* ".$centry{'Aname'}." */\n";
			displayconstant(\%centry);
			print "#endif\n";
		} else {
			displayconstant(\%centry);
		}
	}
	print "\n\n";

	%processedNames;

	# Display the Type (Typedef)
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	$select.= "LEFT JOIN Architecture ON ATaid=Aid ";
	$select.= "WHERE Theadgroup=$HGid ";
	$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
 	$select.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
	$select.= "AND Ttype = 'Typedef' ";
	$select.= "AND Tclass = 0 ";
#  	$select.= "AND Aid = $Aid ";
	$select.= "ORDER BY Tid";
	print $select,"\n" if $trace;
	$th = $Dbh->query($select) || die $Dbh->errmsg();
	print $th->numrows," rows\n" if $trace;
	for(1..$th->numrows) {
		$typeflag=0;
		%tentry=$th->fetchhash;

# 		if( $tentry{'Aname'} eq "All" ) {
# 			$selectArchSpec = "SELECT * FROM Type ";
# 			$selectArchSpec.= "LEFT JOIN ArchType ON ATtid=Tid ";
# 			$selectArchSpec.= "WHERE Tid = ".$tentry{'Tid'};
# 			$selectArchSpec.= " AND ATaid <> 1 ";
# 			print $selectArchSpec,"\n" if $trace;
# 			$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
# 			if( $thArchSpec->numrows ) {
# 				# Arch specific records present - skip generic record
# 				next;
# 			}
# 		}

  		if( not $tentry{'Aname'} ) {
  			next; # Found unsupported architecture
  		}

		if( $tentry{'Aname'} ne "All" ) {
			$selectArchSpec = "SELECT * FROM ArchType ";
			$selectArchSpec.= "LEFT JOIN Type ON Tid=ATtid ";
			$selectArchSpec.= "WHERE ATtid = ".$tentry{'Tid'};
			$selectArchSpec.= " AND ATaid = 1 ";
			$selectArchSpec.= "AND ( (ATappearedin <= '$lsbversion' and ATappearedin<>'' ";
			$selectArchSpec.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
		 	$selectArchSpec.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
			print $selectArchSpec,"\n" if $trace;
			$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
			if( $thArchSpec->numrows ) {
				# Generic records present - skip arch specific
				next;
			}
		}

		if( $tentry{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }

		$TMaid = $tentry{'Aid'} ? $tentry{'Aid'} : $Aid;
		if( $tentry{'Tconly'} eq "Yes" ) {
			print "#if !defined(__cplusplus)\n";
		}
		if( $tentry{'Aid'} && $tentry{'Aname'} ne "All" ) {
			print "#if ".$tentry{'Asymbol'}."\n";
			print "/* ".$tentry{'Aname'}." */\n";
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
			print "#endif\n";
		} else {
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
		}
		if( $tentry{'Tconly'} eq "Yes" ) {
			print "#endif\n";
		}

		# Display headers now that we've declared their
		# dependant types.
		foreach $header_name (keys %{$tentry{'Tid'}}) {
			if (1 == scalar (keys %$header_name)) {
				print "#include <" . $header_name . ">\n";
			}
			delete $$header_name{$tentry{'Tid'}};
		}
	}

	# Display the Types (excluding Typedef)
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	$select.= "LEFT JOIN Architecture ON ATaid=Aid ";
	$select.= "WHERE Theadgroup=$HGid ";
	$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
 	$select.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
	$select.= "AND Ttype != 'Typedef' ";
	$select.= "AND (Tclass=0 OR Ttype='Struct' OR Ttype='Class') ";
#  	$select.= "AND Aid = $Aid ";
	$select.= "ORDER BY Tid";
	print $select,"\n" if $trace;
	$th = $Dbh->query($select) || die $Dbh->errmsg();
	print $th->numrows," rows\n" if $trace;
	for(1..$th->numrows) {
		$typeflag=0;
		%tentry=$th->fetchhash;

# 		if( $tentry{'Aname'} eq "All" ) {
# 			$selectArchSpec = "SELECT * FROM Type ";
# 			$selectArchSpec.= "LEFT JOIN ArchType ON ATtid=Tid ";
# 			$selectArchSpec.= "WHERE Tid = ".$tentry{'Tid'};
# 			$selectArchSpec.= " AND ATaid <> 1 ";
# 			print $selectArchSpec,"\n" if $trace;
# 			$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
# 			if( $thArchSpec->numrows ) {
# 				# Arch specific records present - skip generic record
# 				next;
# 			}
# 		}
		if( $tentry{'Aname'} ne "All" ) {
			$selectArchSpec = "SELECT * FROM Type ";
			$selectArchSpec.= "LEFT JOIN ArchType ON ATtid=Tid ";
			$selectArchSpec.= "WHERE Tid = ".$tentry{'Tid'};
			$selectArchSpec.= " AND ATaid = 1 ";
			$selectArchSpec.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
			$selectArchSpec.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
 			$selectArchSpec.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes'  ) ";
			print $selectArchSpec,"\n" if $trace;
			$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
			if( $thArchSpec->numrows ) {
				# Generic records present - skip arch specific
				next;
			}
		}

		if( $tentry{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }

		$TMaid = $tentry{'Aid'} ? $tentry{'Aid'} : $Aid;

		if( $tentry{'Tconly'} eq "Yes" ) {
			print "#if !defined(__cplusplus)\n";
			}
		if( $tentry{'Aid'} && $tentry{'Aname'} ne "All" ) {
			print "#if ".$tentry{'Asymbol'}."\n";
			print "/* ".$tentry{'Aname'}." */\n";
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
			print "#endif\n";
		} else {
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tdescription'}."\n\n";
			}
		if( $tentry{'Tconly'} eq "Yes" ) {
			print "#endif\n";
			}

 		$processedNames{$tentry{'Tid'},$Aid} = 1;

		# Display headers now that we've declared their
		# dependant types.
		foreach $header_name (keys %{$tentry{'Tid'}}) {
			if (1 == scalar (keys %$header_name)) {
				print "#include <" . $header_name . ">\n";
			}
			delete $$header_name{$tentry{'Tid'}};
		}
		}

		# Display the Types (Struct/Union)
		$select = "SELECT * FROM Type ";
	    $select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "LEFT JOIN Architecture ON ATaid=Aid ";
	    $select.= "WHERE Theadgroup=$HGid ";
		$select.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
		$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
		$select.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
	    $select.= "ORDER BY Tid";
	    print $select,"\n" if $trace;

		$th = $Dbh->query($select) || die $Dbh->errmsg();
	    print $th->numrows," rows\n" if $trace;
	    for(1..$th->numrows) {
	        $typeflag=1;
	        %tentry=$th->fetchhash;

# 			if( $tentry{'Aname'} eq "All" ) {
# 				$selectArchSpec = "SELECT * FROM Type ";
# 				$selectArchSpec.= "LEFT JOIN ArchType ON ATtid=Tid ";
# 				$selectArchSpec.= "WHERE Tid = ".$tentry{'Tid'};
# 				$selectArchSpec.= " AND ATaid <> 1 ";
# 				print $selectArchSpec,"\n" if $trace;
# 				$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
# 				if( $thArchSpec->numrows ) {
# 					# Arch specific records present - skip generic record
# 					next;
# 				}
# 			}
			if( $tentry{'Aname'} ne "All" ) {
				$selectArchSpec = "SELECT * FROM Type ";
				$selectArchSpec.= "LEFT JOIN ArchType ON ATtid=Tid ";
				$selectArchSpec.= "WHERE Tid = ".$tentry{'Tid'};
# 		    	$selectArchSpec.= "AND Theadgroup=$HGid ";
				$selectArchSpec.= " AND ATaid = 1 ";
				$selectArchSpec.= "AND ( ( (ATappearedin <= '$lsbversion' and ATappearedin<>'') ";
				$selectArchSpec.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
				$selectArchSpec.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes'  ) ";
				print $selectArchSpec,"\n" if $trace;
				$thArchSpec = $Dbh->query($selectArchSpec) || die $Dbh->errmsg();
 				if( $thArchSpec->numrows ) {
					# Generic records present - skip arch specific
 					next;
 				}
			}

			if( $tentry{'Ttype'} eq "Typedef" ){
				$OldAid = $Aid;
				# Check if generic record for the basetype presents
				$selectGeneric = "SELECT * FROM ArchType ";
				$selectGeneric.= "LEFT JOIN Type ON Tid=ATtid ";
				$selectGeneric.= "WHERE ATtid=".$tentry{'ATbasetype'}." ";
				$selectGeneric.= "AND ATaid=1 ";
				$selectGeneric.= "AND ( ( ATappearedin <= '$lsbversion' and ATappearedin<>'' ";
				$selectGeneric.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ) ";
			 	$selectGeneric.= "OR Tsrconly = 'Yes' OR Tconly = 'Yes' ) ";
	            $genth= $Dbh->query($selectGeneric) || die $Dbh->errmsg();
	            # if this is the case, we need only generic record in header
	            if( $genth->numrows ) {
	            	$Aid=1;
	            }
	            else {
					$Aid = $tentry{'Aid'};
	            }

				# Maybe the necessary basetype has already been processed?
				if( $processedNames{$tentry{'ATbasetype'},$Aid} ) {
					next;
				}

				$processedNames{$tentry{'ATbasetype'},$Aid} = 1;

	            $tselect = "SELECT * FROM Type ";
	            $tselect.= "WHERE Tid=".$tentry{'ATbasetype'};
	            $tselect.= " AND ( Ttype='Struct' OR Ttype='Union' )";

	            $tth= $Dbh->query($tselect) || die $Dbh->errmsg();
 	            if($tth->numrows) {
	                %ttentry=$tth->fetchhash;
	                if($ttentry{Tname} =~ "anon"){ next;}
	                if( $tentry{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }

					$TMaid = $tentry{'Aid'} ? $tentry{'Aid'} : $Aid;

	                if( $tentry{'Tconly'} eq "Yes" ) {
	                    print "#if !defined(__cplusplus)\n";
					}
	                if( $tentry{'Aid'} && $tentry{'Aname'} ne "All" ) {
	                    print "#if ".$tentry{'Asymbol'}."\n";
	                    print "/* ".$tentry{'Aname'}." */\n";
	                    displaytype(\%tentry);
						if ($semicolonNeeded) {
							$semicolonNeeded = 0;
							print ";";
						}
					    print $tentry{'Tdescription'}."\n\n";
	                    print "#endif\n";
			        } else {
						displaytype(\%tentry);
						if ($semicolonNeeded) {
							$semicolonNeeded = 0;
							print ";";
						}
						print $tentry{'Tdescription'}."\n\n";
					}
				    if( $tentry{'Tconly'} eq "Yes" ) {
				         print "#endif\n";
					}
				}
				$Aid = $OldAid;
	        }

			# Display headers now that we've declared their
			# dependant types.
			foreach $header_name (keys %{$tentry{'Tid'}}) {
				if (1 == scalar (keys %$header_name)) {
					print "#include <" . $header_name . ">\n";
				}
				delete $$header_name{$tentry{'Tid'}};
			}
	        $typeflag=0;
		}
	}

#
# Dump out the function prototypes
#

print "\n";
$select = "SELECT * FROM Interface ";
$select.= "LEFT JOIN Header ON Iheader=Hid ";
$select.= "LEFT JOIN Type ON Ireturn=Tid ";
$select.= "LEFT JOIN ArchInt ON Iid=AIint ";
$select.= "LEFT JOIN ArchType ON ATtid=Tid AND ATaid=AIarch ";
# $select.= "LEFT JOIN ArchType ON ATtid=Tid ";
$select.= "LEFT JOIN Architecture ON AIarch=Aid ";
$select.= "WHERE ";
$select.= "Iid NOT IN ( SELECT AAsrcint FROM AbiApi ) ";
$select.= "AND (Isrcbin='SrcOnly' ";
$select.= " OR ( (Isrcbin='Both' OR Iid IN (SELECT AAbinint FROM AbiApi)) AND ";
$select.= " (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
$select.= " AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ";
$select.= ") ";
$select.= "AND Iclass=0 ";
#$select.= "AND Iarch=$Aid ";
# $select.= "AND (ATaid=AIarch OR ATaid=1)";
$select.= "AND Hname=".$Dbh->quote($headname)." ";
print $select,"\n" if $trace;
$sth = $Dbh->query($select) || die $Dbh->errmsg();

for(1..$sth->numrows) {
	%entry=$sth->fetchhash;

	if( $entry{'Aid'} != 1 ) {
		$selectGeneric = "SELECT Iid FROM Interface ";
		$selectGeneric.= "LEFT JOIN ArchInt ON Iid=AIint ";
		$selectGeneric.= "WHERE AIarch=1 AND Iname='$entry{'Iname'}'";
		$selectGeneric.= "AND Iid NOT IN (SELECT AAsrcint FROM AbiApi) AND (Isrcbin='SrcOnly' ";
		$selectGeneric.= "OR ( (Isrcbin='Both' OR Iid IN (SELECT AAbinint FROM AbiApi)) AND ";
		$selectGeneric.= "(AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
		$selectGeneric.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ) ";
		$sthGeneric = $Dbh->query($selectGeneric) || die $Dbh->errmsg();
		if( $sthGeneric->numrows ) {
			next;
		}
	}

	if( $entry{'Itype'} eq "Function" ) {
		if( $entry{'Ttype'} eq 'FuncPtr' ) {
			print STDERR "Skipping a global function pointer!!\n";
			next;
			}

		$TMaid = $tentry{'Aid'} ? $tentry{'Aid'} : $Aid;

		if( $entry{'Aid'} && $entry{'Aname'} ne "All" ) {
			print "#if ".$entry{'Asymbol'}."\n";
			print "/* ".$entry{'Aname'}." */\n";
		}
		printf "extern ";
		displaytyperef(\%entry);
		printf " %s(",$entry{'Iname'};
		$select = "SELECT Tid,Tname,Ttype,ATbasetype,Parsize FROM Parameter,Type ";
		$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
		$select.= "WHERE Pint=".$entry{'Iid'}." AND Ptype=Tid ";
		$select.= "GROUP BY Ppos ORDER BY Ppos";
		print $select,"\n" if $trace;
		$sth2 = $Dbh->query($select) || die $Dbh->errmsg();
		if( $sth2->numrows != 0 ) {
			%entry2=$sth2->fetchhash;
			displaytyperef(\%entry2);
			if( $entry2{'Ttype'} eq "Array" ) {
				print "[";
				if( $entry2{'Parsize'} != 0 ) {
					print $entry2{'Parsize'};
					}
				print "]";
			}
			for(2..$sth2->numrows) {
				%entry2=$sth2->fetchhash;
				print ", ";
				displaytyperef(\%entry2);
				if( $entry2{'Ttype'} eq "Array" ) {
					print "[";
					if( $entry2{'Parsize'} != 0 ) {
						print $entry2{'Parsize'};
						}
					print "]";
				}
			}
		} else {
			print "void";
		}
		printf ");\n";
		if( $entry{'Aid'} && $entry{'Aname'} ne "All" ) {
			print "#endif\n";
		}
	}
	if( $entry{'Itype'} eq "Data" ) {
		printf "extern ";
		displaytyperef(\%entry);
		printf " %s",$entry{'Iname'};
		if( $entry{'Ttype'} eq "Array" ) {
			print "[";
			if( $entry{'ATsize'} != 0 ) {
				print $entry{'ATsize'};
				}
			print "]";
		}
		if( $entry{'Ttype'} eq "Const" || $entry{'Ttype'} eq "Volatile") {
			if( $entry{'ATbasetype'} != '' ) {
				$basetype = $entry{'ATbasetype'};
			}
			else {
				$selectBase = "SELECT ATbasetype FROM ArchType ";
				$selectBase.= "WHERE ATtid=".$entry{'Tid'}." ";
				$selectBase.= "GROUP BY ATbasetype";
				$sthBase = $Dbh->query($selectBase) || die $Dbh->errmsg();
				if($sthBase->numrows > 1) {
					die "Couldn't determine basetype for type ".$entry{'Tid'}." on $Aid architecture";
				}

				%base=$sthBase->fetchhash;
				$basetype = $base{'ATbasetype'};
			}

            $select = "SELECT * FROM Type ";
            $select.= "LEFT JOIN ArchType ON ATtid=Tid ";
	        $select.= "LEFT JOIN Architecture ON Aid=ATaid ";
 	        $select.= "WHERE Tid=".$basetype." ";
			$select.= "AND ATaid=$Aid";
	        print $select,"\n" if $trace;
	        my $stm = $Dbh->query($select) || die $Dbh->errmsg();
            my %btype=$stm->fetchhash;
            if( $btype{'Ttype'} eq "Array" ) {
				print "[";
				if( $btype{'ATsize'} != 0 ) {
					print $btype{'ATsize'};
				}
				print "]";
			}
		}

		printf " ;\n";
	}
	if( $entry{'Itype'} eq "Alias" ) {
		printf "extern ";
		displaytyperef(\%entry);
		printf " %s",$entry{'Iname'};
		if( $entry{'Ttype'} eq "Array" ) {
			print "[";
			if( $entry{'ATsize'} != 0 ) {
				print $entry{'ATsize'};
				}
			print "]";
		}
		printf " ;\n";
	}
	if( $entry{'Itype'} eq "Common" ) {
		printf "extern ";
		displaytyperef(\%entry);
		printf " %s",$entry{'Iname'};
		if( $entry{'Ttype'} eq "Array" ) {
			print "[";
			if( $entry{'ATsize'} != 0 ) {
				print $entry{'ATsize'};
				}
			print "]";
		}
		printf " ;\n";
	}
}

if( !$classlist ) {
	print "#ifdef __cplusplus\n";
	print "}\n";
	print "#endif\n";
}
else {
	print "// *INDENT-ON*\n";
}
print "#endif\n";
