#!/usr/bin/perl

use Getopt::Long;
use Mysql;

use Env qw(LSBUSER LSBDBPASSWD LSBDB LSBDBHOST);

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

$funcptrname="";

sub
usage()
{
die "mkdatadef -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 is two records here only first 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 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,$nameonly) = @_;
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'}."\t";
	return;
	}

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

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

if( $$type{'Ttype'} eq "Typedef" ) {
	if( $nameonly ) {
		print $$type{'Tname'}."\t";
		return;
	}
	else {
		print "typedef ";
		$basetype = getBaseTypeID($type);
		$tth = getBaseTypeRecord($basetype);
		%entry=$tth->fetchhash;
	# Something about anon or not & wether to set nameonly
		if( ( $entry{'Ttype'} eq 'Typedef' ||
			$entry{'Ttype'} eq 'Function' ||
			$entry{'Ttype'} eq 'FuncPtr' ) ||
 			$entry{'Theadgroup'} != $HGid	) {
			if($entry{'Ttype'} eq 'FuncPtr' ||
				$entry{'Ttype'} eq 'Function'){
				$funcPtrName=$$type{'Tname'};
			}
			$nameonly = 1;
			displaytype(\%entry,1);
			$nameonly = 0;
		} else {
			displaytype(\%entry,$nameonly);
		}
		if( ($entry{'Ttype'} ne 'FuncPtr' &&
			$entry{'Ttype'} ne 'Function') ) {
			print $$type{'Tname'}."\t";
		}
		if( $entry{'Ttype'} eq 'Array' ) {
			my $bound = $entry{'TMarray'};
			$bound ||= $entry{'ATsize'};
			print "[".$bound."]";
		}
		if( !$nameonly && $$type{'ATattribute'} ) {
			print "__attribute__ (".$$type{'ATattribute'}.")";
		}
		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' ) {
			displaytype(\%entry,1);
		}else {
			if (($entry{'Ttype'} eq 'Struct' || $entry{'Ttype'} eq 'Union') ) {
				displaytype(\%entry,1);
			} else {
				displaytype(\%entry,0);
			}
		}
	} else {
		displaytype(\%entry,1);
	}

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

if( $$type{'Ttype'} eq "Struct" ) {
	print "struct ";

	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}
	print $$type{'Tname'}."\t";
	$Tid=$$type{'Tid'};
	if( $nameonly ) { return; }
	#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 ) { print "{\n"; }
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		$TMtypeid=$tmentry{'TMtypeid'};
		$tselect  = "SELECT * FROM Type ";
		$tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
#		$tselect .= "LEFT JOIN ArchType ON ATaid=Tarch AND ATtid=Tid ";
		# $tselect.= "LEFT JOIN TypeMember ON TMtypeid=Tid ";
		$tselect .= "WHERE Tid=$TMtypeid ";
# 		$tselect.= "AND ATaid=$Aid";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$funcPtrName=$tmentry{'TMname'};
		displaytype(\%entry,1);
		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'}";
				$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";
		# $nameonly=0;
		}
	if ($tmh->numrows ) { print "}"; }
	if( $$type{'ATattribute'} ) {
		print "__attribute__ (".$$type{'ATattribute'}.")";
		}
	if ($tmh->numrows ) { print "\n"; }
	return;
	}

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

	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}
	print $$type{'Tname'}."\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 ) { 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 ";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		$funcPtrName=$tmentry{'TMname'};
		displaytype(\%entry,1);
		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
				$basetype = getBaseTypeID($type);
		 		$tth = getBaseTypeRecord($basetype);
				%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";
		# $nameonly=0;
		}
	if ($tmh->numrows ) { print "}\n"; }
	return;
	}

if( $$type{'Ttype'} eq "Enum" ) {
	print "enum ";
	$Tid=$$type{'Tid'};
	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		}
	print $$type{'Tname'}."\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"; }
	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'};
		if( $tmentry{'TMvalue'} ne '' ) {
			print " = ".$tmentry{'TMvalue'};
			}
		if( $_ != $tmh->numrows ) {
			print ",\n";
			}
		#print $tmentry{'TMdescription'}."\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);
 	$tth = getBaseTypeRecord($basetype);
	%entry=$tth->fetchhash;
	displaytype(\%entry,1);
	print "(*" if ($$type{'Ttype'} eq "FuncPtr");
	$Tid=$$type{'Tid'};
	print $funcPtrName;
	print ") " if( $$type{'Ttype'} eq "FuncPtr" && $$type{'Itype'} ne "Function" );
	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.= "LEFT JOIN TypeMember ON TMtypeid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid AND TMaid IN (1,$TMaid) ";
		$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		%entry=$th->fetchhash;
		displaytype(\%entry,1);
		print $tmentry{'TMname'};
		if( $tmentry{'Ttype'} eq 'Array' ) {
			if($tmentry{'TMarray'}){
                            print "[".$tmentry{'TMarray'}."]";
			}else {
			# check the basetype of this array
				$basetype = getBaseTypeID($type);
				$tth = getBaseTypeRecord($basetype);
				%bentry=$tth->fetchhash;
				if ($bentry{'Ttype'} eq 'Array') {
					print "[".$bentry{'ATsize'}."]"."[".$entry{'ATsize'}."]";
				} else {
					print "[".$entry{'ATsize'}."]";
				}
			}
		}
		if( $_ != $tmh->numrows ) {
			print ",";
			}
		}
	print ") " if( $$type{'Ttype'} eq "FuncPtr" && $$type{'Itype'} eq "Function" );
	print ")\n";
	return;
	}

if( $$type{'Ttype'} eq "Array" ) {
	$basetype = getBaseTypeID($type);
 	$tth = getBaseTypeRecord($basetype);
	%entry=$tth->fetchhash;
	displaytype(\%entry,1);
#	if( $$type{'Tname'} =~ "fptr" ) {
#		$$type{'Tname'} =~ s/fptr-//;
#		}
	#print $$type{'Tname'};
	#print "[".$$type{'Tsize'}."]";
	return;
	}

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

# print "Unknown Type: \"$$type{'Ttype'}\"\n";
print STDERR "Unknown Type: \"$$type{'Ttype'}\" for Tid $$type{'Tid'}\n";
exit 2;
}

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 "\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/^\.\///;

$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 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'};

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

#
# Get the parameter types
#
$select = "SELECT Ptype FROM Parameter, Interface ";
$select.= "LEFT JOIN ArchInt ON AIint=Iid ";
$select.= "WHERE Iheader=$Hid AND Isrcbin<>'BinOnly' ";
$select.= "AND Pint=Iid ";
#$select.= "WHERE Pint=Iid ";
$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ";
#$select.= "AND Iarch=$Aid";
$select.= "AND AIarch=$Aid ";
if( $Aid!=1 ) {
	$select.= "AND Iid NOT IN ";
	$select.= "(SELECT DISTINCT AIint FROM ArchInt";
	$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;
	$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=$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;
	$type{$entry{'Tid'}}=1;
	#print "Type ".$entry{'Tname'}."\n";
	}

$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 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 Ttype = 'Pointer' ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		if( $entry{'ATbasetype'} ) {
			$type{$entry{'ATbasetype'}}=1;
		}
		else {
			print STDERR "Couldn't detect base type for '".$entry{'Tname'}."'\n";
		}
		#print "Pointer ".$entry{'Tname'}."\n";
		}
	}

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

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

if( $typelist ne "" ) {
	$select = "SELECT TMtypeid,TMname FROM TypeMember ";
	$select.= "WHERE TMmemberof 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 "TypeMember ".$entry{'TMname'}."\n";
		}
	}

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

# dump AbiApi records
$select = "SELECT AAvalue FROM AbiApi ";
$select.= "LEFT JOIN Interface ON Iid=AAbinint ";
$select.= "LEFT JOIN ArchInt ON Iid=AIint ";
$select.= "WHERE Iheader=$Hid ";
$select.= "AND AIarch=$Aid ";
$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ";
if( $Aid != 1 ) {
    $select.= "AND Iid NOT IN ( ";
    $select.= " SELECT AIint FROM ArchInt ";
    $select.= " WHERE AIarch=1 AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
    $select.= " AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion')";
    $select.= ")";
}
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();
print $hgh->numrows," rows\n" if $trace;
$totrows = 0;
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";

	# Display the Constants
	$select = "SELECT * FROM Constant ";
	$select.= "LEFT JOIN ArchConst ON Cid=ACcid ";
	$select.= "WHERE Cheadgroup=$HGid ";
	$select.= "AND ACaid=$Aid ";
	$select.= "AND (ACappearedin is not NULL and ACappearedin <= '$lsbversion' and ACappearedin<>'') ";
	$select.= "AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
 	$select.= "AND Ctype<>'header_depend' ";
	$select.=" ORDER BY ACvalue, Cname, ACaid";
	$ch = $Dbh->query($select) || die $Dbh->errmsg();
	print $ch->numrows," rows\n" if $trace;
	for(1..$ch->numrows) {
		%centry=$ch->fetchhash;
		displayconstant(\%centry);
		$totrows++;
		}
	print "\n\n";

	# Display the Types
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN ArchType ON ATtid=Tid ";
 	$select.= "LEFT JOIN TypeMember ON TMmemberof=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.= "AND Aid=$Aid ";
 	$select.= "AND (TMaid IS NULL OR TMaid=$Aid) ";
	if( $Aid!=1 ) {
		$select.= "AND Tid NOT IN ";
		$select.= " (SELECT DISTINCT ATtid FROM ArchType ";
 		$select.= " LEFT JOIN TypeMember ON TMmemberof=ATtid ";
		$select.= " WHERE ATaid=1 ";
		$select.= " AND ATappearedin <='$lsbversion' AND ATappearedin <> '' ";
		$select.= " AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ";
  		$select.= " AND (TMaid IS NULL OR TMaid=1) )";
	}
	# Skip structs which are basetypes for included typedefs from this header group
	$select.= "AND (Ttype <> 'Struct' OR Tid NOT IN ";
	$select.= " (SELECT DISTINCT ATbasetype FROM ArchType ";
	$select.= " LEFT JOIN Type ON Tid=ATtid ";
	$select.= " LEFT JOIN HeaderGroup ON Theadgroup=HGid ";
	$select.= " WHERE ATaid=$Aid AND HGid=$HGid AND Ttype='typedef' ";
	$select.= " AND ATappearedin <='$lsbversion' AND ATappearedin <> '' ";
	$select.= " AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) )";
	$select.= "GROUP BY Tid,ATaid ";
	$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) {
		%tentry=$th->fetchhash;
		if( $tentry{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }
		displaytype(\%tentry,0);
		print ";\n";
		$totrows++;
		#print $tentry{'Tdescription'}."\n\n";
		}
	}
#
# now dump out the function prototypes --- see bug 1089
# while it is questionable if these are really part of "Data Definitions",
# it can be argued that they are, and that including them increases
# readability ...
#
$select  = "SELECT * FROM Interface ";
$select .= "LEFT JOIN Type on Ireturn = Tid ";
$select .= "LEFT JOIN ArchInt ON Iid=AIint ";
$select .= "WHERE Iheader = $Hid AND (Isrcbin<>'BinOnly' OR Iid IN (SELECT AAbinint FROM AbiApi))";
$select .= "AND Iid NOT IN (SELECT AAsrcint FROM AbiApi) ";
$select .= "AND AIarch=$Aid ";
$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ";
if( $Aid!=1 ) {
	$select.= "AND Iid NOT IN ";
	$select.= "(SELECT DISTINCT AIint FROM ArchInt";
	$select.= " WHERE AIarch=1 ";
	$select.= "AND (AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
	$select.= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) ";
}

print $select,"\n" if $trace;
$eh = $Dbh->query($select) || die $Dbh->errmsg();
for (1..$eh->numrows) {
	%eentry=$eh->fetchhash;
	next if ($eentry{'Iname'} =~ m/^_Z.*/);	# skip C++ names

	if( $eentry{'Itype'} eq "Function" ) {
		printf "extern ";
		if ($eentry{'Ttype'} eq "FuncPtr") {
			$funcPtrName = $eentry{'Iname'};
		}
		displaytype(\%eentry,1);
		if ($eentry{'Ttype'} eq "FuncPtr") {
			printf "(\n";
		} else {
			printf "%s(\n", $eentry{'Iname'};
		}
		$select  = "SELECT * FROM Parameter ";
		$select .= "LEFT JOIN Type on Ptype=Tid ";
		$select .= "WHERE Pint=$eentry{'Iid'} ";
		$select .= "ORDER BY Ppos";
		print $select,"\n" if $trace;
		$ph = $Dbh->query($select) || die $Dbh->errmsg();
		$moreargs = 0;
		if ($ph->numrows) {
			for (1..$ph->numrows) {
				%pentry = $ph->fetchhash;
				printf ", " if ($moreargs++);
				displaytype(\%pentry,1);
			}
		} else {
			printf "void";
		}
		printf ");\n";
	}
	if( $eentry{'Itype'} eq "Data" ) {
		printf "extern ";
		displaytype(\%eentry, 1);
		printf " %s",$eentry{'Iname'};
		if( $eentry{'Ttype'} eq "Array" ) {
			print "[";
			if( $eentry{'ATsize'} != 0 ) {
				print $eentry{'ATsize'};
				}
			print "]";
		}
       if( $eentry{'Ttype'} eq "Const" || $eentry{'Ttype'} eq "Volatile") {
			if( $eentry{'ATbasetype'} != '' ) {
				$basetype = $eentry{'ATbasetype'};
			}
			else {
				$selectBase = "SELECT ATbasetype FROM ArchType ";
				$selectBase.= "WHERE ATtid=".$eentry{'Tid'}." ";
				$selectBase.= "GROUP BY ATbasetype";
				$sthBase = $Dbh->query($selectBase) || die $Dbh->errmsg();
				if($sthBase->numrows > 1) {
					die "Couldn't determine basetype for type ".$eentry{'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 ATaid=Aid ";
	        $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( $eentry{'Itype'} eq "Alias" ) {
		printf "extern ";
		displaytype(\%eentry, 1);
		printf " %s",$eentry{'Iname'};
		if( $eentry{'Ttype'} eq "Array" ) {
			print "[";
			if( $eentry{'ATsize'} != 0 ) {
				print $eentry{'ATsize'};
				}
			print "]";
		}
		printf " ;\n";
	}
	if( $eentry{'Itype'} eq "Common" ) {
		printf "extern ";
		displaytype(\%eentry, 1);
		printf " %s",$eentry{'Iname'};
		if( $eentry{'Ttype'} eq "Array" ) {
			print "[";
			if( $eentry{'ATsize'} != 0 ) {
				print $eentry{'ATsize'};
				}
			print "]";
		}
		printf " ;\n";
	}
	$totrows++;
}
if($totrows == 0) {
	#
	# one of two things ....
	# either there was no data for this architecture,
	# or there's no data at all (its a header associated entirely
	# with interfaces/constants that are not part of the LSB)
	#
	# Check to see if there is ANY data ... same queries, but not arch
	# dependant
	#
	# if HGid is not defined, then this is a bogus header.
	#
	if(!defined($HGid)) {
		exit 0;
	}
	$select = "SELECT * FROM Constant ";
	$select.= "LEFT JOIN ArchConst ON Cid=ACcid ";
	$select.= "WHERE Cheadgroup=$HGid ";
	$select.= "AND (ACappearedin is not NULL and ACappearedin <= '$lsbversion' and ACappearedin<>'') ";
	$select.= "AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
	$select.= "AND Ctype<>'header_depend' ";
	print STDERR $select,"\n" if $trace;
	$ch = $Dbh->query($select) || die $Dbh->errmsg();
	if ($ch->numrows == 0) {
		$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.= "AND Aid = $Aid ";
		print STDERR $select,"\n" if $trace;
		$th = $Dbh->query($select) || die $Dbh->errmsg();
		if ($th->numrows == 0) {
			exit 0;
		}
	}
	printf "/*\n";
	printf " * This header is architecture %s\n",
		$Aid == 1 ? "dependent" : "neutral";
	printf " * Please refer to the %s specification for details\n",
		$Aid == 1 ? "specific architecture" : "generic";
	printf " */\n";
}
