From db20285f497bc8e481943488bf515768183d5db8 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 13 Mar 2015 18:28:33 -0700 Subject: [PATCH] =?UTF-8?q?Start=20of=20porting=20to=20newest=20sip.=20=20?= =?UTF-8?q?Not=20quite=20ready=20yet=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.py | 4 +- buildtools/config.py | 2 +- sip/siplib/apiversions.c | 6 +- sip/siplib/array.c | 887 ++++++++++++++++++++++++++ sip/siplib/array.h | 46 ++ sip/siplib/bool.cpp | 4 +- sip/siplib/descriptors.c | 202 +++++- sip/siplib/objmap.c | 6 +- sip/siplib/qtlib.c | 31 +- sip/siplib/sip.h | 153 ++++- sip/siplib/sipint.h | 15 +- sip/siplib/siplib.c | 1299 ++++++++++++++++++++++++++++++-------- sip/siplib/threads.c | 18 +- sip/siplib/voidptr.c | 110 +++- wscript | 1 + 15 files changed, 2451 insertions(+), 333 deletions(-) create mode 100644 sip/siplib/array.c create mode 100644 sip/siplib/array.h diff --git a/build.py b/build.py index 8221be89..6961a4b8 100755 --- a/build.py +++ b/build.py @@ -58,9 +58,9 @@ wxICON = 'docs/sphinx/_static/images/sphinxdocs/mondrian.png' # Some tools will be downloaded for the builds. These are the versions and # MD5s of the tool binaries currently in use. -sipCurrentVersion = '4.14.7' +sipCurrentVersion = '4.16.7-snapshot-f652446e2462' sipMD5 = { - 'darwin' : '836e78f3c2bf9f8233b32c1a3599efec', + 'darwin' : '72f61157902148d067eed3145d22990d', 'win32' : '208e8472342c07c2679868602d96a42b', 'linux' : '382c01bae24ace03ec8ae1ba6d76351a', } diff --git a/buildtools/config.py b/buildtools/config.py index e4559ecf..947eb5d2 100644 --- a/buildtools/config.py +++ b/buildtools/config.py @@ -120,7 +120,7 @@ class Configuration(object): self.SIPOPTS = ' '.join(['-w', # enable warnings '-o', # turn on auto-docstrings #'-e', # turn on exceptions support - '-T', # turn off writing the timestamp to the generated files '-g', # always release and reaquire the GIL + #'-T', # turn off writing the timestamp to the generated files '-g', # always release and reaquire the GIL #'-r', # turn on function call tracing '-I', os.path.join(phoenixDir(), 'src'), '-I', os.path.join(phoenixDir(), 'sip', 'gen'), diff --git a/sip/siplib/apiversions.c b/sip/siplib/apiversions.c index 36b4b98e..8da03e8a 100644 --- a/sip/siplib/apiversions.c +++ b/sip/siplib/apiversions.c @@ -1,7 +1,7 @@ /* * The implementation of the supprt for setting API versions. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -185,6 +185,8 @@ PyObject *sipGetAPI(PyObject *self, PyObject *args) const char *api; const apiVersionDef *avd; + (void)self; + if (!PyArg_ParseTuple(args, "s:getapi", &api)) return NULL; @@ -211,6 +213,8 @@ PyObject *sipSetAPI(PyObject *self, PyObject *args) int version_nr; const apiVersionDef *avd; + (void)self; + if (!PyArg_ParseTuple(args, "si:setapi", &api, &version_nr)) return NULL; diff --git a/sip/siplib/array.c b/sip/siplib/array.c new file mode 100644 index 00000000..1f004844 --- /dev/null +++ b/sip/siplib/array.c @@ -0,0 +1,887 @@ +/* + * This file implements the API for the array type. + * + * Copyright (c) 2015 Riverbank Computing Limited + * + * This file is part of SIP. + * + * This copy of SIP is licensed for use under the terms of the SIP License + * Agreement. See the file LICENSE for more details. + * + * This copy of SIP may also used under the terms of the GNU General Public + * License v2 or v3 as published by the Free Software Foundation which can be + * found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. + * + * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include + +#include +#include + +#include "sip.h" +#include "sipint.h" + +#include "array.h" + + +/* The object data structure. */ +typedef struct { + PyObject_HEAD + void *data; + const sipTypeDef *td; + const char *format; + size_t stride; + SIP_SSIZE_T len; + int flags; + PyObject *owner; +} sipArrayObject; + + +static int check_writable(sipArrayObject *array); +static int check_index(sipArrayObject *array, SIP_SSIZE_T idx); +static void *get_value(sipArrayObject *array, PyObject *value); +static void *get_slice(sipArrayObject *array, PyObject *value, + SIP_SSIZE_T len); +#if PY_VERSION_HEX < 0x02050000 +static void fix_bounds(int len, int *left, int *right); +#endif +#if PY_VERSION_HEX >= 0x02050000 +static void bad_key(PyObject *key); +#endif +static void *element(sipArrayObject *array, SIP_SSIZE_T idx); +static PyObject *make_array(void *data, const sipTypeDef *td, + const char *format, size_t stride, SIP_SSIZE_T len, int flags, + PyObject *owner); + + +/* + * Implement len() for the type. + */ +static SIP_SSIZE_T sipArray_length(PyObject *self) +{ + return ((sipArrayObject *)self)->len; +} + + +/* + * Implement sequence item sub-script for the type. + */ +static PyObject *sipArray_item(PyObject *self, SIP_SSIZE_T idx) +{ + sipArrayObject *array = (sipArrayObject *)self; + PyObject *py_item; + void *data; + + if (check_index(array, idx) < 0) + return NULL; + + data = element(array, idx); + + if (array->td != NULL) + { + py_item = sip_api_convert_from_type(data, array->td, NULL); + } + else + { + switch (*array->format) + { + case 'b': + py_item = SIPLong_FromLong(*(char *)data); + break; + + case 'B': + py_item = PyLong_FromUnsignedLong(*(unsigned char *)data); + break; + + case 'h': + py_item = SIPLong_FromLong(*(short *)data); + break; + + case 'H': + py_item = PyLong_FromUnsignedLong(*(unsigned short *)data); + break; + + case 'i': + py_item = SIPLong_FromLong(*(int *)data); + break; + + case 'I': + py_item = PyLong_FromUnsignedLong(*(unsigned int *)data); + break; + + case 'f': + py_item = PyFloat_FromDouble(*(float *)data); + break; + + case 'd': + py_item = PyFloat_FromDouble(*(double *)data); + break; + + default: + py_item = NULL; + } + } + + return py_item; +} + + +#if PY_VERSION_HEX < 0x02050000 +/* + * Implement sequence slice sub-script for the type. + */ +static PyObject *sipArray_slice(PyObject *self, int left, int right) +{ + sipArrayObject *array = (sipArrayObject *)self; + + fix_bounds(array->len, &left, &right); + + if (left == right) + left = right = 0; + + return make_array(element(array, left), array->td, array->format, + array->stride, right - left, (array->flags & ~SIP_OWNS_MEMORY), + array->owner); +} + + +/* + * Implement sequence assignment item sub-script for the type. + */ +static int sipArray_ass_item(PyObject *self, int idx, PyObject *value) +{ + sipArrayObject *array = (sipArrayObject *)self; + void *value_data; + + if (check_writable(array) < 0 || check_index(array, idx) < 0) + return -1; + + if ((value_data = get_value(array, value)) == NULL) + return -1; + + memmove(element(array, idx), value_data, array->stride); + + return 0; +} + + +/* + * Implement sequence assignment slice sub-script for the type. + */ +static int sipArray_ass_slice(PyObject *self, int left, int right, + PyObject *value) +{ + sipArrayObject *array = (sipArrayObject *)self; + void *value_data; + + if (check_writable(array) < 0) + return -1; + + fix_bounds(array->len, &left, &right); + + if ((value_data = get_slice(array, value, right - left)) == NULL) + return -1; + + memmove(element(array, left), value_data, (right - left) * array->stride); + + return 0; +} +#endif + + +/* The sequence methods data structure. */ +static PySequenceMethods sipArray_SequenceMethods = { + sipArray_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + sipArray_item, /* sq_item */ +#if PY_VERSION_HEX >= 0x02050000 + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ +#else + sipArray_slice, /* sq_slice */ + sipArray_ass_item, /* sq_ass_item */ + sipArray_ass_slice, /* sq_ass_slice */ +#endif + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + + +#if PY_VERSION_HEX >= 0x02050000 +/* + * Implement mapping sub-script for the type. + */ +static PyObject *sipArray_subscript(PyObject *self, PyObject *key) +{ + sipArrayObject *array = (sipArrayObject *)self; + + if (PyIndex_Check(key)) + { + Py_ssize_t idx = PyNumber_AsSsize_t(key, PyExc_IndexError); + + if (idx == -1 && PyErr_Occurred()) + return NULL; + + if (idx < 0) + idx += array->len; + + return sipArray_item(self, idx); + } + + if (PySlice_Check(key)) + { + Py_ssize_t start, stop, step, slicelength; + + if (sipConvertFromSliceObject(key, array->len, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (step != 1) + { + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; + } + + return make_array(element(array->data, start), array->td, + array->format, array->stride, slicelength, + (array->flags & ~SIP_OWNS_MEMORY), array->owner); + } + + bad_key(key); + + return NULL; +} + + +/* + * Implement mapping assignment sub-script for the type. + */ +static int sipArray_ass_subscript(PyObject *self, PyObject *key, + PyObject *value) +{ + sipArrayObject *array = (sipArrayObject *)self; + SIP_SSIZE_T start, len; + void *value_data; + + if (check_writable(array) < 0) + return -1; + + if (PyIndex_Check(key)) + { + start = PyNumber_AsSsize_t(key, PyExc_IndexError); + + if (start == -1 && PyErr_Occurred()) + return -1; + + if (start < 0) + start += array->len; + + if (check_index(array, start) < 0) + return -1; + + if ((value_data = get_value(array, value)) == NULL) + return -1; + + len = 1; + } + else if (PySlice_Check(key)) + { + Py_ssize_t stop, step; + + if (sipConvertFromSliceObject(key, array->len, &start, &stop, &step, &len) < 0) + return -1; + + if (step != 1) + { + PyErr_SetNone(PyExc_NotImplementedError); + return -1; + } + + if ((value_data = get_slice(array, value, len)) == NULL) + return -1; + } + else + { + bad_key(key); + + return -1; + } + + memmove(element(array, start), value_data, len * array->stride); + + return 0; +} + + +/* The mapping methods data structure. */ +static PyMappingMethods sipArray_MappingMethods = { + sipArray_length, /* mp_length */ + sipArray_subscript, /* mp_subscript */ + sipArray_ass_subscript, /* mp_ass_subscript */ +}; +#endif + + +#if PY_VERSION_HEX >= 0x02060300 +/* + * The buffer implementation for Python v2.6.3 and later. + */ +static int sipArray_getbuffer(PyObject *self, Py_buffer *view, int flags) +{ + sipArrayObject *array = (sipArrayObject *)self; + + if (view == NULL) + return 0; + + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (array->flags & SIP_READ_ONLY)) + { + PyErr_SetString(PyExc_BufferError, "object is not writable."); + return -1; + } + + view->obj = self; + Py_INCREF(self); + + view->buf = array->data; + view->len = array->len; + view->readonly = (array->flags & SIP_READ_ONLY); + view->itemsize = array->stride; + + view->format = NULL; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = (char *)array->format; + + view->ndim = 1; + + view->shape = NULL; + if ((flags & PyBUF_ND) == PyBUF_ND) + view->shape = &view->len; + + view->strides = NULL; + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + view->strides = &view->itemsize; + + view->suboffsets = NULL; + view->internal = NULL; + + return 0; +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The read buffer implementation for Python v2. + */ +static SIP_SSIZE_T sipArray_getreadbuffer(PyObject *self, SIP_SSIZE_T seg, + void **ptr) +{ + sipArrayObject *array = (sipArrayObject *)self; + + if (seg != 0) + { + PyErr_SetString(PyExc_SystemError, "invalid buffer segment"); + return -1; + } + + *ptr = array->data; + + return array->len; +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The write buffer implementation for Python v2. + */ +static SIP_SSIZE_T sipArray_getwritebuffer(PyObject *self, SIP_SSIZE_T seg, + void **ptr) +{ + if (check_writable((sipArrayObject *)self) < 0) + return -1; + + return sipArray_getreadbuffer(self, seg, ptr); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The segment count implementation for Python v2. + */ +static SIP_SSIZE_T sipArray_getsegcount(PyObject *self, SIP_SSIZE_T *lenp) +{ + SIP_SSIZE_T segs, len; + + len = ((sipArrayObject *)self)->len; + segs = (len < 0 ? 0 : 1); + + if (lenp != NULL) + *lenp = len; + + return segs; +} +#endif + + +/* The buffer methods data structure. */ +static PyBufferProcs sipArray_BufferProcs = { +#if PY_MAJOR_VERSION >= 3 + sipArray_getbuffer, /* bf_getbuffer */ + 0 /* bf_releasebuffer */ +#else + sipArray_getreadbuffer, /* bf_getreadbuffer */ + sipArray_getwritebuffer, /* bf_getwritebuffer */ + sipArray_getsegcount, /* bf_getsegcount */ +#if PY_VERSION_HEX >= 0x02050000 + (charbufferproc)sipArray_getreadbuffer, /* bf_getcharbuffer */ +#if PY_VERSION_HEX >= 0x02060300 + sipArray_getbuffer, /* bf_getbuffer */ + 0 /* bf_releasebuffer */ +#endif +#else + (getcharbufferproc)sipArray_getreadbuffer /* bf_getcharbuffer */ +#endif +#endif +}; + + +/* The instance deallocation function. */ +static void sipArray_dealloc(PyObject *self) +{ + sipArrayObject *array = (sipArrayObject *)self; + + if (array->flags & SIP_OWNS_MEMORY) + sip_api_free(array->data); + else + Py_XDECREF(array->owner); +} + + +/* The type data structure. */ +PyTypeObject sipArray_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.array", /* tp_name */ + sizeof (sipArrayObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + sipArray_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved (Python v3), tp_compare (Python v2) */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &sipArray_SequenceMethods, /* tp_as_sequence */ +#if PY_VERSION_HEX >= 0x02050000 + &sipArray_MappingMethods, /* tp_as_mapping */ +#else + 0, /* tp_as_mapping */ +#endif + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &sipArray_BufferProcs, /* tp_as_buffer */ +#if defined(Py_TPFLAGS_HAVE_NEWBUFFER) + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ +#endif + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version_tag */ +#endif +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif +}; + + +/* + * Check that an array is writable. + */ +static int check_writable(sipArrayObject *array) +{ + if (array->flags & SIP_READ_ONLY) + { + PyErr_SetString(PyExc_TypeError, "sip.array object is read-only"); + return -1; + } + + return 0; +} + + +/* + * Check that an index is valid for an array. + */ +static int check_index(sipArrayObject *array, SIP_SSIZE_T idx) +{ + if (idx >= 0 && idx < array->len) + return 0; + + PyErr_SetString(PyExc_IndexError, "index out of bounds"); + + return -1; +} + + +#if PY_VERSION_HEX < 0x02050000 +/* + * Fix the bounds of a slice in the same way that the Python buffer object + * does. + */ +static void fix_bounds(int len, int *left, int *right) +{ + if (*left < 0) + *left = 0; + else if (*left > len) + *left = len; + + if (*right < *left) + *right = *left; + else if (*right > len) + *right = len; +} +#endif + + +#if PY_VERSION_HEX >= 0x02050000 +/* + * Raise an exception about a bad sub-script key. + */ +static void bad_key(PyObject *key) +{ + PyErr_Format(PyExc_TypeError, + "cannot index a sip.array object using '%s'", + Py_TYPE(key)->tp_name); +} +#endif + + +/* + * Get the address of an element of an array. + */ +static void *element(sipArrayObject *array, SIP_SSIZE_T idx) +{ + return (unsigned char *)(array->data) + idx * array->stride; +} + + +/* + * Get the address of a value that will be copied to an array. + */ +static void *get_value(sipArrayObject *array, PyObject *value) +{ + static union { + signed char s_char_t; + unsigned char u_char_t; + signed short s_short_t; + unsigned short u_short_t; + signed int s_int_t; + unsigned int u_int_t; + float float_t; + double double_t; + } static_data; + + void *data; + + if (array->td != NULL) + { + int iserr = FALSE; + + data = sip_api_force_convert_to_type(value, array->td, NULL, + SIP_NOT_NONE|SIP_NO_CONVERTORS, NULL, &iserr); + } + else + { + PyErr_Clear(); + + switch (*array->format) + { + case 'b': + static_data.s_char_t = (signed char)SIPLong_AsLong(value); + data = &static_data.s_char_t; + break; + + case 'B': + static_data.u_char_t = (unsigned char)sip_api_long_as_unsigned_long(value); + data = &static_data.u_char_t; + break; + + case 'h': + static_data.s_short_t = (signed short)SIPLong_AsLong(value); + data = &static_data.s_short_t; + break; + + case 'H': + static_data.u_short_t = (unsigned short)sip_api_long_as_unsigned_long(value); + data = &static_data.u_short_t; + break; + + case 'i': + static_data.s_int_t = SIPLong_AsLong(value); + data = &static_data.s_int_t; + break; + + case 'I': + static_data.u_int_t = sip_api_long_as_unsigned_long(value); + data = &static_data.u_int_t; + break; + + case 'f': + static_data.float_t = (float)PyFloat_AsDouble(value); + data = &static_data.float_t; + break; + + case 'd': + static_data.double_t = PyFloat_AsDouble(value); + data = &static_data.double_t; + break; + + default: + data = NULL; + } + + if (PyErr_Occurred()) + data = NULL; + } + + return data; +} + + +/* + * Get the address of an value that will be copied to an array slice. + */ +static void *get_slice(sipArrayObject *array, PyObject *value, SIP_SSIZE_T len) +{ + sipArrayObject *other = (sipArrayObject *)value; + + if (!PyObject_IsInstance(value, (PyObject *)&sipArray_Type) || array->td != other->td || strcmp(array->format, other->format) != 0) + { + const char *type; + + if (array->td != NULL) + { + type = sipTypeName(array->td); + } + else + { + switch (*array->format) + { + case 'b': + type = "char"; + break; + + case 'B': + type = "unsigned char"; + break; + + case 'h': + type = "short"; + break; + + case 'H': + type = "unsigned short"; + break; + + case 'i': + type = "int"; + break; + + case 'I': + type = "unsigned int"; + break; + + case 'f': + type = "float"; + break; + + case 'd': + type = "double"; + break; + + default: + type = ""; + } + } + + PyErr_Format(PyExc_TypeError, + "can only assign another array of %s to the slice", type); + + return NULL; + } + + if (other->len != len) + { + PyErr_Format(PyExc_TypeError, + "the array being assigned must have length " SIP_SSIZE_T_FORMAT, + len); + + return NULL; + } + + if (other->stride == array->stride) + { + PyErr_Format(PyExc_TypeError, +#if PY_VERSION_HEX >= 0x02050000 + "the array being assigned must have stride %zu", + array->stride); +#else + "the array being assigned must have stride %ld", + (unsigned long)array->stride); +#endif + + return NULL; + } + + return other->data; +} + + +/* + * Do the work of creating an array. + */ +static PyObject *make_array(void *data, const sipTypeDef *td, + const char *format, size_t stride, SIP_SSIZE_T len, int flags, + PyObject *owner) +{ + sipArrayObject *array; + + if ((array = PyObject_NEW(sipArrayObject, &sipArray_Type)) == NULL) + return NULL; + + array->data = data; + array->td = td; + array->format = format; + array->stride = stride; + array->len = len; + array->flags = flags; + + if (flags & SIP_OWNS_MEMORY) + { + /* This is a borrowed reference to itself. */ + array->owner = (PyObject *)array; + } + else + { + Py_XINCREF(owner); + array->owner = owner; + } + + return (PyObject *)array; +} + + +/* + * Wrap an array of instances of a fundamental type. At the moment format must + * be either "b" (char), "B" (unsigned char), "h" (short), "H" (unsigned + * short), "i" (int), "I" (unsigned int), "f" (float) or "d" (double). + */ +PyObject *sip_api_convert_to_array(void *data, const char *format, + SIP_SSIZE_T len, int flags) +{ + size_t stride; + + if (data == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + switch (*format) + { + case 'b': + stride = sizeof (char); + break; + + case 'B': + stride = sizeof (unsigned char); + break; + + case 'h': + stride = sizeof (short); + break; + + case 'H': + stride = sizeof (unsigned short); + break; + + case 'i': + stride = sizeof (int); + break; + + case 'I': + stride = sizeof (unsigned int); + break; + + case 'f': + stride = sizeof (float); + break; + + case 'd': + stride = sizeof (double); + break; + + default: + stride = 0; + } + + assert(stride > 0); + assert(len >= 0); + + return make_array(data, NULL, format, stride, len, flags, NULL); +} + + +/* + * Wrap an array of instances of a defined type. + */ +PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td, + const char *format, size_t stride, SIP_SSIZE_T len, int flags) +{ + if (data == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + assert(stride > 0); + assert(len >= 0); + + return make_array(data, td, format, stride, len, flags, NULL); +} diff --git a/sip/siplib/array.h b/sip/siplib/array.h new file mode 100644 index 00000000..49863f74 --- /dev/null +++ b/sip/siplib/array.h @@ -0,0 +1,46 @@ +/* + * This file defines the API for the array type. + * + * Copyright (c) 2015 Riverbank Computing Limited + * + * This file is part of SIP. + * + * This copy of SIP is licensed for use under the terms of the SIP License + * Agreement. See the file LICENSE for more details. + * + * This copy of SIP may also used under the terms of the GNU General Public + * License v2 or v3 as published by the Free Software Foundation which can be + * found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package. + * + * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef _ARRAY_H +#define _ARRAY_H + + +#include + +#include "sip.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern PyTypeObject sipArray_Type; + +PyObject *sip_api_convert_to_array(void *data, const char *format, + SIP_SSIZE_T len, int flags); +PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td, + const char *format, size_t stride, SIP_SSIZE_T len, int flags); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sip/siplib/bool.cpp b/sip/siplib/bool.cpp index 5c48aa32..7c096d25 100644 --- a/sip/siplib/bool.cpp +++ b/sip/siplib/bool.cpp @@ -1,6 +1,6 @@ // This contains all the C++ code that is needed by the sip module. // -// Copyright (c) 2013 Riverbank Computing Limited +// Copyright (c) 2015 Riverbank Computing Limited // // This file is part of SIP. // @@ -18,5 +18,5 @@ // Set a C++ bool for the main C implementation of the module. extern "C" void sipSetBool(void *ptr, int val) { - *reinterpret_cast(ptr) = val; + *reinterpret_cast(ptr) = !!val; } diff --git a/sip/siplib/descriptors.c b/sip/siplib/descriptors.c index 6f242a16..4fc28df5 100644 --- a/sip/siplib/descriptors.c +++ b/sip/siplib/descriptors.c @@ -1,7 +1,7 @@ /* * The implementation of the different descriptors. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -25,7 +25,8 @@ /***************************************************************************** * A method descriptor. We don't use the similar Python descriptor because it - * doesn't support a method having static and non-static overloads. + * doesn't support a method having static and non-static overloads, and we + * handle mixins via a delegate. *****************************************************************************/ @@ -33,6 +34,9 @@ static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, PyObject *type); static PyObject *sipMethodDescr_repr(PyObject *self); +static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg); +static int sipMethodDescr_clear(PyObject *self); +static void sipMethodDescr_dealloc(PyObject *self); /* @@ -43,6 +47,9 @@ typedef struct _sipMethodDescr { /* The method definition. */ PyMethodDef *pmd; + + /* The mixin name, if any. */ + PyObject *mixin_name; } sipMethodDescr; @@ -54,7 +61,7 @@ PyTypeObject sipMethodDescr_Type = { "sip.methoddescriptor", /* tp_name */ sizeof (sipMethodDescr), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + sipMethodDescr_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -69,10 +76,10 @@ PyTypeObject sipMethodDescr_Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + sipMethodDescr_traverse,/* tp_traverse */ + sipMethodDescr_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -83,6 +90,25 @@ PyTypeObject sipMethodDescr_Type = { 0, /* tp_base */ 0, /* tp_dict */ sipMethodDescr_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version_tag */ +#endif +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }; @@ -94,7 +120,28 @@ PyObject *sipMethodDescr_New(PyMethodDef *pmd) PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0); if (descr != NULL) + { ((sipMethodDescr *)descr)->pmd = pmd; + ((sipMethodDescr *)descr)->mixin_name = NULL; + } + + return descr; +} + + +/* + * Return a new method descriptor based on an existing one and a mixin name. + */ +PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name) +{ + PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0); + + if (descr != NULL) + { + ((sipMethodDescr *)descr)->pmd = ((sipMethodDescr *)orig)->pmd; + ((sipMethodDescr *)descr)->mixin_name = mixin_name; + Py_INCREF(mixin_name); + } return descr; } @@ -108,8 +155,12 @@ static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, { sipMethodDescr *md = (sipMethodDescr *)self; + (void)type; + if (obj == Py_None) obj = NULL; + else if (md->mixin_name != NULL) + obj = PyObject_GetAttr(obj, md->mixin_name); return PyCFunction_New(md->pmd, obj); } @@ -133,6 +184,47 @@ static PyObject *sipMethodDescr_repr(PyObject *self) } +/* + * The descriptor's traverse slot. + */ +static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg) +{ + if (((sipMethodDescr *)self)->mixin_name != NULL) + { + int vret = visit(((sipMethodDescr *)self)->mixin_name, arg); + + if (vret != 0) + return vret; + } + + return 0; +} + + +/* + * The descriptor's clear slot. + */ +static int sipMethodDescr_clear(PyObject *self) +{ + PyObject *tmp = ((sipMethodDescr *)self)->mixin_name; + + ((sipMethodDescr *)self)->mixin_name = NULL; + Py_XDECREF(tmp); + + return 0; +} + + +/* + * The descriptor's dealloc slot. + */ +static void sipMethodDescr_dealloc(PyObject *self) +{ + sipMethodDescr_clear(self); + Py_TYPE(self)->tp_free(self); +} + + /***************************************************************************** * A variable descriptor. We don't use the similar Python descriptor because * it doesn't support static variables. @@ -144,6 +236,10 @@ static PyObject *sipVariableDescr_descr_get(PyObject *self, PyObject *obj, PyObject *type); static int sipVariableDescr_descr_set(PyObject *self, PyObject *obj, PyObject *value); +static int sipVariableDescr_traverse(PyObject *self, visitproc visit, + void *arg); +static int sipVariableDescr_clear(PyObject *self); +static void sipVariableDescr_dealloc(PyObject *self); /* @@ -160,6 +256,9 @@ typedef struct _sipVariableDescr { /* The generated container definition. */ const sipContainerDef *cod; + + /* The mixin name, if any. */ + PyObject *mixin_name; } sipVariableDescr; @@ -171,7 +270,7 @@ PyTypeObject sipVariableDescr_Type = { "sip.variabledescriptor", /* tp_name */ sizeof (sipVariableDescr), /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /* tp_dealloc */ + sipVariableDescr_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -186,10 +285,10 @@ PyTypeObject sipVariableDescr_Type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + sipVariableDescr_traverse, /* tp_traverse */ + sipVariableDescr_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -201,6 +300,24 @@ PyTypeObject sipVariableDescr_Type = { 0, /* tp_dict */ sipVariableDescr_descr_get, /* tp_descr_get */ sipVariableDescr_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version_tag */ +#endif +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }; @@ -222,6 +339,27 @@ PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td, ((sipVariableDescr *)descr)->vd = vd; ((sipVariableDescr *)descr)->td = td; ((sipVariableDescr *)descr)->cod = cod; + ((sipVariableDescr *)descr)->mixin_name = NULL; + } + + return descr; +} + + +/* + * Return a new variable descriptor based on an existing one and a mixin name. + */ +PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name) +{ + PyObject *descr = PyType_GenericAlloc(&sipVariableDescr_Type, 0); + + if (descr != NULL) + { + ((sipVariableDescr *)descr)->vd = ((sipVariableDescr *)orig)->vd; + ((sipVariableDescr *)descr)->td = ((sipVariableDescr *)orig)->td; + ((sipVariableDescr *)descr)->cod = ((sipVariableDescr *)orig)->cod; + ((sipVariableDescr *)descr)->mixin_name = mixin_name; + Py_INCREF(mixin_name); } return descr; @@ -294,6 +432,9 @@ static int get_instance_address(sipVariableDescr *vd, PyObject *obj, return -1; } + if (vd->mixin_name != NULL) + obj = PyObject_GetAttr(obj, vd->mixin_name); + /* Get the C++ instance. */ if ((addr = sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, vd->td)) == NULL) return -1; @@ -303,3 +444,44 @@ static int get_instance_address(sipVariableDescr *vd, PyObject *obj, return 0; } + + +/* + * The descriptor's traverse slot. + */ +static int sipVariableDescr_traverse(PyObject *self, visitproc visit, void *arg) +{ + if (((sipVariableDescr *)self)->mixin_name != NULL) + { + int vret = visit(((sipVariableDescr *)self)->mixin_name, arg); + + if (vret != 0) + return vret; + } + + return 0; +} + + +/* + * The descriptor's clear slot. + */ +static int sipVariableDescr_clear(PyObject *self) +{ + PyObject *tmp = ((sipVariableDescr *)self)->mixin_name; + + ((sipVariableDescr *)self)->mixin_name = NULL; + Py_XDECREF(tmp); + + return 0; +} + + +/* + * The descriptor's dealloc slot. + */ +static void sipVariableDescr_dealloc(PyObject *self) +{ + sipVariableDescr_clear(self); + Py_TYPE(self)->tp_free(self); +} diff --git a/sip/siplib/objmap.c b/sip/siplib/objmap.c index c65e9ab0..68fcb262 100644 --- a/sip/siplib/objmap.c +++ b/sip/siplib/objmap.c @@ -2,7 +2,7 @@ * This module implements a hash table class for mapping C/C++ addresses to the * corresponding wrapped Python object. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -197,7 +197,7 @@ static void add_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, /* Recurse up the hierachy for the remaining super-classes. */ add_aliases(om, addr, val, base_ctd, sup_ctd); - sup_addr = (*base_ctd->ctd_cast)(addr, sup_ctd); + sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd); if (sup_addr != addr) { @@ -403,7 +403,7 @@ static void remove_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, /* Recurse up the hierachy for the remaining super-classes. */ remove_aliases(om, addr, val, base_ctd, sup_ctd); - sup_addr = (*base_ctd->ctd_cast)(addr, sup_ctd); + sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd); if (sup_addr != addr) remove_object(om, sup_addr, val); diff --git a/sip/siplib/qtlib.c b/sip/siplib/qtlib.c index 384cf3d7..c8234bb1 100644 --- a/sip/siplib/qtlib.c +++ b/sip/siplib/qtlib.c @@ -2,7 +2,7 @@ * The SIP library code that implements the interface to the optional module * supplied Qt support. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -87,9 +87,21 @@ static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, /* - * Invoke a single slot (Qt or Python) and return the result. + * Invoke a single slot (Qt or Python) and return the result. Don't check if + * any receiver C++ object still exists. */ PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) +{ + return sip_api_invoke_slot_ex(slot, sigargs, TRUE); +} + + +/* + * Invoke a single slot (Qt or Python) and return the result. Optionally check + * that any receiver C++ object still exist. + */ +PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs, + int no_receiver_check) { PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref; @@ -145,11 +157,18 @@ PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) PyObject *self = (sref != NULL ? sref : slot->meth.mself); /* - * We used to check that any wrapped C++ object still existed and just - * returning None if it didn't. This caused inconsistent behaviour - * when the slot was a method connected to its object's destroyed() - * signal. + * If the receiver wraps a C++ object then ignore the call if it no + * longer exists. */ + if (!no_receiver_check && + PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) && + sip_api_get_address((sipSimpleWrapper *)self) == NULL) + { + Py_XDECREF(sref); + + Py_INCREF(Py_None); + return Py_None; + } #if PY_MAJOR_VERSION >= 3 sfunc = PyMethod_New(slot->meth.mfunc, self); diff --git a/sip/siplib/sip.h b/sip/siplib/sip.h index b2bbbafa..6d6ad523 100644 --- a/sip/siplib/sip.h +++ b/sip/siplib/sip.h @@ -1,7 +1,7 @@ /* * The SIP module interface. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -54,8 +54,8 @@ extern "C" { /* * Define the SIP version number. */ -#define SIP_VERSION 0x040e07 -#define SIP_VERSION_STR "4.14.7" +#define SIP_VERSION 0x041007 +#define SIP_VERSION_STR "4.16.7-snapshot-f652446e2462" /* @@ -68,6 +68,22 @@ extern "C" { * * History: * + * 11.1 Added sip_api_invoke_slot_ex(). + * + * 11.0 Added the pyqt5QtSignal and pyqt5ClassTypeDef structures. + * Removed qt_interface from pyqt4ClassTypeDef. + * Added hack to pyqt4QtSignal. + * + * 10.1 Added ctd_final to sipClassTypeDef. + * Added ctd_init_mixin to sipClassTypeDef. + * Added sip_api_get_mixin_address() to the public API. + * Added sip_api_convert_from_new_pytype() to the public API. + * Added sip_api_convert_to_array() to the public API. + * Added sip_api_convert_to_typed_array() to the public API. + * Added sip_api_register_proxy_resolver() to the public API. + * Added sip_api_init_mixin() to the private API. + * Added qt_interface to pyqt4ClassTypeDef. + * * 10.0 Added sip_api_set_destroy_on_exit(). * Added sip_api_enable_autoconversion(). * Removed sip_api_call_error_handler_old(). @@ -195,8 +211,8 @@ extern "C" { * * 0.0 Original version. */ -#define SIP_API_MAJOR_NR 10 -#define SIP_API_MINOR_NR 0 +#define SIP_API_MAJOR_NR 11 +#define SIP_API_MINOR_NR 1 /* The name of the sip module. */ @@ -217,6 +233,7 @@ typedef unsigned int uint; #if PY_VERSION_HEX >= 0x02050000 #define SIP_SSIZE_T Py_ssize_t +#define SIP_SSIZE_T_FORMAT "%zd" #define SIP_MLNAME_CAST(s) (s) #define SIP_MLDOC_CAST(s) (s) @@ -225,6 +242,7 @@ typedef unsigned int uint; #else #define SIP_SSIZE_T int +#define SIP_SSIZE_T_FORMAT "%d" #define SIP_MLNAME_CAST(s) ((char *)(s)) #define SIP_MLDOC_CAST(s) ((char *)(s)) @@ -338,6 +356,7 @@ struct _sipTypeDef; typedef void *(*sipInitFunc)(struct _sipSimpleWrapper *, PyObject *, PyObject *, PyObject **, PyObject **, PyObject **); +typedef int (*sipFinalFunc)(PyObject *, void *, PyObject *, PyObject **); typedef void *(*sipAccessFunc)(struct _sipSimpleWrapper *, AccessFuncOp); typedef int (*sipTraverseFunc)(void *, visitproc, void *); typedef int (*sipClearFunc)(void *); @@ -365,6 +384,7 @@ typedef PyObject *(*sipPickleFunc)(void *); typedef int (*sipAttrGetterFunc)(const struct _sipTypeDef *, PyObject *); typedef PyObject *(*sipVariableGetterFunc)(void *, PyObject *, PyObject *); typedef int (*sipVariableSetterFunc)(void *, PyObject *, PyObject *); +typedef void *(*sipProxyResolverFunc)(void *); /* @@ -415,6 +435,9 @@ typedef struct _sipSimpleWrapper { /* The instance dictionary. */ PyObject *dict; + /* The main instance if this is a mixin. */ + PyObject *mixin_main; + /* Next object at this address. */ struct _sipSimpleWrapper *next; } sipSimpleWrapper; @@ -853,7 +876,7 @@ typedef struct _sipClassTypeDef { /* The optional copy function. */ sipCopyFunc ctd_copy; - /* The release function, 0 if a C strict. */ + /* The release function, 0 if a C struct. */ sipReleaseFunc ctd_release; /* The cast function, 0 if a C struct. */ @@ -870,6 +893,12 @@ typedef struct _sipClassTypeDef { /* The pickle function. */ sipPickleFunc ctd_pickle; + + /* The finalisation function. */ + sipFinalFunc ctd_final; + + /* The mixin initialisation function. */ + initproc ctd_init_mixin; } sipClassTypeDef; @@ -1471,6 +1500,28 @@ typedef struct _sipAPIDef { const char *fmt, ...); void (*api_call_error_handler)(sipVirtErrorHandlerFunc, sipSimpleWrapper *, sip_gilstate_t); + int (*api_init_mixin)(PyObject *self, PyObject *args, PyObject *kwds, + const sipClassTypeDef *ctd); + /* + * The following are part of the public API. + */ + void *(*api_get_mixin_address)(struct _sipSimpleWrapper *w, + const sipTypeDef *td); + PyObject *(*api_convert_from_new_pytype)(void *cpp, PyTypeObject *py_type, + sipWrapper *owner, sipSimpleWrapper **selfp, const char *fmt, ...); + PyObject *(*api_convert_to_typed_array)(void *data, const sipTypeDef *td, + const char *format, size_t stride, SIP_SSIZE_T len, int flags); + PyObject *(*api_convert_to_array)(void *data, const char *format, + SIP_SSIZE_T len, int flags); + int (*api_register_proxy_resolver)(const sipTypeDef *td, + sipProxyResolverFunc resolver); + + /* + * The following may be used by Qt support code but no other handwritten + * code. + */ + PyObject *(*api_invoke_slot_ex)(const sipSlot *slot, PyObject *sigargs, + int check_receiver); } sipAPIDef; @@ -1506,6 +1557,13 @@ typedef struct _sipQtAPI { #define SIP_NO_CONVERTORS 0x02 /* Disable any type convertors. */ +/* + * These are flags that can be passed to sipConvertToArray(). + */ +#define SIP_READ_ONLY 0x01 /* The array is read-only. */ +#define SIP_OWNS_MEMORY 0x02 /* The array owns its memory. */ + + /* * These are the state flags returned by %ConvertToTypeCode. Note that these * share the same "namespace" as the flags below. @@ -1560,6 +1618,7 @@ typedef struct _sipQtAPI { #define SIP_TYPE_ALLOW_NONE 0x0020 /* If the type can handle None. */ #define SIP_TYPE_STUB 0x0040 /* If the type is a stub. */ #define SIP_TYPE_NONLAZY 0x0080 /* If the type has a non-lazy method. */ +#define SIP_TYPE_SUPER_INIT 0x0100 /* If the instance's super init should be called. */ /* @@ -1598,6 +1657,7 @@ typedef struct _sipQtAPI { #define sipTypeIsStub(td) ((td)->td_flags & SIP_TYPE_STUB) #define sipTypeSetStub(td) ((td)->td_flags |= SIP_TYPE_STUB) #define sipTypeHasNonlazyMethod(td) ((td)->td_flags & SIP_TYPE_NONLAZY) +#define sipTypeCallSuperInit(td) ((td)->td_flags & SIP_TYPE_SUPER_INIT) /* * Get various names from the string pool for various data types. @@ -1613,12 +1673,12 @@ typedef struct _sipQtAPI { * out to a plugin supplied by PyQt3. */ -typedef int (*pyqt3EmitFunc)(sipSimpleWrapper *, PyObject *); - /* * Maps the name of a Qt signal to a wrapper function to emit it. */ +typedef int (*pyqt3EmitFunc)(sipSimpleWrapper *, PyObject *); + typedef struct _pyqt3QtSignal { /* The signal name. */ const char *st_name; @@ -1663,6 +1723,16 @@ typedef struct _pyqt4QtSignal { * code that implements those methods. */ PyMethodDef *non_signals; + + /* + * The hack to apply when built against Qt5: + * + * 0 - no hack + * 1 - add an optional None + * 2 - add an optional [] + * 3 - add an optional False + */ + int hack; } pyqt4QtSignal; @@ -1677,22 +1747,83 @@ typedef struct _pyqt4ClassTypeDef { sipClassTypeDef super; /* A pointer to the QObject sub-class's staticMetaObject class variable. */ - const void *qt4_static_metaobject; + const void *static_metaobject; /* * A set of flags. At the moment only bit 0 is used to say if the type is * derived from QFlags. */ - unsigned qt4_flags; + unsigned flags; /* * The table of signals emitted by the type. These are grouped by signal * name. */ - const pyqt4QtSignal *qt4_signals; + const pyqt4QtSignal *qt_signals; } pyqt4ClassTypeDef; +/* + * The following are PyQt5-specific extensions. In SIP v5 they will be pushed + * out to a plugin supplied by PyQt5. + */ + +/* + * The description of a Qt signal for PyQt5. + */ +typedef int (*pyqt5EmitFunc)(void *, PyObject *); + +typedef struct _pyqt5QtSignal { + /* The normalised C++ name and signature of the signal. */ + const char *signature; + + /* The optional docstring. */ + const char *docstring; + + /* + * If the signal is an overload of regular methods then this points to the + * code that implements those methods. + */ + PyMethodDef *non_signals; + + /* + * If the signal has optional arguments then this function will implement + * emit() for the signal. + */ + pyqt5EmitFunc emitter; +} pyqt5QtSignal; + + +/* + * This is the PyQt5-specific extension to the generated class type structure. + */ +typedef struct _pyqt5ClassTypeDef { + /* + * The super-type structure. This must be first in the structure so that + * it can be cast to sipClassTypeDef *. + */ + sipClassTypeDef super; + + /* A pointer to the QObject sub-class's staticMetaObject class variable. */ + const void *static_metaobject; + + /* + * A set of flags. At the moment only bit 0 is used to say if the type is + * derived from QFlags. + */ + unsigned flags; + + /* + * The table of signals emitted by the type. These are grouped by signal + * name. + */ + const pyqt5QtSignal *qt_signals; + + /* The name of the interface that the class defines. */ + const char *qt_interface; +} pyqt5ClassTypeDef; + + #ifdef __cplusplus } #endif diff --git a/sip/siplib/sipint.h b/sip/siplib/sipint.h index 05cd9dd5..5f233fd2 100644 --- a/sip/siplib/sipint.h +++ b/sip/siplib/sipint.h @@ -1,7 +1,7 @@ /* * This file defines the SIP library internal interfaces. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -61,10 +61,12 @@ typedef struct */ extern PyTypeObject sipMethodDescr_Type; PyObject *sipMethodDescr_New(PyMethodDef *pmd); +PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name); extern PyTypeObject sipVariableDescr_Type; PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td, const sipContainerDef *cod); +PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name); /* @@ -112,9 +114,14 @@ PyObject *sip_api_convert_from_type(void *cppPtr, const sipTypeDef *td, PyObject *transferObj); void sip_api_common_dtor(sipSimpleWrapper *sipSelf); void sip_api_end_thread(void); +void *sip_api_force_convert_to_type(PyObject *pyObj, const sipTypeDef *td, + PyObject *transferObj, int flags, int *statep, int *iserrp); void sip_api_free_sipslot(sipSlot *slot); +unsigned long sip_api_long_as_unsigned_long(PyObject *o); int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot); PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs); +PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs, + int no_receiver_check); void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs, PyObject *rxObj, const char *slot, const char **memberp, int flags); int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot); @@ -123,13 +130,13 @@ int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot); /* * These are not part of the SIP API but are used within the SIP module. */ -sipClassTypeDef *sipGetGeneratedClassType(sipEncodedTypeDef *enc, +sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc, const sipClassTypeDef *ctd); void sipSaveMethod(sipPyMethod *pm,PyObject *meth); int sipGetPending(void **pp, sipWrapper **op, int *fp); int sipIsPending(); -PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td, - sipWrapper *owner, int initflags); +PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args, + sipWrapper *owner, int flags); void *sipConvertRxEx(sipWrapper *txSelf, const char *sigargs, PyObject *rxObj, const char *slot, const char **memberp, int flags); diff --git a/sip/siplib/siplib.c b/sip/siplib/siplib.c index 164ef478..8e66f869 100644 --- a/sip/siplib/siplib.c +++ b/sip/siplib/siplib.c @@ -1,7 +1,7 @@ /* * SIP library code. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -27,6 +27,7 @@ #include "sip.h" #include "sipint.h" +#include "array.h" /* There doesn't seem to be a standard way of checking for C99 support. */ @@ -89,6 +90,17 @@ static PyTypeObject sipWrapperType_Type = { sipWrapperType_alloc, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }; @@ -145,12 +157,26 @@ static sipWrapperType sipWrapper_Type = { 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version_tag */ +#endif +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }, #if !defined(STACKLESS) }, #endif 0, - 0 + 0, + 0, }; @@ -166,13 +192,13 @@ static int sip_api_can_convert_to_type(PyObject *pyObj, const sipTypeDef *td, int flags); static void *sip_api_convert_to_type(PyObject *pyObj, const sipTypeDef *td, PyObject *transferObj, int flags, int *statep, int *iserrp); -static void *sip_api_force_convert_to_type(PyObject *pyObj, - const sipTypeDef *td, PyObject *transferObj, int flags, int *statep, - int *iserrp); static int sip_api_can_convert_to_enum(PyObject *pyObj, const sipTypeDef *td); static void sip_api_release_type(void *cpp, const sipTypeDef *td, int state); static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td, PyObject *transferObj); +static PyObject *sip_api_convert_from_new_pytype(void *cpp, + PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp, + const char *fmt, ...); static int sip_api_get_state(PyObject *transferObj); static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td); static sipWrapperType *sip_api_map_int_to_class(int typeInt, @@ -221,7 +247,6 @@ static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, sipPySlotType st, const sipTypeDef *td, PyObject *arg0, PyObject *arg1); static void sip_api_add_delayed_dtor(sipSimpleWrapper *w); -static unsigned long sip_api_long_as_unsigned_long(PyObject *o); static int sip_api_export_symbol(const char *name, void *sym); static void *sip_api_import_symbol(const char *name); static const sipTypeDef *sip_api_find_type(const char *type); @@ -258,6 +283,12 @@ static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj); static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp); static void sip_api_set_destroy_on_exit(int value); static int sip_api_enable_autoconversion(const sipTypeDef *td, int enable); +static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds, + const sipClassTypeDef *ctd); +static void *sip_api_get_mixin_address(sipSimpleWrapper *w, + const sipTypeDef *td); +static int sip_api_register_proxy_resolver(const sipTypeDef *td, + sipProxyResolverFunc resolver); /* @@ -374,11 +405,27 @@ static const sipAPIDef sip_api = { sip_api_add_exception, sip_api_parse_result_ex, sip_api_call_error_handler, + sip_api_init_mixin, + /* + * The following are part of the public API. + */ + sip_api_get_mixin_address, + sip_api_convert_from_new_pytype, + sip_api_convert_to_typed_array, + sip_api_convert_to_array, + sip_api_register_proxy_resolver, + /* + * The following may be used by Qt support code but by no other handwritten + * code. + */ + sip_api_invoke_slot_ex, }; #define AUTO_DOCSTRING '\1' /* Marks an auto class docstring. */ +#define non_overflow_exception() (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_OverflowError)) + /* * These are the format flags supported by argument parsers. @@ -451,12 +498,23 @@ typedef struct _sipAttrGetter { } sipAttrGetter; +/* + * An entry in the linked list of proxy resolvers. + */ +typedef struct _sipProxyResolver { + const sipTypeDef *td; /* The type the resolver handles. */ + sipProxyResolverFunc resolver; /* The resolver. */ + struct _sipProxyResolver *next; /* The next in the list. */ +} sipProxyResolver; + + /***************************************************************************** * The structures to support a Python type to hold a named enum. *****************************************************************************/ static PyObject *sipEnumType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems); + /* * The type data structure. We inherit everything from the standard Python * metatype and the size of the type object created is increased to accomodate @@ -502,12 +560,29 @@ static PyTypeObject sipEnumType_Type = { sipEnumType_alloc, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }; +/* + * Remove these in SIP v5. + */ sipQtAPI *sipQtSupport = NULL; sipTypeDef *sipQObjectType; +static int got_kw_handler = FALSE; +static int (*kw_handler)(PyObject *, void *, PyObject *); + /* * Various strings as Python objects created as and when needed. @@ -523,21 +598,26 @@ static sipExportedModuleDef *moduleList = NULL; /* List of registered modules. * static unsigned traceMask = 0; /* The current trace mask. */ static sipTypeDef *currentType = NULL; /* The type being created. */ +static PyObject **unused_backdoor = NULL; /* For passing dict of unused arguments. */ +static PyObject *init_name = NULL; /* '__init__'. */ +static PyObject *empty_tuple; /* The empty tuple. */ static PyObject *type_unpickler; /* The type unpickler function. */ static PyObject *enum_unpickler; /* The enum unpickler function. */ static sipSymbol *sipSymbolList = NULL; /* The list of published symbols. */ static sipAttrGetter *sipAttrGetters = NULL; /* The list of attribute getters. */ +static sipProxyResolver *proxyResolvers = NULL; /* The list of proxy resolvers. */ static sipPyObject *sipRegisteredPyTypes = NULL; /* Registered Python types. */ static sipPyObject *sipDisabledAutoconversions = NULL; /* Python types whose auto-conversion is disabled. */ static PyInterpreterState *sipInterpreter = NULL; /* The interpreter. */ static int destroy_on_exit = TRUE; /* Destroy owned objects on exit. */ -static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd); +static void addClassSlots(sipWrapperType *wt, const sipClassTypeDef *ctd); static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots); static void *findSlot(PyObject *self, sipPySlotType st); -static void *findSlotInType(sipPySlotDef *psd, sipPySlotType st); +static void *findSlotInClass(const sipClassTypeDef *psd, sipPySlotType st); +static void *findSlotInSlotList(sipPySlotDef *psd, sipPySlotType st); static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2, sipPySlotType st); static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1, @@ -581,10 +661,10 @@ static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd, static int createMappedType(sipExportedModuleDef *client, sipMappedTypeDef *mtd, PyObject *mod_dict); static sipExportedModuleDef *getModule(PyObject *mname_obj); -static PyObject *pickle_type(PyObject *obj, PyObject *); -static PyObject *unpickle_type(PyObject *, PyObject *args); -static PyObject *pickle_enum(PyObject *obj, PyObject *); -static PyObject *unpickle_enum(PyObject *, PyObject *args); +static PyObject *pickle_type(PyObject *obj, PyObject *args); +static PyObject *unpickle_type(PyObject *obj, PyObject *args); +static PyObject *pickle_enum(PyObject *obj, PyObject *args); +static PyObject *unpickle_enum(PyObject *obj, PyObject *args); static int setReduce(PyTypeObject *type, PyMethodDef *pickler); static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd, PyObject *mod_dict); @@ -675,11 +755,19 @@ static int isNonlazyMethod(PyMethodDef *pmd); static int addMethod(PyObject *dict, PyMethodDef *pmd); static PyObject *create_property(sipVariableDef *vd); static PyObject *create_function(PyMethodDef *ml); -static PyObject *sip_exit(PyObject *obj, PyObject *ignore); +static PyObject *sip_exit(PyObject *self, PyObject *args); static void register_exit_notifier(void); -static sipConvertFromFunc get_from_convertor(sipTypeDef *td); +static sipConvertFromFunc get_from_convertor(const sipTypeDef *td); static sipPyObject **autoconversion_disabled(const sipTypeDef *td); static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd); +static sipFinalFunc find_finalisation(sipClassTypeDef *ctd); +static PyObject *next_in_mro(PyObject *self, PyObject *after); +static int super_init(PyObject *self, PyObject *args, PyObject *kwds, + PyObject *type); +static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w); +static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td, + sipWrapper *owner, int flags); +static void *resolve_proxy(const sipTypeDef *td, void *proxy); /* @@ -748,7 +836,7 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) * Remind ourselves to add support for capsule variables when we have * another reason to move to the next major version number. */ -#if SIP_API_MAJOR_NR > 10 +#if SIP_API_MAJOR_NR > 11 #error "Add support for capsule variables" #endif @@ -793,6 +881,9 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) if (PyType_Ready(&sipVoidPtr_Type) < 0) SIP_FATAL(SIP_MODULE_NAME ": Failed to initialise sip.voidptr type"); + if (PyType_Ready(&sipArray_Type) < 0) + SIP_FATAL(SIP_MODULE_NAME ": Failed to initialise sip.array type"); + #if PY_MAJOR_VERSION >= 3 mod = PyModule_Create(&module_def); #else @@ -800,7 +891,7 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) #endif if (mod == NULL) - SIP_FATAL(SIP_MODULE_NAME ": Failed to intialise sip module"); + SIP_FATAL(SIP_MODULE_NAME ": Failed to initialise sip module"); mod_dict = PyModule_GetDict(mod); @@ -836,6 +927,19 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) SIP_FATAL(SIP_MODULE_NAME ": Failed to add _C_API object to module dictionary"); } + /* These will always be needed. */ + if (objectify("__init__", &init_name) < 0) + { + SIP_MODULE_DISCARD(mod); + SIP_FATAL(SIP_MODULE_NAME ": Failed to objectify '__init__'"); + } + + if ((empty_tuple = PyTuple_New(0)) == NULL) + { + SIP_MODULE_DISCARD(mod); + SIP_FATAL(SIP_MODULE_NAME ": Failed to create empty tuple"); + } + /* Add the SIP version number, but don't worry about errors. */ #if PY_MAJOR_VERSION >= 3 obj = PyLong_FromLong(SIP_VERSION); @@ -886,7 +990,7 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) sipInterpreter = PyThreadState_Get()->interp; } - /* Make sure are notified when starting to exit. */ + /* Make sure we are notified when starting to exit. */ register_exit_notifier(); SIP_MODULE_RETURN(mod); @@ -917,6 +1021,8 @@ static PyObject *setTraceMask(PyObject *self, PyObject *args) { unsigned new_mask; + (void)self; + if (PyArg_ParseTuple(args, "I:settracemask", &new_mask)) { traceMask = new_mask; @@ -936,6 +1042,8 @@ static PyObject *dumpWrapper(PyObject *self, PyObject *args) { sipSimpleWrapper *sw; + (void)self; + if (PyArg_ParseTuple(args, "O!:dump", &sipSimpleWrapper_Type, &sw)) { print_object(NULL, (PyObject *)sw); @@ -992,6 +1100,8 @@ static PyObject *transferTo(PyObject *self, PyObject *args) { PyObject *w, *owner; + (void)self; + if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner)) { if (owner == Py_None) @@ -1025,6 +1135,8 @@ static PyObject *transferBack(PyObject *self, PyObject *args) { PyObject *w; + (void)self; + if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w)) { sip_api_transfer_back(w); @@ -1049,6 +1161,8 @@ static PyObject *cast(PyObject *self, PyObject *args) void *addr; PyTypeObject *ft, *tt; + (void)self; + if (!PyArg_ParseTuple(args, "O!O!:cast", &sipSimpleWrapper_Type, &sw, &sipWrapperType_Type, &wt)) return NULL; @@ -1072,7 +1186,8 @@ static PyObject *cast(PyObject *self, PyObject *args) * We don't put this new object into the map so that the original object is * always found. It would also totally confuse the map logic. */ - return sipWrapSimpleInstance(addr, wt->type, NULL, (sw->flags | SIP_NOT_IN_MAP) & ~SIP_PY_OWNED); + return wrap_simple_instance(addr, wt->type, NULL, + (sw->flags | SIP_NOT_IN_MAP) & ~SIP_PY_OWNED); } @@ -1085,6 +1200,8 @@ static PyObject *callDtor(PyObject *self, PyObject *args) void *addr; const sipClassTypeDef *ctd; + (void)self; + if (!PyArg_ParseTuple(args, "O!:delete", &sipSimpleWrapper_Type, &sw)) return NULL; @@ -1118,6 +1235,8 @@ static PyObject *isDeleted(PyObject *self, PyObject *args) sipSimpleWrapper *sw; PyObject *res; + (void)self; + if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipSimpleWrapper_Type, &sw)) return NULL; @@ -1136,6 +1255,8 @@ static PyObject *isPyCreated(PyObject *self, PyObject *args) sipSimpleWrapper *sw; PyObject *res; + (void)self; + if (!PyArg_ParseTuple(args, "O!:ispycreated", &sipSimpleWrapper_Type, &sw)) return NULL; @@ -1155,6 +1276,8 @@ static PyObject *isPyOwned(PyObject *self, PyObject *args) sipSimpleWrapper *sw; PyObject *res; + (void)self; + if (!PyArg_ParseTuple(args, "O!:ispyowned", &sipSimpleWrapper_Type, &sw)) return NULL; @@ -1172,6 +1295,8 @@ static PyObject *setDeleted(PyObject *self, PyObject *args) { sipSimpleWrapper *sw; + (void)self; + if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipSimpleWrapper_Type, &sw)) return NULL; @@ -1199,6 +1324,8 @@ static PyObject *unwrapInstance(PyObject *self, PyObject *args) { sipSimpleWrapper *sw; + (void)self; + if (PyArg_ParseTuple(args, "O!:unwrapinstance", &sipSimpleWrapper_Type, &sw)) { void *addr; @@ -1224,10 +1351,12 @@ static PyObject *unwrapInstance(PyObject *self, PyObject *args) */ static PyObject *wrapInstance(PyObject *self, PyObject *args) { - unsigned long addr; + unsigned PY_LONG_LONG addr; sipWrapperType *wt; - if (PyArg_ParseTuple(args, "kO!:wrapinstance", &addr, &sipWrapperType_Type, &wt)) + (void)self; + + if (PyArg_ParseTuple(args, "KO!:wrapinstance", &addr, &sipWrapperType_Type, &wt)) return sip_api_convert_from_type((void *)addr, wt->type, NULL); return NULL; @@ -1239,6 +1368,8 @@ static PyObject *wrapInstance(PyObject *self, PyObject *args) */ static PyObject *setDestroyOnExit(PyObject *self, PyObject *args) { + (void)self; + if (PyArg_ParseTuple(args, "i:setdestroyonexit", &destroy_on_exit)) { Py_INCREF(Py_None); @@ -1268,6 +1399,8 @@ static int sip_api_export_module(sipExportedModuleDef *client, sipExportedModuleDef *em; const char *full_name = sipNameOfModule(client); + (void)unused; + /* Check that we can support it. */ if (api_major != SIP_API_MAJOR_NR || api_minor > SIP_API_MINOR_NR) @@ -1367,6 +1500,13 @@ static int sip_api_export_module(sipExportedModuleDef *client, client->em_next = moduleList; moduleList = client; + /* Get any keyword handler. Remove this in SIP v5. */ + if (!got_kw_handler) + { + kw_handler = sip_api_import_symbol("pyqt_kw_handler"); + got_kw_handler = TRUE; + } + return 0; } @@ -1792,6 +1932,40 @@ static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, } +/* + * Convert a new C/C++ instance to a Python instance of a specific Python type.. + */ +static PyObject *sip_api_convert_from_new_pytype(void *cpp, + PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp, + const char *fmt, ...) +{ + PyObject *args, *res; + va_list va; + + va_start(va, fmt); + + if ((args = PyTuple_New(strlen(fmt))) != NULL && buildObject(args, fmt, va) != NULL) + { + res = sipWrapInstance(cpp, py_type, args, owner, + (selfp != NULL ? SIP_DERIVED_CLASS : 0)); + + /* Initialise the rest of an instance of a derived class. */ + if (selfp != NULL) + *selfp = (sipSimpleWrapper *)res; + } + else + { + res = NULL; + } + + Py_XDECREF(args); + + va_end(va); + + return res; +} + + /* * Call the Python re-implementation of a C++ virtual. */ @@ -1843,7 +2017,7 @@ static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...) if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0') badfmt = TRUE; else - tupsz = ep - fmt - 1; + tupsz = (int)(ep - fmt - 1); } else if (strlen(fmt) == 1) tupsz = -1; @@ -2253,7 +2427,7 @@ static int sip_api_parse_result_ex(sip_gilstate_t gil_state, va_list va; va_start(va, fmt); - rc = parseResult(method, res, py_self, fmt, va); + rc = parseResult(method, res, deref_mixin(py_self), fmt, va); va_end(va); Py_DECREF(res); @@ -2282,7 +2456,7 @@ static void sip_api_call_error_handler(sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, sip_gilstate_t sipGILState) { if (error_handler != NULL) - error_handler(py_self, sipGILState); + error_handler(deref_mixin(py_self), sipGILState); else PyErr_Print(); } @@ -2296,6 +2470,9 @@ static int parseResult(PyObject *method, PyObject *res, { int tupsz, rc = 0; + /* We rely on PyErr_Occurred(). */ + PyErr_Clear(); + /* Get self if it is provided as an argument. */ if (*fmt == 'S') { @@ -2395,12 +2572,13 @@ static int parseResult(PyObject *method, PyObject *res, case 'b': { + char *p = va_arg(va, void *); int v = SIPLong_AsLong(arg); if (PyErr_Occurred()) invalid = TRUE; - else - sipSetBool(va_arg(va, void *), v); + else if (p != NULL) + sipSetBool(p, v); } break; @@ -2461,12 +2639,13 @@ static int parseResult(PyObject *method, PyObject *res, case 'd': { + double *p = va_arg(va, double *); double v = PyFloat_AsDouble(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va,double *) = v; + else if (p != NULL) + *p = v; } break; @@ -2479,9 +2658,14 @@ static int parseResult(PyObject *method, PyObject *res, int *p = va_arg(va, int *); if (sip_api_can_convert_to_enum(arg, ((sipEnumTypeObject *)et)->type)) - *p = SIPLong_AsLong(arg); + { + if (p != NULL) + *p = SIPLong_AsLong(arg); + } else + { invalid = TRUE; + } } break; @@ -2492,69 +2676,79 @@ static int parseResult(PyObject *method, PyObject *res, int *p = va_arg(va, int *); if (sip_api_can_convert_to_enum(arg, td)) - *p = SIPLong_AsLong(arg); + { + if (p != NULL) + *p = SIPLong_AsLong(arg); + } else + { invalid = TRUE; + } } break; case 'f': { - float v = PyFloat_AsDouble(arg); + float *p = va_arg(va, float *); + float v = (float)PyFloat_AsDouble(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va,float *) = v; + else if (p != NULL) + *p = v; } break; case 'L': { - signed char v = SIPLong_AsLong(arg); + signed char *p = va_arg(va, signed char *); + signed char v = (signed char)SIPLong_AsLong(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va, signed char *) = v; + else if (p != NULL) + *p = v; } break; case 'M': { - unsigned char v = sip_api_long_as_unsigned_long(arg); + unsigned char *p = va_arg(va, unsigned char *); + unsigned char v = (unsigned char)sip_api_long_as_unsigned_long(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va, unsigned char *) = v; + else if (p != NULL) + *p = v; } break; case 'h': { - short v = SIPLong_AsLong(arg); + signed short *p = va_arg(va, signed short *); + signed short v = (signed short)SIPLong_AsLong(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va, short *) = v; + else if (p != NULL) + *p = v; } break; case 't': { - unsigned short v = sip_api_long_as_unsigned_long(arg); + unsigned short *p = va_arg(va, unsigned short *); + unsigned short v = (unsigned short)sip_api_long_as_unsigned_long(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va,unsigned short *) = v; + else if (p != NULL) + *p = v; } break; @@ -2562,48 +2756,52 @@ static int parseResult(PyObject *method, PyObject *res, case 'e': case 'i': { + int *p = va_arg(va, int *); int v = SIPLong_AsLong(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va, int *) = v; + else if (p != NULL) + *p = v; } break; case 'u': { + unsigned *p = va_arg(va, unsigned *); unsigned v = sip_api_long_as_unsigned_long(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va,unsigned *) = v; + else if (p != NULL) + *p = v; } break; case 'l': { + long *p = va_arg(va, long *); long v = PyLong_AsLong(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va,long *) = v; + else if (p != NULL) + *p = v; } break; case 'm': { + unsigned long *p = va_arg(va, unsigned long *); unsigned long v = sip_api_long_as_unsigned_long(arg); if (PyErr_Occurred()) invalid = TRUE; - else - *va_arg(va, unsigned long *) = v; + else if (p != NULL) + *p = v; } break; @@ -2611,19 +2809,17 @@ static int parseResult(PyObject *method, PyObject *res, case 'n': { #if defined(HAVE_LONG_LONG) + PY_LONG_LONG *p = va_arg(va, PY_LONG_LONG *); PY_LONG_LONG v = PyLong_AsLongLong(arg); #else + long *p = va_arg(va, long *); long v = PyLong_AsLong(arg); #endif if (PyErr_Occurred()) invalid = TRUE; - else -#if defined(HAVE_LONG_LONG) - *va_arg(va, PY_LONG_LONG *) = v; -#else - *va_arg(va, long *) = v; -#endif + else if (p != NULL) + *p = v; } break; @@ -2631,19 +2827,17 @@ static int parseResult(PyObject *method, PyObject *res, case 'o': { #if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG *p = va_arg(va, unsigned PY_LONG_LONG *); unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLongMask(arg); #else + unsigned long *p = va_arg(va, unsigned long *); unsigned long v = PyLong_AsUnsignedLongMask(arg); #endif if (PyErr_Occurred()) invalid = TRUE; - else -#if defined(HAVE_LONG_LONG) - *va_arg(va, unsigned PY_LONG_LONG *) = v; -#else - *va_arg(va, unsigned long *) = v; -#endif + else if (p != NULL) + *p = v; } break; @@ -2698,7 +2892,9 @@ static int parseResult(PyObject *method, PyObject *res, const char **p = va_arg(va, const char **); if (parseBytes_AsString(arg, p) < 0) + { invalid = TRUE; + } else { Py_INCREF(arg); @@ -2728,7 +2924,9 @@ static int parseResult(PyObject *method, PyObject *res, /* This is deprecated. */ if (*fmt == '\0') + { invalid = TRUE; + } else { int flags = *fmt++ - '0'; @@ -2760,7 +2958,9 @@ static int parseResult(PyObject *method, PyObject *res, /* This is deprecated. */ if (*fmt == '\0') + { invalid = TRUE; + } else { int flags = *fmt++ - '0'; @@ -2790,7 +2990,9 @@ static int parseResult(PyObject *method, PyObject *res, case 'H': { if (*fmt == '\0') + { invalid = TRUE; + } else { int flags = *fmt++ - '0'; @@ -2818,10 +3020,12 @@ static int parseResult(PyObject *method, PyObject *res, assert(assign_helper != NULL); - assign_helper(cpp, 0, val); + if (cpp != NULL) + assign_helper(cpp, 0, val); + sip_api_release_type(val, td, state); } - else + else if (cpp != NULL) { *(void **)cpp = val; } @@ -2832,37 +3036,55 @@ static int parseResult(PyObject *method, PyObject *res, case 'N': { - PyTypeObject *type = va_arg(va,PyTypeObject *); - PyObject **p = va_arg(va,PyObject **); + PyTypeObject *type = va_arg(va, PyTypeObject *); + PyObject **p = va_arg(va, PyObject **); - if (arg == Py_None || PyObject_TypeCheck(arg,type)) + if (arg == Py_None || PyObject_TypeCheck(arg, type)) { - Py_INCREF(arg); - *p = arg; + if (p != NULL) + { + Py_INCREF(arg); + *p = arg; + } } else + { invalid = TRUE; + } } break; case 'O': - Py_INCREF(arg); - *va_arg(va,PyObject **) = arg; - break; - - case 'T': { - PyTypeObject *type = va_arg(va,PyTypeObject *); - PyObject **p = va_arg(va,PyObject **); + PyObject **p = va_arg(va, PyObject **); - if (PyObject_TypeCheck(arg,type)) + if (p != NULL) { Py_INCREF(arg); *p = arg; } + } + + break; + + case 'T': + { + PyTypeObject *type = va_arg(va, PyTypeObject *); + PyObject **p = va_arg(va, PyObject **); + + if (PyObject_TypeCheck(arg, type)) + { + if (p != NULL) + { + Py_INCREF(arg); + *p = arg; + } + } else + { invalid = TRUE; + } } break; @@ -2874,7 +3096,7 @@ static int parseResult(PyObject *method, PyObject *res, if (PyErr_Occurred()) invalid = TRUE; - else + else if (p != NULL) *p = v; } @@ -2887,7 +3109,8 @@ static int parseResult(PyObject *method, PyObject *res, if (arg == Py_None) { - *p = NULL; + if (p != NULL) + *p = NULL; } else { @@ -2895,11 +3118,13 @@ static int parseResult(PyObject *method, PyObject *res, void *v = PyCapsule_GetPointer(arg, name); #else void *v = sip_api_convert_to_void_ptr(arg); + + (void)name; #endif if (PyErr_Occurred()) invalid = TRUE; - else + else if (p != NULL) *p = v; } } @@ -2924,11 +3149,16 @@ static int parseResult(PyObject *method, PyObject *res, if (PyObject_CheckReadBuffer(arg)) #endif { - Py_INCREF(arg); - *p = arg; + if (p != NULL) + { + Py_INCREF(arg); + *p = arg; + } } else + { invalid = TRUE; + } } break; @@ -2945,11 +3175,16 @@ static int parseResult(PyObject *method, PyObject *res, if (arg == Py_None || PyObject_CheckReadBuffer(arg)) #endif { - Py_INCREF(arg); - *p = arg; + if (p != NULL) + { + Py_INCREF(arg); + *p = arg; + } } else + { invalid = TRUE; + } } break; @@ -2977,7 +3212,7 @@ static int parseResult(PyObject *method, PyObject *res, * Python versions prior to v2.4 where an integer (or a named enum) causes an * error. */ -static unsigned long sip_api_long_as_unsigned_long(PyObject *o) +unsigned long sip_api_long_as_unsigned_long(PyObject *o) { #if PY_VERSION_HEX < 0x02040000 if (o != NULL && !PyLong_Check(o) && PyInt_Check(o)) @@ -3042,16 +3277,12 @@ static int sip_api_parse_kwd_args(PyObject **parseErrp, PyObject *sipArgs, if (unused != NULL) { - /* Initialise the return of any unused keyword arguments. */ + /* + * Initialise the return of any unused keyword arguments. This is + * used by any ctor overload. + */ *unused = NULL; } - else if (sipKwdArgs != NULL && kwdlist == NULL) - { - /* __init__ methods avoid the normal Python checks. */ - PyErr_SetString(PyExc_TypeError, - "keyword arguments are not supported"); - return FALSE; - } va_start(va, fmt); ok = parseKwdArgs(parseErrp, sipArgs, sipKwdArgs, kwdlist, unused, fmt, @@ -3609,7 +3840,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, arg = PyTuple_GET_ITEM(sipArgs, argnr); failure.arg_nr = argnr + 1; } - else if (sipKwdArgs != NULL && kwdlist != NULL) + else if (nr_kwd_args != 0 && kwdlist != NULL) { const char *name = kwdlist[argnr - *selfargp]; @@ -4316,7 +4547,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { int v = SIPLong_AsLong(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4360,7 +4591,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { int v = SIPLong_AsLong(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4385,7 +4616,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { unsigned v = sip_api_long_as_unsigned_long(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4408,9 +4639,9 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, if (arg != NULL) { - signed char v = SIPLong_AsLong(arg); + signed char v = (signed char)SIPLong_AsLong(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4433,9 +4664,9 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, if (arg != NULL) { - unsigned char v = sip_api_long_as_unsigned_long(arg); + unsigned char v = (unsigned char)sip_api_long_as_unsigned_long(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4454,13 +4685,13 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { /* Short integer. */ - short *p = va_arg(va, short *); + signed short *p = va_arg(va, signed short *); if (arg != NULL) { - short v = SIPLong_AsLong(arg); + signed short v = (signed short)SIPLong_AsLong(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4483,9 +4714,9 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, if (arg != NULL) { - unsigned short v = sip_api_long_as_unsigned_long(arg); + unsigned short v = (unsigned short)sip_api_long_as_unsigned_long(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4510,7 +4741,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { long v = PyLong_AsLong(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4535,7 +4766,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, { unsigned long v = sip_api_long_as_unsigned_long(arg); - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4568,7 +4799,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, long v = PyLong_AsLong(arg); #endif - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -4601,7 +4832,7 @@ static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, unsigned long v = PyLong_AsUnsignedLongMask(arg); #endif - if (PyErr_Occurred()) + if (non_overflow_exception()) { failure.reason = WrongType; failure.detail_obj = arg; @@ -5206,7 +5437,7 @@ static int parsePass2(sipSimpleWrapper *self, int selfarg, PyObject *sipArgs, if (arg != NULL) { - PyObject *s; + PyObject *s = NULL; switch (sub_fmt) { @@ -5965,13 +6196,15 @@ static sipExportedModuleDef *getModule(PyObject *mname_obj) /* * The type unpickler. */ -static PyObject *unpickle_type(PyObject *ignore, PyObject *args) +static PyObject *unpickle_type(PyObject *obj, PyObject *args) { PyObject *mname_obj, *init_args; const char *tname; sipExportedModuleDef *em; int i; + (void)obj; + if (!PyArg_ParseTuple(args, #if PY_MAJOR_VERSION >= 3 "UsO!:_unpickle_type", @@ -6009,10 +6242,12 @@ static PyObject *unpickle_type(PyObject *ignore, PyObject *args) /* * The type pickler. */ -static PyObject *pickle_type(PyObject *obj, PyObject *ignore) +static PyObject *pickle_type(PyObject *obj, PyObject *args) { sipExportedModuleDef *em; + (void)args; + /* Find the type definition and defining module. */ for (em = moduleList; em != NULL; em = em->em_next) { @@ -6064,13 +6299,15 @@ static PyObject *pickle_type(PyObject *obj, PyObject *ignore) /* * The enum unpickler. */ -static PyObject *unpickle_enum(PyObject *ignore, PyObject *args) +static PyObject *unpickle_enum(PyObject *obj, PyObject *args) { PyObject *mname_obj, *evalue_obj; const char *ename; sipExportedModuleDef *em; int i; + (void)obj; + if (!PyArg_ParseTuple(args, #if PY_MAJOR_VERSION >= 3 "UsO:_unpickle_enum", @@ -6103,10 +6340,12 @@ static PyObject *unpickle_enum(PyObject *ignore, PyObject *args) /* * The enum pickler. */ -static PyObject *pickle_enum(PyObject *obj, PyObject *ignore) +static PyObject *pickle_enum(PyObject *obj, PyObject *args) { sipTypeDef *td = ((sipEnumTypeObject *)Py_TYPE(obj))->type; + (void)args; + return Py_BuildValue("O(Osi)", enum_unpickler, td->td_module->em_nameobj, sipPyNameOfEnum((sipEnumTypeDef *)td), #if PY_MAJOR_VERSION >= 3 @@ -6154,7 +6393,7 @@ static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd, { static PyObject *bases = NULL; PyObject *name, *type_dict, *args, *dict; - PyTypeObject *py_type; + sipEnumTypeObject *eto; etd->etd_base.td_module = client; @@ -6208,24 +6447,45 @@ static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd, /* Pass the type via the back door. */ assert(currentType == NULL); currentType = &etd->etd_base; - py_type = (PyTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type, + eto = (sipEnumTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type, args, NULL); currentType = NULL; Py_DECREF(args); - if (py_type == NULL) + if (eto == NULL) goto relname; /* Add the type to the "parent" dictionary. */ - if (PyDict_SetItem(dict, name, (PyObject *)py_type) < 0) + if (PyDict_SetItem(dict, name, (PyObject *)eto) < 0) { - Py_DECREF((PyObject *)py_type); + Py_DECREF((PyObject *)eto); goto relname; } if (etd->etd_pyslots != NULL) - fix_slots((PyTypeObject *)py_type, etd->etd_pyslots); + fix_slots((PyTypeObject *)eto, etd->etd_pyslots); + +#if PY_VERSION_HEX >= 0x03030000 + /* + * If the enum has a scope then the default __qualname__ will be incorrect. + */ + if (etd->etd_scope >= 0) + { + PyTypeObject *scope_type; + + /* Get the type that is the enum's scope. */ + scope_type = sipTypeAsPyTypeObject(client->em_types[etd->etd_scope]); + + /* Append the name of the enum to the scope's __qualname__. */ + Py_CLEAR(eto->super.ht_qualname); + eto->super.ht_qualname = PyUnicode_FromFormat("%U.%U", + ((PyHeapTypeObject *)scope_type)->ht_qualname, name); + + if (eto->super.ht_qualname == NULL) + goto relname; + } +#endif /* We can now release our remaining references. */ Py_DECREF(name); @@ -6728,6 +6988,27 @@ static int sip_api_register_attribute_getter(const sipTypeDef *td, } +/* + * Register a proxy resolver. + */ +static int sip_api_register_proxy_resolver(const sipTypeDef *td, + sipProxyResolverFunc resolver) +{ + sipProxyResolver *pr = sip_api_malloc(sizeof (sipProxyResolver)); + + if (pr == NULL) + return -1; + + pr->td = td; + pr->resolver = resolver; + pr->next = proxyResolvers; + + proxyResolvers = pr; + + return 0; +} + + /* * Report a function with invalid argument types. */ @@ -6869,14 +7150,13 @@ static void sip_api_no_method(PyObject *parseErr, const char *scope, else { #if PY_MAJOR_VERSION >= 3 - failure = PyUnicode_FromFormat("\n overload %zd: %U", - i + 1, detail); -#elif PY_VERSION_HEX >= 0x02050000 - failure = PyString_FromFormat("\n overload %zd: %s", - i + 1, PyString_AS_STRING(detail)); + failure = PyUnicode_FromFormat( + "\n overload " SIP_SSIZE_T_FORMAT ": %U", i + 1, + detail); #else - failure = PyString_FromFormat("\n overload %d: %s", - i + 1, PyString_AS_STRING(detail)); + failure = PyString_FromFormat( + "\n overload " SIP_SSIZE_T_FORMAT ": %s", i + 1, + PyString_AS_STRING(detail)); #endif } @@ -7170,11 +7450,7 @@ static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen, SIP_SSIZE_T slicelen) { PyErr_Format(PyExc_ValueError, -#if PY_VERSION_HEX >= 0x02050000 - "attempt to assign sequence of size %zd to slice of size %zd", -#else - "attempt to assign sequence of size %d to slice of size %d", -#endif + "attempt to assign sequence of size " SIP_SSIZE_T_FORMAT " to slice of size " SIP_SSIZE_T_FORMAT, seqlen, slicelen); } @@ -7789,12 +8065,16 @@ static int addSingleTypeInstance(PyObject *dict, const char *name, } else { - sipConvertFromFunc cfrom = get_from_convertor(td); + sipConvertFromFunc cfrom; + + cppPtr = resolve_proxy(td, cppPtr); + + cfrom = get_from_convertor(td); if (cfrom != NULL) obj = cfrom(cppPtr, NULL); else - obj = sipWrapSimpleInstance(cppPtr, td, NULL, initflags); + obj = wrap_simple_instance(cppPtr, td, NULL, initflags); } if (obj == NULL) @@ -7862,6 +8142,9 @@ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, * its ctor has returned. In either case say there is no Python * reimplementation. */ + if (sipSelf != NULL) + sipSelf = deref_mixin(sipSelf); + if (sipSelf == NULL) goto release_gil; @@ -8070,7 +8353,7 @@ static void *indirect_access_func(sipSimpleWrapper *sw, AccessFuncOp op) addr = *((void **)sw->data); break; - case ReleaseGuard: + default: addr = NULL; break; } @@ -8317,9 +8600,8 @@ static void *sip_api_convert_to_type(PyObject *pyObj, const sipTypeDef *td, * Convert a Python object to a C/C++ pointer and raise an exception if it * can't be done. */ -static void *sip_api_force_convert_to_type(PyObject *pyObj, - const sipTypeDef *td, PyObject *transferObj, int flags, int *statep, - int *iserrp) +void *sip_api_force_convert_to_type(PyObject *pyObj, const sipTypeDef *td, + PyObject *transferObj, int flags, int *statep, int *iserrp) { /* Don't even try if there has already been an error. */ if (*iserrp) @@ -8408,6 +8690,8 @@ PyObject *sip_api_convert_from_type(void *cpp, const sipTypeDef *td, return Py_None; } + cpp = resolve_proxy(td, cpp); + cfrom = get_from_convertor(td); if (cfrom != NULL) @@ -8420,7 +8704,7 @@ PyObject *sip_api_convert_from_type(void *cpp, const sipTypeDef *td, /* See if we have already wrapped it. */ if ((py = sip_api_get_pyobject(cpp, td)) != NULL) Py_INCREF(py); - else if ((py = sipWrapSimpleInstance(cpp, td, NULL, SIP_SHARE_MAP)) == NULL) + else if ((py = wrap_simple_instance(cpp, td, NULL, SIP_SHARE_MAP)) == NULL) return NULL; /* Handle any ownership transfer. */ @@ -8452,6 +8736,8 @@ static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td, return Py_None; } + cpp = resolve_proxy(td, cpp); + cfrom = get_from_convertor(td); if (cfrom != NULL) @@ -8483,7 +8769,8 @@ static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td, else owner = (sipWrapper *)transferObj; - return sipWrapSimpleInstance(cpp, td, owner, (owner == NULL ? SIP_PY_OWNED : 0)); + return wrap_simple_instance(cpp, td, owner, + (owner == NULL ? SIP_PY_OWNED : 0)); } @@ -8885,7 +9172,7 @@ static void sip_api_raise_type_exception(const sipTypeDef *td, void *ptr) SIP_BLOCK_THREADS - self = sipWrapSimpleInstance(ptr, td, NULL, SIP_PY_OWNED); + self = wrap_simple_instance(ptr, td, NULL, SIP_PY_OWNED); PyErr_SetObject((PyObject *)sipTypeAsPyTypeObject(td), self); @@ -8921,7 +9208,7 @@ static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc, /* * Return the generated class type structure of a class's super-class. */ -sipClassTypeDef *sipGetGeneratedClassType(sipEncodedTypeDef *enc, +sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc, const sipClassTypeDef *ctd) { return (sipClassTypeDef *)getGeneratedType(enc, ctd->ctd_base.td_module); @@ -8939,31 +9226,11 @@ static void *findSlot(PyObject *self, sipPySlotType st) /* See if it is a wrapper. */ if (PyObject_TypeCheck((PyObject *)py_type, &sipWrapperType_Type)) { - sipClassTypeDef *ctd; + const sipClassTypeDef *ctd; ctd = (sipClassTypeDef *)((sipWrapperType *)(py_type))->type; - if (ctd->ctd_pyslots != NULL) - slot = findSlotInType(ctd->ctd_pyslots, st); - else - slot = NULL; - - if (slot == NULL) - { - sipEncodedTypeDef *sup; - - /* Search any super-types. */ - if ((sup = ctd->ctd_supers) != NULL) - do - { - sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, - ctd); - - if (sup_ctd->ctd_pyslots != NULL) - slot = findSlotInType(sup_ctd->ctd_pyslots, st); - } - while (slot == NULL && !sup++->sc_flag); - } + slot = findSlotInClass(ctd, st); } else { @@ -8976,7 +9243,41 @@ static void *findSlot(PyObject *self, sipPySlotType st) assert(etd->etd_pyslots != NULL); - slot = findSlotInType(etd->etd_pyslots, st); + slot = findSlotInSlotList(etd->etd_pyslots, st); + } + + return slot; +} + + +/* + * Find a particular slot function in a class hierarchy. + */ +static void *findSlotInClass(const sipClassTypeDef *ctd, sipPySlotType st) +{ + void *slot; + + if (ctd->ctd_pyslots != NULL) + slot = findSlotInSlotList(ctd->ctd_pyslots, st); + else + slot = NULL; + + if (slot == NULL) + { + sipEncodedTypeDef *sup; + + /* Search any super-types. */ + if ((sup = ctd->ctd_supers) != NULL) + { + do + { + const sipClassTypeDef *sup_ctd = sipGetGeneratedClassType( + sup, ctd); + + slot = findSlotInClass(sup_ctd, st); + } + while (slot == NULL && !sup++->sc_flag); + } } return slot; @@ -8986,7 +9287,7 @@ static void *findSlot(PyObject *self, sipPySlotType st) /* * Find a particular slot function in a particular type. */ -static void *findSlotInType(sipPySlotDef *psd, sipPySlotType st) +static void *findSlotInSlotList(sipPySlotDef *psd, sipPySlotType st) { while (psd->psd_func != NULL) { @@ -9136,7 +9437,8 @@ static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems) if (sipTypeIsClass(currentType)) { - const char *docstring = ((sipClassTypeDef *)currentType)->ctd_docstring; + const sipClassTypeDef *ctd = (const sipClassTypeDef *)currentType; + const char *docstring = ctd->ctd_docstring; /* * Skip the marker that identifies the docstring as being @@ -9147,7 +9449,11 @@ static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems) ((PyTypeObject *)o)->tp_doc = docstring; - addClassSlots((sipWrapperType *)o, (sipClassTypeDef *)currentType); + addClassSlots((sipWrapperType *)o, ctd); + + /* Patch any mixin initialiser. */ + if (ctd->ctd_init_mixin != NULL) + ((PyTypeObject *)o)->tp_init = ctd->ctd_init_mixin; } } @@ -9229,10 +9535,12 @@ static int sipWrapperType_setattro(PyObject *self, PyObject *name, static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args, PyObject *kwds) { - static PyObject *noargs = NULL; sipTypeDef *td = wt->type; sipContainerDef *cod; + (void)args; + (void)kwds; + /* Check the base types are not being used directly. */ if (wt == &sipSimpleWrapper_Type || wt == &sipWrapper_Type) { @@ -9251,15 +9559,6 @@ static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args, else cod = &((sipClassTypeDef *)td)->ctd_container; - /* We need an empty tuple for an empty argument list. */ - if (noargs == NULL) - { - noargs = PyTuple_New(0); - - if (noargs == NULL) - return NULL; - } - /* See if it is a mapped type. */ if (sipTypeIsMapped(td)) { @@ -9303,7 +9602,7 @@ static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args, } /* See if it is an abstract type. */ - if (sipTypeIsAbstract(td) && sipIsExactWrappedType(wt)) + if (sipTypeIsAbstract(td) && sipIsExactWrappedType(wt) && ((sipClassTypeDef *)td)->ctd_init_mixin == NULL) { PyErr_Format(PyExc_TypeError, "%s.%s represents a C++ abstract class and cannot be instantiated", @@ -9315,7 +9614,7 @@ static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args, } /* Call the standard super-type new. */ - return PyBaseObject_Type.tp_new((PyTypeObject *)wt, noargs, NULL); + return PyBaseObject_Type.tp_new((PyTypeObject *)wt, empty_tuple, NULL); } @@ -9326,34 +9625,15 @@ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, PyObject *kwds) { void *sipNew; - int sipFlags; + int sipFlags, from_cpp = TRUE; sipWrapper *owner; sipWrapperType *wt = (sipWrapperType *)Py_TYPE(self); sipTypeDef *td = wt->type; sipClassTypeDef *ctd = (sipClassTypeDef *)td; - PyObject *unused, **unused_p; + PyObject *unused = NULL; + sipFinalFunc final_func; - static int got_kw_handler = FALSE; - static int (*kw_handler)(PyObject *, void *, PyObject *); - - /* - * Get any keyword handler if necessary. In SIP v5 this will be - * generalised and not PyQt specific. - */ - if (!got_kw_handler) - { - kw_handler = sip_api_import_symbol("pyqt_kw_handler"); - got_kw_handler = TRUE; - } - - /* - * We are interested in unused keyword arguments if we are creating a - * QObject and we have a handler. - */ - unused_p = (kw_handler != NULL && isQObject((PyObject *)self)) ? &unused : NULL; - unused = NULL; - - /* Check there is no existing C++ instance waiting to be wrapped. */ + /* Check for an existing C++ instance waiting to be wrapped. */ if (sipGetPending(&sipNew, &owner, &sipFlags) < 0) return -1; @@ -9364,7 +9644,7 @@ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, /* Call the C++ ctor. */ owner = NULL; - sipNew = ctd->ctd_init(self, args, kwds, unused_p, (PyObject **)&owner, + sipNew = ctd->ctd_init(self, args, kwds, &unused, (PyObject **)&owner, &parseErr); if (sipNew != NULL) @@ -9389,7 +9669,7 @@ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, */ while (PyList_Check(parseErr) && ie != NULL) { - sipNew = ie->ie_extender(self, args, kwds, unused_p, + sipNew = ie->ie_extender(self, args, kwds, &unused, (PyObject **)&owner, &parseErr); if (sipNew != NULL) @@ -9433,16 +9713,27 @@ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, Py_INCREF(self); owner = NULL; } + + /* The instance was created from Python. */ + from_cpp = FALSE; } - /* - * If there is an owner then we assume that the wrapper supports the - * concept. - */ - if (owner != NULL) + /* Handler any owner if the type supports the concept. */ + if (PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type)) { - assert(PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type)); - addToParent((sipWrapper *)self, (sipWrapper *)owner); + /* + * The application may be doing something very unadvisable (like + * calling __init__() for a second time), so make sure we don't already + * have a parent. + */ + removeFromParent((sipWrapper *)self); + + if (owner != NULL) + { + assert(PyObject_TypeCheck((PyObject *)owner, (PyTypeObject *)&sipWrapper_Type)); + + addToParent((sipWrapper *)self, (sipWrapper *)owner); + } } self->data = sipNew; @@ -9459,22 +9750,377 @@ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, if (!sipNotInMap(self)) sipOMAddObject(&cppPyMap, self); - /* If we have unused keyword arguments then we know how to handle them. */ - if (unused != NULL) - { - int rc; + /* If we are wrapping an instance returned from C/C++ then we are done. */ + if (from_cpp) + return 0; - rc = kw_handler((PyObject *)self, sipNew, unused); + /* Call any finalisation code. */ + if ((final_func = find_finalisation(ctd)) != NULL) + { + PyObject *new_unused = NULL, **new_unused_p; + + if (unused == NULL || unused != kwds) + { + /* + * There are no unused arguments or we have already created a dict + * containing the unused sub-set, so there is no need to create + * another. + */ + new_unused_p = NULL; + } + else + { + /* + * All of the keyword arguments are unused, so if some of them are + * now going to be used then a new dict will be needed. + */ + new_unused_p = &new_unused; + } + + if (final_func((PyObject *)self, sipNew, unused, new_unused_p) < 0) + { + Py_XDECREF(unused); + return -1; + } + + if (new_unused != NULL) + { + Py_DECREF(unused); + unused = new_unused; + } + } + + /* Call the handler if we have one. Remove this in SIP v5. */ + if (kw_handler != NULL && unused != NULL && isQObject((PyObject *)self)) + { + int rc = kw_handler((PyObject *)self, sipNew, unused); + + /* + * A handler will always consume all unused keyword arguments (or raise + * an exception) so discard the dict now. + */ Py_DECREF(unused); if (rc < 0) return -1; + + unused = NULL; + } + + /* See if we should call the equivalent of super().__init__(). */ + if (sipTypeCallSuperInit(&ctd->ctd_base)) + { + PyObject *next; + + /* Find the next type in the MRO. */ + next = next_in_mro((PyObject *)self, + (PyObject *)&sipSimpleWrapper_Type); + + /* + * If the next type in the MRO is object then take a shortcut by not + * calling super().__init__() but emulating object.__init__() instead. + * This will be the most common case and also allows us to generate a + * better exception message if there are unused keyword arguments. The + * disadvantage is that the exception message will be different if + * there is a mixin. + */ + if (next != (PyObject *)&PyBaseObject_Type) + { + int rc = super_init((PyObject *)self, empty_tuple, unused, next); + + Py_XDECREF(unused); + + return rc; + } + } + + if (unused_backdoor != NULL) + { + /* + * We are being called by a mixin's __init__ so save any unused + * arguments for it to pass on to the main class's __init__. + */ + *unused_backdoor = unused; + } + else if (unused != NULL) + { + /* We shouldn't have any unused keyword arguments. */ + if (PyDict_Size(unused) != 0) + { + PyObject *key, *value; + SIP_SSIZE_T pos = 0; + + /* Just report one of the unused arguments. */ + PyDict_Next(unused, &pos, &key, &value); + +#if PY_MAJOR_VERSION >= 3 + PyErr_Format(PyExc_TypeError, + "'%S' is an unknown keyword argument", key); +#else + { + PyObject *key_s = PyObject_Str(key); + + if (key_s != NULL) + { + PyErr_Format(PyExc_TypeError, + "'%s' is an unknown keyword argument", + PyString_AsString(key_s)); + + Py_DECREF(key_s); + } + } +#endif + + Py_DECREF(unused); + + return -1; + } + + Py_DECREF(unused); } return 0; } +/* + * Get the C++ address of a mixin. + */ +static void *sip_api_get_mixin_address(sipSimpleWrapper *w, + const sipTypeDef *td) +{ + PyObject *mixin; + void *cpp; + + if ((mixin = PyObject_GetAttrString((PyObject *)w, sipTypeName(td))) == NULL) + return NULL; + + cpp = sip_api_get_address((sipSimpleWrapper *)mixin); + + Py_DECREF(mixin); + + return cpp; +} + + +/* + * Initialise a mixin. + */ +static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds, + const sipClassTypeDef *ctd) +{ + int rc; + SIP_SSIZE_T pos; + PyObject *unused, *mixin, *mixin_name, *key, *value; + PyTypeObject *self_wt = sipTypeAsPyTypeObject(((sipWrapperType *)Py_TYPE(self))->type); + PyTypeObject *wt = sipTypeAsPyTypeObject(&ctd->ctd_base); + +#if PY_MAJOR_VERSION >= 3 + static PyObject *double_us = NULL; + + if (objectify("__", &double_us) < 0) + return -1; +#endif + + /* If we are not a mixin to another wrapped class then behave as normal. */ + if (PyType_IsSubtype(self_wt, wt)) + return super_init(self, args, kwds, next_in_mro(self, (PyObject *)wt)); + + /* + * Create the mixin instance. Retain the positional arguments for the + * super-class. Remember that, even though the mixin appears after the + * main class in the MRO, it appears before sipWrapperType where the main + * class's arguments are actually parsed. + */ + unused = NULL; + unused_backdoor = &unused; + mixin = PyObject_Call((PyObject *)wt, empty_tuple, kwds); + unused_backdoor = NULL; + + if (mixin == NULL) + goto gc_unused; + + /* Make sure the mixin can find the main instance. */ + ((sipSimpleWrapper *)mixin)->mixin_main = self; + Py_INCREF(self); + +#if PY_MAJOR_VERSION >= 3 + mixin_name = PyUnicode_FromString(sipTypeName(&ctd->ctd_base)); +#else + mixin_name = PyString_FromString(sipTypeName(&ctd->ctd_base)); +#endif + + if (mixin_name == NULL) + { + Py_DECREF(mixin); + goto gc_unused; + } + + rc = PyObject_SetAttr(self, mixin_name, mixin); + Py_DECREF(mixin); + + if (rc < 0) + goto gc_mixin_name; + + /* Add the mixin's useful attributes to the main class. */ + pos = 0; + + while (PyDict_Next(wt->tp_dict, &pos, &key, &value)) + { + /* Don't replace existing values. */ + if (PyDict_Contains(Py_TYPE(self)->tp_dict, key) != 0) + continue; + + /* Skip values with names that start with double underscore. */ +#if PY_MAJOR_VERSION >= 3 + if (!PyUnicode_Check(key)) + continue; + + /* + * Despite what the docs say this returns a Py_ssize_t - although the + * docs are probably right. + */ + rc = (int)PyUnicode_Tailmatch(key, double_us, 0, 2, -1); + + if (rc < 0) + goto gc_mixin_name; + + if (rc > 0) + continue; +#else + if (!PyString_Check(key)) + continue; + + if (PyString_GET_SIZE(key) >= 2 && strncmp(PyString_AS_STRING(key), "__", 2) == 0) + continue; +#endif + + if (PyObject_IsInstance(value, (PyObject *)&sipMethodDescr_Type)) + { + if ((value = sipMethodDescr_Copy(value, mixin_name)) == NULL) + goto gc_mixin_name; + } + else if (PyObject_IsInstance(value, (PyObject *)&sipVariableDescr_Type)) + { + if ((value = sipVariableDescr_Copy(value, mixin_name)) == NULL) + goto gc_mixin_name; + } + else + { + Py_INCREF(value); + } + + rc = PyDict_SetItem(Py_TYPE(self)->tp_dict, key, value); + + Py_DECREF(value); + + if (rc < 0) + goto gc_mixin_name; + } + + Py_DECREF(mixin_name); + + /* Call the super-class's __init__ with any remaining arguments. */ + rc = super_init(self, args, unused, next_in_mro(self, (PyObject *)wt)); + Py_XDECREF(unused); + + return rc; + +gc_mixin_name: + Py_DECREF(mixin_name); + +gc_unused: + Py_XDECREF(unused); + + return -1; +} + + +/* + * Return the next in the MRO of an instance after a given type. + */ +static PyObject *next_in_mro(PyObject *self, PyObject *after) +{ + int i; + PyObject *mro; + + mro = Py_TYPE(self)->tp_mro; + assert(PyTuple_Check(mro)); + + for (i = 0; i < PyTuple_GET_SIZE(mro); ++i) + if (PyTuple_GET_ITEM(mro, i) == after) + break; + + /* Assert that we have found ourself and that we are not the last. */ + assert(i + 1 < PyTuple_GET_SIZE(mro)); + + return PyTuple_GET_ITEM(mro, i + 1); +} + + +/* + * Call the equivalent of super()__init__() of an instance. + */ +static int super_init(PyObject *self, PyObject *args, PyObject *kwds, + PyObject *type) +{ + int i; + PyObject *init, *init_args, *init_res; + + if ((init = PyObject_GetAttr(type, init_name)) == NULL) + return -1; + + if ((init_args = PyTuple_New(1 + PyTuple_GET_SIZE(args))) == NULL) + { + Py_DECREF(init); + return -1; + } + + PyTuple_SET_ITEM(init_args, 0, self); + Py_INCREF(self); + + for (i = 0; i < PyTuple_GET_SIZE(args); ++i) + { + PyObject *arg = PyTuple_GET_ITEM(args, i); + + PyTuple_SET_ITEM(init_args, 1 + i, arg); + Py_INCREF(arg); + } + + init_res = PyObject_Call(init, init_args, kwds); + Py_DECREF(init_args); + Py_DECREF(init); + Py_XDECREF(init_res); + + return (init_res != NULL) ? 0 : -1; +} + + +/* + * Find any finalisation function for a class, searching its super-classes if + * necessary. + */ +static sipFinalFunc find_finalisation(sipClassTypeDef *ctd) +{ + sipEncodedTypeDef *sup; + + if (ctd->ctd_final != NULL) + return ctd->ctd_final; + + if ((sup = ctd->ctd_supers) != NULL) + do + { + sipTypeDef *sup_td = getGeneratedType(sup, ctd->ctd_base.td_module); + sipFinalFunc func; + + if ((func = find_finalisation((sipClassTypeDef *)sup_td)) != NULL) + return func; + } + while (!sup++->sc_flag); + + return NULL; +} + /* * The instance traverse slot. */ @@ -9492,7 +10138,7 @@ static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit, if (ctd->ctd_traverse == NULL) { - sipEncodedTypeDef *sup; + const sipEncodedTypeDef *sup; if ((sup = ctd->ctd_supers) != NULL) do @@ -9517,6 +10163,10 @@ static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit, if ((vret = visit(self->user, arg)) != 0) return vret; + if (self->mixin_main != NULL) + if ((vret = visit(self->mixin_main, arg)) != 0) + return vret; + return 0; } @@ -9565,6 +10215,11 @@ static int sipSimpleWrapper_clear(sipSimpleWrapper *self) self->user = NULL; Py_XDECREF(tmp); + /* Remove any mixin main. */ + tmp = self->mixin_main; + self->mixin_main = NULL; + Py_XDECREF(tmp); + return vret; } @@ -9813,9 +10468,9 @@ static PyObject *slot_richcompare(PyObject *self, PyObject *arg, int op) /* * The __dict__ getter. */ -static PyObject *sipSimpleWrapper_get_dict(PyObject *self, void *closure) +static PyObject *sipSimpleWrapper_get_dict(sipSimpleWrapper *sw, void *closure) { - sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + (void)closure; /* Create the dictionary if needed. */ if (sw->dict == NULL) @@ -9834,10 +10489,10 @@ static PyObject *sipSimpleWrapper_get_dict(PyObject *self, void *closure) /* * The __dict__ setter. */ -static int sipSimpleWrapper_set_dict(PyObject *self, PyObject *value, +static int sipSimpleWrapper_set_dict(sipSimpleWrapper *sw, PyObject *value, void *closure) { - sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + (void)closure; /* Check that any new value really is a dictionary. */ if (value != NULL && !PyDict_Check(value)) @@ -9861,8 +10516,8 @@ static int sipSimpleWrapper_set_dict(PyObject *self, PyObject *value, * The table of getters and setters. */ static PyGetSetDef sipSimpleWrapper_getset[] = { - {(char *)"__dict__", sipSimpleWrapper_get_dict, sipSimpleWrapper_set_dict, - NULL, NULL}, + {(char *)"__dict__", (getter)sipSimpleWrapper_get_dict, + (setter)sipSimpleWrapper_set_dict, NULL, NULL}, {NULL, NULL, NULL, NULL, NULL} }; @@ -9917,12 +10572,24 @@ sipWrapperType sipSimpleWrapper_Type = { 0, /* tp_alloc */ (newfunc)sipSimpleWrapper_new, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }, #if !defined(STACKLESS) }, #endif 0, - 0 + 0, + 0, }; @@ -10037,7 +10704,7 @@ static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg) /* * Add the slots for a class type and all its super-types. */ -static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd) +static void addClassSlots(sipWrapperType *wt, const sipClassTypeDef *ctd) { /* Add the buffer interface. */ #if PY_MAJOR_VERSION >= 3 @@ -10765,7 +11432,8 @@ static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap) return -1; } - *ap = *SIPBytes_AS_STRING(bytes); + if (ap != NULL) + *ap = *SIPBytes_AS_STRING(bytes); Py_DECREF(bytes); @@ -10925,18 +11593,29 @@ static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj, static int parseBytes_AsCharArray(PyObject *obj, const char **ap, SIP_SSIZE_T *aszp) { + const char *a; + SIP_SSIZE_T asz; + if (obj == Py_None) { - *ap = NULL; - *aszp = 0; + a = NULL; + asz = 0; } else if (SIPBytes_Check(obj)) { - *ap = SIPBytes_AS_STRING(obj); - *aszp = SIPBytes_GET_SIZE(obj); + a = SIPBytes_AS_STRING(obj); + asz = SIPBytes_GET_SIZE(obj); } - else if (PyObject_AsCharBuffer(obj, ap, aszp) < 0) + else if (PyObject_AsCharBuffer(obj, &a, &asz) < 0) + { return -1; + } + + if (ap != NULL) + *ap = a; + + if (aszp != NULL) + *aszp = asz; return 0; } @@ -10956,12 +11635,15 @@ static int parseBytes_AsChar(PyObject *obj, char *ap) sz = SIPBytes_GET_SIZE(obj); } else if (PyObject_AsCharBuffer(obj, &chp, &sz) < 0) + { return -1; + } if (sz != 1) return -1; - *ap = *chp; + if (ap != NULL) + *ap = *chp; return 0; } @@ -10972,9 +11654,16 @@ static int parseBytes_AsChar(PyObject *obj, char *ap) */ static int parseBytes_AsString(PyObject *obj, const char **ap) { + const char *a; SIP_SSIZE_T sz; - return parseBytes_AsCharArray(obj, ap, &sz); + if (parseBytes_AsCharArray(obj, &a, &sz) < 0) + return -1; + + if (ap != NULL) + *ap = a; + + return 0; } @@ -11032,19 +11721,21 @@ static wchar_t *sip_api_unicode_as_wstring(PyObject *obj) */ static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp) { + wchar_t *a; + SIP_SSIZE_T asz; + if (obj == Py_None) { - *ap = NULL; - *aszp = 0; - - return 0; + a = NULL; + asz = 0; + } + else if (PyUnicode_Check(obj)) + { + if (convertToWCharArray(obj, &a, &asz) < 0) + return -1; } - - if (PyUnicode_Check(obj)) - return convertToWCharArray(obj, ap, aszp); - #if PY_MAJOR_VERSION < 3 - if (PyString_Check(obj)) + else if (PyString_Check(obj)) { int rc; PyObject *uobj; @@ -11052,14 +11743,25 @@ static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp) if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; - rc = convertToWCharArray(uobj, ap, aszp); + rc = convertToWCharArray(uobj, &a, &asz); Py_DECREF(uobj); - return rc; + if (rc < 0) + return -1; } #endif + else + { + return -1; + } - return -1; + if (ap != NULL) + *ap = a; + + if (aszp != NULL) + *aszp = asz; + + return 0; } @@ -11105,11 +11807,15 @@ static int convertToWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp) */ static int parseWChar(PyObject *obj, wchar_t *ap) { - if (PyUnicode_Check(obj)) - return convertToWChar(obj, ap); + wchar_t a; + if (PyUnicode_Check(obj)) + { + if (convertToWChar(obj, &a) < 0) + return -1; + } #if PY_MAJOR_VERSION < 3 - if (PyString_Check(obj)) + else if (PyString_Check(obj)) { int rc; PyObject *uobj; @@ -11117,14 +11823,22 @@ static int parseWChar(PyObject *obj, wchar_t *ap) if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; - rc = convertToWChar(uobj, ap); + rc = convertToWChar(uobj, &a); Py_DECREF(uobj); - return rc; + if (rc < 0) + return -1; } #endif + else + { + return -1; + } - return -1; + if (ap != NULL) + *ap = a; + + return 0; } @@ -11156,18 +11870,19 @@ static int convertToWChar(PyObject *obj, wchar_t *ap) */ static int parseWCharString(PyObject *obj, wchar_t **ap) { + wchar_t *a; + if (obj == Py_None) { - *ap = NULL; - - return 0; + a = NULL; + } + else if (PyUnicode_Check(obj)) + { + if (convertToWCharString(obj, &a) < 0) + return -1; } - - if (PyUnicode_Check(obj)) - return convertToWCharString(obj, ap); - #if PY_MAJOR_VERSION < 3 - if (PyString_Check(obj)) + else if (PyString_Check(obj)) { int rc; PyObject *uobj; @@ -11175,14 +11890,22 @@ static int parseWCharString(PyObject *obj, wchar_t **ap) if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; - rc = convertToWCharString(uobj, ap); + rc = convertToWCharString(uobj, &a); Py_DECREF(uobj); - return rc; + if (rc < 0) + return -1; } #endif + else + { + return -1; + } - return -1; + if (ap != NULL) + *ap = a; + + return 0; } @@ -11315,8 +12038,11 @@ static int check_encoded_string(PyObject *obj) /* * This is called by the atexit module. */ -static PyObject *sip_exit(PyObject *obj, PyObject *ignore) +static PyObject *sip_exit(PyObject *self, PyObject *args) { + (void)self; + (void)args; + /* Disable all Python reimplementations of virtuals. */ sipInterpreter = NULL; @@ -11364,7 +12090,7 @@ static void register_exit_notifier(void) /* * Return the function that converts a C++ instance to a Python object. */ -static sipConvertFromFunc get_from_convertor(sipTypeDef *td) +static sipConvertFromFunc get_from_convertor(const sipTypeDef *td) { if (sipTypeIsMapped(td)) return ((const sipMappedTypeDef *)td)->mtd_cfrom; @@ -11441,6 +12167,8 @@ static PyObject *enableAutoconversion(PyObject *self, PyObject *args) sipWrapperType *wt; int enable; + (void)self; + if (PyArg_ParseTuple(args, "O!i:enableautoconversion", &sipWrapperType_Type, &wt, &enable)) { sipTypeDef *td = wt->type; @@ -11486,3 +12214,38 @@ static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd) ++psd; } } + + +/* + * Return the main instance for an object if it is a mixin. + */ +static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w) +{ + return w->mixin_main != NULL ? (sipSimpleWrapper *)w->mixin_main : w; +} + + +/* + * Convert a new C/C++ pointer to a Python instance. + */ +static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td, + sipWrapper *owner, int flags) +{ + return sipWrapInstance(cpp, sipTypeAsPyTypeObject(td), empty_tuple, owner, + flags); +} + + +/* + * Resolve a proxy, if applicable. + */ +static void *resolve_proxy(const sipTypeDef *td, void *proxy) +{ + sipProxyResolver *pr; + + for (pr = proxyResolvers; pr != NULL; pr = pr->next) + if (pr->td == td) + proxy = pr->resolver(proxy); + + return proxy; +} diff --git a/sip/siplib/threads.c b/sip/siplib/threads.c index bc22907d..9b7597aa 100644 --- a/sip/siplib/threads.c +++ b/sip/siplib/threads.c @@ -3,7 +3,7 @@ * C++ classes that provide a thread interface to interact properly with the * Python threading infrastructure. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -71,6 +71,9 @@ int sipGetPending(void **pp, sipWrapper **op, int *fp) *op = pd->owner; *fp = pd->flags; + /* Clear in case we execute Python code before finishing this wrapping. */ + pd->cpp = NULL; + return 0; } @@ -92,18 +95,13 @@ int sipIsPending() /* * Convert a new C/C++ pointer to a Python instance. */ -PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td, +PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args, sipWrapper *owner, int flags) { - static PyObject *nullargs = NULL; - pendingDef old_pending, *pd; PyObject *self; - if (nullargs == NULL && (nullargs = PyTuple_New(0)) == NULL) - return NULL; - - if (cppPtr == NULL) + if (cpp == NULL) { Py_INCREF(Py_None); return Py_None; @@ -120,11 +118,11 @@ PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td, old_pending = *pd; - pd->cpp = cppPtr; + pd->cpp = cpp; pd->owner = owner; pd->flags = flags; - self = PyObject_Call((PyObject *)sipTypeAsPyTypeObject(td), nullargs, NULL); + self = PyObject_Call((PyObject *)py_type, args, NULL); *pd = old_pending; diff --git a/sip/siplib/voidptr.c b/sip/siplib/voidptr.c index 51fdb1fb..d1eb02b5 100644 --- a/sip/siplib/voidptr.c +++ b/sip/siplib/voidptr.c @@ -1,7 +1,7 @@ /* * SIP library code. * - * Copyright (c) 2013 Riverbank Computing Limited + * Copyright (c) 2015 Riverbank Computing Limited * * This file is part of SIP. * @@ -24,6 +24,7 @@ #include "sip.h" #include "sipint.h" +#include "array.h" /* The object data structure. */ @@ -58,6 +59,7 @@ static void bad_key(PyObject *key); static int check_slice_size(SIP_SSIZE_T size, SIP_SSIZE_T value_size); static PyObject *make_voidptr(void *voidptr, SIP_SSIZE_T size, int rw); static int vp_convertor(PyObject *arg, struct vp_values *vp); +static SIP_SSIZE_T get_size_from_arg(sipVoidPtrObject *v, SIP_SSIZE_T size); #if defined(SIP_USE_PYCAPSULE) @@ -66,6 +68,8 @@ static int vp_convertor(PyObject *arg, struct vp_values *vp); */ static PyObject *sipVoidPtr_ascapsule(sipVoidPtrObject *v, PyObject *arg) { + (void)arg; + return PyCapsule_New(v->voidptr, NULL, NULL); } #endif @@ -77,11 +81,40 @@ static PyObject *sipVoidPtr_ascapsule(sipVoidPtrObject *v, PyObject *arg) */ static PyObject *sipVoidPtr_ascobject(sipVoidPtrObject *v, PyObject *arg) { + (void)arg; + return PyCObject_FromVoidPtr(v->voidptr, NULL); } #endif +/* + * Implement asarray() for the type. + */ +static PyObject *sipVoidPtr_asarray(sipVoidPtrObject *v, PyObject *args, + PyObject *kw) +{ + static char *kwlist[] = {"size", NULL}; + + SIP_SSIZE_T size = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kw, +#if PY_VERSION_HEX >= 0x02050000 + "|n:asarray", +#else + "|i:asarray", +#endif + kwlist, &size)) + return NULL; + + if ((size = get_size_from_arg(v, size)) < 0) + return NULL; + + return sip_api_convert_to_array(v->voidptr, "B", size, + (v->rw ? 0 : SIP_READ_ONLY)); +} + + /* * Implement asstring() for the type. */ @@ -101,16 +134,8 @@ static PyObject *sipVoidPtr_asstring(sipVoidPtrObject *v, PyObject *args, kwlist, &size)) return NULL; - /* Use the current size if one wasn't explicitly given. */ - if (size < 0) - size = v->size; - - if (size < 0) - { - PyErr_SetString(PyExc_ValueError, - "a size must be given or the sip.voidptr object must have a size"); + if ((size = get_size_from_arg(v, size)) < 0) return NULL; - } return SIPBytes_FromStringAndSize(v->voidptr, size); } @@ -121,6 +146,8 @@ static PyObject *sipVoidPtr_asstring(sipVoidPtrObject *v, PyObject *args, */ static PyObject *sipVoidPtr_getsize(sipVoidPtrObject *v, PyObject *arg) { + (void)arg; + #if PY_MAJOR_VERSION >= 3 return PyLong_FromSsize_t(v->size); #elif PY_VERSION_HEX >= 0x02050000 @@ -161,6 +188,8 @@ static PyObject *sipVoidPtr_setsize(sipVoidPtrObject *v, PyObject *arg) */ static PyObject *sipVoidPtr_getwriteable(sipVoidPtrObject *v, PyObject *arg) { + (void)arg; + return PyBool_FromLong(v->rw); } @@ -186,21 +215,31 @@ static PyObject *sipVoidPtr_setwriteable(sipVoidPtrObject *v, PyObject *arg) /* The methods data structure. */ static PyMethodDef sipVoidPtr_Methods[] = { + {"asarray", (PyCFunction)sipVoidPtr_asarray, METH_VARARGS|METH_KEYWORDS, NULL}, #if defined(SIP_USE_PYCAPSULE) {"ascapsule", (PyCFunction)sipVoidPtr_ascapsule, METH_NOARGS, NULL}, #endif #if defined(SIP_SUPPORT_PYCOBJECT) {"ascobject", (PyCFunction)sipVoidPtr_ascobject, METH_NOARGS, NULL}, #endif - {"asstring", (PyCFunction)sipVoidPtr_asstring, METH_KEYWORDS, NULL}, + {"asstring", (PyCFunction)sipVoidPtr_asstring, METH_VARARGS|METH_KEYWORDS, NULL}, {"getsize", (PyCFunction)sipVoidPtr_getsize, METH_NOARGS, NULL}, {"setsize", (PyCFunction)sipVoidPtr_setsize, METH_O, NULL}, {"getwriteable", (PyCFunction)sipVoidPtr_getwriteable, METH_NOARGS, NULL}, {"setwriteable", (PyCFunction)sipVoidPtr_setwriteable, METH_O, NULL}, - {NULL} + {NULL, NULL, 0, NULL} }; +/* + * Implement bool() for the type. + */ +static int sipVoidPtr_bool(PyObject *self) +{ + return (((sipVoidPtrObject *)self)->voidptr != NULL); +} + + /* * Implement int() for the type. */ @@ -240,7 +279,7 @@ static PyNumberMethods sipVoidPtr_NumberMethods = { 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ - 0, /* nb_bool (Python v3), nb_nonzero (Python v2) */ + sipVoidPtr_bool, /* nb_bool (Python v3), nb_nonzero (Python v2) */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ @@ -391,11 +430,18 @@ static PySequenceMethods sipVoidPtr_SequenceMethods = { 0, /* sq_concat */ 0, /* sq_repeat */ sipVoidPtr_item, /* sq_item */ -#if PY_VERSION_HEX < 0x02050000 +#if PY_VERSION_HEX >= 0x02050000 + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ +#else sipVoidPtr_slice, /* sq_slice */ sipVoidPtr_ass_item, /* sq_ass_item */ sipVoidPtr_ass_slice, /* sq_ass_slice */ #endif + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ }; @@ -741,6 +787,20 @@ PyTypeObject sipVoidPtr_Type = { 0, /* tp_init */ 0, /* tp_alloc */ sipVoidPtr_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ +#if PY_VERSION_HEX >= 0x02060000 + 0, /* tp_version_tag */ +#endif +#if PY_VERSION_HEX >= 0x03040000 + 0, /* tp_finalize */ +#endif }; @@ -986,10 +1046,12 @@ static int vp_convertor(PyObject *arg, struct vp_values *vp) ptr = view.buf; size = view.len; rw = !view.readonly; + + PyBuffer_Release(&view); } #endif #if PY_VERSION_HEX < 0x03000000 - else if (PyObject_AsReadBuffer(arg, &ptr, &size) >= 0) + else if (PyObject_AsReadBuffer(arg, (const void **)&ptr, &size) >= 0) { rw = (Py_TYPE(arg)->tp_as_buffer->bf_getwritebuffer != NULL); } @@ -1016,3 +1078,21 @@ static int vp_convertor(PyObject *arg, struct vp_values *vp) return 1; } + + +/* + * Get a size possibly supplied as an argument, otherwise get it from the + * object. Raise an exception if there was no size specified. + */ +static SIP_SSIZE_T get_size_from_arg(sipVoidPtrObject *v, SIP_SSIZE_T size) +{ + /* Use the current size if one wasn't explicitly given. */ + if (size < 0) + size = v->size; + + if (size < 0) + PyErr_SetString(PyExc_ValueError, + "a size must be given or the sip.voidptr object must have a size"); + + return size; +} diff --git a/wscript b/wscript index 746f3580..83aba8a4 100644 --- a/wscript +++ b/wscript @@ -440,6 +440,7 @@ def build(bld): features = 'c cxx cshlib cxxshlib pyext', target = makeTargetName(bld, 'siplib'), source = ['sip/siplib/apiversions.c', + 'sip/siplib/array.c', 'sip/siplib/bool.cpp', 'sip/siplib/descriptors.c', 'sip/siplib/objmap.c',