mirror of
https://github.com/samba-team/samba.git
synced 2025-11-23 20:23:50 +03:00
472 lines
11 KiB
Perl
472 lines
11 KiB
Perl
###################################################
|
|
# create C header files for an IDL structure
|
|
# Copyright tridge@samba.org 2000
|
|
# Copyright jelmer@samba.org 2005
|
|
# released under the GNU GPL
|
|
|
|
package NdrHeader;
|
|
|
|
use strict;
|
|
use pidl::typelist;
|
|
|
|
my($res);
|
|
my($tab_depth);
|
|
|
|
sub pidl ($)
|
|
{
|
|
$res .= shift;
|
|
}
|
|
|
|
sub tabs()
|
|
{
|
|
for (my($i)=0; $i < $tab_depth; $i++) {
|
|
pidl "\t";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a properties list
|
|
sub HeaderProperties($$)
|
|
{
|
|
my($props,$ignores) = @_;
|
|
my $ret = "";
|
|
|
|
foreach my $d (keys %{$props}) {
|
|
next if (grep(/^$d$/, @$ignores));
|
|
if($props->{$d} ne "1") {
|
|
$ret.= "$d($props->{$d}),";
|
|
} else {
|
|
$ret.="$d,";
|
|
}
|
|
}
|
|
|
|
if ($ret) {
|
|
pidl "/* [" . substr($ret, 0, -1) . "] */";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a structure element
|
|
sub HeaderElement($)
|
|
{
|
|
my($element) = shift;
|
|
|
|
pidl tabs();
|
|
HeaderType($element, $element->{TYPE}, "");
|
|
pidl " ";
|
|
my $prefix = "";
|
|
my $postfix = "";
|
|
foreach my $l (@{$element->{LEVELS}})
|
|
{
|
|
if (($l->{TYPE} eq "POINTER")) {
|
|
my $nl = Ndr::GetNextLevel($element, $l);
|
|
$nl = Ndr::GetNextLevel($element, $nl) if ($nl->{TYPE} eq "SUBCONTEXT");
|
|
next if ($nl->{TYPE} eq "DATA" and typelist::scalar_is_reference($nl->{DATA_TYPE}));
|
|
$prefix .= "*";
|
|
} elsif ($l->{TYPE} eq "ARRAY") {
|
|
my $pl = Ndr::GetPrevLevel($element, $l);
|
|
next if ($pl and $pl->{TYPE} eq "POINTER");
|
|
|
|
if ($l->{IS_FIXED}) {
|
|
$postfix .= "[$l->{SIZE_IS}]";
|
|
} else {
|
|
$prefix .= "*";
|
|
}
|
|
} elsif ($l->{TYPE} eq "DATA") {
|
|
pidl "$prefix$element->{NAME}$postfix";
|
|
}
|
|
}
|
|
|
|
if (defined $element->{ARRAY_LEN}[0] && util::is_constant($element->{ARRAY_LEN}[0])) {
|
|
pidl "[$element->{ARRAY_LEN}[0]]";
|
|
}
|
|
pidl ";";
|
|
if (defined $element->{PROPERTIES}) {
|
|
HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
|
|
}
|
|
pidl "\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a struct
|
|
sub HeaderStruct($$)
|
|
{
|
|
my($struct,$name) = @_;
|
|
pidl "\nstruct $name {\n";
|
|
$tab_depth++;
|
|
my $el_count=0;
|
|
if (defined $struct->{ELEMENTS}) {
|
|
foreach my $e (@{$struct->{ELEMENTS}}) {
|
|
HeaderElement($e);
|
|
$el_count++;
|
|
}
|
|
}
|
|
if ($el_count == 0) {
|
|
# some compilers can't handle empty structures
|
|
pidl "\tchar _empty_;\n";
|
|
}
|
|
$tab_depth--;
|
|
pidl "}";
|
|
if (defined $struct->{PROPERTIES}) {
|
|
HeaderProperties($struct->{PROPERTIES}, []);
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a enum
|
|
sub HeaderEnum($$)
|
|
{
|
|
my($enum,$name) = @_;
|
|
my $first = 1;
|
|
|
|
if (not util::useUintEnums()) {
|
|
pidl "\nenum $name {\n";
|
|
$tab_depth++;
|
|
foreach my $e (@{$enum->{ELEMENTS}}) {
|
|
unless ($first) { pidl ",\n"; }
|
|
$first = 0;
|
|
tabs();
|
|
pidl $e;
|
|
}
|
|
pidl "\n";
|
|
$tab_depth--;
|
|
pidl "}";
|
|
} else {
|
|
my $count = 0;
|
|
pidl "\nenum $name { __donnot_use_enum_$name=0x7FFFFFFF};\n";
|
|
my $with_val = 0;
|
|
my $without_val = 0;
|
|
foreach my $e (@{$enum->{ELEMENTS}}) {
|
|
my $t = "$e";
|
|
my $name;
|
|
my $value;
|
|
if ($t =~ /(.*)=(.*)/) {
|
|
$name = $1;
|
|
$value = $2;
|
|
$with_val = 1;
|
|
die ("you can't mix enum member with values and without values when using --uint-enums!")
|
|
unless ($without_val == 0);
|
|
} else {
|
|
$name = $t;
|
|
$value = $count++;
|
|
$without_val = 1;
|
|
die ("you can't mix enum member with values and without values when using --uint-enums!")
|
|
unless ($with_val == 0);
|
|
}
|
|
pidl "#define $name ( $value )\n";
|
|
}
|
|
pidl "\n";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a bitmap
|
|
sub HeaderBitmap($$)
|
|
{
|
|
my($bitmap,$name) = @_;
|
|
|
|
pidl "\n/* bitmap $name */\n";
|
|
|
|
foreach my $e (@{$bitmap->{ELEMENTS}})
|
|
{
|
|
pidl "#define $e\n";
|
|
}
|
|
|
|
pidl "\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a union
|
|
sub HeaderUnion($$)
|
|
{
|
|
my($union,$name) = @_;
|
|
my %done = ();
|
|
|
|
pidl "\nunion $name {\n";
|
|
$tab_depth++;
|
|
foreach my $e (@{$union->{ELEMENTS}}) {
|
|
if ($e->{TYPE} ne "EMPTY") {
|
|
if (! defined $done{$e->{NAME}}) {
|
|
HeaderElement($e);
|
|
}
|
|
$done{$e->{NAME}} = 1;
|
|
}
|
|
}
|
|
$tab_depth--;
|
|
pidl "}";
|
|
|
|
if (defined $union->{PROPERTIES}) {
|
|
HeaderProperties($union->{PROPERTIES}, []);
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a type
|
|
sub HeaderType($$$)
|
|
{
|
|
my($e,$data,$name) = @_;
|
|
if (ref($data) eq "HASH") {
|
|
($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
|
|
($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
|
|
($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
|
|
($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
|
|
return;
|
|
}
|
|
|
|
if (util::has_property($e, "charset")) {
|
|
pidl "const char";
|
|
} else {
|
|
pidl typelist::mapType($e->{TYPE});
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a typedef
|
|
sub HeaderTypedef($)
|
|
{
|
|
my($typedef) = shift;
|
|
HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
|
|
pidl ";\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
|
|
}
|
|
|
|
#####################################################################
|
|
# prototype a typedef
|
|
sub HeaderTypedefProto($)
|
|
{
|
|
my($d) = shift;
|
|
|
|
my $tf = NdrParser::get_typefamily($d->{DATA}{TYPE});
|
|
|
|
if (util::has_property($d, "gensize")) {
|
|
my $size_args = $tf->{SIZE_FN_ARGS}->($d);
|
|
pidl "size_t ndr_size_$d->{NAME}($size_args);\n";
|
|
}
|
|
|
|
return unless util::has_property($d, "public");
|
|
|
|
my $pull_args = $tf->{PULL_FN_ARGS}->($d);
|
|
my $push_args = $tf->{PUSH_FN_ARGS}->($d);
|
|
my $print_args = $tf->{PRINT_FN_ARGS}->($d);
|
|
unless (util::has_property($d, "nopush")) {
|
|
pidl "NTSTATUS ndr_push_$d->{NAME}($push_args);\n";
|
|
}
|
|
unless (util::has_property($d, "nopull")) {
|
|
pidl "NTSTATUS ndr_pull_$d->{NAME}($pull_args);\n";
|
|
}
|
|
unless (util::has_property($d, "noprint")) {
|
|
pidl "void ndr_print_$d->{NAME}($print_args);\n";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a const
|
|
sub HeaderConst($)
|
|
{
|
|
my($const) = shift;
|
|
if (!defined($const->{ARRAY_LEN}[0])) {
|
|
pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
|
|
} else {
|
|
pidl "#define $const->{NAME}\t $const->{VALUE}\n";
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a function
|
|
sub HeaderFunctionInOut($$)
|
|
{
|
|
my($fn,$prop) = @_;
|
|
|
|
foreach my $e (@{$fn->{ELEMENTS}}) {
|
|
if (util::has_property($e, $prop)) {
|
|
HeaderElement($e);
|
|
}
|
|
}
|
|
}
|
|
|
|
#####################################################################
|
|
# determine if we need an "in" or "out" section
|
|
sub HeaderFunctionInOut_needed($$)
|
|
{
|
|
my($fn,$prop) = @_;
|
|
|
|
if ($prop eq "out" && $fn->{RETURN_TYPE}) {
|
|
return 1;
|
|
}
|
|
|
|
foreach my $e (@{$fn->{ELEMENTS}}) {
|
|
if (util::has_property($e, $prop)) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
my %headerstructs = ();
|
|
|
|
#####################################################################
|
|
# parse a function
|
|
sub HeaderFunction($)
|
|
{
|
|
my($fn) = shift;
|
|
|
|
return if ($headerstructs{$fn->{NAME}});
|
|
|
|
$headerstructs{$fn->{NAME}} = 1;
|
|
|
|
pidl "\nstruct $fn->{NAME} {\n";
|
|
$tab_depth++;
|
|
my $needed = 0;
|
|
|
|
if (HeaderFunctionInOut_needed($fn, "in")) {
|
|
tabs();
|
|
pidl "struct {\n";
|
|
$tab_depth++;
|
|
HeaderFunctionInOut($fn, "in");
|
|
$tab_depth--;
|
|
tabs();
|
|
pidl "} in;\n\n";
|
|
$needed++;
|
|
}
|
|
|
|
if (HeaderFunctionInOut_needed($fn, "out")) {
|
|
tabs();
|
|
pidl "struct {\n";
|
|
$tab_depth++;
|
|
HeaderFunctionInOut($fn, "out");
|
|
if ($fn->{RETURN_TYPE}) {
|
|
tabs();
|
|
pidl typelist::mapType($fn->{RETURN_TYPE}) . " result;\n";
|
|
}
|
|
$tab_depth--;
|
|
tabs();
|
|
pidl "} out;\n\n";
|
|
$needed++;
|
|
}
|
|
|
|
if (! $needed) {
|
|
# sigh - some compilers don't like empty structures
|
|
tabs();
|
|
pidl "int _dummy_element;\n";
|
|
}
|
|
|
|
$tab_depth--;
|
|
pidl "};\n\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# output prototypes for a IDL function
|
|
sub HeaderFnProto($$)
|
|
{
|
|
my ($interface,$fn) = @_;
|
|
my $name = $fn->{NAME};
|
|
|
|
pidl "void ndr_print_$name(struct ndr_print *ndr, const char *name, int flags, const struct $name *r);\n";
|
|
|
|
if (defined($fn->{OPNUM})) {
|
|
pidl "NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
|
|
pidl "struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
|
|
}
|
|
|
|
return unless util::has_property($fn, "public");
|
|
|
|
pidl "NTSTATUS ndr_push_$name(struct ndr_push *ndr, int flags, const struct $name *r);\n";
|
|
pidl "NTSTATUS ndr_pull_$name(struct ndr_pull *ndr, int flags, struct $name *r);\n";
|
|
|
|
pidl "\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse the interface definitions
|
|
sub HeaderInterface($)
|
|
{
|
|
my($interface) = shift;
|
|
|
|
my $count = 0;
|
|
|
|
pidl "#ifndef _HEADER_NDR_$interface->{NAME}\n";
|
|
pidl "#define _HEADER_NDR_$interface->{NAME}\n\n";
|
|
|
|
if (defined $interface->{PROPERTIES}->{depends}) {
|
|
my @d = split / /, $interface->{PROPERTIES}->{depends};
|
|
foreach my $i (@d) {
|
|
pidl "#include \"librpc/gen_ndr/ndr_$i\.h\"\n";
|
|
}
|
|
}
|
|
|
|
if (defined $interface->{PROPERTIES}->{uuid}) {
|
|
my $name = uc $interface->{NAME};
|
|
pidl "#define DCERPC_$name\_UUID " .
|
|
util::make_str($interface->{PROPERTIES}->{uuid}) . "\n";
|
|
|
|
if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
|
|
pidl "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}\n";
|
|
|
|
pidl "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n";
|
|
|
|
if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
|
|
pidl "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}\n";
|
|
|
|
pidl "\nextern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
|
|
pidl "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);\n\n";
|
|
}
|
|
|
|
foreach my $d (@{$interface->{FUNCTIONS}}) {
|
|
next if not defined($d->{OPNUM});
|
|
my $u_name = uc $d->{NAME};
|
|
pidl "#define DCERPC_$u_name (";
|
|
|
|
if (defined($interface->{BASE})) {
|
|
pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
|
|
}
|
|
|
|
if ($d->{OPNUM} != $count) {
|
|
die ("Function ".$d->{NAME}." has: wrong opnum [".$d->{OPNUM}."] should be [".$count."]");
|
|
}
|
|
|
|
pidl sprintf("0x%02x", $count) . ")\n";
|
|
$count++;
|
|
}
|
|
|
|
pidl "\n#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT (";
|
|
|
|
if (defined($interface->{BASE})) {
|
|
pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
|
|
}
|
|
|
|
pidl "$count)\n\n";
|
|
|
|
foreach my $d (@{$interface->{CONSTS}}) {
|
|
HeaderConst($d);
|
|
}
|
|
|
|
foreach my $d (@{$interface->{TYPEDEFS}}) {
|
|
HeaderTypedef($d);
|
|
HeaderTypedefProto($d);
|
|
}
|
|
|
|
foreach my $d (@{$interface->{FUNCTIONS}}) {
|
|
HeaderFunction($d);
|
|
HeaderFnProto($interface, $d);
|
|
}
|
|
|
|
pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n";
|
|
}
|
|
|
|
#####################################################################
|
|
# parse a parsed IDL into a C header
|
|
sub Parse($)
|
|
{
|
|
my($idl) = shift;
|
|
$tab_depth = 0;
|
|
|
|
$res = "";
|
|
pidl "/* header auto-generated by pidl */\n\n";
|
|
foreach my $x (@{$idl}) {
|
|
($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
1;
|