#!/usr/bin/perl

# Copyright (c) 2001-2006 The Free Standards Group Inc.

use Mysql;
use Getopt::Long;

use Env qw(LSBUSER LSBDBPASSWD LSBDB LSBDBHOST);

sub usage()
{
print STDERR "mktests -v lsbversion\n";
die;
}

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

GetOptions("v=s" => \$lsbversion);
if( !$lsbversion ) { usage(); }

# Temporary workarounds so hand-edited changes aren't lost
# workaround for math functions that don't have protos on all architectures
@mathsyms = qw/__finitel __isinfl __isnanl acoshl acosl asinhl asinl atan2l atanhl atanl cbrtl ceill copysignl coshl cosl dreml erfcl erfl expl expm1l fabsl fdiml finitel floorl fmal fmaxl fminl fmodl frexpl gammal hypotl ilogbl j0l j1l jnl ldexpl lgammal lgammal_r llrintl llroundl log10l log1pl log2l logbl logl lrintl lroundl modfl nanl nearbyintl nextafterl nexttowardl pow10l powl remainderl remquol rintl roundl scalbl scalblnl scalbnl significandl sincosl sinhl sinl sqrtl tanhl tanl tgammal truncl y0l y1l ynl/;
$mathstring = "#if ! __powerpc__ && ! __s390__	/* hack */\n";

# counter used to calculate test number
$cnt = 0;

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,$Aid) = @_;
    $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;
}

# For a given type, check if there are architecture specific records
# in the ArchType table. If not, return -1. Otherwise, check if records
# for every supported architecture present; if not, print appropriate
# 'Msg' calls and return number of missed archs, otherwise return 0
sub checkArchSpecific($$$$) {
 	local ($Tname,$Tid,$condition,$Ttype) = @_;

   	$selectArchSpecific = "SELECT * FROM Type LEFT JOIN ArchType ON ATtid=Tid ";
   	$selectArchSpecific.= "WHERE ATaid<>1 ";
   	$selectArchSpecific.= "AND ATtid=$Tid ";
   	$selectArchSpecific.= "AND ( ATappearedin<>'' AND ATappearedin<='$lsbversion' ";
   	$selectArchSpecific.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
#    	$selectArchSpecific.= "OR Tindirect='Yes')";
	$sth = $Dbh->query($selectArchSpecific) || die $Dbh->errmsg();

	$archNumber = $sth->numrows;
	if( $archNumber == 0 ) {
		return -1;
	}

    for ( 1 .. $archNumber ) {
   	    %archentry = $sth->fetchhash ;
   	    $PresentedArchs{$archentry{'ATaid'}} = 1;
   	}

	# Get history info for generic record - required in cases when we want
	# to display "REPLACE INTO ArchType" warnings
   	$selectGenericHistory = "SELECT * FROM ArchType ";
   	$selectGenericHistory.= "WHERE ATaid=1 ";
   	$selectGenericHistory.= "AND ATtid=$Tid ";
   	$selectGenericHistory.= "AND ( ATappearedin<>'' AND ATappearedin<='$lsbversion' ";
   	$selectGenericHistory.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
	$sthGeneric = $Dbh->query($selectGenericHistory) || die $Dbh->errmsg();

	# Get all supported architectures;
	$selectAllArchs = "SELECT Aid,Asymbol FROM Architecture WHERE Aid<>1";
	$ath = $Dbh->query($selectAllArchs) || die $Dbh->errmsg();

	$allNum = $ath->numrows;

	if( not ( $Tname =~ /anon/ && $Ttype ne 'Enum') and (not ( $Tname =~ /fptr/ ) ) ) {
		if( $allNum > $archNumber ) {
			$missedCount=0;
			for ( 1 .. $allNum ) {
				@aentry = $ath->fetchrow_array;
				if( not $PresentedArchs{$aentry[0]} ) {
					if( $missedCount ) {
						print TESTS "#elif $aentry[1]\n";
					}
					else {
						if( $condition eq "endif" ) {
							print TESTS "#endif\n\n";
							print TESTS "#if $allentry{'Asymbol'}\n";
						}
						elsif( $condition eq "elif" ) {
							print TESTS "#elif $allentry{'Asymbol'}\n";
						}
						elsif( $condition eq "if" ) {
							print TESTS "#if $allentry{'Asymbol'}\n";
						}
						else {
							die "Illegal condition was passed to checkArchSpecific";
						}
					}

					print TESTS "Msg(\"Find size of $Tname ($Tid)\\n\");\n";
					@genentry = $sthGeneric->fetchrow_array;
					$appearedin  = $genentry{'ATappearedin'};
					$basetype    = $genentry{'ATbasetype'};
					$withdrawnin = $genentry{'ATwithdrawnin'} ? "'\"\"$genentry{'ATwithdrawnin'}\"\"'" : "NULL";
					$attribute   = $genentry{'ATattribute'} ? "'\"\"$genentry{'ATattribute'}\"\"'" : "NULL";

					print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
					print TESTS "%d,%d,%d,'\"\"$appearedin\"\"',$withdrawnin,$basetype,$attribute);\\n\",architecture,$Tid,0);\n";
					$missedCount++;
				}
			}
		}
	}

	return $missedCount;
}

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

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

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

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

    if ( $$param{Tname} =~ "anon" ) {
        $$param{Tname} = "";
    }

    if ( $$param{'Ttype'} eq "Struct" ) {
        print TESTS "struct " . $$param{'Tname'};
        return;
    }

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

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

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

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

    if ( $$param{'Ttype'} eq "FuncPtr" ) {
		$basetype = getBaseTypeID($param);
		$sth = getBaseTypeRecord($basetype,$curArch);
		%type=$sth->fetchhash;
        $Tid    = $$param{'Tid'};
        displaytyperef( \%type, $enableConst, $curArch );
        print TESTS "(*";
        if( $$param{'Tname'} =~ /fptr\-\d+\s/ ) {
        	$$param{'Tname'} = "fptr";
        }
        elsif( $$param{'Tname'} =~ "fptr" ) {
            $$param{'Tname'} =~ s/fptr-//;
        }
        print TESTS $$param{'Tname'};
        print TESTS ")";

        print TESTS "(";

        $tmselect = "SELECT * FROM TypeMember";
        $tmselect .= " WHERE TMmemberof=$Tid AND TMaid in(1,$curArch)";
        $tmselect .= " GROUP BY TMid";
        $tmselect .= " ORDER BY TMposition";
        $tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
        if ( $tmh->numrows == 0 ) {
            print TESTS "void";
        }
        for ( 1 .. $tmh->numrows ) {
            %tmentry  = $tmh->fetchhash;
            $TMtypeid = $tmentry{'TMtypeid'};
            $tselect  = "SELECT * FROM Type";
            $tselect .= " LEFT JOIN ArchType ON ATaid=$curArch AND ATtid=Tid";
            $tselect .= " WHERE Tid=$TMtypeid";
            $th    = $Dbh->query($tselect) || die $Dbh->errmsg();
            %entry = $th->fetchhash;

            #$nameonly=1;
            displaytyperef( \%entry, $enableConst, $curArch );

            #print TESTS $tmentry{'TMname'};
            if ( $entry{'Ttype'} eq 'Array' ) {
                print TESTS "[" . $entry{'ATsize'} . "]";
            }
            if ( $_ != $tmh->numrows ) {
                print TESTS ",";
            }

            #$nameonly=0;
        }

        print TESTS ")\n";
        return;
    }

    print TESTS $$param{'Ttype'};
}

sub writetest($$) {
    local ( $Hid, $Hname ) = @_;
    local ($lastid);
    my (%entry);

    # Get Constants
    $select = "SELECT DISTINCT * FROM Constant ";
    $select .= "INNER JOIN HeaderGroup on CHeadgroup=HGid ";
    $select .= "LEFT JOIN ArchConst ON ACcid=Cid ";
    $select .= "LEFT JOIN Architecture ON Aid=ACaid ";
    $select .= "WHERE HGheader=$Hid ";
    $select.= "AND (ACappearedin is not NULL and ACappearedin <= '$lsbversion' and ACappearedin<>'') ";
    $select.= "AND (ACwithdrawnin IS NULL OR ACwithdrawnin > '$lsbversion') ";
    $select .= "ORDER BY Cheadgroup,Cname,ACvalue ";
    $cth = $Dbh->query($select) || die $Dbh->errmsg();

    # Get Types
    $select = "SELECT DISTINCT * FROM Type ";
    $select .= "INNER JOIN HeaderGroup ON Theadgroup=HGid ";
    $select .= "LEFT JOIN ArchType ON ATtid=Tid ";
    $select .= "LEFT JOIN Architecture ON Aid=ATaid ";
    $select .= "WHERE HGheader=$Hid ";
	$select.= "AND (ATappearedin <= '$lsbversion' AND ATappearedin<>'') ";
	$select.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion')";
    $select .= "ORDER BY Theadgroup,Tid ";
    $tth = $Dbh->query($select) || die $Dbh->errmsg();

    $fname = $Hname;
    $fname =~ tr/\/.-/__/;

    # Try to guess if we have a cpp header
    $select = "SELECT * FROM Type ";
    $select.= "LEFT JOIN HeaderGroup ON Theadgroup=HGid ";
    $select.= "WHERE HGheader=$Hid ";
    $select.= "AND (Ttype='Class' OR Ttype='TemplateInstance' OR Tclass>0) ";
    $classth = $Dbh->query($select) || die $Dbh->errmsg();

    if( $classth->numrows ) {
    	$filename = $fname . ".C";
    }
    else {
    	$filename = $fname . ".c";
    }
    $objname  = $fname . ".o";

    open( TESTS, ">$filename" ) || die "Can't open $filename for writing";
    print "Writing tests for $Hname to $filename\n";

    if ( $cth->numrows == 0 && $tth->numrows == 0 ) {
    	print "No type tests to write for $Hname\n";
        print TESTS "/*\n * No values in $Hname\n */\n";
        close(TESTS);
        return;
    }

    print MAKEFILE "\\\n\t$objname ";
    print HARNESS "tcnt+=$fname();\n";
    print SUBDEFS "extern void $fname();\n";
    $cnt++;
    print TET_HDR "\t{ $fname, $cnt },\n";

    print TESTS "/*\n * Test of $Hname\n */\n";
    print TESTS "#include \"hdrchk.h\"\n";
    print TESTS "#include \<stdio.h\>\n";
    print TESTS "#include \<sys/types.h\>\n";
    print TESTS "#define _LSB_DEFAULT_ARCH 1\n";

    open( INCS, "<$fname.inc" );
    while (<INCS>) {
        print TESTS $_;
    }
    close(INCS);
    print TESTS "#include \"$Hname\"\n";
    print TESTS "\n\n\n";
    print TESTS "#ifdef TET_TEST\n";
    print TESTS "void $fname()\n{\n";
    print TESTS "#else\n";
    print TESTS "int $fname()\n{\n";
    print TESTS "#endif\n\n";
    print TESTS "int cnt=0;\n\n";
    print TESTS "int pcnt=0;\n";
    print TESTS "#ifdef TET_TEST\n";
    #print TESTS "int pcnt=0;\n";
    print TESTS "Msg(\"Checking data structures in $Hname\\n\");\n";
    print TESTS "#endif\n\n";
    print TESTS "printf(\"Checking data structures in $Hname\\n\");\n";

    my (%constHash);
    for ( 1 .. $cth->numrows ) {
        my (%centry);
        %centry = $cth->fetchhash;
        $constHash{ $centry{'Cid'} }{ $centry{'Aid'} } = \%centry;
    }

    foreach $cid ( sort keys %constHash ) {
        $archCount = 0;
        foreach $archId ( reverse sort keys %{ $constHash{$cid} } ) {
            %centry       = %{ $constHash{$cid}{$archId} };
            $cname_save   = $centry{'Cname'};
            $type_save    = $centry{'Ctype'};
            $cid_save     = $centry{'Cid'};
            $cappearedin  = $centry{'ACappearedin'};
            $cwithdrawnin = $centry{'ACwithdrawnin'};

            $withdrawnin   = $cwithdrawnin ? "'\"\"$cwithdrawnin\"\"'" : "NULL";
            if ( $centry{'Aid'} == 1 ) {
                $centry{Asymbol} = "_LSB_DEFAULT_ARCH";
            }
            if ( $archCount == 0 ) {
                print TESTS "#if $centry{Asymbol}\n";
            } else {
                print TESTS "#elif $centry{Asymbol}\n";
            }
            $archCount++;

            if ( $centry{'Ctype'} eq 'int' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareConstant($centry{'Cname'},$centry{'ACvalue'},$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } elsif ( $centry{'Ctype'} eq 'long' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareLongConstant($centry{'Cname'},$centry{'ACvalue'},$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } elsif ( $centry{'Ctype'} eq 'float' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareFloatConstant($centry{'Cname'},$centry{'ACvalue'},$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } elsif ( $centry{'Ctype'} eq 'double' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareDoubleConstant($centry{'Cname'},$centry{'ACvalue'},$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } elsif ( $centry{'Ctype'} eq 'longdouble' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareLongDoubleConstant($centry{'Cname'},$centry{'ACvalue'},$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } elsif ( $centry{'Ctype'} eq 'string' ) {
                print TESTS "#ifdef $centry{'Cname'}\n";
                print TESTS "\tCompareStringConstant($centry{'Cname'},\""
                  . $centry{'ACvalue'} . "\",$centry{'Cid'},architecture,$cappearedin,$withdrawnin)\n";
                print TESTS "#else\n";
                print TESTS "Msg( \"Error: Constant not found: $centry{'Cname'}\\n\");\n";
                print TESTS "cnt++;\n";
                print TESTS "#endif\n\n";
            } else {
                print TESTS "/* No test for $centry{'Cname'} */\n";
            }
        }
        if ( exists( $constHash{$cid}{1} ) ) {
            print TESTS "#endif\n\n";
        } else {
            print TESTS "#else\n";
            print TESTS "Msg( \"No definition for $cname_save ($cid_save, $type_save) in db\\n\");\n";
            print TESTS "#ifdef $cname_save\n";
            if ( $type_save eq 'int' ) {
                print TESTS "Msg( \"REPLACE INTO ArchConst (ACaid,ACcid,ACvalue,ACappearedin,ACwithdrawnin) VALUES (%d,$cid_save,%d,'\"\"$cappearedin\"\"',$withdrawnin);\\n\", architecture, $cname_save);\n";
            }
            if ( $type_save eq 'long' ) {
                print TESTS "Msg( \"REPLACE INTO ArchConst (ACaid,ACcid,ACvalue,ACappearedin,ACwithdrawnin) VALUES (%d,$cid_save,%ld,'\"\"$cappearedin\"\"',$withdrawnin);\\n\", architecture, $cname_save);\n";
            }
            if ( $type_save eq 'string' ) {
                print TESTS "Msg( \"REPLACE INTO ArchConst (ACaid,ACcid,ACvalue,ACappearedin,ACwithdrawnin) VALUES (%d,$cid_save,%s,'\"\"$cappearedin\"\"',$withdrawnin);\\n\", architecture, $cname_save);\n";
            }
            print TESTS "#endif\n";
            print TESTS "#endif\n";
        }
    }

    $lastid = 0;
    $total_printed = 0;
    for ( 1 .. $tth->numrows ) {
        %tentry = $tth->fetchhash;
        if ( !$tentry{'Asymbol'} )   {
            print STDERR "Type " . $tentry{'Tname'} . " is missing Arch\n";
            $tentry{'Asymbol'} = '__no_sym__';
        }

		$condition = "elif"; # "elif"
        if ( $tentry{'Tid'} != $lastid ) {
            if ( $lastid != 0 ) {
                $condition = "endif";
            }
            $condition = "if";
        }

		if( $tentry{'Aid'} == 1 ) {
			$printedMsgs = checkArchSpecific($tentry{'Tname'},$tentry{'Tid'},$condition,$tentry{'Ttype'});
			if( $printedMsgs > 0 ) {
				$lastid = $tentry{'Tid'};
			}
			if( $printedMsgs != -1 ) {
				next;
			}
		}

		$idchanged = 0;

        # Do this before we reset the value, so we can re-use the values
        # from the last time through the loop if we need them
		if ( $tentry{'Tid'} != $lastid ) {
 			if( $lastid and $total_printed and ( ( $Tname !~ /anon/ or $Ttype eq 'Enum') and ( $Tname !~ /fptr/ ) ) ) {
				# We have output at least one type, and now we need to
				# put a catchall else clause
				if ( $lastaid != 1 ) {
					$selectGeneric = "SELECT count(*) as cnt FROM ArchType ";
					$selectGeneric.= "WHERE ATtid=$Tid AND ATaid=1 ";
					$selectGeneric.= "AND ATappearedin<>'' AND ATappearedin <= '$lsbversion' ";
					$selectGeneric.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ";
					$gth = $Dbh->query($selectGeneric) || die $Dbh->errmsg();
					%gentry = $gth->fetchhash;
					if ($gentry{'cnt'} > 0) {
						print TESTS "#else\n";
						print TESTS "Msg(\"Find size of $Tname ($Tid)\\n\");\n";
						$withdrawnin = $ATwithdrawnin ? "'\"\"$ATwithdrawnin\"\"'" : "NULL";
						$attribute = $ATattribute ? "'\"\"$ATattribute\"\"'" : "NULL";
						print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
						print TESTS "%d,%d,%d,'\"\"$ATappearedin\"\"',$withdrawnin,$ATbasetype,$attribute);\\n\",architecture,$Tid,0);\n";
					}
				}
				print TESTS "#endif\n\n";
			}
			$idchanged = 1;
			$total_printed = 0;

			if( ( $tentry{'Tname'} !~ /anon/ or $tentry{'Ttype'} eq 'Enum' ) and ( $tentry{'Tname'} !~ /fptr/ ) and ( $tentry{'Ttype'} ne 'Typedef' ) ) {
				print TESTS "#if $tentry{'Asymbol'}\n";
				$total_printed++;
			}
		} else {
			if( ( $tentry{'Tname'} !~ /anon/ or $tentry{'Ttype'} eq 'Enum' ) and ( $tentry{'Tname'} !~ /fptr/ ) and ( $tentry{'Ttype'} ne 'Typedef' ) ) {
				print TESTS "#elif $tentry{'Asymbol'}\n";
				$total_printed++;
			}
		}
        $lastid   = $tentry{'Tid'};
        $lastaid  = $tentry{'Aid'};
        $Tid      = $tentry{'Tid'};
        $Tname    = $tentry{'Tunmangled'} ? $tentry{'Tunmangled'} : $tentry{'Tname'};
        $Ttype    = $tentry{'Ttype'};
        $ATsize   = $tentry{'ATsize'};
        $Aid      = $tentry{'Aid'};
        $Asymbol  = $tentry{'Asymbol'};
        $Aname    = $tentry{'Aname'};
        $ATappearedin  = $tentry{'ATappearedin'};
        $ATwithdrawnin = $tentry{'ATwithdrawnin'};
        $ATbasetype    = $tentry{'ATbasetype'};
        $ATattribute   = $tentry{'ATattribute'};
        if ( $Tname =~ /anon/ && $tentry{'Ttype'} ne 'Enum' ) { next; }
        if ( $Tname =~ /fptr/ ) { next; }

        #switch( $tentry{'Ttype'}
        #case Struct:
        #case Union:
        if ( $tentry{'Ttype'} eq 'Struct' || $tentry{'Ttype'} eq 'Union' ) {
            if ( $tentry{'Ttype'} eq 'Struct' ) {
                $type = "struct";
            } else {
                $type = "union";
            }

			$tselect = "SELECT * FROM Type ";
			$tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
			$tselect .= "LEFT JOIN Architecture ON Aid=ATaid ";
			$tselect .= "WHERE (ATappearedin <> '' AND ATappearedin <= '$lsbversion' ";
			$tselect .= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
			$tselect .= "AND Tid=" . $tentry{'ATbasetype'};
# 			$tselect .= " OR Tindirect='Yes')";
			print $tselect, "\n" if $trace;
			$ttth    = $Dbh->query($tselect) || die $Dbh->errmsg();
			%ttentry = $ttth->fetchhash;
			if( $ttentry{'Tid'} or ($tentry{'ATbasetype'} == 0) ) {
				$withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
				$attribute = $ATattribute ? "'$ATattribute'" : "NULL";
           		print TESTS "CheckTypeSize($type $Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
            }
            else {
            	next; # do not check members of not included types
            }

            # Get the members
			if( $Aid ) {
				$select = "SELECT DISTINCT * FROM TypeMember ";
 				$select .= "LEFT JOIN TypeMemberExtras ON TMEtmid=TMid ";
				$select .= "WHERE TMmemberof=$Tid AND TMaid in (1,$Aid) ";
				$select .= "AND TMbitfield = 0 ";
 				$select .= "AND TMEaid=$Aid ";
				$select .= "ORDER BY TMposition ";
				print $select, "\n" if $trace;
				$mth = $Dbh->query($select) || die $Dbh->errmsg();
			}

            if ( $mth->numrows ) {
                for ( 1 .. $mth->numrows ) {
					%mentry = $mth->fetchhash;

					# XXXSTU - We really should fetch the info for the member
					# type so we can validate the size in the DB
					#
					print TESTS "CheckMemberSize($type $tentry{'Tname'},$mentry{'TMname'},$mentry{'TMEsize'},$Aid,$mentry{'TMid'})\n";
					print TESTS "CheckOffset($type $tentry{'Tname'},$mentry{'TMname'},$mentry{'TMEoffset'},$Aid,$mentry{'TMid'})\n";
				}
            } else {
	        	#Checking Structure Member Bit-Field value
				$select = "SELECT DISTINCT * FROM TypeMember ";
                $select .= "WHERE TMmemberof=$Tid AND TMaid in (1,$Aid) ";
                $select .= "AND TMbitfield > 0 ";
                $select .= "ORDER BY TMposition ";
                print $select, "\n" if $trace;
                $mth = $Dbh->query($select) || die $Dbh->errmsg();
				if($mth->numrows){
					for ( 1 .. $mth->numrows ) {
						%mentry = $mth->fetchhash;
						print TESTS "CheckBitField($type $tentry{'Tname'},$mentry{'TMname'},$mentry{'TMbitfield'},$Aid,$mentry{'TMid'})\n";
					}
				}else{
	                # Get the members that are supposed to be there
        	        $select = "SELECT DISTINCT * FROM TypeMember ";
                	$select .= "WHERE TMmemberof=$Tid AND TMaid in (1,$Aid) ";
	                $select .= "AND TMbitfield = 0 ";
        	        $select .= "ORDER BY TMposition ";
                	print $select, "\n" if $trace;
	                $mth = $Dbh->query($select) || die $Dbh->errmsg();
        	        print TESTS "Msg(\"Missing member data for $Tname on $Aname\\n\");\n";
                	for ( 1 .. $mth->numrows ) {
	                    %mentry = $mth->fetchhash;
        	            print TESTS "CheckOffset($type $tentry{'Tname'},$mentry{'TMname'},0,$Aid,$mentry{'TMid'})\n";
					}
				}
			}
            next;
        }

        #case Pointer:
        if ( $tentry{'Ttype'} eq 'Pointer' ) {

            # need to get the basetype first
            $tselect = "SELECT * FROM Type ";
            $tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
            $tselect .= "LEFT JOIN Architecture ON Aid=ATaid ";
            $tselect .= "WHERE Tid=" . $tentry{'ATbasetype'};
			print $tselect, "\n" if $trace;
            $ttth = $Dbh->query($tselect) || die $Dbh->errmsg();
            %ttentry = $ttth->fetchhash;
            my $typeName;

			$withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
			$attribute = $ATattribute ? "'$ATattribute'" : "NULL";
            if ( $ttentry{'Ttype'} eq 'Struct' ) {
                $typeName = "struct " . $Tname;
                print TESTS "CheckTypeSize($typeName,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
            } elsif ( $ttentry{'Ttype'} eq 'Union' ) {
                $typeName = "union " . $Tname;
                print TESTS "CheckTypeSize($typeName,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
            } elsif ( $ttentry{'Ttype'} eq 'Typedef' ) {
                print TESTS "CheckTypeSize($Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
            }
            next;
        }

        #case Enum:
        if ( $tentry{'Ttype'} eq 'Enum' ) {
            $tmselect = "SELECT * FROM TypeMember ";
            $tmselect .= "WHERE TMmemberof=" . $tentry{'Tid'} . " AND TMaid in (1,$Aid) ";
            $tmselect .= " ORDER BY TMposition";
	     print $tmselect, "\n" if $trace;
            $tmh = $Dbh->query($tmselect) || die $Dbh->errmsg();
            for ( 1 .. $tmh->numrows ) {
                %tmentry = $tmh->fetchhash;
                if ( $tmentry{'TMarray'} ne '' ) {
                    $lastvalue = "$tmentry{'TMarray'}";
                    print TESTS "CheckEnum(\"$tmentry{'TMname'}\",$tmentry{'TMname'},$tmentry{'TMarray'},$tmentry{'TMid'})\n";
                } else {
                    if ( $_ == 1 ) {
                        $lastvalue = "0";
                    } else {
                        $lastvalue = "(" . $lastvalue . ") + 1";
                    }
                    print TESTS "CheckEnum(\"$tmentry{'TMname'}\",$tmentry{'TMname'},$lastvalue,$tmentry{'TMid'})\n";
                }
            }
            next;
        }

        #case Typedef:
        if ( $tentry{'Ttype'} eq 'Typedef' ) {

            # Need to check for Array, and adjust the size value accordingly

#             $tselect = "SELECT * FROM Type ";
#             $tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
#             $tselect .= "LEFT JOIN Architecture ON Aid=ATaid ";
#             $tselect .= "WHERE Tid=" . $tentry{'ATbasetype'};
# 			$tselect .= " AND (ATappearedin <> '' AND ATappearedin <= '$lsbversion' ";
# 			$tselect .= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
# # 			$tselect .= "OR Tindirect='Yes' )";
#             $ttth    = $Dbh->query($tselect) || die $Dbh->errmsg();
#             %ttentry = $ttth->fetchhash;

			$baseselect = "SELECT Ttype, count(TMid) AS mem_cnt FROM Type ";
			$baseselect .= "LEFT JOIN ArchType ON ATbasetype=Tid ";
			$baseselect .= "LEFT JOIN TypeMember ON TMmemberof=Tid ";
			$baseselect .= "WHERE ATtid=$Tid ";
			$baseselect .= "GROUP BY Tid ";
			print $baseselect, "\n" if $trace;
# 			$tselect .= " OR Tindirect='Yes')";
			$baseth = $Dbh->query($baseselect) || die $Dbh->errmsg();
			if( $baseth->numrows ) {
				%baseentry = $baseth->fetchhash;
				if( ($baseentry{'Ttype'} eq 'Struct' or $baseentry{'Ttype'} eq 'Union' or $baseentry{'Ttype'} eq 'Enum')
						and $baseentry{'mem_cnt'} == 0 ) {
					next;
				}
			}

			$total_printed++;
			if( $idchanged ) {
				if( $tentry{'Tname'} !~ /fptr/ ) {
					print TESTS "#if $tentry{'Asymbol'}\n";
				}
			} else {
				if( $tentry{'Tname'} !~ /fptr/ ) {
					print TESTS "#elif $tentry{'Asymbol'}\n";
				}
			}
# 			if ($ttentry{'Tid'}) {
				$withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
				$attribute = $ATattribute ? "'$ATattribute'" : "NULL";
	            print TESTS "CheckTypeSize($Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
# 			} else {
# 				$tentry{'ATaid'} = 0;
# 			}

            next;
        }

        # case Const
        if ( $tentry{'Ttype'} eq 'Const' ) {

            # need to get the basetype first
            $tselect = "SELECT * FROM Type ";
            $tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
            $tselect .= "LEFT JOIN Architecture ON Aid=ATaid ";
            $tselect .= "WHERE Tid=" . $tentry{'ATbasetype'};
			$tselect .= " AND (ATappearedin <> '' AND ATappearedin <= '$lsbversion' ";
			$tselect .= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
# 			$tselect .= "OR Tindirect='Yes' ) ";
			print $tselect, "\n" if $trace;
            $ttth = $Dbh->query($tselect) || die $Dbh->errmsg();
            %ttentry = $ttth->fetchhash;
            my $typeName;

			$withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
			$attribute = $ATattribute ? "'$ATattribute'" : "NULL";
            if ( $ttentry{'Ttype'} eq 'Typedef' || $ttentry{'Ttype'} eq 'Pointer' ) {
				if ($ttentry{'Ttype'} eq 'Typedef') {
					$tselect = "SELECT * FROM Type ";
					$tselect .= "LEFT JOIN ArchType ON ATtid=Tid ";
					$tselect .= "LEFT JOIN Architecture ON Aid=ATaid ";
					$tselect .= "WHERE (ATappearedin <> '' AND ATappearedin <= '$lsbversion' ";
					$tselect .= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ) ";
# 					$tselect .= "OR Tindirect='Yes' ) ";
					$tselect .= "AND Tid=" . $ttentry{'ATbasetype'};
					$ttth = $Dbh->query($tselect) || die $Dbh->errmsg();
					%ttentry = $ttth->fetchhash;
					if ($ttentry{'Tid'} or ($ttentry{'ATbasetype'} == 0) ) {
						print TESTS "CheckTypeSize($Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
					}
				} else {
					print TESTS "CheckTypeSize($Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
				}
			} else {
				$tentry{'ATaid'} = 0;
			}

            next;
        }

        if ( $tentry{'Ttype'} eq 'Class' ) {
        	next;
        }

        # Default case
		$withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
		print TESTS "CheckTypeSize($Tname,$ATsize, $Tid, $Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n"
		if $tentry{'Ttype'} ne 'Array';
    }

 	if( not ( $Tname =~ /anon/ && $Ttype ne 'Enum') and (not ( $Tname =~ /fptr/ ) ) ) {
		if( $lastid and $total_printed ) {
			if( $lastaid != 1 ) {
				$selectGeneric = "SELECT count(*) as cnt FROM ArchType ";
				$selectGeneric.= "WHERE ATtid=$Tid AND ATaid=1 ";
				$selectGeneric.= "AND ATappearedin<>'' AND ATappearedin <= '$lsbversion' ";
				$selectGeneric.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ";
				print $selectGeneric, "\n" if $trace;
				$gth = $Dbh->query($selectGeneric) || die $Dbh->errmsg();
				%gentry = $gth->fetchhash;
				if ($gentry{'cnt'} > 0) {
					print TESTS "#else\n";
					print TESTS "Msg(\"Find size of $Tname ($Tid)\\n\");\n";
					$withdrawnin = $ATwithdrawnin ? "'\"\"$ATwithdrawnin\"\"'" : "NULL";
					$attribute = $ATattribute ? "'\"\"$ATattribute\"\"'" : "NULL";
					print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
					print TESTS "%d,%d,%d,'\"\"$ATappearedin\"\"',$withdrawnin,$ATbasetype, $attribute);\\n\",architecture,$Tid,0);\n";
				}
			}
			print TESTS "#endif\n\n";
		}
 	}

    #
    # Interface testing
    #
    my $GlX11 = 0;
    my $math = 0;
    my $special;

    #print $Hname;
    if ( $Hname =~ /GL\// || $Hname =~ /X11\// ) {
        #print "Found GL or X11 header\n";
        $GlX11 = 1;
    }
    if ( $Hname =~ /math\.h/ ) {
	#print "Found math header\n";
	$mathhdr = 1;
    }
    if ( $GlX11 == 0 ) {    # ignore GL and X11 interfaces
		$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 Architecture ON AIarch=Aid ";
 		$select .= "WHERE (Isrcbin='SrcOnly' OR ( Isrcbin='Both' AND ";
		$select .= "(AIappearedin <= '$lsbversion' and AIappearedin<>'') ";
		$select .= "AND (AIwithdrawnin IS NULL OR AIwithdrawnin >'$lsbversion') ) )";
		$select .= "AND Hid=$Hid";
		print $select, "\n" if $trace;
		$sth = $Dbh->query($select) || die $Dbh->errmsg();

		for ( 1 .. $sth->numrows ) {
			$special = 0;
			%entry = $sth->fetchhash;
			if ( $mathhdr ) { $special = grep /^$entry{'Iname'}$/, @mathsyms; }
			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" ) {
					$selectCheck ="SELECT Iid FROM Interface ";
					$selectCheck.="LEFT JOIN ArchInt ON Iid=AIint ";
					$selectCheck.="WHERE AIarch=1 AND Iname='$entry{'Iname'}'";
					print $selectCheck, "\n" if $trace;
					$sthCheck = $Dbh->query($selectCheck) || die $Dbh->errmsg();
					if( $sthCheck->numrows ) {
						next;
					}
				}

				if ( $entry{'Aid'} && $entry{'Aname'} ne "All" ) {
					print TESTS "#if $entry{'Asymbol'}\n";
					print TESTS "/* $entry{'Aname'} */\n";
				}
				elsif ( $special) {
					print TESTS $mathstring;
				}

				# Class interfaces are not checked at the moment...
 				if( $entry{'Iclass'} == 0 ) {
					print TESTS "extern ";
					displaytyperef( \%entry, 1, $entry{'Aid'} );
					print TESTS " $entry{'Iname'}_db(";

					$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 ) {
						for ( 1 .. $sth2->numrows ) {
							%entry2 = $sth2->fetchhash;

							#print TESTS ", ";
							displaytyperef( \%entry2, 1, $entry{'Aid'} );
							if ( $entry2{'Ttype'} eq "Array" ) {
								print TESTS "[";
								if ( $entry2{'Parsize'} != 0 ) {
									print TESTS "$entry2{'Parsize'}";
								}
								print TESTS "]";
							}
							if ( $_ != $sth2->numrows ) { print TESTS ", "; }
						}
					} else {
						print TESTS "void";
					}
					print TESTS ");\n";
					print TESTS "CheckInterfacedef($entry{'Iname'},$entry{'Iname'}_db);\n";
				}

				if ( $entry{'Aid'} && $entry{'Aname'} ne "All" ) {
					print TESTS "#endif\n";
				}
				elsif ( $special) {
					print TESTS "#endif		/* hack */\n";
				}
			}
            #elsif ( $entry{'Itype'} eq "Data" ) {
            #    print TESTS "extern ";
            #    displaytyperef( \%entry, 0 );
            #    print TESTS " $entry{'Iname'}_db";
            #    if ( $entry{'Ttype'} eq "Array" ) {
            #        print TESTS "[";
            #        if ( $entry{'ATsize'} != 0 ) {
            #            print TESTS $entry{'ATsize'};
            #        }
            #        print TESTS "]";
            #    }
            #    print TESTS " ;\n";
            #    print TESTS "CheckGlobalVar($entry{'Iname'}_db, $entry{'Iname'});\n";
            #}
        }
    }

    print TESTS "#ifdef TET_TEST\n";
    print TESTS "if (pcnt == cnt )\n";
    print TESTS "\ttet_result(TET_PASS);\n";
    print TESTS "else\n";
    print TESTS "\ttet_result(TET_FAIL);\n";
    print TESTS "return;\n";
    print TESTS "#else\n";
    print TESTS "printf(\"%d tests passed out of %d tests in $Hname\\n\\n\",pcnt,cnt);\n";

    #print TESTS "printf(\"%d tests in $Hname\\n\",cnt);\n";
    print TESTS "return cnt;\n";
    print TESTS "#endif\n\n";
    print TESTS "}\n";

    close(TESTS);
}

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

$Dbh->selectdb("lsb") || die $Dbh->errmsg();

if ( $ARGV[0] ne "" ) {
    $select = "SELECT DISTINCT * FROM Header ";
	$select.= "WHERE (Happearedin <= '$lsbversion' and Happearedin<>\'\') ";
	$select.= "AND (Hwithdrawnin IS NULL OR Hwithdrawnin > '$lsbversion' )",
    $select .= "AND Hname='" . $ARGV[0] . "'";
	print $select, "\n" if $trace;
    $hth = $Dbh->query($select) || die $Dbh->errmsg();
    %entry = $hth->fetchhash;
    writetest( $entry{'Hid'}, $entry{'Hname'} );
    exit;
}

open( HARNESS, ">hdrchk.c" ) || die "Can't open hdrchk.c for writing";
print HARNESS "#include <stdio.h>\n";
print HARNESS "#include <stdarg.h>\n\n";
open( MAKEFILE, ">makefile" ) || die "Can't open makefile for writing";

#print MAKEFILE "CFLAGS = -g -I../../headers\n";
print MAKEFILE "OBJS = hdrchk.o ";

$select = "SELECT DISTINCT * FROM Architecture ";
$select .= "WHERE Aname!='All'";
print $select, "\n" if $trace;

$ath = $Dbh->query($select) || die $Dbh->errmsg();
for ( 1 .. $ath->numrows ) {
    %entry = $ath->fetchhash;
    print HARNESS "#if ",              $entry{'Asymbol'}, "\n";
    print HARNESS "int architecture=", $entry{'Aid'},     ";\n";
    print HARNESS "#define __found_arch__\n";
    print HARNESS "#endif\n";
}

print HARNESS "#ifndef __found_arch__\n";
print HARNESS "#error \"Unable to identify architecture\"\n";
print HARNESS "#endif\n\n";

print HARNESS "#ifdef TET_TEST\n\n";
print HARNESS "#include \"hdrchk_tet.h\"\n\n";
print HARNESS "#endif\n\n";

print HARNESS "Msg( char *f, ...)\n";
print HARNESS "{\n";
print HARNESS "va_list args;\n";
print HARNESS "va_start(args,f);\n";
print HARNESS "vfprintf(stderr, f, args);\n";
print HARNESS "va_end(args);\n";
print HARNESS "}\n\n";
print HARNESS "Log( char *f, ...)\n";
print HARNESS "{\n";
print HARNESS "/* Quietly drop extraneous messages when running in non TET mode */\n";
print HARNESS "}\n\n";
print HARNESS "int tcnt=0;\n\n";
print HARNESS "#ifndef TET_TEST\n\n";
print HARNESS "main()\n{\n";

open( TET_HDR, ">hdrchk_tet.h" ) || die "Can't open hdrchk_tet.h for writing";
print TET_HDR "#include <tet_api.h>\n\n";
print TET_HDR "#include \"testdefs.h\"\n\n";

print TET_HDR "static void startup(), cleanup();\n\n";
print TET_HDR "void (*tet_startup)() = NULL;\n";
print TET_HDR "void (*tet_cleanup)() = NULL;\n\n";
print TET_HDR "struct tet_testlist tet_testlist[] = {\n";

open( SUBDEFS, ">testdefs.h" ) || die "Can't open testdefs.h for writing";

$select = "SELECT DISTINCT * FROM Header ";
$select.= "WHERE (Happearedin is not NULL and Happearedin <= '$lsbversion' and Happearedin<>\'\') ";
$select.= "AND (Hwithdrawnin IS NULL OR Hwithdrawnin > '$lsbversion' ) ",
$select .= "ORDER BY Hname ";

#
# Dump out each header
#
$hth = $Dbh->query($select) || die $Dbh->errmsg();
for ( 1 .. $hth->numrows ) {
    %entry = $hth->fetchhash;
    if ( $entry{'Hid'} <= 228 || $entry{'Hid'} > 487 ) {
        writetest( $entry{'Hid'}, $entry{'Hname'} );
    }
}

#
# Dump out the fundamental types (Intrinsic types)
#
open( TESTS, ">intrinsic.c" ) || die "Can't open intrinsic.c for writing";

# Get Types
$select = "SELECT DISTINCT * FROM Type ";
$select .= "LEFT JOIN ArchType ON ATtid=Tid ";
$select .= "LEFT JOIN Architecture ON Aid=ATaid ";
$select .= "WHERE Ttype='Intrinsic' ";
$select .= "AND Tname!='...' ";
$select .= "ORDER BY Tid,ATaid";
$tth = $Dbh->query($select) || die $Dbh->errmsg();
if ( $tth->numrows == 0 ) {
    print TESTS "/*\n * No values in $Hname\n */\n";
    close(TESTS);
    return;
}

print MAKEFILE "\\\n\tintrinsic.o ";
print HARNESS "tcnt+=intrinsic();\n";

print TESTS "/*\n * Test of intrinsic types\n */\n";
print TESTS "#include \"hdrchk.h\"\n";
print TESTS "#include \<stdio.h\>\n";
print TESTS "#include \<sys/types.h\>\n";
print TESTS "#include \<complex.h\>\n";
print TESTS "\n\n\n";
print TESTS "#ifdef TET_TEST\n";
print TESTS "void intrinsic()\n{\n";
print TESTS "#else\n";
print TESTS "int intrinsic()\n{\n";
print TESTS "#endif\n";
print TESTS "int cnt=0;\n";
print TESTS "int pcnt=0;\n";
print TESTS "#ifdef TET_TEST\n";

#print TESTS "int pcnt=0;\n";
print TESTS "#endif\n\n";
print TESTS "printf(\"Checking Intrinsic types\\n\");\n";

$lastid = 0;
for ( 1 .. $tth->numrows ) {
    %tentry = $tth->fetchhash;

    # Do this before we reset the value, so we can re-use the values
    # from the last time through the loop if we need them
    #
    if ( $tentry{'Tname'} eq 'bool' ) {
        $lastid = 0;
    }

    if( $tentry{'Aid'}==1 && $tentry{'ATsize'}==0 ) {
    	$selectArchSpecific = "SELECT * FROM ArchType ";
    	$selectArchSpecific.= "WHERE ATaid<>1 ";
    	$selectArchSpecific.= "AND ATtid=".$tentry{'Tid'}; # do not check status here - the types are intrinsic
		$ath = $Dbh->query($selectArchSpecific) || die $Dbh->errmsg();
		if ( $ath->numrows != 0 ) {
			# arch specific records found - skip generic
			next;
		}
    }

    if ( $tentry{'Tid'} != $lastid ) {
        if ( $lastid != 0 ) {

            # We have output at least one type, and now we need to
            # put a catch-all else clause
            #
			$selectGeneric = "SELECT count(*) as cnt FROM ArchType ";
			$selectGeneric.= "WHERE ATtid=$Tid AND ATaid=1 ";
# 			$selectGeneric.= "AND ATappearedin<>'' AND ATappearedin <= '$lsbversion' ";
# 			$selectGeneric.= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin > '$lsbversion') ";
			$gth = $Dbh->query($selectGeneric) || die $Dbh->errmsg();
			%gentry = $gth->fetchhash;
			if ($gentry{'cnt'} > 0) {
				print TESTS "#else\n";
				print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
				print TESTS "%d,%d,%d,'\"\"\"\"',\"\"NULL\"\",0,NULL);\\n\",architecture,$Tid,0);\n";
				print TESTS "#endif\n\n";
			}
        }
        print TESTS "#if $tentry{'Asymbol'}\n" if $tentry{'Tname'} ne 'bool';
        $lastid = $tentry{'Tid'} if $tentry{'Tname'} ne 'bool';
    } else {
        print TESTS "#elif $tentry{'Asymbol'}\n";
    }
    $Tid    = $tentry{'Tid'};
    $ATsize = $tentry{'ATsize'};
    $Aid    = $tentry{'Aid'};
    $Tname  = $tentry{'Tname'};
    $ATbasetype  = $tentry{'ATbasetype'};
    $ATattribute = $tentry{'ATattribute'};

	$attribute = $ATattribute ? "'$ATattribute'" : "NULL";

    print TESTS "CheckTypeSize($Tname,$ATsize,$Tid,$Aid, \"\", \"NULL\",0,\"NULL\")\n"
		if $tentry{'Tname'} ne 'bool';
}
print TESTS "#else\n";
print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
print TESTS "%d,%d,%d,'\"\"\"\"',\"\"NULL\"\",0,\"\"NULL\"\");\\n\",architecture,$Tid,0);\n";
print TESTS "#endif\n\n";

print TESTS "#ifdef TET_TEST\n";
print TESTS "if (pcnt == cnt )\n";
print TESTS "\ttet_result(TET_PASS);\n";
print TESTS "else\n";
print TESTS "\ttet_result(TET_FAIL);\n";
print TESTS "return;\n";
print TESTS "#else\n";
print TESTS "printf(\"%d tests passed out of %d tests intrinsic types\\n\\n\",pcnt,cnt);\n";

#print TESTS "printf(\"%d intrinsic types\\n\",cnt);\n";
print TESTS "return cnt;\n";
print TESTS "#endif\n\n";
print TESTS "}\n";
close(TEST);

#
# Dump out the C++ types (Class types)
#
open( TESTS, "|c++filt |c++filt >cxx.C" ) || die "Can't open cxx.C for writing";

# Get Types
$select = "SELECT DISTINCT * FROM Type ";
$select .= "LEFT JOIN ArchType ON ATtid=Tid ";
$select .= "LEFT JOIN Architecture ON Aid=ATaid ";
$select .= "WHERE Ttype='Class' AND Theadgroup<669 ";
$select .= "AND ATappearedin <> '' AND ATappearedin <='$lsbversion' ";
$select .= "AND (ATwithdrawnin IS NULL OR ATwithdrawnin >'$lsbversion') ";
$select .= "ORDER BY Tname,ATaid";
$tth = $Dbh->query($select) || die $Dbh->errmsg();
if ( $tth->numrows == 0 ) {
    print TESTS "/*\n * No values in $Hname\n */\n";
    close(TESTS);
    return;
}

print MAKEFILE "\\\n\tcxx.o ";
print HARNESS "tcnt+=cxx();\n";

print TESTS "/*\n * Test of intrinsic types\n */\n";
print TESTS "#include <fstream>\n";
print TESTS "#include <ios>\n";
print TESTS "#include <istream>\n";
print TESTS "#include <iterator>\n";
print TESTS "#include <limits>\n";
print TESTS "#include <locale>\n";
print TESTS "#include <numeric>\n";
print TESTS "#include <stdexcept>\n";
print TESTS "#include <string>\n";
print TESTS "#include <sstream>\n";
print TESTS "#include <valarray>\n";
print TESTS "#include <vector>\n";
if( $lsbversion < '3.0' ) {
	print TESTS "#include <backward/strstream>\n";
}
print TESTS "#include <ext/stdio_filebuf.h>\n";
print TESTS "#include <cxxabi.h>\n";
print TESTS "#include \"hdrchk.h\"\n";
print TESTS "\n\n\n";
print TESTS "extern \"C\" {\n";
print TESTS "#ifdef TET_TEST\n";
print TESTS "void cxx();\n";
print TESTS "#else\n";
print TESTS "int cxx();\n";
print TESTS "#endif\n";
print TESTS "}\n\n";
print TESTS "#ifdef TET_TEST\n";
print TESTS "void cxx()\n{\n";
print TESTS "#else\n";
print TESTS "int cxx()\n{\n";
print TESTS "#endif\n";
print TESTS "int cnt=0;\n";
print TESTS "int pcnt=0;\n";
print TESTS "#ifdef TET_TEST\n";

#print TESTS "int pcnt=0;\n";
print TESTS "#endif\n\n";
print TESTS "printf(\"Checking C++ types\\n\");\n";

$lastid = 0;
for ( 1 .. $tth->numrows ) {
    %tentry = $tth->fetchhash;

	$condition = "elif"; # "elif"
	if ( $tentry{'Tid'} != $lastid ) {
		if ( $lastid != 0 ) {
			$condition = "endif";
		}
		$condition = "if";
	}

	if( $tentry{'Aid'} == 1 ) {
		$printedMsgs = checkArchSpecific($tentry{'Tname'},$tentry{'Tid'},$condition,$tentry{'Ttype'});
		if( $printedMsgs > 0 ) {
			$lastid = $tentry{'Tid'};
		}
		if( $printedMsgs != -1 ) {
			next;
		}
	}

    # Do this before we reset the value, so we can re-use the values
    # from the last time through the loop if we need them
    if ( $tentry{'Tid'} != $lastid ) {
        if ( $lastid != 0 ) {

            # We have output at least one type, and now we need to
            # put a catch-all else clause

            print TESTS "#else\n";
            $withdrawnin = $ATwithdrawnin ? "'\"\"$ATwithdrawnin\"\"'" : "NULL";
            $attribute = $ATattribute ? "'\"\"$ATattribute\"\"'" : "NULL";
            print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
            print TESTS "%d,%d,%d,'\"\"$ATappearedin\"\"',$withdrawnin,$ATbasetype,$attribute);\\n\",architecture,$Tid,0);\n";
            print TESTS "#endif\n\n";
        }

        # Hope the check for zero ATsize is temporary; but we have a lot of 'classes'
        # without any additional information (Qt classes) and their presence will break
        # devchk compilation
        if ( !$tentry{'Asymbol'} or $tentry{'ATsize'} == 0 ) {
            $tentry{'Asymbol'} = '0';
        }
        print TESTS "#if $tentry{'Asymbol'}\n";
        $lastid = $tentry{'Tid'};
    } else {
        print TESTS "#elif $tentry{'Asymbol'}\n";
    }
    $Tid    = $tentry{'Tid'};
    $ATsize = $tentry{'ATsize'};
    $Aid    = $tentry{'Aid'};
    $Tname  = $tentry{'Tname'};
    $ATappearedin  = $tentry{'ATappearedin'};
    $ATwithdrawnin = $tentry{'ATwithdrawnin'};
    $ATbasetype    = $tentry{'ATbasetype'};
    $ATattribute   = $tentry{'ATattribute'};

    # Unmangled types have commas, which confuse the preprocessor
    if( $Tname =~ "^_Z" ) {
       print TESTS "#define TYPE " . "$Tname\n";
    }
    else {
       print TESTS "#define TYPE _Z" . "$Tname\n";
    }
    $withdrawnin = $ATwithdrawnin ? "'$ATwithdrawnin'" : "NULL";
    $attribute = $ATattribute ? "'$ATattribute'" : "NULL";
    print TESTS "CheckTypeSize(TYPE,$ATsize,$Tid,$Aid, $ATappearedin, $withdrawnin, $ATbasetype, $attribute)\n";
    print TESTS "#undef TYPE\n";
}
$withdrawnin = $ATwithdrawnin ? "'\"\"$ATwithdrawnin\"\"'" : "NULL";
$attribute = $ATattribute ? "'\"\"$ATattribute\"\"'" : "NULL";
print TESTS "#else\n";
print TESTS "Msg(\"REPLACE INTO ArchType VALUES (";
print TESTS "%d,%d,%d,'\"\"$ATappearedin\"\"',$withdrawnin,$ATbasetype,$attribute);\\n\",architecture,$Tid,0);\n";
print TESTS "#endif\n\n";

print TESTS "#ifdef TET_TEST\n";
print TESTS "if (pcnt == cnt )\n";
print TESTS "\ttet_result(TET_PASS);\n";
print TESTS "else\n";
print TESTS "\ttet_result(TET_FAIL);\n";
print TESTS "return;\n";
print TESTS "#else\n";
print TESTS "printf(\"%d tests passed out of %d tests in C++ types\\n\\n\",pcnt,cnt);\n";

#print TESTS "printf(\"%d c++ types\\n\",cnt);\n";
print TESTS "return cnt;\n";
print TESTS "#endif\n\n";
print TESTS "}\n";
close(TEST);

#
# Finish up and close the files
#
print MAKEFILE "\n\n";
print MAKEFILE "ifdef TET_ROOT\n";
print MAKEFILE "LIBDIR = \$\(TET_ROOT)/lib/tet3\n";
print MAKEFILE "INCDIR = \$\(TET_ROOT)/inc/tet3\n";
print MAKEFILE "EXTRALIBS = \$\(LIBDIR)/tcm.o \$\(LIBDIR)/libapi.a\n";
print MAKEFILE "else\n";
print MAKEFILE "EXTRALIBS =\n";
print MAKEFILE "endif\n\n";

print MAKEFILE "# for LSB 3.2, must force the old 64-bit long double ABI for some arches\n";
print MAKEFILE "LDBL_FLAG:=\$(shell case `uname -m` in (ppc|ppc64|s390|s390x) echo \"-mlong-double-64\";; (*) echo ;; esac)\n\n";
print MAKEFILE "ifdef LSB_PRODUCT\n";
print MAKEFILE "CFLAGS=-DLSBCC_MODE -D_ISOC99_SOURCE -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -D_GNU_SOURCE -DXLIB_ILLEGAL_ACCESS -I/usr/X11R6/include -I/opt/lsb/include/glib-2.0 -I/opt/lsb/include/atk-1.0 -I/opt/lsb/include/pango-1.0 -I/opt/lsb/include/gtk-2.0 -I/opt/lsb/include/libxml2 -I/opt/lsb/include/fontconfig\n";
print MAKEFILE "else\n";
print MAKEFILE "CFLAGS=\$(LDBL_FLAG) -O -DQT_THREAD_SUPPORT -D_ISOC99_SOURCE -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -D_GNU_SOURCE -DXLIB_ILLEGAL_ACCESS -I/usr/X11R6/include -I/usr/include/glib-2.0 -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/gtk-2.0 -I/usr/include/freetype2 -I/usr/lib64/gtk-2.0/include -I/usr/lib/gtk-2.0/include -I/usr/lib64/glib-2.0/include -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -I/usr/include/fontconfig -I/usr/include/cairo -I/usr/lib64/qt3/include -I/usr/lib/qt3/include -I/usr/lib64/qt-3.3/include -I/usr/lib/qt-3.3/include -I/opt/gnome/include -I/opt/gnome/include/atk-1.0 -I/opt/gnome/include/glib-2.0 -I/opt/gnome/include/gtk-2.0 -I/opt/gnome/include/pango-1.0 -I/opt/gnome/lib64/glib-2.0/include -I/opt/gnome/lib/glib-2.0/include -I/opt/gnome/lib64/gtk-2.0/include -I/opt/gnome/lib/gtk-2.0/include\n\n";
print MAKEFILE "endif\n\n";
print MAKEFILE "CXXFLAGS = \$\(CFLAGS)\n\n";

print MAKEFILE "ifdef TET_ROOT\n";
print MAKEFILE "CFLAGS += -DTET_TEST -I\$\(INCDIR)\n";
print MAKEFILE "endif\n\n";

print MAKEFILE "all: hdrchk\n\n";
print MAKEFILE "hdrchk: \$\(OBJS)\n";
print MAKEFILE "\t\$(CXX) -o hdrchk \$(OBJS) \$(EXTRALIBS) -L /usr/X11R6/lib64 -L/usr/X11R6/lib -L/usr/lib/qt3/lib64 -L/usr/lib/qt3/lib -L/usr/lib64/qt-3.3/lib -L/usr/lib/qt-3.3/lib -lXt -lX11 -lncurses -lqt-mt -lrt\n";
print MAKEFILE "\n";
print MAKEFILE "hdrchk.o: hdrchk.c\n";
print MAKEFILE "\t\$(CC) \$\(CFLAGS) -g -c hdrchk.c\n";
print MAKEFILE "\n\n";
print MAKEFILE "hdrchk.c:\n";
print MAKEFILE "\t./mktests -v `cat LSB_VERSION`\n";
print MAKEFILE "\n\n";
print MAKEFILE "install:\n";
print MAKEFILE "\n\n";
print MAKEFILE "clean:\n\trm -f \$\(OBJS) hdrchk\n\n";
print MAKEFILE "clobber:\tclean\n";
print MAKEFILE "\trm -f *.c hdrchk_tet.h testdefs.h\n";
print MAKEFILE "\n\n";
print MAKEFILE "distclean:\tclobber\n";
close(MAKEFILE);

print HARNESS "printf(\"Total Tests: %d\\n\", tcnt );\n";
print HARNESS "}\n";
print HARNESS "#endif\n";
close(HARNESS);

print TET_HDR "\t{ NULL, 0 }\n";
print TET_HDR "};\n";
close(TET_HDR);
close(SUBDEFS);


