r5475: Move some existing and new type information functions to typelist.pm
[samba.git] / source4 / build / pidl / header.pm
index 25f0fecd47fe130b60c1ee64b30b56187650114e..803916a79c2234104aeb70a587c8decc6ddd525c 100644 (file)
@@ -6,37 +6,46 @@
 package IdlHeader;
 
 use strict;
-use Data::Dumper;
+use needed;
+use typelist;
 
 my($res);
 my($tab_depth);
-my $if_uuid;
-my $if_version;
+
+sub pidl ($)
+{
+       $res .= shift;
+}
 
 sub tabs()
 {
        for (my($i)=0; $i < $tab_depth; $i++) {
-               $res .= "\t";
+               pidl "\t";
        }
 }
 
 #####################################################################
 # parse a properties list
-sub HeaderProperties($)
+sub HeaderProperties($$)
 {
     my($props) = shift;
+       my($ignores) = shift;
+       my $ret = "";
+
+       return; 
+
+    foreach my $d (keys %{$props}) {
+               next if ($ignores->{$d});
+               if($props->{$d} ne "1") {
+                       $ret.= "$d(" . $props->{$d} . "),";
+               } else {
+                       $ret.="$d,";
+               }
+       }
 
-    return;
-
-    foreach my $d (@{$props}) {
-       if (ref($d) ne "HASH") {
-           $res .= "/* [$d] */ ";
-       } else {
-           foreach my $k (keys %{$d}) {
-               $res .= "/* [$k($d->{$k})] */ ";
-           }
+       if ($ret) {
+               pidl "/* [" . substr($ret, 0, -1) . "] */";
        }
-    }
 }
 
 #####################################################################
@@ -45,28 +54,30 @@ sub HeaderElement($)
 {
     my($element) = shift;
 
-    (defined $element->{PROPERTIES}) && HeaderProperties($element->{PROPERTIES});
-    $res .= tabs();
+    if (defined $element->{PROPERTIES}) {
+               HeaderProperties($element->{PROPERTIES}, {"in" => 1, "out" => 1});
+       }
+    pidl tabs();
     HeaderType($element, $element->{TYPE}, "");
-    $res .= " ";
-    if ($element->{POINTERS} && 
-       $element->{TYPE} ne "string") {
+    pidl " ";
+    if ($element->{POINTERS} && $element->{TYPE} ne "string") {
            my($n) = $element->{POINTERS};
            for (my($i)=$n; $i > 0; $i--) {
-                   $res .= "*";
+                   pidl "*";
            }
     }
     if (defined $element->{ARRAY_LEN} && 
-       !util::is_constant($element->{ARRAY_LEN})) {
+       !util::is_constant($element->{ARRAY_LEN}) &&
+       !$element->{POINTERS}) {
            # conformant arrays are ugly! I choose to implement them with
            # pointers instead of the [1] method
-           $res .= "*";
+           pidl "*";
     }
-    $res .= "$element->{NAME}";
+    pidl "$element->{NAME}";
     if (defined $element->{ARRAY_LEN} && util::is_constant($element->{ARRAY_LEN})) {
-           $res .= "[$element->{ARRAY_LEN}]";
+           pidl "[$element->{ARRAY_LEN}]";
     }
-    $res .= ";\n";
+    pidl ";\n";
 }
 
 #####################################################################
@@ -75,41 +86,93 @@ sub HeaderStruct($$)
 {
     my($struct) = shift;
     my($name) = shift;
-    $res .= "struct $name {\n";
+    pidl "\nstruct $name {\n";
     $tab_depth++;
+    my $el_count=0;
     if (defined $struct->{ELEMENTS}) {
-       foreach my $e (@{$struct->{ELEMENTS}}) {
-           HeaderElement($e);
-       }
+               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--;
-    $res .= "}";
+    pidl "}";
 }
 
+#####################################################################
+# parse a enum
+sub HeaderEnum($$)
+{
+    my($enum) = shift;
+    my($name) = shift;
+
+    pidl "\nenum $name {\n";
+    $tab_depth++;
+    my $els = \@{$enum->{ELEMENTS}};
+    foreach my $i (0 .. $#{$els}-1) {
+           my $e = ${$els}[$i];
+           tabs();
+           chomp $e;
+           pidl "$e,\n";
+    }
+
+    my $e = ${$els}[$#{$els}];
+    tabs();
+    chomp $e;
+    if ($e !~ /^(.*?)\s*$/) {
+           die "Bad enum $name\n";
+    }
+    pidl "$1\n";
+    $tab_depth--;
+    pidl "}";
+}
 
 #####################################################################
-# parse a union element
-sub HeaderUnionElement($)
+# parse a bitmap
+sub HeaderBitmap($$)
 {
-    my($element) = shift;
-    $res .= "/* [case($element->{CASE})] */ ";
-    if ($element->{TYPE} eq "UNION_ELEMENT") {
-           HeaderElement($element->{DATA});
+    my($bitmap) = shift;
+    my($name) = shift;
+
+    pidl "\n/* bitmap $name */\n";
+
+    my $els = \@{$bitmap->{ELEMENTS}};
+    foreach my $i (0 .. $#{$els}) {
+           my $e = ${$els}[$i];
+           chomp $e;
+           pidl "#define $e\n";
     }
+
+    pidl "\n";
 }
 
 #####################################################################
 # parse a union
 sub HeaderUnion($$)
 {
-    my($union) = shift;
-    my($name) = shift;
-    (defined $union->{PROPERTIES}) && HeaderProperties($union->{PROPERTIES});
-    $res .= "union $name {\n";
-    foreach my $e (@{$union->{DATA}}) {
-       HeaderUnionElement($e);
-    }
-    $res .= "}";
+       my($union) = shift;
+       my($name) = shift;
+       my %done = ();
+
+       if (defined $union->{PROPERTIES}) {
+               HeaderProperties($union->{PROPERTIES}, {});
+       }
+       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 "}";
 }
 
 #####################################################################
@@ -120,21 +183,18 @@ sub HeaderType($$$)
        my($data) = shift;
        my($name) = shift;
        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 ($data =~ "string") {
-               $res .= "const char *";
-       } elsif (util::is_scalar_type($data)) {
-               $res .= "$data";
-       } elsif (util::has_property($e, "switch_is")) {
-               $res .= "union $data";
-       } else {
-               $res .= "struct $data";
-       }
+
+       pidl typelist::mapType($e);
 }
 
 #####################################################################
@@ -143,7 +203,48 @@ sub HeaderTypedef($)
 {
     my($typedef) = shift;
     HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
-    $res .= ";\n\n";
+    pidl ";\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
+}
+
+#####################################################################
+# prototype a typedef
+sub HeaderTypedefProto($)
+{
+    my($d) = shift;
+
+    if (needed::is_needed("ndr_size_$d->{NAME}")) {
+           if ($d->{DATA}{TYPE} eq "STRUCT") {
+                   pidl "size_t ndr_size_$d->{NAME}(const struct $d->{NAME} *r, int flags);\n";
+           }
+           if ($d->{DATA}{TYPE} eq "UNION") {
+                   pidl "size_t ndr_size_$d->{NAME}(const union $d->{NAME} *r, uint32_t level, int flags);\n";
+           }
+    }
+
+    return unless util::has_property($d, "public");
+
+       my $tf = NdrParser::get_typefamily($d->{DATA}{TYPE});
+
+       my $pull_args = $tf->{PULL_FN_ARGS}->($d);
+       my $push_args = $tf->{PUSH_FN_ARGS}->($d);
+       my $print_args = $tf->{PRINT_FN_ARGS}->($d);
+       pidl "NTSTATUS ndr_push_$d->{NAME}($push_args);\n";
+    pidl "NTSTATUS ndr_pull_$d->{NAME}($pull_args);\n";
+    if (!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})) {
+       pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
+    } else {
+       pidl "#define $const->{NAME}\t $const->{VALUE}\n";
+    }
 }
 
 #####################################################################
@@ -152,43 +253,119 @@ sub HeaderFunctionInOut($$)
 {
     my($fn) = shift;
     my($prop) = shift;
-    foreach my $e (@{$fn->{DATA}}) {
+
+    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) = shift;
+    my($prop) = shift;
+
+    if ($prop eq "out" && $fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
+           return 1;
+    }
+
+    foreach my $e (@{$fn->{ELEMENTS}}) {
+           if (util::has_property($e, $prop)) {
+                   return 1;
+           }
+    }
+
+    return undef;
+}
+
 
 #####################################################################
 # parse a function
 sub HeaderFunction($)
 {
     my($fn) = shift;
-    $res .= "struct $fn->{NAME} {\n";
-    $tab_depth++;
-    tabs();
-    $res .= "struct {\n";
-    $tab_depth++;
-    HeaderFunctionInOut($fn, "in");
-    $tab_depth--;
-    tabs();
-    $res .= "} in;\n\n";
-    tabs();
-    $res .= "struct {\n";
+
+    pidl "\nstruct $fn->{NAME} {\n";
     $tab_depth++;
-    HeaderFunctionInOut($fn, "out");
-    if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
+    my $needed = 0;
+
+    if (HeaderFunctionInOut_needed($fn, "in")) {
+           tabs();
+           pidl "struct {\n";
+           $tab_depth++;
+           HeaderFunctionInOut($fn, "in");
+           $tab_depth--;
            tabs();
-           $res .= "$fn->{RETURN_TYPE} result;\n";
+           pidl "} in;\n\n";
+           $needed++;
     }
+
+    if (HeaderFunctionInOut_needed($fn, "out")) {
+           tabs();
+           pidl "struct {\n";
+           $tab_depth++;
+           HeaderFunctionInOut($fn, "out");
+           if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
+                   tabs();
+                   pidl typelist::mapScalarType($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--;
-    tabs();
-    $res .= "} out;\n\n";
-    $tab_depth--;
-    $res .= "};\n\n";
+    pidl "};\n\n";
+}
+
+#####################################################################
+# output prototypes for a IDL function
+sub HeaderFnProto($$)
+{
+       my $interface = shift;
+    my $fn = shift;
+    my $name = $fn->{NAME};
+       
+    pidl "void ndr_print_$name(struct ndr_print *ndr, const char *name, int flags, struct $name *r);\n";
+
+       if (util::has_property($interface, "object")) {
+               pidl "NTSTATUS dcom_$interface->{NAME}_$name (struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r);\n";
+       } else {
+           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";
+       }
+    pidl "\n";
+}
+
+
+#####################################################################
+# generate vtable structure for DCOM interface
+sub HeaderVTable($)
+{
+       my $interface = shift;
+       pidl "struct dcom_$interface->{NAME}_vtable {\n";
+       if (defined($interface->{BASE})) {
+               pidl "\tstruct dcom_$interface->{BASE}\_vtable base;\n";
+       }
+
+       my $data = $interface->{DATA};
+       foreach my $d (@{$data}) {
+               pidl "\tNTSTATUS (*$d->{NAME}) (struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $d->{NAME} *r);\n" if ($d->{TYPE} eq "FUNCTION");
+       }
+       pidl "};\n\n";
 }
 
+
 #####################################################################
 # parse the interface definitions
 sub HeaderInterface($)
@@ -198,43 +375,74 @@ sub HeaderInterface($)
 
     my $count = 0;
 
-    if (defined $if_uuid) {
+    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};
-           $res .= "#define DCERPC_$name\_UUID \"$if_uuid\"\n";
-           $res .= "#define DCERPC_$name\_VERSION $if_version\n";
-           $res .= "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n\n";
+           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 (@{$data}) {
            if ($d->{TYPE} eq "FUNCTION") {
                    my $u_name = uc $d->{NAME};
-                   $res .= "#define DCERPC_$u_name $count\n";
+                       pidl "#define DCERPC_$u_name (";
+               
+                       if (defined($interface->{BASE})) {
+                               pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
+                       }
+                       
+                   pidl sprintf("0x%02x", $count) . ")\n";
                    $count++;
            }
     }
 
-    $res .= "\n\n";
+       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 (@{$data}) {
+       ($d->{TYPE} eq "CONST") &&
+           HeaderConst($d);
        ($d->{TYPE} eq "TYPEDEF") &&
            HeaderTypedef($d);
-       ($d->{TYPE} eq "FUNCTION") && 
+       ($d->{TYPE} eq "TYPEDEF") &&
+           HeaderTypedefProto($d);
+       ($d->{TYPE} eq "FUNCTION") &&
            HeaderFunction($d);
+       ($d->{TYPE} eq "FUNCTION") &&
+           HeaderFnProto($interface, $d);
     }
+       
+       (util::has_property($interface, "object")) &&
+               HeaderVTable($interface);
 
+    pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n";
 }
 
-#####################################################################
-# parse the interface definitions
-sub ModuleHeader($)
-{
-    my($h) = shift;
-
-    $if_uuid = $h->{PROPERTIES}->{uuid};
-    $if_version = $h->{PROPERTIES}->{version};
-}
-
-
 #####################################################################
 # parse a parsed IDL into a C header
 sub Parse($)
@@ -242,13 +450,15 @@ sub Parse($)
     my($idl) = shift;
     $tab_depth = 0;
 
-    $res = "/* header auto-generated by pidl */\n\n";
-    foreach my $x (@{$idl}) {
-       ($x->{TYPE} eq "MODULEHEADER") && 
-           ModuleHeader($x);
+       NdrParser::Load($idl);
 
-       ($x->{TYPE} eq "INTERFACE") && 
-           HeaderInterface($x);
+       $res = "";
+    pidl "/* header auto-generated by pidl */\n\n";
+    foreach my $x (@{$idl}) {
+           if ($x->{TYPE} eq "INTERFACE") {
+                   needed::BuildNeeded($x);
+                   HeaderInterface($x);
+           }
     }
     return $res;
 }