###################################################
# Samba4 parser generator for IDL structures
# Copyright jelmer@samba.org 2005
# released under the GNU GPL

package typelist;

use strict;

my %typedefs = ();

sub addType($)
{
	my $t = shift;
	$typedefs{$t->{NAME}} = $t;
}

sub getType($)
{
	my $t = shift;
	return undef unless(defined($typedefs{$t}));
	return $typedefs{$t};
}

sub typeIs($$)
{
	my $t = shift;
	my $tt = shift;

	return 1 if (hasType($t) and getType($t)->{DATA}->{TYPE} eq $tt);
	return 0;
}

sub hasType($)
{
	my $t = shift;
	return 1 if defined($typedefs{$t});
	return 0;
}

sub RegisterPrimitives()
{
	my @primitives = (
		"char", "int8", "uint8", "short", "wchar_t", 
		"int16", "uint16", "long", "int32", "uint32", 
		"dlong", "udlong", "udlongr", "NTTIME", "NTTIME_1sec", 
		"time_t", "DATA_BLOB", "error_status_t", "WERROR", 
		"NTSTATUS", "boolean32", "unsigned32", "ipv4address", 
		"hyper", "NTTIME_hyper");
		
	foreach my $k (@primitives) {
		$typedefs{$k} = {
			NAME => $k,
			TYPE => "TYPEDEF",
			DATA => {
				TYPE => "SCALAR",
				NAME => $k
			}
		};
	}
}

sub enum_type_fn($)
{
	my $enum = shift;
	if (util::has_property($enum->{PARENT}, "enum8bit")) {
		return "uint8";
	} elsif (util::has_property($enum->{PARENT}, "v1_enum")) {
		return "uint32";
	}
	return "uint16";
}

sub bitmap_type_fn($)
{
	my $bitmap = shift;

	if (util::has_property($bitmap, "bitmap8bit")) {
		return "uint8";
	} elsif (util::has_property($bitmap, "bitmap16bit")) {
		return "uint16";
	} elsif (util::has_property($bitmap, "bitmap64bit")) {
		return "uint64";
	}
	return "uint32";
}

# provide mappings between IDL base types and types in our headers
my %scalar_type_mappings = 
    (
     "int8"         => "int8_t",
     "uint8"        => "uint8_t",
     "short"        => "int16_t",
     "wchar_t"      => "uint16_t",
     "int16"        => "int16_t",
     "uint16"       => "uint16_t",
     "int32"        => "int32_t",
     "uint32"       => "uint32_t",
     "int64"        => "int64_t",
     "uint64"       => "uint64_t",
     "dlong"        => "int64_t",
     "udlong"       => "uint64_t",
     "udlongr"      => "uint64_t",
     "hyper"        => "uint64_t",
     "NTTIME_1sec"  => "NTTIME",
     "NTTIME_hyper" => "NTTIME",
     "ipv4address"  => "const char *",
     "nbt_string"   => "const char *"
     );

# map from a IDL type to a C header type
sub mapScalarType($)
{
	my $name = shift;
	if (my $ret = $scalar_type_mappings{$name}) {
		return $ret;
	}
	return $name;
}

sub mapType($)
{
	my $e = shift;
	my $dt;

	return "const char *" if ($e->{TYPE} =~ "string");

	if ($e->{TYPE} eq "ENUM" or $e->{TYPE} eq "BITMAP") {
		$dt = getType($e->{PARENT}->{NAME});
	}
	
	unless ($dt or $dt = getType($e->{TYPE})) {
		# Best guess
		return "struct $e->{TYPE}";
	}
	return mapScalarType($e->{TYPE}) if ($dt->{DATA}->{TYPE} eq "SCALAR");
	return "enum $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "ENUM");
	return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "STRUCT");
	return "struct $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "INTERFACE");
	return "union $dt->{NAME}" if ($dt->{DATA}->{TYPE} eq "UNION");
	return mapScalarType(bitmap_type_fn($dt->{DATA})) if ($dt->{DATA}->{TYPE} eq "BITMAP");

	die("Unknown type $dt->{DATA}->{TYPE}");
}

sub LoadIdl($)
{
	my $idl = shift;

	foreach my $x (@{$idl}) {
		next if $x->{TYPE} ne "INTERFACE";

		# DCOM interfaces can be types as well
		addType({
			NAME => $x->{NAME},
			TYPE => "TYPEDEF",
			DATA => $x
			}) if (util::has_property($x, "object"));

		foreach my $y (@{$x->{DATA}}) {
			addType($y) if (
				$y->{TYPE} eq "TYPEDEF" 
			 or $y->{TYPE} eq "DECLARE");
		}
	}
}

RegisterPrimitives();


1;
