#!/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="";

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

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

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

#print $$type{'Tname'};
#print $$type{'Ttype'};
#if( $$type{'Tname'} =~ "anon" ) { return; }

#switch ($ttype{'Ttype'})

if( $$type{'Ttype'} eq "Intrinsic" ) {
	print $$type{'Tname'}."\t";
	return;
	}

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

if( $$type{'Ttype'} eq "Volatile" ) {
    $select = "SELECT * FROM Type WHERE Tid=".$$type{'Tbasetype'};
    $sth = $Dbh->query($select) || die $Dbh->errmsg();
    %type=$sth->fetchhash;
    if( $type{'Ttype'} eq "Pointer" ) {
	    displaytype(\%type);
        print "volatile ";
	} else {
       	print "volatile ";
	    displaytype(\%type);
	}
    return;
 }
																
if( $$type{'Ttype'} eq "Const" ) {
	$select = "SELECT * FROM Type WHERE Tid=".$$type{'Tbasetype'};
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	%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=$$type{'Tbasetype'};
	$tselect = "SELECT * FROM Type ";
	$tselect.= "LEFT JOIN ArchType ON ATaid=Tarch AND ATtid=Tid ";
	$tselect.= "WHERE Tid=$basetype";
	$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
	%entry=$tth->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{'Theadergroup'} != $HGid )){
					displaytype(\%entry);
				}
			}
		}else{return;}
																								
	}elsif (!$nameonly) {
		if( ( $entry{'Ttype'} eq 'Typedef' ||
		    $entry{'Ttype'} eq 'FuncPtr' ) ||
		    $entry{'Theadergroup'} != $HGid ) {
			if($entry{'Ttype'} eq 'FuncPtr'){
				$funcPtrName = $$type{'Tname'};
			}
			$nameonly=1;
			displaytype(\%entry);
			$nameonly=0;
		}elsif( ($entry{'Ttype'} eq 'Struct' || 
			$entry{'Ttype'} eq 'Union')  
			&& $entry{'Theadergroup'} == $HGid){
				if( !($entry{'Tname'} =~ "anon" )) {
					$nameonly=1;
					displaytype(\%entry);
       				$nameonly=0;
				}else {displaytype(\%entry);}
		} else {
			displaytype(\%entry);
			}
		}
	if( $entry{'Ttype'} ne 'FuncPtr' || $nameonly ) {
		if(!$typeflag){
			print $$type{'Tname'}."\t";
			}
		}
	if( $entry{'Ttype'} eq 'Array' && $nameonly==0) {
		print "[".$entry{'ATsize'}."]";
		}
	if( !$nameonly && $$type{'Tattribute'} && !$typeflag ) {
			print "__attribute__ (".$$type{'Tattribute'}.")";
		}
	if (!$nameonly) {
		print $$type{'Tcomment'}."\n";
		}
	return;
	}

if( $$type{'Ttype'} eq "Pointer" ) {
	$basetype=$$type{'Tbasetype'};
	$tselect="SELECT * FROM Type WHERE Tid=$basetype";
	$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
	%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);
			}
		 }
		print "* ";
	} else {
		displaytype(\%entry);
		print "* ";
	}
	return;
	}

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

	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}
	if (!$typeflag){
		print "struct ".$$type{'Tname'}."\t";
		}
	$Tid=$$type{'Tid'};
	if( $nameonly ) { return; }
	#print $$type{'Tcomment'}."\n";

	$tmselect = "SELECT * FROM TypeMember ";
	#$tmselect.= "LEFT JOIN ArchTypeMem ON ATMtmid = TMid ";
	#$tmselect.= "LEFT JOIN Architecture ON ATMaid = Aid ";
	$tmselect.= "WHERE TMmemberof=$Tid ";
	$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 ATaid=Tarch AND ATtid=Tid ";
		$tselect.= "WHERE Tid=$TMtypeid";
		$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 ATaid=Tarch AND ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'Tbasetype'}";
				$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{'TMcomment'} ) {
			print "/* ".$tmentry{'TMcomment'}." */";
			}
		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{'Tattribute'} ) {
		print "__attribute__ (".$$type{'Tattribute'}.")";
		}
#	print "\n";
	return;
	}

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

	if( $$type{'Tname'} =~ "anon" ) {
		$$type{'Tname'} ="";
		$nameonly = 0;
		}
	if(!$typeflag){
		print "union ".$$type{'Tname'}."\t";}
	$Tid=$$type{'Tid'};
	if( $nameonly ) { return; }
	#print $$type{'Tcomment'}."\n";

	$tmselect="SELECT * FROM TypeMember WHERE TMmemberof=$Tid";
	$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 ATaid=Tarch AND ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid";
		$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 ATaid=Tarch AND ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'Tbasetype'}";
				$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{'TMcomment'} ) {
			print "/* ".$tmentry{'TMcomment'}." */";
			}
		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'} ="";
		}
	print $$type{'Tname'}."\t";
	if( $nameonly ) { return; }
	print $$type{'Tcomment'}."\n";

	$tmselect="SELECT * FROM TypeMember WHERE TMmemberof=$Tid";
	$tmselect.=" ORDER BY TMposition";
	$tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
	if ($tmh->numrows ) { print "{\n"; }
	for(1..$tmh->numrows) {
		%tmentry=$tmh->fetchhash;
		# It's an enum, don't print out the types, just the names
		#$TMtypeid=$tmentry{'TMtypeid'};
		#$tselect="SELECT * FROM Type WHERE Tid=$TMtypeid";
		#$th = $Dbh->query($tselect) || die $Dbh->errmsg();
		#%entry=$th->fetchhash;
		#$nameonly=1;
		#displaytype(\%entry);
		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( $_ != $tmh->numrows ) {
			print ",\t";
			}
		if( $tmentry{'TMcomment'} ) {
			print "/* ".$tmentry{'TMcomment'}."*/";
			}
		print "\n";
		$nameonly=0;
		}
	if ($tmh->numrows ) { print "}\n"; }
	return;
	}

if( $$type{'Ttype'} eq "FuncPtr" ) {
	$basetype=$$type{'Tbasetype'};
	$tselect="SELECT * FROM Type WHERE Tid=$basetype";
	$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
	%entry=$tth->fetchhash;
	if( !$nameonly ) {
		$nameonly=1;
		displaytype(\%entry);
		$nameonly=0;
	} else {
		displaytype(\%entry);
		}
	print "(*"; 
	$Tid=$$type{'Tid'};
#	if( $$type{'Tname'} =~ "fptr" ) {
#		$$type{'Tname'} =~ s/fptr-//;
#		}
#	print $$type{'Tname'}.")";
	print $funcPtrName.")";
	print $$type{'Tcomment'}."(";

	$tmselect="SELECT * FROM TypeMember WHERE TMmemberof=$Tid";
	$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 ATaid=Tarch AND ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid";
		$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 ATaid=Tarch AND ATtid=Tid ";
				$tselect.="WHERE Tid=$entry{'Tbasetype'}";
				$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=$$type{'Tbasetype'};
	$tselect="SELECT * FROM Type WHERE Tid=$basetype";
	$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
	%entry=$tth->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;
	}

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

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

if( $$param{'Pconst'} eq "Y" ) {
	print "const ";
	}

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

if( $$param{'Ttype'} eq "Literal" ) {
	print $$param{'Tname'};
	return;
	}
	
if( $$param{'Ttype'} eq "Volatile" ) {
    $select = "SELECT * FROM Type WHERE Tid=".$$param{'Tbasetype'};
    $sth = $Dbh->query($select) || die $Dbh->errmsg();
    %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" ) {
	$select = "SELECT * FROM Type WHERE Tid=".$$param{'Tbasetype'};
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	%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" ) {
	$select = "SELECT * FROM Type WHERE Tid=".$$param{'Tbasetype'};
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	%type=$sth->fetchhash;
	displaytyperef(\%type);
	print " *";
	return;
	}

if( $$param{'Ttype'} eq "Struct" ) {
	print "struct ".$$param{'Tname'};
	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=$$param{'Tbasetype'};
	$tselect="SELECT * FROM Type WHERE Tid=$basetype";
	$tth = $Dbh->query($tselect) || die $Dbh->errmsg();
	%type=$tth->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" ) {
	$select = "SELECT * FROM Type WHERE Tid=".$$param{'Tbasetype'};
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	%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";
	$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 ATaid=Tarch AND ATtid=Tid ";
		$tselect.="WHERE Tid=$TMtypeid";
		$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;
	}

print $$param{'Ttype'};
}

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

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

GetOptions("h=s" => \$headname,
	   "a=s" => \$archname);
 
if( !$headname ) { usage(); }  
if( !$archname ) { 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'};

#
# Get the Header id
#
$select = "SELECT Hid,Hstd 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'};
$Hstd=$entry{'Hstd'};

#
# 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.= "WHERE Iheader=$Hid ";
$select.= "AND ( Istatus='Included' OR Istatus='Deprecated' ) ";
$select.= "AND Iarch=$Aid";
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 DISTINCT Ptype FROM Interface,Parameter ";
$select.= "WHERE Iheader=$Hid ";
$select.= "AND Pint=Iid ";
#$select.= "WHERE Pint=Iid ";
$select.= "AND ( Istatus='Included' OR Istatus='Deprecated' ) ";
$select.= "AND Iarch=$Aid";
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 Theadergroup=HGid ";
$select.= "WHERE HGheader=$Hid ";
$select.= "AND Tstatus != 'Excluded' ";
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 Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype 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{'Tbasetype'}}=1;
		}
	}

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

#
# Get the base types of Pointers
#

if( $typelist ne "" ) { 
	$select = "SELECT Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype 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{'Tbasetype'}}=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)";
	$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 Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype 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{'Tbasetype'}}=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 Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype 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{'Tbasetype'}}=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 Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype NOT IN ($typelist) ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		$type{$entry{'Tbasetype'}}=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 Tbasetype,Tname FROM Type ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tbasetype NOT IN ($typelist) ";
	print $select,"\n" if $trace;
	$sth = $Dbh->query($select) || die $Dbh->errmsg();
	for(1..$sth->numrows) {
		%entry=$sth->fetchhash;
		$type{$entry{'Tbasetype'}}=1;
		#print STDERR "Type2 ".$entry{'Tname'}."\n";
		}
	}

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

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

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

#
# Get the base types of Const
#

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

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

#$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='macro' ";
#$select.= "AND ( Cstd ='Yes' OR Cstd ='SrcOnly' ) ";
#print $select,"\n" if $trace;
#$sth = $Dbh->query($select) || die $Dbh->errmsg();
#for(1..$sth->numrows) {
#	%entry=$sth->fetchhash;
#	$const{$entry{'ACvalue'}}=1;
	#print "Const ".$entry{'ACvalue'}."\n";
#	}
#$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=Theadergroup ";
	$select.= "LEFT JOIN Header ON Hid=HGheader ";
	$select.= "WHERE Tid IN ($typelist) ";
	$select.= "AND Tstatus != 'Excluded' ";
	$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 containing referenced types
#

#if( $constlist ne "" ) { 
#	$select = "SELECT DISTINCT Hid FROM Constant ";
#	$select.= "LEFT JOIN HeaderGroup ON HGid=Cheadgroup ";
#	$select.= "LEFT JOIN Header ON Hid=HGheader ";
#	$select.= "WHERE Cname IN (\'$constlist\') ";
	#$select.= "AND Cstatus != 'Excluded' ";
#	$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 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";
			}
		}
	}

print "\n#ifdef __cplusplus\n";
print "extern \"C\" {\n";
print "#endif\n\n";

if( $Hstd eq 'SrcError' ) {
	print "#error \"This header not permitted by the LSB\"\n\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
	$select = "SELECT * FROM Constant ";
	$select.= "LEFT JOIN ArchConst ON Cid=ACcid ";
	$select.= "LEFT JOIN Architecture ON Aid=ACaid ";
	$select.= "WHERE Cheadgroup=$HGid ";
	#$select.= "AND ACaid=$Aid ";
	$select.= "AND ( Cstd ='Yes' OR Cstd ='SrcOnly' )";
	$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";
	
	# Display the Type (Typedef)
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN Architecture ON Tarch=Aid ";
	$select.= "LEFT JOIN ArchType ON ATaid=Aid AND ATtid=Tid ";
	$select.= "WHERE Theadergroup=$HGid ";
	$select.= "AND ( Tstatus = 'Referenced' OR Tstatus = 'SrcOnly' OR Tstatus = 'Conly' ) ";
	$select.= "AND Ttype = 'Typedef' ";
	$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{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }
		if( $tentry{'Tstatus'} eq "Conly" ) {
			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{'Tcomment'}."\n\n";
			print "#endif\n";
		} else {
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tcomment'}."\n\n";
			}
		if( $tentry{'Tstatus'} eq "Conly" ) {
			print "#endif\n";
			}
		}

	# Display the Types (excluding Typedef)
	$select = "SELECT * FROM Type ";
	$select.= "LEFT JOIN Architecture ON Tarch=Aid ";
	$select.= "LEFT JOIN ArchType ON ATaid=Aid AND ATtid=Tid ";
	$select.= "WHERE Theadergroup=$HGid ";
	$select.= "AND ( Tstatus = 'Referenced' OR Tstatus = 'SrcOnly' OR Tstatus = 'Conly' ) ";
	$select.= "AND Ttype != 'Typedef' ";
	$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{'Aid'} && $tentry{'Aname'} eq "None" ) { next; }
		if( $tentry{'Tstatus'} eq "Conly" ) {
			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{'Tcomment'}."\n\n";
			print "#endif\n";
		} else {
			displaytype(\%tentry);
			print ";";
			print $tentry{'Tcomment'}."\n\n";
			}
		if( $tentry{'Tstatus'} eq "Conly" ) {
			print "#endif\n";
			}
		}
	
		# Display the Types (Struct/Union)
		$select = "SELECT * FROM Type ";
	    $select.= "LEFT JOIN Architecture ON Tarch=Aid ";
	    $select.= "LEFT JOIN ArchType ON ATaid=Aid AND ATtid=Tid ";
	    $select.= "WHERE Theadergroup=$HGid ";
	    $select.= "AND ( Tstatus = 'Referenced' OR Tstatus = 'SrcOnly' OR Tstatus = 'Conly' ) ";
	    $select.= "GROUP BY Tbasetype ";
	    $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{'Ttype'} eq "Typedef" ){
	            $tselect= "SELECT * FROM Type WHERE Tid=".$tentry{'Tbasetype'};
	            $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; }
	                if( $tentry{'Tstatus'} eq "Conly" ) {
	                    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{'Tcomment'}."\n\n";
	                    print "#endif\n";
			         } else {
				        displaytype(\%tentry);
				        if ($semicolonNeeded) {
				            $semicolonNeeded = 0;
				            print ";";}
		                    print $tentry{'Tcomment'}."\n\n";
				            }
				        if( $tentry{'Tstatus'} eq "Conly" ) {
				             print "#endif\n";}
																																							              }
	          }
	          $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 ArchType ON ATtid=Tid AND ATaid=Iarch ";
$select.= "LEFT JOIN Architecture ON Iarch=Aid ";
$select.= "WHERE ( Istatus='Included' OR Istatus='SrcOnly' )";
#$select.= "AND Iarch=$Aid ";
$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{'Itype'} eq "Function" ) {
		if( $entry{'Ttype'} eq 'FuncPtr' ) {
			print STDERR "Skipping a global function pointer!!\n";
			next;
			}
		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,Tbasetype,Parsize,Pconst FROM Type,Parameter ";
		$select.= "WHERE Pint=".$entry{'Iid'}." AND Ptype=Tid ";
		$select.= "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") {
            $select = "SELECT * FROM Type ";
            $select.= "LEFT JOIN ArchType ON ATtid=Tid AND ATaid=Tarch ";
	        $select.= "LEFT JOIN Architecture ON Tarch=Aid ";
	        $select.= "WHERE Tid=".$entry{'Tbasetype'};
	        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";
	}
}
print "#ifdef __cplusplus\n";
print "}\n";
print "#endif\n";
print "#endif\n";
