pidl:Python: improve the .doc string for the get/set elements
[samba.git] / pidl / lib / Parse / Pidl / Samba4 / Python.pm
index 2ace7a0d0619de2d05a3b34e5e5d6fd4810a13ff..c72d8fe34ec7dc59b2a157143a983c8783817e2f 100644 (file)
@@ -224,7 +224,7 @@ sub PythonStruct($$$$$$)
                        if ($l->{TYPE} eq "POINTER" and
                                not ($nl->{TYPE} eq "ARRAY" and ($nl->{IS_FIXED} or is_charset_array($e, $nl))) and
                                not ($nl->{TYPE} eq "DATA" and Parse::Pidl::Typelist::scalar_is_reference($nl->{DATA_TYPE}))) {
-                               $self->pidl("talloc_unlink(pytalloc_get_mem_ctx(py_obj), discard_const($varname));");
+                               $self->pidl("talloc_unlink($mem_ctx, discard_const($varname));");
                        }
                        $self->ConvertObjectFromPython($env, $mem_ctx, $e, "value", $varname, "return -1;");
                        $self->pidl("return 0;");
@@ -237,9 +237,16 @@ sub PythonStruct($$$$$$)
                $self->pidl("static PyGetSetDef ".$getsetters."[] = {");
                $self->indent;
                foreach my $e (@{$d->{ELEMENTS}}) {
-                       $self->pidl("{ discard_const_p(char, \"$e->{NAME}\"), py_$name\_get_$e->{NAME}, py_$name\_set_$e->{NAME} },");
+                       $self->pidl("{");
+                       $self->indent;
+                       $self->pidl(".name = discard_const_p(char, \"$e->{NAME}\"),");
+                       $self->pidl(".get = py_$name\_get_$e->{NAME},");
+                       $self->pidl(".set = py_$name\_set_$e->{NAME},");
+                       $self->pidl(".doc = discard_const_p(char, \"PIDL-generated element of base type $e->{TYPE}\")");
+                       $self->deindent;
+                       $self->pidl("},");
                }
-               $self->pidl("{ NULL }");
+               $self->pidl("{ .name = NULL }");
                $self->deindent;
                $self->pidl("};");
                $self->pidl("");
@@ -262,17 +269,28 @@ sub PythonStruct($$$$$$)
                $self->pidl("{");
                $self->indent;
                $self->pidl("$cname *object = ($cname *)pytalloc_get_ptr(py_obj);");
+               $self->pidl("PyObject *ret = NULL;");
                $self->pidl("DATA_BLOB blob;");
                $self->pidl("enum ndr_err_code err;");
-               $self->pidl("err = ndr_push_struct_blob(&blob, pytalloc_get_mem_ctx(py_obj), object, (ndr_push_flags_fn_t)ndr_push_$name);");
-               $self->pidl("if (err != NDR_ERR_SUCCESS) {");
+               $self->pidl("TALLOC_CTX *tmp_ctx = talloc_new(pytalloc_get_mem_ctx(py_obj));");
+               $self->pidl("if (tmp_ctx == NULL) {");
                $self->indent;
+               $self->pidl("PyErr_SetNdrError(NDR_ERR_ALLOC);");
+               $self->pidl("return NULL;");
+               $self->deindent;
+               $self->pidl("}");
+               $self->pidl("err = ndr_push_struct_blob(&blob, tmp_ctx, object, (ndr_push_flags_fn_t)ndr_push_$name);");
+               $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(err)) {");
+               $self->indent;
+               $self->pidl("TALLOC_FREE(tmp_ctx);");
                $self->pidl("PyErr_SetNdrError(err);");
                $self->pidl("return NULL;");
                $self->deindent;
                $self->pidl("}");
                $self->pidl("");
-               $self->pidl("return PyString_FromStringAndSize((char *)blob.data, blob.length);");
+               $self->pidl("ret = PyString_FromStringAndSize((char *)blob.data, blob.length);");
+               $self->pidl("TALLOC_FREE(tmp_ctx);");
+               $self->pidl("return ret;");
                $self->deindent;
                $self->pidl("}");
                $self->pidl("");
@@ -282,7 +300,7 @@ sub PythonStruct($$$$$$)
                $self->indent;
                $self->pidl("$cname *object = ($cname *)pytalloc_get_ptr(py_obj);");
                $self->pidl("DATA_BLOB blob;");
-               $self->pidl("int blob_length = 0;");
+               $self->pidl("Py_ssize_t blob_length = 0;");
                $self->pidl("enum ndr_err_code err;");
                $self->pidl("const char * const kwnames[] = { \"data_blob\", \"allow_remaining\", NULL };");
                $self->pidl("PyObject *allow_remaining_obj = NULL;");
@@ -315,7 +333,7 @@ sub PythonStruct($$$$$$)
                $self->pidl("err = ndr_pull_struct_blob_all(&blob, pytalloc_get_mem_ctx(py_obj), object, (ndr_pull_flags_fn_t)ndr_pull_$name);");
                $self->deindent;
                $self->pidl("}");
-               $self->pidl("if (err != NDR_ERR_SUCCESS) {");
+               $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(err)) {");
                $self->indent;
                $self->pidl("PyErr_SetNdrError(err);");
                $self->pidl("return NULL;");
@@ -348,7 +366,7 @@ sub PythonStruct($$$$$$)
                $self->indent;
                $self->pidl("{ \"__ndr_pack__\", (PyCFunction)py_$name\_ndr_pack, METH_NOARGS, \"S.ndr_pack(object) -> blob\\nNDR pack\" },");
                $self->pidl("{ \"__ndr_unpack__\", (PyCFunction)py_$name\_ndr_unpack, METH_VARARGS|METH_KEYWORDS, \"S.ndr_unpack(class, blob, allow_remaining=False) -> None\\nNDR unpack\" },");
-               $self->pidl("{ \"__ndr_print__\", (PyCFunction)py_$name\_ndr_print, METH_VARARGS, \"S.ndr_print(object) -> None\\nNDR print\" },");
+               $self->pidl("{ \"__ndr_print__\", (PyCFunction)py_$name\_ndr_print, METH_NOARGS, \"S.ndr_print(object) -> None\\nNDR print\" },");
                $self->pidl("{ NULL, NULL, 0, NULL }");
                $self->deindent;
                $self->pidl("};");
@@ -369,15 +387,16 @@ sub PythonStruct($$$$$$)
        }
        $self->pidl(".tp_methods = $py_methods,");
        $self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,");
-       $self->pidl(".tp_basicsize = sizeof(pytalloc_Object),");
        $self->pidl(".tp_new = py_$name\_new,");
        $self->deindent;
        $self->pidl("};");
 
        $self->pidl("");
 
-       my $talloc_typename = $self->import_type_variable("talloc", "Object");
-       $self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;", ""]);
+       my $talloc_typename = $self->import_type_variable("talloc", "BaseObject");
+       $self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;",
+                                            "$name\_Type.tp_basicsize = pytalloc_BaseObject_size();",
+                                            ""]);
 
        return "&$typeobject";
 }
@@ -551,6 +570,12 @@ sub PythonFunctionPackIn($$$)
                        my $val = "PyList_GET_SIZE($py_var)";
                        if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
                                $self->pidl("r->in.$e->{NAME} = talloc_ptrtype(r, r->in.$e->{NAME});");
+                               $self->pidl("if (r->in.$e->{NAME} == NULL) {");
+                               $self->indent;
+                               $self->pidl("PyErr_NoMemory();");
+                               $self->pidl($fail);
+                               $self->deindent;
+                               $self->pidl("}");
                                $self->pidl("*r->in.$e->{NAME} = $val;");
                        } else {
                                $self->pidl("r->in.$e->{NAME} = $val;");
@@ -803,7 +828,6 @@ sub Interface($$$)
                $self->indent;
                $self->pidl("PyObject_HEAD_INIT(NULL) 0,");
                $self->pidl(".tp_name = \"$basename.$interface->{NAME}\",");
-               $self->pidl(".tp_basicsize = sizeof(pytalloc_Object),");
                $self->pidl(".tp_doc = $docstring,");
                $self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,");
                $self->pidl(".tp_new = syntax_$interface->{NAME}_new,");
@@ -814,7 +838,9 @@ sub Interface($$$)
 
                $self->register_module_typeobject("abstract_syntax", "&$syntax_typename");
                my $ndr_typename = $self->import_type_variable("samba.dcerpc.misc", "ndr_syntax_id");
-               $self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;", ""]);
+               $self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;",
+                                                    "$syntax_typename.tp_basicsize = pytalloc_BaseObject_size();",
+                                                    ""]);
        }
 
        $self->pidl_hdr("\n");
@@ -940,6 +966,55 @@ sub assign($$$)
        }
 }
 
+sub ConvertStringFromPythonData($$$$$)
+{
+       my ($self, $mem_ctx, $py_var, $target, $fail) = @_;
+
+       $self->pidl("{");
+       $self->indent;
+       $self->pidl("const char *test_str;");
+       $self->pidl("const char *talloc_str;");
+       $self->pidl("PyObject *unicode = NULL;");
+       $self->pidl("if (PyUnicode_Check($py_var)) {");
+       $self->indent;
+       # FIXME: Use Unix charset setting rather than utf-8
+       $self->pidl("unicode = PyUnicode_AsEncodedString($py_var, \"utf-8\", \"ignore\");");
+       $self->pidl("if (unicode == NULL) {");
+       $self->indent;
+       $self->pidl("PyErr_NoMemory();");
+       $self->pidl("$fail");
+       $self->deindent;
+       $self->pidl("}");
+
+       $self->pidl("test_str = PyString_AS_STRING(unicode);");
+       $self->deindent;
+       $self->pidl("} else if (PyString_Check($py_var)) {");
+       $self->indent;
+       $self->pidl("test_str = PyString_AS_STRING($py_var);");
+       $self->deindent;
+       $self->pidl("} else {");
+       $self->indent;
+       $self->pidl("PyErr_Format(PyExc_TypeError, \"Expected string or unicode object, got %s\", Py_TYPE($py_var)->tp_name);");
+       $self->pidl("$fail");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("talloc_str = talloc_strdup($mem_ctx, test_str);");
+       $self->pidl("if (unicode != NULL) {");
+       $self->indent;
+       $self->pidl("Py_DECREF(unicode);");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("if (talloc_str == NULL) {");
+       $self->indent;
+       $self->pidl("PyErr_NoMemory();");
+       $self->pidl("$fail");
+       $self->deindent;
+       $self->pidl("}");
+       $self->pidl("$target = talloc_str;");
+       $self->deindent;
+       $self->pidl("}");
+}
+
 sub ConvertObjectFromPythonData($$$$$$;$)
 {
        my ($self, $mem_ctx, $cvar, $ctype, $target, $fail, $location) = @_;
@@ -958,21 +1033,21 @@ sub ConvertObjectFromPythonData($$$$$$;$)
        my $ctype_alias = "";
        my $uint_max = "";
        if ($actual_ctype->{TYPE} eq "ENUM") {
-               # Importantly, ENUM values are unsigned in pidl, and
-               # typically map to uint32
-               $ctype_alias = enum_type_fn($actual_ctype);
+               # Importantly, ENUM values are unsigned in pidl, and
+               # typically map to uint32
+               $ctype_alias = enum_type_fn($actual_ctype);
        } elsif ($actual_ctype->{TYPE} eq "BITMAP") {
-               $ctype_alias = bitmap_type_fn($actual_ctype);
+               $ctype_alias = bitmap_type_fn($actual_ctype);
        } elsif ($actual_ctype->{TYPE} eq "SCALAR") {
-               $ctype_alias = expandAlias($actual_ctype->{NAME});
+               $ctype_alias = expandAlias($actual_ctype->{NAME});
        }
 
        # This is the unsigned Python Integer -> C integer validation
-       # case.  The signed case is below.
+       # case.  The signed case is below.
        if ($ctype_alias  =~ /^(uint[0-9]*|hyper|udlong|udlongr
-                                |NTTIME_hyper|NTTIME|NTTIME_1sec
-                                |uid_t|gid_t)$/x) {
-               $self->pidl("{");
+                               |NTTIME_hyper|NTTIME|NTTIME_1sec
+                               |uid_t|gid_t)$/x) {
+               $self->pidl("{");
                $self->indent;
                $self->pidl("const unsigned long long uint_max = ndr_sizeof2uintmax(sizeof($target));");
                $self->pidl("if (PyLong_Check($cvar)) {");
@@ -1023,7 +1098,7 @@ sub ConvertObjectFromPythonData($$$$$$;$)
        # above, so while it looks like a duplicate, it is not
        # actually a duplicate.
        if ($ctype_alias  =~ /^(dlong|char|int[0-9]*|time_t)$/x) {
-               $self->pidl("{");
+               $self->pidl("{");
                $self->indent;
                $self->pidl("const long long int_max = ndr_sizeof2intmax(sizeof($target));");
                $self->pidl("const long long int_min = -int_max - 1;");
@@ -1094,33 +1169,17 @@ sub ConvertObjectFromPythonData($$$$$$;$)
        }
 
        if ($actual_ctype->{TYPE} eq "SCALAR" and
-               ($actual_ctype->{NAME} eq "string" or $actual_ctype->{NAME} eq "nbt_string" or $actual_ctype->{NAME} eq "nbt_name" or $actual_ctype->{NAME} eq "wrepl_nbt_name")) {
-               $self->pidl("$target = talloc_strdup($mem_ctx, PyString_AS_STRING($cvar));");
-               return;
-       }
-
-       if ($actual_ctype->{TYPE} eq "SCALAR" and ($actual_ctype->{NAME} eq "dns_string" or $actual_ctype->{NAME} eq "dns_name")) {
-               $self->pidl("$target = talloc_strdup($mem_ctx, PyString_AS_STRING($cvar));");
-               return;
-       }
-
-       if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "ipv4address") {
-               $self->pidl("$target = PyString_AS_STRING($cvar);");
-               return;
-       }
-
-       if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "ipv6address") {
-               $self->pidl("$target = PyString_AsString($cvar);");
-               return;
-       }
-
-       if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "dnsp_name") {
-               $self->pidl("$target = PyString_AS_STRING($cvar);");
-               return;
-       }
-
-       if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "dnsp_string") {
-               $self->pidl("$target = PyString_AS_STRING($cvar);");
+               ($actual_ctype->{NAME} eq "string"
+                or $actual_ctype->{NAME} eq "nbt_string"
+                or $actual_ctype->{NAME} eq "nbt_name"
+                or $actual_ctype->{NAME} eq "wrepl_nbt_name"
+                or $actual_ctype->{NAME} eq "dns_string"
+                or $actual_ctype->{NAME} eq "dnsp_string"
+                or $actual_ctype->{NAME} eq "dns_name"
+                or $actual_ctype->{NAME} eq "ipv4address"
+                or $actual_ctype->{NAME} eq "ipv6address"
+                or $actual_ctype->{NAME} eq "dnsp_name")) {
+               $self->ConvertStringFromPythonData($mem_ctx, $cvar, $target, $fail);
                return;
        }
 
@@ -1165,6 +1224,14 @@ sub ConvertObjectFromPythonLevel($$$$$$$$)
                $pl = GetPrevLevel($e, $pl);
        }
 
+        $self->pidl("if ($py_var == NULL) {");
+        $self->indent;
+        $self->pidl("PyErr_Format(PyExc_AttributeError, \"Cannot delete NDR object: " .
+                    mapTypeName($var_name) . "\");");
+        $self->pidl($fail);
+        $self->deindent;
+        $self->pidl("}");
+
        if ($l->{TYPE} eq "POINTER") {
                if ($l->{POINTER_TYPE} ne "ref") {
                        $self->pidl("if ($py_var == Py_None) {");
@@ -1178,9 +1245,21 @@ sub ConvertObjectFromPythonLevel($$$$$$$$)
                # then this is where we would need to allocate it
                if ($l->{POINTER_TYPE} eq "ref") {
                        $self->pidl("$var_name = talloc_ptrtype($mem_ctx, $var_name);");
+                       $self->pidl("if ($var_name == NULL) {");
+                       $self->indent;
+                       $self->pidl("PyErr_NoMemory();");
+                       $self->pidl($fail);
+                       $self->deindent;
+                       $self->pidl("}");
                } elsif ($nl->{TYPE} eq "DATA" and Parse::Pidl::Typelist::is_scalar($nl->{DATA_TYPE})
                         and not Parse::Pidl::Typelist::scalar_is_reference($nl->{DATA_TYPE})) {
                        $self->pidl("$var_name = talloc_ptrtype($mem_ctx, $var_name);");
+                       $self->pidl("if ($var_name == NULL) {");
+                       $self->indent;
+                       $self->pidl("PyErr_NoMemory();");
+                       $self->pidl($fail);
+                       $self->deindent;
+                       $self->pidl("}");
                } else {
                        $self->pidl("$var_name = NULL;");
                }
@@ -1198,21 +1277,7 @@ sub ConvertObjectFromPythonLevel($$$$$$$$)
                }
 
                if (is_charset_array($e, $l)) {
-                       $self->pidl("if (PyUnicode_Check($py_var)) {");
-                       $self->indent;
-                       # FIXME: Use Unix charset setting rather than utf-8
-                       $self->pidl($var_name . " = PyString_AS_STRING(PyUnicode_AsEncodedString($py_var, \"utf-8\", \"ignore\"));");
-                       $self->deindent;
-                       $self->pidl("} else if (PyString_Check($py_var)) {");
-                       $self->indent;
-                       $self->pidl($var_name . " = PyString_AS_STRING($py_var);");
-                       $self->deindent;
-                       $self->pidl("} else {");
-                       $self->indent;
-                       $self->pidl("PyErr_Format(PyExc_TypeError, \"Expected string or unicode object, got %s\", Py_TYPE($py_var)->tp_name);");
-                       $self->pidl("$fail");
-                       $self->deindent;
-                       $self->pidl("}");
+                       $self->ConvertStringFromPythonData($mem_ctx, $py_var, $var_name, $fail);
                } else {
                        my $counter = "$e->{NAME}_cntr_$l->{LEVEL_INDEX}";
                        $self->pidl("PY_CHECK_TYPE(&PyList_Type, $py_var, $fail);");
@@ -1280,11 +1345,11 @@ sub ConvertScalarToPython($$$)
        $ctypename = expandAlias($ctypename);
 
        if ($ctypename =~ /^(int64|dlong)$/) {
-               return "($cvar > LONG_MAX || $cvar < LONG_MIN) ? PyLong_FromLongLong($cvar) : PyInt_FromLong($cvar)";
+               return "ndr_PyLong_FromLongLong($cvar)";
        }
 
        if ($ctypename =~ /^(uint64|hyper|NTTIME_hyper|NTTIME|NTTIME_1sec|udlong|udlongr|uid_t|gid_t)$/) {
-               return "$cvar > LONG_MAX ? PyLong_FromUnsignedLongLong($cvar) : PyInt_FromLong($cvar)";
+               return "ndr_PyLong_FromUnsignedLongLong($cvar)";
        }
 
        if ($ctypename =~ /^(char|int|int8|int16|int32|time_t)$/) {
@@ -1296,7 +1361,7 @@ sub ConvertScalarToPython($$$)
        # possibly 64 bit unsigned long.  (enums are signed in C,
        # unsigned in NDR)
        if ($ctypename =~ /^(uint32|uint3264)$/) {
-               return "(uint32_t)$cvar > LONG_MAX ? PyLong_FromUnsignedLong((uint32_t)$cvar) : PyInt_FromLong((uint32_t)$cvar)";
+               return "ndr_PyLong_FromUnsignedLongLong((uint32_t)$cvar)";
        }
 
        if ($ctypename =~ /^(uint|uint8|uint16|uint1632)$/) {
@@ -1490,6 +1555,7 @@ sub Parse($$$$$)
 
     $self->pidl_hdr("
 /* Python wrapper functions auto-generated by pidl */
+#define PY_SSIZE_T_CLEAN 1 /* We use Py_ssize_t for PyArg_ParseTupleAndKeywords */
 #include <Python.h>
 #include \"includes.h\"
 #include <pytalloc.h>
@@ -1499,7 +1565,7 @@ sub Parse($$$$$)
 #include \"$ndr_hdr\"
 
 /*
- * These functions are here to ensure they can be optomised out by
+ * These functions are here to ensure they can be optimized out by
  * the compiler based on the constant input values
  */
 
@@ -1535,6 +1601,24 @@ static inline long long ndr_sizeof2intmax(size_t var_size)
        return 0;
 }
 
+static inline PyObject *ndr_PyLong_FromLongLong(long long v)
+{
+       if (v > LONG_MAX || v < LONG_MIN) {
+               return PyLong_FromLongLong(v);
+       } else {
+               return PyInt_FromLong(v);
+       }
+}
+
+static inline PyObject *ndr_PyLong_FromUnsignedLongLong(unsigned long long v)
+{
+       if (v > LONG_MAX) {
+               return PyLong_FromUnsignedLongLong(v);
+       } else {
+               return PyInt_FromLong(v);
+       }
+}
+
 ");
 
        foreach my $x (@$ndr) {
@@ -1614,7 +1698,7 @@ static inline long long ndr_sizeof2intmax(size_t var_size)
                my $py_obj;
                my ($ctype, $cvar) = @{$h->{'val'}};
                if ($cvar =~ /^[0-9]+$/ or $cvar =~ /^0x[0-9a-fA-F]+$/) {
-                       $py_obj = "$cvar > LONG_MAX ? PyLong_FromUnsignedLongLong($cvar) : PyInt_FromLong($cvar)";
+                       $py_obj = "ndr_PyLong_FromUnsignedLongLong($cvar)";
                } elsif ($cvar =~ /^".*"$/) {
                        $py_obj = "PyString_FromString($cvar)";
                } else {