r5465: Add support to multiple levels of pointers in pidl.
authorJelmer Vernooij <jelmer@samba.org>
Sun, 20 Feb 2005 02:57:38 +0000 (02:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:10:48 +0000 (13:10 -0500)
Also add a new function to echo.idl that tests this behaviour.
(This used to be commit e5eb5e847e75f2b7b041a66f84d9b919ddf27739)

source4/build/pidl/ndr.pm
source4/build/pidl/validator.pm
source4/librpc/idl/echo.idl
source4/rpc_server/echo/rpc_echo.c
source4/torture/rpc/echo.c

index 2d885ca455d006518ac7854b871c67efb5ba479b..4f78ca6888ccb98cdf82437fa1f206479abdce09 100644 (file)
@@ -170,7 +170,10 @@ sub need_wire_pointer($)
        my $n = $e->{POINTERS};
        my $pt = pointer_type($e);
 
-       if (defined($pt) and $pt eq "ref") {
+       if (    defined($pt) 
+               and $pt eq "ref" 
+               and $e->{PARENT}->{TYPE} eq "FUNCTION") 
+       {
                $n--;
        }
 
@@ -182,11 +185,8 @@ sub need_wire_pointer($)
 sub is_pure_scalar($)
 {
        my $e = shift;
-       if (util::has_property($e, "ref")) {
-               return 1;
-       }
        if (is_scalar_type($e->{TYPE}) && 
-           !$e->{POINTERS} && 
+           need_wire_pointer($e) == 0 && 
            !util::array_size($e)) {
                return 1;
        }
@@ -198,17 +198,19 @@ sub need_alloc($)
 {
        my $e = shift;
 
-       if (util::has_property($e, "ref")) {
-               return 0;
-       }
-
-       if ($e->{POINTERS} || util::array_size($e)) {
-               return 1;
-       }
-
+       return 0 if (util::has_property($e, "ref"));
+       return 1 if ($e->{POINTERS} || util::array_size($e));
        return 0;
 }
 
+sub c_ptr_prefix($)
+{
+       my $e = shift;
+       my $pointers = "";
+       foreach my $i (need_wire_pointer($e)..$e->{POINTERS}-1) { $pointers.="*"; }
+       return $pointers;
+}
+
 # determine the C prefix used to refer to a variable when passing to a push
 # function. This will be '*' for pointers to scalar types, '' for scalar
 # types and normal pointers and '&' for pass-by-reference structures
@@ -216,20 +218,22 @@ sub c_push_prefix($)
 {
        my $e = shift;
 
-       if ($e->{TYPE} =~ "string") {
-               return "";
-       }
+       my $ret = "";
 
-       if (is_scalar_type($e->{TYPE}) &&
+       if ($e->{TYPE} =~ "string") {
+               $ret = "";
+       } elsif (is_scalar_type($e->{TYPE}) &&
            $e->{POINTERS}) {
-               return "*";
-       }
-       if (!is_scalar_type($e->{TYPE}) &&
+               $ret = "*";
+       } elsif (!is_scalar_type($e->{TYPE}) &&
            !$e->{POINTERS} &&
            !util::array_size($e)) {
                return "&";
        }
-       return "";
+
+       foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
+       
+       return $ret;
 }
 
 # determine the C prefix used to refer to a variable when passing to a pull
@@ -246,7 +250,9 @@ sub c_pull_prefix($)
                return "&";
        }
 
-       return "";
+       my $ret = "";
+       foreach my $i (2..$e->{POINTERS}) { $ret.="*"; }
+       return $ret;
 }
 my $res = "";
 my $tabs = "";
@@ -488,10 +494,9 @@ sub ParseArrayPrint($$)
        my $e = shift;
        my $var_prefix = shift;
        my $size = ParseExpr($e, util::array_size($e), $var_prefix);
-       my $length = util::has_property($e, "length_is");
 
-       if (defined $length) {
-               $size = ParseExpr($e, $length, $var_prefix);
+       if (is_varying_array($e)) {
+               $size = ParseExpr($e, util::has_property($e, "length_is"), $var_prefix);
        }
 
        if (is_scalar_type($e->{TYPE})) {
@@ -508,8 +513,7 @@ sub CheckArraySizes($$)
        my $e = shift;
        my $var_prefix = shift;
 
-       if (!is_surrounding_array($e) && 
-               is_conformant_array($e)) {
+       if (!is_surrounding_array($e) && is_conformant_array($e)) {
                my $size = ParseExpr($e, util::array_size($e), $var_prefix);
                pidl "if ($var_prefix$e->{NAME}) {";
                indent;
@@ -592,12 +596,13 @@ sub ParseArrayPull($$$)
                }
        }
 
-       if (my $length = util::has_property($e, "length_is")) {
+       if (is_varying_array($e)) {
                pidl "NDR_CHECK(ndr_pull_array_length(ndr, &$var_prefix$e->{NAME}));";
                $size = "ndr_get_array_length(ndr, &$var_prefix$e->{NAME})";
        }
 
        check_null_pointer($size);
+
        if (is_scalar_type($e->{TYPE})) {
                pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));";
        } else {
@@ -613,6 +618,7 @@ sub ParseElementPushScalar($$$)
        my($var_prefix) = shift;
        my($ndr_flags) = shift;
        my $cprefix = c_push_prefix($e);
+       my $ptr_prefix = c_ptr_prefix($e);
        my $sub_size = util::has_property($e, "subcontext");
 
        start_flags($e);
@@ -622,11 +628,11 @@ sub ParseElementPushScalar($$$)
        }
 
        if (util::has_property($e, "relative")) {
-               pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));";
+               pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $ptr_prefix$var_prefix$e->{NAME}));";
+       } elsif (need_wire_pointer($e)) {
+               ParseElementPushPtr($e, $ptr_prefix.$var_prefix, "NDR_SCALARS");
        } elsif (is_inline_array($e)) {
                ParseArrayPush($e, "r->", "NDR_SCALARS");
-       } elsif (need_wire_pointer($e)) {
-               ParseElementPushPtr($e, $var_prefix, $ndr_flags);
        } elsif (need_alloc($e)) {
                # no scalar component
        } elsif (my $switch = util::has_property($e, "switch_is")) {
@@ -659,6 +665,7 @@ sub ParseElementPrint($$)
        my($e) = shift;
        my($var_prefix) = shift;
        my $cprefix = c_push_prefix($e);
+       my $ptr_prefix = c_ptr_prefix($e);
 
        return if (util::has_property($e, "noprint"));
 
@@ -670,13 +677,16 @@ sub ParseElementPrint($$)
                pidl "}";
        }
 
-       if (!is_fixed_array($e) and ($e->{POINTERS} or util::array_size($e))) {
+       my $l = $e->{POINTERS};
+       $l++ if (util::array_size($e) and $l == 0 and !is_fixed_array($e));
+
+       foreach my $i (1..$l) {
                pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});";
                pidl "ndr->depth++;";
-       }
-       if (need_wire_pointer($e)) {
-               pidl "if ($var_prefix$e->{NAME}) {";
-               indent;
+               if ($i > $l-need_wire_pointer($e)) {
+                       pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {";
+                       indent;
+               }
        }
 
        if (util::array_size($e)) {
@@ -690,11 +700,11 @@ sub ParseElementPrint($$)
                pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});";
        }
 
-       if (need_wire_pointer($e)) {
-               deindent;
-               pidl "}";
-       }
-       if (!is_fixed_array($e) and ($e->{POINTERS} or util::array_size($e))) {
+       foreach my $i (1..$l) {
+               if ($i > $l-need_wire_pointer($e)) {
+                       deindent;
+                       pidl "}";
+               }
                pidl "ndr->depth--;";
        }
 }
@@ -804,6 +814,7 @@ sub ParseElementPullScalar($$$)
        my($var_prefix) = shift;
        my($ndr_flags) = shift;
        my $cprefix = c_pull_prefix($e);
+       my $ptr_prefix = c_ptr_prefix($e);
        my $sub_size = util::has_property($e, "subcontext");
 
        start_flags($e);
@@ -811,9 +822,8 @@ sub ParseElementPullScalar($$$)
        if (is_inline_array($e)) {
                ParseArrayPull($e, "r->", "NDR_SCALARS");
        } elsif (need_wire_pointer($e)) {
-               ParseElementPullPtr($e, $var_prefix, $ndr_flags);
-       } elsif (need_alloc($e)) {
-               # no scalar component
+               ParseElementPullPtr($e, $ptr_prefix.$var_prefix, "NDR_SCALARS");
+       } elsif (is_surrounding_array($e)) {
        } elsif (my $switch = util::has_property($e, "switch_is")) {
                ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch);
        } elsif (defined $sub_size) {
@@ -821,6 +831,7 @@ sub ParseElementPullScalar($$$)
        } else {
                pidl "NDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
        }
+
        if (my $range = util::has_property($e, "range")) {
                my ($low, $high) = split(/ /, $range, 2);
                pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {";
@@ -862,18 +873,22 @@ sub ParseElementPushBuffer($$$)
        my $cprefix = c_push_prefix($e);
        my $sub_size = util::has_property($e, "subcontext");
 
-       if (is_pure_scalar($e)) {
-               return;
-       }
+       return if (is_pure_scalar($e));
 
        start_flags($e);
 
-       if (need_wire_pointer($e)) {
-               pidl "if ($var_prefix$e->{NAME}) {";
-               indent;
-               if (util::has_property($e, "relative")) {
-                       pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
+       my $pointers = c_ptr_prefix($e);
+       for my $i (1..need_wire_pointer($e)) {
+               if ($i > 1) {
+                       ParseElementPushPtr($e,$pointers.$var_prefix,$ndr_flags);
                }
+               pidl "if ($pointers$var_prefix$e->{NAME}) {";
+               indent;
+               $pointers.="*";
+       }
+               
+       if (util::has_property($e, "relative")) {
+               pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
        }
            
        if (is_inline_array($e)) {
@@ -896,10 +911,10 @@ sub ParseElementPushBuffer($$$)
                pidl "NDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
        }
 
-       if (need_wire_pointer($e)) {
+       for my $i (1..need_wire_pointer($e)) {
                deindent;
                pidl "}";
-       }       
+       }
 
        end_flags($e);
 }
@@ -914,22 +929,26 @@ sub ParseElementPullBuffer($$$)
        my $cprefix = c_pull_prefix($e);
        my $sub_size = util::has_property($e, "subcontext");
 
-       if (is_pure_scalar($e)) {
-               return;
-       }
+       return if (is_pure_scalar($e));
 
        start_flags($e);
 
-       if (need_wire_pointer($e)) {
-               pidl "if ($var_prefix$e->{NAME}) {";
-               indent;
-               if (util::has_property($e, "relative")) {
-                       pidl "struct ndr_pull_save _relative_save;";
-                       pidl "ndr_pull_save(ndr, &_relative_save);";
-                       pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
-               }
-       }
-           
+       my $pointers = c_ptr_prefix($e);
+       for my $i (1..need_wire_pointer($e)) {
+               if ($i > 1) {
+                       ParseElementPullPtr($e,$pointers.$var_prefix,"NDR_SCALARS");
+               }
+               pidl "if ($pointers$var_prefix$e->{NAME}) {";
+               indent;
+               $pointers.="*";
+       }
+       if (util::has_property($e, "relative")) {
+               pidl "struct ndr_pull_save _relative_save;";
+               pidl "ndr_pull_save(ndr, &_relative_save);";
+               pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));";
+       }
+           
        if (is_inline_array($e)) {
                ParseArrayPull($e, "r->", "NDR_BUFFERS");
        } elsif (util::array_size($e)) {
@@ -950,13 +969,13 @@ sub ParseElementPullBuffer($$$)
                pidl "NDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));";
        }
 
-       if (need_wire_pointer($e)) {
-               if (util::has_property($e, "relative")) {
-                       pidl "ndr_pull_restore(ndr, &_relative_save);";
-               }
+       if (util::has_property($e, "relative")) {
+               pidl "ndr_pull_restore(ndr, &_relative_save);";
+       }
+       for my $i (1..need_wire_pointer($e)) {
                deindent;
                pidl "}";
-       }       
+       }
 
        end_flags($e);
 }
@@ -1710,7 +1729,7 @@ sub ParseFunctionElementPush($$)
        } else {
                ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
 
-               if ($e->{POINTERS}) {
+               if (need_wire_pointer($e)) {
                        ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
                }
        }
@@ -1769,14 +1788,12 @@ sub ParseFunctionElementPull($$)
                        pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));";
                        pidl "r->$inout.$e->{NAME} = NULL;";
                        pidl "if (_ptr_$e->{NAME}) {";
-                       indent;
                } elsif ($inout eq "out" && util::has_property($e, "ref")) {
                        pidl "if (r->$inout.$e->{NAME}) {";
-                       indent;
                } else {
                        pidl "{";
-                       indent;
                }
+               indent;
                ParseArrayPull($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
                deindent;
                pidl "}";
@@ -1786,12 +1803,13 @@ sub ParseFunctionElementPull($$)
                        pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});";
                        pidl "}";
                }
+
                if ($inout eq "in" && util::has_property($e, "ref")) {
                        pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});";
                }
 
                ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
-               if ($e->{POINTERS}) {
+               if (need_wire_pointer($e)) {
                        ParseElementPullBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS");
                }
        }
@@ -2175,3 +2193,4 @@ sub Parse($$)
 RegisterPrimitives();
 
 1;
+
index c61c89392b6e3da4822fd9ffee70ce51bac4c35b..cf7df0dcb24abd9d2c5e373142cd46d5de9f0f03 100644 (file)
@@ -40,10 +40,6 @@ sub el_name($)
 sub ValidElement($)
 {
        my $e = shift;
-       if ($e->{POINTERS} && $e->{POINTERS} > 1) {
-               fatal(el_name($e) . " : pidl cannot handle multiple pointer levels. Use a sub-structure containing a pointer instead\n");
-       }
-
        if ($e->{POINTERS} && $e->{ARRAY_LEN}) {
                fatal(el_name($e) . " : pidl cannot handle pointers to arrays. Use a substructure instead\n");
        }
index c0a694389821b38f85f299003c49a423418047a5..612cdb319e29215d588634dc325b9e4f70747b4c 100644 (file)
@@ -128,4 +128,6 @@ interface rpcecho
        void echo_TestSurrounding(
                [in,out,ref] echo_Surrounding *data
        );
+
+       uint16 echo_TestDoublePointer([in,ref] uint16 ***data);
 }
index a2d2e552d6979440f53ebc03fd9095d2bb0ce62f..daf16e12d7eb5727a339c68eb1ff3cf24ab3282f 100644 (file)
@@ -151,6 +151,15 @@ static NTSTATUS echo_TestSurrounding(struct dcesrv_call_state *dce_call, TALLOC_
        return NT_STATUS_OK;
 }
 
+static uint16_t echo_TestDoublePointer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestDoublePointer *r) 
+{
+       if (!*r->in.data) 
+               return 0;
+       if (!**r->in.data)
+               return 0;
+       return ***r->in.data;
+}
+
 static long echo_TestSleep(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestSleep *r)
 {
        struct echo_TestSleep_private *p;
index 35df96c89707fb2e293c787bdce82b94fb5f1b8d..8ef0b00eb252ed80784aa35ec46177eac2d0e7f6 100644 (file)
@@ -352,6 +352,49 @@ static BOOL test_surrounding(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
        return ret;
 }
 
+/*
+  test multiple levels of pointers
+*/
+static BOOL test_doublepointer(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+{
+       NTSTATUS status;
+       struct echo_TestDoublePointer r;
+       BOOL ret = True;
+       uint16_t value = 12;
+       uint16_t *pvalue = &value;
+       uint16_t **ppvalue = &pvalue;
+
+       ZERO_STRUCT(r);
+       r.in.data = &ppvalue;
+
+       printf("\nTesting TestDoublePointer\n");
+       status = dcerpc_echo_TestDoublePointer(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("TestDoublePointer failed - %s\n", nt_errstr(status));
+               ret = False;
+       }
+
+       if (value != r.out.result) {
+               printf("TestSurrounding did not return original value\n");
+               ret = False;
+       }
+
+       pvalue = NULL;
+
+       status = dcerpc_echo_TestDoublePointer(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("TestDoublePointer failed - %s\n", nt_errstr(status));
+               ret = False;
+       }
+
+       if (r.out.result != 0) {
+               printf("TestSurrounding did not return 0 when passed a NULL pointer\n");
+               ret = False;
+       }
+
+       return ret;
+}
+
 BOOL torture_rpc_echo(void)
 {
        NTSTATUS status;
@@ -377,6 +420,7 @@ BOOL torture_rpc_echo(void)
        ret &= test_testcall2(p, mem_ctx);
        ret &= test_enum(p, mem_ctx);
        ret &= test_surrounding(p, mem_ctx);
+       ret &= test_doublepointer(p, mem_ctx);
        ret &= test_sleep(p, mem_ctx);
 
        printf("\n");