diff options
Diffstat (limited to 'siplib')
-rw-r--r-- | siplib/apiversions.c | 295 | ||||
-rw-r--r-- | siplib/bool.cpp | 22 | ||||
-rw-r--r-- | siplib/descriptors.c | 305 | ||||
-rw-r--r-- | siplib/objmap.c | 282 | ||||
-rw-r--r-- | siplib/qtlib.c | 659 | ||||
-rw-r--r-- | siplib/sip.h | 1587 | ||||
-rw-r--r-- | siplib/sipint.h | 149 | ||||
-rw-r--r-- | siplib/siplib.c | 10501 | ||||
-rw-r--r-- | siplib/siplib.sbf | 19 | ||||
-rw-r--r-- | siplib/threads.c | 226 | ||||
-rw-r--r-- | siplib/voidptr.c | 579 |
11 files changed, 14624 insertions, 0 deletions
diff --git a/siplib/apiversions.c b/siplib/apiversions.c new file mode 100644 index 0000000..7d86c76 --- /dev/null +++ b/siplib/apiversions.c @@ -0,0 +1,295 @@ +/* + * The implementation of the supprt for setting API versions. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <Python.h> + +#include <string.h> + +#include "sip.h" +#include "sipint.h" + + +/* + * The structure that defines the version number of an API. + */ +typedef struct _apiVersionDef { + /* The name of the API. */ + const char *api_name; + + /* + * The version number of the API. This will either be set explicitly via + * a call to sip.setapi() or implicitly by an imported module. + */ + int version_nr; + + /* The next in the list of APIs. */ + struct _apiVersionDef *next; +} apiVersionDef; + + +/* + * The list of API versions. + */ +static apiVersionDef *api_versions = NULL; + + +/* + * Forward declarations. + */ +static int add_api(const char *api, int version_nr); +static apiVersionDef *find_api(const char *api); + + +/* + * See if a range of versions of a particular API is enabled. + */ +int sip_api_is_api_enabled(const char *name, int from, int to) +{ + const apiVersionDef *avd; + + if ((avd = find_api(name)) == NULL) + return FALSE; + + if (from > 0 && avd->version_nr < from) + return FALSE; + + if (to > 0 && avd->version_nr >= to) + return FALSE; + + return TRUE; +} + + +/* + * Initialise the the API for a module and return a negative value on error. + */ +int sipInitAPI(sipExportedModuleDef *em, PyObject *mod_dict) +{ + int *apis, i; + sipVersionedFunctionDef *vf; + sipTypeDef **tdp; + + /* See if the module defines any APIs. */ + if ((apis = em->em_versions) != NULL) + { + while (apis[0] >= 0) + { + /* + * See if it is an API definition rather than a range + * definition. + */ + if (apis[2] < 0) + { + const char *api_name; + const apiVersionDef *avd; + + api_name = sipNameFromPool(em, apis[0]); + + /* Use the default version if not already set explicitly. */ + if ((avd = find_api(api_name)) == NULL) + if (add_api(api_name, apis[1]) < 0) + return -1; + } + + apis += 3; + } + } + + /* Add any versioned global functions to the module dictionary. */ + if ((vf = em->em_versioned_functions) != NULL) + { + while (vf->vf_name >= 0) + { + if (sipIsRangeEnabled(em, vf->vf_api_range)) + { + const char *func_name = sipNameFromPool(em, vf->vf_name); + PyMethodDef *pmd; + PyObject *py_func; + + if ((pmd = sip_api_malloc(sizeof (PyMethodDef))) == NULL) + return -1; + + pmd->ml_name = SIP_MLNAME_CAST(func_name); + pmd->ml_meth = vf->vf_function; + pmd->ml_flags = vf->vf_flags; + pmd->ml_doc = vf->vf_docstring; + + if ((py_func = PyCFunction_New(pmd, NULL)) == NULL) + return -1; + + if (PyDict_SetItemString(mod_dict, func_name, py_func) < 0) + { + Py_DECREF(py_func); + return -1; + } + + Py_DECREF(py_func); + } + + ++vf; + } + } + + /* Update the types table according to any version information. */ + for (tdp = em->em_types, i = 0; i < em->em_nrtypes; ++i, ++tdp) + { + sipTypeDef *td; + + if ((td = *tdp) != NULL && td->td_version >= 0) + { + do + { + if (sipIsRangeEnabled(em, td->td_version)) + { + /* Update the type with the enabled version. */ + *tdp = td; + break; + } + } + while ((td = td->td_next_version) != NULL); + + /* + * If there is no enabled version then stub the disabled version + * so that we don't lose the name from the (sorted) types table. + */ + if (td == NULL) + sipTypeSetStub(*tdp); + } + } + + return 0; +} + + +/* + * Get the version number for an API. + */ +PyObject *sipGetAPI(PyObject *self, PyObject *args) +{ + const char *api; + const apiVersionDef *avd; + + if (!PyArg_ParseTuple(args, "s:getapi", &api)) + return NULL; + + if ((avd = find_api(api)) == NULL) + { + PyErr_Format(PyExc_ValueError, "unknown API '%s'", api); + return NULL; + } + +#if PY_MAJOR_VERSION >= 3 + return PyLong_FromLong(avd->version_nr); +#else + return PyInt_FromLong(avd->version_nr); +#endif +} + + +/* + * Set the version number for an API. + */ +PyObject *sipSetAPI(PyObject *self, PyObject *args) +{ + const char *api; + int version_nr; + const apiVersionDef *avd; + + if (!PyArg_ParseTuple(args, "si:setapi", &api, &version_nr)) + return NULL; + + if (version_nr < 1) + { + PyErr_Format(PyExc_ValueError, + "API version numbers must be greater or equal to 1, not %d", + version_nr); + return NULL; + } + + if ((avd = find_api(api)) == NULL) + { + char *api_copy; + + /* Make a deep copy of the name. */ + if ((api_copy = sip_api_malloc(strlen(api) + 1)) == NULL) + return NULL; + + strcpy(api_copy, api); + + if (add_api(api_copy, version_nr) < 0) + return NULL; + } + else if (avd->version_nr != version_nr) + { + PyErr_Format(PyExc_ValueError, + "API '%s' has already been set to version %d", api, + avd->version_nr); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Add a new API to the global list returning a negative value on error. + */ +static int add_api(const char *api, int version_nr) +{ + apiVersionDef *avd; + + if ((avd = sip_api_malloc(sizeof (apiVersionDef))) == NULL) + return -1; + + avd->api_name = api; + avd->version_nr = version_nr; + avd->next = api_versions; + + api_versions = avd; + + return 0; +} + + +/* + * Return the definition for the given API, or NULL if there was none. + */ +static apiVersionDef *find_api(const char *api) +{ + apiVersionDef *avd; + + for (avd = api_versions; avd != NULL; avd = avd->next) + if (strcmp(avd->api_name, api) == 0) + break; + + return avd; +} + + +/* + * Return TRUE if a range defined by a range index is enabled. + */ +int sipIsRangeEnabled(sipExportedModuleDef *em, int range_index) +{ + int *range = &em->em_versions[range_index * 3]; + const char *api_name = sipNameFromPool(em, range[0]); + + return sip_api_is_api_enabled(api_name, range[1], range[2]); +} diff --git a/siplib/bool.cpp b/siplib/bool.cpp new file mode 100644 index 0000000..8936287 --- /dev/null +++ b/siplib/bool.cpp @@ -0,0 +1,22 @@ +// This contains all the C++ code that is needed by the sip module. +// +// Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> +// +// 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. + + +// Set a C++ bool for the main C implementation of the module. +extern "C" void sipSetBool(void *ptr, int val) +{ + *reinterpret_cast<bool *>(ptr) = val; +} diff --git a/siplib/descriptors.c b/siplib/descriptors.c new file mode 100644 index 0000000..29277c5 --- /dev/null +++ b/siplib/descriptors.c @@ -0,0 +1,305 @@ +/* + * The implementation of the different descriptors. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <Python.h> + +#include "sip.h" +#include "sipint.h" + + +/***************************************************************************** + * A method descriptor. We don't use the similar Python descriptor because it + * doesn't support a method having static and non-static overloads. + *****************************************************************************/ + + +/* Forward declarations of slots. */ +static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, + PyObject *type); +static PyObject *sipMethodDescr_repr(PyObject *self); + + +/* + * The object data structure. + */ +typedef struct _sipMethodDescr { + PyObject_HEAD + + /* The method definition. */ + PyMethodDef *pmd; +} sipMethodDescr; + + +/* + * The type data structure. + */ +PyTypeObject sipMethodDescr_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.methoddescriptor", /* tp_name */ + sizeof (sipMethodDescr), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + sipMethodDescr_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 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 */ + sipMethodDescr_descr_get, /* tp_descr_get */ +}; + + +/* + * Return a new method descriptor for the given method. + */ +PyObject *sipMethodDescr_New(PyMethodDef *pmd) +{ + PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0); + + if (descr != NULL) + ((sipMethodDescr *)descr)->pmd = pmd; + + return descr; +} + + +/* + * The descriptor's descriptor get slot. + */ +static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, + PyObject *type) +{ + sipMethodDescr *md = (sipMethodDescr *)self; + + if (obj == Py_None) + obj = NULL; + + return PyCFunction_New(md->pmd, obj); +} + + +/* + * The descriptor's repr slot. This is for the benefit of cProfile which seems + * to determine attribute names differently to the rest of Python. + */ +static PyObject *sipMethodDescr_repr(PyObject *self) +{ + sipMethodDescr *md = (sipMethodDescr *)self; + + return +#if PY_MAJOR_VERSION >= 3 + PyUnicode_FromFormat +#else + PyString_FromFormat +#endif + ("<built-in method %s>", md->pmd->ml_name); +} + + +/***************************************************************************** + * A variable descriptor. We don't use the similar Python descriptor because + * it doesn't support static variables. + *****************************************************************************/ + + +/* Forward declarations of slots. */ +static PyObject *sipVariableDescr_descr_get(PyObject *self, PyObject *obj, + PyObject *type); +static int sipVariableDescr_descr_set(PyObject *self, PyObject *obj, + PyObject *value); + + +/* + * The object data structure. + */ +typedef struct _sipVariableDescr { + PyObject_HEAD + + /* The getter/setter definition. */ + sipVariableDef *vd; + + /* The generated type definition. */ + const sipTypeDef *td; + + /* The generated container definition. */ + const sipContainerDef *cod; +} sipVariableDescr; + + +/* + * The type data structure. + */ +PyTypeObject sipVariableDescr_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.variabledescriptor", /* tp_name */ + sizeof (sipVariableDescr), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 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 */ + sipVariableDescr_descr_get, /* tp_descr_get */ + sipVariableDescr_descr_set, /* tp_descr_set */ +}; + + +/* Forward declarations. */ +static int get_instance_address(sipVariableDescr *vd, PyObject *obj, + void **addrp); + + +/* + * Return a new method descriptor for the given getter/setter. + */ +PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td, + const sipContainerDef *cod) +{ + PyObject *descr = PyType_GenericAlloc(&sipVariableDescr_Type, 0); + + if (descr != NULL) + { + ((sipVariableDescr *)descr)->vd = vd; + ((sipVariableDescr *)descr)->td = td; + ((sipVariableDescr *)descr)->cod = cod; + } + + return descr; +} + + +/* + * The descriptor's descriptor get slot. + */ +static PyObject *sipVariableDescr_descr_get(PyObject *self, PyObject *obj, + PyObject *type) +{ + sipVariableDescr *vd = (sipVariableDescr *)self; + void *addr; + + if (get_instance_address(vd, obj, &addr) < 0) + return NULL; + + return vd->vd->vd_getter(addr, type); +} + + +/* + * The descriptor's descriptor set slot. + */ +static int sipVariableDescr_descr_set(PyObject *self, PyObject *obj, + PyObject *value) +{ + sipVariableDescr *vd = (sipVariableDescr *)self; + void *addr; + + /* Check that the value isn't const. */ + if (vd->vd->vd_setter == NULL) + { + PyErr_Format(PyExc_AttributeError, + "'%s' object attribute '%s' is read-only", + sipPyNameOfContainer(vd->cod, vd->td), vd->vd->vd_name); + + return -1; + } + + if (get_instance_address(vd, obj, &addr) < 0) + return -1; + + return vd->vd->vd_setter(addr, value, obj); +} + + +/* + * Return the C/C++ address of any instance. + */ +static int get_instance_address(sipVariableDescr *vd, PyObject *obj, + void **addrp) +{ + void *addr; + + if (vd->vd->vd_is_static) + { + addr = NULL; + } + else + { + /* Check that access was via an instance. */ + if (obj == NULL || obj == Py_None) + { + PyErr_Format(PyExc_AttributeError, + "'%s' object attribute '%s' is an instance attribute", + sipPyNameOfContainer(vd->cod, vd->td), vd->vd->vd_name); + + return -1; + } + + /* Get the C++ instance. */ + if ((addr = sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, vd->td)) == NULL) + return -1; + } + + *addrp = addr; + + return 0; +} diff --git a/siplib/objmap.c b/siplib/objmap.c new file mode 100644 index 0000000..f9c196d --- /dev/null +++ b/siplib/objmap.c @@ -0,0 +1,282 @@ +/* + * This module implements a hash table class for mapping C/C++ addresses to the + * corresponding wrapped Python object. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <string.h> + +#include "sip.h" +#include "sipint.h" + + +#define hash_1(k,s) (((unsigned long)(k)) % (s)) +#define hash_2(k,s) ((s) - 2 - (hash_1((k),(s)) % ((s) - 2))) + + +/* Prime numbers to use as hash table sizes. */ +static unsigned long hash_primes[] = { + 521, 1031, 2053, 4099, + 8209, 16411, 32771, 65537, 131101, 262147, + 524309, 1048583, 2097169, 4194319, 8388617, 16777259, + 33554467, 67108879, 134217757, 268435459, 536870923, 1073741827, + 2147483659U,0 +}; + + +static sipHashEntry *newHashTable(unsigned long); +static sipHashEntry *findHashEntry(sipObjectMap *,void *); +static void reorganiseMap(sipObjectMap *om); + + +/* + * Initialise an object map. + */ +void sipOMInit(sipObjectMap *om) +{ + om -> primeIdx = 0; + om -> unused = om -> size = hash_primes[om -> primeIdx]; + om -> stale = 0; + om -> hash_array = newHashTable(om -> size); +} + + +/* + * Finalise an object map. + */ +void sipOMFinalise(sipObjectMap *om) +{ + sip_api_free(om -> hash_array); +} + + +/* + * Allocate and initialise a new hash table. + */ +static sipHashEntry *newHashTable(unsigned long size) +{ + size_t nbytes; + sipHashEntry *hashtab; + + nbytes = sizeof (sipHashEntry) * size; + + if ((hashtab = (sipHashEntry *)sip_api_malloc(nbytes)) != NULL) + memset(hashtab,0,nbytes); + + return hashtab; +} + + +/* + * Return a pointer to the hash entry that is used, or should be used, for the + * given C/C++ address. + */ +static sipHashEntry *findHashEntry(sipObjectMap *om,void *key) +{ + unsigned long hash, inc; + void *hek; + + hash = hash_1(key,om -> size); + inc = hash_2(key,om -> size); + + while ((hek = om -> hash_array[hash].key) != NULL && hek != key) + hash = (hash + inc) % om -> size; + + return &om -> hash_array[hash]; +} + + +/* + * Return the wrapped Python object of a specific type for a C/C++ address or + * NULL if it wasn't found. + */ +sipSimpleWrapper *sipOMFindObject(sipObjectMap *om, void *key, + const sipTypeDef *td) +{ + sipHashEntry *he = findHashEntry(om, key); + sipSimpleWrapper *sw; + PyTypeObject *py_type = sipTypeAsPyTypeObject(td); + + /* Go through each wrapped object at this address. */ + for (sw = he->first; sw != NULL; sw = sw->next) + { + /* + * If the reference count is 0 then it is in the process of being + * deleted, so ignore it. It's not completely clear how this can + * happen (but it can) because it implies that the garbage collection + * code is being re-entered (and there are guards in place to prevent + * this). + */ + if (Py_REFCNT(sw) == 0) + continue; + + /* + * If this wrapped object is of the given type, or a sub-type of it, + * then we assume it is the same C++ object. + */ + if (PyObject_TypeCheck(sw, py_type)) + return sw; + } + + return NULL; +} + + +/* + * Add a C/C++ address and the corresponding wrapped Python object to the map. + */ +void sipOMAddObject(sipObjectMap *om, sipSimpleWrapper *val) +{ + sipHashEntry *he = findHashEntry(om, val->u.cppPtr); + + /* + * If the bucket is in use then we appear to have several objects at the + * same address. + */ + if (he -> first != NULL) + { + /* + * This can happen for three reasons. A variable of one class can be + * declared at the start of another class. Therefore there are two + * objects, of different classes, with the same address. The second + * reason is that the old C/C++ object has been deleted by C/C++ but we + * didn't get to find out for some reason, and a new C/C++ instance has + * been created at the same address. The third reason is if we are in + * the process of deleting a Python object but the C++ object gets + * wrapped again because the C++ dtor called a method that has been + * re-implemented in Python. The absence of the SIP_SHARE_MAP flag + * tells us that a new C++ instance has just been created and so we + * know the second reason is the correct one so we mark the old + * pointers as invalid and reuse the entry. Otherwise we just add this + * one to the existing list of objects at this address. + */ + if (!(val->flags & SIP_SHARE_MAP)) + { + sipSimpleWrapper *sw = he->first; + + he->first = NULL; + + while (sw != NULL) + { + sipSimpleWrapper *next = sw->next; + + /* We are removing it from the map here. */ + sipSetNotInMap(sw); + sip_api_common_dtor(sw); + + sw = next; + } + } + + val->next = he->first; + he->first = val; + + return; + } + + /* See if the bucket was unused or stale. */ + if (he->key == NULL) + { + he->key = val -> u.cppPtr; + om->unused--; + } + else + om->stale--; + + /* Add the rest of the new value. */ + he->first = val; + val->next = NULL; + + reorganiseMap(om); +} + + +/* + * Reorganise a map if it is running short of space. + */ +static void reorganiseMap(sipObjectMap *om) +{ + unsigned long old_size, i; + sipHashEntry *ohe, *old_tab; + + /* Don't bother if it still has more than 12% available. */ + if (om -> unused > om -> size >> 3) + return; + + /* + * If reorganising (ie. making the stale buckets unused) using the same + * sized table would make 25% available then do that. Otherwise use a + * bigger table (if possible). + */ + if (om -> unused + om -> stale < om -> size >> 2 && hash_primes[om -> primeIdx + 1] != 0) + om -> primeIdx++; + + old_size = om -> size; + old_tab = om -> hash_array; + + om -> unused = om -> size = hash_primes[om -> primeIdx]; + om -> stale = 0; + om -> hash_array = newHashTable(om -> size); + + /* Transfer the entries from the old table to the new one. */ + ohe = old_tab; + + for (i = 0; i < old_size; ++i) + { + if (ohe -> key != NULL && ohe -> first != NULL) + { + *findHashEntry(om,ohe -> key) = *ohe; + om -> unused--; + } + + ++ohe; + } + + sip_api_free(old_tab); +} + + +/* + * Remove a C/C++ object from the table. Return 0 if it was removed + * successfully. + */ +int sipOMRemoveObject(sipObjectMap *om, sipSimpleWrapper *val) +{ + sipHashEntry *he = findHashEntry(om, val->u.cppPtr); + sipSimpleWrapper **swp; + + for (swp = &he->first; *swp != NULL; swp = &(*swp)->next) + if (*swp == val) + { + *swp = val->next; + + /* + * If the bucket is now empty then count it as stale. Note that we + * do not NULL the key and count it as unused because that might + * throw out the search for another entry that wanted to go here, + * found it already occupied, and was put somewhere else. In other + * words, searches must be repeatable until we reorganise the + * table. + */ + if (he->first == NULL) + om->stale++; + + return 0; + } + + return -1; +} diff --git a/siplib/qtlib.c b/siplib/qtlib.c new file mode 100644 index 0000000..ca0817a --- /dev/null +++ b/siplib/qtlib.c @@ -0,0 +1,659 @@ +/* + * The SIP library code that implements the interface to the optional module + * supplied Qt support. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <Python.h> +#include <assert.h> +#include <string.h> + +#include "sip.h" +#include "sipint.h" + + +/* This is how Qt "types" signals and slots. */ +#define isQtSlot(s) (*(s) == '1') +#define isQtSignal(s) (*(s) == '2') + + +static PyObject *getWeakRef(PyObject *obj); +static char *sipStrdup(const char *); +static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, + PyObject *rxObj, const char *slot, const char **member, int flags); +static void *findSignal(void *txrx, const char **sig); +static void *newSignal(void *txrx, const char **sig); + + +/* + * Find an existing signal. + */ +static void *findSignal(void *txrx, const char **sig) +{ + if (sipQtSupport->qt_find_universal_signal != NULL) + txrx = sipQtSupport->qt_find_universal_signal(txrx, sig); + + return txrx; +} + + +/* + * Return a usable signal, creating a new universal signal if needed. + */ +static void *newSignal(void *txrx, const char **sig) +{ + void *new_txrx = findSignal(txrx, sig); + + if (new_txrx == NULL && sipQtSupport->qt_create_universal_signal != NULL) + new_txrx = sipQtSupport->qt_create_universal_signal(txrx, sig); + + return new_txrx; +} + + +/* + * Create a universal slot. Returns a pointer to it or 0 if there was an + * error. + */ +static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, + PyObject *rxObj, const char *slot, const char **member, int flags) +{ + void *us = sipQtSupport->qt_create_universal_slot(txSelf, sig, rxObj, slot, + member, flags); + + if (us && txSelf) + sipSetPossibleProxy((sipSimpleWrapper *)txSelf); + + return us; +} + + +/* + * Invoke a single slot (Qt or Python) and return the result. + */ +PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) +{ + PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref; + + /* Keep some compilers quiet. */ + oxtype = oxvalue = oxtb = NULL; + + /* Fan out Qt signals. (Only PyQt3 will do this.) */ + if (slot->name != NULL && slot->name[0] != '\0') + { + assert(sipQtSupport->qt_emit_signal); + + if (sipQtSupport->qt_emit_signal(slot->pyobj, slot->name, sigargs) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + /* Get the object to call, resolving any weak references. */ + if (slot->weakSlot == Py_True) + { + /* + * The slot is guaranteed to be Ok because it has an extra reference or + * is None. + */ + sref = slot->pyobj; + Py_INCREF(sref); + } + else if (slot -> weakSlot == NULL) + sref = NULL; + else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL) + return NULL; + else + Py_INCREF(sref); + + if (sref == Py_None) + { + /* + * If the real object has gone then we pretend everything is Ok. This + * mimics the Qt behaviour of not caring if a receiving object has been + * deleted. + */ + Py_DECREF(sref); + + Py_INCREF(Py_None); + return Py_None; + } + + if (slot -> pyobj == NULL) + { + PyObject *self = (sref != NULL ? sref : slot->meth.mself); + + /* + * If the receiver wraps a C++ object then ignore the call if it no + * longer exists. + */ + if (PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) && + sipGetAddress(self) == NULL) + { + Py_XDECREF(sref); + + Py_INCREF(Py_None); + return Py_None; + } + +#if PY_MAJOR_VERSION >= 3 + sfunc = PyMethod_New(slot->meth.mfunc, self); +#else + sfunc = PyMethod_New(slot->meth.mfunc, self, slot->meth.mclass); +#endif + + if (sfunc == NULL) + { + Py_XDECREF(sref); + return NULL; + } + } + else if (slot -> name != NULL) + { + char *mname = slot -> name + 1; + PyObject *self = (sref != NULL ? sref : slot->pyobj); + + if ((sfunc = PyObject_GetAttrString(self, mname)) == NULL || !PyCFunction_Check(sfunc)) + { + /* + * Note that in earlier versions of SIP this error would be + * detected when the slot was connected. + */ + PyErr_Format(PyExc_NameError,"Invalid slot %s",mname); + + Py_XDECREF(sfunc); + Py_XDECREF(sref); + return NULL; + } + } + else + { + sfunc = slot->pyobj; + Py_INCREF(sfunc); + } + + /* + * We make repeated attempts to call a slot. If we work out that it failed + * because of an immediate type error we try again with one less argument. + * We keep going until we run out of arguments to drop. This emulates the + * Qt ability of the slot to accept fewer arguments than a signal provides. + */ + sa = sigargs; + Py_INCREF(sa); + + for (;;) + { + PyObject *nsa, *xtype, *xvalue, *xtb, *resobj; + + if ((resobj = PyEval_CallObject(sfunc, sa)) != NULL) + { + Py_DECREF(sfunc); + Py_XDECREF(sref); + + /* Remove any previous exception. */ + + if (sa != sigargs) + { + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + PyErr_Clear(); + } + + Py_DECREF(sa); + + return resobj; + } + + /* Get the exception. */ + PyErr_Fetch(&xtype,&xvalue,&xtb); + + /* + * See if it is unacceptable. An acceptable failure is a type error + * with no traceback - so long as we can still reduce the number of + * arguments and try again. + */ + if (!PyErr_GivenExceptionMatches(xtype,PyExc_TypeError) || + xtb != NULL || + PyTuple_GET_SIZE(sa) == 0) + { + /* + * If there is a traceback then we must have called the slot and + * the exception was later on - so report the exception as is. + */ + if (xtb != NULL) + { + if (sa != sigargs) + { + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + } + + PyErr_Restore(xtype,xvalue,xtb); + } + else if (sa == sigargs) + PyErr_Restore(xtype,xvalue,xtb); + else + { + /* + * Discard the latest exception and restore the original one. + */ + Py_XDECREF(xtype); + Py_XDECREF(xvalue); + Py_XDECREF(xtb); + + PyErr_Restore(oxtype,oxvalue,oxtb); + } + + break; + } + + /* If this is the first attempt, save the exception. */ + if (sa == sigargs) + { + oxtype = xtype; + oxvalue = xvalue; + oxtb = xtb; + } + else + { + Py_XDECREF(xtype); + Py_XDECREF(xvalue); + Py_XDECREF(xtb); + } + + /* Create the new argument tuple. */ + if ((nsa = PyTuple_GetSlice(sa,0,PyTuple_GET_SIZE(sa) - 1)) == NULL) + { + /* Tidy up. */ + Py_XDECREF(oxtype); + Py_XDECREF(oxvalue); + Py_XDECREF(oxtb); + + break; + } + + Py_DECREF(sa); + sa = nsa; + } + + Py_DECREF(sfunc); + Py_XDECREF(sref); + + Py_DECREF(sa); + + return NULL; +} + + +/* + * Compare two slots to see if they are the same. + */ +int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot) +{ + /* See if they are signals or Qt slots, ie. they have a name. */ + if (slot != NULL) + { + if (sp->name == NULL || sp->name[0] == '\0') + return 0; + + return (sipQtSupport->qt_same_name(sp->name, slot) && sp->pyobj == rxObj); + } + + /* See if they are pure Python methods. */ + if (PyMethod_Check(rxObj)) + { + if (sp->pyobj != NULL) + return 0; + + return (sp->meth.mfunc == PyMethod_GET_FUNCTION(rxObj) + && sp->meth.mself == PyMethod_GET_SELF(rxObj) +#if PY_MAJOR_VERSION < 3 + && sp->meth.mclass == PyMethod_GET_CLASS(rxObj) +#endif + ); + } + + /* See if they are wrapped C++ methods. */ + if (PyCFunction_Check(rxObj)) + { + if (sp->name == NULL || sp->name[0] != '\0') + return 0; + + return (sp->pyobj == PyCFunction_GET_SELF(rxObj) && + strcmp(&sp->name[1], ((PyCFunctionObject *)rxObj)->m_ml->ml_name) == 0); + } + + /* The objects must be the same. */ + return (sp->pyobj == rxObj); +} + + +/* + * Convert a valid Python signal or slot to an existing universal slot. + */ +void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj, + const char *slot, const char **memberp) +{ + if (slot != NULL) + if (isQtSlot(slot) || isQtSignal(slot)) + { + void *rx; + + *memberp = slot; + + if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipQObjectType)) == NULL) + return NULL; + + if (isQtSignal(slot)) + rx = findSignal(rx, memberp); + + return rx; + } + + /* + * The slot was either a Python callable or PyQt3 Python signal so there + * should be a universal slot. + */ + return sipQtSupport->qt_find_slot(sipGetAddress(txSelf), sigargs, rxObj, slot, memberp); +} + + +/* + * Convert a Python receiver (either a Python signal or slot or a Qt signal or + * slot) to a Qt receiver. It is only ever called when the signal is a Qt + * signal. Return NULL is there was an error. + */ +void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs, + PyObject *rxObj, const char *slot, const char **memberp, int flags) +{ + if (slot == NULL) + return createUniversalSlot(txSelf, sigargs, rxObj, NULL, memberp, flags); + + if (isQtSlot(slot) || isQtSignal(slot)) + { + void *rx; + + *memberp = slot; + + if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipQObjectType)) == NULL) + return NULL; + + if (isQtSignal(slot)) + rx = newSignal(rx, memberp); + + return rx; + } + + /* The slot is a Python signal so we need a universal slot to catch it. */ + return createUniversalSlot(txSelf, sigargs, rxObj, slot, memberp, 0); +} + + +/* + * Connect a Qt signal or a Python signal to a Qt slot, a Qt signal, a Python + * slot or a Python signal. This is all possible combinations. + */ +PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj, + const char *slot, int type) +{ + /* Handle Qt signals. */ + if (isQtSignal(sig)) + { + void *tx, *rx; + const char *member, *real_sig; + int res; + + if ((tx = sip_api_get_cpp_ptr((sipSimpleWrapper *)txObj, sipQObjectType)) == NULL) + return NULL; + + real_sig = sig; + + if ((tx = newSignal(tx, &real_sig)) == NULL) + return NULL; + + if ((rx = sip_api_convert_rx((sipWrapper *)txObj, sig, rxObj, slot, &member, 0)) == NULL) + return NULL; + + res = sipQtSupport->qt_connect(tx, real_sig, rx, member, type); + + return PyBool_FromLong(res); + } + + /* Handle Python signals. Only PyQt3 will get this far. */ + assert(sipQtSupport->qt_connect_py_signal); + + if (sipQtSupport->qt_connect_py_signal(txObj, sig, rxObj, slot) < 0) + return NULL; + + Py_INCREF(Py_True); + return Py_True; +} + + +/* + * Disconnect a signal to a signal or a Qt slot. + */ +PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig, + PyObject *rxObj,const char *slot) +{ + /* Handle Qt signals. */ + if (isQtSignal(sig)) + { + sipSimpleWrapper *txSelf = (sipSimpleWrapper *)txObj; + void *tx, *rx; + const char *member; + int res; + + if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectType)) == NULL) + return NULL; + + if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL) + { + Py_INCREF(Py_False); + return Py_False; + } + + /* Handle Python signals. */ + tx = findSignal(tx, &sig); + + res = sipQtSupport->qt_disconnect(tx, sig, rx, member); + + /* + * Delete it if it is a universal slot as this will be it's only + * connection. If the slot is actually a universal signal then it + * should leave it in place. + */ + sipQtSupport->qt_destroy_universal_slot(rx); + + return PyBool_FromLong(res); + } + + /* Handle Python signals. Only PyQt3 will get this far. */ + assert(sipQtSupport->qt_disconnect_py_signal); + + sipQtSupport->qt_disconnect_py_signal(txObj, sig, rxObj, slot); + + Py_INCREF(Py_True); + return Py_True; +} + + +/* + * Free the resources of a slot. + */ +void sip_api_free_sipslot(sipSlot *slot) +{ + if (slot->name != NULL) + { + sip_api_free(slot->name); + } + else if (slot->weakSlot == Py_True) + { + Py_DECREF(slot->pyobj); + } + + /* Remove any weak reference. */ + Py_XDECREF(slot->weakSlot); +} + + +/* + * Implement strdup() using sip_api_malloc(). + */ +static char *sipStrdup(const char *s) +{ + char *d; + + if ((d = (char *)sip_api_malloc(strlen(s) + 1)) != NULL) + strcpy(d,s); + + return d; +} + + +/* + * Initialise a slot, returning 0 if there was no error. If the signal was a + * Qt signal, then the slot may be a Python signal or a Python slot. If the + * signal was a Python signal, then the slot may be anything. + */ +int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot) +{ + sp -> weakSlot = NULL; + + if (slot == NULL) + { + sp -> name = NULL; + + if (PyMethod_Check(rxObj)) + { + /* + * Python creates methods on the fly. We could increment the + * reference count to keep it alive, but that would keep "self" + * alive as well and would probably be a circular reference. + * Instead we remember the component parts and hope they are still + * valid when we re-create the method when we need it. + */ + sipSaveMethod(&sp -> meth,rxObj); + + /* Notice if the class instance disappears. */ + sp -> weakSlot = getWeakRef(sp -> meth.mself); + + /* This acts a flag to say that the slot is a method. */ + sp -> pyobj = NULL; + } + else + { + PyObject *self; + + /* + * We know that it is another type of callable, ie. a + * function/builtin. + */ + + if (PyCFunction_Check(rxObj) && + (self = PyCFunction_GET_SELF(rxObj)) != NULL && + PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type)) + { + /* + * It is a wrapped C++ class method. We can't keep a copy + * because they are generated on the fly and we can't take a + * reference as that may keep the instance (ie. self) alive. + * We therefore treat it as if the user had specified the slot + * at "obj, SLOT('meth()')" rather than "obj.meth" (see below). + */ + + const char *meth; + + /* Get the method name. */ + meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name; + + if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL) + return -1; + + /* + * Copy the name and set the marker that it needs converting to + * a built-in method. + */ + sp -> name[0] = '\0'; + strcpy(&sp -> name[1],meth); + + sp -> pyobj = self; + sp -> weakSlot = getWeakRef(self); + } + else + { + /* + * Give the slot an extra reference to keep it alive and + * remember we have done so by treating weakSlot specially. + */ + Py_INCREF(rxObj); + sp->pyobj = rxObj; + + Py_INCREF(Py_True); + sp->weakSlot = Py_True; + } + } + } + else if ((sp -> name = sipStrdup(slot)) == NULL) + return -1; + else if (isQtSlot(slot)) + { + /* + * The user has decided to connect a Python signal to a Qt slot and + * specified the slot as "obj, SLOT('meth()')" rather than "obj.meth". + */ + + char *tail; + + /* Remove any arguments. */ + if ((tail = strchr(sp -> name,'(')) != NULL) + *tail = '\0'; + + /* + * A bit of a hack to indicate that this needs converting to a built-in + * method. + */ + sp -> name[0] = '\0'; + + /* Notice if the class instance disappears. */ + sp -> weakSlot = getWeakRef(rxObj); + + sp -> pyobj = rxObj; + } + else + /* It's a Qt signal. */ + sp -> pyobj = rxObj; + + return 0; +} + + +/* + * Return a weak reference to the given object. + */ +static PyObject *getWeakRef(PyObject *obj) +{ + PyObject *wr; + + if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL) + PyErr_Clear(); + + return wr; +} diff --git a/siplib/sip.h b/siplib/sip.h new file mode 100644 index 0000000..b22b77c --- /dev/null +++ b/siplib/sip.h @@ -0,0 +1,1587 @@ +/* + * The SIP module interface. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 _SIP_H +#define _SIP_H + + +/* + * This gets round a problem with Qt's moc and Python v2.3. Strictly speaking + * it's a Qt problem but later versions of Python include a fix for it so we + * might as well too. + */ +#undef slots + + +#include <Python.h> + +/* + * There is a mis-feature somewhere with the Borland compiler. This works + * around it. + */ +#if defined(__BORLANDC__) +#include <rpc.h> +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Sanity check on the Python version. */ +#if PY_VERSION_HEX < 0x02030000 +#error "This version of SIP requires Python v2.3 or later" +#endif + + +/* + * Define the SIP version number. + */ +#define SIP_VERSION 0x040a05 +#define SIP_VERSION_STR "4.10.5" + + +/* + * Define the current API version number. SIP must handle modules with the + * same major number and with the same or earlier minor number. Whenever data + * structure elements are added they must be appended and the minor number + * incremented. Whenever data structure elements are removed or the order + * changed then the major number must be incremented and the minor number set + * to 0. + * + * History: + * + * 7.1 Added the 'H' format character to sip_api_parse_result(). + * Deprecated the 'D' format character of sip_api_parse_result(). + * + * 7.0 Added sip_api_parse_kwd_args(). + * Added sipErrorState, sip_api_add_exception(). + * The type initialisation function is now passed a dictionary of keyword + * arguments. + * All argument parsers now update a set of error messages rather than an + * argument count. + * The signatures of sip_api_no_function() and sip_api_no_method() have + * changed. + * Added ctd_docstring to sipClassTypeDef. + * Added vf_docstring to sipVersionedFunctionDef. + * + * 6.0 Added the sipContainerDef structure to define the contents of a class + * or mapped type. Restructured sipClassDef and sipMappedTypeDef + * accordingly. + * Added the 'r' format character to sip_api_parse_args(). + * Added the 'r' format character to sip_api_call_method() and + * sip_api_build_result(). + * Added the assignment, array and copy allocation helpers. + * + * 5.0 Added sip_api_is_api_enabled(). + * Renamed the td_version_nr member of sipTypeDef to be int and where -1 + * indicates it is not versioned. + * Added the em_versions member to sipExportedModuleDef. + * Added the em_versioned_functions member to sipExportedModuleDef. + * + * 4.0 Much refactoring. + * + * 3.8 Added sip_api_register_qt_metatype() and sip_api_deprecated(). + * Added qt_register_meta_type() to the Qt support API. + * The C/C++ names of enums and types are now always defined in the + * relevant structures and don't default to the Python name. + * Added the 'XE' format characters to sip_api_parse_args(). + * + * 3.7 Added sip_api_convert_from_const_void_ptr(), + * sip_api_convert_from_void_ptr_and_size() and + * sip_api_convert_from_const_void_ptr_and_size(). + * Added the 'g' and 'G' format characters (to replace the now deprecated + * 'a' and 'A' format characters) to sip_api_build_result(), + * sip_api_call_method() and sip_api_parse_result(). + * Added the 'k' and 'K' format characters (to replace the now deprecated + * 'a' and 'A' format characters) to sip_api_parse_args(). + * Added sip_api_invoke_slot(). + * Added sip_api_parse_type(). + * Added sip_api_is_exact_wrapped_type(). + * Added sip_api_assign_instance(). + * Added sip_api_assign_mapped_type(). + * Added the td_assign and td_qt fields to the sipTypeDef structure. + * Added the mt_assign field to the sipMappedType structure. + * + * 3.6 Added the 'g' format character to sip_api_parse_args(). + * + * 3.5 Added the td_pickle field to the sipTypeDef structure. + * Added sip_api_transfer_break(). + * + * 3.4 Added qt_find_connection() to the Qt support API. + * Added sip_api_string_as_char(), sip_api_unicode_as_wchar(), + * sip_api_unicode_as_wstring(), sip_api_find_class(), + * sip_api_find_named_enum() and sip_api_parse_signature(). + * Added the 'A', 'w' and 'x' format characters to sip_api_parse_args(), + * sip_api_parse_result(), sip_api_build_result() and + * sip_api_call_method(). + * + * 3.3 Added sip_api_register_int_types(). + * + * 3.2 Added sip_api_export_symbol() and sip_api_import_symbol(). + * + * 3.1 Added sip_api_add_mapped_type_instance(). + * + * 3.0 Moved the Qt support out of the sip module and into PyQt. This is + * such a dramatic change that there is no point in attempting to maintain + * backwards compatibility. + * + * 2.0 Added the td_flags field to the sipTypeDef structure. + * Added the first_child, sibling_next, sibling_prev and parent fields to + * the sipWrapper structure. + * Added the td_traverse and td_clear fields to the sipTypeDef structure. + * Added the em_api_minor field to the sipExportedModuleDef structure. + * Added sip_api_bad_operator_arg(). + * Added sip_api_wrapper_check(). + * + * 1.1 Added support for __pos__ and __abs__. + * + * 1.0 Removed all deprecated parts of the API. + * Removed the td_proxy field from the sipTypeDef structure. + * Removed the create proxy function from the 'q' and 'y' format + * characters to sip_api_parse_args(). + * Removed sip_api_emit_to_slot(). + * Reworked the enum related structures. + * + * 0.2 Added the 'H' format character to sip_api_parse_args(). + * + * 0.1 Added sip_api_add_class_instance(). + * Added the 't' format character to sip_api_parse_args(). + * Deprecated the 'J' and 'K' format characters to sip_api_parse_result(). + * + * 0.0 Original version. + */ +#define SIP_API_MAJOR_NR 7 +#define SIP_API_MINOR_NR 1 + + +/* Some compatibility stuff to help with handwritten code for SIP v3. */ +#if !defined(ANY) +#define ANY void +#endif + + +/* Some Python compatibility stuff. */ +#if PY_VERSION_HEX >= 0x02050000 + +#define SIP_SSIZE_T Py_ssize_t + +#define SIP_MLNAME_CAST(s) (s) +#define SIP_MLDOC_CAST(s) (s) +#define SIP_TPNAME_CAST(s) (s) + +#else + +#define SIP_SSIZE_T int + +#define SIP_MLNAME_CAST(s) ((char *)(s)) +#define SIP_MLDOC_CAST(s) ((char *)(s)) +#define SIP_TPNAME_CAST(s) ((char *)(s)) + +#endif + +#if PY_MAJOR_VERSION >= 3 + +#define SIPLong_FromLong PyLong_FromLong +#define SIPLong_AsLong PyLong_AsLong + +#define SIPBytes_Check PyBytes_Check +#define SIPBytes_FromString PyBytes_FromString +#define SIPBytes_FromStringAndSize PyBytes_FromStringAndSize +#define SIPBytes_AS_STRING PyBytes_AS_STRING +#define SIPBytes_GET_SIZE PyBytes_GET_SIZE + +#if PY_MINOR_VERSION >= 1 +#define SIP_USE_PYCAPSULE +#endif + +#else + +#define SIPLong_FromLong PyInt_FromLong +#define SIPLong_AsLong PyInt_AsLong + +#define SIPBytes_Check PyString_Check +#define SIPBytes_FromString PyString_FromString +#define SIPBytes_FromStringAndSize PyString_FromStringAndSize +#define SIPBytes_AS_STRING PyString_AS_STRING +#define SIPBytes_GET_SIZE PyString_GET_SIZE + +#if PY_MINOR_VERSION >= 7 +#define SIP_USE_PYCAPSULE +#endif + +#endif + +#if !defined(Py_REFCNT) +#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) +#endif + +#if !defined(Py_TYPE) +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif + +#if !defined(PyVarObject_HEAD_INIT) +#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, +#endif + + +/* + * The mask that can be passed to sipTrace(). + */ +#define SIP_TRACE_CATCHERS 0x0001 +#define SIP_TRACE_CTORS 0x0002 +#define SIP_TRACE_DTORS 0x0004 +#define SIP_TRACE_INITS 0x0008 +#define SIP_TRACE_DEALLOCS 0x0010 +#define SIP_TRACE_METHODS 0x0020 + + +/* + * Hide some thread dependent stuff. + */ +#ifdef WITH_THREAD +typedef PyGILState_STATE sip_gilstate_t; +#define SIP_RELEASE_GIL(gs) PyGILState_Release(gs); +#define SIP_BLOCK_THREADS {PyGILState_STATE sipGIL = PyGILState_Ensure(); +#define SIP_UNBLOCK_THREADS PyGILState_Release(sipGIL);} +#else +typedef int sip_gilstate_t; +#define SIP_RELEASE_GIL(gs) +#define SIP_BLOCK_THREADS +#define SIP_UNBLOCK_THREADS +#endif + + +/* + * The meta-type of a wrapper type. + */ +typedef struct _sipWrapperType { + /* + * The super-metatype. This must be first in the structure so that it can + * be cast to a PyTypeObject *. + */ + PyHeapTypeObject super; + + /* The generated type structure. */ + struct _sipTypeDef *type; + + /* The list of init extenders. */ + struct _sipInitExtenderDef *iextend; + + /* Set if the type's dictionary contains all lazy attributes. */ + int dict_complete; +} sipWrapperType; + + +/* + * The type of a simple C/C++ wrapper object. + */ +typedef struct _sipSimpleWrapper { + PyObject_HEAD + + union { + /* C/C++ object pointer. */ + void *cppPtr; + + /* Access function. */ + void *(*afPtr)(); + } u; + + /* Object flags. */ + int flags; + + /* The optional dictionary of extra references keyed by argument number. */ + PyObject *extra_refs; + + /* For the user to use. */ + PyObject *user; + + /* The instance dictionary. */ + PyObject *dict; + + /* Next object at this address. */ + struct _sipSimpleWrapper *next; +} sipSimpleWrapper; + + +/* + * The type of a C/C++ wrapper object that supports parent/child relationships. + */ +typedef struct _sipWrapper { + /* The super-type. */ + sipSimpleWrapper super; + + /* First child object. */ + struct _sipWrapper *first_child; + + /* Next sibling. */ + struct _sipWrapper *sibling_next; + + /* Previous sibling. */ + struct _sipWrapper *sibling_prev; + + /* Owning object. */ + struct _sipWrapper *parent; +} sipWrapper; + + +/* + * The meta-type of an enum type. (This is exposed only to support the + * deprecated sipConvertFromNamedEnum() macro.) + */ +typedef struct _sipEnumTypeObject { + /* + * The super-metatype. This must be first in the structure so that it can + * be cast to a PyTypeObject *. + */ + PyHeapTypeObject super; + + /* The generated type structure. */ + struct _sipTypeDef *type; +} sipEnumTypeObject; + + +/* + * Some convenient function pointers. + */ +typedef void *(*sipInitFunc)(sipSimpleWrapper *, PyObject *, PyObject *, + PyObject **, PyObject **, PyObject **); +typedef int (*sipTraverseFunc)(void *, visitproc, void *); +typedef int (*sipClearFunc)(void *); +#if PY_MAJOR_VERSION >= 3 +typedef int (*sipGetBufferFunc)(PyObject *, void *, Py_buffer *, int); +typedef void (*sipReleaseBufferFunc)(PyObject *, void *, Py_buffer *); +#else +typedef SIP_SSIZE_T (*sipBufferFunc)(PyObject *, void *, SIP_SSIZE_T, void **); +typedef SIP_SSIZE_T (*sipSegCountFunc)(PyObject *, void *, SIP_SSIZE_T *); +#endif +typedef void (*sipDeallocFunc)(sipSimpleWrapper *); +typedef void *(*sipCastFunc)(void *, const struct _sipTypeDef *); +typedef const struct _sipTypeDef *(*sipSubClassConvertFunc)(void **); +typedef int (*sipConvertToFunc)(PyObject *, void **, int *, PyObject *); +typedef PyObject *(*sipConvertFromFunc)(void *, PyObject *); +typedef int (*sipVirtHandlerFunc)(void *, PyObject *, ...); +typedef void (*sipAssignFunc)(void *, SIP_SSIZE_T, const void *); +typedef void *(*sipArrayFunc)(SIP_SSIZE_T); +typedef void *(*sipCopyFunc)(const void *, SIP_SSIZE_T); +typedef void (*sipReleaseFunc)(void *, int); +typedef PyObject *(*sipPickleFunc)(void *); +typedef int (*sipAttrGetterFunc)(const struct _sipTypeDef *, PyObject *); +typedef PyObject *(*sipVariableGetterFunc)(void *, PyObject *); +typedef int (*sipVariableSetterFunc)(void *, PyObject *, PyObject *); + + +/* + * The information describing an encoded type ID. + */ +typedef struct _sipEncodedTypeDef { + /* The type number. */ + unsigned sc_type:16; + + /* The module number (255 for this one). */ + unsigned sc_module:8; + + /* A context specific flag. */ + unsigned sc_flag:1; +} sipEncodedTypeDef; + + +/* + * The information describing an enum member. + */ +typedef struct _sipEnumMemberDef { + /* The member name. */ + const char *em_name; + + /* The member value. */ + int em_val; + + /* The member enum, -ve if anonymous. */ + int em_enum; +} sipEnumMemberDef; + + +/* + * The information describing static instances. + */ +typedef struct _sipInstancesDef { + /* The types. */ + struct _sipTypeInstanceDef *id_type; + + /* The void *. */ + struct _sipVoidPtrInstanceDef *id_voidp; + + /* The chars. */ + struct _sipCharInstanceDef *id_char; + + /* The strings. */ + struct _sipStringInstanceDef *id_string; + + /* The ints. */ + struct _sipIntInstanceDef *id_int; + + /* The longs. */ + struct _sipLongInstanceDef *id_long; + + /* The unsigned longs. */ + struct _sipUnsignedLongInstanceDef *id_ulong; + + /* The long longs. */ + struct _sipLongLongInstanceDef *id_llong; + + /* The unsigned long longs. */ + struct _sipUnsignedLongLongInstanceDef *id_ullong; + + /* The doubles. */ + struct _sipDoubleInstanceDef *id_double; +} sipInstancesDef; + + +/* + * The information describing a type initialiser extender. + */ +typedef struct _sipInitExtenderDef { + /* The API version range index. */ + int ie_api_range; + + /* The extender function. */ + sipInitFunc ie_extender; + + /* The class being extended. */ + sipEncodedTypeDef ie_class; + + /* The next extender for this class. */ + struct _sipInitExtenderDef *ie_next; +} sipInitExtenderDef; + + +/* + * The information describing a sub-class convertor. + */ +typedef struct _sipSubClassConvertorDef { + /* The convertor. */ + sipSubClassConvertFunc scc_convertor; + + /* The encoded base type. */ + sipEncodedTypeDef scc_base; + + /* The base type. */ + struct _sipTypeDef *scc_basetype; +} sipSubClassConvertorDef; + + +/* + * The different error states of handwritten code. + */ +typedef enum { + sipErrorNone, /* There is no error. */ + sipErrorFail, /* The error is a failure. */ + sipErrorContinue /* It may not apply if a later operation succeeds. */ +} sipErrorState; + + +/* + * The different Python slot types. + */ +typedef enum { + str_slot, /* __str__ */ + int_slot, /* __int__ */ +#if PY_MAJOR_VERSION < 3 + long_slot, /* __long__ */ +#endif + float_slot, /* __float__ */ + len_slot, /* __len__ */ + contains_slot, /* __contains__ */ + add_slot, /* __add__ for number */ + concat_slot, /* __add__ for sequence types */ + sub_slot, /* __sub__ */ + mul_slot, /* __mul__ for number types */ + repeat_slot, /* __mul__ for sequence types */ + div_slot, /* __div__ */ + mod_slot, /* __mod__ */ + floordiv_slot, /* __floordiv__ */ + truediv_slot, /* __truediv__ */ + and_slot, /* __and__ */ + or_slot, /* __or__ */ + xor_slot, /* __xor__ */ + lshift_slot, /* __lshift__ */ + rshift_slot, /* __rshift__ */ + iadd_slot, /* __iadd__ for number types */ + iconcat_slot, /* __iadd__ for sequence types */ + isub_slot, /* __isub__ */ + imul_slot, /* __imul__ for number types */ + irepeat_slot, /* __imul__ for sequence types */ + idiv_slot, /* __idiv__ */ + imod_slot, /* __imod__ */ + ifloordiv_slot, /* __ifloordiv__ */ + itruediv_slot, /* __itruediv__ */ + iand_slot, /* __iand__ */ + ior_slot, /* __ior__ */ + ixor_slot, /* __ixor__ */ + ilshift_slot, /* __ilshift__ */ + irshift_slot, /* __irshift__ */ + invert_slot, /* __invert__ */ + call_slot, /* __call__ */ + getitem_slot, /* __getitem__ */ + setitem_slot, /* __setitem__ */ + delitem_slot, /* __delitem__ */ + lt_slot, /* __lt__ */ + le_slot, /* __le__ */ + eq_slot, /* __eq__ */ + ne_slot, /* __ne__ */ + gt_slot, /* __gt__ */ + ge_slot, /* __ge__ */ +#if PY_MAJOR_VERSION < 3 + cmp_slot, /* __cmp__ */ +#endif + bool_slot, /* __bool__, __nonzero__ */ + neg_slot, /* __neg__ */ + repr_slot, /* __repr__ */ + hash_slot, /* __hash__ */ + pos_slot, /* __pos__ */ + abs_slot, /* __abs__ */ +#if PY_VERSION_HEX >= 0x02050000 + index_slot, /* __index__ */ +#endif + iter_slot, /* __iter__ */ + next_slot, /* __next__ */ +} sipPySlotType; + + +/* + * The information describing a Python slot function. + */ +typedef struct _sipPySlotDef { + /* The function. */ + void *psd_func; + + /* The type. */ + sipPySlotType psd_type; +} sipPySlotDef; + + +/* + * The information describing a Python slot extender. + */ +typedef struct _sipPySlotExtenderDef { + /* The function. */ + void *pse_func; + + /* The type. */ + sipPySlotType pse_type; + + /* The encoded class. */ + sipEncodedTypeDef pse_class; +} sipPySlotExtenderDef; + + +/* + * The information describing a typedef. + */ +typedef struct _sipTypedefDef { + /* The typedef name. */ + const char *tdd_name; + + /* The typedef value. */ + const char *tdd_type_name; +} sipTypedefDef; + + +/* + * The information describing a variable. + */ +typedef struct _sipVariableDef { + /* The variable name. */ + const char *vd_name; + + /* The variable getter. */ + sipVariableGetterFunc vd_getter; + + /* The variable setter. It is NULL if the variable is const. */ + sipVariableSetterFunc vd_setter; + + /* This is set if the variable is static. */ + int vd_is_static; +} sipVariableDef; + + +/* + * The information describing a type, either a C++ class (or C struct), a C++ + * namespace, a mapped type or a named enum. + */ +typedef struct _sipTypeDef { + /* The version range index, -1 if the type isn't versioned. */ + int td_version; + + /* The next version of this type. */ + struct _sipTypeDef *td_next_version; + + /* The module, 0 if the type hasn't been initialised. */ + struct _sipExportedModuleDef *td_module; + + /* Type flags, see the sipType*() macros. */ + int td_flags; + + /* The C/C++ name of the type. */ + int td_cname; + + /* + * The Python type object. This needs to be a union until we remove the + * deprecated sipClass_* macros. + */ + union { + PyTypeObject *td_py_type; + sipWrapperType *td_wrapper_type; + } u; +} sipTypeDef; + + +/* + * The information describing a container (ie. a class, namespace or a mapped + * type). + */ +typedef struct _sipContainerDef { + /* + * The Python name of the type, -1 if this is a namespace extender (in the + * context of a class) or doesn't require a namespace (in the context of a + * mapped type). */ + int cod_name; + + /* + * The scoping type or the namespace this is extending if it is a namespace + * extender. + */ + sipEncodedTypeDef cod_scope; + + /* The number of lazy methods. */ + int cod_nrmethods; + + /* The table of lazy methods. */ + PyMethodDef *cod_methods; + + /* The number of lazy enum members. */ + int cod_nrenummembers; + + /* The table of lazy enum members. */ + sipEnumMemberDef *cod_enummembers; + + /* The number of variables. */ + int cod_nrvariables; + + /* The table of variables. */ + sipVariableDef *cod_variables; + + /* The static instances. */ + sipInstancesDef cod_instances; +} sipContainerDef; + + +/* + * The information describing a C++ class (or C struct) or a C++ namespace. + */ +typedef struct _sipClassTypeDef { + /* The base type information. */ + sipTypeDef ctd_base; + + /* The container information. */ + sipContainerDef ctd_container; + + /* The docstring. */ + const char *ctd_docstring; + + /* + * The meta-type name, -1 to use the meta-type of the first super-type + * (normally sipWrapperType). + */ + int ctd_metatype; + + /* The super-type name, -1 to use sipWrapper. */ + int ctd_supertype; + + /* The super-types. */ + sipEncodedTypeDef *ctd_supers; + + /* The table of Python slots. */ + sipPySlotDef *ctd_pyslots; + + /* The initialisation function. */ + sipInitFunc ctd_init; + + /* The traverse function. */ + sipTraverseFunc ctd_traverse; + + /* The clear function. */ + sipClearFunc ctd_clear; + +#if PY_MAJOR_VERSION >= 3 + /* The get buffer function. */ + sipGetBufferFunc ctd_getbuffer; + + /* The release buffer function. */ + sipReleaseBufferFunc ctd_releasebuffer; +#else + /* The read buffer function. */ + sipBufferFunc ctd_readbuffer; + + /* The write buffer function. */ + sipBufferFunc ctd_writebuffer; + + /* The segment count function. */ + sipSegCountFunc ctd_segcount; + + /* The char buffer function. */ + sipBufferFunc ctd_charbuffer; +#endif + + /* The deallocation function. */ + sipDeallocFunc ctd_dealloc; + + /* The optional assignment function. */ + sipAssignFunc ctd_assign; + + /* The optional array allocation function. */ + sipArrayFunc ctd_array; + + /* The optional copy function. */ + sipCopyFunc ctd_copy; + + /* The release function, 0 if a C strict. */ + sipReleaseFunc ctd_release; + + /* The cast function, 0 if a C struct. */ + sipCastFunc ctd_cast; + + /* The optional convert to function. */ + sipConvertToFunc ctd_cto; + + /* The next namespace extender. */ + struct _sipClassTypeDef *ctd_nsextender; + + /* The pickle function. */ + sipPickleFunc ctd_pickle; +} sipClassTypeDef; + + +/* + * The information describing a mapped type. + */ +typedef struct _sipMappedTypeDef { + /* The base type information. */ + sipTypeDef mtd_base; + + /* The container information. */ + sipContainerDef mtd_container; + + /* The optional assignment function. */ + sipAssignFunc mtd_assign; + + /* The optional array allocation function. */ + sipArrayFunc mtd_array; + + /* The optional copy function. */ + sipCopyFunc mtd_copy; + + /* The optional release function. */ + sipReleaseFunc mtd_release; + + /* The convert to function. */ + sipConvertToFunc mtd_cto; + + /* The convert from function. */ + sipConvertFromFunc mtd_cfrom; +} sipMappedTypeDef; + + +/* + * The information describing a named enum. + */ +typedef struct _sipEnumTypeDef { + /* The base type information. */ + sipTypeDef etd_base; + + /* The Python name of the enum. */ + int etd_name; + + /* The scoping type, -1 if it is defined at the module level. */ + int etd_scope; + + /* The Python slots. */ + struct _sipPySlotDef *etd_pyslots; +} sipEnumTypeDef; + + +/* + * The information describing an external type. + */ +typedef struct _sipExternalTypeDef { + /* The index into the type table. */ + int et_nr; + + /* The name of the type. */ + const char *et_name; +} sipExternalTypeDef; + + +/* + * The information describing a mapped class. This (and anything that uses it) + * is deprecated. + */ +typedef sipTypeDef sipMappedType; + + +/* + * Defines an entry in the module specific list of delayed dtor calls. + */ +typedef struct _sipDelayedDtor { + /* The C/C++ instance. */ + void *dd_ptr; + + /* The class name. */ + const char *dd_name; + + /* Non-zero if dd_ptr is a derived class instance. */ + int dd_isderived; + + /* Next in the list. */ + struct _sipDelayedDtor *dd_next; +} sipDelayedDtor; + + +/* + * Defines an entry in the table of global functions all of whose overloads + * are versioned (so their names can't be automatically added to the module + * dictionary). + */ +typedef struct _sipVersionedFunctionDef { + /* The name, -1 marks the end of the table. */ + int vf_name; + + /* The function itself. */ + PyCFunction vf_function; + + /* The METH_* flags. */ + int vf_flags; + + /* The docstring. */ + const char *vf_docstring; + + /* The API version range index. */ + int vf_api_range; +} sipVersionedFunctionDef; + + +/* + * The information describing an imported module. + */ +typedef struct _sipImportedModuleDef { + /* The module name. */ + const char *im_name; + + /* The required version. */ + int im_version; + + /* The imported module. */ + struct _sipExportedModuleDef *im_module; +} sipImportedModuleDef; + + +/* + * The main client module structure. + */ +typedef struct _sipExportedModuleDef { + /* The next in the list. */ + struct _sipExportedModuleDef *em_next; + + /* The SIP API minor version number. */ + unsigned em_api_minor; + + /* The module name. */ + int em_name; + + /* The module name as an object. */ + PyObject *em_nameobj; + + /* The module version. */ + int em_version; + + /* The string pool. */ + const char *em_strings; + + /* The imported modules. */ + sipImportedModuleDef *em_imports; + + /* The optional Qt support API. */ + struct _sipQtAPI *em_qt_api; + + /* The number of types. */ + int em_nrtypes; + + /* The table of types. */ + sipTypeDef **em_types; + + /* The table of external types. */ + sipExternalTypeDef *em_external; + + /* The number of members in global enums. */ + int em_nrenummembers; + + /* The table of members in global enums. */ + sipEnumMemberDef *em_enummembers; + + /* The number of typedefs. */ + int em_nrtypedefs; + + /* The table of typedefs. */ + sipTypedefDef *em_typedefs; + + /* The table of virtual handlers. */ + sipVirtHandlerFunc *em_virthandlers; + + /* The sub-class convertors. */ + sipSubClassConvertorDef *em_convertors; + + /* The static instances. */ + sipInstancesDef em_instances; + + /* The license. */ + struct _sipLicenseDef *em_license; + + /* The table of exception types. */ + PyObject **em_exceptions; + + /* The table of Python slot extenders. */ + sipPySlotExtenderDef *em_slotextend; + + /* The table of initialiser extenders. */ + sipInitExtenderDef *em_initextend; + + /* The delayed dtor handler. */ + void (*em_delayeddtors)(const sipDelayedDtor *); + + /* The list of delayed dtors. */ + sipDelayedDtor *em_ddlist; + + /* + * The array of API version definitions. Each definition takes up 3 + * elements. If the third element of a 3-tuple is negative then the first + * two elements define an API and its default version. All such + * definitions will appear at the end of the array. If the first element + * of a 3-tuple is negative then that is the last element of the array. + */ + int *em_versions; + + /* The optional table of versioned functions. */ + sipVersionedFunctionDef *em_versioned_functions; +} sipExportedModuleDef; + + +/* + * The information describing a license to be added to a dictionary. + */ +typedef struct _sipLicenseDef { + /* The type of license. */ + const char *lc_type; + + /* The licensee. */ + const char *lc_licensee; + + /* The timestamp. */ + const char *lc_timestamp; + + /* The signature. */ + const char *lc_signature; +} sipLicenseDef; + + +/* + * The information describing a void pointer instance to be added to a + * dictionary. + */ +typedef struct _sipVoidPtrInstanceDef { + /* The void pointer name. */ + const char *vi_name; + + /* The void pointer value. */ + void *vi_val; +} sipVoidPtrInstanceDef; + + +/* + * The information describing a char instance to be added to a dictionary. + */ +typedef struct _sipCharInstanceDef { + /* The char name. */ + const char *ci_name; + + /* The char value. */ + char ci_val; + + /* The encoding used, either 'A', 'L', '8' or 'N'. */ + char ci_encoding; +} sipCharInstanceDef; + + +/* + * The information describing a string instance to be added to a dictionary. + */ +typedef struct _sipStringInstanceDef { + /* The string name. */ + const char *si_name; + + /* The string value. */ + const char *si_val; + + /* The encoding used, either 'A', 'L', '8' or 'N'. */ + char si_encoding; +} sipStringInstanceDef; + + +/* + * The information describing an int instance to be added to a dictionary. + */ +typedef struct _sipIntInstanceDef { + /* The int name. */ + const char *ii_name; + + /* The int value. */ + int ii_val; +} sipIntInstanceDef; + + +/* + * The information describing a long instance to be added to a dictionary. + */ +typedef struct _sipLongInstanceDef { + /* The long name. */ + const char *li_name; + + /* The long value. */ + long li_val; +} sipLongInstanceDef; + + +/* + * The information describing an unsigned long instance to be added to a + * dictionary. + */ +typedef struct _sipUnsignedLongInstanceDef { + /* The unsigned long name. */ + const char *uli_name; + + /* The unsigned long value. */ + unsigned long uli_val; +} sipUnsignedLongInstanceDef; + + +/* + * The information describing a long long instance to be added to a dictionary. + */ +typedef struct _sipLongLongInstanceDef { + /* The long long name. */ + const char *lli_name; + + /* The long long value. */ +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG lli_val; +#else + long lli_val; +#endif +} sipLongLongInstanceDef; + + +/* + * The information describing an unsigned long long instance to be added to a + * dictionary. + */ +typedef struct _sipUnsignedLongLongInstanceDef { + /* The unsigned long long name. */ + const char *ulli_name; + + /* The unsigned long long value. */ +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG ulli_val; +#else + unsigned long ulli_val; +#endif +} sipUnsignedLongLongInstanceDef; + + +/* + * The information describing a double instance to be added to a dictionary. + */ +typedef struct _sipDoubleInstanceDef { + /* The double name. */ + const char *di_name; + + /* The double value. */ + double di_val; +} sipDoubleInstanceDef; + + +/* + * The information describing a class or enum instance to be added to a + * dictionary. + */ +typedef struct _sipTypeInstanceDef { + /* The type instance name. */ + const char *ti_name; + + /* The actual instance. */ + void *ti_ptr; + + /* A pointer to the generated type. */ + struct _sipTypeDef **ti_type; + + /* The wrapping flags. */ + int ti_flags; +} sipTypeInstanceDef; + + +/* + * Define a mapping between a wrapped type identified by a string and the + * corresponding Python type. This is deprecated. + */ +typedef struct _sipStringTypeClassMap { + /* The type as a string. */ + const char *typeString; + + /* A pointer to the Python type. */ + struct _sipWrapperType **pyType; +} sipStringTypeClassMap; + + +/* + * Define a mapping between a wrapped type identified by an integer and the + * corresponding Python type. This is deprecated. + */ +typedef struct _sipIntTypeClassMap { + /* The type as an integer. */ + int typeInt; + + /* A pointer to the Python type. */ + struct _sipWrapperType **pyType; +} sipIntTypeClassMap; + + +/* + * A Python method's component parts. This allows us to re-create the method + * without changing the reference counts of the components. + */ +typedef struct _sipPyMethod { + /* The function. */ + PyObject *mfunc; + + /* Self if it is a bound method. */ + PyObject *mself; + +#if PY_MAJOR_VERSION < 3 + /* The class. */ + PyObject *mclass; +#endif +} sipPyMethod; + + +/* + * A slot (in the Qt, rather than Python, sense). + */ +typedef struct _sipSlot { + /* Name if a Qt or Python signal. */ + char *name; + + /* Signal or Qt slot object. */ + PyObject *pyobj; + + /* Python slot method, pyobj is NULL. */ + sipPyMethod meth; + + /* A weak reference to the slot, Py_True if pyobj has an extra reference. */ + PyObject *weakSlot; +} sipSlot; + + +/* + * The API exported by the SIP module, ie. pointers to all the data and + * functions that can be used by generated code. + */ +typedef struct _sipAPIDef { + /* + * This must be the first entry and it's signature must not change so that + * version number mismatches can be detected and reported. + */ + int (*api_export_module)(sipExportedModuleDef *client, unsigned api_major, + unsigned api_minor, void *unused); + + /* + * The following are part of the public API. + */ + PyTypeObject *api_simplewrapper_type; + PyTypeObject *api_wrapper_type; + PyTypeObject *api_wrappertype_type; + PyTypeObject *api_voidptr_type; + + void (*api_bad_catcher_result)(PyObject *method); + void (*api_bad_length_for_slice)(SIP_SSIZE_T seqlen, SIP_SSIZE_T slicelen); + PyObject *(*api_build_result)(int *isErr, const char *fmt, ...); + PyObject *(*api_call_method)(int *isErr, PyObject *method, const char *fmt, + ...); + PyObject *(*api_connect_rx)(PyObject *txObj, const char *sig, + PyObject *rxObj, const char *slot, int type); + SIP_SSIZE_T (*api_convert_from_sequence_index)(SIP_SSIZE_T idx, + SIP_SSIZE_T len); + int (*api_can_convert_to_type)(PyObject *pyObj, const sipTypeDef *td, + int flags); + void *(*api_convert_to_type)(PyObject *pyObj, const sipTypeDef *td, + PyObject *transferObj, int flags, int *statep, int *iserrp); + void *(*api_force_convert_to_type)(PyObject *pyObj, const sipTypeDef *td, + PyObject *transferObj, int flags, int *statep, int *iserrp); + int (*api_can_convert_to_enum)(PyObject *pyObj, const sipTypeDef *td); + void (*api_release_type)(void *cpp, const sipTypeDef *td, int state); + PyObject *(*api_convert_from_type)(void *cpp, const sipTypeDef *td, + PyObject *transferObj); + PyObject *(*api_convert_from_new_type)(void *cpp, const sipTypeDef *td, + PyObject *transferObj); + PyObject *(*api_convert_from_enum)(int eval, const sipTypeDef *td); + int (*api_get_state)(PyObject *transferObj); + PyObject *(*api_disconnect_rx)(PyObject *txObj, const char *sig, + PyObject *rxObj, const char *slot); + void (*api_free)(void *mem); + PyObject *(*api_get_pyobject)(void *cppPtr, const sipTypeDef *td); + void *(*api_malloc)(size_t nbytes); + int (*api_parse_result)(int *isErr, PyObject *method, PyObject *res, + const char *fmt, ...); + void (*api_trace)(unsigned mask, const char *fmt, ...); + void (*api_transfer_back)(PyObject *self); + void (*api_transfer_to)(PyObject *self, PyObject *owner); + void (*api_transfer_break)(PyObject *self); + unsigned long (*api_long_as_unsigned_long)(PyObject *o); + PyObject *(*api_convert_from_void_ptr)(void *val); + PyObject *(*api_convert_from_const_void_ptr)(const void *val); + PyObject *(*api_convert_from_void_ptr_and_size)(void *val, + SIP_SSIZE_T size); + PyObject *(*api_convert_from_const_void_ptr_and_size)(const void *val, + SIP_SSIZE_T size); + void *(*api_convert_to_void_ptr)(PyObject *obj); + int (*api_export_symbol)(const char *name, void *sym); + void *(*api_import_symbol)(const char *name); + const sipTypeDef *(*api_find_type)(const char *type); + int (*api_register_py_type)(PyTypeObject *type); + const sipTypeDef *(*api_type_from_py_type_object)(PyTypeObject *py_type); + const sipTypeDef *(*api_type_scope)(const sipTypeDef *td); + const char *(*api_resolve_typedef)(const char *name); + int (*api_register_attribute_getter)(const sipTypeDef *td, + sipAttrGetterFunc getter); + int (*api_is_api_enabled)(const char *name, int from, int to); + sipErrorState (*api_bad_callable_arg)(int arg_nr, PyObject *arg); + + /* + * The following are deprecated parts of the public API. + */ + PyTypeObject *(*api_find_named_enum)(const char *type); + const sipMappedType *(*api_find_mapped_type)(const char *type); + sipWrapperType *(*api_find_class)(const char *type); + sipWrapperType *(*api_map_int_to_class)(int typeInt, + const sipIntTypeClassMap *map, int maplen); + sipWrapperType *(*api_map_string_to_class)(const char *typeString, + const sipStringTypeClassMap *map, int maplen); + + /* + * The following may be used by Qt support code but no other handwritten + * code. + */ + void (*api_free_sipslot)(sipSlot *slot); + int (*api_same_slot)(const sipSlot *sp, PyObject *rxObj, const char *slot); + void *(*api_convert_rx)(sipWrapper *txSelf, const char *sigargs, + PyObject *rxObj, const char *slot, const char **memberp, + int flags); + PyObject *(*api_invoke_slot)(const sipSlot *slot, PyObject *sigargs); + int (*api_save_slot)(sipSlot *sp, PyObject *rxObj, const char *slot); + void (*api_clear_any_slot_reference)(sipSlot *slot); + int (*api_visit_slot)(sipSlot *slot, visitproc visit, void *arg); + + /* + * The following are not part of the public API. + */ + int (*api_init_module)(sipExportedModuleDef *client, PyObject *mod_dict); + int (*api_parse_args)(PyObject **parseErrp, PyObject *sipArgs, + const char *fmt, ...); + int (*api_parse_pair)(PyObject **parseErrp, PyObject *arg0, PyObject *arg1, + const char *fmt, ...); + void (*api_common_dtor)(sipSimpleWrapper *sipSelf); + void (*api_no_function)(PyObject *parseErr, const char *func, + const char *doc); + void (*api_no_method)(PyObject *parseErr, const char *scope, + const char *method, const char *doc); + void (*api_abstract_method)(const char *classname, const char *method); + void (*api_bad_class)(const char *classname); + void *(*api_get_cpp_ptr)(sipSimpleWrapper *w, const sipTypeDef *td); + void *(*api_get_complex_cpp_ptr)(sipSimpleWrapper *w); + PyObject *(*api_is_py_method)(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper *sipSelf, const char *cname, const char *mname); + void (*api_call_hook)(const char *hookname); + void (*api_start_thread)(void); + void (*api_end_thread)(void); + void (*api_raise_unknown_exception)(void); + void (*api_raise_type_exception)(const sipTypeDef *td, void *ptr); + int (*api_add_type_instance)(PyObject *dict, const char *name, + void *cppPtr, const sipTypeDef *td); + void (*api_bad_operator_arg)(PyObject *self, PyObject *arg, + sipPySlotType st); + PyObject *(*api_pyslot_extend)(sipExportedModuleDef *mod, sipPySlotType st, + const sipTypeDef *type, PyObject *arg0, PyObject *arg1); + void (*api_add_delayed_dtor)(sipSimpleWrapper *w); + char (*api_bytes_as_char)(PyObject *obj); + const char *(*api_bytes_as_string)(PyObject *obj); + char (*api_string_as_ascii_char)(PyObject *obj); + const char *(*api_string_as_ascii_string)(PyObject **obj); + char (*api_string_as_latin1_char)(PyObject *obj); + const char *(*api_string_as_latin1_string)(PyObject **obj); + char (*api_string_as_utf8_char)(PyObject *obj); + const char *(*api_string_as_utf8_string)(PyObject **obj); +#if defined(HAVE_WCHAR_H) + wchar_t (*api_unicode_as_wchar)(PyObject *obj); + wchar_t *(*api_unicode_as_wstring)(PyObject *obj); +#else + int (*api_unicode_as_wchar)(PyObject *obj); + int *(*api_unicode_as_wstring)(PyObject *obj); +#endif + int (*api_deprecated)(const char *classname, const char *method); + void (*api_keep_reference)(PyObject *self, int key, PyObject *obj); + int (*api_parse_kwd_args)(PyObject **parseErrp, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused, + const char *fmt, ...); + void (*api_add_exception)(sipErrorState es, PyObject **parseErrp); +} sipAPIDef; + + +/* + * The API implementing the optional Qt support. + */ +typedef struct _sipQtAPI { + sipTypeDef **qt_qobject; + void *(*qt_create_universal_signal)(void *, const char **); + void *(*qt_find_universal_signal)(void *, const char **); + void *(*qt_create_universal_slot)(struct _sipWrapper *, const char *, + PyObject *, const char *, const char **, int); + void (*qt_destroy_universal_slot)(void *); + void *(*qt_find_slot)(void *, const char *, PyObject *, const char *, + const char **); + int (*qt_connect)(void *, const char *, void *, const char *, int); + int (*qt_disconnect)(void *, const char *, void *, const char *); + int (*qt_same_name)(const char *, const char *); + sipSlot *(*qt_find_sipslot)(void *, void **); + int (*qt_emit_signal)(PyObject *, const char *, PyObject *); + int (*qt_connect_py_signal)(PyObject *, const char *, PyObject *, + const char *); + void (*qt_disconnect_py_signal)(PyObject *, const char *, PyObject *, + const char *); +} sipQtAPI; + + +/* + * These are flags that can be passed to sipCanConvertToType(), + * sipConvertToType() and sipForceConvertToType(). + */ +#define SIP_NOT_NONE 0x01 /* Disallow None. */ +#define SIP_NO_CONVERTORS 0x02 /* Disable any type convertors. */ + + +/* + * These are the state flags returned by %ConvertToTypeCode. Note that these + * share the same "namespace" as the flags below. + */ +#define SIP_TEMPORARY 0x0001 /* A temporary instance. */ +#define SIP_DERIVED_CLASS 0x0002 /* The instance is derived. */ + + +/* + * These flags are specific to the Qt support API. + */ +#define SIP_SINGLE_SHOT 0x01 /* The connection is single shot. */ + + +/* + * Useful macros, not part of the public API. + */ +#define SIP_PY_OWNED 0x0004 /* Owned by Python. */ +#define SIP_INDIRECT 0x0008 /* If there is a level of indirection. */ +#define SIP_ACCFUNC 0x0010 /* If there is an access function. */ +#define SIP_NOT_IN_MAP 0x0020 /* If Python object not in the map. */ +#define SIP_SHARE_MAP 0x0040 /* If the map slot might be occupied. */ +#define SIP_CPP_HAS_REF 0x0080 /* If C/C++ has a reference. */ +#define SIP_POSSIBLE_PROXY 0x0100 /* If there might be a proxy slot. */ + +#define sipIsPyOwned(w) ((w)->flags & SIP_PY_OWNED) +#define sipSetPyOwned(w) ((w)->flags |= SIP_PY_OWNED) +#define sipResetPyOwned(w) ((w)->flags &= ~SIP_PY_OWNED) +#define sipIsDerived(w) ((w)->flags & SIP_DERIVED_CLASS) +#define sipIsIndirect(w) ((w)->flags & SIP_INDIRECT) +#define sipIsAccessFunc(w) ((w)->flags & SIP_ACCFUNC) +#define sipNotInMap(w) ((w)->flags & SIP_NOT_IN_MAP) +#define sipSetNotInMap(w) ((w)->flags |= SIP_NOT_IN_MAP) +#define sipCppHasRef(w) ((w)->flags & SIP_CPP_HAS_REF) +#define sipSetCppHasRef(w) ((w)->flags |= SIP_CPP_HAS_REF) +#define sipResetCppHasRef(w) ((w)->flags &= ~SIP_CPP_HAS_REF) +#define sipPossibleProxy(w) ((w)->flags & SIP_POSSIBLE_PROXY) +#define sipSetPossibleProxy(w) ((w)->flags |= SIP_POSSIBLE_PROXY) + + +#define SIP_TYPE_TYPE_MASK 0x0007 /* The type type mask. */ +#define SIP_TYPE_CLASS 0x0000 /* If the type is a C++ class. */ +#define SIP_TYPE_NAMESPACE 0x0001 /* If the type is a C++ namespace. */ +#define SIP_TYPE_MAPPED 0x0002 /* If the type is a mapped type. */ +#define SIP_TYPE_ENUM 0x0003 /* If the type is a named enum. */ +#define SIP_TYPE_ABSTRACT 0x0008 /* If the type is abstract. */ +#define SIP_TYPE_SCC 0x0010 /* If the type is subject to sub-class convertors. */ +#define SIP_TYPE_ALLOW_NONE 0x0020 /* If the type can handle None. */ +#define SIP_TYPE_STUB 0x0040 /* If the type is a stub. */ + + +/* + * The following are part of the public API. + */ +#define sipTypeIsClass(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_CLASS) +#define sipTypeIsNamespace(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_NAMESPACE) +#define sipTypeIsMapped(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_MAPPED) +#define sipTypeIsEnum(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_ENUM) +#define sipTypeAsPyTypeObject(td) ((td)->u.td_py_type) +#define sipTypeName(td) sipNameFromPool((td)->td_module, (td)->td_cname) + +#define sipIsExactWrappedType(wt) (sipTypeAsPyTypeObject((wt)->type) == (PyTypeObject *)(wt)) + +#define sipConvertFromSliceObject(o,len,start,stop,step,slen) \ + PySlice_GetIndicesEx((PySliceObject *)(o), (len), (start), (stop), \ + (step), (slen)) + + +/* + * The following are deprecated parts of the public API. + */ +#define sipClassName(w) PyString_FromString(Py_TYPE(w)->tp_name) + + +/* + * The following are not part of the public API. + */ +#define sipTypeIsAbstract(td) ((td)->td_flags & SIP_TYPE_ABSTRACT) +#define sipTypeHasSCC(td) ((td)->td_flags & SIP_TYPE_SCC) +#define sipTypeAllowNone(td) ((td)->td_flags & SIP_TYPE_ALLOW_NONE) +#define sipTypeIsStub(td) ((td)->td_flags & SIP_TYPE_STUB) +#define sipTypeSetStub(td) ((td)->td_flags |= SIP_TYPE_STUB) + +/* + * Get various names from the string pool for various data types. + */ +#define sipNameFromPool(em, mr) (&((em)->em_strings)[(mr)]) +#define sipNameOfModule(em) sipNameFromPool((em), (em)->em_name) +#define sipPyNameOfContainer(cod, td) sipNameFromPool((td)->td_module, (cod)->cod_name) +#define sipPyNameOfEnum(etd) sipNameFromPool((etd)->etd_base.td_module, (etd)->etd_name) + + +/* + * The following are PyQt3-specific extensions. In SIP v5 they will be pushed + * 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 struct _pyqt3QtSignal { + /* The signal name. */ + const char *st_name; + + /* The emitter function. */ + pyqt3EmitFunc st_emitfunc; +} pyqt3QtSignal; + + +/* + * This is the PyQt3-specific extension to the generated class type structure. + */ +typedef struct _pyqt3ClassTypeDef { + /* + * The super-type structure. This must be first in the structure so that + * it can be cast to sipClassTypeDef *. + */ + sipClassTypeDef super; + + /* The emit table for Qt signals. */ + pyqt3QtSignal *qt3_emit; +} pyqt3ClassTypeDef; + + +/* + * The following are PyQt4-specific extensions. In SIP v5 they will be pushed + * out to a plugin supplied by PyQt4. + */ + +/* + * The description of a Qt signal for PyQt4. + */ +typedef struct _pyqt4QtSignal { + /* The 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; +} pyqt4QtSignal; + + +/* + * This is the PyQt4-specific extension to the generated class type structure. + */ +typedef struct _pyqt4ClassTypeDef { + /* + * 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 *qt4_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; + + /* + * The table of signals emitted by the type. These are grouped by signal + * name. + */ + const pyqt4QtSignal *qt4_signals; +} pyqt4ClassTypeDef; + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/siplib/sipint.h b/siplib/sipint.h new file mode 100644 index 0000000..19a8b1b --- /dev/null +++ b/siplib/sipint.h @@ -0,0 +1,149 @@ +/* + * This file defines the SIP library internal interfaces. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 _SIPINT_H +#define _SIPINT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#undef TRUE +#define TRUE 1 + +#undef FALSE +#define FALSE 0 + + +/* + * This defines a single entry in an object map's hash table. + */ +typedef struct +{ + void *key; /* The C/C++ address. */ + sipSimpleWrapper *first; /* The first object at this address. */ +} sipHashEntry; + + +/* + * This defines the interface to a hash table class for mapping C/C++ addresses + * to the corresponding wrapped Python object. + */ +typedef struct +{ + int primeIdx; /* Index into table sizes. */ + unsigned long size; /* Size of hash table. */ + unsigned long unused; /* Nr. unused in hash table. */ + unsigned long stale; /* Nr. stale in hash table. */ + sipHashEntry *hash_array; /* Current hash table. */ +} sipObjectMap; + + +/* + * Support for the descriptors. + */ +extern PyTypeObject sipMethodDescr_Type; +PyObject *sipMethodDescr_New(PyMethodDef *pmd); + +extern PyTypeObject sipVariableDescr_Type; +PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td, + const sipContainerDef *cod); + + +/* + * Support for API versions. + */ +PyObject *sipGetAPI(PyObject *self, PyObject *args); +PyObject *sipSetAPI(PyObject *self, PyObject *args); +int sip_api_is_api_enabled(const char *name, int from, int to); +int sipIsRangeEnabled(sipExportedModuleDef *em, int range_index); +int sipInitAPI(sipExportedModuleDef *em, PyObject *mod_dict); + + +/* + * Support for void pointers. + */ +extern PyTypeObject sipVoidPtr_Type; +void *sip_api_convert_to_void_ptr(PyObject *obj); +PyObject *sip_api_convert_from_void_ptr(void *val); +PyObject *sip_api_convert_from_const_void_ptr(const void *val); +PyObject *sip_api_convert_from_void_ptr_and_size(void *val, SIP_SSIZE_T size); +PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val, + SIP_SSIZE_T size); + + +extern sipQtAPI *sipQtSupport; /* The Qt support API. */ +extern sipWrapperType sipSimpleWrapper_Type; /* The simple wrapper type. */ +extern sipTypeDef *sipQObjectType; /* The QObject type. */ + +void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj, + const char *slot, const char **memberp); +PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj, + const char *slot, int type); +PyObject *sip_api_disconnect_rx(PyObject *txObj, const char *sig, + PyObject *rxObj,const char *slot); + + +/* + * These are part of the SIP API but are also used within the SIP module. + */ +void *sip_api_malloc(size_t nbytes); +void sip_api_free(void *mem); +void *sip_api_get_cpp_ptr(sipSimpleWrapper *w, const sipTypeDef *td); +PyObject *sip_api_convert_from_type(void *cppPtr, const sipTypeDef *td, + PyObject *transferObj); +void sip_api_common_dtor(sipSimpleWrapper *sipSelf); +void sip_api_start_thread(void); +void sip_api_end_thread(void); +void sip_api_free_sipslot(sipSlot *slot); +int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot); +PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs); +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); + + +/* + * These are not part of the SIP API but are used within the SIP module. + */ +void sipSaveMethod(sipPyMethod *pm,PyObject *meth); +void *sipGetPending(sipWrapper **op, int *fp); +PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td, + sipWrapper *owner, int initflags); +void *sipConvertRxEx(sipWrapper *txSelf, const char *sigargs, + PyObject *rxObj, const char *slot, const char **memberp, int flags); + +void sipOMInit(sipObjectMap *om); +void sipOMFinalise(sipObjectMap *om); +sipSimpleWrapper *sipOMFindObject(sipObjectMap *om, void *key, + const sipTypeDef *td); +void sipOMAddObject(sipObjectMap *om, sipSimpleWrapper *val); +int sipOMRemoveObject(sipObjectMap *om, sipSimpleWrapper *val); + +void sipSetBool(void *ptr,int val); + +void *sipGetAddress(sipSimpleWrapper *w); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/siplib/siplib.c b/siplib/siplib.c new file mode 100644 index 0000000..f419b6b --- /dev/null +++ b/siplib/siplib.c @@ -0,0 +1,10501 @@ +/* + * SIP library code. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <Python.h> + +#include <assert.h> +#include <stdio.h> +#include <stdarg.h> +#include <stddef.h> +#include <string.h> + +#include "sip.h" +#include "sipint.h" + + +/* There doesn't seem to be a standard way of checking for C99 support. */ +#if !defined(va_copy) +#define va_copy(d, s) ((d) = (s)) +#endif + + +/* + * The Python metatype for a C++ wrapper type. We inherit everything from the + * standard Python metatype except the init and getattro methods and the size + * of the type object created is increased to accomodate the extra information + * we associate with a wrapped type. + */ + +static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems); +static PyObject *sipWrapperType_getattro(PyObject *self, PyObject *name); +static int sipWrapperType_init(sipWrapperType *self, PyObject *args, + PyObject *kwds); +static int sipWrapperType_setattro(PyObject *self, PyObject *name, + PyObject *value); + +static PyTypeObject sipWrapperType_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.wrappertype", /* tp_name */ + sizeof (sipWrapperType), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* 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 */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + sipWrapperType_getattro, /* tp_getattro */ + sipWrapperType_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 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 */ + (initproc)sipWrapperType_init, /* tp_init */ + sipWrapperType_alloc, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + + +/* + * The Python type that is the super-type for all C++ wrapper types that + * support parent/child relationships. + */ + +static int sipWrapper_clear(sipWrapper *self); +static void sipWrapper_dealloc(sipWrapper *self); +static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg); + +static sipWrapperType sipWrapper_Type = { +#if !defined(STACKLESS) + { +#endif + { + PyVarObject_HEAD_INIT(&sipWrapperType_Type, 0) + "sip.wrapper", /* tp_name */ + sizeof (sipWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)sipWrapper_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 */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)sipWrapper_traverse, /* tp_traverse */ + (inquiry)sipWrapper_clear, /* 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 */ + }, +#if !defined(STACKLESS) + }, +#endif + 0, + 0 +}; + + +static void sip_api_bad_catcher_result(PyObject *method); +static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen, + SIP_SSIZE_T slicelen); +static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...); +static PyObject *sip_api_call_method(int *isErr, PyObject *method, + const char *fmt, ...); +static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx, + SIP_SSIZE_T len); +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 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, + const sipIntTypeClassMap *map, int maplen); +static sipWrapperType *sip_api_map_string_to_class(const char *typeString, + const sipStringTypeClassMap *map, int maplen); +static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, + const char *fmt, ...); +static void sip_api_trace(unsigned mask,const char *fmt,...); +static void sip_api_transfer_back(PyObject *self); +static void sip_api_transfer_to(PyObject *self, PyObject *owner); +static int sip_api_export_module(sipExportedModuleDef *client, + unsigned api_major, unsigned api_minor, void *unused); +static int sip_api_init_module(sipExportedModuleDef *client, + PyObject *mod_dict); +static int sip_api_parse_args(PyObject **parseErrp, PyObject *sipArgs, + const char *fmt, ...); +static int sip_api_parse_kwd_args(PyObject **parseErrp, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused, + const char *fmt, ...); +static int sip_api_parse_pair(PyObject **parseErrp, PyObject *sipArg0, + PyObject *sipArg1, const char *fmt, ...); +static void sip_api_no_function(PyObject *parseErr, const char *func, + const char *doc); +static void sip_api_no_method(PyObject *parseErr, const char *scope, + const char *method, const char *doc); +static void sip_api_abstract_method(const char *classname, const char *method); +static void sip_api_bad_class(const char *classname); +static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw); +static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper *sipSelf, const char *cname, const char *mname); +static void sip_api_call_hook(const char *hookname); +static void sip_api_raise_unknown_exception(void); +static void sip_api_raise_type_exception(const sipTypeDef *td, void *ptr); +static int sip_api_add_type_instance(PyObject *dict, const char *name, + void *cppPtr, const sipTypeDef *td); +static sipErrorState sip_api_bad_callable_arg(int arg_nr, PyObject *arg); +static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg, + sipPySlotType st); +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); +static sipWrapperType *sip_api_find_class(const char *type); +static const sipMappedType *sip_api_find_mapped_type(const char *type); +static PyTypeObject *sip_api_find_named_enum(const char *type); +static char sip_api_bytes_as_char(PyObject *obj); +static const char *sip_api_bytes_as_string(PyObject *obj); +static char sip_api_string_as_ascii_char(PyObject *obj); +static const char *sip_api_string_as_ascii_string(PyObject **obj); +static char sip_api_string_as_latin1_char(PyObject *obj); +static const char *sip_api_string_as_latin1_string(PyObject **obj); +static char sip_api_string_as_utf8_char(PyObject *obj); +static const char *sip_api_string_as_utf8_string(PyObject **obj); +#if defined(HAVE_WCHAR_H) +static wchar_t sip_api_unicode_as_wchar(PyObject *obj); +static wchar_t *sip_api_unicode_as_wstring(PyObject *obj); +#else +static int sip_api_unicode_as_wchar(PyObject *obj); +static int *sip_api_unicode_as_wstring(PyObject *obj); +#endif +static void sip_api_transfer_break(PyObject *self); +static int sip_api_deprecated(const char *classname, const char *method); +static int sip_api_register_py_type(PyTypeObject *supertype); +static PyObject *sip_api_convert_from_enum(int eval, const sipTypeDef *td); +static const sipTypeDef *sip_api_type_from_py_type_object(PyTypeObject *py_type); +static const sipTypeDef *sip_api_type_scope(const sipTypeDef *td); +static const char *sip_api_resolve_typedef(const char *name); +static int sip_api_register_attribute_getter(const sipTypeDef *td, + sipAttrGetterFunc getter); +static void sip_api_clear_any_slot_reference(sipSlot *slot); +static int sip_api_visit_slot(sipSlot *slot, visitproc visit, void *arg); +static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj); +static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp); + + +/* + * The data structure that represents the SIP API. + */ +static const sipAPIDef sip_api = { + /* This must be first. */ + sip_api_export_module, + /* + * The following are part of the public API. + */ + (PyTypeObject *)&sipSimpleWrapper_Type, + (PyTypeObject *)&sipWrapper_Type, + &sipWrapperType_Type, + &sipVoidPtr_Type, + + sip_api_bad_catcher_result, + sip_api_bad_length_for_slice, + sip_api_build_result, + sip_api_call_method, + sip_api_connect_rx, + sip_api_convert_from_sequence_index, + sip_api_can_convert_to_type, + sip_api_convert_to_type, + sip_api_force_convert_to_type, + sip_api_can_convert_to_enum, + sip_api_release_type, + sip_api_convert_from_type, + sip_api_convert_from_new_type, + sip_api_convert_from_enum, + sip_api_get_state, + sip_api_disconnect_rx, + sip_api_free, + sip_api_get_pyobject, + sip_api_malloc, + sip_api_parse_result, + sip_api_trace, + sip_api_transfer_back, + sip_api_transfer_to, + sip_api_transfer_break, + sip_api_long_as_unsigned_long, + sip_api_convert_from_void_ptr, + sip_api_convert_from_const_void_ptr, + sip_api_convert_from_void_ptr_and_size, + sip_api_convert_from_const_void_ptr_and_size, + sip_api_convert_to_void_ptr, + sip_api_export_symbol, + sip_api_import_symbol, + sip_api_find_type, + sip_api_register_py_type, + sip_api_type_from_py_type_object, + sip_api_type_scope, + sip_api_resolve_typedef, + sip_api_register_attribute_getter, + sip_api_is_api_enabled, + sip_api_bad_callable_arg, + /* + * The following are deprecated parts of the public API. + */ + sip_api_find_named_enum, + sip_api_find_mapped_type, + sip_api_find_class, + sip_api_map_int_to_class, + sip_api_map_string_to_class, + /* + * The following may be used by Qt support code but by no other handwritten + * code. + */ + sip_api_free_sipslot, + sip_api_same_slot, + sip_api_convert_rx, + sip_api_invoke_slot, + sip_api_save_slot, + sip_api_clear_any_slot_reference, + sip_api_visit_slot, + /* + * The following are not part of the public API. + */ + sip_api_init_module, + sip_api_parse_args, + sip_api_parse_pair, + sip_api_common_dtor, + sip_api_no_function, + sip_api_no_method, + sip_api_abstract_method, + sip_api_bad_class, + sip_api_get_cpp_ptr, + sip_api_get_complex_cpp_ptr, + sip_api_is_py_method, + sip_api_call_hook, + sip_api_start_thread, + sip_api_end_thread, + sip_api_raise_unknown_exception, + sip_api_raise_type_exception, + sip_api_add_type_instance, + sip_api_bad_operator_arg, + sip_api_pyslot_extend, + sip_api_add_delayed_dtor, + sip_api_bytes_as_char, + sip_api_bytes_as_string, + sip_api_string_as_ascii_char, + sip_api_string_as_ascii_string, + sip_api_string_as_latin1_char, + sip_api_string_as_latin1_string, + sip_api_string_as_utf8_char, + sip_api_string_as_utf8_string, + sip_api_unicode_as_wchar, + sip_api_unicode_as_wstring, + sip_api_deprecated, + sip_api_keep_reference, + sip_api_parse_kwd_args, + sip_api_add_exception +}; + + +#define AUTO_DOCSTRING '\1' /* Marks an auto class docstring. */ + + +/* + * These are the format flags supported by argument parsers. + */ +#define FMT_AP_DEREF 0x01 /* The pointer will be dereferenced. */ +#define FMT_AP_TRANSFER 0x02 /* Implement /Transfer/. */ +#define FMT_AP_TRANSFER_BACK 0x04 /* Implement /TransferBack/. */ +#define FMT_AP_NO_CONVERTORS 0x08 /* Suppress any convertors. */ +#define FMT_AP_TRANSFER_THIS 0x10 /* Support for /TransferThis/. */ + + +/* + * These are the format flags supported by result parsers. Deprecated values + * have a _DEPR suffix. + */ +#define FMT_RP_DEREF 0x01 /* The pointer will be dereferenced. */ +#define FMT_RP_FACTORY 0x02 /* /Factory/ or /TransferBack/. */ +#define FMT_RP_MAKE_COPY 0x04 /* Return a copy of the value. */ +#define FMT_RP_NO_STATE_DEPR 0x04 /* Don't return the C/C++ state. */ + + +/* + * The different reasons for failing to parse an overload. These include + * internal (i.e. non-user) errors. + */ +typedef enum { + Ok, Unbound, TooFew, TooMany, UnknownKeyword, Duplicate, WrongType, Raised, + KeywordNotString, Exception +} sipParseFailureReason; + + +/* + * The description of a failure to parse an overload because of a user error. + */ +typedef struct _sipParseFailure { + sipParseFailureReason reason; /* The reason for the failure. */ + const char *detail_str; /* The detail if a string. */ + PyObject *detail_obj; /* The detail if a Python object. */ + int arg_nr; /* The wrong positional argument. */ + const char *arg_name; /* The wrong keyword argument. */ +} sipParseFailure; + + +/* + * An entry in a linked list of name/symbol pairs. + */ +typedef struct _sipSymbol { + const char *name; /* The name. */ + void *symbol; /* The symbol. */ + struct _sipSymbol *next; /* The next in the list. */ +} sipSymbol; + + +/* + * An entry in a linked list of Python objects. + */ +typedef struct _sipPyObject { + PyObject *object; /* The Python object. */ + struct _sipPyObject *next; /* The next in the list. */ +} sipPyObject; + + +/* + * An entry in the linked list of attribute getters. + */ +typedef struct _sipAttrGetter { + PyTypeObject *type; /* The Python type being handled. */ + sipAttrGetterFunc getter; /* The getter. */ + struct _sipAttrGetter *next; /* The next in the list. */ +} sipAttrGetter; + + +/***************************************************************************** + * 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 + * the extra information we associate with a named enum type. + */ +static PyTypeObject sipEnumType_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.enumtype", /* tp_name */ + sizeof (sipEnumTypeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* 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 */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 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 */ + sipEnumType_alloc, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + + +sipQtAPI *sipQtSupport = NULL; +sipTypeDef *sipQObjectType; + + +/* + * Various strings as Python objects created as and when needed. + */ +static PyObject *licenseName = NULL; +static PyObject *licenseeName = NULL; +static PyObject *typeName = NULL; +static PyObject *timestampName = NULL; +static PyObject *signatureName = NULL; + +static sipObjectMap cppPyMap; /* The C/C++ to Python map. */ +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 *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 sipPyObject *sipRegisteredPyTypes = NULL; /* Registered Python types. */ +static PyInterpreterState *sipInterpreter = NULL; /* The interpreter. */ + + +static void addClassSlots(sipWrapperType *wt, 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 int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2, + sipPySlotType st); +static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1, + PyObject *arg2, sipPySlotType st); +static PyObject *buildObject(PyObject *tup, const char *fmt, va_list va); +static int parseKwdArgs(PyObject **parseErrp, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused, + const char *fmt, va_list va_orig); +static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, + int *selfargp, PyObject *sipArgs, PyObject *sipKwdArgs, + const char **kwdlist, PyObject **unused, const char *fmt, va_list va); +static int parsePass2(sipSimpleWrapper *self, int selfarg, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, const char *fmt, + va_list va); +static PyObject *signature_FromDocstring(const char *doc, SIP_SSIZE_T line); +static PyObject *detail_FromFailure(PyObject *failure_obj); +static int isQObject(PyObject *obj); +static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td); +static int convertFromSequence(PyObject *seq, const sipTypeDef *td, + void **array, SIP_SSIZE_T *nr_elem); +static PyObject *convertToSequence(void *array, SIP_SSIZE_T nr_elem, + const sipTypeDef *td); +static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr, + sipSimpleWrapper **selfp); +static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm); +static int compareTypedefName(const void *key, const void *el); +static int checkPointer(void *ptr); +static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type, + const sipTypeDef *dst_type); +static void finalise(void); +static PyObject *getDefaultBases(void); +static PyObject *getScopeDict(sipTypeDef *td, PyObject *mod_dict, + sipExportedModuleDef *client); +static PyObject *createContainerType(sipContainerDef *cod, sipTypeDef *td, + PyObject *bases, PyObject *metatype, PyObject *mod_dict, + sipExportedModuleDef *client); +static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd, + PyObject *mod_dict); +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 int setReduce(PyTypeObject *type, PyMethodDef *pickler); +static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd, + PyObject *mod_dict); +static PyObject *createTypeDict(PyObject *mname); +static sipExportedModuleDef *getTypeModule(const sipEncodedTypeDef *enc, + sipExportedModuleDef *em); +static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc, + sipExportedModuleDef *em); +static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr); +static void *getPtrTypeDef(sipSimpleWrapper *self, + const sipClassTypeDef **ctd); +static int addInstances(PyObject *dict, sipInstancesDef *id); +static int addVoidPtrInstances(PyObject *dict, sipVoidPtrInstanceDef *vi); +static int addCharInstances(PyObject *dict, sipCharInstanceDef *ci); +static int addStringInstances(PyObject *dict, sipStringInstanceDef *si); +static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii); +static int addLongInstances(PyObject *dict, sipLongInstanceDef *li); +static int addUnsignedLongInstances(PyObject *dict, + sipUnsignedLongInstanceDef *uli); +static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli); +static int addUnsignedLongLongInstances(PyObject *dict, + sipUnsignedLongLongInstanceDef *ulli); +static int addDoubleInstances(PyObject *dict, sipDoubleInstanceDef *di); +static int addTypeInstances(PyObject *dict, sipTypeInstanceDef *ti); +static int addSingleTypeInstance(PyObject *dict, const char *name, + void *cppPtr, const sipTypeDef *td, int initflags); +static int addLicense(PyObject *dict, sipLicenseDef *lc); +static PyObject *cast(PyObject *self, PyObject *args); +static PyObject *callDtor(PyObject *self, PyObject *args); +static PyObject *dumpWrapper(PyObject *self, PyObject *args); +static PyObject *isDeleted(PyObject *self, PyObject *args); +static PyObject *isPyOwned(PyObject *self, PyObject *args); +static PyObject *setDeleted(PyObject *self, PyObject *args); +static PyObject *setTraceMask(PyObject *self, PyObject *args); +static PyObject *wrapInstance(PyObject *self, PyObject *args); +static PyObject *unwrapInstance(PyObject *self, PyObject *args); +static PyObject *transferBack(PyObject *self, PyObject *args); +static PyObject *transferTo(PyObject *self, PyObject *args); +static void print_object(const char *label, PyObject *obj); +static void addToParent(sipWrapper *self, sipWrapper *owner); +static void removeFromParent(sipWrapper *self); +static void release(void *addr, const sipTypeDef *td, int state); +static void callPyDtor(sipSimpleWrapper *self); +static int parseBytes_AsCharArray(PyObject *obj, const char **ap, + SIP_SSIZE_T *aszp); +static int parseBytes_AsChar(PyObject *obj, char *ap); +static int parseBytes_AsString(PyObject *obj, const char **ap); +static int parseString_AsASCIIChar(PyObject *obj, char *ap); +static PyObject *parseString_AsASCIIString(PyObject *obj, const char **ap); +static int parseString_AsLatin1Char(PyObject *obj, char *ap); +static PyObject *parseString_AsLatin1String(PyObject *obj, const char **ap); +static int parseString_AsUTF8Char(PyObject *obj, char *ap); +static PyObject *parseString_AsUTF8String(PyObject *obj, const char **ap); +static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap); +static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj, + const char **ap); +#if defined(HAVE_WCHAR_H) +static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp); +static int convertToWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp); +static int parseWChar(PyObject *obj, wchar_t *ap); +static int convertToWChar(PyObject *obj, wchar_t *ap); +static int parseWCharString(PyObject *obj, wchar_t **ap); +static int convertToWCharString(PyObject *obj, wchar_t **ap); +#else +static void raiseNoWChar(); +#endif +static void *getComplexCppPtr(sipSimpleWrapper *w, const sipTypeDef *td); +static PyObject *findPyType(const char *name); +static int addPyObjectToList(sipPyObject **head, PyObject *object); +static PyObject *getDictFromObject(PyObject *obj); +static void forgetObject(sipSimpleWrapper *sw); +static int add_lazy_container_attrs(sipTypeDef *td, sipContainerDef *cod, + PyObject *dict); +static int add_lazy_attrs(sipTypeDef *td); +static int add_all_lazy_attrs(sipTypeDef *td); +static int objectify(const char *s, PyObject **objp); +static void add_failure(PyObject **parseErrp, sipParseFailure *failure); +static PyObject *bad_type_str(int arg_nr, PyObject *arg); + + +/* + * The Python module initialisation function. + */ +#if PY_MAJOR_VERSION >= 3 +#define SIP_MODULE_ENTRY PyInit_sip +#define SIP_MODULE_TYPE PyObject * +#define SIP_MODULE_DISCARD(m) Py_DECREF(m) +#define SIP_FATAL(s) return NULL +#define SIP_MODULE_RETURN(m) return (m) +#else +#define SIP_MODULE_ENTRY initsip +#define SIP_MODULE_TYPE void +#define SIP_MODULE_DISCARD(m) +#define SIP_FATAL(s) Py_FatalError(s) +#define SIP_MODULE_RETURN(m) +#endif + +#if defined(SIP_STATIC_MODULE) +SIP_MODULE_TYPE SIP_MODULE_ENTRY(void) +#else +PyMODINIT_FUNC SIP_MODULE_ENTRY(void) +#endif +{ + static PyMethodDef methods[] = { + {"cast", cast, METH_VARARGS, NULL}, + {"delete", callDtor, METH_VARARGS, NULL}, + {"dump", dumpWrapper, METH_VARARGS, NULL}, + {"getapi", sipGetAPI, METH_VARARGS, NULL}, + {"isdeleted", isDeleted, METH_VARARGS, NULL}, + {"ispyowned", isPyOwned, METH_VARARGS, NULL}, + {"setapi", sipSetAPI, METH_VARARGS, NULL}, + {"setdeleted", setDeleted, METH_VARARGS, NULL}, + {"settracemask", setTraceMask, METH_VARARGS, NULL}, + {"transferback", transferBack, METH_VARARGS, NULL}, + {"transferto", transferTo, METH_VARARGS, NULL}, + {"wrapinstance", wrapInstance, METH_VARARGS, NULL}, + {"unwrapinstance", unwrapInstance, METH_VARARGS, NULL}, + {"_unpickle_type", unpickle_type, METH_VARARGS, NULL}, + {"_unpickle_enum", unpickle_enum, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} + }; + +#if PY_MAJOR_VERSION >= 3 + static PyModuleDef module_def = { + PyModuleDef_HEAD_INIT, + "sip", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ + }; +#endif + + int rc; + PyObject *mod, *mod_dict, *obj; + +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + + /* Initialise the types. */ + sipWrapperType_Type.tp_base = &PyType_Type; + + if (PyType_Ready(&sipWrapperType_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.wrappertype type"); + + if (PyType_Ready((PyTypeObject *)&sipSimpleWrapper_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.simplewrapper type"); + + if (sip_api_register_py_type((PyTypeObject *)&sipSimpleWrapper_Type) < 0) + SIP_FATAL("sip: Failed to register sip.simplewrapper type"); + +#if defined(STACKLESS) + sipWrapper_Type.super.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; +#elif PY_VERSION_HEX >= 0x02050000 + sipWrapper_Type.super.ht_type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; +#else + sipWrapper_Type.super.type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; +#endif + + if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.wrapper type"); + + if (PyType_Ready(&sipMethodDescr_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.methoddescriptor type"); + + if (PyType_Ready(&sipVariableDescr_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.variabledescriptor type"); + + sipEnumType_Type.tp_base = &PyType_Type; + + if (PyType_Ready(&sipEnumType_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.enumtype type"); + + if (PyType_Ready(&sipVoidPtr_Type) < 0) + SIP_FATAL("sip: Failed to initialise sip.voidptr type"); + +#if PY_MAJOR_VERSION >= 3 + mod = PyModule_Create(&module_def); +#else + mod = Py_InitModule("sip", methods); +#endif + + if (mod == NULL) + SIP_FATAL("sip: Failed to intialise sip module"); + + mod_dict = PyModule_GetDict(mod); + + /* Get a reference to the pickle helpers. */ + type_unpickler = PyDict_GetItemString(mod_dict, "_unpickle_type"); + enum_unpickler = PyDict_GetItemString(mod_dict, "_unpickle_enum"); + + if (type_unpickler == NULL || enum_unpickler == NULL) + { + SIP_MODULE_DISCARD(mod); + SIP_FATAL("sip: Failed to get pickle helpers"); + } + + /* Publish the SIP API. */ +#if defined(SIP_USE_PYCAPSULE) + obj = PyCapsule_New((void *)&sip_api, "sip._C_API", NULL); +#else + obj = PyCObject_FromVoidPtr((void *)&sip_api, NULL); +#endif + + if (obj == NULL) + { + SIP_MODULE_DISCARD(mod); + SIP_FATAL("sip: Failed to create _C_API object"); + } + + rc = PyDict_SetItemString(mod_dict, "_C_API", obj); + Py_DECREF(obj); + + if (rc < 0) + { + SIP_MODULE_DISCARD(mod); + SIP_FATAL("sip: Failed to add _C_API object to module dictionary"); + } + + /* Add the SIP version number, but don't worry about errors. */ +#if PY_MAJOR_VERSION >= 3 + obj = PyLong_FromLong(SIP_VERSION); +#else + obj = PyInt_FromLong(SIP_VERSION); +#endif + + if (obj != NULL) + { + PyDict_SetItemString(mod_dict, "SIP_VERSION", obj); + Py_DECREF(obj); + } + +#if PY_MAJOR_VERSION >= 3 + obj = PyUnicode_FromString(SIP_VERSION_STR); +#else + obj = PyString_FromString(SIP_VERSION_STR); +#endif + + if (obj != NULL) + { + PyDict_SetItemString(mod_dict, "SIP_VERSION_STR", obj); + Py_DECREF(obj); + } + + /* Add the type objects, but don't worry about errors. */ + PyDict_SetItemString(mod_dict, "wrappertype", + (PyObject *)&sipWrapperType_Type); + PyDict_SetItemString(mod_dict, "simplewrapper", + (PyObject *)&sipSimpleWrapper_Type); + PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type); + PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type); + + /* Initialise the module if it hasn't already been done. */ + if (sipInterpreter == NULL) + { + Py_AtExit(finalise); + + /* Initialise the object map. */ + sipOMInit(&cppPyMap); + + sipQtSupport = NULL; + + /* + * Get the current interpreter. This will be shared between all + * threads. + */ + sipInterpreter = PyThreadState_Get()->interp; + } + + SIP_MODULE_RETURN(mod); +} + + +/* + * Display a printf() style message to stderr according to the current trace + * mask. + */ +static void sip_api_trace(unsigned mask, const char *fmt, ...) +{ + va_list ap; + + va_start(ap,fmt); + + if (mask & traceMask) + vfprintf(stderr, fmt, ap); + + va_end(ap); +} + + +/* + * Set the trace mask. + */ +static PyObject *setTraceMask(PyObject *self, PyObject *args) +{ + unsigned new_mask; + + if (PyArg_ParseTuple(args, "I:settracemask", &new_mask)) + { + traceMask = new_mask; + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Dump various bits of potentially useful information to stdout. + */ +static PyObject *dumpWrapper(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + + if (PyArg_ParseTuple(args, "O!:dump", &sipSimpleWrapper_Type, &sw)) + { + print_object(NULL, (PyObject *)sw); + +#if PY_VERSION_HEX >= 0x02050000 + printf(" Reference count: %" PY_FORMAT_SIZE_T "d\n", Py_REFCNT(sw)); +#else + printf(" Reference count: %d\n", Py_REFCNT(sw)); +#endif + printf(" Address of wrapped object: %p\n", sipGetAddress(sw)); + printf(" To be destroyed by: %s\n", (sipIsPyOwned(sw) ? "Python" : "C/C++")); + printf(" Derived class?: %s\n", (sipIsDerived(sw) ? "yes" : "no")); + + if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type)) + { + sipWrapper *w = (sipWrapper *)sw; + + print_object("Parent wrapper", (PyObject *)w->parent); + print_object("Next sibling wrapper", (PyObject *)w->sibling_next); + print_object("Previous sibling wrapper", + (PyObject *)w->sibling_prev); + print_object("First child wrapper", (PyObject *)w->first_child); + } + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Write a reference to a wrapper to stdout. + */ +static void print_object(const char *label, PyObject *obj) +{ + if (label != NULL) + printf(" %s: ", label); + + if (obj != NULL) + PyObject_Print(obj, stdout, 0); + else + printf("NULL"); + + printf("\n"); +} + + +/* + * Transfer the ownership of an instance to C/C++. + */ +static PyObject *transferTo(PyObject *self, PyObject *args) +{ + PyObject *w, *owner; + + if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner)) + { + if (owner == Py_None) + owner = NULL; + else if (PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type)) + { + PyErr_Format(PyExc_TypeError, "transferto() argument 2 must be sip.wrapper, not %s", Py_TYPE(owner)->tp_name); + return NULL; + } + + sip_api_transfer_to(w, owner); + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Transfer the ownership of an instance to Python. + */ +static PyObject *transferBack(PyObject *self, PyObject *args) +{ + PyObject *w; + + if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w)) + { + sip_api_transfer_back(w); + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Cast an instance to one of it's sub or super-classes by returning a new + * Python object with the superclass type wrapping the same C++ instance. + */ +static PyObject *cast(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + sipWrapperType *wt; + const sipTypeDef *td; + void *addr; + PyTypeObject *ft, *tt; + + if (!PyArg_ParseTuple(args, "O!O!:cast", &sipSimpleWrapper_Type, &sw, &sipWrapperType_Type, &wt)) + return NULL; + + ft = Py_TYPE(sw); + tt = (PyTypeObject *)wt; + + if (ft == tt || PyType_IsSubtype(tt, ft)) + td = NULL; + else if (PyType_IsSubtype(ft, tt)) + td = wt->type; + else + { + PyErr_SetString(PyExc_TypeError, "argument 1 of sip.cast() must be an instance of a sub or super-type of argument 2"); + return NULL; + } + + if ((addr = sip_api_get_cpp_ptr(sw, td)) == NULL) + return NULL; + + /* + * 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); +} + + +/* + * Call an instance's dtor. + */ +static PyObject *callDtor(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + void *addr; + const sipClassTypeDef *ctd; + + if (!PyArg_ParseTuple(args, "O!:delete", &sipSimpleWrapper_Type, &sw)) + return NULL; + + addr = getPtrTypeDef(sw, &ctd); + + if (checkPointer(addr) < 0) + return NULL; + + if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type)) + { + /* + * Transfer ownership to C++ so we don't try to release it again when + * the Python object is garbage collected. + */ + removeFromParent((sipWrapper *)sw); + sipResetPyOwned(sw); + } + + release(addr, (const sipTypeDef *)ctd, sw->flags); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Check if an instance still exists without raising an exception. + */ +static PyObject *isDeleted(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + PyObject *res; + + if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipSimpleWrapper_Type, &sw)) + return NULL; + + res = (sipGetAddress(sw) == NULL ? Py_True : Py_False); + + Py_INCREF(res); + return res; +} + + +/* + * Check if an instance is owned by Python or C/C++. + */ +static PyObject *isPyOwned(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + PyObject *res; + + if (!PyArg_ParseTuple(args, "O!:ispyowned", &sipSimpleWrapper_Type, &sw)) + return NULL; + + res = (sipIsPyOwned(sw) ? Py_True : Py_False); + + Py_INCREF(res); + return res; +} + + +/* + * Mark an instance as having been deleted. + */ +static PyObject *setDeleted(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + + if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipSimpleWrapper_Type, &sw)) + return NULL; + + if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type)) + { + /* + * Transfer ownership to C++ so we don't try to release it when the + * Python object is garbage collected. + */ + removeFromParent((sipWrapper *)sw); + sipResetPyOwned(sw); + } + + sw->u.cppPtr = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Unwrap an instance. + */ +static PyObject *unwrapInstance(PyObject *self, PyObject *args) +{ + sipSimpleWrapper *sw; + + if (PyArg_ParseTuple(args, "O!:unwrapinstance", &sipSimpleWrapper_Type, &sw)) + { + void *addr; + + /* + * We just get the pointer but don't try and cast it (which isn't + * needed and wouldn't work with the way casts are currently + * implemented if we are unwrapping something derived from a wrapped + * class). + */ + if ((addr = sip_api_get_cpp_ptr(sw, NULL)) == NULL) + return NULL; + + return PyLong_FromVoidPtr(addr); + } + + return NULL; +} + + +/* + * Wrap an instance. + */ +static PyObject *wrapInstance(PyObject *self, PyObject *args) +{ + unsigned long addr; + sipWrapperType *wt; + + if (PyArg_ParseTuple(args, "kO!:wrapinstance", &addr, &sipWrapperType_Type, &wt)) + return sip_api_convert_from_type((void *)addr, wt->type, NULL); + + return NULL; +} + + +/* + * Register a client module. A negative value is returned and an exception + * raised if there was an error. + */ +static int sip_api_export_module(sipExportedModuleDef *client, + unsigned api_major, unsigned api_minor, void *unused) +{ + sipExportedModuleDef *em; + const char *full_name = sipNameOfModule(client); + + /* Check that we can support it. */ + + if (api_major != SIP_API_MAJOR_NR || api_minor > SIP_API_MINOR_NR) + { +#if SIP_API_MINOR_NR > 0 + PyErr_Format(PyExc_RuntimeError, + "the sip module implements API v%d.0 to v%d.%d but the %s module requires API v%d.%d", + SIP_API_MAJOR_NR, SIP_API_MAJOR_NR, SIP_API_MINOR_NR, + full_name, api_major, api_minor); +#else + PyErr_Format(PyExc_RuntimeError, + "the sip module implements API v%d.0 but the %s module requires API v%d.%d", + SIP_API_MAJOR_NR, full_name, api_major, api_minor); +#endif + + return -1; + } + + /* Import any required modules. */ + if (client->em_imports != NULL) + { + sipImportedModuleDef *im = client->em_imports; + + while (im->im_name != NULL) + { + PyObject *mod; + + if ((mod = PyImport_ImportModule(im->im_name)) == NULL) + return -1; + + for (em = moduleList; em != NULL; em = em->em_next) + if (strcmp(sipNameOfModule(em), im->im_name) == 0) + break; + + if (em == NULL) + { + PyErr_Format(PyExc_RuntimeError, + "the %s module failed to register with the sip module", + im->im_name); + + return -1; + } + + /* Check the versions are compatible. */ + if (im->im_version >= 0 || em->em_version >= 0) + if (im->im_version != em->em_version) + { + PyErr_Format(PyExc_RuntimeError, + "the %s module is version %d but the %s module requires version %d", + sipNameOfModule(em), em->em_version, full_name, + im->im_version); + + return -1; + } + + /* Save the imported module. */ + im->im_module = em; + + ++im; + } + } + + for (em = moduleList; em != NULL; em = em->em_next) + { + /* SIP clients must have unique names. */ + if (strcmp(sipNameOfModule(em), full_name) == 0) + { + PyErr_Format(PyExc_RuntimeError, + "the sip module has already registered a module called %s", + full_name); + + return -1; + } + + /* Only one module can claim to wrap QObject. */ + if (em->em_qt_api != NULL && client->em_qt_api != NULL) + { + PyErr_Format(PyExc_RuntimeError, + "the %s and %s modules both wrap the QObject class", + full_name, sipNameOfModule(em)); + + return -1; + } + } + + /* Convert the module name to an object. */ +#if PY_MAJOR_VERSION >= 3 + client->em_nameobj = PyUnicode_FromString(full_name); +#else + client->em_nameobj = PyString_FromString(full_name); +#endif + + if (client->em_nameobj == NULL) + return -1; + + /* Add it to the list of client modules. */ + client->em_next = moduleList; + moduleList = client; + + return 0; +} + + +/* + * Initialise the contents of a client module. By this time anything that + * this depends on should have been initialised. A negative value is returned + * and an exception raised if there was an error. + */ +static int sip_api_init_module(sipExportedModuleDef *client, + PyObject *mod_dict) +{ + sipExportedModuleDef *em; + sipEnumMemberDef *emd; + int i; + + /* Handle any API. */ + if (sipInitAPI(client, mod_dict) < 0) + return -1; + + /* Create the module's types. */ + for (i = 0; i < client->em_nrtypes; ++i) + { + sipTypeDef *td = client->em_types[i]; + + /* Skip external classes. */ + if (td == NULL) + continue; + + /* Skip if already initialised. */ + if (td->td_module != NULL) + continue; + + /* If it is a stub then just set the module so we can get its name. */ + if (sipTypeIsStub(td)) + { + td->td_module = client; + continue; + } + + if (sipTypeIsEnum(td)) + { + sipEnumTypeDef *etd = (sipEnumTypeDef *)td; + + if (td->td_version < 0 || sipIsRangeEnabled(client, td->td_version)) + if (createEnumType(client, etd, mod_dict) < 0) + return -1; + + /* + * Register the enum pickler for scoped enums (unscoped, ie. those + * not nested, don't need special treatment). + */ + if (etd->etd_scope >= 0) + { + static PyMethodDef md = { + "_pickle_enum", pickle_enum, METH_NOARGS, NULL + }; + + if (setReduce(sipTypeAsPyTypeObject(td), &md) < 0) + return -1; + } + } + else if (sipTypeIsMapped(td)) + { + sipMappedTypeDef *mtd = (sipMappedTypeDef *)td; + + /* If there is a name then we need a namespace. */ + if (mtd->mtd_container.cod_name >= 0) + { + if (createMappedType(client, mtd, mod_dict) < 0) + return -1; + } + else + { + td->td_module = client; + } + } + else + { + sipClassTypeDef *ctd = (sipClassTypeDef *)td; + + /* See if this is a namespace extender. */ + if (ctd->ctd_container.cod_name < 0) + { + sipTypeDef *real_nspace; + sipClassTypeDef **last; + + ctd->ctd_base.td_module = client; + + real_nspace = getGeneratedType(&ctd->ctd_container.cod_scope, + client); + + /* Append this type to the real one. */ + last = &((sipClassTypeDef *)real_nspace)->ctd_nsextender; + + while (*last != NULL) + last = &(*last)->ctd_nsextender; + + *last = ctd; + + /* + * Save the real namespace type so that it is the correct scope + * for any enums or classes defined in this module. + */ + client->em_types[i] = real_nspace; + } + else if (createClassType(client, ctd, mod_dict) < 0) + return -1; + } + } + + /* Set any Qt support API. */ + if (client->em_qt_api != NULL) + { + sipQtSupport = client->em_qt_api; + sipQObjectType = *sipQtSupport->qt_qobject; + } + + /* Append any initialiser extenders to the relevant classes. */ + if (client->em_initextend != NULL) + { + sipInitExtenderDef *ie = client->em_initextend; + + while (ie->ie_extender != NULL) + { + sipTypeDef *td = getGeneratedType(&ie->ie_class, client); + int enabled; + + if (ie->ie_api_range < 0) + enabled = TRUE; + else + enabled = sipIsRangeEnabled(td->td_module, ie->ie_api_range); + + if (enabled) + { + sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td); + + ie->ie_next = wt->iextend; + wt->iextend = ie; + } + + ++ie; + } + } + + /* Set the base class object for any sub-class convertors. */ + if (client->em_convertors != NULL) + { + sipSubClassConvertorDef *scc = client->em_convertors; + + while (scc->scc_convertor != NULL) + { + scc->scc_basetype = getGeneratedType(&scc->scc_base, client); + + ++scc; + } + } + + /* Create the module's enum members. */ + for (emd = client->em_enummembers, i = 0; i < client->em_nrenummembers; ++i, ++emd) + { + PyObject *mo; + + if ((mo = sip_api_convert_from_enum(emd->em_val, client->em_types[emd->em_enum])) == NULL) + return -1; + + if (PyDict_SetItemString(mod_dict, emd->em_name, mo) < 0) + return -1; + + Py_DECREF(mo); + } + + + /* + * Add any class static instances. We need to do this once all types are + * fully formed because of potential interdependencies. + */ + for (i = 0; i < client->em_nrtypes; ++i) + { + sipTypeDef *td = client->em_types[i]; + + if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td)) + if (addInstances((sipTypeAsPyTypeObject(td))->tp_dict, &((sipClassTypeDef *)td)->ctd_container.cod_instances) < 0) + return -1; + } + + /* Add any global static instances. */ + if (addInstances(mod_dict, &client->em_instances) < 0) + return -1; + + /* Add any license. */ + if (client->em_license != NULL && addLicense(mod_dict, client->em_license) < 0) + return -1; + + /* See if the new module satisfies any outstanding external types. */ + for (em = moduleList; em != NULL; em = em->em_next) + { + sipExternalTypeDef *etd; + + if (em == client || em->em_external == NULL) + continue; + + for (etd = em->em_external; etd->et_nr >= 0; ++etd) + { + if (etd->et_name == NULL) + continue; + + for (i = 0; i < client->em_nrtypes; ++i) + { + sipTypeDef *td = client->em_types[i]; + + if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td)) + { + const char *pyname = sipPyNameOfContainer( + &((sipClassTypeDef *)td)->ctd_container, td); + + if (strcmp(etd->et_name, pyname) == 0) + { + em->em_types[etd->et_nr] = td; + etd->et_name = NULL; + + break; + } + } + } + } + } + + return 0; +} + + +/* + * Called by the interpreter to do any final clearing up, just in case the + * interpreter will re-start. + */ +static void finalise(void) +{ + sipExportedModuleDef *em; + + /* Mark the Python API as unavailable. */ + sipInterpreter = NULL; + + /* Handle any delayed dtors. */ + for (em = moduleList; em != NULL; em = em->em_next) + if (em->em_ddlist != NULL) + { + em->em_delayeddtors(em->em_ddlist); + + /* Free the list. */ + do + { + sipDelayedDtor *dd = em->em_ddlist; + + em->em_ddlist = dd->dd_next; + sip_api_free(dd); + } + while (em->em_ddlist != NULL); + } + + licenseName = NULL; + licenseeName = NULL; + typeName = NULL; + timestampName = NULL; + signatureName = NULL; + + /* Release all memory we've allocated directly. */ + sipOMFinalise(&cppPyMap); + + /* Re-initialise those globals that (might) need it. */ + moduleList = NULL; +} + + +/* + * Register the given Python type. + */ +static int sip_api_register_py_type(PyTypeObject *type) +{ + return addPyObjectToList(&sipRegisteredPyTypes, (PyObject *)type); +} + + +/* + * Find the registered type with the given name. Raise an exception if it + * couldn't be found. + */ +static PyObject *findPyType(const char *name) +{ + sipPyObject *po; + + for (po = sipRegisteredPyTypes; po != NULL; po = po->next) + { + PyObject *type = po->object; + + if (strcmp(((PyTypeObject *)type)->tp_name, name) == 0) + return type; + } + + PyErr_Format(PyExc_RuntimeError, "%s is not a registered type", name); + + return NULL; +} + + +/* + * Add a wrapped C/C++ pointer to the list of delayed dtors. + */ +static void sip_api_add_delayed_dtor(sipSimpleWrapper *sw) +{ + void *ptr; + const sipClassTypeDef *ctd; + sipExportedModuleDef *em; + + if ((ptr = getPtrTypeDef(sw, &ctd)) == NULL) + return; + + /* Find the defining module. */ + for (em = moduleList; em != NULL; em = em->em_next) + { + int i; + + for (i = 0; i < em->em_nrtypes; ++i) + if (em->em_types[i] == (const sipTypeDef *)ctd) + { + sipDelayedDtor *dd; + + if ((dd = sip_api_malloc(sizeof (sipDelayedDtor))) == NULL) + return; + + /* Add to the list. */ + dd->dd_ptr = ptr; + dd->dd_name = sipPyNameOfContainer(&ctd->ctd_container, + (sipTypeDef *)ctd); + dd->dd_isderived = sipIsDerived(sw); + dd->dd_next = em->em_ddlist; + + em->em_ddlist = dd; + + return; + } + } +} + + +/* + * A wrapper around the Python memory allocater that will raise an exception if + * if the allocation fails. + */ +void *sip_api_malloc(size_t nbytes) +{ + void *mem; + + if ((mem = PyMem_Malloc(nbytes)) == NULL) + PyErr_NoMemory(); + + return mem; +} + + +/* + * A wrapper around the Python memory de-allocater. + */ +void sip_api_free(void *mem) +{ + PyMem_Free(mem); +} + + +/* + * Extend a Python slot by looking in other modules to see if there is an + * extender function that can handle the arguments. + */ +static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, + sipPySlotType st, const sipTypeDef *td, PyObject *arg0, + PyObject *arg1) +{ + sipExportedModuleDef *em; + + /* Go through each module. */ + for (em = moduleList; em != NULL; em = em->em_next) + { + sipPySlotExtenderDef *ex; + + /* Skip the module that couldn't handle the arguments. */ + if (em == mod) + continue; + + /* Skip if the module doesn't have any extenders. */ + if (em->em_slotextend == NULL) + continue; + + /* Go through each extender. */ + for (ex = em->em_slotextend; ex->pse_func != NULL; ++ex) + { + PyObject *res; + + /* Skip if not the right slot type. */ + if (ex->pse_type != st) + continue; + + /* Check against the type if one was given. */ + if (td != NULL && td != getGeneratedType(&ex->pse_class, NULL)) + continue; + + PyErr_Clear(); + + res = ((binaryfunc)ex->pse_func)(arg0, arg1); + + if (res != Py_NotImplemented) + return res; + } + } + + /* The arguments couldn't handled anywhere. */ + PyErr_Clear(); + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +/* + * Call the Python re-implementation of a C++ virtual. + */ +static PyObject *sip_api_call_method(int *isErr, PyObject *method, + 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 = PyEval_CallObject(method,args); + else + { + res = NULL; + + if (isErr != NULL) + *isErr = TRUE; + } + + Py_XDECREF(args); + + va_end(va); + + return res; +} + + +/* + * Build a result object based on a format string. + */ +static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...) +{ + PyObject *res = NULL; + int badfmt, tupsz; + va_list va; + + va_start(va,fmt); + + /* Basic validation of the format string. */ + + badfmt = FALSE; + + if (*fmt == '(') + { + char *ep; + + if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0') + badfmt = TRUE; + else + tupsz = ep - fmt - 1; + } + else if (strlen(fmt) == 1) + tupsz = -1; + else + badfmt = TRUE; + + if (badfmt) + PyErr_Format(PyExc_SystemError,"sipBuildResult(): invalid format string \"%s\"",fmt); + else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL) + res = buildObject(res,fmt,va); + + va_end(va); + + if (res == NULL && isErr != NULL) + *isErr = TRUE; + + return res; +} + + +/* + * Get the values off the stack and put them into an object. + */ +static PyObject *buildObject(PyObject *obj, const char *fmt, va_list va) +{ + char ch, termch; + int i; + + /* + * The format string has already been checked that it is properly formed if + * it is enclosed in parenthesis. + */ + if (*fmt == '(') + { + termch = ')'; + ++fmt; + } + else + termch = '\0'; + + i = 0; + + while ((ch = *fmt++) != termch) + { + PyObject *el; + + switch (ch) + { + case 'g': + { + char *s; + SIP_SSIZE_T l; + + s = va_arg(va, char *); + l = va_arg(va, SIP_SSIZE_T); + + if (s != NULL) + { + el = SIPBytes_FromStringAndSize(s, l); + } + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } + + break; + + case 'G': +#if defined(HAVE_WCHAR_H) + { + wchar_t *s; + SIP_SSIZE_T l; + + s = va_arg(va, wchar_t *); + l = va_arg(va, SIP_SSIZE_T); + + if (s != NULL) + el = PyUnicode_FromWideChar(s, l); + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } +#else + raiseNoWChar(); + el = NULL; +#endif + + break; + + case 'b': + el = PyBool_FromLong(va_arg(va,int)); + break; + + case 'c': + { + char c = va_arg(va, int); + + el = SIPBytes_FromStringAndSize(&c, 1); + } + + break; + + case 'a': + { + char c = va_arg(va, int); + +#if PY_MAJOR_VERSION >= 3 + el = PyUnicode_FromStringAndSize(&c, 1); +#else + el = PyString_FromStringAndSize(&c, 1); +#endif + } + + break; + + case 'w': +#if defined(HAVE_WCHAR_H) + { + wchar_t c = va_arg(va, int); + + el = PyUnicode_FromWideChar(&c, 1); + } +#else + raiseNoWChar(); + el = NULL; +#endif + + break; + + case 'E': + { + /* This is deprecated. */ + + int ev = va_arg(va, int); + PyTypeObject *et = va_arg(va, PyTypeObject *); + + el = sip_api_convert_from_enum(ev, + ((const sipEnumTypeObject *)et)->type); + } + + break; + + case 'F': + { + int ev = va_arg(va, int); + const sipTypeDef *td = va_arg(va, const sipTypeDef *); + + el = sip_api_convert_from_enum(ev, td); + } + + break; + + case 'd': + case 'f': + el = PyFloat_FromDouble(va_arg(va,double)); + break; + + case 'e': + case 'h': + case 'i': +#if PY_MAJOR_VERSION >= 3 + el = PyLong_FromLong(va_arg(va, int)); +#else + el = PyInt_FromLong(va_arg(va, int)); +#endif + break; + + case 'l': + el = PyLong_FromLong(va_arg(va, long)); + break; + + case 'm': + el = PyLong_FromUnsignedLong(va_arg(va, unsigned long)); + break; + + case 'n': +#if defined(HAVE_LONG_LONG) + el = PyLong_FromLongLong(va_arg(va, PY_LONG_LONG)); +#else + el = PyLong_FromLong(va_arg(va, long)); +#endif + break; + + case 'o': +#if defined(HAVE_LONG_LONG) + el = PyLong_FromUnsignedLongLong(va_arg(va, unsigned PY_LONG_LONG)); +#else + el = PyLong_FromUnsignedLong(va_arg(va, unsigned long)); +#endif + break; + + case 's': + { + char *s = va_arg(va, char *); + + if (s != NULL) + { + el = SIPBytes_FromString(s); + } + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } + + break; + + case 'A': + { + char *s = va_arg(va, char *); + + if (s != NULL) +#if PY_MAJOR_VERSION >= 3 + el = PyUnicode_FromString(s); +#else + el = PyString_FromString(s); +#endif + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } + + break; + + case 'x': +#if defined(HAVE_WCHAR_H) + { + wchar_t *s = va_arg(va, wchar_t *); + + if (s != NULL) + el = PyUnicode_FromWideChar(s, (SIP_SSIZE_T)wcslen(s)); + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } +#else + raiseNoWChar(); + el = NULL; +#endif + + break; + + case 't': + case 'u': + el = PyLong_FromUnsignedLong(va_arg(va, unsigned)); + break; + + case 'B': + { + /* This is deprecated. */ + + void *p = va_arg(va,void *); + sipWrapperType *wt = va_arg(va, sipWrapperType *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_new_type(p, wt->type, xfer); + } + + break; + + case 'N': + { + void *p = va_arg(va, void *); + const sipTypeDef *td = va_arg(va, const sipTypeDef *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_new_type(p, td, xfer); + } + + break; + + case 'C': + { + /* This is deprecated. */ + + void *p = va_arg(va,void *); + sipWrapperType *wt = va_arg(va, sipWrapperType *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_type(p, wt->type, xfer); + } + + break; + + case 'D': + { + void *p = va_arg(va, void *); + const sipTypeDef *td = va_arg(va, const sipTypeDef *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_type(p, td, xfer); + } + + break; + + case 'r': + { + void *p = va_arg(va, void *); + SIP_SSIZE_T l = va_arg(va, SIP_SSIZE_T); + const sipTypeDef *td = va_arg(va, const sipTypeDef *); + + el = convertToSequence(p, l, td); + } + + break; + + case 'R': + el = va_arg(va,PyObject *); + break; + + case 'S': + el = va_arg(va,PyObject *); + Py_INCREF(el); + break; + + case 'V': + el = sip_api_convert_from_void_ptr(va_arg(va, void *)); + break; + + default: + PyErr_Format(PyExc_SystemError,"buildObject(): invalid format character '%c'",ch); + el = NULL; + } + + if (el == NULL) + { + Py_XDECREF(obj); + return NULL; + } + + if (obj == NULL) + return el; + + PyTuple_SET_ITEM(obj,i,el); + ++i; + } + + return obj; +} + + +/* + * Parse a result object based on a format string. + */ +static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, + const char *fmt, ...) +{ + int tupsz, rc = 0; + sipSimpleWrapper *self = NULL; + va_list va; + + va_start(va,fmt); + + /* Get self if it is provided. */ + if (*fmt == 'S') + { + self = va_arg(va, sipSimpleWrapper *); + ++fmt; + } + + /* Basic validation of the format string. */ + if (*fmt == '(') + { + char ch; + const char *cp = ++fmt; + + tupsz = 0; + + while ((ch = *cp++) != ')') + { + if (ch == '\0') + { + PyErr_Format(PyExc_SystemError, "sipParseResult(): invalid format string \"%s\"", fmt - 1); + rc = -1; + + break; + } + + /* + * Some format characters have a sub-format so skip the character + * and count the sub-format character next time round. + */ + if (strchr("HDC", ch) == NULL) + ++tupsz; + } + + if (rc == 0) + if (!PyTuple_Check(res) || PyTuple_GET_SIZE(res) != tupsz) + { + sip_api_bad_catcher_result(method); + rc = -1; + } + } + else + tupsz = -1; + + if (rc == 0) + { + char ch; + int i = 0; + + while ((ch = *fmt++) != '\0' && ch != ')' && rc == 0) + { + PyObject *arg; + int invalid = FALSE; + + if (tupsz > 0) + { + arg = PyTuple_GET_ITEM(res,i); + ++i; + } + else + arg = res; + + switch (ch) + { + case 'g': + { + const char **p = va_arg(va, const char **); + SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *); + + if (parseBytes_AsCharArray(arg, p, szp) < 0) + invalid = TRUE; + } + + break; + + case 'G': +#if defined(HAVE_WCHAR_H) + { + wchar_t **p = va_arg(va, wchar_t **); + SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *); + + if (parseWCharArray(arg, p, szp) < 0) + invalid = TRUE; + } +#else + raiseNoWChar(); + invalid = TRUE; +#endif + + break; + + case 'b': + { + int v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + sipSetBool(va_arg(va, void *), v); + } + + break; + + case 'c': + { + char *p = va_arg(va, char *); + + if (parseBytes_AsChar(arg, p) < 0) + invalid = TRUE; + } + + break; + + case 'a': + { + char *p = va_arg(va, char *); + int enc; + + switch (*fmt++) + { + case 'A': + enc = parseString_AsASCIIChar(arg, p); + break; + + case 'L': + enc = parseString_AsLatin1Char(arg, p); + break; + + case '8': + enc = parseString_AsUTF8Char(arg, p); + break; + + default: + enc = -1; + } + + if (enc < 0) + invalid = TRUE; + } + + break; + + case 'w': +#if defined(HAVE_WCHAR_H) + { + wchar_t *p = va_arg(va, wchar_t *); + + if (parseWChar(arg, p) < 0) + invalid = TRUE; + } +#else + raiseNoWChar(); + invalid = TRUE; +#endif + + break; + + case 'd': + { + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,double *) = v; + } + + break; + + case 'E': + { + /* This is deprecated. */ + + PyTypeObject *et = va_arg(va, PyTypeObject *); + int *p = va_arg(va, int *); + + if (sip_api_can_convert_to_enum(arg, ((sipEnumTypeObject *)et)->type)) + *p = SIPLong_AsLong(arg); + else + invalid = TRUE; + } + + break; + + case 'F': + { + sipTypeDef *td = va_arg(va, sipTypeDef *); + int *p = va_arg(va, int *); + + if (sip_api_can_convert_to_enum(arg, td)) + *p = SIPLong_AsLong(arg); + else + invalid = TRUE; + } + + break; + + case 'f': + { + float v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,float *) = v; + } + + break; + + case 'h': + { + short v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va, short *) = v; + } + + break; + + case 't': + { + unsigned short v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,unsigned short *) = v; + } + + break; + + case 'e': + case 'i': + { + int v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va, int *) = v; + } + + break; + + case 'u': + { + unsigned v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,unsigned *) = v; + } + + break; + + case 'l': + { + long v = PyLong_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,long *) = v; + } + + break; + + case 'm': + { + unsigned long v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va, unsigned long *) = v; + } + + break; + + case 'n': + { +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG v = PyLong_AsLongLong(arg); +#else + 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 + } + + break; + + case 'o': + { +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg); +#else + unsigned long v = PyLong_AsUnsignedLong(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 + } + + break; + + case 's': + { + /* This is deprecated. */ + + const char **p = va_arg(va, const char **); + + if (parseBytes_AsString(arg, p) < 0) + invalid = TRUE; + } + + break; + + case 'A': + { + int key = va_arg(va, int); + const char **p = va_arg(va, const char **); + PyObject *keep; + + switch (*fmt++) + { + case 'A': + keep = parseString_AsASCIIString(arg, p); + break; + + case 'L': + keep = parseString_AsLatin1String(arg, p); + break; + + case '8': + keep = parseString_AsUTF8String(arg, p); + break; + + default: + keep = NULL; + } + + if (keep == NULL) + invalid = TRUE; + else + sip_api_keep_reference((PyObject *)self, key, keep); + } + + break; + + case 'B': + { + int key = va_arg(va, int); + const char **p = va_arg(va, const char **); + + if (parseBytes_AsString(arg, p) < 0) + invalid = TRUE; + else + { + Py_INCREF(arg); + sip_api_keep_reference((PyObject *)self, key, arg); + } + } + + break; + + case 'x': +#if defined(HAVE_WCHAR_H) + { + wchar_t **p = va_arg(va, wchar_t **); + + if (parseWCharString(arg, p) < 0) + invalid = TRUE; + } +#else + raiseNoWChar(); + invalid = TRUE; +#endif + + break; + + case 'C': + { + /* This is deprecated. */ + + if (*fmt == '\0') + invalid = TRUE; + else + { + int flags = *fmt++ - '0'; + int iserr = FALSE; + sipWrapperType *type; + void **cpp; + int *state; + + type = va_arg(va, sipWrapperType *); + + if (flags & FMT_RP_NO_STATE_DEPR) + state = NULL; + else + state = va_arg(va, int *); + + cpp = va_arg(va, void **); + + *cpp = sip_api_force_convert_to_type(arg, type->type, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr); + + if (iserr) + invalid = TRUE; + } + } + + break; + + case 'D': + { + /* This is deprecated. */ + + if (*fmt == '\0') + invalid = TRUE; + else + { + int flags = *fmt++ - '0'; + int iserr = FALSE; + const sipTypeDef *td; + void **cpp; + int *state; + + td = va_arg(va, const sipTypeDef *); + + if (flags & FMT_RP_NO_STATE_DEPR) + state = NULL; + else + state = va_arg(va, int *); + + cpp = va_arg(va, void **); + + *cpp = sip_api_force_convert_to_type(arg, td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr); + + if (iserr) + invalid = TRUE; + } + } + + break; + + case 'H': + { + if (*fmt == '\0') + invalid = TRUE; + else + { + int flags = *fmt++ - '0'; + int iserr = FALSE, state; + const sipTypeDef *td; + void *cpp, *val; + + td = va_arg(va, const sipTypeDef *); + cpp = va_arg(va, void **); + + val = sip_api_force_convert_to_type(arg, td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), &state, &iserr); + + if (iserr) + { + invalid = TRUE; + } + else if (flags & FMT_RP_MAKE_COPY) + { + sipAssignFunc assign_helper; + + if (sipTypeIsMapped(td)) + assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign; + else + assign_helper = ((const sipClassTypeDef *)td)->ctd_assign; + + assert(assign_helper != NULL); + + assign_helper(cpp, 0, val); + sip_api_release_type(val, td, state); + } + else + { + *(void **)cpp = val; + } + } + } + + break; + + case 'N': + { + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (arg == Py_None || PyObject_TypeCheck(arg,type)) + { + 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 **); + + if (PyObject_TypeCheck(arg,type)) + { + Py_INCREF(arg); + *p = arg; + } + else + invalid = TRUE; + } + + break; + + case 'V': + { + void *v = sip_api_convert_to_void_ptr(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,void **) = v; + } + + break; + + case 'Z': + if (arg != Py_None) + invalid = TRUE; + + break; + + default: + PyErr_Format(PyExc_SystemError,"sipParseResult(): invalid format character '%c'",ch); + rc = -1; + } + + if (invalid) + { + sip_api_bad_catcher_result(method); + rc = -1; + break; + } + } + } + + va_end(va); + + if (isErr != NULL && rc < 0) + *isErr = TRUE; + + return rc; +} + + +/* + * A thin wrapper around PyLong_AsUnsignedLong() that works around a bug in + * 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) +{ +#if PY_VERSION_HEX < 0x02040000 + if (o != NULL && !PyLong_Check(o) && PyInt_Check(o)) + { + long v = PyInt_AsLong(o); + + if (v < 0) + { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned long"); + + return (unsigned long)-1; + } + + return v; + } +#endif + + return PyLong_AsUnsignedLong(o); +} + + +/* + * Parse the arguments to a C/C++ function without any side effects. + */ +static int sip_api_parse_args(PyObject **parseErrp, PyObject *sipArgs, + const char *fmt, ...) +{ + int ok; + va_list va; + + va_start(va, fmt); + ok = parseKwdArgs(parseErrp, sipArgs, NULL, NULL, NULL, fmt, va); + va_end(va); + + return ok; +} + + +/* + * Parse the positional and/or keyword arguments to a C/C++ function without + * any side effects. + */ +static int sip_api_parse_kwd_args(PyObject **parseErrp, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused, + const char *fmt, ...) +{ + int ok; + va_list va; + + /* Initialise the return of any unused keyword arguments. */ + if (unused != NULL) + *unused = NULL; + + va_start(va, fmt); + ok = parseKwdArgs(parseErrp, sipArgs, sipKwdArgs, kwdlist, unused, fmt, + va); + va_end(va); + + /* Release any unused arguments if the parse failed. */ + if (!ok && unused != NULL) + { + Py_XDECREF(*unused); + } + + return ok; +} + + +/* + * Parse the arguments to a C/C++ function without any side effects. + */ +static int parseKwdArgs(PyObject **parseErrp, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused, + const char *fmt, va_list va_orig) +{ + int no_tmp_tuple, ok, selfarg; + sipSimpleWrapper *self; + PyObject *single_arg; + va_list va; + + /* Previous second pass errors stop subsequent parses. */ + if (*parseErrp != NULL && !PyList_Check(*parseErrp)) + return FALSE; + + /* + * See if we are parsing a single argument. In current versions we are + * told explicitly by the first character of the format string. In earlier + * versions we guessed (sometimes wrongly). + */ + if (*fmt == '1') + { + ++fmt; + no_tmp_tuple = FALSE; + } + else + no_tmp_tuple = PyTuple_Check(sipArgs); + + if (no_tmp_tuple) + { + Py_INCREF(sipArgs); + } + else if ((single_arg = PyTuple_New(1)) != NULL) + { + Py_INCREF(sipArgs); + PyTuple_SET_ITEM(single_arg, 0, sipArgs); + + sipArgs = single_arg; + } + else + { + /* Stop all parsing and indicate an exception has been raised. */ + Py_XDECREF(*parseErrp); + *parseErrp = Py_None; + Py_INCREF(Py_None); + + return FALSE; + } + + /* + * The first pass checks all the types and does conversions that are cheap + * and have no side effects. + */ + va_copy(va, va_orig); + ok = parsePass1(parseErrp, &self, &selfarg, sipArgs, sipKwdArgs, kwdlist, + unused, fmt, va); + va_end(va); + + if (ok) + { + /* + * The second pass does any remaining conversions now that we know we + * have the right signature. + */ + va_copy(va, va_orig); + ok = parsePass2(self, selfarg, sipArgs, sipKwdArgs, kwdlist, fmt, va); + va_end(va); + + /* Remove any previous failed parses. */ + Py_XDECREF(*parseErrp); + + if (ok) + { + *parseErrp = NULL; + } + else + { + /* Indicate that an exception has been raised. */ + *parseErrp = Py_None; + Py_INCREF(Py_None); + } + } + + Py_DECREF(sipArgs); + + return ok; +} + + +/* + * Return a string as a Python object that describes an argument with an + * unexpected type. + */ +static PyObject *bad_type_str(int arg_nr, PyObject *arg) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromFormat("argument %d has unexpected type '%s'", arg_nr, + Py_TYPE(arg)->tp_name); +#else + return PyString_FromFormat("argument %d has unexpected type '%s'", arg_nr, + Py_TYPE(arg)->tp_name); +#endif +} + + +/* + * Adds a failure about an argument with an incorrect type to the current list + * of exceptions. + */ +static sipErrorState sip_api_bad_callable_arg(int arg_nr, PyObject *arg) +{ + PyObject *detail = bad_type_str(arg_nr + 1, arg); + + if (detail == NULL) + return sipErrorFail; + + PyErr_SetObject(PyExc_TypeError, detail); + Py_DECREF(detail); + + return sipErrorContinue; +} + + +/* + * Adds the current exception to the current list of exceptions (if it is a + * user exception) or replace the current list of exceptions. + */ +static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp) +{ + assert(*parseErrp == NULL); + + if (es == sipErrorContinue) + { + sipParseFailure failure; + PyObject *e_type, *e_traceback; + + /* Get the value of the exception. */ + PyErr_Fetch(&e_type, &failure.detail_obj, &e_traceback); + Py_XDECREF(e_type); + Py_XDECREF(e_traceback); + + failure.reason = Exception; + + add_failure(parseErrp, &failure); + + if (failure.reason == Raised) + { + Py_XDECREF(failure.detail_obj); + es = sipErrorFail; + } + } + + if (es == sipErrorFail) + { + Py_XDECREF(*parseErrp); + *parseErrp = Py_None; + Py_INCREF(Py_None); + } +} + + +/* + * The dtor for parse failure wrapped in a Python object. + */ +#if defined(SIP_USE_PYCAPSULE) +static void failure_dtor(PyObject *capsule) +{ + sipParseFailure *failure = (sipParseFailure *)PyCapsule_GetPointer(capsule, NULL); + + Py_XDECREF(failure->detail_obj); + + sip_api_free(failure); +} +#else +static void failure_dtor(void *ptr) +{ + sipParseFailure *failure = (sipParseFailure *)ptr; + + Py_XDECREF(failure->detail_obj); + + sip_api_free(failure); +} +#endif + + +/* + * Add a parse failure to the current list of exceptions. + */ +static void add_failure(PyObject **parseErrp, sipParseFailure *failure) +{ + sipParseFailure *failure_copy; + PyObject *failure_obj; + + /* Create the list if necessary. */ + if (*parseErrp == NULL && (*parseErrp = PyList_New(0)) == NULL) + { + failure->reason = Raised; + return; + } + + /* + * Make a copy of the failure, convert it to a Python object and add it to + * the list. We do it this way to make it as lightweight as possible. + */ + if ((failure_copy = sip_api_malloc(sizeof (sipParseFailure))) == NULL) + { + failure->reason = Raised; + return; + } + + *failure_copy = *failure; + +#if defined(SIP_USE_PYCAPSULE) + failure_obj = PyCapsule_New(failure_copy, NULL, failure_dtor); +#else + failure_obj = PyCObject_FromVoidPtr(failure_copy, failure_dtor); +#endif + + if (failure_obj == NULL) + { + sip_api_free(failure_copy); + failure->reason = Raised; + return; + } + + /* Ownership of any detail object is now with the wrapped failure. */ + failure->detail_obj = NULL; + + if (PyList_Append(*parseErrp, failure_obj) < 0) + { + Py_DECREF(failure_obj); + failure->reason = Raised; + return; + } + + Py_DECREF(failure_obj); +} + + +/* + * Parse a pair of arguments to a C/C++ function without any side effects. + */ +static int sip_api_parse_pair(PyObject **parseErrp, PyObject *sipArg0, + PyObject *sipArg1, const char *fmt, ...) +{ + int ok, selfarg; + sipSimpleWrapper *self; + PyObject *args; + va_list va; + + /* Previous second pass errors stop subsequent parses. */ + if (*parseErrp != NULL && !PyList_Check(*parseErrp)) + return FALSE; + + if ((args = PyTuple_New(2)) == NULL) + { + /* Stop all parsing and indicate an exception has been raised. */ + Py_XDECREF(*parseErrp); + *parseErrp = Py_None; + Py_INCREF(Py_None); + + return FALSE; + } + + Py_INCREF(sipArg0); + PyTuple_SET_ITEM(args, 0, sipArg0); + + Py_INCREF(sipArg1); + PyTuple_SET_ITEM(args, 1, sipArg1); + + /* + * The first pass checks all the types and does conversions that are cheap + * and have no side effects. + */ + va_start(va, fmt); + ok = parsePass1(parseErrp, &self, &selfarg, args, NULL, NULL, NULL, fmt, + va); + va_end(va); + + if (ok) + { + /* + * The second pass does any remaining conversions now that we know we + * have the right signature. + */ + va_start(va, fmt); + ok = parsePass2(self, selfarg, args, NULL, NULL, fmt, va); + va_end(va); + + /* Remove any previous failed parses. */ + Py_XDECREF(*parseErrp); + + if (ok) + { + *parseErrp = NULL; + } + else + { + /* Indicate that an exception has been raised. */ + *parseErrp = Py_None; + Py_INCREF(Py_None); + } + } + + Py_DECREF(args); + + return ok; +} + + +/* + * First pass of the argument parse, converting those that can be done so + * without any side effects. Return TRUE if the arguments matched. + */ +static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp, + int *selfargp, PyObject *sipArgs, PyObject *sipKwdArgs, + const char **kwdlist, PyObject **unused, const char *fmt, va_list va) +{ + int compulsory, argnr, nr_args; + SIP_SSIZE_T nr_pos_args, nr_kwd_args, nr_kwd_args_used; + sipParseFailure failure; + + failure.reason = Ok; + failure.detail_obj = NULL; + compulsory = TRUE; + argnr = 0; + nr_args = 0; + nr_pos_args = PyTuple_GET_SIZE(sipArgs); + nr_kwd_args = nr_kwd_args_used = 0; + + if (sipKwdArgs != NULL) + { + assert(PyDict_Check(sipKwdArgs)); + + nr_kwd_args = PyDict_Size(sipKwdArgs); + } + + /* + * Handle those format characters that deal with the "self" argument. They + * will always be the first one. + */ + *selfp = NULL; + *selfargp = FALSE; + + switch (*fmt++) + { + case 'B': + case 'p': + { + PyObject *self; + sipTypeDef *td; + + self = *va_arg(va, PyObject **); + td = va_arg(va, sipTypeDef *); + va_arg(va, void **); + + if (self == NULL) + { + if (!getSelfFromArgs(td, sipArgs, argnr, selfp)) + { + failure.reason = Unbound; + failure.detail_str = sipPyNameOfContainer( + &((sipClassTypeDef *)td)->ctd_container, td); + break; + } + + *selfargp = TRUE; + ++argnr; + } + else + *selfp = (sipSimpleWrapper *)self; + + break; + } + + case 'C': + *selfp = (sipSimpleWrapper *)va_arg(va,PyObject *); + break; + + default: + --fmt; + } + + /* Now handle the remaining arguments. */ + while (failure.reason == Ok) + { + char ch; + PyObject *arg; + + PyErr_Clear(); + + /* See if the following arguments are optional. */ + if ((ch = *fmt++) == '|') + { + compulsory = FALSE; + ch = *fmt++; + } + + /* See if we don't expect anything else. */ + + if (ch == '\0') + { + if (argnr < nr_pos_args) + { + /* There are still positional arguments. */ + failure.reason = TooMany; + } + else if (nr_kwd_args_used != nr_kwd_args) + { + /* + * Take a shortcut if no keyword arguments were used and we are + * interested in them. + */ + if (nr_kwd_args_used == 0 && unused != NULL) + { + Py_INCREF(sipKwdArgs); + *unused = sipKwdArgs; + } + else + { + PyObject *key, *value, *unused_dict = NULL; + SIP_SSIZE_T pos = 0; + + /* + * Go through the keyword arguments to find any that were + * duplicates of positional arguments. For the remaining + * ones remember the unused ones if we are interested. + */ + while (PyDict_Next(sipKwdArgs, &pos, &key, &value)) + { + int a; + +#if PY_MAJOR_VERSION >= 3 + if (!PyUnicode_Check(key)) +#else + if (!PyString_Check(key)) +#endif + { + failure.reason = KeywordNotString; + failure.detail_obj = key; + Py_INCREF(key); + break; + } + + if (kwdlist != NULL) + { + /* Get the argument's index if it is one. */ + for (a = 0; a < nr_args; ++a) + { + const char *name = kwdlist[a]; + + if (name == NULL) + continue; + +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_CompareWithASCIIString(key, name) == 0) +#else + if (strcmp(PyString_AS_STRING(key), name) == 0) +#endif + break; + } + } + else + { + a = nr_args; + } + + if (a == nr_args) + { + /* + * The name doesn't correspond to a keyword + * argument. + */ + if (unused == NULL) + { + /* + * It may correspond to a keyword argument of a + * different overload. + */ + failure.reason = UnknownKeyword; + failure.detail_obj = key; + Py_INCREF(key); + + break; + } + + /* + * Add it to the dictionary of unused arguments + * creating it if necessary. Note that if the + * unused arguments are actually used by a later + * overload then the parse will incorrectly + * succeed. This should be picked up (perhaps with + * a misleading exception) so long as the code that + * handles the unused arguments checks that it can + * handle them all. + */ + if (unused_dict == NULL && (*unused = unused_dict = PyDict_New()) == NULL) + { + failure.reason = Raised; + break; + } + + if (PyDict_SetItem(unused_dict, key, value) < 0) + { + failure.reason = Raised; + break; + } + } + else if (a < nr_pos_args) + { + /* + * The argument has been given positionally and as + * a keyword. + */ + failure.reason = Duplicate; + failure.detail_obj = key; + Py_INCREF(key); + break; + } + } + } + } + + break; + } + + /* Get the next argument. */ + arg = NULL; + failure.arg_nr = -1; + failure.arg_name = NULL; + + if (argnr < nr_pos_args) + { + arg = PyTuple_GET_ITEM(sipArgs, argnr); + failure.arg_nr = argnr + 1; + } + else if (sipKwdArgs != NULL && kwdlist != NULL) + { + const char *name = kwdlist[argnr]; + + if (name != NULL) + { + arg = PyDict_GetItemString(sipKwdArgs, name); + + if (arg != NULL) + ++nr_kwd_args_used; + + failure.arg_name = name; + } + } + + ++argnr; + ++nr_args; + + if (arg == NULL && compulsory) + { + if (ch == 'W') + { + /* + * A variable number of arguments was allowed but none were + * given. + */ + break; + } + + /* An argument was required. */ + failure.reason = TooFew; + + /* + * Check if there were any unused keyword arguments so that we give + * a (possibly) more accurate diagnostic in the case that a keyword + * argument has been mis-spelled. + */ + if (unused == NULL && sipKwdArgs != NULL && nr_kwd_args_used != nr_kwd_args) + { + PyObject *key, *value; + SIP_SSIZE_T pos = 0; + + while (PyDict_Next(sipKwdArgs, &pos, &key, &value)) + { + int a; + +#if PY_MAJOR_VERSION >= 3 + if (!PyUnicode_Check(key)) +#else + if (!PyString_Check(key)) +#endif + { + failure.reason = KeywordNotString; + failure.detail_obj = key; + Py_INCREF(key); + break; + } + + if (kwdlist != NULL) + { + /* Get the argument's index if it is one. */ + for (a = 0; a < nr_args; ++a) + { + const char *name = kwdlist[a]; + + if (name == NULL) + continue; + +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_CompareWithASCIIString(key, name) == 0) +#else + if (strcmp(PyString_AS_STRING(key), name) == 0) +#endif + break; + } + } + else + { + a = nr_args; + } + + if (a == nr_args) + { + failure.reason = UnknownKeyword; + failure.detail_obj = key; + Py_INCREF(key); + + break; + } + } + } + + break; + } + + /* + * Handle the format character even if we don't have an argument so + * that we skip the right number of arguments. + */ + switch (ch) + { + case 'W': + /* Ellipsis. */ + break; + + case '@': + { + /* Implement /GetWrapper/. */ + + PyObject **p = va_arg(va, PyObject **); + + if (arg != NULL) + *p = arg; + + /* Process the same argument next time round. */ + --argnr; + --nr_args; + + break; + } + + case 's': + { + /* String from a Python bytes or None. */ + + const char **p = va_arg(va, const char **); + + if (arg != NULL && parseBytes_AsString(arg, p) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'A': + { + /* String from a Python string or None. */ + + PyObject **keep = va_arg(va, PyObject **); + const char **p = va_arg(va, const char **); + char sub_fmt = *fmt++; + + if (arg != NULL) + { + PyObject *s; + + switch (sub_fmt) + { + case 'A': + s = parseString_AsASCIIString(arg, p); + break; + + case 'L': + s = parseString_AsLatin1String(arg, p); + break; + + case '8': + s = parseString_AsUTF8String(arg, p); + break; + } + + if (s == NULL) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *keep = s; + } + } + + break; + } + + case 'x': +#if defined(HAVE_WCHAR_H) + { + /* Wide string or None. */ + + wchar_t **p = va_arg(va, wchar_t **); + + if (arg != NULL && parseWCharString(arg, p) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } +#else + raiseNoWChar(); + failure.reason = Raised; + break; +#endif + + case 'U': + { + /* Slot name or callable, return the name or callable. */ + + char **sname = va_arg(va, char **); + PyObject **scall = va_arg(va, PyObject **); + + if (arg != NULL) + { + *sname = NULL; + *scall = NULL; + + if (SIPBytes_Check(arg)) + { + char *s = SIPBytes_AS_STRING(arg); + + if (*s == '1' || *s == '2' || *s == '9') + { + *sname = s; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + else if (PyCallable_Check(arg)) + { + *scall = arg; + } + else if (arg != Py_None) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'S': + { + /* Slot name, return the name. */ + + char **p = va_arg(va, char **); + + if (arg != NULL) + { + if (SIPBytes_Check(arg)) + { + char *s = SIPBytes_AS_STRING(arg); + + if (*s == '1' || *s == '2' || *s == '9') + { + *p = s; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'G': + { + /* Signal name, return the name. */ + + char **p = va_arg(va, char **); + + if (arg != NULL) + { + if (SIPBytes_Check(arg)) + { + char *s = SIPBytes_AS_STRING(arg); + + if (*s == '2' || *s == '9') + { + *p = s; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'r': + { + /* Sequence of class or mapped type instances. */ + + const sipTypeDef *td; + + td = va_arg(va, const sipTypeDef *); + va_arg(va, void **); + va_arg(va, SIP_SSIZE_T *); + + if (arg != NULL && !canConvertFromSequence(arg, td)) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'J': + { + /* Class or mapped type instance. */ + + char sub_fmt = *fmt++; + const sipTypeDef *td; + int flags = sub_fmt - '0'; + int iflgs = 0; + + td = va_arg(va, const sipTypeDef *); + va_arg(va, void **); + + if (flags & FMT_AP_DEREF) + iflgs |= SIP_NOT_NONE; + + if (flags & FMT_AP_TRANSFER_THIS) + va_arg(va, PyObject **); + + if (flags & FMT_AP_NO_CONVERTORS) + iflgs |= SIP_NO_CONVERTORS; + else + va_arg(va, int *); + + if (arg != NULL && !sip_api_can_convert_to_type(arg, td, iflgs)) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'N': + { + /* Python object of given type or None. */ + + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (arg != NULL) + { + if (arg == Py_None || PyObject_TypeCheck(arg,type)) + { + *p = arg; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'P': + { + /* Python object of any type with a sub-format. */ + + va_arg(va, PyObject **); + + /* Skip the sub-format. */ + ++fmt; + + break; + } + + case 'T': + { + /* Python object of given type. */ + + PyTypeObject *type = va_arg(va, PyTypeObject *); + PyObject **p = va_arg(va, PyObject **); + + if (arg != NULL) + { + if (PyObject_TypeCheck(arg,type)) + { + *p = arg; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'R': + { + /* Sub-class of QObject. */ + + PyObject **p = va_arg(va, PyObject **); + + if (arg != NULL) + { + if (isQObject(arg)) + { + *p = arg; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'F': + { + /* Python callable object. */ + + PyObject **p = va_arg(va, PyObject **); + + if (arg != NULL) + { + if (PyCallable_Check(arg)) + { + *p = arg; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'H': + { + /* Python callable object or None. */ + + PyObject **p = va_arg(va, PyObject **); + + if (arg != NULL) + { + if (arg == Py_None || PyCallable_Check(arg)) + { + *p = arg; + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'q': + { + /* Qt receiver to connect. */ + + va_arg(va, char *); + va_arg(va, void **); + va_arg(va, const char **); + + if (arg != NULL && !isQObject(arg)) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'Q': + { + /* Qt receiver to disconnect. */ + + va_arg(va, char *); + va_arg(va, void **); + va_arg(va, const char **); + + if (arg != NULL && !isQObject(arg)) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'g': + case 'y': + { + /* Python slot to connect. */ + + va_arg(va, char *); + va_arg(va, void **); + va_arg(va, const char **); + + if (arg != NULL && (sipQtSupport == NULL || !PyCallable_Check(arg))) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'Y': + { + /* Python slot to disconnect. */ + + va_arg(va, char *); + va_arg(va, void **); + va_arg(va, const char **); + + if (arg != NULL && (sipQtSupport == NULL || !PyCallable_Check(arg))) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'k': + { + /* Char array or None. */ + + const char **p = va_arg(va, const char **); + SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *); + + if (arg != NULL && parseBytes_AsCharArray(arg, p, szp) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'K': +#if defined(HAVE_WCHAR_H) + { + /* Wide char array or None. */ + + wchar_t **p = va_arg(va, wchar_t **); + SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *); + + if (arg != NULL && parseWCharArray(arg, p, szp) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } +#else + raiseNoWChar(); + failure.reason = Raised; + break +#endif + + case 'c': + { + /* Character from a Python bytes. */ + + char *p = va_arg(va, char *); + + if (arg != NULL && parseBytes_AsChar(arg, p) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'a': + { + /* Character from a Python string. */ + + char *p = va_arg(va, char *); + char sub_fmt = *fmt++; + + if (arg != NULL) + { + int enc; + + switch (sub_fmt) + { + case 'A': + enc = parseString_AsASCIIChar(arg, p); + break; + + case 'L': + enc = parseString_AsLatin1Char(arg, p); + break; + + case '8': + enc = parseString_AsUTF8Char(arg, p); + break; + } + + if (enc < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + } + + case 'w': +#if defined(HAVE_WCHAR_H) + { + /* Wide character. */ + + wchar_t *p = va_arg(va, wchar_t *); + + if (arg != NULL && parseWChar(arg, p) < 0) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } +#else + raiseNoWChar(); + failure.reason = Raised; + break +#endif + + case 'b': + { + /* Bool. */ + + void *p = va_arg(va, void *); + + if (arg != NULL) + { + int v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + sipSetBool(p, v); + } + } + + break; + } + + case 'E': + { + /* Named enum or integer. */ + + sipTypeDef *td = va_arg(va, sipTypeDef *); + + va_arg(va, int *); + + if (arg != NULL && !sip_api_can_convert_to_enum(arg, td)) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + + break; + + case 'e': + case 'i': + { + /* Integer or anonymous enum. */ + + int *p = va_arg(va, int *); + + if (arg != NULL) + { + int v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'u': + { + /* Unsigned integer. */ + + unsigned *p = va_arg(va, unsigned *); + + if (arg != NULL) + { + unsigned v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'h': + { + /* Short integer. */ + + short *p = va_arg(va, short *); + + if (arg != NULL) + { + short v = SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 't': + { + /* Unsigned short integer. */ + + unsigned short *p = va_arg(va, unsigned short *); + + if (arg != NULL) + { + unsigned short v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'l': + { + /* Long integer. */ + + long *p = va_arg(va, long *); + + if (arg != NULL) + { + long v = PyLong_AsLong(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'm': + { + /* Unsigned long integer. */ + + unsigned long *p = va_arg(va, unsigned long *); + + if (arg != NULL) + { + unsigned long v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'n': + { + /* Long long integer. */ + +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG *p = va_arg(va, PY_LONG_LONG *); +#else + long *p = va_arg(va, long *); +#endif + + if (arg != NULL) + { +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG v = PyLong_AsLongLong(arg); +#else + long v = PyLong_AsLong(arg); +#endif + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'o': + { + /* Unsigned long long integer. */ + +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG *p = va_arg(va, unsigned PY_LONG_LONG *); +#else + unsigned long *p = va_arg(va, unsigned long *); +#endif + + if (arg != NULL) + { +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg); +#else + unsigned long v = PyLong_AsUnsignedLong(arg); +#endif + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'f': + { + /* Float. */ + + float *p = va_arg(va, float *); + + if (arg != NULL) + { + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = (float)v; + } + } + + break; + } + + case 'X': + { + /* Constrained types. */ + + char sub_fmt = *fmt++; + + if (sub_fmt == 'E') + { + /* Named enum. */ + + sipTypeDef *td = va_arg(va, sipTypeDef *); + + va_arg(va, int *); + + if (arg != NULL && !PyObject_TypeCheck(arg, sipTypeAsPyTypeObject(td))) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + } + else + { + void *p = va_arg(va, void *); + + if (arg != NULL) + { + switch (sub_fmt) + { + case 'b': + { + /* Boolean. */ + + if (PyBool_Check(arg)) + { + sipSetBool(p, (arg == Py_True)); + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'd': + { + /* Double float. */ + + if (PyFloat_Check(arg)) + { + *(double *)p = PyFloat_AS_DOUBLE(arg); + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'f': + { + /* Float. */ + + if (PyFloat_Check(arg)) + { + *(float *)p = (float)PyFloat_AS_DOUBLE(arg); + } + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + + case 'i': + { + /* Integer. */ + +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(arg)) + { + *(int *)p = PyLong_AS_LONG(arg); + } +#else + if (PyInt_Check(arg)) + { + *(int *)p = PyInt_AS_LONG(arg); + } +#endif + else + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + + break; + } + } + } + } + + break; + } + + case 'd': + { + /* Double float. */ + + double *p = va_arg(va,double *); + + if (arg != NULL) + { + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + + case 'v': + { + /* Void pointer. */ + + void **p = va_arg(va, void **); + + if (arg != NULL) + { + void *v = sip_api_convert_to_void_ptr(arg); + + if (PyErr_Occurred()) + { + failure.reason = WrongType; + failure.detail_obj = arg; + Py_INCREF(arg); + } + else + { + *p = v; + } + } + + break; + } + } + + if (failure.reason == Ok && ch == 'W') + { + /* An ellipsis matches everything and ends the parse. */ + break; + } + } + + /* Handle parse failures appropriately. */ + + if (failure.reason == Ok) + return TRUE; + + if (failure.reason != Raised) + { + add_failure(parseErrp, &failure); + } + + if (failure.reason == Raised) + { + Py_XDECREF(failure.detail_obj); + + /* + * The error isn't a user error so don't bother with the detail of the + * overload. + */ + Py_XDECREF(*parseErrp); + *parseErrp = Py_None; + Py_INCREF(Py_None); + } + + return FALSE; +} + + +/* + * Second pass of the argument parse, converting the remaining ones that might + * have side effects. Return TRUE if there was no error. + */ +static int parsePass2(sipSimpleWrapper *self, int selfarg, PyObject *sipArgs, + PyObject *sipKwdArgs, const char **kwdlist, const char *fmt, + va_list va) +{ + int a, ok; + SIP_SSIZE_T nr_pos_args; + + /* Handle the converions of "self" first. */ + switch (*fmt++) + { + case 'B': + { + /* + * The address of a C++ instance when calling one of its public + * methods. + */ + + const sipTypeDef *td; + void **p; + + *va_arg(va, PyObject **) = (PyObject *)self; + td = va_arg(va, const sipTypeDef *); + p = va_arg(va, void **); + + if ((*p = sip_api_get_cpp_ptr(self, td)) == NULL) + return FALSE; + + break; + } + + case 'p': + { + /* + * The address of a C++ instance when calling one of its protected + * methods. + */ + + const sipTypeDef *td; + void **p; + + *va_arg(va, PyObject **) = (PyObject *)self; + td = va_arg(va, const sipTypeDef *); + p = va_arg(va, void **); + + if ((*p = getComplexCppPtr(self, td)) == NULL) + return FALSE; + + break; + } + + case 'C': + va_arg(va, PyObject *); + break; + + default: + --fmt; + } + + ok = TRUE; + nr_pos_args = PyTuple_GET_SIZE(sipArgs); + + for (a = (selfarg ? 1 : 0); *fmt != '\0' && *fmt != 'W' && ok; ++a) + { + char ch; + PyObject *arg; + + /* Skip the optional character. */ + if ((ch = *fmt++) == '|') + ch = *fmt++; + + /* Get the next argument. */ + arg = NULL; + + if (a < nr_pos_args) + { + arg = PyTuple_GET_ITEM(sipArgs, a); + } + else if (sipKwdArgs != NULL) + { + const char *name = kwdlist[a]; + + if (name != NULL) + arg = PyDict_GetItemString(sipKwdArgs, name); + } + + /* + * Do the outstanding conversions. For most types it has already been + * done, so we are just skipping the parameters. + */ + switch (ch) + { + case '@': + /* Implement /GetWrapper/. */ + va_arg(va, PyObject **); + + /* Process the same argument next time round. */ + --a; + + break; + + case 'q': + { + /* Qt receiver to connect. */ + + char *sig = va_arg(va, char *); + void **rx = va_arg(va, void **); + const char **slot = va_arg(va, const char **); + + if (arg != NULL) + { + *rx = sip_api_convert_rx((sipWrapper *)self, sig, arg, + *slot, slot, 0); + + if (*rx == NULL) + return FALSE; + } + + break; + } + + case 'Q': + { + /* Qt receiver to disconnect. */ + + char *sig = va_arg(va, char *); + void **rx = va_arg(va, void **); + const char **slot = va_arg(va, const char **); + + if (arg != NULL) + *rx = sipGetRx(self, sig, arg, *slot, slot); + + break; + } + + case 'g': + { + /* Python single shot slot to connect. */ + + char *sig = va_arg(va, char *); + void **rx = va_arg(va, void **); + const char **slot = va_arg(va, const char **); + + if (arg != NULL) + { + *rx = sip_api_convert_rx((sipWrapper *)self, sig, arg, + NULL, slot, SIP_SINGLE_SHOT); + + if (*rx == NULL) + return FALSE; + } + + break; + } + + case 'y': + { + /* Python slot to connect. */ + + char *sig = va_arg(va, char *); + void **rx = va_arg(va, void **); + const char **slot = va_arg(va, const char **); + + if (arg != NULL) + { + *rx = sip_api_convert_rx((sipWrapper *)self, sig, arg, + NULL, slot, 0); + + if (*rx == NULL) + return FALSE; + } + + break; + } + + case 'Y': + { + /* Python slot to disconnect. */ + + char *sig = va_arg(va, char *); + void **rx = va_arg(va, void **); + const char **slot = va_arg(va, const char **); + + if (arg != NULL) + *rx = sipGetRx(self, sig, arg, NULL, slot); + + break; + } + + case 'r': + { + /* Sequence of class or mapped type instances. */ + + const sipTypeDef *td; + void **array; + SIP_SSIZE_T *nr_elem; + + td = va_arg(va, const sipTypeDef *); + array = va_arg(va, void **); + nr_elem = va_arg(va, SIP_SSIZE_T *); + + if (arg != NULL && !convertFromSequence(arg, td, array, nr_elem)) + return FALSE; + + break; + } + + case 'J': + { + /* Class or mapped type instance. */ + + int flags = *fmt++ - '0'; + const sipTypeDef *td; + void **p; + int iflgs = 0; + int *state; + PyObject *xfer, **owner; + + td = va_arg(va, const sipTypeDef *); + p = va_arg(va, void **); + + if (flags & FMT_AP_TRANSFER) + xfer = (self ? (PyObject *)self : arg); + else if (flags & FMT_AP_TRANSFER_BACK) + xfer = Py_None; + else + xfer = NULL; + + if (flags & FMT_AP_DEREF) + iflgs |= SIP_NOT_NONE; + + if (flags & FMT_AP_TRANSFER_THIS) + owner = va_arg(va, PyObject **); + + if (flags & FMT_AP_NO_CONVERTORS) + { + iflgs |= SIP_NO_CONVERTORS; + state = NULL; + } + else + { + state = va_arg(va, int *); + } + + if (arg != NULL) + { + int iserr = FALSE; + + *p = sip_api_convert_to_type(arg, td, xfer, iflgs, state, + &iserr); + + if (iserr) + return FALSE; + + if (flags & FMT_AP_TRANSFER_THIS && *p != NULL) + *owner = arg; + } + + break; + } + + case 'P': + { + /* Python object of any type with a sub-format. */ + + PyObject **p = va_arg(va, PyObject **); + int flags = *fmt++ - '0'; + + if (arg != NULL) + { + if (flags & FMT_AP_TRANSFER) + { + Py_XINCREF(arg); + } + else if (flags & FMT_AP_TRANSFER_BACK) + { + Py_XDECREF(arg); + } + + *p = arg; + } + + break; + } + + case 'X': + { + /* Constrained types. */ + + va_arg(va, void *); + + if (*fmt++ == 'E') + { + /* Named enum. */ + + int *p = va_arg(va, int *); + + if (arg != NULL) + *p = SIPLong_AsLong(arg); + } + + break; + } + + case 'E': + { + /* Named enum. */ + + int *p; + + va_arg(va, sipTypeDef *); + p = va_arg(va, int *); + + if (arg != NULL) + *p = SIPLong_AsLong(arg); + + break; + } + + /* + * These need special handling because they have a sub-format + * character. + */ + case 'A': + va_arg(va, void *); + + /* Drop through. */ + + case 'a': + va_arg(va, void *); + fmt++; + break; + + /* + * Every other argument is a pointer and only differ in how many there + * are. + */ + case 'N': + case 'T': + case 'k': + case 'K': + va_arg(va, void *); + + /* Drop through. */ + + default: + va_arg(va, void *); + } + } + + /* Handle any ellipsis argument. */ + if (*fmt == 'W') + { + PyObject *al; + int da = 0; + + /* Create a tuple for any remaining arguments. */ + if ((al = PyTuple_New(nr_pos_args - a)) == NULL) + return FALSE; + + while (a < nr_pos_args) + { + PyObject *arg = PyTuple_GET_ITEM(sipArgs, a); + + /* Add the remaining argument to the tuple. */ + Py_INCREF(arg); + PyTuple_SET_ITEM(al, da, arg); + + ++a; + ++da; + } + + /* Return the tuple. */ + *va_arg(va, PyObject **) = al; + } + + return TRUE; +} + + +/* + * Return TRUE if an object is a QObject. + */ +static int isQObject(PyObject *obj) +{ + return (sipQtSupport != NULL && PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(sipQObjectType))); +} + + +/* + * See if a Python object is a sequence of a particular type. + */ +static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td) +{ + SIP_SSIZE_T i, size = PySequence_Size(seq); + + if (size < 0) + return FALSE; + + for (i = 0; i < size; ++i) + { + int ok; + PyObject *val_obj; + + if ((val_obj = PySequence_GetItem(seq, i)) == NULL) + return FALSE; + + ok = sip_api_can_convert_to_type(val_obj, td, + SIP_NO_CONVERTORS|SIP_NOT_NONE); + + Py_DECREF(val_obj); + + if (!ok) + return FALSE; + } + + return TRUE; +} + + +/* + * Convert a Python sequence to an array that has already "passed" + * canConvertFromSequence(). Return TRUE if the conversion was successful. + */ +static int convertFromSequence(PyObject *seq, const sipTypeDef *td, + void **array, SIP_SSIZE_T *nr_elem) +{ + int iserr = 0; + SIP_SSIZE_T i, size = PySequence_Size(seq); + sipArrayFunc array_helper; + sipAssignFunc assign_helper; + void *array_mem; + + /* Get the type's helpers. */ + if (sipTypeIsMapped(td)) + { + array_helper = ((const sipMappedTypeDef *)td)->mtd_array; + assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign; + } + else + { + array_helper = ((const sipClassTypeDef *)td)->ctd_array; + assign_helper = ((const sipClassTypeDef *)td)->ctd_assign; + } + + assert(array_helper != NULL); + assert(assign_helper != NULL); + + /* + * Create the memory for the array of values. Note that this will leak if + * there is an error. + */ + array_mem = array_helper(size); + + for (i = 0; i < size; ++i) + { + PyObject *val_obj; + void *val; + + if ((val_obj = PySequence_GetItem(seq, i)) == NULL) + return FALSE; + + val = sip_api_convert_to_type(val_obj, td, NULL, + SIP_NO_CONVERTORS|SIP_NOT_NONE, NULL, &iserr); + + Py_DECREF(val_obj); + + if (iserr) + return FALSE; + + assign_helper(array_mem, i, val); + } + + *array = array_mem; + *nr_elem = size; + + return TRUE; +} + + +/* + * Convert an array of a type to a Python sequence. + */ +static PyObject *convertToSequence(void *array, SIP_SSIZE_T nr_elem, + const sipTypeDef *td) +{ + SIP_SSIZE_T i; + PyObject *seq; + sipCopyFunc copy_helper; + + /* Get the type's copy helper. */ + if (sipTypeIsMapped(td)) + copy_helper = ((const sipMappedTypeDef *)td)->mtd_copy; + else + copy_helper = ((const sipClassTypeDef *)td)->ctd_copy; + + assert(copy_helper != NULL); + + if ((seq = PyTuple_New(nr_elem)) == NULL) + return NULL; + + for (i = 0; i < nr_elem; ++i) + { + void *el = copy_helper(array, i); + PyObject *el_obj = sip_api_convert_from_new_type(el, td, NULL); + + if (el_obj == NULL) + { + release(el, td, 0); + Py_DECREF(seq); + } + + PyTuple_SET_ITEM(seq, i, el_obj); + } + + return seq; +} + + +/* + * Carry out actions common to all dtors. + */ +void sip_api_common_dtor(sipSimpleWrapper *sipSelf) +{ + if (sipSelf != NULL && sipInterpreter != NULL) + { + PyObject *xtype, *xvalue, *xtb; + + SIP_BLOCK_THREADS + + /* We may be tidying up after an exception so preserve it. */ + PyErr_Fetch(&xtype, &xvalue, &xtb); + callPyDtor(sipSelf); + PyErr_Restore(xtype, xvalue, xtb); + + if (!sipNotInMap(sipSelf)) + sipOMRemoveObject(&cppPyMap, sipSelf); + + /* This no longer points to anything useful. */ + sipSelf->u.cppPtr = NULL; + + /* + * If C/C++ has a reference (and therefore no parent) then remove it. + * Otherwise remove the object from any parent. + */ + if (sipCppHasRef(sipSelf)) + { + sipResetCppHasRef(sipSelf); + Py_DECREF(sipSelf); + } + else if (PyObject_TypeCheck((PyObject *)sipSelf, (PyTypeObject *)&sipWrapper_Type)) + removeFromParent((sipWrapper *)sipSelf); + + SIP_UNBLOCK_THREADS + } +} + + +/* + * Call self.__dtor__() if it is implemented. + */ +static void callPyDtor(sipSimpleWrapper *self) +{ + sip_gilstate_t sipGILState; + char pymc = 0; + PyObject *meth; + + meth = sip_api_is_py_method(&sipGILState, &pymc, self, NULL, "__dtor__"); + + if (meth != NULL) + { + PyObject *res = sip_api_call_method(0, meth, "", NULL); + + Py_DECREF(meth); + + /* Discard any result. */ + Py_XDECREF(res); + + /* Handle any error the best we can. */ + if (PyErr_Occurred()) + PyErr_Print(); + + SIP_RELEASE_GIL(sipGILState); + } +} + + +/* + * Add a wrapper to it's parent owner. The wrapper must not currently have a + * parent and, therefore, no siblings. + */ +static void addToParent(sipWrapper *self, sipWrapper *owner) +{ + if (owner->first_child != NULL) + { + self->sibling_next = owner->first_child; + owner->first_child->sibling_prev = self; + } + + owner->first_child = self; + self->parent = owner; + + /* + * The owner holds a real reference so that the cyclic garbage collector + * works properly. + */ + Py_INCREF((sipSimpleWrapper *)self); +} + + +/* + * Remove a wrapper from it's parent if it has one. + */ +static void removeFromParent(sipWrapper *self) +{ + if (self->parent != NULL) + { + if (self->parent->first_child == self) + self->parent->first_child = self->sibling_next; + + if (self->sibling_next != NULL) + self->sibling_next->sibling_prev = self->sibling_prev; + + if (self->sibling_prev != NULL) + self->sibling_prev->sibling_next = self->sibling_next; + + self->parent = NULL; + self->sibling_next = NULL; + self->sibling_prev = NULL; + + /* + * We must do this last, after all the pointers are correct, because + * this is used by the clear slot. + */ + Py_DECREF((sipSimpleWrapper *)self); + } +} + + +/* + * Convert a sequence index. Return the index or a negative value if there was + * an error. + */ +static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx, + SIP_SSIZE_T len) +{ + /* Negative indices start from the other end. */ + if (idx < 0) + idx = len + idx; + + if (idx < 0 || idx >= len) + { + PyErr_Format(PyExc_IndexError, "sequence index out of range"); + return -1; + } + + return idx; +} + + +/* + * Return a tuple of the base classes of a type that has no explicit + * super-type. + */ +static PyObject *getDefaultBases(void) +{ + static PyObject *default_bases = NULL; + + /* Only do this once. */ + if (default_bases == NULL) + { +#if PY_VERSION_HEX >= 0x02040000 + default_bases = PyTuple_Pack(1, (PyObject *)&sipWrapper_Type); +#else + default_bases = Py_BuildValue("(O)", &sipWrapper_Type); +#endif + + if (default_bases == NULL) + return NULL; + } + + Py_INCREF(default_bases); + + return default_bases; +} + + +/* + * Return the dictionary of a type. + */ +static PyObject *getScopeDict(sipTypeDef *td, PyObject *mod_dict, + sipExportedModuleDef *client) +{ + /* + * Initialise the scoping type if necessary. It will always be in the + * same module if it needs doing. + */ + if (sipTypeIsMapped(td)) + { + if (createMappedType(client, (sipMappedTypeDef *)td, mod_dict) < 0) + return NULL; + + /* Check that the mapped type can act as a container. */ + assert(sipTypeAsPyTypeObject(td) != NULL); + } + else + { + if (createClassType(client, (sipClassTypeDef *)td, mod_dict) < 0) + return NULL; + } + + return (sipTypeAsPyTypeObject(td))->tp_dict; +} + + +/* + * Create a container type and return a borrowed reference to it. + */ +static PyObject *createContainerType(sipContainerDef *cod, sipTypeDef *td, + PyObject *bases, PyObject *metatype, PyObject *mod_dict, + sipExportedModuleDef *client) +{ + PyObject *py_type, *scope_dict, *typedict, *name, *args; + + /* Get the dictionary to place the type in. */ + if (cod->cod_scope.sc_flag) + { + scope_dict = mod_dict; + } + else if ((scope_dict = getScopeDict(getGeneratedType(&cod->cod_scope, client), mod_dict, client)) == NULL) + goto reterr; + + /* Create the type dictionary. */ + if ((typedict = createTypeDict(client->em_nameobj)) == NULL) + goto reterr; + + /* Create an object corresponding to the type name. */ +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString(sipPyNameOfContainer(cod, td)); +#else + name = PyString_FromString(sipPyNameOfContainer(cod, td)); +#endif + + if (name == NULL) + goto reldict; + + /* Create the type by calling the metatype. */ +#if PY_VERSION_HEX >= 0x02040000 + args = PyTuple_Pack(3, name, bases, typedict); +#else + args = Py_BuildValue("OOO", name, bases, typedict); +#endif + + if (args == NULL) + goto relname; + + /* Pass the type via the back door. */ + currentType = td; + + if ((py_type = PyObject_Call(metatype, args, NULL)) == NULL) + goto relargs; + + /* Add the type to the "parent" dictionary. */ + if (PyDict_SetItem(scope_dict, name, py_type) < 0) + goto reltype; + + Py_DECREF(args); + Py_DECREF(name); + Py_DECREF(typedict); + + return py_type; + + /* Unwind on error. */ + +reltype: + Py_DECREF(py_type); + +relargs: + Py_DECREF(args); + +relname: + Py_DECREF(name); + +reldict: + Py_DECREF(typedict); + +reterr: + currentType = NULL; + return NULL; +} + + +/* + * Create a single class type object. + */ +static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd, + PyObject *mod_dict) +{ + PyObject *bases, *metatype, *py_type; + sipEncodedTypeDef *sup; + + /* Handle the trivial case where we have already been initialised. */ + if (ctd->ctd_base.td_module != NULL) + return 0; + + /* Set this up now to gain access to the string pool. */ + ctd->ctd_base.td_module = client; + + /* Create the tuple of super-types. */ + if ((sup = ctd->ctd_supers) == NULL) + { + if (ctd->ctd_supertype < 0) + { + bases = getDefaultBases(); + } + else + { + PyObject *supertype; + const char *supertype_name = sipNameFromPool(client, + ctd->ctd_supertype); + + if ((supertype = findPyType(supertype_name)) == NULL) + goto reterr; + +#if PY_VERSION_HEX >= 0x02040000 + bases = PyTuple_Pack(1, supertype); +#else + bases = Py_BuildValue("(O)", supertype); +#endif + } + + if (bases == NULL) + goto reterr; + } + else + { + int i, nrsupers = 0; + + do + ++nrsupers; + while (!sup++->sc_flag); + + if ((bases = PyTuple_New(nrsupers)) == NULL) + goto reterr; + + for (sup = ctd->ctd_supers, i = 0; i < nrsupers; ++i, ++sup) + { + PyObject *st; + sipTypeDef *sup_td = getGeneratedType(sup, client); + + /* + * Initialise the super-class if necessary. It will always be in + * the same module if it needs doing. + */ + if (createClassType(client, (sipClassTypeDef *)sup_td, mod_dict) < 0) + goto relbases; + + st = (PyObject *)sipTypeAsPyTypeObject(sup_td); + + Py_INCREF(st); + PyTuple_SET_ITEM(bases, i, st); + } + } + + /* + * Use the explicit meta-type if there is one, otherwise use the meta-type + * of the first super-type. + */ + if (ctd->ctd_metatype >= 0) + { + const char *metatype_name = sipNameFromPool(client, ctd->ctd_metatype); + + if ((metatype = findPyType(metatype_name)) == NULL) + goto relbases; + } + else + metatype = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(bases, 0)); + + if ((py_type = createContainerType(&ctd->ctd_container, (sipTypeDef *)ctd, bases, metatype, mod_dict, client)) == NULL) + goto relbases; + + /* Handle the pickle function. */ + if (ctd->ctd_pickle != NULL) + { + static PyMethodDef md = { + "_pickle_type", pickle_type, METH_NOARGS, NULL + }; + + if (setReduce((PyTypeObject *)py_type, &md) < 0) + goto reltype; + } + + /* We can now release our references. */ + Py_DECREF(bases); + + return 0; + + /* Unwind after an error. */ + +reltype: + Py_DECREF(py_type); + +relbases: + Py_DECREF(bases); + +reterr: + ctd->ctd_base.td_module = NULL; + return -1; +} + + +/* + * Create a single mapped type object. + */ +static int createMappedType(sipExportedModuleDef *client, + sipMappedTypeDef *mtd, PyObject *mod_dict) +{ + PyObject *bases; + + /* Handle the trivial case where we have already been initialised. */ + if (mtd->mtd_base.td_module != NULL) + return 0; + + /* Set this up now to gain access to the string pool. */ + mtd->mtd_base.td_module = client; + + /* Create the tuple of super-types. */ + if ((bases = getDefaultBases()) == NULL) + goto reterr; + + if (createContainerType(&mtd->mtd_container, (sipTypeDef *)mtd, bases, (PyObject *)&sipWrapperType_Type, mod_dict, client) == NULL) + goto relbases; + + /* We can now release our references. */ + Py_DECREF(bases); + + return 0; + + /* Unwind after an error. */ + +relbases: + Py_DECREF(bases); + +reterr: + mtd->mtd_base.td_module = NULL; + return -1; +} + + +/* + * Return the module definition for a named module. + */ +static sipExportedModuleDef *getModule(PyObject *mname_obj) +{ + PyObject *mod; + sipExportedModuleDef *em; + + /* Make sure the module is imported. */ + if ((mod = PyImport_Import(mname_obj)) == NULL) + return NULL; + + /* Find the module definition. */ + for (em = moduleList; em != NULL; em = em->em_next) +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Compare(mname_obj, em->em_nameobj) == 0) +#else + if (strcmp(PyString_AS_STRING(mname_obj), sipNameOfModule(em)) == 0) +#endif + break; + + Py_DECREF(mod); + + if (em == NULL) + { +#if PY_MAJOR_VERSION >= 3 + PyErr_Format(PyExc_SystemError, "unable to find to find module: %U", + mname_obj); +#else + PyErr_Format(PyExc_SystemError, "unable to find to find module: %s", + PyString_AS_STRING(mname_obj)); +#endif + } + + return em; +} + + +/* + * The type unpickler. + */ +static PyObject *unpickle_type(PyObject *ignore, PyObject *args) +{ + PyObject *mname_obj, *init_args; + const char *tname; + sipExportedModuleDef *em; + int i; + + if (!PyArg_ParseTuple(args, +#if PY_MAJOR_VERSION >= 3 + "UsO!:_unpickle_type", +#else + "SsO!:_unpickle_type", +#endif + &mname_obj, &tname, &PyTuple_Type, &init_args)) + return NULL; + + /* Get the module definition. */ + if ((em = getModule(mname_obj)) == NULL) + return NULL; + + /* Find the class type object. */ + for (i = 0; i < em->em_nrtypes; ++i) + { + sipTypeDef *td = em->em_types[i]; + + if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td)) + { + const char *pyname = sipPyNameOfContainer( + &((sipClassTypeDef *)td)->ctd_container, td); + + if (strcmp(pyname, tname) == 0) + return PyObject_CallObject((PyObject *)sipTypeAsPyTypeObject(td), init_args); + } + } + + PyErr_Format(PyExc_SystemError, "unable to find to find type: %s", tname); + + return NULL; +} + + +/* + * The type pickler. + */ +static PyObject *pickle_type(PyObject *obj, PyObject *ignore) +{ + sipExportedModuleDef *em; + + /* Find the type definition and defining module. */ + for (em = moduleList; em != NULL; em = em->em_next) + { + int i; + + for (i = 0; i < em->em_nrtypes; ++i) + { + sipTypeDef *td = em->em_types[i]; + + if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td)) + if (sipTypeAsPyTypeObject(td) == Py_TYPE(obj)) + { + PyObject *init_args; + sipClassTypeDef *ctd = (sipClassTypeDef *)td; + const char *pyname = sipPyNameOfContainer(&ctd->ctd_container, td); + + /* + * Ask the handwritten pickle code for the tuple of + * arguments that will recreate the object. + */ + init_args = ctd->ctd_pickle(sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, NULL)); + + if (!PyTuple_Check(init_args)) + { + PyErr_Format(PyExc_TypeError, + "%%PickleCode for type %s.%s did not return a tuple", + sipNameOfModule(em), pyname); + + return NULL; + } + + return Py_BuildValue("O(OsN)", type_unpickler, + em->em_nameobj, pyname, init_args); + } + } + } + + /* We should never get here. */ + PyErr_Format(PyExc_SystemError, "attempt to pickle unknown type '%s'", + Py_TYPE(obj)->tp_name); + + return NULL; +} + + +/* + * The enum unpickler. + */ +static PyObject *unpickle_enum(PyObject *ignore, PyObject *args) +{ + PyObject *mname_obj, *evalue_obj; + const char *ename; + sipExportedModuleDef *em; + int i; + + if (!PyArg_ParseTuple(args, +#if PY_MAJOR_VERSION >= 3 + "UsO:_unpickle_enum", +#else + "SsO:_unpickle_enum", +#endif + &mname_obj, &ename, &evalue_obj)) + return NULL; + + /* Get the module definition. */ + if ((em = getModule(mname_obj)) == NULL) + return NULL; + + /* Find the enum type object. */ + for (i = 0; i < em->em_nrtypes; ++i) + { + sipTypeDef *td = em->em_types[i]; + + if (td != NULL && !sipTypeIsStub(td) && sipTypeIsEnum(td)) + if (strcmp(sipPyNameOfEnum((sipEnumTypeDef *)td), ename) == 0) + return PyObject_CallFunctionObjArgs((PyObject *)sipTypeAsPyTypeObject(td), evalue_obj, NULL); + } + + PyErr_Format(PyExc_SystemError, "unable to find to find enum: %s", ename); + + return NULL; +} + + +/* + * The enum pickler. + */ +static PyObject *pickle_enum(PyObject *obj, PyObject *ignore) +{ + sipTypeDef *td = ((sipEnumTypeObject *)Py_TYPE(obj))->type; + + return Py_BuildValue("O(Osi)", enum_unpickler, td->td_module->em_nameobj, + sipPyNameOfEnum((sipEnumTypeDef *)td), +#if PY_MAJOR_VERSION >= 3 + (int)PyLong_AS_LONG(obj) +#else + (int)PyInt_AS_LONG(obj) +#endif + ); +} + + +/* + * Set the __reduce__method for a type. + */ +static int setReduce(PyTypeObject *type, PyMethodDef *pickler) +{ + static PyObject *rstr = NULL; + PyObject *descr; + int rc; + + if (objectify("__reduce__", &rstr) < 0) + return -1; + + /* Create the method descripter. */ + if ((descr = PyDescr_NewMethod(type, pickler)) == NULL) + return -1; + + /* + * Save the method. Note that we don't use PyObject_SetAttr() as we want + * to bypass any lazy attribute loading (which may not be safe yet). + */ + rc = PyType_Type.tp_setattro((PyObject *)type, rstr, descr); + + Py_DECREF(descr); + + return rc; +} + + +/* + * Create an enum type object. + */ +static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd, + PyObject *mod_dict) +{ + static PyObject *bases = NULL; + PyObject *name, *typedict, *args, *dict; + PyTypeObject *py_type; + + etd->etd_base.td_module = client; + + /* Get the dictionary into which the type will be placed. */ + if (etd->etd_scope < 0) + dict = mod_dict; + else if ((dict = getScopeDict(client->em_types[etd->etd_scope], mod_dict, client)) == NULL) + goto reterr; + + /* Create the base type tuple if it hasn't already been done. */ + if (bases == NULL) + { +#if PY_MAJOR_VERSION >= 3 + bases = PyTuple_Pack(1, (PyObject *)&PyLong_Type); +#elif PY_VERSION_HEX >= 0x02040000 + bases = PyTuple_Pack(1, (PyObject *)&PyInt_Type); +#else + bases = Py_BuildValue("(O)", &PyInt_Type); +#endif + + if (bases == NULL) + goto reterr; + } + + /* Create an object corresponding to the type name. */ +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString(sipPyNameOfEnum(etd)); +#else + name = PyString_FromString(sipPyNameOfEnum(etd)); +#endif + + if (name == NULL) + goto reterr; + + /* Create the type dictionary. */ + if ((typedict = createTypeDict(client->em_nameobj)) == NULL) + goto relname; + + /* Create the type by calling the metatype. */ +#if PY_VERSION_HEX >= 0x02040000 + args = PyTuple_Pack(3, name, bases, typedict); +#else + args = Py_BuildValue("OOO", name, bases, typedict); +#endif + + Py_DECREF(typedict); + + if (args == NULL) + goto relname; + + /* Pass the type via the back door. */ + currentType = &etd->etd_base; + + py_type = (PyTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type, args, NULL); + + Py_DECREF(args); + + if (py_type == NULL) + goto relname; + + /* Add the type to the "parent" dictionary. */ + if (PyDict_SetItem(dict, name, (PyObject *)py_type) < 0) + { + Py_DECREF((PyObject *)py_type); + goto relname; + } + + /* We can now release our remaining references. */ + Py_DECREF(name); + + return 0; + + /* Unwind after an error. */ + +relname: + Py_DECREF(name); + +reterr: + etd->etd_base.td_module = client; + return -1; +} + + +/* + * Create a type dictionary for dynamic type being created in the module with + * the specified name. + */ +static PyObject *createTypeDict(PyObject *mname) +{ + static PyObject *mstr = NULL; + PyObject *dict; + + if (objectify("__module__", &mstr) < 0) + return NULL; + + /* Create the dictionary. */ + if ((dict = PyDict_New()) == NULL) + return NULL; + + /* We need to set the module name as an attribute for dynamic types. */ + if (PyDict_SetItem(dict, mstr, mname) < 0) + { + Py_DECREF(dict); + return NULL; + } + + return dict; +} + + +/* + * Convert an ASCII string to a Python object if it hasn't already been done. + */ +static int objectify(const char *s, PyObject **objp) +{ + if (*objp == NULL) + { +#if PY_MAJOR_VERSION >= 3 + *objp = PyUnicode_FromString(s); +#else + *objp = PyString_FromString(s); +#endif + + if (*objp == NULL) + return -1; + } + + return 0; +} + + +/* + * Add a set of static instances to a dictionary. + */ +static int addInstances(PyObject *dict, sipInstancesDef *id) +{ + if (id->id_type != NULL && addTypeInstances(dict, id->id_type) < 0) + return -1; + + if (id->id_voidp != NULL && addVoidPtrInstances(dict,id->id_voidp) < 0) + return -1; + + if (id->id_char != NULL && addCharInstances(dict,id->id_char) < 0) + return -1; + + if (id->id_string != NULL && addStringInstances(dict,id->id_string) < 0) + return -1; + + if (id->id_int != NULL && addIntInstances(dict, id->id_int) < 0) + return -1; + + if (id->id_long != NULL && addLongInstances(dict,id->id_long) < 0) + return -1; + + if (id->id_ulong != NULL && addUnsignedLongInstances(dict, id->id_ulong) < 0) + return -1; + + if (id->id_llong != NULL && addLongLongInstances(dict, id->id_llong) < 0) + return -1; + + if (id->id_ullong != NULL && addUnsignedLongLongInstances(dict, id->id_ullong) < 0) + return -1; + + if (id->id_double != NULL && addDoubleInstances(dict,id->id_double) < 0) + return -1; + + return 0; +} + + +/* + * Get "self" from the argument tuple for a method called as + * Class.Method(self, ...) rather than self.Method(...). + */ +static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr, + sipSimpleWrapper **selfp) +{ + PyObject *self; + + /* Get self from the argument tuple. */ + + if (argnr >= PyTuple_GET_SIZE(args)) + return FALSE; + + self = PyTuple_GET_ITEM(args, argnr); + + if (!PyObject_TypeCheck(self, sipTypeAsPyTypeObject(td))) + return FALSE; + + *selfp = (sipSimpleWrapper *)self; + + return TRUE; +} + + +/* + * Populate a container's type dictionary. + */ +static int add_lazy_container_attrs(sipTypeDef *td, sipContainerDef *cod, + PyObject *dict) +{ + int i; + PyMethodDef *pmd; + sipEnumMemberDef *enm; + sipVariableDef *vd; + + /* Do the methods. */ + pmd = cod->cod_methods; + + for (i = 0; i < cod->cod_nrmethods; ++i) + { + int rc; + PyObject *descr; + + if ((descr = sipMethodDescr_New(pmd)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, pmd->ml_name, descr); + + Py_DECREF(descr); + + if (rc < 0) + return -1; + + ++pmd; + } + + /* Do the enum members. */ + enm = cod->cod_enummembers; + + for (i = 0; i < cod->cod_nrenummembers; ++i) + { + int rc; + PyObject *val; + + if ((val = createEnumMember(td, enm)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, enm->em_name, val); + + Py_DECREF(val); + + if (rc < 0) + return -1; + + ++enm; + } + + /* Do the variables. */ + vd = cod->cod_variables; + + for (i = 0; i < cod->cod_nrvariables; ++i) + { + int rc; + PyObject *descr; + + if ((descr = sipVariableDescr_New(vd, td, cod)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, vd->vd_name, descr); + + Py_DECREF(descr); + + if (rc < 0) + return -1; + + ++vd; + } + + return 0; +} + + +/* + * Populate a type dictionary with all lazy attributes if it hasn't already + * been done. + */ +static int add_lazy_attrs(sipTypeDef *td) +{ + sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td); + PyObject *dict; + sipAttrGetter *ag; + + /* Handle the trivial case. */ + if (wt->dict_complete) + return 0; + + dict = ((PyTypeObject *)wt)->tp_dict; + + if (sipTypeIsMapped(td)) + { + if (add_lazy_container_attrs(td, &((sipMappedTypeDef *)td)->mtd_container, dict) < 0) + return -1; + } + else + { + sipClassTypeDef *nsx; + + /* Search the possible linked list of namespace extenders. */ + for (nsx = (sipClassTypeDef *)td; nsx != NULL; nsx = nsx->ctd_nsextender) + if (add_lazy_container_attrs((sipTypeDef *)nsx, &nsx->ctd_container, dict) < 0) + return -1; + } + + /* + * Get any lazy attributes from registered getters. This must be done last + * to allow any existing attributes to be replaced. + */ + for (ag = sipAttrGetters; ag != NULL; ag = ag->next) + if (ag->type == NULL || PyType_IsSubtype((PyTypeObject *)wt, ag->type)) + if (ag->getter(td, dict) < 0) + return -1; + + wt->dict_complete = TRUE; + + return 0; +} + + +/* + * Populate the type dictionary and all its super-types. + */ +static int add_all_lazy_attrs(sipTypeDef *td) +{ + if (td == NULL) + return 0; + + if (add_lazy_attrs(td) < 0) + return -1; + + if (sipTypeIsClass(td)) + { + sipClassTypeDef *ctd = (sipClassTypeDef *)td; + sipEncodedTypeDef *sup; + + if ((sup = ctd->ctd_supers) != NULL) + do + { + sipTypeDef *sup_td = getGeneratedType(sup, td->td_module); + + if (add_all_lazy_attrs(sup_td) < 0) + return -1; + } + while (!sup++->sc_flag); + } + + return 0; +} + + +/* + * Return the generated type structure corresponding to the given Python type + * object. + */ +static const sipTypeDef *sip_api_type_from_py_type_object(PyTypeObject *py_type) +{ + if (PyObject_TypeCheck((PyObject *)py_type, &sipWrapperType_Type)) + return ((sipWrapperType *)py_type)->type; + + if (PyObject_TypeCheck((PyObject *)py_type, &sipEnumType_Type)) + return ((sipEnumTypeObject *)py_type)->type; + + return NULL; +} + + +/* + * Return the generated type structure corresponding to the scope of the given + * type. + */ +static const sipTypeDef *sip_api_type_scope(const sipTypeDef *td) +{ + if (sipTypeIsEnum(td)) + { + const sipEnumTypeDef *etd = (const sipEnumTypeDef *)td; + + if (etd->etd_scope >= 0) + return td->td_module->em_types[etd->etd_scope]; + } + else + { + const sipContainerDef *cod; + + if (sipTypeIsMapped(td)) + cod = &((const sipMappedTypeDef *)td)->mtd_container; + else + cod = &((const sipClassTypeDef *)td)->ctd_container; + + if (!cod->cod_scope.sc_flag) + return getGeneratedType(&cod->cod_scope, td->td_module); + } + + return NULL; +} + + +/* + * Return TRUE if an object can be converted to a named enum. + */ +static int sip_api_can_convert_to_enum(PyObject *obj, const sipTypeDef *td) +{ + assert(sipTypeIsEnum(td)); + + /* If the object is an enum then it must be the right enum. */ + if (PyObject_TypeCheck((PyObject *)Py_TYPE(obj), &sipEnumType_Type)) + return (PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(td))); + +#if PY_MAJOR_VERSION >= 3 + return PyLong_Check(obj); +#else + return PyInt_Check(obj); +#endif +} + + +/* + * Create a Python object for an enum member. + */ +static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm) +{ + if (enm->em_enum < 0) +#if PY_MAJOR_VERSION >= 3 + return PyLong_FromLong(enm->em_val); +#else + return PyInt_FromLong(enm->em_val); +#endif + + return sip_api_convert_from_enum(enm->em_val, + td->td_module->em_types[enm->em_enum]); +} + + +/* + * Create a Python object for a member of a named enum. + */ +static PyObject *sip_api_convert_from_enum(int eval, const sipTypeDef *td) +{ + assert(sipTypeIsEnum(td)); + + return PyObject_CallFunction((PyObject *)sipTypeAsPyTypeObject(td), "(i)", + eval); +} + + +/* + * Register a getter for unknown attributes. + */ +static int sip_api_register_attribute_getter(const sipTypeDef *td, + sipAttrGetterFunc getter) +{ + sipAttrGetter *ag = sip_api_malloc(sizeof (sipAttrGetter)); + + if (ag == NULL) + return -1; + + ag->type = sipTypeAsPyTypeObject(td); + ag->getter = getter; + ag->next = sipAttrGetters; + + sipAttrGetters = ag; + + return 0; +} + + +/* + * Report a function with invalid argument types. + */ +static void sip_api_no_function(PyObject *parseErr, const char *func, + const char *doc) +{ + sip_api_no_method(parseErr, NULL, func, doc); +} + + +/* + * Report a method/function/signal with invalid argument types. + */ +static void sip_api_no_method(PyObject *parseErr, const char *scope, + const char *method, const char *doc) +{ + const char *sep = "."; + + if (scope == NULL) + scope = ++sep; + + if (parseErr == NULL) + { + /* + * If we have got this far without trying a parse then there must be no + * overloads. + */ + PyErr_Format(PyExc_TypeError, "%s%s%s() is a private method", scope, + sep, method); + } + else if (PyList_Check(parseErr)) + { + PyObject *exc; + + /* There is an entry for each overload that was tried. */ + if (PyList_GET_SIZE(parseErr) == 1) + { + PyObject *detail = detail_FromFailure( + PyList_GET_ITEM(parseErr, 0)); + + if (detail != NULL) + { + if (doc != NULL) + { + PyObject *doc_obj = signature_FromDocstring(doc, 0); + + if (doc_obj != NULL) + { +#if PY_MAJOR_VERSION >= 3 + exc = PyUnicode_FromFormat("%U: %U", doc_obj, detail); +#else + exc = PyString_FromFormat("%s: %s", + PyString_AS_STRING(doc_obj), + PyString_AS_STRING(detail)); +#endif + + Py_DECREF(doc_obj); + } + else + { + exc = NULL; + } + } + else + { +#if PY_MAJOR_VERSION >= 3 + exc = PyUnicode_FromFormat("%s%s%s(): %U", scope, sep, + method, detail); +#else + exc = PyString_FromFormat("%s%s%s(): %s", scope, sep, + method, PyString_AS_STRING(detail)); +#endif + } + + Py_DECREF(detail); + } + else + { + exc = NULL; + } + } + else + { + static const char *summary = "arguments did not match any overloaded call:"; + + SIP_SSIZE_T i; + + if (doc != NULL) + { +#if PY_MAJOR_VERSION >= 3 + exc = PyUnicode_FromString(summary); +#else + exc = PyString_FromString(summary); +#endif + } + else + { +#if PY_MAJOR_VERSION >= 3 + exc = PyUnicode_FromFormat("%s%s%s(): %s", scope, sep, method, + summary); +#else + exc = PyString_FromFormat("%s%s%s(): %s", scope, sep, method, + summary); +#endif + } + + for (i = 0; i < PyList_GET_SIZE(parseErr); ++i) + { + PyObject *failure; + PyObject *detail = detail_FromFailure( + PyList_GET_ITEM(parseErr, i)); + + if (detail != NULL) + { + if (doc != NULL) + { + PyObject *doc_obj = signature_FromDocstring(doc, i); + + if (doc_obj != NULL) + { +#if PY_MAJOR_VERSION >= 3 + failure = PyUnicode_FromFormat("\n %U: %U", + doc_obj, detail); +#else + failure = PyString_FromFormat("\n %s: %s", + PyString_AS_STRING(doc_obj), + PyString_AS_STRING(detail)); +#endif + + Py_DECREF(doc_obj); + } + else + { + Py_XDECREF(exc); + exc = NULL; + break; + } + } + 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)); +#else + failure = PyString_FromFormat("\n overload %d: %s", + i + 1, PyString_AS_STRING(detail)); +#endif + } + + Py_DECREF(detail); + +#if PY_MAJOR_VERSION >= 3 + PyUnicode_AppendAndDel(&exc, failure); +#else + PyString_ConcatAndDel(&exc, failure); +#endif + } + else + { + Py_XDECREF(exc); + exc = NULL; + break; + } + } + } + + if (exc != NULL) + { + PyErr_SetObject(PyExc_TypeError, exc); + Py_DECREF(exc); + } + } + else + { + /* + * None is used as a marker to say that an exception has already been + * raised. This won't show which overload we were parsing but it + * doesn't really matter as it is a fundamental problem rather than a + * user error. + */ + assert(parseErr == Py_None); + } + + Py_XDECREF(parseErr); +} + + +/* + * Return a string/unicode object extracted from a particular line of a + * docstring. + */ +static PyObject *signature_FromDocstring(const char *doc, SIP_SSIZE_T line) +{ + const char *eol; + SIP_SSIZE_T size = 0; + + /* + * Find the start of the line. If there is a non-default versioned + * overload that has been enabled then it won't have an entry in the + * docstring. This means that the returned signature may be incorrect. + */ + while (line-- > 0) + { + const char *next = strchr(doc, '\n'); + + if (next == NULL) + break; + + doc = next + 1; + } + + /* Find the last closing parenthesis. */ + for (eol = doc; *eol != '\n' && *eol != '\0'; ++eol) + if (*eol == ')') + size = eol - doc + 1; + +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_FromStringAndSize(doc, size); +#else + return PyString_FromStringAndSize(doc, size); +#endif +} + + +/* + * Return a string/unicode object that describes the given failure. + */ +static PyObject *detail_FromFailure(PyObject *failure_obj) +{ + sipParseFailure *failure; + PyObject *detail; + +#if defined(SIP_USE_PYCAPSULE) + failure = (sipParseFailure *)PyCapsule_GetPointer(failure_obj, NULL); +#else + failure = (sipParseFailure *)PyCObject_AsVoidPtr(failure_obj); +#endif + + switch (failure->reason) + { + case Unbound: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromFormat( + "first argument of unbound method must have type '%s'", + failure->detail_str); +#else + detail = PyString_FromFormat( + "first argument of unbound method must have type '%s'", + failure->detail_str); +#endif + break; + + case TooFew: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromString("not enough arguments"); +#else + detail = PyString_FromString("not enough arguments"); +#endif + break; + + case TooMany: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromString("too many arguments"); +#else + detail = PyString_FromString("too many arguments"); +#endif + break; + + case KeywordNotString: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromFormat( + "%S keyword argument name is not a string", + failure->detail_obj); +#else + { + PyObject *str = PyObject_Str(failure->detail_obj); + + if (str != NULL) + { + detail = PyString_FromFormat( + "%s keyword argument name is not a string", + PyString_AsString(str)); + + Py_DECREF(str); + } + else + { + detail = NULL; + } + } +#endif + break; + + case UnknownKeyword: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromFormat("'%U' is not a valid keyword argument", + failure->detail_obj); +#else + detail = PyString_FromFormat("'%s' is not a valid keyword argument", + PyString_AS_STRING(failure->detail_obj)); +#endif + break; + + case Duplicate: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromFormat( + "'%U' has already been given as a positional argument", + failure->detail_obj); +#else + detail = PyString_FromFormat( + "'%s' has already been given as a positional argument", + PyString_AS_STRING(failure->detail_obj)); +#endif + break; + + case WrongType: + if (failure->arg_nr >= 0) + { + detail = bad_type_str(failure->arg_nr, failure->detail_obj); + } + else + { +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromFormat( + "keyword argument '%s' has unexpected type '%s'", + failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name); +#else + detail = PyString_FromFormat( + "keyword argument '%s' has unexpected type '%s'", + failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name); +#endif + } + + break; + + case Exception: + detail = failure->detail_obj; + + if (detail) + { + Py_INCREF(detail); + break; + } + + /* Drop through. */ + + default: +#if PY_MAJOR_VERSION >= 3 + detail = PyUnicode_FromString("unknown reason"); +#else + detail = PyString_FromString("unknown reason"); +#endif + } + + return detail; +} + + +/* + * Report an abstract method called with an unbound self. + */ +static void sip_api_abstract_method(const char *classname, const char *method) +{ + PyErr_Format(PyExc_TypeError, + "%s.%s() is abstract and cannot be called as an unbound method", + classname, method); +} + + +/* + * Report a deprecated class or method. + */ +static int sip_api_deprecated(const char *classname, const char *method) +{ + char buf[100]; + + if (classname == NULL) + PyOS_snprintf(buf, sizeof (buf), "%s() is deprecated", method); + else if (method == NULL) + PyOS_snprintf(buf, sizeof (buf), "%s constructor is deprecated", + classname); + else + PyOS_snprintf(buf, sizeof (buf), "%s.%s() is deprecated", classname, + method); + +#if PY_VERSION_HEX >= 0x02050000 + return PyErr_WarnEx(PyExc_DeprecationWarning, buf, 1); +#else + return PyErr_Warn(PyExc_DeprecationWarning, buf); +#endif +} + + +/* + * Report a bad operator argument. Only a small subset of operators need to + * be handled (those that don't return Py_NotImplemented). + */ +static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg, + sipPySlotType st) +{ + const char *sn = NULL; + + /* Try and get the text to match a Python exception. */ + + switch (st) + { + case concat_slot: + case iconcat_slot: + PyErr_Format(PyExc_TypeError, + "cannot concatenate '%s' and '%s' objects", + Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name); + break; + + case repeat_slot: + sn = "*"; + break; + + case irepeat_slot: + sn = "*="; + break; + + default: + sn = "unknown"; + } + + if (sn != NULL) + PyErr_Format(PyExc_TypeError, + "unsupported operand type(s) for %s: '%s' and '%s'", sn, + Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name); +} + + +/* + * Report a sequence length that does not match the length of a slice. + */ +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 + seqlen, slicelen); +} + + +/* + * Report a Python object that cannot be converted to a particular class. + */ +static void sip_api_bad_class(const char *classname) +{ + PyErr_Format(PyExc_TypeError, + "cannot convert Python object to an instance of %s", classname); +} + + +/* + * Report a Python member function with an unexpected return type. + */ +static void sip_api_bad_catcher_result(PyObject *method) +{ + PyObject *mname; + + /* + * This is part of the public API so we make no assumptions about the + * method object. + */ + if (!PyMethod_Check(method) || + PyMethod_GET_FUNCTION(method) == NULL || + !PyFunction_Check(PyMethod_GET_FUNCTION(method)) || + PyMethod_GET_SELF(method) == NULL) + { + PyErr_Format(PyExc_TypeError, + "invalid argument to sipBadCatcherResult()"); + return; + } + + mname = ((PyFunctionObject *)PyMethod_GET_FUNCTION(method))->func_name; + +#if PY_MAJOR_VERSION >= 3 + PyErr_Format(PyExc_TypeError, "invalid result type from %s.%U()", + Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname); +#else + PyErr_Format(PyExc_TypeError, "invalid result type from %s.%s()", + Py_TYPE(PyMethod_GET_SELF(method))->tp_name, + PyString_AsString(mname)); +#endif +} + + +/* + * Transfer ownership of a class instance to Python from C/C++. + */ +static void sip_api_transfer_back(PyObject *self) +{ + if (self != NULL && PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type)) + { + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + if (sipCppHasRef(sw)) + { + sipResetCppHasRef(sw); + Py_DECREF(sw); + } + else + removeFromParent((sipWrapper *)sw); + + sipSetPyOwned(sw); + } +} + + +/* + * Break the association of a C++ owned Python object with any parent. + */ +static void sip_api_transfer_break(PyObject *self) +{ + if (self != NULL && PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type)) + { + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + if (sipCppHasRef(sw)) + { + sipResetCppHasRef(sw); + Py_DECREF(sw); + } + else + removeFromParent((sipWrapper *)sw); + } +} + + +/* + * Transfer ownership of a class instance to C/C++ from Python. + */ +static void sip_api_transfer_to(PyObject *self, PyObject *owner) +{ + /* + * There is a legitimate case where we try to transfer a PyObject that + * may not be a SIP generated class. The virtual handler code calls + * this function to keep the C/C++ instance alive when it gets rid of + * the Python object returned by the Python method. A class may have + * handwritten code that converts a regular Python type - so we can't + * assume that we can simply cast to sipWrapper. + */ + if (self != NULL && + PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type) && + (owner == NULL || + PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type))) + { + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + /* + * Keep the object alive while we do the transfer. If C++ has a + * reference then there is no need to increment it, just reset the flag + * and the following decrement will bring everything back to the way it + * should be. + */ + if (sipCppHasRef(sw)) + sipResetCppHasRef(sw); + else + { + Py_INCREF(sw); + removeFromParent((sipWrapper *)sw); + } + + if (owner != NULL) + addToParent((sipWrapper *)sw, (sipWrapper *)owner); + + Py_DECREF(sw); + + sipResetPyOwned(sw); + } +} + + +/* + * Add a license to a dictionary. + */ +static int addLicense(PyObject *dict,sipLicenseDef *lc) +{ + int rc; + PyObject *ldict, *proxy, *o; + + /* Convert the strings we use to objects if not already done. */ + + if (objectify("__license__", &licenseName) < 0) + return -1; + + if (objectify("Licensee", &licenseeName) < 0) + return -1; + + if (objectify("Type", &typeName) < 0) + return -1; + + if (objectify("Timestamp", ×tampName) < 0) + return -1; + + if (objectify("Signature", &signatureName) < 0) + return -1; + + /* We use a dictionary to hold the license information. */ + if ((ldict = PyDict_New()) == NULL) + return -1; + + /* The license type is compulsory, the rest are optional. */ + if (lc->lc_type == NULL) + goto deldict; + +#if PY_MAJOR_VERSION >= 3 + o = PyUnicode_FromString(lc->lc_type); +#else + o = PyString_FromString(lc->lc_type); +#endif + + if (o == NULL) + goto deldict; + + rc = PyDict_SetItem(ldict,typeName,o); + Py_DECREF(o); + + if (rc < 0) + goto deldict; + + if (lc->lc_licensee != NULL) + { +#if PY_MAJOR_VERSION >= 3 + o = PyUnicode_FromString(lc->lc_licensee); +#else + o = PyString_FromString(lc->lc_licensee); +#endif + + if (o == NULL) + goto deldict; + + rc = PyDict_SetItem(ldict,licenseeName,o); + Py_DECREF(o); + + if (rc < 0) + goto deldict; + } + + if (lc->lc_timestamp != NULL) + { +#if PY_MAJOR_VERSION >= 3 + o = PyUnicode_FromString(lc->lc_timestamp); +#else + o = PyString_FromString(lc->lc_timestamp); +#endif + + if (o == NULL) + goto deldict; + + rc = PyDict_SetItem(ldict,timestampName,o); + Py_DECREF(o); + + if (rc < 0) + goto deldict; + } + + if (lc->lc_signature != NULL) + { +#if PY_MAJOR_VERSION >= 3 + o = PyUnicode_FromString(lc->lc_signature); +#else + o = PyString_FromString(lc->lc_signature); +#endif + + if (o == NULL) + goto deldict; + + rc = PyDict_SetItem(ldict,signatureName,o); + Py_DECREF(o); + + if (rc < 0) + goto deldict; + } + + /* Create a read-only proxy. */ + if ((proxy = PyDictProxy_New(ldict)) == NULL) + goto deldict; + + Py_DECREF(ldict); + + rc = PyDict_SetItem(dict, licenseName, proxy); + Py_DECREF(proxy); + + return rc; + +deldict: + Py_DECREF(ldict); + + return -1; +} + + +/* + * Add the void pointer instances to a dictionary. + */ +static int addVoidPtrInstances(PyObject *dict,sipVoidPtrInstanceDef *vi) +{ + while (vi->vi_name != NULL) + { + int rc; + PyObject *w; + + if ((w = sip_api_convert_from_void_ptr(vi->vi_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,vi->vi_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++vi; + } + + return 0; +} + + +/* + * Add the char instances to a dictionary. + */ +static int addCharInstances(PyObject *dict, sipCharInstanceDef *ci) +{ + while (ci->ci_name != NULL) + { + int rc; + PyObject *w; + + switch (ci->ci_encoding) + { + case 'A': + w = PyUnicode_DecodeASCII(&ci->ci_val, 1, NULL); + break; + + case 'L': + w = PyUnicode_DecodeLatin1(&ci->ci_val, 1, NULL); + break; + + case '8': +#if PY_MAJOR_VERSION >= 3 + w = PyUnicode_FromStringAndSize(&ci->ci_val, 1); +#else + w = PyUnicode_DecodeUTF8(&ci->ci_val, 1, NULL); +#endif + break; + + default: + w = SIPBytes_FromStringAndSize(&ci->ci_val, 1); + } + + if (w == NULL) + return -1; + + rc = PyDict_SetItemString(dict, ci->ci_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ci; + } + + return 0; +} + + +/* + * Add the string instances to a dictionary. + */ +static int addStringInstances(PyObject *dict, sipStringInstanceDef *si) +{ + while (si->si_name != NULL) + { + int rc; + PyObject *w; + + switch (si->si_encoding) + { + case 'A': + w = PyUnicode_DecodeASCII(si->si_val, strlen(si->si_val), NULL); + break; + + case 'L': + w = PyUnicode_DecodeLatin1(si->si_val, strlen(si->si_val), NULL); + break; + + case '8': +#if PY_MAJOR_VERSION >= 3 + w = PyUnicode_FromString(si->si_val); +#else + w = PyUnicode_DecodeUTF8(si->si_val, strlen(si->si_val), NULL); +#endif + break; + + default: + w = SIPBytes_FromString(si->si_val); + } + + if (w == NULL) + return -1; + + rc = PyDict_SetItemString(dict, si->si_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++si; + } + + return 0; +} + + +/* + * Add the int instances to a dictionary. + */ +static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii) +{ + while (ii->ii_name != NULL) + { + int rc; + PyObject *w; + +#if PY_MAJOR_VERSION >= 3 + w = PyLong_FromLong(ii->ii_val); +#else + w = PyInt_FromLong(ii->ii_val); +#endif + + if (w == NULL) + return -1; + + rc = PyDict_SetItemString(dict, ii->ii_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ii; + } + + return 0; +} + + +/* + * Add the long instances to a dictionary. + */ +static int addLongInstances(PyObject *dict,sipLongInstanceDef *li) +{ + while (li->li_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyLong_FromLong(li->li_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,li->li_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++li; + } + + return 0; +} + + +/* + * Add the unsigned long instances to a dictionary. + */ +static int addUnsignedLongInstances(PyObject *dict, sipUnsignedLongInstanceDef *uli) +{ + while (uli->uli_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyLong_FromUnsignedLong(uli->uli_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, uli->uli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++uli; + } + + return 0; +} + + +/* + * Add the long long instances to a dictionary. + */ +static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli) +{ + while (lli->lli_name != NULL) + { + int rc; + PyObject *w; + +#if defined(HAVE_LONG_LONG) + if ((w = PyLong_FromLongLong(lli->lli_val)) == NULL) +#else + if ((w = PyLong_FromLong(lli->lli_val)) == NULL) +#endif + return -1; + + rc = PyDict_SetItemString(dict, lli->lli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++lli; + } + + return 0; +} + + +/* + * Add the unsigned long long instances to a dictionary. + */ +static int addUnsignedLongLongInstances(PyObject *dict, sipUnsignedLongLongInstanceDef *ulli) +{ + while (ulli->ulli_name != NULL) + { + int rc; + PyObject *w; + +#if defined(HAVE_LONG_LONG) + if ((w = PyLong_FromUnsignedLongLong(ulli->ulli_val)) == NULL) +#else + if ((w = PyLong_FromUnsignedLong(ulli->ulli_val)) == NULL) +#endif + return -1; + + rc = PyDict_SetItemString(dict, ulli->ulli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ulli; + } + + return 0; +} + + +/* + * Add the double instances to a dictionary. + */ +static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di) +{ + while (di->di_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyFloat_FromDouble(di->di_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,di->di_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++di; + } + + return 0; +} + + +/* + * Wrap a set of type instances and add them to a dictionary. + */ +static int addTypeInstances(PyObject *dict, sipTypeInstanceDef *ti) +{ + while (ti->ti_name != NULL) + { + if (addSingleTypeInstance(dict, ti->ti_name, ti->ti_ptr, *ti->ti_type, ti->ti_flags) < 0) + return -1; + + ++ti; + } + + return 0; +} + + +/* + * Wrap a single type instance and add it to a dictionary. + */ +static int addSingleTypeInstance(PyObject *dict, const char *name, + void *cppPtr, const sipTypeDef *td, int initflags) +{ + int rc; + PyObject *obj; + + if (sipTypeIsClass(td)) + { + obj = sipWrapSimpleInstance(cppPtr, td, NULL, initflags); + } + else if (sipTypeIsEnum(td)) + { + obj = sip_api_convert_from_enum(*(int *)cppPtr, td); + } + else + { + assert(sipTypeIsMapped(td)); + + obj = ((const sipMappedTypeDef *)td)->mtd_cfrom(cppPtr, NULL); + } + + if (obj == NULL) + return -1; + + rc = PyDict_SetItemString(dict, name, obj); + Py_DECREF(obj); + + return rc; +} + + +/* + * Convert a type instance and add it to a dictionary. + */ +static int sip_api_add_type_instance(PyObject *dict, const char *name, + void *cppPtr, const sipTypeDef *td) +{ + return addSingleTypeInstance(getDictFromObject(dict), name, cppPtr, td, 0); +} + + +/* + * Return the instance dictionary for an object if it is a wrapped type. + * Otherwise assume that it is a module dictionary. + */ +static PyObject *getDictFromObject(PyObject *obj) +{ + if (PyObject_TypeCheck(obj, (PyTypeObject *)&sipWrapperType_Type)) + obj = ((PyTypeObject *)obj)->tp_dict; + + return obj; +} + + +/* + * Return a Python reimplementation corresponding to a C/C++ virtual function, + * if any. If one was found then the Python lock is acquired. + */ +static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper *sipSelf, const char *cname, const char *mname) +{ + PyObject *mname_obj, *reimp, *mro, *cls; + SIP_SSIZE_T i; + + + /* + * This is the most common case (where there is no Python reimplementation) + * so we take a fast shortcut without acquiring the GIL. + */ + if (*pymc != 0) + return NULL; + + /* We might still have C++ going after the interpreter has gone. */ + if (sipInterpreter == NULL) + return NULL; + + /* + * It's possible that the Python object has been deleted but the underlying + * C++ instance is still working and trying to handle virtual functions. + * Alternatively, an instance has started handling virtual functions before + * its ctor has returned. In either case say there is no Python + * reimplementation. + */ + if (sipSelf == NULL) + return NULL; + + /* Get any reimplementation. */ + +#ifdef WITH_THREAD + *gil = PyGILState_Ensure(); +#endif + +#if PY_MAJOR_VERSION >= 3 + mname_obj = PyUnicode_FromString(mname); +#else + mname_obj = PyString_FromString(mname); +#endif + + if (mname_obj == NULL) + { +#ifdef WITH_THREAD + PyGILState_Release(*gil); +#endif + return NULL; + } + + /* + * We don't use PyObject_GetAttr() because that might find the generated + * C function before a reimplementation defined in a mixin (ie. later in + * the MRO). + */ + + if (sipSelf->dict != NULL) + { + /* Check the instance dictionary in case it has been monkey patched. */ + if ((reimp = PyDict_GetItem(sipSelf->dict, mname_obj)) != NULL && PyCallable_Check(reimp)) + { + Py_DECREF(mname_obj); + + Py_INCREF(reimp); + return reimp; + } + } + + cls = (PyObject *)Py_TYPE(sipSelf); + mro = ((PyTypeObject *)cls)->tp_mro; + assert(PyTuple_Check(mro)); + + reimp = NULL; + + for (i = 0; i < PyTuple_GET_SIZE(mro); ++i) + { + PyObject *cls_dict; + + cls = PyTuple_GET_ITEM(mro, i); + +#if PY_MAJOR_VERSION >= 3 + cls_dict = ((PyTypeObject *)cls)->tp_dict; +#else + // Allow for classic classes as mixins. + if (PyClass_Check(cls)) + cls_dict = ((PyClassObject *)cls)->cl_dict; + else + cls_dict = ((PyTypeObject *)cls)->tp_dict; +#endif + + if (cls_dict != NULL && (reimp = PyDict_GetItem(cls_dict, mname_obj)) != NULL) + { + /* + * Check any reimplementation is Python code and is not the wrapped + * C++ method. + */ + if (PyMethod_Check(reimp)) + { + /* It's already a method but make sure it is bound. */ + if (PyMethod_GET_SELF(reimp) != NULL) + { + Py_INCREF(reimp); + } + else + { +#if PY_MAJOR_VERSION >= 3 + reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp), + (PyObject *)sipSelf); +#else + reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp), + (PyObject *)sipSelf, PyMethod_GET_CLASS(reimp)); +#endif + } + + break; + } + + if (PyFunction_Check(reimp)) + { +#if PY_MAJOR_VERSION >= 3 + reimp = PyMethod_New(reimp, (PyObject *)sipSelf); +#else + reimp = PyMethod_New(reimp, (PyObject *)sipSelf, cls); +#endif + + break; + } + + reimp = NULL; + } + } + + Py_DECREF(mname_obj); + + if (reimp == NULL) + { + /* Use the fast track in future. */ + *pymc = 1; + + if (cname != NULL) + { + /* Note that this will only be raised once per method. */ + PyErr_Format(PyExc_NotImplementedError, + "%s.%s() is abstract and must be overridden", cname, + mname); + PyErr_Print(); + } + +#ifdef WITH_THREAD + PyGILState_Release(*gil); +#endif + } + + return reimp; +} + + +/* + * Convert a C/C++ pointer to the object that wraps it. + */ +static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td) +{ + return (PyObject *)sipOMFindObject(&cppPyMap, cppPtr, td); +} + + +/* + * Return the C/C++ pointer from a wrapper without any checks. + */ +void *sipGetAddress(sipSimpleWrapper *sw) +{ + if (sipIsAccessFunc(sw)) + return (*sw->u.afPtr)(); + + if (sipIsIndirect(sw)) + return *((void **)sw->u.cppPtr); + + return sw->u.cppPtr; +} + + +/* + * Get the C/C++ pointer for a complex object. Note that not casting the C++ + * pointer is a bug. However this is only ever called by PyQt3 signal emitter + * code and PyQt doesn't contain anything that multiply inherits from QObject. + */ +static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw) +{ + return getComplexCppPtr(sw, NULL); +} + + +/* + * Get the C/C++ pointer for a complex object and optionally cast it to the + * required type. + */ +static void *getComplexCppPtr(sipSimpleWrapper *sw, const sipTypeDef *td) +{ + if (!sipIsDerived(sw)) + { + PyErr_SetString(PyExc_RuntimeError, + "no access to protected functions or signals for objects not created from Python"); + + return NULL; + } + + return sip_api_get_cpp_ptr(sw, td); +} + + +/* + * Get the C/C++ pointer from a wrapper and optionally cast it to the required + * type. + */ +void *sip_api_get_cpp_ptr(sipSimpleWrapper *sw, const sipTypeDef *td) +{ + void *ptr = sipGetAddress(sw); + + if (checkPointer(ptr) < 0) + return NULL; + + if (td != NULL) + { + ptr = cast_cpp_ptr(ptr, Py_TYPE(sw), td); + + if (ptr == NULL) + PyErr_Format(PyExc_TypeError, "could not convert '%s' to '%s'", + Py_TYPE(sw)->tp_name, + sipPyNameOfContainer(&((const sipClassTypeDef *)td)->ctd_container, td)); + } + + return ptr; +} + + +/* + * Cast a C/C++ pointer from a source type to a destination type. + */ +static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type, + const sipTypeDef *dst_type) +{ + sipCastFunc cast = ((const sipClassTypeDef *)((sipWrapperType *)src_type)->type)->ctd_cast; + + /* C structures don't have cast functions. */ + if (cast != NULL) + ptr = (*cast)(ptr, dst_type); + + return ptr; +} + + +/* + * Check that a pointer is non-NULL. + */ +static int checkPointer(void *ptr) +{ + if (ptr == NULL) + { + PyErr_SetString(PyExc_RuntimeError, + "underlying C/C++ object has been deleted"); + return -1; + } + + return 0; +} + + +/* + * Keep an extra reference to an object. + */ +static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj) +{ + PyObject *dict, *key_obj; + + /* + * If there isn't a "self" to keep the extra reference for later garbage + * collection then just take a reference and let it leak. This could + * happen, for example, if virtuals were still being called while Python + * was shutting down. + */ + if (self == NULL) + { + Py_XINCREF(obj); + return; + } + + /* Create the extra references dictionary if needed. */ + if ((dict = ((sipSimpleWrapper *)self)->extra_refs) == NULL) + { + if ((dict = PyDict_New()) == NULL) + return; + + ((sipSimpleWrapper *)self)->extra_refs = dict; + } + +#if PY_MAJOR_VERSION >= 3 + key_obj = PyLong_FromLong(key); +#else + key_obj = PyInt_FromLong(key); +#endif + + if (key_obj != NULL) + { + /* This can happen if the argument was optional. */ + if (obj == NULL) + obj = Py_None; + + PyDict_SetItem(dict, key_obj, obj); + Py_DECREF(key_obj); + } +} + + +/* + * Check to see if a Python object can be converted to a type. + */ +static int sip_api_can_convert_to_type(PyObject *pyObj, const sipTypeDef *td, + int flags) +{ + int ok; + + assert(sipTypeIsClass(td) || sipTypeIsMapped(td)); + + /* None is handled outside the type checkers. */ + if (pyObj == Py_None) + { + /* If the type explicitly handles None then ignore the flags. */ + if (sipTypeAllowNone(td)) + ok = TRUE; + else + ok = ((flags & SIP_NOT_NONE) == 0); + } + else + { + sipConvertToFunc cto; + + if (sipTypeIsClass(td)) + { + cto = ((const sipClassTypeDef *)td)->ctd_cto; + + if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0) + ok = PyObject_TypeCheck(pyObj, sipTypeAsPyTypeObject(td)); + else + ok = cto(pyObj, NULL, NULL, NULL); + } + else + { + cto = ((const sipMappedTypeDef *)td)->mtd_cto; + ok = cto(pyObj, NULL, NULL, NULL); + } + } + + return ok; +} + + +/* + * Convert a Python object to a C/C++ pointer, assuming a previous call to + * sip_api_can_convert_to_type() has been successful. Allow ownership to be + * transferred and any type convertors to be disabled. + */ +static void *sip_api_convert_to_type(PyObject *pyObj, const sipTypeDef *td, + PyObject *transferObj, int flags, int *statep, int *iserrp) +{ + void *cpp = NULL; + int state = 0; + + assert(sipTypeIsClass(td) || sipTypeIsMapped(td)); + + /* Don't convert if there has already been an error. */ + if (!*iserrp) + { + /* Do the conversion. */ + if (pyObj == Py_None && !sipTypeAllowNone(td)) + cpp = NULL; + else + { + sipConvertToFunc cto; + + if (sipTypeIsClass(td)) + { + cto = ((const sipClassTypeDef *)td)->ctd_cto; + + if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0) + { + if ((cpp = sip_api_get_cpp_ptr((sipSimpleWrapper *)pyObj, td)) == NULL) + *iserrp = TRUE; + else if (transferObj != NULL) + { + if (transferObj == Py_None) + sip_api_transfer_back(pyObj); + else + sip_api_transfer_to(pyObj, transferObj); + } + } + else + { + state = cto(pyObj, &cpp, iserrp, transferObj); + } + } + else + { + cto = ((const sipMappedTypeDef *)td)->mtd_cto; + state = cto(pyObj, &cpp, iserrp, transferObj); + } + } + } + + if (statep != NULL) + *statep = state; + + return cpp; +} + + +/* + * 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) +{ + /* Don't even try if there has already been an error. */ + if (*iserrp) + return NULL; + + /* See if the object's type can be converted. */ + if (!sip_api_can_convert_to_type(pyObj, td, flags)) + { + if (sipTypeIsMapped(td)) + PyErr_Format(PyExc_TypeError, + "%s cannot be converted to a C/C++ %s in this context", + Py_TYPE(pyObj)->tp_name, sipTypeName(td)); + else + PyErr_Format(PyExc_TypeError, + "%s cannot be converted to %s.%s in this context", + Py_TYPE(pyObj)->tp_name, sipNameOfModule(td->td_module), + sipPyNameOfContainer(&((const sipClassTypeDef *)td)->ctd_container, td)); + + if (statep != NULL) + *statep = 0; + + *iserrp = TRUE; + return NULL; + } + + /* Do the conversion. */ + return sip_api_convert_to_type(pyObj, td, transferObj, flags, statep, + iserrp); +} + + +/* + * Release a possibly temporary C/C++ instance created by a type convertor. + */ +static void sip_api_release_type(void *cpp, const sipTypeDef *td, int state) +{ + /* See if there is something to release. */ + if (state & SIP_TEMPORARY) + release(cpp, td, state); +} + + +/* + * Release an instance. + */ +static void release(void *addr, const sipTypeDef *td, int state) +{ + sipReleaseFunc rel; + + if (sipTypeIsClass(td)) + { + rel = ((const sipClassTypeDef *)td)->ctd_release; + + /* + * If there is no release function then it must be a C structure and we + * can just free it. + */ + if (rel == NULL) + sip_api_free(addr); + } + else if (sipTypeIsMapped(td)) + rel = ((const sipMappedTypeDef *)td)->mtd_release; + else + rel = NULL; + + if (rel != NULL) + rel(addr, state); +} + + +/* + * Convert a C/C++ instance to a Python instance. + */ +PyObject *sip_api_convert_from_type(void *cpp, const sipTypeDef *td, + PyObject *transferObj) +{ + PyObject *py; + + assert(sipTypeIsClass(td) || sipTypeIsMapped(td)); + + /* Handle None. */ + if (cpp == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + if (sipTypeIsMapped(td)) + return ((const sipMappedTypeDef *)td)->mtd_cfrom(cpp, transferObj); + + /* Apply any sub-class convertor. */ + if (sipTypeHasSCC(td)) + td = convertSubClass(td, &cpp); + + /* 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) + return NULL; + + /* Handle any ownership transfer. */ + if (transferObj != NULL) + { + if (transferObj == Py_None) + sip_api_transfer_back(py); + else + sip_api_transfer_to(py, transferObj); + } + + return py; +} + + +/* + * Convert a new C/C++ instance to a Python instance. + */ +static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td, + PyObject *transferObj) +{ + sipWrapper *owner; + + /* Handle None. */ + if (cpp == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + if (sipTypeIsMapped(td)) + { + PyObject *res = ((const sipMappedTypeDef *)td)->mtd_cfrom(cpp, + transferObj); + + if (res != NULL) + { + /* + * We no longer need the C/C++ instance so we release it (unless + * its ownership is transferred). This means this call is + * semantically equivalent to the case where the type is a wrapped + * class. + */ + if (transferObj == NULL || transferObj == Py_None) + release(cpp, td, 0); + } + + return res; + } + + assert(sipTypeIsClass(td)); + + /* Apply any sub-class convertor. */ + if (sipTypeHasSCC(td)) + td = convertSubClass(td, &cpp); + + /* Handle any ownership transfer. */ + if (transferObj == NULL || transferObj == Py_None) + owner = NULL; + else + owner = (sipWrapper *)transferObj; + + return sipWrapSimpleInstance(cpp, td, owner, (owner == NULL ? SIP_PY_OWNED : 0)); +} + + +/* + * Implement the normal transfer policy for the result of %ConvertToTypeCode, + * ie. it is temporary unless it is being transferred from Python. + */ +int sip_api_get_state(PyObject *transferObj) +{ + return (transferObj == NULL || transferObj == Py_None) ? SIP_TEMPORARY : 0; +} + + +/* + * This is set by sip_api_find_type() before calling bsearch() on the types + * table for the module. This is a hack that works around the problem of + * unresolved externally defined types. + */ +static sipExportedModuleDef *module_searched; + + +/* + * The bsearch() helper function for searching the types table. + */ +static int compareTypeDef(const void *key, const void *el) +{ + const char *s1 = (const char *)key; + const char *s2 = NULL; + const sipTypeDef *td; + char ch1, ch2; + + /* Allow for unresolved externally defined types. */ + td = *(const sipTypeDef **)el; + + if (td != NULL) + s2 = sipTypeName(td); + else + { + sipExternalTypeDef *etd = module_searched->em_external; + + assert(etd != NULL); + + /* Find which external type it is. */ + while (etd->et_nr >= 0) + { + const sipTypeDef **tdp = &module_searched->em_types[etd->et_nr]; + + if (tdp == (const sipTypeDef **)el) + { + s2 = etd->et_name; + break; + } + + ++etd; + } + + assert(s2 != NULL); + } + + /* + * Compare while ignoring spaces so that we don't impose a rigorous naming + * standard. This only really affects template-based mapped types. + */ + do + { + while ((ch1 = *s1++) == ' ') + ; + + while ((ch2 = *s2++) == ' ') + ; + + /* We might be looking for a pointer or a reference. */ + if ((ch1 == '*' || ch1 == '&' || ch1 == '\0') && ch2 == '\0') + return 0; + } + while (ch1 == ch2); + + return (ch1 < ch2 ? -1 : 1); +} + + +/* + * Return the type structure for a particular type. + */ +static const sipTypeDef *sip_api_find_type(const char *type) +{ + sipExportedModuleDef *em; + + for (em = moduleList; em != NULL; em = em->em_next) + { + sipTypeDef **tdp; + + /* The backdoor to the comparison helper. */ + module_searched = em; + + tdp = (sipTypeDef **)bsearch((const void *)type, + (const void *)em->em_types, em->em_nrtypes, + sizeof (sipTypeDef *), compareTypeDef); + + if (tdp != NULL) + { + /* + * Note that this will be NULL for unresolved externally defined + * types. + */ + return *tdp; + } + } + + return NULL; +} + + +/* + * Return the mapped type structure for a particular mapped type. This is + * deprecated. + */ +static const sipMappedType *sip_api_find_mapped_type(const char *type) +{ + const sipTypeDef *td = sip_api_find_type(type); + + if (td != NULL && sipTypeIsMapped(td)) + return (const sipMappedType *)td; + + return NULL; +} + + +/* + * Return the type structure for a particular class. This is deprecated. + */ +static sipWrapperType *sip_api_find_class(const char *type) +{ + const sipTypeDef *td = sip_api_find_type(type); + + if (td != NULL && sipTypeIsClass(td)) + return (sipWrapperType *)sipTypeAsPyTypeObject(td); + + return NULL; +} + + +/* + * Return the type structure for a particular named enum. This is deprecated. + */ +static PyTypeObject *sip_api_find_named_enum(const char *type) +{ + const sipTypeDef *td = sip_api_find_type(type); + + if (td != NULL && sipTypeIsEnum(td)) + return sipTypeAsPyTypeObject(td); + + return NULL; +} + + +/* + * Save the components of a Python method. + */ +void sipSaveMethod(sipPyMethod *pm, PyObject *meth) +{ + pm->mfunc = PyMethod_GET_FUNCTION(meth); + pm->mself = PyMethod_GET_SELF(meth); +#if PY_MAJOR_VERSION < 3 + pm->mclass = PyMethod_GET_CLASS(meth); +#endif +} + + +/* + * Call a hook. + */ +static void sip_api_call_hook(const char *hookname) +{ + PyObject *dictofmods, *mod, *dict, *hook, *res; + + /* Get the dictionary of modules. */ + if ((dictofmods = PyImport_GetModuleDict()) == NULL) + return; + + /* Get the __builtin__ module. */ + if ((mod = PyDict_GetItemString(dictofmods, "__builtin__")) == NULL) + return; + + /* Get it's dictionary. */ + if ((dict = PyModule_GetDict(mod)) == NULL) + return; + + /* Get the function hook. */ + if ((hook = PyDict_GetItemString(dict, hookname)) == NULL) + return; + + /* Call the hook and discard any result. */ + res = PyObject_CallObject(hook, NULL); + + Py_XDECREF(res); +} + + +/* + * Call any sub-class convertors for a given type returning a pointer to the + * sub-type object, and possibly modifying the C++ address (in the case of + * multiple inheritence). + */ +static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr) +{ + PyTypeObject *py_type = sipTypeAsPyTypeObject(td); + sipExportedModuleDef *em; + + if (*cppPtr == NULL) + return NULL; + + /* + * Note that this code depends on the fact that a module appears in the + * list of modules before any module it imports, ie. sub-class convertors + * will be invoked for more specific types first. + */ + for (em = moduleList; em != NULL; em = em->em_next) + { + sipSubClassConvertorDef *scc; + + if ((scc = em->em_convertors) == NULL) + continue; + + while (scc->scc_convertor != NULL) + { + /* + * The base type is the "root" class that may have a number of + * convertors each handling a "branch" of the derived tree of + * classes. The "root" normally implements the base function that + * provides the RTTI used by the convertors and is re-implemented + * by derived classes. We therefore see if the target type is a + * sub-class of the root, ie. see if the convertor might be able to + * convert the target type to something more specific. + */ + if (PyType_IsSubtype(py_type, sipTypeAsPyTypeObject(scc->scc_basetype))) + { + void *ptr; + const sipTypeDef *subtype; + + ptr = cast_cpp_ptr(*cppPtr, py_type, scc->scc_basetype); + subtype = (*scc->scc_convertor)(&ptr); + + /* + * We are only interested in types that are not super-classes + * of the target. This happens either because it is in an + * earlier convertor than the one that handles the type or it + * is in a later convertor that handles a different branch of + * the hierarchy. Either way, the ordering of the modules + * ensures that there will be no more than one and that it will + * be the right one. + */ + if (subtype != NULL && !PyType_IsSubtype(py_type, sipTypeAsPyTypeObject(subtype))) + { + *cppPtr = ptr; + return subtype; + } + } + + ++scc; + } + } + + /* + * We haven't found the exact type, so return the most specific type that + * it must be. This can happen legitimately if the wrapped library is + * returning an internal class that is down-cast to a more generic class. + * Also we want this function to be safe when a class doesn't have any + * convertors. + */ + return td; +} + + +/* + * The bsearch() helper function for searching a sorted string map table. + */ +static int compareStringMapEntry(const void *key,const void *el) +{ + return strcmp((const char *)key,((const sipStringTypeClassMap *)el)->typeString); +} + + +/* + * A convenience function for %ConvertToSubClassCode for types represented as a + * string. Returns the Python class object or NULL if the type wasn't + * recognised. This is deprecated. + */ +static sipWrapperType *sip_api_map_string_to_class(const char *typeString, + const sipStringTypeClassMap *map, int maplen) +{ + sipStringTypeClassMap *me; + + me = (sipStringTypeClassMap *)bsearch((const void *)typeString, + (const void *)map,maplen, + sizeof (sipStringTypeClassMap), + compareStringMapEntry); + + return ((me != NULL) ? *me->pyType : NULL); +} + + +/* + * The bsearch() helper function for searching a sorted integer map table. + */ +static int compareIntMapEntry(const void *keyp,const void *el) +{ + int key = *(int *)keyp; + + if (key > ((const sipIntTypeClassMap *)el)->typeInt) + return 1; + + if (key < ((const sipIntTypeClassMap *)el)->typeInt) + return -1; + + return 0; +} + + +/* + * A convenience function for %ConvertToSubClassCode for types represented as + * an integer. Returns the Python class object or NULL if the type wasn't + * recognised. This is deprecated. + */ +static sipWrapperType *sip_api_map_int_to_class(int typeInt, + const sipIntTypeClassMap *map, int maplen) +{ + sipIntTypeClassMap *me; + + me = (sipIntTypeClassMap *)bsearch((const void *)&typeInt, + (const void *)map,maplen, + sizeof (sipIntTypeClassMap), + compareIntMapEntry); + + return ((me != NULL) ? *me->pyType : NULL); +} + + +/* + * Raise an unknown exception. Make no assumptions about the GIL. + */ +static void sip_api_raise_unknown_exception(void) +{ + static PyObject *mobj = NULL; + + SIP_BLOCK_THREADS + + objectify("unknown", &mobj); + + PyErr_SetObject(PyExc_Exception, mobj); + + SIP_UNBLOCK_THREADS +} + + +/* + * Raise an exception implemented as a type. Make no assumptions about the + * GIL. + */ +static void sip_api_raise_type_exception(const sipTypeDef *td, void *ptr) +{ + PyObject *self; + + assert(sipTypeIsClass(td)); + + SIP_BLOCK_THREADS + + self = sipWrapSimpleInstance(ptr, td, NULL, SIP_PY_OWNED); + + PyErr_SetObject((PyObject *)sipTypeAsPyTypeObject(td), self); + + Py_XDECREF(self); + + SIP_UNBLOCK_THREADS +} + + +/* + * Return the module of an encoded type. + */ +static sipExportedModuleDef *getTypeModule(const sipEncodedTypeDef *enc, + sipExportedModuleDef *em) +{ + if (enc->sc_module != 255) + em = em->em_imports[enc->sc_module].im_module; + + return em; +} + + +/* + * Return the generated type structure of an encoded type. + */ +static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc, + sipExportedModuleDef *em) +{ + return getTypeModule(enc, em)->em_types[enc->sc_type]; +} + + +/* + * Find a particular slot function for a type. + */ +static void *findSlot(PyObject *self, sipPySlotType st) +{ + void *slot; + PyTypeObject *py_type = Py_TYPE(self); + + /* See if it is a wrapper. */ + if (PyObject_TypeCheck((PyObject *)py_type, &sipWrapperType_Type)) + { + 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) + { + sipClassTypeDef *sup_ctd; + + do + { + sup_ctd = (sipClassTypeDef *)getGeneratedType(sup, + ctd->ctd_base.td_module); + + if (sup_ctd->ctd_pyslots != NULL) + slot = findSlotInType(sup_ctd->ctd_pyslots, st); + } + while (slot == NULL && !sup++->sc_flag); + } + } + } + else + { + sipEnumTypeDef *etd; + + /* If it is not a wrapper then it must be an enum. */ + assert(PyObject_TypeCheck((PyObject *)py_type, &sipEnumType_Type)); + + etd = (sipEnumTypeDef *)((sipEnumTypeObject *)(py_type))->type; + + assert(etd->etd_pyslots != NULL); + + slot = findSlotInType(etd->etd_pyslots, st); + } + + return slot; +} + + +/* + * Find a particular slot function in a particular type. + */ +static void *findSlotInType(sipPySlotDef *psd, sipPySlotType st) +{ + while (psd->psd_func != NULL) + { + if (psd->psd_type == st) + return psd->psd_func; + + ++psd; + } + + return NULL; +} + + +/* + * Return the C/C++ address and the generated class structure for a wrapper. + */ +static void *getPtrTypeDef(sipSimpleWrapper *self, const sipClassTypeDef **ctd) +{ + *ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(self))->type; + + return (sipNotInMap(self) ? NULL : self->u.cppPtr); +} + + +/* + * Handle an objobjargproc slot. + */ +static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2, + sipPySlotType st) +{ + int (*f)(PyObject *, PyObject *); + int res; + + f = (int (*)(PyObject *, PyObject *))findSlot(self, st); + + if (f != NULL) + { + PyObject *args; + + /* + * Slot handlers require a single PyObject *. The second argument is + * optional. + */ + if (arg2 == NULL) + { + args = arg1; + Py_INCREF(args); + } + else + { +#if PY_VERSION_HEX >= 0x02040000 + args = PyTuple_Pack(2, arg1, arg2); +#else + args = Py_BuildValue("(OO)", arg1, arg2); +#endif + + if (args == NULL) + return -1; + } + + res = f(self, args); + Py_DECREF(args); + } + else + { + PyErr_SetNone(PyExc_NotImplementedError); + res = -1; + } + + return res; +} + + +/* + * Handle an ssizeobjargproc slot. + */ +static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1, + PyObject *arg2, sipPySlotType st) +{ + int (*f)(PyObject *, PyObject *); + int res; + + f = (int (*)(PyObject *, PyObject *))findSlot(self, st); + + if (f != NULL) + { + PyObject *args; + + /* + * Slot handlers require a single PyObject *. The second argument is + * optional. + */ + if (arg2 == NULL) +#if PY_MAJOR_VERSION >= 3 + args = PyLong_FromSsize_t(arg1); +#elif PY_VERSION_HEX >= 0x02050000 + args = PyInt_FromSsize_t(arg1); +#else + args = PyInt_FromLong(arg1); +#endif + else +#if PY_VERSION_HEX >= 0x02050000 + args = Py_BuildValue("(nO)", arg1, arg2); +#else + args = Py_BuildValue("(iO)", arg1, arg2); +#endif + + if (args == NULL) + return -1; + + res = f(self, args); + Py_DECREF(args); + } + else + { + PyErr_SetNone(PyExc_NotImplementedError); + res = -1; + } + + return res; +} + + +/* + * The metatype alloc slot. + */ +static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems) +{ + PyObject *o; + + /* Call the standard super-metatype alloc. */ + if ((o = PyType_Type.tp_alloc(self, nitems)) == NULL) + return NULL; + + /* + * Consume any extra type specific information and use it to initialise the + * slots. This only happens for directly wrapped classes (and not + * programmer written sub-classes). This must be done in the alloc + * function because it is the only place we can break out of the default + * new() function before PyType_Ready() is called. + */ + if (currentType != NULL) + { + ((sipWrapperType *)o)->type = currentType; + + if (sipTypeIsClass(currentType)) + { + const char *docstring = ((sipClassTypeDef *)currentType)->ctd_docstring; + + /* + * Skip the marker that identifies the docstring as being + * automatically generated. + */ + if (docstring != NULL && *docstring == AUTO_DOCSTRING) + ++docstring; + + ((PyTypeObject *)o)->tp_doc = docstring; + + addClassSlots((sipWrapperType *)o, (sipClassTypeDef *)currentType); + } + + currentType = NULL; + } + + return o; +} + + +/* + * The metatype init slot. + */ +static int sipWrapperType_init(sipWrapperType *self, PyObject *args, + PyObject *kwds) +{ + /* Call the standard super-metatype init. */ + if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + + /* + * If we don't yet have any extra type specific information (because we are + * a programmer defined sub-class) then get it from the (first) super-type. + */ + if (self->type == NULL) + { + PyTypeObject *base = ((PyTypeObject *)self)->tp_base; + + /* + * We allow the class to use this as a meta-type without being derived + * from a class that uses it. This allows mixin classes that need + * their own meta-type to work so long as their meta-type is derived + * from this meta-type. This condition is indicated by the pointer to + * the generated type structure being NULL. + */ + if (base != NULL && PyObject_TypeCheck((PyObject *)base, (PyTypeObject *)&sipWrapperType_Type)) + self->type = ((sipWrapperType *)base)->type; + } + else + { + /* + * We must be a generated type so remember the type object in the + * generated type structure. + */ + assert(self->type->u.td_py_type == NULL); + + self->type->u.td_py_type = (PyTypeObject *)self; + } + + return 0; +} + + +/* + * The metatype getattro slot. + */ +static PyObject *sipWrapperType_getattro(PyObject *self, PyObject *name) +{ + if (add_all_lazy_attrs(((sipWrapperType *)self)->type) < 0) + return NULL; + + return PyType_Type.tp_getattro(self, name); +} + + +/* + * The metatype setattro slot. + */ +static int sipWrapperType_setattro(PyObject *self, PyObject *name, + PyObject *value) +{ + if (add_all_lazy_attrs(((sipWrapperType *)self)->type) < 0) + return -1; + + return PyType_Type.tp_setattro(self, name, value); +} + + +/* + * The instance new slot. + */ +static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args, + PyObject *kwds) +{ + static PyObject *noargs = NULL; + sipTypeDef *td = wt->type; + sipContainerDef *cod; + + /* Check the base types are not being used directly. */ + if (wt == &sipSimpleWrapper_Type || wt == &sipWrapper_Type) + { + PyErr_Format(PyExc_TypeError, + "the %s type cannot be instantiated or sub-classed", + ((PyTypeObject *)wt)->tp_name); + + return NULL; + } + + if (sipTypeIsMapped(td)) + cod = &((sipMappedTypeDef *)td)->mtd_container; + 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)) + { + PyErr_Format(PyExc_TypeError, + "%s.%s represents a mapped type and cannot be instantiated", + sipNameOfModule(td->td_module), + sipPyNameOfContainer(cod, td)); + + return NULL; + } + + /* See if it is a namespace. */ + if (sipTypeIsNamespace(td)) + { + PyErr_Format(PyExc_TypeError, + "%s.%s represents a C++ namespace and cannot be instantiated", + sipNameOfModule(td->td_module), + sipPyNameOfContainer(cod, td)); + + return NULL; + } + + /* + * See if the object is being created explicitly rather than being wrapped. + */ + if (sipGetPending(NULL, NULL) == NULL) + { + /* + * See if it cannot be instantiated or sub-classed from Python, eg. + * it's an opaque class. Some restrictions might be overcome with + * better SIP support. + */ + if (((sipClassTypeDef *)td)->ctd_init == NULL) + { + PyErr_Format(PyExc_TypeError, + "%s.%s cannot be instantiated or sub-classed", + sipNameOfModule(td->td_module), + sipPyNameOfContainer(cod, td)); + + return NULL; + } + + /* See if it is an abstract type. */ + if (sipTypeIsAbstract(td) && sipIsExactWrappedType(wt)) + { + PyErr_Format(PyExc_TypeError, + "%s.%s represents a C++ abstract class and cannot be instantiated", + sipNameOfModule(td->td_module), + sipPyNameOfContainer(cod, td)); + + return NULL; + } + } + + /* Call the standard super-type new. */ + return PyBaseObject_Type.tp_new((PyTypeObject *)wt, noargs, NULL); +} + + +/* + * The instance init slot. + */ +static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, + PyObject *kwds) +{ + void *sipNew; + int sipFlags; + sipWrapper *owner; + sipWrapperType *wt = (sipWrapperType *)Py_TYPE(self); + sipTypeDef *td = wt->type; + sipClassTypeDef *ctd = (sipClassTypeDef *)td; + PyObject *unused, **unused_p; + + 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. */ + if ((sipNew = sipGetPending(&owner, &sipFlags)) == NULL) + { + PyObject *parseErr = NULL; + + /* Call the C++ ctor. */ + owner = NULL; + + sipNew = ctd->ctd_init(self, args, kwds, unused_p, (PyObject **)&owner, + &parseErr); + + if (sipNew != NULL) + { + sipFlags = SIP_DERIVED_CLASS; + } + else if (parseErr == NULL) + { + /* + * The C++ ctor must have raised an exception which has been + * translated to a Python exception. + */ + return -1; + } + else + { + sipInitExtenderDef *ie = wt->iextend; + + assert(parseErr != NULL); + + /* + * If we have not found an appropriate overload then try any + * extenders. + */ + while (PyList_Check(parseErr) && ie != NULL) + { + sipNew = ie->ie_extender(self, args, kwds, unused_p, + (PyObject **)&owner, &parseErr); + + if (sipNew != NULL) + break; + + ie = ie->ie_next; + } + + if (sipNew == NULL) + { + const char *docstring = ctd->ctd_docstring; + + /* + * Use the docstring for errors if it was automatically + * generated. + */ + if (docstring != NULL) + { + if (*docstring == AUTO_DOCSTRING) + ++docstring; + else + docstring = NULL; + } + + sip_api_no_function(parseErr, + sipPyNameOfContainer(&ctd->ctd_container, td), + docstring); + + return -1; + } + + sipFlags = 0; + } + + if (owner == NULL) + sipFlags |= SIP_PY_OWNED; + else if ((PyObject *)owner == Py_None) + { + /* This is the hack that means that C++ owns the new instance. */ + sipFlags |= SIP_CPP_HAS_REF; + Py_INCREF(self); + owner = NULL; + } + } + + /* + * If there is an owner then we assume that the wrapper supports the + * concept. + */ + if (owner != NULL) + { + assert(PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type)); + addToParent((sipWrapper *)self, (sipWrapper *)owner); + } + + self->u.cppPtr = sipNew; + self->flags = sipFlags; + + if (!sipNotInMap(self)) + sipOMAddObject(&cppPyMap, self); + + /* If we have unused keyword arguments then we know how to handle them. */ + if (unused != NULL) + { + int rc; + + rc = kw_handler((PyObject *)self, sipNew, unused); + Py_DECREF(unused); + + if (rc < 0) + return -1; + } + + return 0; +} + + +/* + * The instance traverse slot. + */ +static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit, + void *arg) +{ + int vret; + void *ptr; + const sipClassTypeDef *ctd; + + /* Call the nearest handwritten traverse code in the class hierachy. */ + if ((ptr = getPtrTypeDef(self, &ctd)) != NULL) + { + const sipClassTypeDef *sup_ctd = ctd; + + if (ctd->ctd_traverse == NULL) + { + sipEncodedTypeDef *sup; + + if ((sup = ctd->ctd_supers) != NULL) + do + sup_ctd = (sipClassTypeDef *)getGeneratedType(sup, ctd->ctd_base.td_module); + while (sup_ctd->ctd_traverse == NULL && !sup++->sc_flag); + } + + if (sup_ctd->ctd_traverse != NULL) + if ((vret = sup_ctd->ctd_traverse(ptr, visit, arg)) != 0) + return vret; + } + + if (self->dict != NULL) + if ((vret = visit(self->dict, arg)) != 0) + return vret; + + if (self->extra_refs != NULL) + if ((vret = visit(self->extra_refs, arg)) != 0) + return vret; + + if (self->user != NULL) + if ((vret = visit(self->user, arg)) != 0) + return vret; + + return 0; +} + + +/* + * The instance clear slot. + */ +static int sipSimpleWrapper_clear(sipSimpleWrapper *self) +{ + int vret = 0; + void *ptr; + const sipClassTypeDef *ctd; + PyObject *tmp; + + /* Call the nearest handwritten clear code in the class hierachy. */ + if ((ptr = getPtrTypeDef(self, &ctd)) != NULL) + { + const sipClassTypeDef *sup_ctd = ctd; + + if (ctd->ctd_clear == NULL) + { + sipEncodedTypeDef *sup; + + if ((sup = ctd->ctd_supers) != NULL) + do + sup_ctd = (sipClassTypeDef *)getGeneratedType(sup, ctd->ctd_base.td_module); + while (sup_ctd->ctd_clear == NULL && !sup++->sc_flag); + } + + if (sup_ctd->ctd_clear != NULL) + vret = sup_ctd->ctd_clear(ptr); + } + + /* Remove the instance dictionary. */ + tmp = self->dict; + self->dict = NULL; + Py_XDECREF(tmp); + + /* Remove any extra references dictionary. */ + tmp = self->extra_refs; + self->extra_refs = NULL; + Py_XDECREF(tmp); + + /* Remove any user object. */ + tmp = self->user; + self->user = NULL; + Py_XDECREF(tmp); + + return vret; +} + + +#if PY_MAJOR_VERSION >= 3 +/* + * The instance get buffer slot for Python v3. + */ +static int sipSimpleWrapper_getbuffer(sipSimpleWrapper *self, Py_buffer *buf, + int flags) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return -1; + + return ctd->ctd_getbuffer((PyObject *)self, ptr, buf, flags); +} +#endif + + +#if PY_MAJOR_VERSION >= 3 +/* + * The instance release buffer slot for Python v3. + */ +static void sipSimpleWrapper_releasebuffer(sipSimpleWrapper *self, + Py_buffer *buf) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return -1; + + return ctd->ctd_releasebuffer((PyObject *)self, ptr, buf); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The instance read buffer slot for Python v2. + */ +static SIP_SSIZE_T sipSimpleWrapper_getreadbuffer(sipSimpleWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return -1; + + return ctd->ctd_readbuffer((PyObject *)self, ptr, segment, ptrptr); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The instance write buffer slot for Python v2. + */ +static SIP_SSIZE_T sipSimpleWrapper_getwritebuffer(sipSimpleWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return -1; + + return ctd->ctd_writebuffer((PyObject *)self, ptr, segment, ptrptr); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The instance segment count slot for Python v2. + */ +static SIP_SSIZE_T sipSimpleWrapper_getsegcount(sipSimpleWrapper *self, + SIP_SSIZE_T *lenp) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return 0; + + return ctd->ctd_segcount((PyObject *)self, ptr, lenp); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The instance char buffer slot for Python v2. + */ +static SIP_SSIZE_T sipSimpleWrapper_getcharbuffer(sipSimpleWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + const sipClassTypeDef *ctd; + + if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) + return -1; + + return ctd->ctd_charbuffer((PyObject *)self, ptr, segment, ptrptr); +} +#endif + + +/* + * The instance dealloc slot. + */ +static void sipSimpleWrapper_dealloc(sipSimpleWrapper *self) +{ + forgetObject(self); + + /* + * Now that the C++ object no longer exists we can tidy up the Python + * object. We used to do this first but that meant lambda slots were + * removed too soon (if they were connected to QObject.destroyed()). + */ + sipSimpleWrapper_clear(self); + + /* Call the standard super-type dealloc. */ + PyBaseObject_Type.tp_dealloc((PyObject *)self); +} + + +/* + * The type call slot. Note that keyword arguments aren't supported. + */ +static PyObject *slot_call(PyObject *self,PyObject *args,PyObject *kw) +{ + PyObject *(*f)(PyObject *,PyObject *); + + f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, call_slot); + + assert(f != NULL); + + return f(self,args); +} + + +/* + * The sequence type item slot. + */ +static PyObject *slot_sq_item(PyObject *self, SIP_SSIZE_T n) +{ + PyObject *(*f)(PyObject *,PyObject *); + PyObject *arg, *res; + +#if PY_MAJOR_VERSION >= 3 + arg = PyLong_FromSsize_t(n); +#elif PY_VERSION_HEX >= 0x02050000 + arg = PyInt_FromSsize_t(n); +#else + arg = PyInt_FromLong(n); +#endif + + if (arg == NULL) + return NULL; + + f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, getitem_slot); + + assert(f != NULL); + + res = f(self,arg); + + Py_DECREF(arg); + + return res; +} + + +/* + * The mapping type assign subscript slot. + */ +static int slot_mp_ass_subscript(PyObject *self, PyObject *key, + PyObject *value) +{ + return objobjargprocSlot(self, key, value, + (value != NULL ? setitem_slot : delitem_slot)); +} + + +/* + * The sequence type assign item slot. + */ +static int slot_sq_ass_item(PyObject *self, SIP_SSIZE_T i, PyObject *o) +{ + return ssizeobjargprocSlot(self, i, o, + (o != NULL ? setitem_slot : delitem_slot)); +} + + +/* + * The type rich compare slot. + */ +static PyObject *slot_richcompare(PyObject *self, PyObject *arg, int op) +{ + PyObject *(*f)(PyObject *,PyObject *); + sipPySlotType st; + + /* Convert the operation to a slot type. */ + switch (op) + { + case Py_LT: + st = lt_slot; + break; + + case Py_LE: + st = le_slot; + break; + + case Py_EQ: + st = eq_slot; + break; + + case Py_NE: + st = ne_slot; + break; + + case Py_GT: + st = gt_slot; + break; + + case Py_GE: + st = ge_slot; + break; + } + + /* It might not exist if not all the above have been implemented. */ + if ((f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, st)) == NULL) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + return f(self, arg); +} + + +/* + * The instance getattro slot. + */ +static PyObject *sipSimpleWrapper_getattro(PyObject *self, PyObject *name) +{ + if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(self))->type) < 0) + return NULL; + + return PyObject_GenericGetAttr(self, name); +} + + +/* + * The instance setattro slot. + */ +static int sipSimpleWrapper_setattro(PyObject *self, PyObject *name, + PyObject *value) +{ + if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(self))->type) < 0) + return -1; + + return PyObject_GenericSetAttr(self, name, value); +} + + +/* + * The __dict__ getter. + */ +static PyObject *sipSimpleWrapper_get_dict(PyObject *self, void *closure) +{ + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + /* Create the dictionary if needed. */ + if (sw->dict == NULL) + { + sw->dict = PyDict_New(); + + if (sw->dict == NULL) + return NULL; + } + + Py_INCREF(sw->dict); + return sw->dict; +} + + +/* + * The __dict__ setter. + */ +static int sipSimpleWrapper_set_dict(PyObject *self, PyObject *value, + void *closure) +{ + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + /* Check that any new value really is a dictionary. */ + if (value != NULL && !PyDict_Check(value)) + { + PyErr_Format(PyExc_TypeError, + "__dict__ must be set to a dictionary, not a '%s'", + Py_TYPE(value)->tp_name); + return -1; + } + + Py_XDECREF(sw->dict); + + Py_XINCREF(value); + sw->dict = value; + + return 0; +} + + +/* + * The table of getters and setters. + */ +static PyGetSetDef sipSimpleWrapper_getset[] = { + {(char *)"__dict__", sipSimpleWrapper_get_dict, sipSimpleWrapper_set_dict, + NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + + +/* + * The type data structure. Note that we pretend to be a mapping object and a + * sequence object at the same time. Python will choose one over another, + * depending on the context, but we implement as much as we can and don't make + * assumptions about which Python will choose. + */ +sipWrapperType sipSimpleWrapper_Type = { +#if !defined(STACKLESS) + { +#endif + { + PyVarObject_HEAD_INIT(&sipWrapperType_Type, 0) + "sip.simplewrapper", /* tp_name */ + sizeof (sipSimpleWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)sipSimpleWrapper_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 */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + sipSimpleWrapper_getattro, /* tp_getattro */ + sipSimpleWrapper_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)sipSimpleWrapper_traverse, /* tp_traverse */ + (inquiry)sipSimpleWrapper_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + sipSimpleWrapper_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(sipSimpleWrapper, dict), /* tp_dictoffset */ + (initproc)sipSimpleWrapper_init, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)sipSimpleWrapper_new, /* tp_new */ + 0, /* tp_free */ + }, +#if !defined(STACKLESS) + }, +#endif + 0, + 0 +}; + + +/* + * The wrapper clear slot. + */ +static int sipWrapper_clear(sipWrapper *self) +{ + int vret; + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + + vret = sipSimpleWrapper_clear(sw); + + /* Remove any slots connected via a proxy. */ + if (sipQtSupport != NULL && sipPossibleProxy(sw)) + { + void *tx = sipGetAddress(sw); + + if (tx != NULL) + { + sipSlot *slot; + void *context = NULL; + + while ((slot = sipQtSupport->qt_find_sipslot(tx, &context)) != NULL) + { + sip_api_clear_any_slot_reference(slot); + + if (context == NULL) + break; + } + } + } + + /* Detach children (which will be owned by C/C++). */ + while ((sw = (sipSimpleWrapper *)self->first_child) != NULL) + { + /* + * Although this object is being garbage collected it doesn't follow + * that it's children should be. So we make sure that the child stays + * alive and remember we have done so. + */ + Py_INCREF(sw); + sipSetCppHasRef(sw); + + removeFromParent(self->first_child); + } + + return vret; +} + + +/* + * The wrapper dealloc slot. + */ +static void sipWrapper_dealloc(sipWrapper *self) +{ + /* + * We can't simply call the super-type because things have to be done in a + * certain order. The first thing is to get rid of the wrapped instance. + */ + forgetObject((sipSimpleWrapper *)self); + + sipWrapper_clear(self); + + /* Skip the super-type's dealloc. */ + PyBaseObject_Type.tp_dealloc((PyObject *)self); +} + + +/* + * The wrapper traverse slot. + */ +static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg) +{ + int vret; + sipSimpleWrapper *sw = (sipSimpleWrapper *)self; + sipWrapper *w; + + if ((vret = sipSimpleWrapper_traverse(sw, visit, arg)) != 0) + return vret; + + /* This should be handwritten code in PyQt. */ + if (sipQtSupport != NULL) + { + void *tx = sipGetAddress(sw); + + if (tx != NULL) + { + sipSlot *slot; + void *context = NULL; + + while ((slot = sipQtSupport->qt_find_sipslot(tx, &context)) != NULL) + { + if ((vret = sip_api_visit_slot(slot, visit, arg)) != 0) + return vret; + + if (context == NULL) + break; + } + } + } + + for (w = self->first_child; w != NULL; w = w->sibling_next) + { + /* + * We don't traverse if the wrapper is a child of itself. We do this + * so that wrapped objects returned by virtual methods with the + * /Factory/ don't have those objects collected. This then means that + * plugins implemented in Python have a chance of working. + */ + if (w != self) + if ((vret = visit((PyObject *)w, arg)) != 0) + return vret; + } + + return 0; +} + + +/* + * Add the slots for a class type and all its super-types. + */ +static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd) +{ + /* Add the buffer interface. */ +#if PY_MAJOR_VERSION >= 3 + if (ctd->ctd_getbuffer != NULL) + wt->super.as_buffer.bf_getbuffer = (getbufferproc)sipSimpleWrapper_getbuffer; + + if (ctd->ctd_releasebuffer != NULL) + wt->super.as_buffer.bf_releasebuffer = (releasebufferproc)sipSimpleWrapper_releasebuffer; +#else + if (ctd->ctd_readbuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getreadbuffer = (readbufferproc)sipSimpleWrapper_getreadbuffer; +#else + wt->super.as_buffer.bf_getreadbuffer = (getreadbufferproc)sipSimpleWrapper_getreadbuffer; +#endif + + if (ctd->ctd_writebuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getwritebuffer = (writebufferproc)sipSimpleWrapper_getwritebuffer; +#else + wt->super.as_buffer.bf_getwritebuffer = (getwritebufferproc)sipSimpleWrapper_getwritebuffer; +#endif + + if (ctd->ctd_segcount != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getsegcount = (segcountproc)sipSimpleWrapper_getsegcount; +#else + wt->super.as_buffer.bf_getsegcount = (getsegcountproc)sipSimpleWrapper_getsegcount; +#endif + + if (ctd->ctd_charbuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getcharbuffer = (charbufferproc)sipSimpleWrapper_getcharbuffer; +#else + wt->super.as_buffer.bf_getcharbuffer = (getcharbufferproc)sipSimpleWrapper_getcharbuffer; +#endif +#endif + + /* Add the slots for this type. */ + if (ctd->ctd_pyslots != NULL) + addTypeSlots(&wt->super, ctd->ctd_pyslots); +} + + +/* + * Add the slot handler for each slot present in the type. + */ +static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots) +{ + PyTypeObject *to; + PyNumberMethods *nb; + PySequenceMethods *sq; + PyMappingMethods *mp; + void *f; + + to = (PyTypeObject *)heap_to; + nb = &heap_to->as_number; + sq = &heap_to->as_sequence; + mp = &heap_to->as_mapping; + + while ((f = slots->psd_func) != NULL) + switch (slots++->psd_type) + { + case str_slot: + to->tp_str = (reprfunc)f; + break; + + case int_slot: + if (nb != NULL) + nb->nb_int = (unaryfunc)f; + break; + +#if PY_MAJOR_VERSION < 3 + case long_slot: + if (nb != NULL) + nb->nb_long = (unaryfunc)f; + break; +#endif + + case float_slot: + if (nb != NULL) + nb->nb_float = (unaryfunc)f; + break; + + case len_slot: + if (mp != NULL) +#if PY_VERSION_HEX >= 0x02050000 + mp->mp_length = (lenfunc)f; +#else + mp->mp_length = (inquiry)f; +#endif + if (sq != NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_length = (lenfunc)f; +#else + sq->sq_length = (inquiry)f; +#endif + break; + + case contains_slot: + if (sq != NULL) + sq->sq_contains = (objobjproc)f; + break; + + case add_slot: + if (nb != NULL) + nb->nb_add = (binaryfunc)f; + break; + + case concat_slot: + if (sq != NULL) + sq->sq_concat = (binaryfunc)f; + break; + + case sub_slot: + if (nb != NULL) + nb->nb_subtract = (binaryfunc)f; + break; + + case mul_slot: + if (nb != NULL) + nb->nb_multiply = (binaryfunc)f; + break; + + case repeat_slot: + if (sq != NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_repeat = (ssizeargfunc)f; +#else + sq->sq_repeat = (intargfunc)f; +#endif + break; + + case div_slot: + if (nb != NULL) + { + nb->nb_true_divide = (binaryfunc)f; +#if PY_MAJOR_VERSION < 3 + nb->nb_divide = (binaryfunc)f; +#endif + } + break; + + case mod_slot: + if (nb != NULL) + nb->nb_remainder = (binaryfunc)f; + break; + + case floordiv_slot: + if (nb != NULL) + nb->nb_floor_divide = (binaryfunc)f; + break; + + case truediv_slot: + if (nb != NULL) + nb->nb_true_divide = (binaryfunc)f; + break; + + case and_slot: + if (nb != NULL) + nb->nb_and = (binaryfunc)f; + break; + + case or_slot: + if (nb != NULL) + nb->nb_or = (binaryfunc)f; + break; + + case xor_slot: + if (nb != NULL) + nb->nb_xor = (binaryfunc)f; + break; + + case lshift_slot: + if (nb != NULL) + nb->nb_lshift = (binaryfunc)f; + break; + + case rshift_slot: + if (nb != NULL) + nb->nb_rshift = (binaryfunc)f; + break; + + case iadd_slot: + if (nb != NULL) + nb->nb_inplace_add = (binaryfunc)f; + break; + + case iconcat_slot: + if (sq != NULL) + sq->sq_inplace_concat = (binaryfunc)f; + break; + + case isub_slot: + if (nb != NULL) + nb->nb_inplace_subtract = (binaryfunc)f; + break; + + case imul_slot: + if (nb != NULL) + nb->nb_inplace_multiply = (binaryfunc)f; + break; + + case irepeat_slot: + if (sq != NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_inplace_repeat = (ssizeargfunc)f; +#else + sq->sq_inplace_repeat = (intargfunc)f; +#endif + break; + + case idiv_slot: + if (nb != NULL) + { + nb->nb_inplace_true_divide = (binaryfunc)f; +#if PY_MAJOR_VERSION < 3 + nb->nb_inplace_divide = (binaryfunc)f; +#endif + } + break; + + case imod_slot: + if (nb != NULL) + nb->nb_inplace_remainder = (binaryfunc)f; + break; + + case ifloordiv_slot: + if (nb != NULL) + nb->nb_inplace_floor_divide = (binaryfunc)f; + break; + + case itruediv_slot: + if (nb != NULL) + nb->nb_inplace_true_divide = (binaryfunc)f; + break; + + case iand_slot: + if (nb != NULL) + nb->nb_inplace_and = (binaryfunc)f; + break; + + case ior_slot: + if (nb != NULL) + nb->nb_inplace_or = (binaryfunc)f; + break; + + case ixor_slot: + if (nb != NULL) + nb->nb_inplace_xor = (binaryfunc)f; + break; + + case ilshift_slot: + if (nb != NULL) + nb->nb_inplace_lshift = (binaryfunc)f; + break; + + case irshift_slot: + if (nb != NULL) + nb->nb_inplace_rshift = (binaryfunc)f; + break; + + case invert_slot: + if (nb != NULL) + nb->nb_invert = (unaryfunc)f; + break; + + case call_slot: + to->tp_call = slot_call; + break; + + case getitem_slot: + if (mp != NULL) + mp->mp_subscript = (binaryfunc)f; + if (sq != NULL) + sq->sq_item = slot_sq_item; + break; + + case setitem_slot: + case delitem_slot: + if (mp != NULL) + mp->mp_ass_subscript = slot_mp_ass_subscript; + if (sq != NULL) + sq->sq_ass_item = slot_sq_ass_item; + break; + + case lt_slot: + case le_slot: + case eq_slot: + case ne_slot: + case gt_slot: + case ge_slot: + to->tp_richcompare = slot_richcompare; + break; + +#if PY_MAJOR_VERSION < 3 + case cmp_slot: + to->tp_compare = (cmpfunc)f; + break; +#endif + + case bool_slot: + if (nb != NULL) +#if PY_MAJOR_VERSION >= 3 + nb->nb_bool = (inquiry)f; +#else + nb->nb_nonzero = (inquiry)f; +#endif + break; + + case neg_slot: + if (nb != NULL) + nb->nb_negative = (unaryfunc)f; + break; + + case repr_slot: + to->tp_repr = (reprfunc)f; + break; + + case hash_slot: + to->tp_hash = (hashfunc)f; + break; + + case pos_slot: + if (nb != NULL) + nb->nb_positive = (unaryfunc)f; + break; + + case abs_slot: + if (nb != NULL) + nb->nb_absolute = (unaryfunc)f; + break; + +#if PY_VERSION_HEX >= 0x02050000 + case index_slot: + if (nb != NULL) + nb->nb_index = (unaryfunc)f; + break; +#endif + + case iter_slot: + to->tp_iter = (getiterfunc)f; + break; + + case next_slot: + to->tp_iternext = (iternextfunc)f; + break; + } +} + + +/* + * Remove the object from the map and call the C/C++ dtor if we own the + * instance. + */ +static void forgetObject(sipSimpleWrapper *sw) +{ + const sipClassTypeDef *ctd; + + /* + * This is needed because we release the GIL when calling a C++ dtor. + * Without it the cyclic garbage collector can be invoked from another + * thread resulting in a crash. + */ + PyObject_GC_UnTrack((PyObject *)sw); + + if (getPtrTypeDef(sw, &ctd) != NULL) + { + /* + * Remove the object from the map before calling the class specific + * dealloc code. This code calls the C++ dtor and may result in + * further calls that pass the instance as an argument. If this is + * still in the map then it's reference count would be increased (to + * one) and bad things happen when it drops back to zero again. (An + * example is PyQt events generated during the dtor call being passed + * to an event filter implemented in Python.) By removing it from the + * map first we ensure that a new Python object is created. + */ + sipOMRemoveObject(&cppPyMap, sw); + + /* Call the C++ dtor if there is one. */ + if (ctd->ctd_dealloc != NULL) + ctd->ctd_dealloc(sw); + } +} + + +/* + * If the given name is that of a typedef then the corresponding type is + * returned. + */ +static const char *sip_api_resolve_typedef(const char *name) +{ + const sipExportedModuleDef *em; + + /* + * Note that if the same name is defined as more than one type (which is + * possible if more than one completely independent modules are being + * used) then we might pick the wrong one. + */ + for (em = moduleList; em != NULL; em = em->em_next) + { + if (em->em_nrtypedefs > 0) + { + sipTypedefDef *tdd; + + tdd = (sipTypedefDef *)bsearch(name, em->em_typedefs, + em->em_nrtypedefs, sizeof (sipTypedefDef), + compareTypedefName); + + if (tdd != NULL) + return tdd->tdd_type_name; + } + } + + return NULL; +} + + +/* + * The bsearch() helper function for searching a sorted typedef table. + */ +static int compareTypedefName(const void *key, const void *el) +{ + return strcmp((const char *)key, ((const sipTypedefDef *)el)->tdd_name); +} + + +/* + * Add the given Python object to the given list. Return 0 if there was no + * error. + */ +static int addPyObjectToList(sipPyObject **head, PyObject *object) +{ + sipPyObject *po; + + if ((po = sip_api_malloc(sizeof (sipPyObject))) == NULL) + return -1; + + po->object = object; + po->next = *head; + + *head = po; + + return 0; +} + + +/* + * Register a symbol with a name. A negative value is returned if the name was + * already registered. + */ +static int sip_api_export_symbol(const char *name, void *sym) +{ + sipSymbol *ss; + + if (sip_api_import_symbol(name) != NULL) + return -1; + + if ((ss = sip_api_malloc(sizeof (sipSymbol))) == NULL) + return -1; + + ss->name = name; + ss->symbol = sym; + ss->next = sipSymbolList; + + sipSymbolList = ss; + + return 0; +} + + +/* + * Return the symbol registered with the given name. NULL is returned if the + * name was not registered. + */ +static void *sip_api_import_symbol(const char *name) +{ + sipSymbol *ss; + + for (ss = sipSymbolList; ss != NULL; ss = ss->next) + if (strcmp(ss->name, name) == 0) + return ss->symbol; + + return NULL; +} + + +/* + * Visit a slot connected to an object for the cyclic garbage collector. This + * is only called externally by PyQt3. + */ +static int sip_api_visit_slot(sipSlot *slot, visitproc visit, void *arg) +{ + /* See if the slot has an extra reference. */ + if (slot->weakSlot == Py_True && slot->pyobj != Py_None) + return visit(slot->pyobj, arg); + + return 0; +} + + +/* + * Clear a slot if it has an extra reference to keep it alive. This is only + * called externally by PyQt3. + */ +static void sip_api_clear_any_slot_reference(sipSlot *slot) +{ + if (slot->weakSlot == Py_True) + { + PyObject *xref = slot->pyobj; + + /* + * Replace the slot with None. We don't use NULL as this has another + * meaning. + */ + Py_INCREF(Py_None); + slot->pyobj = Py_None; + + Py_DECREF(xref); + } +} + + +/* + * Convert a Python object to a character and raise an exception if there was + * an error. + */ +static char sip_api_bytes_as_char(PyObject *obj) +{ + char ch; + + if (parseBytes_AsChar(obj, &ch) < 0) + { + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes of length 1 expected not '%s'", +#else + "string of length 1 expected not '%s'", +#endif + Py_TYPE(obj)->tp_name); + + return '\0'; + } + + return ch; +} + + +/* + * Convert a Python object to a string and raise an exception if there was + * an error. + */ +static const char *sip_api_bytes_as_string(PyObject *obj) +{ + const char *a; + + if (parseBytes_AsString(obj, &a) < 0) + { + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes expected not '%s'", +#else + "string expected not '%s'", +#endif + Py_TYPE(obj)->tp_name); + + return NULL; + } + + return a; +} + + +/* + * Convert a Python ASCII string object to a character and raise an exception + * if there was an error. + */ +static char sip_api_string_as_ascii_char(PyObject *obj) +{ + char ch; + + if (parseString_AsASCIIChar(obj, &ch) < 0) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(obj) || PyUnicode_GET_SIZE(obj) != 1) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or ASCII string of length 1 expected not '%s'", +#else + "string or ASCII unicode of length 1 expected not '%s'", +#endif + Py_TYPE(obj)->tp_name); + + return '\0'; + } + + return ch; +} + + +/* + * Parse an ASCII character and return it. + */ +static int parseString_AsASCIIChar(PyObject *obj, char *ap) +{ + return parseString_AsEncodedChar(PyUnicode_AsASCIIString(obj), obj, ap); +} + + +/* + * Convert a Python Latin-1 string object to a character and raise an exception + * if there was an error. + */ +static char sip_api_string_as_latin1_char(PyObject *obj) +{ + char ch; + + if (parseString_AsLatin1Char(obj, &ch) < 0) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(obj) || PyUnicode_GET_SIZE(obj) != 1) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or Latin-1 string of length 1 expected not '%s'", +#else + "string or Latin-1 unicode of length 1 expected not '%s'", +#endif + Py_TYPE(obj)->tp_name); + + return '\0'; + } + + return ch; +} + + +/* + * Parse a Latin-1 character and return it. + */ +static int parseString_AsLatin1Char(PyObject *obj, char *ap) +{ + return parseString_AsEncodedChar(PyUnicode_AsLatin1String(obj), obj, ap); +} + + +/* + * Convert a Python UTF-8 string object to a character and raise an exception + * if there was an error. + */ +static char sip_api_string_as_utf8_char(PyObject *obj) +{ + char ch; + + if (parseString_AsUTF8Char(obj, &ch) < 0) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(obj) || PyUnicode_GET_SIZE(obj) != 1) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or UTF-8 string of length 1 expected not '%s'", +#else + "string or UTF-8 unicode of length 1 expected not '%s'", +#endif + Py_TYPE(obj)->tp_name); + + return '\0'; + } + + return ch; +} + + +/* + * Parse a UTF-8 character and return it. + */ +static int parseString_AsUTF8Char(PyObject *obj, char *ap) +{ + return parseString_AsEncodedChar(PyUnicode_AsUTF8String(obj), obj, ap); +} + + +/* + * Parse an encoded character and return it. + */ +static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap) +{ + SIP_SSIZE_T size; + + if (bytes == NULL) + { + PyErr_Clear(); + + return parseBytes_AsChar(obj, ap); + } + + size = SIPBytes_GET_SIZE(bytes); + + if (size != 1) + { + Py_DECREF(bytes); + return -1; + } + + *ap = *SIPBytes_AS_STRING(bytes); + + Py_DECREF(bytes); + + return 0; +} + + +/* + * Convert a Python ASCII string object to a string and raise an exception if + * there was an error. The object is updated with the one that owns the + * string. Note that None is considered an error. + */ +static const char *sip_api_string_as_ascii_string(PyObject **obj) +{ + PyObject *s = *obj; + const char *a; + + if (s == Py_None || (*obj = parseString_AsASCIIString(s, &a)) == NULL) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(s)) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or ASCII string expected not '%s'", +#else + "string or ASCII unicode expected not '%s'", +#endif + Py_TYPE(s)->tp_name); + + return NULL; + } + + return a; +} + + +/* + * Parse an ASCII string and return it and a new reference to the object that + * owns the string. + */ +static PyObject *parseString_AsASCIIString(PyObject *obj, const char **ap) +{ + return parseString_AsEncodedString(PyUnicode_AsASCIIString(obj), obj, ap); +} + + +/* + * Convert a Python Latin-1 string object to a string and raise an exception if + * there was an error. The object is updated with the one that owns the + * string. Note that None is considered an error. + */ +static const char *sip_api_string_as_latin1_string(PyObject **obj) +{ + PyObject *s = *obj; + const char *a; + + if (s == Py_None || (*obj = parseString_AsLatin1String(s, &a)) == NULL) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(s)) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or Latin-1 string expected not '%s'", +#else + "string or Latin-1 unicode expected not '%s'", +#endif + Py_TYPE(s)->tp_name); + + return NULL; + } + + return a; +} + + +/* + * Parse a Latin-1 string and return it and a new reference to the object that + * owns the string. + */ +static PyObject *parseString_AsLatin1String(PyObject *obj, const char **ap) +{ + return parseString_AsEncodedString(PyUnicode_AsLatin1String(obj), obj, ap); +} + + +/* + * Convert a Python UTF-8 string object to a string and raise an exception if + * there was an error. The object is updated with the one that owns the + * string. Note that None is considered an error. + */ +static const char *sip_api_string_as_utf8_string(PyObject **obj) +{ + PyObject *s = *obj; + const char *a; + + if (s == Py_None || (*obj = parseString_AsUTF8String(s, &a)) == NULL) + { + /* Use the exception set if it was an encoding error. */ + if (!PyUnicode_Check(s)) + PyErr_Format(PyExc_TypeError, +#if PY_MAJOR_VERSION >= 3 + "bytes or UTF-8 string expected not '%s'", +#else + "string or UTF-8 unicode expected not '%s'", +#endif + Py_TYPE(s)->tp_name); + + return NULL; + } + + return a; +} + + +/* + * Parse a UTF-8 string and return it and a new reference to the object that + * owns the string. + */ +static PyObject *parseString_AsUTF8String(PyObject *obj, const char **ap) +{ + return parseString_AsEncodedString(PyUnicode_AsUTF8String(obj), obj, ap); +} + + +/* + * Parse an encoded string and return it and a new reference to the object that + * owns the string. + */ +static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj, + const char **ap) +{ + if (bytes != NULL) + { + *ap = SIPBytes_AS_STRING(bytes); + + return bytes; + } + + PyErr_Clear(); + + if (parseBytes_AsString(obj, ap) < 0) + return NULL; + + Py_INCREF(obj); + + return obj; +} + + +/* + * Parse a character array and return it's address and length. + */ +static int parseBytes_AsCharArray(PyObject *obj, const char **ap, + SIP_SSIZE_T *aszp) +{ + if (obj == Py_None) + { + *ap = NULL; + *aszp = 0; + } + else if (SIPBytes_Check(obj)) + { + *ap = SIPBytes_AS_STRING(obj); + *aszp = SIPBytes_GET_SIZE(obj); + } + else if (PyObject_AsCharBuffer(obj, ap, aszp) < 0) + return -1; + + return 0; +} + + +/* + * Parse a character and return it. + */ +static int parseBytes_AsChar(PyObject *obj, char *ap) +{ + const char *chp; + SIP_SSIZE_T sz; + + if (SIPBytes_Check(obj)) + { + chp = SIPBytes_AS_STRING(obj); + sz = SIPBytes_GET_SIZE(obj); + } + else if (PyObject_AsCharBuffer(obj, &chp, &sz) < 0) + return -1; + + if (sz != 1) + return -1; + + *ap = *chp; + + return 0; +} + + +/* + * Parse a character string and return it. + */ +static int parseBytes_AsString(PyObject *obj, const char **ap) +{ + SIP_SSIZE_T sz; + + return parseBytes_AsCharArray(obj, ap, &sz); +} + + +#if defined(HAVE_WCHAR_H) +/* + * Convert a Python object to a wide character. + */ +static wchar_t sip_api_unicode_as_wchar(PyObject *obj) +{ + wchar_t ch; + + if (parseWChar(obj, &ch) < 0) + { + PyErr_Format(PyExc_ValueError, +#if PY_MAJOR_VERSION >= 3 + "string" +#else + "unicode string" +#endif + " of length 1 expected, not %s", Py_TYPE(obj)->tp_name); + + return L'\0'; + } + + return ch; +} + + +/* + * Convert a Python object to a wide character string on the heap. + */ +static wchar_t *sip_api_unicode_as_wstring(PyObject *obj) +{ + wchar_t *p; + + if (parseWCharString(obj, &p) < 0) + { + PyErr_Format(PyExc_ValueError, +#if PY_MAJOR_VERSION >= 3 + "string" +#else + "unicode string" +#endif + " expected, not %s", Py_TYPE(obj)->tp_name); + + return NULL; + } + + return p; +} + + +/* + * Parse a wide character array and return it's address and length. + */ +static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp) +{ + if (obj == Py_None) + { + *ap = NULL; + *aszp = 0; + + return 0; + } + + if (PyUnicode_Check(obj)) + return convertToWCharArray(obj, ap, aszp); + +#if PY_MAJOR_VERSION < 3 + if (PyString_Check(obj)) + { + int rc; + PyObject *uobj; + + if ((uobj = PyUnicode_FromObject(obj)) == NULL) + return -1; + + rc = convertToWCharArray(uobj, ap, aszp); + Py_DECREF(uobj); + + return rc; + } +#endif + + return -1; +} + + +/* + * Convert a Unicode object to a wide character array and return it's address + * and length. + */ +static int convertToWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp) +{ + SIP_SSIZE_T ulen; + wchar_t *wc; + + ulen = PyUnicode_GET_SIZE(obj); + + if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL) + return -1; + + ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); + + if (ulen < 0) + { + sip_api_free(wc); + return -1; + } + + *ap = wc; + *aszp = ulen; + + return 0; +} + + +/* + * Parse a wide character and return it. + */ +static int parseWChar(PyObject *obj, wchar_t *ap) +{ + if (PyUnicode_Check(obj)) + return convertToWChar(obj, ap); + +#if PY_MAJOR_VERSION < 3 + if (PyString_Check(obj)) + { + int rc; + PyObject *uobj; + + if ((uobj = PyUnicode_FromObject(obj)) == NULL) + return -1; + + rc = convertToWChar(uobj, ap); + Py_DECREF(uobj); + + return rc; + } +#endif + + return -1; +} + + +/* + * Convert a Unicode object to a wide character and return it. + */ +static int convertToWChar(PyObject *obj, wchar_t *ap) +{ + if (PyUnicode_GET_SIZE(obj) != 1) + return -1; + + if (PyUnicode_AsWideChar((PyUnicodeObject *)obj, ap, 1) != 1) + return -1; + + return 0; +} + + +/* + * Parse a wide character string and return a copy on the heap. + */ +static int parseWCharString(PyObject *obj, wchar_t **ap) +{ + if (obj == Py_None) + { + *ap = NULL; + + return 0; + } + + if (PyUnicode_Check(obj)) + return convertToWCharString(obj, ap); + +#if PY_MAJOR_VERSION < 3 + if (PyString_Check(obj)) + { + int rc; + PyObject *uobj; + + if ((uobj = PyUnicode_FromObject(obj)) == NULL) + return -1; + + rc = convertToWCharString(uobj, ap); + Py_DECREF(uobj); + + return rc; + } +#endif + + return -1; +} + + +/* + * Convert a Unicode object to a wide character string and return a copy on + * the heap. + */ +static int convertToWCharString(PyObject *obj, wchar_t **ap) +{ + SIP_SSIZE_T ulen; + wchar_t *wc; + + ulen = PyUnicode_GET_SIZE(obj); + + if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL) + return -1; + + ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); + + if (ulen < 0) + { + sip_api_free(wc); + return -1; + } + + wc[ulen] = L'\0'; + + *ap = wc; + + return 0; +} + +#else + +/* + * Convert a Python object to a wide character. + */ +static int sip_api_unicode_as_wchar(PyObject *obj) +{ + raiseNoWChar(); + + return 0; +} + + +/* + * Convert a Python object to a wide character. + */ +static int *sip_api_unicode_as_wstring(PyObject *obj) +{ + raiseNoWChar(); + + return NULL; +} + + +/* + * Report the need for absent wide character support. + */ +static void raiseNoWChar() +{ + PyErr_SetString(PyExc_SystemError, "sip built without wchar_t support"); +} + +#endif + + +/* + * The enum type alloc slot. + */ +static PyObject *sipEnumType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems) +{ + sipEnumTypeObject *py_type; + sipPySlotDef *psd; + + assert(currentType != NULL); + + /* Call the standard super-metatype alloc. */ + if ((py_type = (sipEnumTypeObject *)PyType_Type.tp_alloc(self, nitems)) == NULL) + return NULL; + + /* + * Set the links between the Python type object and the generated type + * structure. Strictly speaking this doesn't need to be done here. + */ + py_type->type = currentType; + currentType->u.td_py_type = (PyTypeObject *)py_type; + + /* + * Initialise any slots. This must be done here, after the type is + * allocated but before PyType_Ready() is called. + */ + if ((psd = ((sipEnumTypeDef *)currentType)->etd_pyslots) != NULL) + addTypeSlots(&py_type->super, psd); + + currentType = NULL; + + return (PyObject *)py_type; +} diff --git a/siplib/siplib.sbf b/siplib/siplib.sbf new file mode 100644 index 0000000..79f9a45 --- /dev/null +++ b/siplib/siplib.sbf @@ -0,0 +1,19 @@ +# This is the build file for the extension module. +# +# Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> +# +# 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. + +target = sip +sources = siplib.c apiversions.c descriptors.c qtlib.c threads.c objmap.c voidptr.c bool.cpp +headers = sip.h sipint.h diff --git a/siplib/threads.c b/siplib/threads.c new file mode 100644 index 0000000..0854a0a --- /dev/null +++ b/siplib/threads.c @@ -0,0 +1,226 @@ +/* + * Thread support for the SIP library. This module provides the hooks for + * C++ classes that provide a thread interface to interact properly with the + * Python threading infrastructure. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 "sip.h" +#include "sipint.h" + + +/* + * The data associated with pending request to wrap an object. + */ +typedef struct _pendingDef { + void *cpp; /* The C/C++ object ot be wrapped. */ + sipWrapper *owner; /* The owner of the object. */ + int flags; /* The flags. */ +} pendingDef; + + +#ifdef WITH_THREAD + +#include <pythread.h> + + +/* + * The per thread data we need to maintain. + */ +typedef struct _threadDef { + long thr_ident; /* The thread identifier. */ + pendingDef pending; /* An object waiting to be wrapped. */ + struct _threadDef *next; /* Next in the list. */ +} threadDef; + + +static threadDef *threads = NULL; /* Linked list of threads. */ + + +static threadDef *currentThreadDef(void); + +#endif + + +static pendingDef pending; /* An object waiting to be wrapped. */ + + +/* + * Get the address of any C/C++ object waiting to be wrapped. + */ +void *sipGetPending(sipWrapper **op, int *fp) +{ + pendingDef *pp; + +#ifdef WITH_THREAD + threadDef *thread; + + if ((thread = currentThreadDef()) != NULL) + pp = &thread->pending; + else + pp = &pending; +#else + pp = &pending; +#endif + + if (pp->cpp != NULL) + { + if (op != NULL) + *op = pp->owner; + + if (fp != NULL) + *fp = pp->flags; + } + + return pp->cpp; +} + + +/* + * Convert a new C/C++ pointer to a Python instance. + */ +PyObject *sipWrapSimpleInstance(void *cppPtr, const sipTypeDef *td, + sipWrapper *owner, int flags) +{ + static PyObject *nullargs = NULL; + + pendingDef old_pending; + PyObject *self; +#ifdef WITH_THREAD + threadDef *thread; +#endif + + if (nullargs == NULL && (nullargs = PyTuple_New(0)) == NULL) + return NULL; + + if (cppPtr == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + /* + * Object creation can trigger the Python garbage collector which in turn + * can execute arbitrary Python code which can then call this function + * recursively. Therefore we save any existing pending object before + * setting the new one. + */ +#ifdef WITH_THREAD + if ((thread = currentThreadDef()) != NULL) + { + old_pending = thread->pending; + + thread->pending.cpp = cppPtr; + thread->pending.owner = owner; + thread->pending.flags = flags; + } + else + { + old_pending = pending; + + pending.cpp = cppPtr; + pending.owner = owner; + pending.flags = flags; + } +#else + old_pending = pending; + + pending.cpp = cppPtr; + pending.owner = owner; + pending.flags = flags; +#endif + + self = PyObject_Call((PyObject *)sipTypeAsPyTypeObject(td), nullargs, NULL); + +#ifdef WITH_THREAD + if (thread != NULL) + thread->pending = old_pending; + else + pending = old_pending; +#else + pending = old_pending; +#endif + + return self; +} + + +/* + * This is called from a newly created thread to initialise some thread local + * storage. + */ +void sip_api_start_thread(void) +{ +#ifdef WITH_THREAD + threadDef *thread; + + /* Save the thread ID. First, find an empty slot in the list. */ + for (thread = threads; thread != NULL; thread = thread->next) + if (thread->thr_ident == 0) + break; + + if (thread == NULL) + { + thread = sip_api_malloc(sizeof (threadDef)); + thread->next = threads; + threads = thread; + } + + if (thread != NULL) + { + thread->thr_ident = PyThread_get_thread_ident(); + thread->pending.cpp = NULL; + } +#endif +} + + +/* + * Handle the termination of a thread. The thread state should already have + * been handled by the last call to PyGILState_Release(). + */ +void sip_api_end_thread(void) +{ +#ifdef WITH_THREAD + threadDef *thread; + + /* We have the GIL at this point. */ + if ((thread = currentThreadDef()) != NULL) + thread->thr_ident = 0; +#endif +} + + +#ifdef WITH_THREAD + +/* + * Return the thread data for the current thread or NULL if it wasn't + * recognised. + */ +static threadDef *currentThreadDef(void) +{ + threadDef *thread; + long ident = PyThread_get_thread_ident(); + + for (thread = threads; thread != NULL; thread = thread->next) + if (thread->thr_ident == ident) + break; + + return thread; +} + +#endif diff --git a/siplib/voidptr.c b/siplib/voidptr.c new file mode 100644 index 0000000..fc26046 --- /dev/null +++ b/siplib/voidptr.c @@ -0,0 +1,579 @@ +/* + * SIP library code. + * + * Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com> + * + * 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 <Python.h> + +#include <stddef.h> + +#include "sip.h" +#include "sipint.h" + + +/* The object data structure. */ +typedef struct { + PyObject_HEAD + void *voidptr; + SIP_SSIZE_T size; + int rw; +} sipVoidPtrObject; + + +/* The structure used to hold the results of a voidptr conversion. */ +struct vp_values { + void *voidptr; + SIP_SSIZE_T size; + int rw; +}; + + +static PyObject *make_voidptr(void *voidptr, SIP_SSIZE_T size, int rw); +static int vp_convertor(PyObject *arg, struct vp_values *vp); + + +/* + * Implement __new__ for the type. + */ +static PyObject *sipVoidPtr_new(PyTypeObject *subtype, PyObject *args, + PyObject *kw) +{ + static char *kwlist[] = {"address", "size", "writeable", NULL}; + + struct vp_values vp_conversion; + SIP_SSIZE_T size = -1; + int rw = -1; + PyObject *obj; + + if (!PyArg_ParseTupleAndKeywords(args, kw, +#if PY_VERSION_HEX >= 0x02050000 + "O&|ni:voidptr", +#else + "O&|ii:voidptr", +#endif + kwlist, vp_convertor, &vp_conversion, &size, &rw)) + return NULL; + + /* Use the explicit size if one was given. */ + if (size >= 0) + vp_conversion.size = size; + + /* Use the explicit writeable flag if one was given. */ + if (rw >= 0) + vp_conversion.rw = rw; + + /* Create the instance. */ + if ((obj = subtype->tp_alloc(subtype, 0)) == NULL) + return NULL; + + /* Save the values. */ + ((sipVoidPtrObject *)obj)->voidptr = vp_conversion.voidptr; + ((sipVoidPtrObject *)obj)->size = vp_conversion.size; + ((sipVoidPtrObject *)obj)->rw = vp_conversion.rw; + + return obj; +} + + +#if PY_MAJOR_VERSION >= 3 +/* + * The read buffer implementation for Python v3. + */ +static int sipVoidPtr_getbuffer(PyObject *self, Py_buffer *buf, int flags) +{ + sipVoidPtrObject *v = (sipVoidPtrObject *)self; + + return PyBuffer_FillInfo(buf, self, v->voidptr, v->size, !v->rw, flags); +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The read buffer implementation for Python v2. + */ +static SIP_SSIZE_T sipVoidPtr_getbuffer(PyObject *self, SIP_SSIZE_T seg, + void **ptr) +{ + SIP_SSIZE_T size = ((sipVoidPtrObject *)self)->size; + + if (size < 0 || seg != 0) + { + PyErr_SetString(PyExc_SystemError, "invalid buffer segment"); + return -1; + } + + *ptr = ((sipVoidPtrObject *)self)->voidptr; + + return size; +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The write buffer implementation for Python v2. + */ +static SIP_SSIZE_T sipVoidPtr_getwritebuffer(PyObject *self, SIP_SSIZE_T seg, + void **ptr) +{ + if (((sipVoidPtrObject *)self)->rw) + return sipVoidPtr_getbuffer(self, seg, ptr); + + PyErr_SetString(PyExc_TypeError, "the sip.voidptr is not writeable"); + return -1; +} +#endif + + +#if PY_MAJOR_VERSION < 3 +/* + * The segment count implementation for Python v2. + */ +static SIP_SSIZE_T sipVoidPtr_getsegcount(PyObject *self, SIP_SSIZE_T *lenp) +{ + SIP_SSIZE_T segs, len; + + len = ((sipVoidPtrObject *)self)->size; + segs = (len < 0 ? 0 : 1); + + if (lenp != NULL) + *lenp = len; + + return segs; +} +#endif + + +/* + * Implement int() for the type. + */ +static PyObject *sipVoidPtr_int(sipVoidPtrObject *v) +{ + return PyLong_FromVoidPtr(v->voidptr); +} + + +#if PY_MAJOR_VERSION < 3 +/* + * Implement hex() for the type. + */ +static PyObject *sipVoidPtr_hex(sipVoidPtrObject *v) +{ + char buf[2 + 16 + 1]; + + PyOS_snprintf(buf, sizeof (buf), "0x%.*lx", (int)(sizeof (void *) * 2), + (unsigned long)v->voidptr); + + return PyString_FromString(buf); +} +#endif + + +#if defined(SIP_USE_PYCAPSULE) +/* + * Implement ascapsule() for the type. + */ +static PyObject *sipVoidPtr_ascapsule(sipVoidPtrObject *v, PyObject *arg) +{ + return PyCapsule_New(v->voidptr, NULL, NULL); +} +#endif + + +/* + * Implement ascobject() for the type. + */ +static PyObject *sipVoidPtr_ascobject(sipVoidPtrObject *v, PyObject *arg) +{ + return PyCObject_FromVoidPtr(v->voidptr, NULL); +} + + +/* + * Implement asstring() for the type. + */ +static PyObject *sipVoidPtr_asstring(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:asstring", +#else + "|i:asstring", +#endif + 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 must have a size"); + return NULL; + } + + return SIPBytes_FromStringAndSize(v->voidptr, size); +} + + +/* + * Implement getsize() for the type. + */ +static PyObject *sipVoidPtr_getsize(sipVoidPtrObject *v, PyObject *arg) +{ +#if PY_MAJOR_VERSION >= 3 + return PyLong_FromSsize_t(v->size); +#elif PY_VERSION_HEX >= 0x02050000 + return PyInt_FromSsize_t(v->size); +#else + return PyInt_FromLong(v->size); +#endif +} + + +/* + * Implement setsize() for the type. + */ +static PyObject *sipVoidPtr_setsize(sipVoidPtrObject *v, PyObject *arg) +{ + SIP_SSIZE_T size; + +#if PY_MAJOR_VERSION >= 3 + size = PyLong_AsSsize_t(arg); +#elif PY_VERSION_HEX >= 0x02050000 + size = PyInt_AsSsize_t(arg); +#else + size = (int)PyInt_AsLong(arg); +#endif + + if (PyErr_Occurred()) + return NULL; + + v->size = size; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Implement getwriteable() for the type. + */ +static PyObject *sipVoidPtr_getwriteable(sipVoidPtrObject *v, PyObject *arg) +{ + return PyBool_FromLong(v->rw); +} + + +/* + * Implement setwriteable() for the type. + */ +static PyObject *sipVoidPtr_setwriteable(sipVoidPtrObject *v, PyObject *arg) +{ + int rw; + + rw = (int)SIPLong_AsLong(arg); + + if (PyErr_Occurred()) + return NULL; + + v->rw = rw; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* The methods data structure. */ +static PyMethodDef sipVoidPtr_Methods[] = { +#if defined(SIP_USE_PYCAPSULE) + {"ascapsule", (PyCFunction)sipVoidPtr_ascapsule, METH_NOARGS, NULL}, +#endif + {"ascobject", (PyCFunction)sipVoidPtr_ascobject, METH_NOARGS, NULL}, + {"asstring", (PyCFunction)sipVoidPtr_asstring, 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} +}; + + +/* The number methods data structure. */ +static PyNumberMethods sipVoidPtr_NumberMethods = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_divide */ +#endif + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_bool (Python v3), nb_nonzero (Python v2) */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_coerce */ +#endif + (unaryfunc)sipVoidPtr_int, /* nb_int */ + 0, /* nb_reserved (Python v3), nb_long (Python v2) */ + 0, /* nb_float */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_oct */ + (unaryfunc)sipVoidPtr_hex, /* nb_hex */ +#endif + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ +#if PY_MAJOR_VERSION < 3 + 0, /* nb_inplace_divide */ +#endif + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +#if PY_VERSION_HEX >= 0x02050000 + 0 /* nb_index */ +#endif +}; + + +/* The buffer methods data structure. */ +static PyBufferProcs sipVoidPtr_BufferProcs = { + sipVoidPtr_getbuffer, +#if PY_MAJOR_VERSION >= 3 + NULL, +#else + sipVoidPtr_getwritebuffer, + sipVoidPtr_getsegcount, +#if PY_VERSION_HEX >= 0x02050000 + (charbufferproc)sipVoidPtr_getbuffer +#else + (getcharbufferproc)sipVoidPtr_getbuffer +#endif +#endif +}; + + +/* The type data structure. */ +PyTypeObject sipVoidPtr_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "sip.voidptr", /* tp_name */ + sizeof (sipVoidPtrObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved (Python v3), tp_compare (Python v2) */ + 0, /* tp_repr */ + &sipVoidPtr_NumberMethods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &sipVoidPtr_BufferProcs, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + sipVoidPtr_Methods, /* 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 */ + sipVoidPtr_new, /* tp_new */ +}; + + +/* + * A convenience function to convert a C/C++ void pointer from a Python object. + */ +void *sip_api_convert_to_void_ptr(PyObject *obj) +{ + if (obj == NULL) + { + PyErr_SetString(PyExc_TypeError, "sip.voidptr is NULL"); + return NULL; + } + + if (obj == Py_None) + return NULL; + + if (PyObject_TypeCheck(obj, &sipVoidPtr_Type)) + return ((sipVoidPtrObject *)obj)->voidptr; + +#if defined(SIP_USE_PYCAPSULE) + if (PyCapsule_CheckExact(obj)) + return PyCapsule_GetPointer(obj, NULL); +#endif + + if (PyCObject_Check(obj)) + return PyCObject_AsVoidPtr(obj); + +#if PY_MAJOR_VERSION >= 3 + return PyLong_AsVoidPtr(obj); +#else + return (void *)PyInt_AsLong(obj); +#endif +} + + +/* + * Convert a C/C++ void pointer to a sip.voidptr object. + */ +PyObject *sip_api_convert_from_void_ptr(void *val) +{ + return make_voidptr(val, -1, TRUE); +} + + +/* + * Convert a C/C++ void pointer to a sip.voidptr object. + */ +PyObject *sip_api_convert_from_const_void_ptr(const void *val) +{ + return make_voidptr((void *)val, -1, FALSE); +} + + +/* + * Convert a sized C/C++ void pointer to a sip.voidptr object. + */ +PyObject *sip_api_convert_from_void_ptr_and_size(void *val, SIP_SSIZE_T size) +{ + return make_voidptr(val, size, TRUE); +} + + +/* + * Convert a sized C/C++ const void pointer to a sip.voidptr object. + */ +PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val, + SIP_SSIZE_T size) +{ + return make_voidptr((void *)val, size, FALSE); +} + + +/* + * Do the work of converting a void pointer. + */ +static PyObject *make_voidptr(void *voidptr, SIP_SSIZE_T size, int rw) +{ + sipVoidPtrObject *self; + + if (voidptr == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + if ((self = PyObject_NEW(sipVoidPtrObject, &sipVoidPtr_Type)) == NULL) + return NULL; + + self->voidptr = voidptr; + self->size = size; + self->rw = rw; + + return (PyObject *)self; +} + + +/* + * Convert a Python object to the values needed to create a voidptr. + */ +static int vp_convertor(PyObject *arg, struct vp_values *vp) +{ + void *ptr; + SIP_SSIZE_T size = -1; + int rw = TRUE; + + if (arg == Py_None) + ptr = NULL; +#if defined(SIP_USE_PYCAPSULE) + else if (PyCapsule_CheckExact(arg)) + ptr = PyCapsule_GetPointer(arg, NULL); +#endif + else if (PyCObject_Check(arg)) + ptr = PyCObject_AsVoidPtr(arg); + else if (PyObject_TypeCheck(arg, &sipVoidPtr_Type)) + { + ptr = ((sipVoidPtrObject *)arg)->voidptr; + size = ((sipVoidPtrObject *)arg)->size; + rw = ((sipVoidPtrObject *)arg)->rw; + } + else + { +#if PY_MAJOR_VERSION >= 3 + ptr = PyLong_AsVoidPtr(arg); +#else + ptr = (void *)PyInt_AsLong(arg); +#endif + + if (PyErr_Occurred()) + { +#if PY_VERSION_HEX >= 0x03010000 + PyErr_SetString(PyExc_TypeError, "a single integer, CObject, None or another voidptr is required"); +#else + PyErr_SetString(PyExc_TypeError, "a single integer, Capsule, CObject, None or another voidptr is required"); +#endif + return 0; + } + } + + vp->voidptr = ptr; + vp->size = size; + vp->rw = rw; + + return 1; +} |