././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1720784898.5584564 PyQt5_sip-12.15.0/0000755000076500000240000000000014644214003012372 5ustar00philstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/LICENSE0000644000076500000240000000242414644214002013400 0ustar00philstaffCopyright 2024 Phil Thompson Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/MANIFEST.in0000644000076500000240000000004314644214002014124 0ustar00philstaffinclude *.h include pyproject.toml ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1720784898.5583668 PyQt5_sip-12.15.0/PKG-INFO0000644000076500000240000000064514644214003013474 0ustar00philstaffMetadata-Version: 2.1 Name: PyQt5_sip Version: 12.15.0 Summary: The sip module support for PyQt5 Home-page: https://github.com/Python-SIP/sip Author: Phil Thompson Author-email: phil@riverbankcomputing.com License: SIP Platform: X11 Platform: macOS Platform: Windows Requires-Python: >=3.8 License-File: LICENSE sip Extension Module ==================== The sip extension module provides support for the PyQt5 package. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1720784898.5580735 PyQt5_sip-12.15.0/PyQt5_sip.egg-info/0000755000076500000240000000000014644214003015721 5ustar00philstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/PyQt5_sip.egg-info/PKG-INFO0000644000076500000240000000064514644214002017022 0ustar00philstaffMetadata-Version: 2.1 Name: PyQt5-sip Version: 12.15.0 Summary: The sip module support for PyQt5 Home-page: https://github.com/Python-SIP/sip Author: Phil Thompson Author-email: phil@riverbankcomputing.com License: SIP Platform: X11 Platform: macOS Platform: Windows Requires-Python: >=3.8 License-File: LICENSE sip Extension Module ==================== The sip extension module provides support for the PyQt5 package. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/PyQt5_sip.egg-info/SOURCES.txt0000644000076500000240000000050214644214002017601 0ustar00philstaffLICENSE MANIFEST.in README apiversions.c descriptors.c int_convertors.c objmap.c pyproject.toml qtlib.c setup.cfg setup.py sip.h sip_array.c sip_array.h sipint.h siplib.c threads.c voidptr.c PyQt5_sip.egg-info/PKG-INFO PyQt5_sip.egg-info/SOURCES.txt PyQt5_sip.egg-info/dependency_links.txt PyQt5_sip.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/PyQt5_sip.egg-info/dependency_links.txt0000644000076500000240000000000114644214002021766 0ustar00philstaff ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/PyQt5_sip.egg-info/top_level.txt0000644000076500000240000000000614644214002020446 0ustar00philstaffPyQt5 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/README0000644000076500000240000000015414644214002013251 0ustar00philstaffsip Extension Module ==================== The sip extension module provides support for the PyQt5 package. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/apiversions.c0000644000076500000240000001522214644214002015101 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * The implementation of the supprt for setting API versions. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #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 = 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; (void)self; if (sip_api_deprecated(NULL, "getapi") < 0) return NULL; 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; } return PyLong_FromLong(avd->version_nr); } /* * Set the version number for an API. */ PyObject *sipSetAPI(PyObject *self, PyObject *args) { const char *api; int version_nr; const apiVersionDef *avd; (void)self; if (sip_api_deprecated(NULL, "setapi") < 0) return NULL; 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]); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/descriptors.c0000644000076500000240000003143414644214002015103 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * The implementation of the different descriptors. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #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, and we * handle mixins via a delegate. *****************************************************************************/ /* Forward declarations of slots. */ static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, PyObject *type); static PyObject *sipMethodDescr_repr(PyObject *self); static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg); static int sipMethodDescr_clear(PyObject *self); static void sipMethodDescr_dealloc(PyObject *self); /* * The object data structure. */ typedef struct _sipMethodDescr { PyObject_HEAD /* The method definition. */ PyMethodDef *pmd; /* The mixin name, if any. */ PyObject *mixin_name; } sipMethodDescr; /* * The type data structure. */ PyTypeObject sipMethodDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) "sip.methoddescriptor", /* tp_name */ sizeof (sipMethodDescr), /* tp_basicsize */ 0, /* tp_itemsize */ sipMethodDescr_dealloc, /* 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|Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ sipMethodDescr_traverse,/* tp_traverse */ sipMethodDescr_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 */ sipMethodDescr_descr_get, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; /* * 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; ((sipMethodDescr *)descr)->mixin_name = NULL; } return descr; } /* * Return a new method descriptor based on an existing one and a mixin name. */ PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name) { PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0); if (descr != NULL) { ((sipMethodDescr *)descr)->pmd = ((sipMethodDescr *)orig)->pmd; ((sipMethodDescr *)descr)->mixin_name = mixin_name; Py_INCREF(mixin_name); } return descr; } /* * The descriptor's descriptor get slot. */ static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj, PyObject *type) { sipMethodDescr *md = (sipMethodDescr *)self; (void)type; if (obj == Py_None) obj = NULL; else if (md->mixin_name != NULL) obj = PyObject_GetAttr(obj, md->mixin_name); return PyCFunction_New(md->pmd, obj); } /* * 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 PyUnicode_FromFormat("", md->pmd->ml_name); } /* * The descriptor's traverse slot. */ static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg) { if (((sipMethodDescr *)self)->mixin_name != NULL) { int vret = visit(((sipMethodDescr *)self)->mixin_name, arg); if (vret != 0) return vret; } return 0; } /* * The descriptor's clear slot. */ static int sipMethodDescr_clear(PyObject *self) { PyObject *tmp = ((sipMethodDescr *)self)->mixin_name; ((sipMethodDescr *)self)->mixin_name = NULL; Py_XDECREF(tmp); return 0; } /* * The descriptor's dealloc slot. */ static void sipMethodDescr_dealloc(PyObject *self) { PyObject_GC_UnTrack(self); sipMethodDescr_clear(self); Py_TYPE(self)->tp_free(self); } /***************************************************************************** * A variable descriptor. We don't use the similar Python descriptor because * it doesn't support static variables. *****************************************************************************/ /* 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); static int sipVariableDescr_traverse(PyObject *self, visitproc visit, void *arg); static int sipVariableDescr_clear(PyObject *self); static void sipVariableDescr_dealloc(PyObject *self); /* * 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; /* The mixin name, if any. */ PyObject *mixin_name; } sipVariableDescr; /* * The type data structure. */ PyTypeObject sipVariableDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) "sip.variabledescriptor", /* tp_name */ sizeof (sipVariableDescr), /* tp_basicsize */ 0, /* tp_itemsize */ sipVariableDescr_dealloc, /* 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|Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ sipVariableDescr_traverse, /* tp_traverse */ sipVariableDescr_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 */ sipVariableDescr_descr_get, /* tp_descr_get */ sipVariableDescr_descr_set, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; /* 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; ((sipVariableDescr *)descr)->mixin_name = NULL; } return descr; } /* * Return a new variable descriptor based on an existing one and a mixin name. */ PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name) { PyObject *descr = PyType_GenericAlloc(&sipVariableDescr_Type, 0); if (descr != NULL) { ((sipVariableDescr *)descr)->vd = ((sipVariableDescr *)orig)->vd; ((sipVariableDescr *)descr)->td = ((sipVariableDescr *)orig)->td; ((sipVariableDescr *)descr)->cod = ((sipVariableDescr *)orig)->cod; ((sipVariableDescr *)descr)->mixin_name = mixin_name; Py_INCREF(mixin_name); } return descr; } /* * 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 ((sipVariableGetterFunc)vd->vd->vd_getter)(addr, obj, 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 ((sipVariableSetterFunc)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_type == ClassVariable) { 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; } if (vd->mixin_name != NULL) obj = PyObject_GetAttr(obj, vd->mixin_name); /* Get the C++ instance. */ if ((addr = sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, vd->td)) == NULL) return -1; } *addrp = addr; return 0; } /* * The descriptor's traverse slot. */ static int sipVariableDescr_traverse(PyObject *self, visitproc visit, void *arg) { if (((sipVariableDescr *)self)->mixin_name != NULL) { int vret = visit(((sipVariableDescr *)self)->mixin_name, arg); if (vret != 0) return vret; } return 0; } /* * The descriptor's clear slot. */ static int sipVariableDescr_clear(PyObject *self) { PyObject *tmp = ((sipVariableDescr *)self)->mixin_name; ((sipVariableDescr *)self)->mixin_name = NULL; Py_XDECREF(tmp); return 0; } /* * The descriptor's dealloc slot. */ static void sipVariableDescr_dealloc(PyObject *self) { PyObject_GC_UnTrack(self); sipVariableDescr_clear(self); Py_TYPE(self)->tp_free(self); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/int_convertors.c0000644000076500000240000001744114644214002015622 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * The implementation of the Python object to C/C++ integer convertors. * * Copyright (c) 2024 Phil Thompson */ /* * NOTES * * The legacy integer conversions (ie. without support for overflow checking) * are flawed and inconsistent. Large Python signed values were converted to * -1 whereas small values were truncated. When converting function arguments * all overlows were ignored, however when converting the results returned by * Python re-implementations then large Python values raised an exception * whereas small values were truncated. * * With the new integer conversions large Python signed values will always * raise an overflow exception (even if overflow checking is disabled). This * is because a truncated value is not available - it would have to be * computed. This may cause new exceptions to be raised but is justified in * that the value that was being used bore no relation to the original value. */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include "sipint.h" /* Wrappers to deal with lack of long long support. */ #if defined(HAVE_LONG_LONG) #define SIPLong_AsLongLong PyLong_AsLongLong #define SIP_LONG_LONG PY_LONG_LONG #define SIP_LONG_LONG_FORMAT "%lld" #define SIP_UNSIGNED_LONG_LONG_FORMAT "%llu" #else #define SIPLong_AsLongLong PyLong_AsLong #define SIP_LONG_LONG long #define SIP_LONG_LONG_FORMAT "%ld" #define SIP_UNSIGNED_LONG_LONG_FORMAT "%lu" #endif static int overflow_checking = FALSE; /* Check for overflows. */ static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min, SIP_LONG_LONG max); static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max); static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max); static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max); /* * Enable or disable overflow checking (Python API). */ PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args) { int enable; (void)self; if (PyArg_ParseTuple(args, "i:enableoverflowchecking", &enable)) { PyObject *res; res = (sip_api_enable_overflow_checking(enable) ? Py_True : Py_False); Py_INCREF(res); return res; } return NULL; } /* * Enable or disable overflow checking (C API). */ int sip_api_enable_overflow_checking(int enable) { int was_enabled = overflow_checking; overflow_checking = enable; return was_enabled; } /* * Convert a Python object to a C++ bool (returned as an int). */ int sip_api_convert_to_bool(PyObject *o) { int was_enabled, v; /* Convert the object to an int while checking for overflow. */ was_enabled = sip_api_enable_overflow_checking(TRUE); v = sip_api_long_as_int(o); sip_api_enable_overflow_checking(was_enabled); if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Clear(); /* The value must have been non-zero. */ v = 1; } else { PyErr_Format(PyExc_TypeError, "a 'bool' is expected not '%s'", Py_TYPE(o)->tp_name); v = -1; } } else if (v != 0) { v = 1; } return v; } /* * Convert a Python object to a C char. */ char sip_api_long_as_char(PyObject *o) { return (char)long_as_long_long(o, CHAR_MIN, CHAR_MAX); } /* * Convert a Python object to a C signed char. */ signed char sip_api_long_as_signed_char(PyObject *o) { return (signed char)long_as_long_long(o, SCHAR_MIN, SCHAR_MAX); } /* * Convert a Python object to a C unsigned char. */ unsigned char sip_api_long_as_unsigned_char(PyObject *o) { return (unsigned char)long_as_unsigned_long(o, UCHAR_MAX); } /* * Convert a Python object to a C short. */ short sip_api_long_as_short(PyObject *o) { return (short)long_as_long_long(o, SHRT_MIN, SHRT_MAX); } /* * Convert a Python object to a C unsigned short. */ unsigned short sip_api_long_as_unsigned_short(PyObject *o) { return (unsigned short)long_as_unsigned_long(o, USHRT_MAX); } /* * Convert a Python object to a C int. */ int sip_api_long_as_int(PyObject *o) { return (int)long_as_long_long(o, INT_MIN, INT_MAX); } /* * Convert a Python object to a C unsigned int. */ unsigned sip_api_long_as_unsigned_int(PyObject *o) { return (unsigned)long_as_unsigned_long(o, UINT_MAX); } /* * Convert a Python object to a C size_t. */ size_t sip_api_long_as_size_t(PyObject *o) { return (size_t)long_as_unsigned_long(o, SIZE_MAX); } /* * Convert a Python object to a C long. */ long sip_api_long_as_long(PyObject *o) { return (long)long_as_long_long(o, LONG_MIN, LONG_MAX); } /* * Convert a Python object to a C unsigned long. */ unsigned long sip_api_long_as_unsigned_long(PyObject *o) { return long_as_unsigned_long(o, ULONG_MAX); } #if defined(HAVE_LONG_LONG) /* * Convert a Python object to a C long long. */ PY_LONG_LONG sip_api_long_as_long_long(PyObject *o) { return long_as_long_long(o, LLONG_MIN, LLONG_MAX); } /* * Convert a Python object to a C unsigned long long. */ unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o) { unsigned PY_LONG_LONG value; /* * Note that this doesn't handle Python v2 int objects, but the old * convertors didn't either. */ PyErr_Clear(); if (overflow_checking) { value = PyLong_AsUnsignedLongLong(o); if (PyErr_Occurred()) { /* Provide a better exception message. */ if (PyErr_ExceptionMatches(PyExc_OverflowError)) raise_unsigned_overflow(ULLONG_MAX); } } else { value = PyLong_AsUnsignedLongLongMask(o); } return value; } #endif /* * Convert a Python object to a long long checking that the value is within a * range if overflow checking is enabled. */ static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min, SIP_LONG_LONG max) { SIP_LONG_LONG value; PyErr_Clear(); value = SIPLong_AsLongLong(o); if (PyErr_Occurred()) { /* Provide a better exception message. */ if (PyErr_ExceptionMatches(PyExc_OverflowError)) raise_signed_overflow(min, max); } else if (overflow_checking && (value < min || value > max)) { raise_signed_overflow(min, max); } return value; } /* * Convert a Python object to an unsigned long checking that the value is * within a range if overflow checking is enabled. */ static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max) { unsigned long value; PyErr_Clear(); if (overflow_checking) { value = PyLong_AsUnsignedLong(o); if (PyErr_Occurred()) { /* Provide a better exception message. */ if (PyErr_ExceptionMatches(PyExc_OverflowError)) raise_unsigned_overflow(max); } else if (value > max) { raise_unsigned_overflow(max); } } else { value = PyLong_AsUnsignedLongMask(o); } return value; } /* * Raise an overflow exception if a signed value is out of range. */ static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max) { PyErr_Format(PyExc_OverflowError, "value must be in the range " SIP_LONG_LONG_FORMAT " to " SIP_LONG_LONG_FORMAT, min, max); } /* * Raise an overflow exception if an unsigned value is out of range. */ static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max) { PyErr_Format(PyExc_OverflowError, "value must be in the range 0 to " SIP_UNSIGNED_LONG_LONG_FORMAT, max); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/objmap.c0000644000076500000240000003174414644214002014016 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * This module implements a hash table class for mapping C/C++ addresses to the * corresponding wrapped Python object. * * Copyright (c) 2024 Phil Thompson */ #include #include #include "sipint.h" #define hash_1(k,s) (((uintptr_t)(k)) % (s)) #define hash_2(k,s) ((s) - 2 - (hash_1((k),(s)) % ((s) - 2))) /* Prime numbers to use as hash table sizes. */ static uintptr_t 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(uintptr_t); static sipHashEntry *findHashEntry(sipObjectMap *,void *); static void add_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val); static void add_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd); static int remove_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val); static void remove_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd); static void reorganiseMap(sipObjectMap *om); static void *getUnguardedPointer(sipSimpleWrapper *w); /* * 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(uintptr_t 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) { uintptr_t 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) { sipSimpleWrapper *unaliased; unaliased = (sipIsAlias(sw) ? (sipSimpleWrapper *)sw->data : sw); /* * 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(unaliased) == 0) continue; /* Ignore it if the C/C++ address is no longer valid. */ if (sip_api_get_address(unaliased) == NULL) 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(unaliased, py_type)) return unaliased; } return NULL; } /* * Add a C/C++ address and the corresponding wrapped Python object to the map. */ void sipOMAddObject(sipObjectMap *om, sipSimpleWrapper *val) { void *addr = getUnguardedPointer(val); const sipClassTypeDef *base_ctd; /* Add the object. */ add_object(om, addr, val); /* Add any aliases. */ base_ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(val))->wt_td; add_aliases(om, addr, val, base_ctd, base_ctd); } /* * Add an alias for any address that is different when cast to a super-type. */ static void add_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd) { const sipEncodedTypeDef *sup; /* See if there are any super-classes. */ if ((sup = ctd->ctd_supers) != NULL) { sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd); /* Recurse up the hierachy for the first super-class. */ add_aliases(om, addr, val, base_ctd, sup_ctd); /* * We only check for aliases for subsequent super-classes because the * first one can never need one. */ while (!sup++->sc_flag) { void *sup_addr; sup_ctd = sipGetGeneratedClassType(sup, ctd); /* Recurse up the hierachy for the remaining super-classes. */ add_aliases(om, addr, val, base_ctd, sup_ctd); sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd); if (sup_addr != addr) { sipSimpleWrapper *alias; /* Note that we silently ignore errors. */ if ((alias = sip_api_malloc(sizeof (sipSimpleWrapper))) != NULL) { /* * An alias is basically a bit-wise copy of the Python * object but only to ensure the fields we are subverting * are in the right place. An alias should never be passed * to the Python API. */ *alias = *val; alias->sw_flags = (val->sw_flags & SIP_SHARE_MAP) | SIP_ALIAS; alias->data = val; alias->next = NULL; add_object(om, sup_addr, alias); } } } } } /* * Add a wrapper (which may be an alias) to the map. */ static void add_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val) { sipHashEntry *he = findHashEntry(om, addr); /* * 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->sw_flags & SIP_SHARE_MAP)) { sipSimpleWrapper *sw = he->first; he->first = NULL; while (sw != NULL) { sipSimpleWrapper *next = sw->next; if (sipIsAlias(sw)) { sip_api_free(sw); } else { /* * We are removing it from the map here. We first have to * call the destructor as the destructor itself might end * up trying to remove the wrapper and its aliases from the * map. */ sip_api_instance_destroyed(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 = addr; 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) { uintptr_t 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) { void *addr; const sipClassTypeDef *base_ctd; /* Handle the trivial case. */ if (sipNotInMap(val)) return 0; if ((addr = getUnguardedPointer(val)) == NULL) return 0; /* Remove any aliases. */ base_ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(val))->wt_td; remove_aliases(om, addr, val, base_ctd, base_ctd); /* Remove the object. */ return remove_object(om, addr, val); } /* * Remove an alias for any address that is different when cast to a super-type. */ static void remove_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val, const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd) { const sipEncodedTypeDef *sup; /* See if there are any super-classes. */ if ((sup = ctd->ctd_supers) != NULL) { sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd); /* Recurse up the hierachy for the first super-class. */ remove_aliases(om, addr, val, base_ctd, sup_ctd); /* * We only check for aliases for subsequent super-classes because the * first one can never need one. */ while (!sup++->sc_flag) { void *sup_addr; sup_ctd = sipGetGeneratedClassType(sup, ctd); /* Recurse up the hierachy for the remaining super-classes. */ remove_aliases(om, addr, val, base_ctd, sup_ctd); sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd); if (sup_addr != addr) remove_object(om, sup_addr, val); } } } /* * Remove a wrapper from the map. */ static int remove_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val) { sipHashEntry *he = findHashEntry(om, addr); sipSimpleWrapper **swp; for (swp = &he->first; *swp != NULL; swp = &(*swp)->next) { sipSimpleWrapper *sw, *next; int do_remove; sw = *swp; next = sw->next; if (sipIsAlias(sw)) { if (sw->data == val) { sip_api_free(sw); do_remove = TRUE; } else { do_remove = FALSE; } } else { do_remove = (sw == val); } if (do_remove) { *swp = 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; } /* * Return the unguarded pointer to a C/C++ instance, ie. the pointer was valid * but may longer be. */ static void *getUnguardedPointer(sipSimpleWrapper *w) { return (w->access_func != NULL) ? w->access_func(w, UnguardedPointer) : w->data; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/pyproject.toml0000644000076500000240000000007114644214002015303 0ustar00philstaff[build-system] requires = ["setuptools >=30.3", "wheel"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/qtlib.c0000644000076500000240000004370014644214002013654 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * The SIP library code that implements the interface to the optional module * supplied Qt support. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include #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; assert(sipQtSupport->qt_create_universal_slot); 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. Don't check if * any receiver C++ object still exists. */ PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs) { return sip_api_invoke_slot_ex(slot, sigargs, TRUE); } /* * Invoke a single slot (Qt or Python) and return the result. Optionally check * that any receiver C++ object still exist. */ PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs, int no_receiver_check) { PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref; assert(sipQtSupport); /* Keep some compilers quiet. */ oxtype = oxvalue = oxtb = NULL; /* Fan out Qt signals. (Only PyQt3 would 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 PY_VERSION_HEX >= 0x030d0000 if (PyWeakref_GetRef(slot->weakSlot, &sref) < 0) return NULL; if (sref == NULL) { sref = Py_None; Py_INCREF(sref); } #else if ((sref = PyWeakref_GetObject(slot->weakSlot)) == NULL) return NULL; Py_INCREF(sref); #endif } 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 (!no_receiver_check && PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) && sip_api_get_address((sipSimpleWrapper *)self) == NULL) { Py_XDECREF(sref); Py_INCREF(Py_None); return Py_None; } if ((sfunc = PyMethod_New(slot->meth.mfunc, self)) == 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 = PyObject_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) { assert(sipQtSupport); assert(sipQtSupport->qt_same_name); /* 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)); } /* 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) { assert(sipQtSupport); assert(sipQtSupport->qt_find_slot); 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(sip_api_get_address(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) { assert(sipQtSupport); 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) { assert(sipQtSupport); assert(sipQtSupport->qt_connect); /* 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 would 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) { assert(sipQtSupport); assert(sipQtSupport->qt_disconnect); assert(sipQtSupport->qt_destroy_universal_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 would 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) { assert(sipQtSupport); 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) { assert(sipQtSupport); 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; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1720784898.5586884 PyQt5_sip-12.15.0/setup.cfg0000644000076500000240000000041314644214003014211 0ustar00philstaff[metadata] description = The sip module support for PyQt5 long_description = file: README author = Phil Thompson author_email = phil@riverbankcomputing.com url = https://github.com/Python-SIP/sip platforms = X11, macOS, Windows [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/setup.py0000644000076500000240000000067514644214002014113 0ustar00philstaff# SPDX-License-Identifier: BSD-2-Clause # Copyright (c) 2024 Phil Thompson import glob from setuptools import Extension, setup # Build the extension module. module_src = sorted(glob.glob('*.c')) module = Extension('PyQt5.sip', module_src) # Do the setup. setup( name='PyQt5_sip', version='12.15.0', license='SIP', python_requires='>=3.8', ext_modules=[module] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/sip.h0000644000076500000240000015701414644214002013345 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * The SIP module interface. * * Copyright (c) 2024 Phil Thompson */ #ifndef _SIP_H #define _SIP_H #include /* Sanity check on the Python version. */ #if PY_VERSION_HEX < 0x03080000 #error "This version of PyQt5.sip requires Python v3.8 or later" #endif #ifdef __cplusplus #include typedef bool (*sipExceptionHandler)(std::exception_ptr); #else typedef void *sipExceptionHandler; #endif #ifdef __cplusplus extern "C" { #endif /* The version of the ABI. */ #define SIP_ABI_MAJOR_VERSION 12 #define SIP_ABI_MINOR_VERSION 15 #define SIP_MODULE_PATCH_VERSION 0 /* * The change history of the ABI. * * v12.15 * - Added the 'I' conversion character to the argument and result parsers. * * v12.14 * - Added support for Python v3.13. * - Python v3.8 or later is required. * - C99 support is assumed. * * v12.13 * - Added support for Python v3.12. * - Added sipPyTypeDictRef(). * - Deprecated sipPyTypeDict(). * * v12.12 * - Added the '#' conversion character to the argument parsers. * * v12.11 * - Published the 'array' type. * - Added the ctd_sizeof, ctd_array_delete members to sipClassTypeDef. * - Added the '>' conversion character to the argument parsers. * * v12.10 * - Python v3.7 or later is required. * - Added support for Python v3.11. * * v12.9 * - Added sipNextExceptionHandler(). * * v12.8 * - Added a new thread-safe implementation of sipIsPyMethod(). */ /* The version of the code generator. */ #define SIP_VERSION 0x60806 #define SIP_VERSION_STR "6.8.6" /* These are all dependent on the user-specified name of the sip module. */ #define _SIP_MODULE_FQ_NAME "PyQt5.sip" #define _SIP_MODULE_NAME "sip" #define _SIP_MODULE_SHARED 1 #define _SIP_MODULE_ENTRY PyInit_sip #define _SIP_MODULE_LEGACY 1 /* Support the historical names. */ #define SIP_API_MAJOR_NR SIP_ABI_MAJOR_VERSION #define SIP_API_MINOR_NR SIP_ABI_MINOR_VERSION /* * Qt includes this typedef and its meta-object system explicitly converts * types to uint. If these correspond to signal arguments then that conversion * is exposed. Therefore SIP generates code that uses it. This definition is * for the cases that SIP is generating non-Qt related bindings with compilers * that don't include it themselves (i.e. MSVC). */ typedef unsigned int uint; /* Some C++ compatibility stuff. */ #if defined(__cplusplus) /* * Cast a PyCFunctionWithKeywords to a PyCFunction in such a way that it * suppresses the GCC -Wcast-function-type warning. */ #define SIP_MLMETH_CAST(m) reinterpret_cast(reinterpret_cast(m)) #if __cplusplus >= 201103L || defined(_MSVC_LANG) /* C++11 and later. */ #define SIP_NULLPTR nullptr #define SIP_OVERRIDE override #else /* Earlier versions of C++. */ #define SIP_NULLPTR NULL #define SIP_OVERRIDE #endif #else /* Cast a PyCFunctionWithKeywords to a PyCFunction. */ #define SIP_MLMETH_CAST(m) ((PyCFunction)(m)) /* C. */ #define SIP_NULLPTR NULL #define SIP_OVERRIDE #endif #define SIP_SSIZE_T Py_ssize_t #define SIP_SSIZE_T_FORMAT "%zd" #define SIP_USE_PYCAPSULE #define SIP_MODULE_RETURN(v) return (v) #define SIPLong_Check PyLong_Check #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_AsString PyBytes_AsString #define SIPBytes_Size PyBytes_Size #define SIPBytes_AS_STRING PyBytes_AS_STRING #define SIPBytes_GET_SIZE PyBytes_GET_SIZE /* * 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 /* * Forward declarations of types. */ struct _sipBufferDef; typedef struct _sipBufferDef sipBufferDef; struct _sipBufferInfoDef; typedef struct _sipBufferInfoDef sipBufferInfoDef; struct _sipCFunctionDef; typedef struct _sipCFunctionDef sipCFunctionDef; struct _sipDateDef; typedef struct _sipDateDef sipDateDef; struct _sipEnumTypeObject; typedef struct _sipEnumTypeObject sipEnumTypeObject; struct _sipMethodDef; typedef struct _sipMethodDef sipMethodDef; struct _sipSimpleWrapper; typedef struct _sipSimpleWrapper sipSimpleWrapper; struct _sipTimeDef; typedef struct _sipTimeDef sipTimeDef; struct _sipTypeDef; typedef struct _sipTypeDef sipTypeDef; struct _sipWrapperType; typedef struct _sipWrapperType sipWrapperType; struct _sipWrapper; typedef struct _sipWrapper sipWrapper; /* * The different events a handler can be registered for. */ typedef enum { sipEventWrappedInstance, /* After wrapping a C/C++ instance. */ sipEventCollectingWrapper, /* When garbage collecting a wrapper object. */ sipEventNrEvents } sipEventType; /* * The event handlers. */ typedef void (*sipWrappedInstanceEventHandler)(void *sipCpp); typedef void (*sipCollectingWrapperEventHandler)(sipSimpleWrapper *sipSelf); /* * The operation an access function is being asked to perform. */ typedef enum { UnguardedPointer, /* Return the unguarded pointer. */ GuardedPointer, /* Return the guarded pointer, ie. 0 if it has gone. */ ReleaseGuard /* Release the guard, if any. */ } AccessFuncOp; /* * Some convenient function pointers. */ typedef void *(*sipInitFunc)(sipSimpleWrapper *, PyObject *, PyObject *, PyObject **, PyObject **, PyObject **); typedef int (*sipFinalFunc)(PyObject *, void *, PyObject *, PyObject **); typedef void *(*sipAccessFunc)(sipSimpleWrapper *, AccessFuncOp); typedef int (*sipTraverseFunc)(void *, visitproc, void *); typedef int (*sipClearFunc)(void *); typedef int (*sipGetBufferFuncLimited)(PyObject *, void *, sipBufferDef *); typedef void (*sipReleaseBufferFuncLimited)(PyObject *, void *); #if !defined(Py_LIMITED_API) typedef int (*sipGetBufferFunc)(PyObject *, void *, Py_buffer *, int); typedef void (*sipReleaseBufferFunc)(PyObject *, void *, Py_buffer *); #endif typedef void (*sipDeallocFunc)(sipSimpleWrapper *); typedef void *(*sipCastFunc)(void *, const sipTypeDef *); typedef const sipTypeDef *(*sipSubClassConvertFunc)(void **); typedef int (*sipConvertToFunc)(PyObject *, void **, int *, PyObject *); typedef PyObject *(*sipConvertFromFunc)(void *, PyObject *); typedef void (*sipVirtErrorHandlerFunc)(sipSimpleWrapper *, sip_gilstate_t); typedef int (*sipVirtHandlerFunc)(sip_gilstate_t, sipVirtErrorHandlerFunc, sipSimpleWrapper *, PyObject *, ...); typedef void (*sipAssignFunc)(void *, Py_ssize_t, void *); typedef void *(*sipArrayFunc)(Py_ssize_t); typedef void (*sipArrayDeleteFunc)(void *); typedef void *(*sipCopyFunc)(const void *, Py_ssize_t); typedef void (*sipReleaseFunc)(void *, int); typedef PyObject *(*sipPickleFunc)(void *); typedef int (*sipAttrGetterFunc)(const sipTypeDef *, PyObject *); typedef PyObject *(*sipVariableGetterFunc)(void *, PyObject *, PyObject *); typedef int (*sipVariableSetterFunc)(void *, PyObject *, PyObject *); typedef void *(*sipProxyResolverFunc)(void *); typedef int (*sipNewUserTypeFunc)(sipWrapperType *); typedef void (*sipWrapperVisitorFunc)(sipSimpleWrapper *, void *); #if !defined(Py_LIMITED_API) /* * The meta-type of a wrapper type. */ struct _sipWrapperType { /* * The super-metatype. This must be first in the structure so that it can * be cast to a PyTypeObject *. */ PyHeapTypeObject super; /* Set if the type is a user implemented Python sub-class. */ unsigned wt_user_type : 1; /* Set if the type's dictionary contains all lazy attributes. */ unsigned wt_dict_complete : 1; /* Unused and available for future use. */ unsigned wt_unused : 30; /* The generated type structure. */ sipTypeDef *wt_td; /* The list of init extenders. */ struct _sipInitExtenderDef *wt_iextend; /* The handler called whenever a new user type has been created. */ sipNewUserTypeFunc wt_new_user_type_handler; /* * For the user to use. Note that any data structure will leak if the * type is garbage collected. */ void *wt_user_data; }; /* * The type of a simple C/C++ wrapper object. */ struct _sipSimpleWrapper { PyObject_HEAD /* * The data, initially a pointer to the C/C++ object, as interpreted by the * access function. */ void *data; /* The optional access function. */ sipAccessFunc access_func; /* Object flags. */ unsigned sw_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; /* The main instance if this is a mixin. */ PyObject *mixin_main; /* Next object at this address. */ struct _sipSimpleWrapper *next; }; /* * The type of a C/C++ wrapper object that supports parent/child relationships. */ 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; }; /* * The meta-type of an enum type. (This is exposed only to support the * deprecated sipConvertFromNamedEnum() macro.) */ 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; }; #endif /* * 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 structure populated by %BIGetBufferCode when the limited API is enabled. */ struct _sipBufferDef { /* The address of the buffer. */ void *bd_buffer; /* The length of the buffer. */ Py_ssize_t bd_length; /* Set if the buffer is read-only. */ int bd_readonly; }; /* * The structure describing a Python buffer. */ struct _sipBufferInfoDef { /* This is internal to sip. */ void *bi_internal; /* The address of the buffer. */ void *bi_buf; /* A reference to the object implementing the buffer interface. */ PyObject *bi_obj; /* The length of the buffer in bytes. */ Py_ssize_t bi_len; /* The number of dimensions. */ int bi_ndim; /* The format of each element of the buffer. */ char *bi_format; }; /* * The structure describing a Python C function. */ struct _sipCFunctionDef { /* The C function. */ PyMethodDef *cf_function; /* The optional bound object. */ PyObject *cf_self; }; /* * The structure describing a Python method. */ struct _sipMethodDef { /* The function that implements the method. */ PyObject *pm_function; /* The bound object. */ PyObject *pm_self; }; /* * The structure describing a Python date. */ struct _sipDateDef { /* The year. */ int pd_year; /* The month (1-12). */ int pd_month; /* The day (1-31). */ int pd_day; }; /* * The structure describing a Python time. */ struct _sipTimeDef { /* The hour (0-23). */ int pt_hour; /* The minute (0-59). */ int pt_minute; /* The second (0-59). */ int pt_second; /* The microsecond (0-999999). */ int pt_microsecond; }; /* * 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. New slots must be added to the end, * otherwise the major version of the internal ABI must be changed. */ typedef enum { str_slot, /* __str__ */ int_slot, /* __int__ */ 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__ */ bool_slot, /* __bool__, __nonzero__ */ neg_slot, /* __neg__ */ repr_slot, /* __repr__ */ hash_slot, /* __hash__ */ pos_slot, /* __pos__ */ abs_slot, /* __abs__ */ index_slot, /* __index__ */ iter_slot, /* __iter__ */ next_slot, /* __next__ */ setattr_slot, /* __setattr__, __delattr__ */ matmul_slot, /* __matmul__ (for Python v3.5 and later) */ imatmul_slot, /* __imatmul__ (for Python v3.5 and later) */ await_slot, /* __await__ (for Python v3.5 and later) */ aiter_slot, /* __aiter__ (for Python v3.5 and later) */ anext_slot, /* __anext__ (for Python v3.5 and later) */ } 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 or property. */ typedef enum { PropertyVariable, /* A property. */ InstanceVariable, /* An instance variable. */ ClassVariable /* A class (i.e. static) variable. */ } sipVariableType; typedef struct _sipVariableDef { /* The type of variable. */ sipVariableType vd_type; /* The name. */ const char *vd_name; /* * The getter. If this is a variable (rather than a property) then the * actual type is sipVariableGetterFunc. */ PyMethodDef *vd_getter; /* * The setter. If this is a variable (rather than a property) then the * actual type is sipVariableSetterFunc. It is NULL if the property cannot * be set or the variable is const. */ PyMethodDef *vd_setter; /* The property deleter. */ PyMethodDef *vd_deleter; /* The docstring. */ const char *vd_docstring; } sipVariableDef; /* * The information describing a type, either a C++ class (or C struct), a C++ * namespace, a mapped type or a named enum. */ 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. */ PyTypeObject *td_py_type; /* Any additional fixed data generated by a plugin. */ void *td_plugin_data; }; /* * 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; /* The get buffer function. */ #if defined(Py_LIMITED_API) sipGetBufferFuncLimited ctd_getbuffer; #else sipGetBufferFunc ctd_getbuffer; #endif /* The release buffer function. */ #if defined(Py_LIMITED_API) sipReleaseBufferFuncLimited ctd_releasebuffer; #else sipReleaseBufferFunc ctd_releasebuffer; #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 struct. */ sipReleaseFunc ctd_release; /* The cast function, 0 if a C struct. */ sipCastFunc ctd_cast; /* The optional convert to function. */ sipConvertToFunc ctd_cto; /* The optional convert from function. */ sipConvertFromFunc ctd_cfrom; /* The next namespace extender. */ struct _sipClassTypeDef *ctd_nsextender; /* The pickle function. */ sipPickleFunc ctd_pickle; /* The finalisation function. */ sipFinalFunc ctd_final; /* The mixin initialisation function. */ initproc ctd_init_mixin; /* The optional array delete function. */ sipArrayDeleteFunc ctd_array_delete; /* The sizeof the class. */ size_t ctd_sizeof; } 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; /* * Defines a virtual error handler. */ typedef struct _sipVirtErrorHandlerDef { /* The name of the handler. */ const char *veh_name; /* The handler function. */ sipVirtErrorHandlerFunc veh_handler; } sipVirtErrorHandlerDef; /* * Defines a type imported from another module. */ typedef union _sipImportedTypeDef { /* The type name before the module is imported. */ const char *it_name; /* The type after the module is imported. */ sipTypeDef *it_td; } sipImportedTypeDef; /* * Defines a virtual error handler imported from another module. */ typedef union _sipImportedVirtErrorHandlerDef { /* The handler name before the module is imported. */ const char *iveh_name; /* The handler after the module is imported. */ sipVirtErrorHandlerFunc iveh_handler; } sipImportedVirtErrorHandlerDef; /* * Defines an exception imported from another module. */ typedef union _sipImportedExceptionDef { /* The exception name before the module is imported. */ const char *iexc_name; /* The exception object after the module is imported. */ PyObject *iexc_object; } sipImportedExceptionDef; /* * The information describing an imported module. */ typedef struct _sipImportedModuleDef { /* The module name. */ const char *im_name; /* The types imported from the module. */ sipImportedTypeDef *im_imported_types; /* The virtual error handlers imported from the module. */ sipImportedVirtErrorHandlerDef *im_imported_veh; /* The exceptions imported from the module. */ sipImportedExceptionDef *im_imported_exceptions; } 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 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 error handlers. */ sipVirtErrorHandlerDef *em_virterrorhandlers; /* 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; /* The exception handler. */ sipExceptionHandler em_exception_handler; } 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. * This is also used as a hack to add (or fix) other types rather than add a * new table type and so requiring a new major version of the API. */ 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'. 'w' and 'W' are also * used to support the fix for wchar_t. */ 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. */ 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. */ 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; } 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)(Py_ssize_t seqlen, Py_ssize_t slicelen); PyObject *(*api_build_result)(int *isErr, const char *fmt, ...); PyObject *(*api_call_method)(int *isErr, PyObject *method, const char *fmt, ...); void (*api_call_procedure_method)(sip_gilstate_t, sipVirtErrorHandlerFunc, sipSimpleWrapper *, PyObject *, const char *, ...); PyObject *(*api_connect_rx)(PyObject *txObj, const char *sig, PyObject *rxObj, const char *slot, int type); Py_ssize_t (*api_convert_from_sequence_index)(Py_ssize_t idx, Py_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); /* * The following are deprecated parts of the public API. */ int (*api_can_convert_to_enum)(PyObject *pyObj, const sipTypeDef *td); /* * The following are part of the public API. */ 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, Py_ssize_t size); PyObject *(*api_convert_from_const_void_ptr_and_size)(const void *val, Py_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); void *(*api_get_address)(struct _sipSimpleWrapper *w); void (*api_set_destroy_on_exit)(int); int (*api_enable_autoconversion)(const sipTypeDef *td, int enable); void *(*api_get_mixin_address)(struct _sipSimpleWrapper *w, const sipTypeDef *td); PyObject *(*api_convert_from_new_pytype)(void *cpp, PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp, const char *fmt, ...); PyObject *(*api_convert_to_typed_array)(void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags); PyObject *(*api_convert_to_array)(void *data, const char *format, Py_ssize_t len, int flags); int (*api_register_proxy_resolver)(const sipTypeDef *td, sipProxyResolverFunc resolver); PyInterpreterState *(*api_get_interpreter)(void); sipNewUserTypeFunc (*api_set_new_user_type_handler)(const sipTypeDef *, sipNewUserTypeFunc); void (*api_set_type_user_data)(sipWrapperType *, void *); void *(*api_get_type_user_data)(const sipWrapperType *); PyObject *(*api_py_type_dict)(const PyTypeObject *); const char *(*api_py_type_name)(const PyTypeObject *); int (*api_get_method)(PyObject *, sipMethodDef *); PyObject *(*api_from_method)(const sipMethodDef *); int (*api_get_c_function)(PyObject *, sipCFunctionDef *); int (*api_get_date)(PyObject *, sipDateDef *); PyObject *(*api_from_date)(const sipDateDef *); int (*api_get_datetime)(PyObject *, sipDateDef *, sipTimeDef *); PyObject *(*api_from_datetime)(const sipDateDef *, const sipTimeDef *); int (*api_get_time)(PyObject *, sipTimeDef *); PyObject *(*api_from_time)(const sipTimeDef *); int (*api_is_user_type)(const sipWrapperType *); struct _frame *(*api_get_frame)(int); int (*api_check_plugin_for_type)(const sipTypeDef *, const char *); PyObject *(*api_unicode_new)(Py_ssize_t, unsigned, int *, void **); void (*api_unicode_write)(int, void *, int, unsigned); void *(*api_unicode_data)(PyObject *, int *, Py_ssize_t *); int (*api_get_buffer_info)(PyObject *, sipBufferInfoDef *); void (*api_release_buffer_info)(sipBufferInfoDef *); PyObject *(*api_get_user_object)(const sipSimpleWrapper *); void (*api_set_user_object)(sipSimpleWrapper *, PyObject *); /* * 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, ...); /* * The following are part of the public API. */ void (*api_instance_destroyed)(sipSimpleWrapper *sipSelf); /* * The following are not part of the public API. */ 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_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); int (*api_parse_result_ex)(sip_gilstate_t, sipVirtErrorHandlerFunc, sipSimpleWrapper *, PyObject *method, PyObject *res, const char *fmt, ...); void (*api_call_error_handler)(sipVirtErrorHandlerFunc, sipSimpleWrapper *, sip_gilstate_t); int (*api_init_mixin)(PyObject *self, PyObject *args, PyObject *kwds, const sipClassTypeDef *ctd); PyObject *(*api_get_reference)(PyObject *self, int key); /* * The following are part of the public API. */ int (*api_is_owned_by_python)(sipSimpleWrapper *); /* * The following are not part of the public API. */ int (*api_is_derived_class)(sipSimpleWrapper *); /* * 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); PyObject *(*api_invoke_slot_ex)(const sipSlot *slot, PyObject *sigargs, int check_receiver); 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 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 are part of the public API. */ int (*api_enable_gc)(int enable); void (*api_print_object)(PyObject *o); int (*api_register_event_handler)(sipEventType type, const sipTypeDef *td, void *handler); int (*api_convert_to_enum)(PyObject *obj, const sipTypeDef *td); int (*api_convert_to_bool)(PyObject *obj); int (*api_enable_overflow_checking)(int enable); char (*api_long_as_char)(PyObject *o); signed char (*api_long_as_signed_char)(PyObject *o); unsigned char (*api_long_as_unsigned_char)(PyObject *o); short (*api_long_as_short)(PyObject *o); unsigned short (*api_long_as_unsigned_short)(PyObject *o); int (*api_long_as_int)(PyObject *o); unsigned int (*api_long_as_unsigned_int)(PyObject *o); long (*api_long_as_long)(PyObject *o); #if defined(HAVE_LONG_LONG) PY_LONG_LONG (*api_long_as_long_long)(PyObject *o); unsigned PY_LONG_LONG (*api_long_as_unsigned_long_long)(PyObject *o); #else void *api_long_as_long_long; void *api_long_as_unsigned_long_long; #endif /* * The following are not part of the public API. */ void (*api_instance_destroyed_ex)(sipSimpleWrapper **sipSelfp); /* * The following are part of the public API. */ int (*api_convert_from_slice_object)(PyObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength); size_t (*api_long_as_size_t)(PyObject *o); void (*api_visit_wrappers)(sipWrapperVisitorFunc visitor, void *closure); int (*api_register_exit_notifier)(PyMethodDef *md); /* * The following are not part of the public API. */ PyObject *(*api_is_py_method_12_8)(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper **sipSelfp, const char *cname, const char *mname); sipExceptionHandler (*api_next_exception_handler)(void **statep); /* * The following are part of the public API. */ PyObject *(*api_py_type_dict_ref)(PyTypeObject *); } sipAPIDef; const sipAPIDef *sip_init_library(PyObject *mod_dict); /* * 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 flags that can be passed to sipConvertToArray(). These are held * in sw_flags. */ #define SIP_READ_ONLY 0x01 /* The array is read-only. */ #define SIP_OWNS_MEMORY 0x02 /* The array owns its memory. */ /* * These are the state flags returned by %ConvertToTypeCode. Note that the * values share the same "flagspace" as the contents of sw_flags. */ #define SIP_TEMPORARY 0x01 /* A temporary instance. */ #define SIP_DERIVED_CLASS 0x02 /* 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. */ /* These are held in sw_flags. */ #define SIP_INDIRECT 0x0004 /* If there is a level of indirection. */ #define SIP_ACCFUNC 0x0008 /* If there is an access function. */ #define SIP_NOT_IN_MAP 0x0010 /* If Python object is not in the map. */ #if !defined(Py_LIMITED_API) #define SIP_PY_OWNED 0x0020 /* If owned by Python. */ #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 SIP_ALIAS 0x0200 /* If it is an alias. */ #define SIP_CREATED 0x0400 /* If the C/C++ object has been created. */ #define sipIsDerived(sw) ((sw)->sw_flags & SIP_DERIVED_CLASS) #define sipIsIndirect(sw) ((sw)->sw_flags & SIP_INDIRECT) #define sipIsAccessFunc(sw) ((sw)->sw_flags & SIP_ACCFUNC) #define sipNotInMap(sw) ((sw)->sw_flags & SIP_NOT_IN_MAP) #define sipSetNotInMap(sw) ((sw)->sw_flags |= SIP_NOT_IN_MAP) #define sipIsPyOwned(sw) ((sw)->sw_flags & SIP_PY_OWNED) #define sipSetPyOwned(sw) ((sw)->sw_flags |= SIP_PY_OWNED) #define sipResetPyOwned(sw) ((sw)->sw_flags &= ~SIP_PY_OWNED) #define sipCppHasRef(sw) ((sw)->sw_flags & SIP_CPP_HAS_REF) #define sipSetCppHasRef(sw) ((sw)->sw_flags |= SIP_CPP_HAS_REF) #define sipResetCppHasRef(sw) ((sw)->sw_flags &= ~SIP_CPP_HAS_REF) #define sipPossibleProxy(sw) ((sw)->sw_flags & SIP_POSSIBLE_PROXY) #define sipSetPossibleProxy(sw) ((sw)->sw_flags |= SIP_POSSIBLE_PROXY) #define sipIsAlias(sw) ((sw)->sw_flags & SIP_ALIAS) #define sipWasCreated(sw) ((sw)->sw_flags & SIP_CREATED) #endif #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_SCOPED_ENUM 0x0004 /* If the type is a scoped 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. */ #define SIP_TYPE_NONLAZY 0x0080 /* If the type has a non-lazy method. */ #define SIP_TYPE_SUPER_INIT 0x0100 /* If the instance's super init should be called. */ #define SIP_TYPE_LIMITED_API 0x0200 /* Use the limited API. If this is more generally required it may need to be moved to the module definition. */ /* * 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 sipTypeIsScopedEnum(td) (((td)->td_flags & SIP_TYPE_TYPE_MASK) == SIP_TYPE_SCOPED_ENUM) #define sipTypeAsPyTypeObject(td) ((td)->td_py_type) #define sipTypeName(td) sipNameFromPool((td)->td_module, (td)->td_cname) #define sipTypePluginData(td) ((td)->td_plugin_data) /* * These are deprecated. */ #define sipClassName(w) PyString_FromString(Py_TYPE(w)->tp_name) #define sipIsExactWrappedType(wt) (sipTypeAsPyTypeObject((wt)->wt_td) == (PyTypeObject *)(wt)) /* * 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) #define sipTypeHasNonlazyMethod(td) ((td)->td_flags & SIP_TYPE_NONLAZY) #define sipTypeCallSuperInit(td) ((td)->td_flags & SIP_TYPE_SUPER_INIT) #define sipTypeUseLimitedAPI(td) ((td)->td_flags & SIP_TYPE_LIMITED_API) /* * 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 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; /* * The hack to apply when built against Qt5: * * 0 - no hack * 1 - add an optional None * 2 - add an optional [] * 3 - add an optional False */ int hack; } pyqt4QtSignal; /* * This is the PyQt4-specific extension to the generated class type structure. */ typedef struct _pyqt4ClassPluginDef { /* A pointer to the QObject sub-class's staticMetaObject class variable. */ const void *static_metaobject; /* * A set of flags. At the moment only bit 0 is used to say if the type is * derived from QFlags. */ unsigned flags; /* * The table of signals emitted by the type. These are grouped by signal * name. */ const pyqt4QtSignal *qt_signals; } pyqt4ClassPluginDef; /* * The following are PyQt5-specific extensions. In SIP v5 they will be pushed * out to a plugin supplied by PyQt5. */ /* * The description of a Qt signal for PyQt5. */ typedef int (*pyqt5EmitFunc)(void *, PyObject *); typedef struct _pyqt5QtSignal { /* The normalised C++ name and signature of the signal. */ const char *signature; /* The optional docstring. */ const char *docstring; /* * If the signal is an overload of regular methods then this points to the * code that implements those methods. */ PyMethodDef *non_signals; /* * If the signal has optional arguments then this function will implement * emit() for the signal. */ pyqt5EmitFunc emitter; } pyqt5QtSignal; /* * This is the PyQt5-specific extension to the generated class type structure. */ typedef struct _pyqt5ClassPluginDef { /* A pointer to the QObject sub-class's staticMetaObject class variable. */ const void *static_metaobject; /* * A set of flags. At the moment only bit 0 is used to say if the type is * derived from QFlags. */ unsigned flags; /* * The table of signals emitted by the type. These are grouped by signal * name. */ const pyqt5QtSignal *qt_signals; /* The name of the interface that the class defines. */ const char *qt_interface; } pyqt5ClassPluginDef; #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/sip_array.c0000644000076500000240000005036714644214002014541 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * This file implements the API for the array type. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include #include "sipint.h" #include "sip_array.h" /* The object data structure. */ typedef struct { PyObject_HEAD void *data; const sipTypeDef *td; const char *format; size_t stride; Py_ssize_t len; int flags; PyObject *owner; } sipArrayObject; static void bad_key(PyObject *key); static int check_index(sipArrayObject *array, Py_ssize_t idx); static int check_writable(sipArrayObject *array); static PyObject *create_array(void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags, PyObject *owner); static void *element(sipArrayObject *array, Py_ssize_t idx); static void *get_slice(sipArrayObject *array, PyObject *value, Py_ssize_t len); static const char *get_type_name(sipArrayObject *array); static void *get_value(sipArrayObject *array, PyObject *value); static void init_array(sipArrayObject *array, void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags, PyObject *owner); /* * Implement len() for the type. */ static Py_ssize_t sipArray_length(PyObject *self) { return ((sipArrayObject *)self)->len; } /* * Implement sequence item sub-script for the type. */ static PyObject *sipArray_item(PyObject *self, Py_ssize_t idx) { sipArrayObject *array = (sipArrayObject *)self; PyObject *py_item; void *data; if (check_index(array, idx) < 0) return NULL; data = element(array, idx); if (array->td != NULL) { py_item = sip_api_convert_from_type(data, array->td, NULL); } else { switch (*array->format) { case 'b': py_item = PyLong_FromLong(*(char *)data); break; case 'B': py_item = PyLong_FromUnsignedLong(*(unsigned char *)data); break; case 'h': py_item = PyLong_FromLong(*(short *)data); break; case 'H': py_item = PyLong_FromUnsignedLong(*(unsigned short *)data); break; case 'i': py_item = PyLong_FromLong(*(int *)data); break; case 'I': py_item = PyLong_FromUnsignedLong(*(unsigned int *)data); break; case 'f': py_item = PyFloat_FromDouble(*(float *)data); break; case 'd': py_item = PyFloat_FromDouble(*(double *)data); break; default: py_item = NULL; } } return py_item; } /* The sequence methods data structure. */ static PySequenceMethods sipArray_SequenceMethods = { sipArray_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ sipArray_item, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ 0, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; /* * Implement mapping sub-script for the type. */ static PyObject *sipArray_subscript(PyObject *self, PyObject *key) { sipArrayObject *array = (sipArrayObject *)self; if (PyIndex_Check(key)) { Py_ssize_t idx = PyNumber_AsSsize_t(key, PyExc_IndexError); if (idx == -1 && PyErr_Occurred()) return NULL; if (idx < 0) idx += array->len; return sipArray_item(self, idx); } if (PySlice_Check(key)) { Py_ssize_t start, stop, step, slicelength; if (sip_api_convert_from_slice_object(key, array->len, &start, &stop, &step, &slicelength) < 0) return NULL; if (step != 1) { PyErr_SetNone(PyExc_NotImplementedError); return NULL; } return create_array(element(array, start), array->td, array->format, array->stride, slicelength, (array->flags & ~SIP_OWNS_MEMORY), array->owner); } bad_key(key); return NULL; } /* * Implement mapping assignment sub-script for the type. */ static int sipArray_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { sipArrayObject *array = (sipArrayObject *)self; Py_ssize_t start, len; void *value_data; if (check_writable(array) < 0) return -1; if (PyIndex_Check(key)) { start = PyNumber_AsSsize_t(key, PyExc_IndexError); if (start == -1 && PyErr_Occurred()) return -1; if (start < 0) start += array->len; if (check_index(array, start) < 0) return -1; if ((value_data = get_value(array, value)) == NULL) return -1; len = 1; } else if (PySlice_Check(key)) { Py_ssize_t stop, step; if (sip_api_convert_from_slice_object(key, array->len, &start, &stop, &step, &len) < 0) return -1; if (step != 1) { PyErr_SetNone(PyExc_NotImplementedError); return -1; } if ((value_data = get_slice(array, value, len)) == NULL) return -1; } else { bad_key(key); return -1; } if (array->td != NULL) { const sipClassTypeDef *ctd = (const sipClassTypeDef *)(array->td); sipAssignFunc assign; Py_ssize_t i; if ((assign = ctd->ctd_assign) == NULL) { PyErr_Format(PyExc_TypeError, "a sip.array cannot copy '%s'", Py_TYPE(self)->tp_name); return -1; } for (i = 0; i < len; ++i) { assign(array->data, start + i, value_data); value_data = (char *)value_data + array->stride; } } else { memmove(element(array, start), value_data, len * array->stride); } return 0; } /* The mapping methods data structure. */ static PyMappingMethods sipArray_MappingMethods = { sipArray_length, /* mp_length */ sipArray_subscript, /* mp_subscript */ sipArray_ass_subscript, /* mp_ass_subscript */ }; /* * The buffer implementation. */ static int sipArray_getbuffer(PyObject *self, Py_buffer *view, int flags) { sipArrayObject *array = (sipArrayObject *)self; const char *format; Py_ssize_t itemsize; if (view == NULL) return 0; if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (array->flags & SIP_READ_ONLY)) { PyErr_SetString(PyExc_BufferError, "object is not writable"); return -1; } view->obj = self; Py_INCREF(self); /* * If there is no format, ie. it is a wrapped type, then present it as * bytes. */ if ((format = array->format) == NULL) { format = "B"; itemsize = sizeof (unsigned char); } else { itemsize = array->stride; } view->buf = array->data; view->len = array->len * array->stride; view->readonly = (array->flags & SIP_READ_ONLY); view->itemsize = itemsize; view->format = NULL; if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) /* Note that the need for a cast is probably a Python bug. */ view->format = (char *)format; view->ndim = 1; view->shape = NULL; if ((flags & PyBUF_ND) == PyBUF_ND) view->shape = &view->len; view->strides = NULL; if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) view->strides = &view->itemsize; view->suboffsets = NULL; view->internal = NULL; return 0; } /* The buffer methods data structure. */ static PyBufferProcs sipArray_BufferProcs = { sipArray_getbuffer, /* bf_getbuffer */ 0 /* bf_releasebuffer */ }; /* * The instance deallocation function. */ static void sipArray_dealloc(PyObject *self) { sipArrayObject *array = (sipArrayObject *)self; if (array->flags & SIP_OWNS_MEMORY) { if (array->td != NULL) ((const sipClassTypeDef *)(array->td))->ctd_array_delete(array->data); else PyMem_Free(array->data); } else { Py_XDECREF(array->owner); } } /* * Implement __repr__ for the type. */ static PyObject *sipArray_repr(PyObject *self) { sipArrayObject *array = (sipArrayObject *)self; return PyUnicode_FromFormat("sip.array(%s, %zd)", get_type_name(array), array->len); } /* * Implement __new__ for the type. */ static PyObject *sipArray_new(PyTypeObject *cls, PyObject *args, PyObject *kw) { #if PY_VERSION_HEX >= 0x030d0000 static char * const kwlist[] = {"", "", NULL}; #else static char *kwlist[] = {"", "", NULL}; #endif Py_ssize_t length; PyObject *array, *type; const sipClassTypeDef *ctd; if (!PyArg_ParseTupleAndKeywords(args, kw, "O!n:array", kwlist, &sipWrapperType_Type, &type, &length)) return NULL; ctd = (const sipClassTypeDef *)((sipWrapperType *)type)->wt_td; /* We require the array delete helper which was added in ABI v12.11. */ if (ctd->ctd_base.td_module->em_api_minor < 11) { PyErr_SetString(PyExc_TypeError, "a sip.array can only be created for types using ABI v12.11 or later"); return NULL; } if (ctd->ctd_array == NULL || ctd->ctd_sizeof == 0) { PyErr_Format(PyExc_TypeError, "a sip.array cannot be created for '%s'", Py_TYPE(type)->tp_name); return NULL; } if (length < 0) { PyErr_SetString(PyExc_ValueError, "a sip.array length cannot be negative"); return NULL; } /* Create the instance. */ if ((array = cls->tp_alloc(cls, 0)) == NULL) return NULL; init_array((sipArrayObject *)array, ctd->ctd_array(length), &ctd->ctd_base, NULL, ctd->ctd_sizeof, length, SIP_OWNS_MEMORY, NULL); return array; } /* The type data structure. */ PyTypeObject sipArray_Type = { PyVarObject_HEAD_INIT(NULL, 0) "sip.array", /* tp_name */ sizeof (sipArrayObject), /* tp_basicsize */ 0, /* tp_itemsize */ sipArray_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ sipArray_repr, /* tp_repr */ 0, /* tp_as_number */ &sipArray_SequenceMethods, /* tp_as_sequence */ &sipArray_MappingMethods, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ &sipArray_BufferProcs, /* tp_as_buffer */ #if defined(Py_TPFLAGS_HAVE_NEWBUFFER) Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */ #else Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ #endif 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ sipArray_new, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; /* * Return TRUE if an object is a sip.array with elements of a given type. */ int sip_array_can_convert(PyObject *obj, const sipTypeDef *td) { if (!PyObject_TypeCheck(obj, &sipArray_Type)) return FALSE; return (((sipArrayObject *)obj)->td == td); } /* * Return the address and number of elements of a sip.array for which * sip_array_can_convert has already returned TRUE. */ void sip_array_convert(PyObject *obj, void **data, Py_ssize_t *size) { sipArrayObject *array = (sipArrayObject *)obj; *data = array->data; *size = array->len; } /* * Check that an array is writable. */ static int check_writable(sipArrayObject *array) { if (array->flags & SIP_READ_ONLY) { PyErr_SetString(PyExc_TypeError, "sip.array object is read-only"); return -1; } return 0; } /* * Check that an index is valid for an array. */ static int check_index(sipArrayObject *array, Py_ssize_t idx) { if (idx >= 0 && idx < array->len) return 0; PyErr_SetString(PyExc_IndexError, "index out of bounds"); return -1; } /* * Raise an exception about a bad sub-script key. */ static void bad_key(PyObject *key) { PyErr_Format(PyExc_TypeError, "cannot index a sip.array object using '%s'", Py_TYPE(key)->tp_name); } /* * Get the address of an element of an array. */ static void *element(sipArrayObject *array, Py_ssize_t idx) { return (unsigned char *)(array->data) + idx * array->stride; } /* * Get the address of a value that will be copied to an array. */ static void *get_value(sipArrayObject *array, PyObject *value) { static union { signed char s_char_t; unsigned char u_char_t; signed short s_short_t; unsigned short u_short_t; signed int s_int_t; unsigned int u_int_t; float float_t; double double_t; } static_data; void *data; if (array->td != NULL) { int iserr = FALSE; data = sip_api_force_convert_to_type(value, array->td, NULL, SIP_NOT_NONE|SIP_NO_CONVERTORS, NULL, &iserr); } else { PyErr_Clear(); switch (*array->format) { case 'b': static_data.s_char_t = sip_api_long_as_char(value); data = &static_data.s_char_t; break; case 'B': static_data.u_char_t = sip_api_long_as_unsigned_char(value); data = &static_data.u_char_t; break; case 'h': static_data.s_short_t = sip_api_long_as_short(value); data = &static_data.s_short_t; break; case 'H': static_data.u_short_t = sip_api_long_as_unsigned_short(value); data = &static_data.u_short_t; break; case 'i': static_data.s_int_t = sip_api_long_as_int(value); data = &static_data.s_int_t; break; case 'I': static_data.u_int_t = sip_api_long_as_unsigned_int(value); data = &static_data.u_int_t; break; case 'f': static_data.float_t = (float)PyFloat_AsDouble(value); data = &static_data.float_t; break; case 'd': static_data.double_t = PyFloat_AsDouble(value); data = &static_data.double_t; break; default: data = NULL; } if (PyErr_Occurred()) data = NULL; } return data; } /* * Get the address of an value that will be copied to an array slice. */ static void *get_slice(sipArrayObject *array, PyObject *value, Py_ssize_t len) { sipArrayObject *other = (sipArrayObject *)value; if (!PyObject_IsInstance(value, (PyObject *)&sipArray_Type) || array->td != other->td || strcmp(array->format, other->format) != 0) { PyErr_Format(PyExc_TypeError, "can only assign another array of %s to the slice", get_type_name(array)); return NULL; } if (other->len != len) { PyErr_Format(PyExc_TypeError, "the array being assigned must have length %zd", len); return NULL; } if (other->stride == array->stride) { PyErr_Format(PyExc_TypeError, "the array being assigned must have stride %zu", array->stride); return NULL; } return other->data; } /* * Get the name of the type of an element of an array. */ static const char *get_type_name(sipArrayObject *array) { const char *type_name; if (array->td != NULL) { type_name = sipTypeName(array->td); } else { switch (*array->format) { case 'b': type_name = "char"; break; case 'B': type_name = "unsigned char"; break; case 'h': type_name = "short"; break; case 'H': type_name = "unsigned short"; break; case 'i': type_name = "int"; break; case 'I': type_name = "unsigned int"; break; case 'f': type_name = "float"; break; case 'd': type_name = "double"; break; default: type_name = ""; } } return type_name; } /* * Create an array for the C API. */ static PyObject *create_array(void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags, PyObject *owner) { sipArrayObject *array; if ((array = PyObject_NEW(sipArrayObject, &sipArray_Type)) == NULL) return NULL; init_array(array, data, td, format, stride, len, flags, owner); return (PyObject *)array; } /* * Initialise an array. */ static void init_array(sipArrayObject *array, void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags, PyObject *owner) { array->data = data; array->td = td; array->format = format; array->stride = stride; array->len = len; array->flags = flags; if (flags & SIP_OWNS_MEMORY) { /* This is a borrowed reference to itself. */ array->owner = (PyObject *)array; } else { Py_XINCREF(owner); array->owner = owner; } } /* * Wrap an array of instances of a fundamental type. At the moment format must * be either "b" (char), "B" (unsigned char), "h" (short), "H" (unsigned * short), "i" (int), "I" (unsigned int), "f" (float) or "d" (double). */ PyObject *sip_api_convert_to_array(void *data, const char *format, Py_ssize_t len, int flags) { size_t stride; assert(len >= 0); if (data == NULL) { Py_INCREF(Py_None); return Py_None; } switch (*format) { case 'b': stride = sizeof (char); break; case 'B': stride = sizeof (unsigned char); break; case 'h': stride = sizeof (short); break; case 'H': stride = sizeof (unsigned short); break; case 'i': stride = sizeof (int); break; case 'I': stride = sizeof (unsigned int); break; case 'f': stride = sizeof (float); break; case 'd': stride = sizeof (double); break; default: PyErr_Format(PyExc_ValueError, "'%c' is not a supported format", format); return NULL; } return create_array(data, NULL, format, stride, len, flags, NULL); } /* * Wrap an array of instances of a defined type. */ PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags) { if (data == NULL) { Py_INCREF(Py_None); return Py_None; } assert(stride > 0); assert(len >= 0); return create_array(data, td, format, stride, len, flags, NULL); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/sip_array.h0000644000076500000240000000150314644214002014532 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * This file defines the API for the array type. * * Copyright (c) 2024 Phil Thompson */ #ifndef _SIP_ARRAY_H #define _SIP_ARRAY_H /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include "sip.h" #ifdef __cplusplus extern "C" { #endif extern PyTypeObject sipArray_Type; PyObject *sip_api_convert_to_array(void *data, const char *format, Py_ssize_t len, int flags); PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td, const char *format, size_t stride, Py_ssize_t len, int flags); int sip_array_can_convert(PyObject *obj, const sipTypeDef *td); void sip_array_convert(PyObject *obj, void **data, Py_ssize_t *size); #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/sipint.h0000644000076500000240000001403114644214002014047 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * This file defines the SIP library internal interfaces. * * Copyright (c) 2024 Phil Thompson */ #ifndef _SIPINT_H #define _SIPINT_H /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include #include "sip.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. */ uintptr_t size; /* Size of hash table. */ uintptr_t unused; /* Nr. unused in hash table. */ uintptr_t 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); PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name); extern PyTypeObject sipVariableDescr_Type; PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td, const sipContainerDef *cod); PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name); /* * 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, Py_ssize_t size); PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val, Py_ssize_t size); /* * Support for int convertors. */ PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args); int sip_api_enable_overflow_checking(int enable); int sip_api_convert_to_bool(PyObject *o); char sip_api_long_as_char(PyObject *o); signed char sip_api_long_as_signed_char(PyObject *o); unsigned char sip_api_long_as_unsigned_char(PyObject *o); short sip_api_long_as_short(PyObject *o); unsigned short sip_api_long_as_unsigned_short(PyObject *o); int sip_api_long_as_int(PyObject *o); unsigned int sip_api_long_as_unsigned_int(PyObject *o); long sip_api_long_as_long(PyObject *o); unsigned long sip_api_long_as_unsigned_long(PyObject *o); #if defined(HAVE_LONG_LONG) PY_LONG_LONG sip_api_long_as_long_long(PyObject *o); unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o); #endif size_t sip_api_long_as_size_t(PyObject *o); extern sipQtAPI *sipQtSupport; /* The Qt support API. */ extern PyTypeObject sipWrapperType_Type; /* The wrapper type type. */ 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_address(sipSimpleWrapper *w); 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_instance_destroyed(sipSimpleWrapper *sipSelf); void sip_api_end_thread(void); void *sip_api_force_convert_to_type(PyObject *pyObj, const sipTypeDef *td, PyObject *transferObj, int flags, int *statep, int *iserrp); void sip_api_free_sipslot(sipSlot *slot); int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot); PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs); PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs, int no_receiver_check); void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs, PyObject *rxObj, const char *slot, const char **memberp, int flags); int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot); int sip_api_convert_from_slice_object(PyObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength); int sip_api_deprecated(const char *classname, const char *method); /* * These are not part of the SIP API but are used within the SIP module. */ sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc, const sipClassTypeDef *ctd); void sipSaveMethod(sipPyMethod *pm,PyObject *meth); int sipGetPending(void **pp, sipWrapper **op, int *fp); int sipIsPending(void); PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args, sipWrapper *owner, int flags); void *sipConvertRxEx(sipWrapper *txSelf, const char *sigargs, PyObject *rxObj, const char *slot, const char **memberp, int flags); 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); #define sipSetBool(p, v) (*(_Bool *)(p) = (v)) #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/siplib.c0000644000076500000240000126355114644214002014034 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * SIP library code. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include #include #include #include #include #include #include "sip.h" #include "sipint.h" #include "sip_array.h" /* * 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, Py_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); 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_as_async (Python v3.5), 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 */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; /* * 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_as_async (Python v3.5), 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 */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }, { 0, /* am_await */ 0, /* am_aiter */ 0, /* am_anext */ }, { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ 0, /* nb_bool */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ 0, /* nb_and */ 0, /* nb_xor */ 0, /* nb_or */ 0, /* nb_int */ 0, /* nb_reserved */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ 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 */ 0, /* nb_index */ 0, /* nb_matrix_multiply */ 0, /* nb_inplace_matrix_multiply */ }, { 0, /* mp_length */ 0, /* mp_subscript */ 0, /* mp_ass_subscript */ }, { 0, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* was_sq_slice */ 0, /* sq_ass_item */ 0, /* was_sq_ass_slice */ 0, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }, { 0, /* bf_getbuffer */ 0, /* bf_releasebuffer */ }, 0, /* ht_name */ 0, /* ht_slots */ 0, /* ht_qualname */ 0, /* ht_cached_keys */ #if PY_VERSION_HEX >= 0x03090000 0, /* ht_module */ #endif #if !defined(STACKLESS) }, #endif 0, /* wt_user_type */ 0, /* wt_dict_complete */ 0, /* wt_unused */ 0, /* wt_td */ 0, /* wt_iextend */ 0, /* wt_new_user_type_handler */ 0, /* wt_user_data */ }; static void sip_api_bad_catcher_result(PyObject *method); static void sip_api_bad_length_for_slice(Py_ssize_t seqlen, Py_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 void sip_api_call_procedure_method(sip_gilstate_t gil_state, sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, PyObject *method, const char *fmt, ...); static Py_ssize_t sip_api_convert_from_sequence_index(Py_ssize_t idx, Py_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 int sip_api_can_convert_to_enum(PyObject *pyObj, const sipTypeDef *td); static int sip_api_convert_to_enum(PyObject *pyObj, const sipTypeDef *td); static void sip_api_release_type(void *cpp, const sipTypeDef *td, int state); static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td, PyObject *transferObj); static PyObject *sip_api_convert_from_new_pytype(void *cpp, PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp, const char *fmt, ...); static int sip_api_get_state(PyObject *transferObj); static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td); static sipWrapperType *sip_api_map_int_to_class(int typeInt, 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_ex(sip_gilstate_t gil_state, sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, PyObject *method, PyObject *res, const char *fmt, ...); static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, const char *fmt, ...); static void sip_api_call_error_handler(sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, sip_gilstate_t gil_state); 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 PyObject *sip_api_is_py_method_12_8(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper **sipSelfp, 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 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_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 PyObject *sip_api_get_reference(PyObject *self, int key); static int sip_api_is_owned_by_python(sipSimpleWrapper *sw); static int sip_api_is_derived_class(sipSimpleWrapper *sw); static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp); static void sip_api_set_destroy_on_exit(int value); static int sip_api_enable_autoconversion(const sipTypeDef *td, int enable); static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds, const sipClassTypeDef *ctd); static void *sip_api_get_mixin_address(sipSimpleWrapper *w, const sipTypeDef *td); static int sip_api_register_proxy_resolver(const sipTypeDef *td, sipProxyResolverFunc resolver); static PyInterpreterState *sip_api_get_interpreter(void); static sipNewUserTypeFunc sip_api_set_new_user_type_handler( const sipTypeDef *td, sipNewUserTypeFunc handler); static void sip_api_set_type_user_data(sipWrapperType *wt, void *data); static void *sip_api_get_type_user_data(const sipWrapperType *wt); static PyObject *sip_api_py_type_dict(const PyTypeObject *py_type); static PyObject *sip_api_py_type_dict_ref(PyTypeObject *py_type); static const char *sip_api_py_type_name(const PyTypeObject *py_type); static int sip_api_get_method(PyObject *obj, sipMethodDef *method); static PyObject *sip_api_from_method(const sipMethodDef *method); static int sip_api_get_c_function(PyObject *obj, sipCFunctionDef *c_function); static int sip_api_get_date(PyObject *obj, sipDateDef *date); static PyObject *sip_api_from_date(const sipDateDef *date); static int sip_api_get_datetime(PyObject *obj, sipDateDef *date, sipTimeDef *time); static PyObject *sip_api_from_datetime(const sipDateDef *date, const sipTimeDef *time); static int sip_api_get_time(PyObject *obj, sipTimeDef *time); static PyObject *sip_api_from_time(const sipTimeDef *time); static int sip_api_is_user_type(const sipWrapperType *wt); static struct _frame *sip_api_get_frame(int); static int sip_api_check_plugin_for_type(const sipTypeDef *td, const char *name); static PyObject *sip_api_unicode_new(Py_ssize_t len, unsigned maxchar, int *kind, void **data); static void sip_api_unicode_write(int kind, void *data, int index, unsigned value); static void *sip_api_unicode_data(PyObject *obj, int *char_size, Py_ssize_t *len); static int sip_api_get_buffer_info(PyObject *obj, sipBufferInfoDef *bi); static void sip_api_release_buffer_info(sipBufferInfoDef *bi); static PyObject *sip_api_get_user_object(const sipSimpleWrapper *sw); static void sip_api_set_user_object(sipSimpleWrapper *sw, PyObject *user); static int sip_api_enable_gc(int enable); static void sip_api_print_object(PyObject *o); static int sip_api_register_event_handler(sipEventType type, const sipTypeDef *td, void *handler); static void sip_api_instance_destroyed_ex(sipSimpleWrapper **sipSelfp); static void sip_api_visit_wrappers(sipWrapperVisitorFunc visitor, void *closure); static int sip_api_register_exit_notifier(PyMethodDef *md); static sipExceptionHandler sip_api_next_exception_handler(void **statep); /* * 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_call_procedure_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, sip_api_get_address, sip_api_set_destroy_on_exit, sip_api_enable_autoconversion, sip_api_get_mixin_address, sip_api_convert_from_new_pytype, sip_api_convert_to_typed_array, sip_api_convert_to_array, sip_api_register_proxy_resolver, sip_api_get_interpreter, sip_api_set_new_user_type_handler, sip_api_set_type_user_data, sip_api_get_type_user_data, sip_api_py_type_dict, sip_api_py_type_name, sip_api_get_method, sip_api_from_method, sip_api_get_c_function, sip_api_get_date, sip_api_from_date, sip_api_get_datetime, sip_api_from_datetime, sip_api_get_time, sip_api_from_time, sip_api_is_user_type, sip_api_get_frame, sip_api_check_plugin_for_type, sip_api_unicode_new, sip_api_unicode_write, sip_api_unicode_data, sip_api_get_buffer_info, sip_api_release_buffer_info, sip_api_get_user_object, sip_api_set_user_object, /* * The following are not part of the public API. */ sip_api_init_module, sip_api_parse_args, sip_api_parse_pair, /* * The following are part of the public API. */ sip_api_instance_destroyed, /* * The following are not part of the public API. */ 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_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, sip_api_parse_result_ex, sip_api_call_error_handler, sip_api_init_mixin, sip_api_get_reference, /* * The following are part of the public API. */ sip_api_is_owned_by_python, /* * The following are not part of the public API. */ sip_api_is_derived_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_invoke_slot_ex, sip_api_save_slot, sip_api_clear_any_slot_reference, sip_api_visit_slot, /* * 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 are part of the public API. */ sip_api_enable_gc, sip_api_print_object, sip_api_register_event_handler, sip_api_convert_to_enum, sip_api_convert_to_bool, sip_api_enable_overflow_checking, sip_api_long_as_char, sip_api_long_as_signed_char, sip_api_long_as_unsigned_char, sip_api_long_as_short, sip_api_long_as_unsigned_short, sip_api_long_as_int, sip_api_long_as_unsigned_int, sip_api_long_as_long, #if defined(HAVE_LONG_LONG) sip_api_long_as_long_long, sip_api_long_as_unsigned_long_long, #else 0, 0, #endif /* * The following are not part of the public API. */ sip_api_instance_destroyed_ex, /* * The following are part of the public API. */ sip_api_convert_from_slice_object, sip_api_long_as_size_t, sip_api_visit_wrappers, sip_api_register_exit_notifier, /* * The following are not part of the public API. */ sip_api_is_py_method_12_8, sip_api_next_exception_handler, /* * The following are part of the public API. */ sip_api_py_type_dict_ref, }; #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, Overflow } 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. */ int overflow_arg_nr; /* The overflowed positional argument. */ const char *overflow_arg_name; /* The overflowed 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; /* * An entry in the linked list of proxy resolvers. */ typedef struct _sipProxyResolver { const sipTypeDef *td; /* The type the resolver handles. */ sipProxyResolverFunc resolver; /* The resolver. */ struct _sipProxyResolver *next; /* The next in the list. */ } sipProxyResolver; /* * An entry in the linked list of event handlers. */ typedef struct _sipEventHandler { const sipClassTypeDef *ctd; /* The type the handler handles. */ void *handler; /* The handler. */ struct _sipEventHandler *next; /* The next in the list. */ } sipEventHandler; /***************************************************************************** * The structures to support a Python type to hold a named enum. *****************************************************************************/ static PyObject *sipEnumType_alloc(PyTypeObject *self, Py_ssize_t nitems); static PyObject *sipEnumType_getattro(PyObject *self, PyObject *name); /* * 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_as_async (Python v3.5), 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 */ sipEnumType_getattro, /* 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 */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; sipQtAPI *sipQtSupport = NULL; sipTypeDef *sipQObjectType; static int got_kw_handler = FALSE; static int (*kw_handler)(PyObject *, void *, PyObject *); /* * Various strings as Python objects created as and when needed. */ 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 **unused_backdoor = NULL; /* For passing dict of unused arguments. */ static PyObject *init_name = NULL; /* '__init__'. */ static PyObject *empty_tuple; /* The empty tuple. */ static PyObject *type_unpickler; /* The type unpickler function. */ static PyObject *enum_unpickler; /* The enum unpickler function. */ static sipSymbol *sipSymbolList = NULL; /* The list of published symbols. */ static sipAttrGetter *sipAttrGetters = NULL; /* The list of attribute getters. */ static sipProxyResolver *proxyResolvers = NULL; /* The list of proxy resolvers. */ static sipPyObject *sipRegisteredPyTypes = NULL; /* Registered Python types. */ static sipPyObject *sipDisabledAutoconversions = NULL; /* Python types whose auto-conversion is disabled. */ static PyInterpreterState *sipInterpreter = NULL; /* The interpreter. */ static int destroy_on_exit = TRUE; /* Destroy owned objects on exit. */ static sipEventHandler *event_handlers[sipEventNrEvents]; /* The event handler lists. */ static void addClassSlots(sipWrapperType *wt, const sipClassTypeDef *ctd); static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots); static void *findSlot(PyObject *self, sipPySlotType st); static void *findSlotInClass(const sipClassTypeDef *psd, sipPySlotType st); static void *findSlotInSlotList(sipPySlotDef *psd, sipPySlotType st); static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2, sipPySlotType st); static int ssizeobjargprocSlot(PyObject *self, Py_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 int parseResult(PyObject *method, PyObject *res, sipSimpleWrapper *py_self, const char *fmt, va_list va); static PyObject *signature_FromDocstring(const char *doc, Py_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, Py_ssize_t *nr_elem); static PyObject *convertToSequence(void *array, Py_ssize_t nr_elem, const sipTypeDef *td); static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr, sipSimpleWrapper **selfp); static int compareTypedefName(const void *key, const void *el); static int checkPointer(void *ptr, sipSimpleWrapper *sw); static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type, const sipTypeDef *dst_type); static void finalise(void); static PyObject *getDefaultBase(void); static PyObject *getDefaultSimpleBase(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, PyObject *type_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 *args); static PyObject *unpickle_type(PyObject *obj, PyObject *args); static PyObject *pickle_enum(PyObject *obj, PyObject *args); static PyObject *unpickle_enum(PyObject *obj, PyObject *args); static int setReduce(PyTypeObject *type, PyMethodDef *pickler); static int createEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, int enum_nr, PyObject *mod_dict); static PyObject *createUnscopedEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, PyObject *name); static PyObject *createScopedEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, int enum_nr, PyObject *name); static PyObject *createTypeDict(sipExportedModuleDef *em); static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc, sipExportedModuleDef *em); static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr); static int convertPass(const sipTypeDef **tdp, 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 *assign(PyObject *self, PyObject *args); static PyObject *cast(PyObject *self, PyObject *args); static PyObject *callDtor(PyObject *self, PyObject *args); static PyObject *dumpWrapper(PyObject *self, PyObject *arg); static PyObject *enableAutoconversion(PyObject *self, PyObject *args); static PyObject *isDeleted(PyObject *self, PyObject *args); static PyObject *isPyCreated(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 PyObject *setDestroyOnExit(PyObject *self, PyObject *args); static void clear_wrapper(sipSimpleWrapper *sw); static void print_object(const char *label, PyObject *obj); static void addToParent(sipWrapper *self, sipWrapper *owner); static void removeFromParent(sipWrapper *self); static void detachChildren(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, Py_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, Py_ssize_t *aszp); static int convertToWCharArray(PyObject *obj, wchar_t **ap, Py_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); static void *explicit_access_func(sipSimpleWrapper *sw, AccessFuncOp op); static void *indirect_access_func(sipSimpleWrapper *sw, AccessFuncOp op); static void clear_access_func(sipSimpleWrapper *sw); static int check_encoded_string(PyObject *obj); static int isNonlazyMethod(PyMethodDef *pmd); static int addMethod(PyObject *dict, PyMethodDef *pmd); static PyObject *create_property(sipVariableDef *vd); static PyObject *create_function(PyMethodDef *ml); static PyObject *sip_exit(PyObject *self, PyObject *args); static sipConvertFromFunc get_from_convertor(const sipTypeDef *td); static sipPyObject **autoconversion_disabled(const sipTypeDef *td); static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd); static sipFinalFunc find_finalisation(sipClassTypeDef *ctd); static sipNewUserTypeFunc find_new_user_type_handler(sipWrapperType *wt); static PyObject *next_in_mro(PyObject *self, PyObject *after); static int super_init(PyObject *self, PyObject *args, PyObject *kwds, PyObject *type); static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w); static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td, sipWrapper *owner, int flags); static void *resolve_proxy(const sipTypeDef *td, void *proxy); static PyObject *call_method(PyObject *method, const char *fmt, va_list va); static int importTypes(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em); static int importErrorHandlers(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em); static int importExceptions(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em); static int is_subtype(const sipClassTypeDef *ctd, const sipClassTypeDef *base_ctd); static PyObject *import_module_attr(const char *module, const char *attr); static const sipContainerDef *get_container(const sipTypeDef *td); static PyObject *get_qualname(const sipTypeDef *td, PyObject *name); static int convert_to_enum(PyObject *obj, const sipTypeDef *td, int allow_int); static void handle_failed_int_conversion(sipParseFailure *pf, PyObject *arg); static void enum_expected(PyObject *obj, const sipTypeDef *td); static int long_as_nonoverflow_int(PyObject *val_obj); static int dict_set_and_discard(PyObject *dict, const char *name, PyObject *obj); /* * Initialise the module as a library. */ const sipAPIDef *sip_init_library(PyObject *mod_dict) { static PyMethodDef methods[] = { /* This must be first. */ {"_unpickle_enum", unpickle_enum, METH_VARARGS, NULL}, /* This must be second. */ {"_unpickle_type", unpickle_type, METH_VARARGS, NULL}, {"assign", assign, METH_VARARGS, NULL}, {"cast", cast, METH_VARARGS, NULL}, {"delete", callDtor, METH_VARARGS, NULL}, {"dump", dumpWrapper, METH_O, NULL}, {"enableautoconversion", enableAutoconversion, METH_VARARGS, NULL}, {"enableoverflowchecking", sipEnableOverflowChecking, METH_VARARGS, NULL}, {"getapi", sipGetAPI, METH_VARARGS, NULL}, {"isdeleted", isDeleted, METH_VARARGS, NULL}, {"ispycreated", isPyCreated, METH_VARARGS, NULL}, {"ispyowned", isPyOwned, METH_VARARGS, NULL}, {"setapi", sipSetAPI, METH_VARARGS, NULL}, {"setdeleted", setDeleted, METH_VARARGS, NULL}, {"setdestroyonexit", setDestroyOnExit, 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}, {NULL, NULL, 0, NULL} }; static PyMethodDef sip_exit_md = { "_sip_exit", sip_exit, METH_NOARGS, NULL }; PyObject *obj; PyMethodDef *md; /* Add the SIP version number. */ obj = PyLong_FromLong(SIP_VERSION); if (dict_set_and_discard(mod_dict, "SIP_VERSION", obj) < 0) return NULL; obj = PyUnicode_FromString(SIP_VERSION_STR); if (dict_set_and_discard(mod_dict, "SIP_VERSION_STR", obj) < 0) return NULL; /* Add the methods. */ for (md = methods; md->ml_name != NULL; ++md) { PyObject *meth = PyCFunction_New(md, NULL); if (dict_set_and_discard(mod_dict, md->ml_name, meth) < 0) return NULL; if (md == &methods[0]) { Py_INCREF(meth); enum_unpickler = meth; } else if (md == &methods[1]) { Py_INCREF(meth); type_unpickler = meth; } } /* Initialise the types. */ sipWrapperType_Type.tp_base = &PyType_Type; if (PyType_Ready(&sipWrapperType_Type) < 0) return NULL; if (PyType_Ready((PyTypeObject *)&sipSimpleWrapper_Type) < 0) return NULL; if (sip_api_register_py_type((PyTypeObject *)&sipSimpleWrapper_Type) < 0) return NULL; #if defined(STACKLESS) sipWrapper_Type.super.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; #else sipWrapper_Type.super.ht_type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; #endif if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0) return NULL; if (PyType_Ready(&sipMethodDescr_Type) < 0) return NULL; if (PyType_Ready(&sipVariableDescr_Type) < 0) return NULL; sipEnumType_Type.tp_base = &PyType_Type; if (PyType_Ready(&sipEnumType_Type) < 0) return NULL; if (PyType_Ready(&sipVoidPtr_Type) < 0) return NULL; if (PyType_Ready(&sipArray_Type) < 0) return NULL; /* Add the public types. */ if (PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type) < 0) return NULL; if (PyDict_SetItemString(mod_dict, "simplewrapper", (PyObject *)&sipSimpleWrapper_Type) < 0) return NULL; if (PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type) < 0) return NULL; if (PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type) < 0) return NULL; if (PyDict_SetItemString(mod_dict, "array", (PyObject *)&sipArray_Type) < 0) return NULL; /* These will always be needed. */ if (objectify("__init__", &init_name) < 0) return NULL; if ((empty_tuple = PyTuple_New(0)) == NULL) return NULL; /* Initialise the object map. */ sipOMInit(&cppPyMap); /* Make sure we are notified at the end of the exit process. */ if (Py_AtExit(finalise) < 0) return NULL; /* Make sure we are notified at the start of the exit process. */ if (sip_api_register_exit_notifier(&sip_exit_md) < 0) return NULL; /* * Get the current interpreter. This will be shared between all threads. */ sipInterpreter = PyThreadState_Get()->interp; return &sip_api; } /* * Set a dictionary item and discard the reference to the item even if there * was an error. */ static int dict_set_and_discard(PyObject *dict, const char *name, PyObject *obj) { int rc; if (obj == NULL) return -1; rc = PyDict_SetItemString(dict, name, obj); Py_DECREF(obj); return rc; } #if _SIP_MODULE_SHARED /* * The Python module initialisation function. */ #if defined(SIP_STATIC_MODULE) PyObject *_SIP_MODULE_ENTRY(void) #else PyMODINIT_FUNC _SIP_MODULE_ENTRY(void) #endif { static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, _SIP_MODULE_FQ_NAME, /* m_name */ NULL, /* m_doc */ -1, /* m_size */ NULL, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; const sipAPIDef *api; PyObject *mod, *mod_dict, *api_obj; /* Create the module. */ if ((mod = PyModule_Create(&module_def)) == NULL) return NULL; mod_dict = PyModule_GetDict(mod); /* Initialise the module dictionary and static variables. */ if ((api = sip_init_library(mod_dict)) == NULL) return NULL; /* Publish the SIP API. */ api_obj = PyCapsule_New((void *)api, _SIP_MODULE_FQ_NAME "._C_API", NULL); if (dict_set_and_discard(mod_dict, "_C_API", api_obj) < 0) { Py_DECREF(mod); return NULL; } #if _SIP_MODULE_LEGACY { /* * Also install the package-specific module at the top level for * backwards compatibility. */ PyObject *modules = PySys_GetObject("modules"); if (modules != NULL) PyDict_SetItemString(modules, "sip", mod); } #endif return mod; } #endif /* * Return the current interpreter, if there is one. */ static PyInterpreterState *sip_api_get_interpreter(void) { return sipInterpreter; } /* * 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; (void)self; 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. Note that we * use the same calling convention as sys.getrefcount() so that it has the * same caveat regarding the reference count. */ static PyObject *dumpWrapper(PyObject *self, PyObject *arg) { sipSimpleWrapper *sw; (void)self; if (!PyObject_TypeCheck(arg, (PyTypeObject *)&sipSimpleWrapper_Type)) { PyErr_Format(PyExc_TypeError, "dump() argument 1 must be sip.simplewrapper, not %s", Py_TYPE(arg)->tp_name); return NULL; } sw = (sipSimpleWrapper *)arg; print_object(NULL, (PyObject *)sw); printf(" Reference count: %" PY_FORMAT_SIZE_T "d\n", Py_REFCNT(sw)); printf(" Address of wrapped object: %p\n", sip_api_get_address(sw)); printf(" Created by: %s\n", (sipIsDerived(sw) ? "Python" : "C/C++")); printf(" To be destroyed by: %s\n", (sipIsPyOwned(sw) ? "Python" : "C/C++")); 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; } /* * 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; (void)self; if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner)) { if (owner == Py_None) { /* * Note that the Python API is different to the C API when the * owner is 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; (void)self; if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w)) { sip_api_transfer_back(w); Py_INCREF(Py_None); return Py_None; } return NULL; } /* * Invoke the assignment operator for a C++ instance. */ static PyObject *assign(PyObject *self, PyObject *args) { sipSimpleWrapper *dst, *src; PyTypeObject *dst_type, *src_type; const sipTypeDef *td, *super_td; sipAssignFunc assign_helper; void *dst_addr, *src_addr; (void)self; if (!PyArg_ParseTuple(args, "O!O!:assign", &sipSimpleWrapper_Type, &dst, &sipSimpleWrapper_Type, &src)) return NULL; /* Get the assignment helper. */ dst_type = Py_TYPE(dst); td = ((sipWrapperType *)dst_type)->wt_td; if (sipTypeIsMapped(td)) assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign; else assign_helper = ((const sipClassTypeDef *)td)->ctd_assign; if (assign_helper == NULL) { PyErr_SetString(PyExc_TypeError, "argument 1 of assign() does not support assignment"); return NULL; } /* Check the types are compatible. */ src_type = Py_TYPE(src); if (src_type == dst_type) { super_td = NULL; } else if (PyType_IsSubtype(src_type, dst_type)) { super_td = td; } else { PyErr_SetString(PyExc_TypeError, "type of argument 1 of assign() must be a super-type of type of argument 2"); return NULL; } /* Get the addresses. */ if ((dst_addr = sip_api_get_cpp_ptr(dst, NULL)) == NULL) return NULL; if ((src_addr = sip_api_get_cpp_ptr(src, super_td)) == NULL) return NULL; /* Do the assignment. */ assign_helper(dst_addr, 0, src_addr); Py_INCREF(Py_None); return Py_None; } /* * 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; (void)self; 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->wt_td; else { PyErr_SetString(PyExc_TypeError, "argument 1 of 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 wrap_simple_instance(addr, wt->wt_td, NULL, (sw->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; (void)self; if (!PyArg_ParseTuple(args, "O!:delete", &sipSimpleWrapper_Type, &sw)) return NULL; addr = getPtrTypeDef(sw, &ctd); if (checkPointer(addr, sw) < 0) return NULL; clear_wrapper(sw); release(addr, (const sipTypeDef *)ctd, sw->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; (void)self; if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipSimpleWrapper_Type, &sw)) return NULL; res = (sip_api_get_address(sw) == NULL ? Py_True : Py_False); Py_INCREF(res); return res; } /* * Check if an instance was created by Python. */ static PyObject *isPyCreated(PyObject *self, PyObject *args) { sipSimpleWrapper *sw; PyObject *res; (void)self; if (!PyArg_ParseTuple(args, "O!:ispycreated", &sipSimpleWrapper_Type, &sw)) return NULL; /* sipIsDerived() is a misnomer. */ res = (sipIsDerived(sw) ? 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; (void)self; 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; (void)self; if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipSimpleWrapper_Type, &sw)) return NULL; clear_wrapper(sw); Py_INCREF(Py_None); return Py_None; } /* * Unwrap an instance. */ static PyObject *unwrapInstance(PyObject *self, PyObject *args) { sipSimpleWrapper *sw; (void)self; 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 PY_LONG_LONG addr; sipWrapperType *wt; (void)self; if (PyArg_ParseTuple(args, "KO!:wrapinstance", &addr, &sipWrapperType_Type, &wt)) return sip_api_convert_from_type((void *)addr, wt->wt_td, NULL); return NULL; } /* * Set the destroy on exit flag from Python code. */ static PyObject *setDestroyOnExit(PyObject *self, PyObject *args) { (void)self; if (PyArg_ParseTuple(args, "i:setdestroyonexit", &destroy_on_exit)) { Py_INCREF(Py_None); return Py_None; } return NULL; } /* * Set the destroy on exit flag from C++ code. */ static void sip_api_set_destroy_on_exit(int value) { destroy_on_exit = value; } /* * 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); (void)unused; /* 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; } if (im->im_imported_types != NULL && importTypes(client, im, em) < 0) return -1; if (im->im_imported_veh != NULL && importErrorHandlers(client, im, em) < 0) return -1; if (im->im_imported_exceptions != NULL && importExceptions(client, im, em) < 0) return -1; ++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 ((client->em_nameobj = PyUnicode_FromString(full_name)) == NULL) return -1; /* Add it to the list of client modules. */ client->em_next = moduleList; moduleList = client; /* Get any keyword handler. */ if (!got_kw_handler) { kw_handler = sip_api_import_symbol("pyqt_kw_handler"); got_kw_handler = TRUE; } 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) || sipTypeIsScopedEnum(td)) { sipEnumTypeDef *etd = (sipEnumTypeDef *)td; if (td->td_version < 0 || sipIsRangeEnabled(client, td->td_version)) if (createEnum(client, etd, i, mod_dict) < 0) return -1; /* * Register the enum pickler for nested enums (non-nested enums * don't need special treatment). */ if (sipTypeIsEnum(td) && 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->wt_iextend; wt->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) { sipTypeDef *etd = client->em_types[emd->em_enum]; PyObject *mo; if (sipTypeIsScopedEnum(etd)) continue; mo = sip_api_convert_from_enum(emd->em_val, etd); if (dict_set_and_discard(mod_dict, emd->em_name, mo) < 0) return -1; } /* * 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. This should already have been done, * but just in case... */ 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_RawMalloc(nbytes)) == NULL) PyErr_NoMemory(); return mem; } /* * A wrapper around the Python memory de-allocater. */ void sip_api_free(void *mem) { PyMem_RawFree(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; } /* * Convert a new C/C++ instance to a Python instance of a specific Python type.. */ static PyObject *sip_api_convert_from_new_pytype(void *cpp, PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp, const char *fmt, ...) { PyObject *args, *res; va_list va; va_start(va, fmt); if ((args = PyTuple_New(strlen(fmt))) != NULL && buildObject(args, fmt, va) != NULL) { res = sipWrapInstance(cpp, py_type, args, owner, (selfp != NULL ? SIP_DERIVED_CLASS : 0)); /* Initialise the rest of an instance of a derived class. */ if (selfp != NULL) *selfp = (sipSimpleWrapper *)res; } else { res = NULL; } Py_XDECREF(args); va_end(va); return res; } /* * Call a method and return the result. */ static PyObject *call_method(PyObject *method, const char *fmt, va_list va) { PyObject *args, *res; if ((args = PyTuple_New(strlen(fmt))) == NULL) return NULL; if (buildObject(args, fmt, va) != NULL) res = PyObject_CallObject(method, args); else res = NULL; Py_DECREF(args); return res; } /* * Call the Python re-implementation of a C++ virtual that does not return a * value and handle the result.. */ static void sip_api_call_procedure_method(sip_gilstate_t gil_state, sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, PyObject *method, const char *fmt, ...) { PyObject *res; va_list va; va_start(va, fmt); res = call_method(method, fmt, va); va_end(va); if (res != NULL) { Py_DECREF(res); if (res != Py_None) { sip_api_bad_catcher_result(method); res = NULL; } } Py_DECREF(method); if (res == NULL) sip_api_call_error_handler(error_handler, py_self, gil_state); SIP_RELEASE_GIL(gil_state); } /* * Call the Python re-implementation of a C++ virtual. */ static PyObject *sip_api_call_method(int *isErr, PyObject *method, const char *fmt, ...) { PyObject *res; va_list va; va_start(va, fmt); res = call_method(method, fmt, va); va_end(va); if (res == NULL && isErr != NULL) *isErr = TRUE; 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 = (int)(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; Py_ssize_t l; s = va_arg(va, char *); l = va_arg(va, Py_ssize_t); if (s != NULL) { el = PyBytes_FromStringAndSize(s, l); } else { Py_INCREF(Py_None); el = Py_None; } } break; case 'G': #if defined(HAVE_WCHAR_H) { wchar_t *s; Py_ssize_t l; s = va_arg(va, wchar_t *); l = va_arg(va, Py_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 = PyBytes_FromStringAndSize(&c, 1); } break; case 'a': { char c = va_arg(va, int); el = PyUnicode_FromStringAndSize(&c, 1); } 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': { 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': case 'L': el = PyLong_FromLong(va_arg(va, int)); 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 = PyBytes_FromString(s); } else { Py_INCREF(Py_None); el = Py_None; } } break; case 'A': { char *s = va_arg(va, char *); if (s != NULL) { el = PyUnicode_FromString(s); } 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, (Py_ssize_t)wcslen(s)); else { Py_INCREF(Py_None); el = Py_None; } } #else raiseNoWChar(); el = NULL; #endif break; case 't': case 'u': case 'M': el = PyLong_FromUnsignedLong(va_arg(va, unsigned)); break; case '=': el = PyLong_FromSize_t(va_arg(va, size_t)); break; case 'B': { 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->wt_td, 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': { 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->wt_td, 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 *); Py_ssize_t l = va_arg(va, Py_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; case 'z': { const char *name = va_arg(va, const char *); void *p = va_arg(va, void *); if (p == NULL) { el = Py_None; Py_INCREF(el); } else { el = PyCapsule_New(p, name, NULL); } } 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. As of v9.0 of the API this * is only ever called by handwritten code. */ static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, const char *fmt, ...) { int rc; va_list va; va_start(va, fmt); rc = parseResult(method, res, NULL, fmt, va); va_end(va); if (isErr != NULL && rc < 0) *isErr = TRUE; return rc; } /* * Parse a result object based on a format string. */ static int sip_api_parse_result_ex(sip_gilstate_t gil_state, sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, PyObject *method, PyObject *res, const char *fmt, ...) { int rc; if (res != NULL) { va_list va; va_start(va, fmt); rc = parseResult(method, res, deref_mixin(py_self), fmt, va); va_end(va); Py_DECREF(res); } else { rc = -1; } Py_DECREF(method); if (rc < 0) sip_api_call_error_handler(error_handler, py_self, gil_state); SIP_RELEASE_GIL(gil_state); return rc; } /* * Call a virtual error handler. This is called with the GIL and from the * thread that raised the error. */ static void sip_api_call_error_handler(sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self, sip_gilstate_t sipGILState) { if (error_handler != NULL) error_handler(deref_mixin(py_self), sipGILState); else PyErr_Print(); } /* * Do the main work of parsing a result object based on a format string. */ static int parseResult(PyObject *method, PyObject *res, sipSimpleWrapper *py_self, const char *fmt, va_list va) { int tupsz, rc = 0; /* We rely on PyErr_Occurred(). */ PyErr_Clear(); /* Get self if it is provided as an argument. */ if (*fmt == 'S') { py_self = va_arg(va, sipSimpleWrapper *); ++fmt; } /* Basic validation of the format string. */ if (*fmt == '(') { char ch; const char *cp = ++fmt; int sub_format = FALSE; tupsz = 0; while ((ch = *cp++) != ')') { if (ch == '\0') { PyErr_Format(PyExc_SystemError, "sipParseResult(): invalid format string \"%s\"", fmt - 1); rc = -1; break; } if (sub_format) { sub_format = FALSE; } else { ++tupsz; /* Some format characters have a sub-format. */ if (strchr("aAHDC", ch) != NULL) sub_format = TRUE; } } 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 **); Py_ssize_t *szp = va_arg(va, Py_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 **); Py_ssize_t *szp = va_arg(va, Py_ssize_t *); if (parseWCharArray(arg, p, szp) < 0) invalid = TRUE; } #else raiseNoWChar(); invalid = TRUE; #endif break; case 'b': { char *p = va_arg(va, void *); int v = sip_api_convert_to_bool(arg); if (v < 0) invalid = TRUE; else if (p != NULL) sipSetBool(p, 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 *p = va_arg(va, double *); double v = PyFloat_AsDouble(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'E': { PyTypeObject *et = va_arg(va, PyTypeObject *); int *p = va_arg(va, int *); int v = sip_api_convert_to_enum(arg, ((sipEnumTypeObject *)et)->type); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'F': { sipTypeDef *td = va_arg(va, sipTypeDef *); int *p = va_arg(va, int *); int v = sip_api_convert_to_enum(arg, td); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'f': { float *p = va_arg(va, float *); float v = (float)PyFloat_AsDouble(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'I': { char *p = va_arg(va, char *); char v = sip_api_long_as_char(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'L': { signed char *p = va_arg(va, signed char *); signed char v = sip_api_long_as_signed_char(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'M': { unsigned char *p = va_arg(va, unsigned char *); unsigned char v = sip_api_long_as_unsigned_char(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'h': { signed short *p = va_arg(va, signed short *); signed short v = sip_api_long_as_short(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 't': { unsigned short *p = va_arg(va, unsigned short *); unsigned short v = sip_api_long_as_unsigned_short(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'e': { int *p = va_arg(va, int *); int v = long_as_nonoverflow_int(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'i': { int *p = va_arg(va, int *); int v = sip_api_long_as_int(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'u': { unsigned *p = va_arg(va, unsigned *); unsigned v = sip_api_long_as_unsigned_int(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case '=': { size_t *p = va_arg(va, size_t *); size_t v = sip_api_long_as_size_t(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'l': { long *p = va_arg(va, long *); long v = sip_api_long_as_long(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'm': { unsigned long *p = va_arg(va, unsigned long *); unsigned long v = sip_api_long_as_unsigned_long(arg); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'n': { #if defined(HAVE_LONG_LONG) PY_LONG_LONG *p = va_arg(va, PY_LONG_LONG *); PY_LONG_LONG v = sip_api_long_as_long_long(arg); #else long *p = va_arg(va, long *); long v = sip_api_long_as_long(arg); #endif if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'o': { #if defined(HAVE_LONG_LONG) unsigned PY_LONG_LONG *p = va_arg(va, unsigned PY_LONG_LONG *); unsigned PY_LONG_LONG v = sip_api_long_as_unsigned_long_long(arg); #else unsigned long *p = va_arg(va, unsigned long *); unsigned long v = sip_api_long_as_unsigned_long(arg); #endif if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 's': { 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 *)py_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 sip_api_keep_reference((PyObject *)py_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': { 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->wt_td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr); if (iserr) invalid = TRUE; } } break; case 'D': { 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); if (cpp != NULL) assign_helper(cpp, 0, val); sip_api_release_type(val, td, state); } else if (cpp != NULL) { *(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)) { if (p != NULL) { Py_INCREF(arg); *p = arg; } } else { invalid = TRUE; } } break; case 'O': { PyObject **p = va_arg(va, PyObject **); if (p != NULL) { Py_INCREF(arg); *p = arg; } } break; case 'T': { PyTypeObject *type = va_arg(va, PyTypeObject *); PyObject **p = va_arg(va, PyObject **); if (PyObject_TypeCheck(arg, type)) { if (p != NULL) { Py_INCREF(arg); *p = arg; } } else { invalid = TRUE; } } break; case 'V': { void *v = sip_api_convert_to_void_ptr(arg); void **p = va_arg(va, void **); if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } break; case 'z': { const char *name = va_arg(va, const char *); void **p = va_arg(va, void **); if (arg == Py_None) { if (p != NULL) *p = NULL; } else { #if defined(SIP_USE_CAPSULE) void *v = PyCapsule_GetPointer(arg, name); #else void *v = sip_api_convert_to_void_ptr(arg); (void)name; #endif if (PyErr_Occurred()) invalid = TRUE; else if (p != NULL) *p = v; } } break; case 'Z': if (arg != Py_None) invalid = TRUE; break; case '!': { PyObject **p = va_arg(va, PyObject **); if (PyObject_CheckBuffer(arg)) { if (p != NULL) { Py_INCREF(arg); *p = arg; } } else { invalid = TRUE; } } break; case '$': { PyObject **p = va_arg(va, PyObject **); if (arg == Py_None || PyObject_CheckBuffer(arg)) { if (p != NULL) { Py_INCREF(arg); *p = arg; } } else { 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; } } } return rc; } /* * 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; if (unused != NULL) { /* * Initialise the return of any unused keyword arguments. This is * used by any ctor overload. */ *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) { return PyUnicode_FromFormat("argument %d has unexpected type '%s'", arg_nr, Py_TYPE(arg)->tp_name); } /* * 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. */ static void failure_dtor(PyObject *capsule) { sipParseFailure *failure = (sipParseFailure *)PyCapsule_GetPointer(capsule, NULL); Py_XDECREF(failure->detail_obj); sip_api_free(failure); } /* * 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 ((failure_obj = PyCapsule_New(failure_copy, NULL, failure_dtor)) == 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 one or 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(sipArg1 != NULL ? 2 : 1)) == 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); if (sipArg1 != NULL) { 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; Py_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 '#': /* A ctor has an argument with the /Transfer/ annotation. */ *selfp = (sipSimpleWrapper *)va_arg(va, PyObject *); break; 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. We continue to parse if we get an * overflow because that is, strictly speaking, a second pass error. */ while (failure.reason == Ok || failure.reason == Overflow) { 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; Py_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 (!PyUnicode_Check(key)) { 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 (PyUnicode_CompareWithASCIIString(key, name) == 0) 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 - *selfargp) { /* * 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 (nr_kwd_args != 0 && kwdlist != NULL) { const char *name = kwdlist[argnr - *selfargp]; 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; Py_ssize_t pos = 0; while (PyDict_Next(sipKwdArgs, &pos, &key, &value)) { int a; if (!PyUnicode_Check(key)) { 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 (PyUnicode_CompareWithASCIIString(key, name) == 0) 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. */ va_arg(va, PyObject **); va_arg(va, const char **); fmt++; if (arg != NULL && check_encoded_string(arg) < 0) { failure.reason = WrongType; failure.detail_obj = arg; Py_INCREF(arg); } break; } case 'a': { /* Character from a Python string. */ va_arg(va, char *); fmt++; if (arg != NULL && check_encoded_string(arg) < 0) { failure.reason = WrongType; failure.detail_obj = arg; Py_INCREF(arg); } 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 (PyBytes_Check(arg)) { char *s = PyBytes_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 (PyBytes_Check(arg)) { char *s = PyBytes_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 (PyBytes_Check(arg)) { char *s = PyBytes_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 mapped type instances. For ABI v12.10 and * earlier this is also used for class instances. */ const sipTypeDef *td; td = va_arg(va, const sipTypeDef *); va_arg(va, void **); va_arg(va, Py_ssize_t *); if (arg != NULL && !canConvertFromSequence(arg, td)) { failure.reason = WrongType; failure.detail_obj = arg; Py_INCREF(arg); } break; } case '>': { /* * Sequence or sip.array of class instances. This is only used * by ABI v12.11 and later. */ const sipTypeDef *td; td = va_arg(va, const sipTypeDef *); va_arg(va, void **); va_arg(va, Py_ssize_t *); va_arg(va, int *); if (arg != NULL && !sip_array_can_convert(arg, td) && !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 '!': { /* Python object that implements the buffer protocol. */ PyObject **p = va_arg(va, PyObject **); if (arg != NULL) { if (PyObject_CheckBuffer(arg)) { *p = arg; } else { failure.reason = WrongType; failure.detail_obj = arg; Py_INCREF(arg); } } break; } case '$': { /* * Python object that implements the buffer protocol or None. */ PyObject **p = va_arg(va, PyObject **); if (arg != NULL) { if (arg == Py_None || PyObject_CheckBuffer(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 **); Py_ssize_t *szp = va_arg(va, Py_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 **); Py_ssize_t *szp = va_arg(va, Py_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 '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 = sip_api_convert_to_bool(arg); if (v < 0) { 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 *); int *p = va_arg(va, int *); if (arg != NULL) { int v = sip_api_convert_to_enum(arg, td); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } } break; case 'e': { /* Anonymous enum. */ int *p = va_arg(va, int *); if (arg != NULL) { int v = long_as_nonoverflow_int(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } } break; case 'i': { /* Integer. */ int *p = va_arg(va, int *); if (arg != NULL) { int v = sip_api_long_as_int(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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_int(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case '=': { /* size_t integer. */ size_t *p = va_arg(va, size_t *); if (arg != NULL) { size_t v = sip_api_long_as_size_t(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case 'I': { /* Char as an integer. */ char *p = va_arg(va, char *); if (arg != NULL) { char v = sip_api_long_as_char(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case 'L': { /* Signed char as an integer. */ signed char *p = va_arg(va, signed char *); if (arg != NULL) { signed char v = sip_api_long_as_signed_char(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case 'M': { /* Unsigned char as an integer. */ unsigned char *p = va_arg(va, unsigned char *); if (arg != NULL) { unsigned char v = sip_api_long_as_unsigned_char(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case 'h': { /* Short integer. */ signed short *p = va_arg(va, signed short *); if (arg != NULL) { signed short v = sip_api_long_as_short(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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_short(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); else *p = v; } break; } case 'l': { /* Long integer. */ long *p = va_arg(va, long *); if (arg != NULL) { long v = sip_api_long_as_long(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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()) handle_failed_int_conversion(&failure, 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 = sip_api_long_as_long_long(arg); #else long v = sip_api_long_as_long(arg); #endif if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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 = sip_api_long_as_unsigned_long_long(arg); #else unsigned long v = sip_api_long_as_unsigned_long(arg); #endif if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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 *); int *p = va_arg(va, int *); if (arg != NULL) { *p = convert_to_enum(arg, td, FALSE); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, 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 (PyLong_Check(arg)) { *(int *)p = sip_api_long_as_int(arg); if (PyErr_Occurred()) handle_failed_int_conversion(&failure, arg); } 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; } case 'z': { /* Void pointer as a capsule. */ const char *name = va_arg(va, const char *); void **p = va_arg(va, void **); if (arg == Py_None) { *p = NULL; } else if (arg != NULL) { void *v = PyCapsule_GetPointer(arg, name); if (PyErr_Occurred()) { failure.reason = WrongType; failure.detail_obj = arg; Py_INCREF(arg); } else { *p = v; } } break; } } if ((failure.reason == Ok || failure.reason == Overflow) && ch == 'W') { /* An ellipsis matches everything and ends the parse. */ break; } } /* Handle parse failures appropriately. */ if (failure.reason == Ok) return TRUE; if (failure.reason == Overflow) { /* * We have successfully parsed the signature but one of the arguments * has been found to overflow. Raise an appropriate exception and * ensure we don't parse any subsequent overloads. */ if (failure.overflow_arg_nr >= 0) { PyErr_Format(PyExc_OverflowError, "argument %d overflowed: %S", failure.overflow_arg_nr, failure.detail_obj); } else { PyErr_Format(PyExc_OverflowError, "argument '%s' overflowed: %S", failure.overflow_arg_name, failure.detail_obj); } /* The overflow exception has now been raised. */ failure.reason = Raised; } if (failure.reason != Raised) add_failure(parseErrp, &failure); if (failure.reason == Raised) { Py_XDECREF(failure.detail_obj); /* * Discard any previous errors and flag that the exception we want the * user to see has been raised. */ Py_XDECREF(*parseErrp); *parseErrp = Py_None; Py_INCREF(Py_None); } return FALSE; } /* * Called after a failed conversion of an integer. */ static void handle_failed_int_conversion(sipParseFailure *pf, PyObject *arg) { PyObject *xtype, *xvalue, *xtb; assert(pf->reason == Ok || pf->reason == Overflow); PyErr_Fetch(&xtype, &xvalue, &xtb); if (PyErr_GivenExceptionMatches(xtype, PyExc_OverflowError) && xvalue != NULL) { /* Remove any previous overflow exception. */ Py_XDECREF(pf->detail_obj); pf->reason = Overflow; pf->overflow_arg_nr = pf->arg_nr; pf->overflow_arg_name = pf->arg_name; pf->detail_obj = xvalue; Py_INCREF(xvalue); } else { pf->reason = WrongType; pf->detail_obj = arg; Py_INCREF(arg); } PyErr_Restore(xtype, xvalue, xtb); } /* * 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; Py_ssize_t nr_pos_args; /* Handle the converions of "self" first. */ switch (*fmt++) { case '#': va_arg(va, PyObject *); break; 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 - selfarg]; 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 mapped type instances. */ const sipTypeDef *td; void **array; Py_ssize_t *nr_elem; td = va_arg(va, const sipTypeDef *); array = va_arg(va, void **); nr_elem = va_arg(va, Py_ssize_t *); if (arg != NULL && !convertFromSequence(arg, td, array, nr_elem)) return FALSE; break; } case '>': { /* Sequence or sip.array of class instances. */ const sipTypeDef *td; void **array; Py_ssize_t *nr_elem; int *is_temp; td = va_arg(va, const sipTypeDef *); array = va_arg(va, void **); nr_elem = va_arg(va, Py_ssize_t *); is_temp = va_arg(va, int *); if (arg != NULL) { if (sip_array_can_convert(arg, td)) { sip_array_convert(arg, array, nr_elem); *is_temp = FALSE; } else if (convertFromSequence(arg, td, array, nr_elem)) { /* * Note that this will leak if there is a subsequent * error. */ *is_temp = TRUE; } else { 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 **); else owner = NULL; 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 (owner != NULL && *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. */ if (*fmt++ == 'E') va_arg(va, void *); va_arg(va, void *); 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 = NULL; 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) return FALSE; *keep = s; } 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) return FALSE; } break; } /* * Every other argument is a pointer and only differ in how many there * are. */ case 'N': case 'T': case 'k': case 'K': case 'U': case 'E': 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) { Py_ssize_t i, size = PySequence_Size(seq); if (size < 0) return FALSE; /* * Check the type of each element. Note that this is inconsistent with how * similiar situations are handled elsewhere. We should instead just check * we have an iterator and assume (until the second pass) that the type is * correct. */ 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, Py_ssize_t *nr_elem) { int iserr = 0; Py_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, Py_ssize_t nr_elem, const sipTypeDef *td) { Py_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; } /* * Perform housekeeping after a C++ instance has been destroyed. */ void sip_api_instance_destroyed(sipSimpleWrapper *sw) { sip_api_instance_destroyed_ex(&sw); } /* * Carry out actions common to all dtors. */ static void sip_api_instance_destroyed_ex(sipSimpleWrapper **sipSelfp) { /* If there is no interpreter just to the minimum and get out. */ if (sipInterpreter == NULL) { *sipSelfp = NULL; return; } SIP_BLOCK_THREADS sipSimpleWrapper *sipSelf = *sipSelfp; if (sipSelf != NULL) { PyObject *xtype, *xvalue, *xtb; /* We may be tidying up after an exception so preserve it. */ PyErr_Fetch(&xtype, &xvalue, &xtb); callPyDtor(sipSelf); PyErr_Restore(xtype, xvalue, xtb); sipOMRemoveObject(&cppPyMap, sipSelf); /* * This no longer points to anything useful. Actually it might do as * the partialy destroyed C++ instance may still be trying to invoke * reimplemented virtuals. */ clear_access_func(sipSelf); /* * 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); } /* * Normally this is done in the generated dealloc function. However * this is only called if the pointer/access function has not been * reset (which it has). It acts as a guard to prevent any further * invocations of reimplemented virtuals. */ *sipSelfp = NULL; } SIP_UNBLOCK_THREADS } /* * Clear any access function so that sip_api_get_address() will always return a * NULL pointer. */ static void clear_access_func(sipSimpleWrapper *sw) { if (sw->access_func != NULL) { sw->access_func(sw, ReleaseGuard); sw->access_func = NULL; } sw->data = NULL; } /* * 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_12_8(&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); } } /* * Detach and children of a parent. */ static void detachChildren(sipWrapper *self) { while (self->first_child != NULL) removeFromParent(self->first_child); } /* * Convert a sequence index. Return the index or a negative value if there was * an error. */ static Py_ssize_t sip_api_convert_from_sequence_index(Py_ssize_t idx, Py_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 class of a type that has no explicit super-type. */ static PyObject *getDefaultBase(void) { static PyObject *default_base = NULL; /* Only do this once. */ if (default_base == NULL) { if ((default_base = PyTuple_Pack(1, (PyObject *)&sipWrapper_Type)) == NULL) return NULL; } Py_INCREF(default_base); return default_base; } /* * Return a tuple of the base class of a simple type that has no explicit * super-type. */ static PyObject *getDefaultSimpleBase(void) { static PyObject *default_simple_base = NULL; /* Only do this once. */ if (default_simple_base == NULL) { if ((default_simple_base = PyTuple_Pack(1, (PyObject *)&sipSimpleWrapper_Type)) == NULL) return NULL; } Py_INCREF(default_simple_base); return default_simple_base; } /* * 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, PyObject *type_dict, sipExportedModuleDef *client) { PyObject *py_type, *scope_dict, *name, *args; sipTypeDef *scope_td; /* Get the dictionary to place the type in. */ if (cod->cod_scope.sc_flag) { scope_td = NULL; scope_dict = mod_dict; } else { scope_td = getGeneratedType(&cod->cod_scope, client); scope_dict = getScopeDict(scope_td, mod_dict, client); if (scope_dict == NULL) goto reterr; } /* Create an object corresponding to the type name. */ if ((name = PyUnicode_FromString(sipPyNameOfContainer(cod, td))) == NULL) goto reterr; /* Create the type by calling the metatype. */ if ((args = PyTuple_Pack(3, name, bases, type_dict)) == NULL) goto relname; /* Pass the type via the back door. */ assert(currentType == NULL); currentType = td; py_type = PyObject_Call(metatype, args, NULL); currentType = NULL; if (py_type == NULL) goto relargs; /* Fix __qualname__ if there is a scope. */ if (scope_td != NULL) { PyHeapTypeObject *ht; PyObject *qualname = get_qualname(scope_td, name); if (qualname == NULL) goto reltype; ht = (PyHeapTypeObject *)py_type; Py_CLEAR(ht->ht_qualname); ht->ht_qualname = qualname; } /* Add the type to the "parent" dictionary. */ if (PyDict_SetItem(scope_dict, name, py_type) < 0) goto reltype; Py_DECREF(args); Py_DECREF(name); return py_type; /* Unwind on error. */ reltype: Py_DECREF(py_type); relargs: Py_DECREF(args); relname: Py_DECREF(name); reterr: return NULL; } /* * Create a single class type object. */ static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd, PyObject *mod_dict) { PyObject *bases, *metatype, *py_type, *type_dict; sipEncodedTypeDef *sup; int i; /* 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 = (sipTypeIsNamespace(&ctd->ctd_base) ? getDefaultSimpleBase() : getDefaultBase()); } else { PyObject *supertype; const char *supertype_name = sipNameFromPool(client, ctd->ctd_supertype); if ((supertype = findPyType(supertype_name)) == NULL) goto reterr; bases = PyTuple_Pack(1, supertype); } if (bases == NULL) goto reterr; } else { int 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); /* * Inherit any garbage collector code rather than look for it each * time it is needed. */ if (ctd->ctd_traverse == NULL) ctd->ctd_traverse = ((sipClassTypeDef *)sup_td)->ctd_traverse; if (ctd->ctd_clear == NULL) ctd->ctd_clear = ((sipClassTypeDef *)sup_td)->ctd_clear; } } /* * 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)); /* Create the type dictionary and populate it with any non-lazy methods. */ if ((type_dict = createTypeDict(client)) == NULL) goto relbases; if (sipTypeHasNonlazyMethod(&ctd->ctd_base)) { PyMethodDef *pmd = ctd->ctd_container.cod_methods; for (i = 0; i < ctd->ctd_container.cod_nrmethods; ++i) { if (isNonlazyMethod(pmd) && addMethod(type_dict, pmd) < 0) goto reldict; ++pmd; } } if ((py_type = createContainerType(&ctd->ctd_container, (sipTypeDef *)ctd, bases, metatype, mod_dict, type_dict, client)) == NULL) goto reldict; if (ctd->ctd_pyslots != NULL) fix_slots((PyTypeObject *)py_type, ctd->ctd_pyslots); /* 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); Py_DECREF(type_dict); return 0; /* Unwind after an error. */ reltype: Py_DECREF(py_type); reldict: Py_DECREF(type_dict); 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, *type_dict; /* 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 = getDefaultBase()) == NULL) goto reterr; /* Create the type dictionary. */ if ((type_dict = createTypeDict(client)) == NULL) goto relbases; if (createContainerType(&mtd->mtd_container, (sipTypeDef *)mtd, bases, (PyObject *)&sipWrapperType_Type, mod_dict, type_dict, client) == NULL) goto reldict; /* We can now release our references. */ Py_DECREF(bases); Py_DECREF(type_dict); return 0; /* Unwind after an error. */ reldict: Py_DECREF(type_dict); 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 (PyUnicode_Compare(mname_obj, em->em_nameobj) == 0) break; Py_DECREF(mod); if (em == NULL) PyErr_Format(PyExc_SystemError, "unable to find to find module: %U", mname_obj); return em; } /* * The type unpickler. */ static PyObject *unpickle_type(PyObject *obj, PyObject *args) { PyObject *mname_obj, *init_args; const char *tname; sipExportedModuleDef *em; int i; (void)obj; if (!PyArg_ParseTuple(args, "UsO!:_unpickle_type", &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 *args) { sipExportedModuleDef *em; (void)args; /* 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 (init_args == NULL) return 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 *obj, PyObject *args) { PyObject *mname_obj, *evalue_obj; const char *ename; sipExportedModuleDef *em; int i; (void)obj; if (!PyArg_ParseTuple(args, "UsO:_unpickle_enum", &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 *args) { sipTypeDef *td = ((sipEnumTypeObject *)Py_TYPE(obj))->type; (void)args; return Py_BuildValue("O(Osi)", enum_unpickler, td->td_module->em_nameobj, sipPyNameOfEnum((sipEnumTypeDef *)td), (int)PyLong_AS_LONG(obj)); } /* * 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 object. */ static int createEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, int enum_nr, PyObject *mod_dict) { int rc; PyObject *name, *dict, *enum_obj; 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) return -1; /* Create an object corresponding to the type name. */ if ((name = PyUnicode_FromString(sipPyNameOfEnum(etd))) == NULL) return -1; /* Create the enum. */ if (sipTypeIsEnum(&etd->etd_base)) enum_obj = createUnscopedEnum(client, etd, name); else enum_obj = createScopedEnum(client, etd, enum_nr, name); if (enum_obj == NULL) { Py_DECREF(name); return -1; } /* Add the enum to the "parent" dictionary. */ rc = PyDict_SetItem(dict, name, enum_obj); /* We can now release our remaining references. */ Py_DECREF(name); Py_DECREF(enum_obj); return rc; } /* * Create an unscoped enum. */ static PyObject *createUnscopedEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, PyObject *name) { static PyObject *bases = NULL; PyObject *type_dict, *args; sipEnumTypeObject *eto; /* Create the base type tuple if it hasn't already been done. */ if (bases == NULL) if ((bases = PyTuple_Pack(1, (PyObject *)&PyLong_Type)) == NULL) return NULL; /* Create the type dictionary. */ if ((type_dict = createTypeDict(client)) == NULL) return NULL; /* Create the type by calling the metatype. */ args = PyTuple_Pack(3, name, bases, type_dict); Py_DECREF(type_dict); if (args == NULL) return NULL; /* Pass the type via the back door. */ assert(currentType == NULL); currentType = &etd->etd_base; eto = (sipEnumTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type, args, NULL); currentType = NULL; Py_DECREF(args); if (eto == NULL) return NULL; if (etd->etd_pyslots != NULL) fix_slots((PyTypeObject *)eto, etd->etd_pyslots); /* * If the enum has a scope then the default __qualname__ will be incorrect. */ if (etd->etd_scope >= 0) { /* Append the name of the enum to the scope's __qualname__. */ Py_CLEAR(eto->super.ht_qualname); eto->super.ht_qualname = get_qualname( client->em_types[etd->etd_scope], name); if (eto->super.ht_qualname == NULL) { Py_DECREF((PyObject *)eto); return NULL; } } return (PyObject *)eto; } /* * Create a scoped enum. */ static PyObject *createScopedEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd, int enum_nr, PyObject *name) { static PyObject *enum_type = NULL, *module_arg = NULL; static PyObject *qualname_arg = NULL; int i, nr_members; sipEnumMemberDef *enm; PyObject *members, *enum_obj, *args, *kw_args; /* Get the enum type if we haven't done so already. */ if (enum_type == NULL) { if ((enum_type = import_module_attr("enum", "IntEnum")) == NULL) goto ret_err; } /* Create a dict of the members. */ if ((members = PyDict_New()) == NULL) goto ret_err; /* * Note that the current structures for defining scoped enums are not ideal * as we are re-using the ones used for unscoped enums (which are designed * to support lazy implementations). */ if (etd->etd_scope < 0) { nr_members = client->em_nrenummembers; enm = client->em_enummembers; } else { const sipContainerDef *cod = get_container(client->em_types[etd->etd_scope]); nr_members = cod->cod_nrenummembers; enm = cod->cod_enummembers; } for (i = 0; i < nr_members; ++i) { if (enm->em_enum == enum_nr) { PyObject *val = PyLong_FromLong(enm->em_val); if (dict_set_and_discard(members, enm->em_name, val) < 0) goto rel_members; } ++enm; } if ((args = PyTuple_Pack(2, name, members)) == NULL) goto rel_members; if ((kw_args = PyDict_New()) == NULL) goto rel_args; if (objectify("module", &module_arg) < 0) goto rel_kw_args; if (PyDict_SetItem(kw_args, module_arg, client->em_nameobj) < 0) goto rel_kw_args; /* * If the enum has a scope then the default __qualname__ will be incorrect. */ if (etd->etd_scope >= 0) { int rc; PyObject *qualname; if (objectify("qualname", &qualname_arg) < 0) goto rel_kw_args; if ((qualname = get_qualname(client->em_types[etd->etd_scope], name)) == NULL) goto rel_kw_args; rc = PyDict_SetItem(kw_args, qualname_arg, qualname); Py_DECREF(qualname); if (rc < 0) goto rel_kw_args; } if ((enum_obj = PyObject_Call(enum_type, args, kw_args)) == NULL) goto rel_kw_args; Py_DECREF(kw_args); Py_DECREF(args); Py_DECREF(members); /* Note that it isn't actually a PyTypeObject. */ etd->etd_base.td_py_type = (PyTypeObject *)enum_obj; return enum_obj; /* Unwind on errors. */ rel_kw_args: Py_DECREF(kw_args); rel_args: Py_DECREF(args); rel_members: Py_DECREF(members); ret_err: return NULL; } /* * Create a type dictionary for dynamic type being created in a module. */ static PyObject *createTypeDict(sipExportedModuleDef *em) { 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, em->em_nameobj) < 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 ((*objp = PyUnicode_FromString(s)) == 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; } /* * Return non-zero if a method is non-lazy, ie. it must be added to the type * when it is created. */ static int isNonlazyMethod(PyMethodDef *pmd) { static const char *lazy[] = { "__getattribute__", "__getattr__", "__enter__", "__exit__", "__aenter__", "__aexit__", NULL }; const char **l; for (l = lazy; *l != NULL; ++l) if (strcmp(pmd->ml_name, *l) == 0) return TRUE; return FALSE; } /* * Add a method to a dictionary. */ static int addMethod(PyObject *dict, PyMethodDef *pmd) { PyObject *descr = sipMethodDescr_New(pmd); return dict_set_and_discard(dict, pmd->ml_name, descr); } /* * 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. */ for (pmd = cod->cod_methods, i = 0; i < cod->cod_nrmethods; ++i, ++pmd) { /* Non-lazy methods will already have been handled. */ if (!sipTypeHasNonlazyMethod(td) || !isNonlazyMethod(pmd)) { if (addMethod(dict, pmd) < 0) return -1; } } /* Do the unscoped enum members. */ for (enm = cod->cod_enummembers, i = 0; i < cod->cod_nrenummembers; ++i, ++enm) { PyObject *val; if (enm->em_enum < 0) { /* It's an unnamed unscoped enum. */ val = PyLong_FromLong(enm->em_val); } else { sipTypeDef *etd = td->td_module->em_types[enm->em_enum]; if (sipTypeIsScopedEnum(etd)) continue; val = sip_api_convert_from_enum(enm->em_val, etd); } if (dict_set_and_discard(dict, enm->em_name, val) < 0) return -1; } /* Do the variables. */ for (vd = cod->cod_variables, i = 0; i < cod->cod_nrvariables; ++i, ++vd) { PyObject *descr; if (vd->vd_type == PropertyVariable) descr = create_property(vd); else descr = sipVariableDescr_New(vd, td, cod); if (dict_set_and_discard(dict, vd->vd_name, descr) < 0) return -1; } return 0; } /* * Create a Python property object from the SIP generated structure. */ static PyObject *create_property(sipVariableDef *vd) { PyObject *descr, *fget, *fset, *fdel, *doc; descr = fget = fset = fdel = doc = NULL; if ((fget = create_function(vd->vd_getter)) == NULL) goto done; if ((fset = create_function(vd->vd_setter)) == NULL) goto done; if ((fdel = create_function(vd->vd_deleter)) == NULL) goto done; if (vd->vd_docstring == NULL) { doc = Py_None; Py_INCREF(doc); } else if ((doc = PyUnicode_FromString(vd->vd_docstring)) == NULL) { goto done; } descr = PyObject_CallFunctionObjArgs((PyObject *)&PyProperty_Type, fget, fset, fdel, doc, NULL); done: Py_XDECREF(fget); Py_XDECREF(fset); Py_XDECREF(fdel); Py_XDECREF(doc); return descr; } /* * Return a PyCFunction as an object or Py_None if there isn't one. */ static PyObject *create_function(PyMethodDef *ml) { if (ml != NULL) return PyCFunction_New(ml, NULL); Py_INCREF(Py_None); return Py_None; } /* * 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->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. */ /* TODO: Deprecate this mechanism in favour of an event handler. */ 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->wt_dict_complete = TRUE; PyType_Modified((PyTypeObject *)wt); 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)->wt_td; 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) || sipTypeIsScopedEnum(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))); return PyLong_Check(obj); } /* * Convert a Python object implementing a named enum to an integer value. */ static int sip_api_convert_to_enum(PyObject *obj, const sipTypeDef *td) { return convert_to_enum(obj, td, TRUE); } /* * Convert a Python object implementing a named enum (or, optionally, an int) * to an integer value. */ static int convert_to_enum(PyObject *obj, const sipTypeDef *td, int allow_int) { int val; assert(sipTypeIsEnum(td) || sipTypeIsScopedEnum(td)); if (sipTypeIsScopedEnum(td)) { static PyObject *value = NULL; PyObject *val_obj; if (PyObject_IsInstance(obj, (PyObject *)sipTypeAsPyTypeObject(td)) <= 0) { enum_expected(obj, td); return -1; } if (objectify("value", &value) < 0) return -1; if ((val_obj = PyObject_GetAttr(obj, value)) == NULL) return -1; /* This will never overflow. */ val = long_as_nonoverflow_int(val_obj); Py_DECREF(val_obj); } else { if (PyObject_TypeCheck((PyObject *)Py_TYPE(obj), &sipEnumType_Type)) { if (!PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(td))) { enum_expected(obj, td); return -1; } /* This will never overflow. */ val = long_as_nonoverflow_int(obj); } else if (allow_int && PyLong_Check(obj)) { val = long_as_nonoverflow_int(obj); } else { enum_expected(obj, td); return -1; } } return val; } /* * Raise an exception when failing to convert an enum because of its type. */ static void enum_expected(PyObject *obj, const sipTypeDef *td) { PyErr_Format(PyExc_TypeError, "a member of enum '%s' is expected not '%s'", sipPyNameOfEnum((sipEnumTypeDef *)td), Py_TYPE(obj)->tp_name); } /* Convert to a C/C++ int while checking for overflow. */ static int long_as_nonoverflow_int(PyObject *val_obj) { int old_overflow, val; old_overflow = sip_api_enable_overflow_checking(TRUE); val = sip_api_long_as_int(val_obj); sip_api_enable_overflow_checking(old_overflow); return val; } /* * 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) || sipTypeIsScopedEnum(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; } /* * Register a proxy resolver. */ static int sip_api_register_proxy_resolver(const sipTypeDef *td, sipProxyResolverFunc resolver) { sipProxyResolver *pr = sip_api_malloc(sizeof (sipProxyResolver)); if (pr == NULL) return -1; pr->td = td; pr->resolver = resolver; pr->next = proxyResolvers; proxyResolvers = pr; return 0; } /* * Report a function with invalid argument types. */ 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) { exc = PyUnicode_FromFormat("%U: %U", doc_obj, detail); Py_DECREF(doc_obj); } else { exc = NULL; } } else { exc = PyUnicode_FromFormat("%s%s%s(): %U", scope, sep, method, detail); } Py_DECREF(detail); } else { exc = NULL; } } else { static const char *summary = "arguments did not match any overloaded call:"; Py_ssize_t i; if (doc != NULL) exc = PyUnicode_FromString(summary); else exc = PyUnicode_FromFormat("%s%s%s(): %s", scope, sep, method, summary); 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) { failure = PyUnicode_FromFormat("\n %U: %U", doc_obj, detail); Py_DECREF(doc_obj); } else { Py_XDECREF(exc); exc = NULL; break; } } else { failure = PyUnicode_FromFormat("\n overload %zd: %U", i + 1, detail); } Py_DECREF(detail); PyUnicode_AppendAndDel(&exc, failure); } 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. */ 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, Py_ssize_t line) { const char *eol; Py_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; return PyUnicode_FromStringAndSize(doc, size); } /* * Return a string/unicode object that describes the given failure. */ static PyObject *detail_FromFailure(PyObject *failure_obj) { sipParseFailure *failure; PyObject *detail; failure = (sipParseFailure *)PyCapsule_GetPointer(failure_obj, NULL); switch (failure->reason) { case Unbound: detail = PyUnicode_FromFormat( "first argument of unbound method must have type '%s'", failure->detail_str); break; case TooFew: detail = PyUnicode_FromString("not enough arguments"); break; case TooMany: detail = PyUnicode_FromString("too many arguments"); break; case KeywordNotString: detail = PyUnicode_FromFormat( "%S keyword argument name is not a string", failure->detail_obj); break; case UnknownKeyword: detail = PyUnicode_FromFormat("'%U' is not a valid keyword argument", failure->detail_obj); break; case Duplicate: detail = PyUnicode_FromFormat( "'%U' has already been given as a positional argument", failure->detail_obj); break; case WrongType: if (failure->arg_nr >= 0) detail = bad_type_str(failure->arg_nr, failure->detail_obj); else detail = PyUnicode_FromFormat( "argument '%s' has unexpected type '%s'", failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name); break; case Exception: detail = failure->detail_obj; if (detail) { Py_INCREF(detail); break; } /* Drop through. */ default: detail = PyUnicode_FromString("unknown reason"); } 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. */ 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); return PyErr_WarnEx(PyExc_DeprecationWarning, buf, 1); } /* * 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(Py_ssize_t seqlen, Py_ssize_t slicelen) { PyErr_Format(PyExc_ValueError, "attempt to assign sequence of size %zd to slice of size %zd", 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 result. */ static void sip_api_bad_catcher_result(PyObject *method) { PyObject *mname, *etype, *evalue, *etraceback; /* * Get the current exception object if there is one. Its string * representation will be used as the detail of a new exception. */ PyErr_Fetch(&etype, &evalue, &etraceback); PyErr_NormalizeException(&etype, &evalue, &etraceback); Py_XDECREF(etraceback); /* * 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 (evalue != NULL) { PyErr_Format(etype, "invalid result from %s.%U(), %S", Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname, evalue); Py_DECREF(evalue); } else { PyErr_Format(PyExc_TypeError, "invalid result from %s.%U()", Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname); } Py_XDECREF(etype); } /* * 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. This is * deprecated because it is the equivalent of sip_api_transfer_to(self, NULL). */ 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)) { sipSimpleWrapper *sw = (sipSimpleWrapper *)self; if (owner == NULL) { /* There is no owner. */ if (sipCppHasRef(sw)) { sipResetCppHasRef(sw); } else { Py_INCREF(sw); removeFromParent((sipWrapper *)sw); sipResetPyOwned(sw); } Py_DECREF(sw); } else if (owner == Py_None) { /* * The owner is a C++ instance and not a Python object (ie. there * is no parent) so there is an explicit extra reference to keep * this Python object alive. Note that there is no way to * specify this from a .sip file - it is useful when embedding in * C/C++ applications. */ if (!sipCppHasRef(sw)) { Py_INCREF(sw); removeFromParent((sipWrapper *)sw); sipResetPyOwned(sw); sipSetCppHasRef(sw); } } else if (PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type)) { /* * The owner is a Python object (ie. the C++ instance that the * Python object wraps). */ if (sipCppHasRef(sw)) { sipResetCppHasRef(sw); } else { Py_INCREF(sw); removeFromParent((sipWrapper *)sw); sipResetPyOwned(sw); } addToParent((sipWrapper *)sw, (sipWrapper *)owner); Py_DECREF(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 ((o = PyUnicode_FromString(lc->lc_type)) == NULL) goto deldict; rc = PyDict_SetItem(ldict,typeName,o); Py_DECREF(o); if (rc < 0) goto deldict; if (lc->lc_licensee != NULL) { if ((o = PyUnicode_FromString(lc->lc_licensee)) == NULL) goto deldict; rc = PyDict_SetItem(ldict,licenseeName,o); Py_DECREF(o); if (rc < 0) goto deldict; } if (lc->lc_timestamp != NULL) { if ((o = PyUnicode_FromString(lc->lc_timestamp)) == NULL) goto deldict; rc = PyDict_SetItem(ldict,timestampName,o); Py_DECREF(o); if (rc < 0) goto deldict; } if (lc->lc_signature != NULL) { if ((o = PyUnicode_FromString(lc->lc_signature)) == 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) { PyObject *w = sip_api_convert_from_void_ptr(vi->vi_val); if (dict_set_and_discard(dict, vi->vi_name, w) < 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) { 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': w = PyUnicode_FromStringAndSize(&ci->ci_val, 1); break; default: w = PyBytes_FromStringAndSize(&ci->ci_val, 1); } if (dict_set_and_discard(dict, ci->ci_name, w) < 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) { 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': w = PyUnicode_FromString(si->si_val); break; case 'w': /* The hack for wchar_t. */ #if defined(HAVE_WCHAR_H) w = PyUnicode_FromWideChar((const wchar_t *)si->si_val, 1); break; #else raiseNoWChar(); return -1; #endif case 'W': /* The hack for wchar_t*. */ #if defined(HAVE_WCHAR_H) w = PyUnicode_FromWideChar((const wchar_t *)si->si_val, wcslen((const wchar_t *)si->si_val)); break; #else raiseNoWChar(); return -1; #endif default: w = PyBytes_FromString(si->si_val); } if (dict_set_and_discard(dict, si->si_name, w) < 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) { PyObject *w = PyLong_FromLong(ii->ii_val); if (dict_set_and_discard(dict, ii->ii_name, w) < 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) { PyObject *w = PyLong_FromLong(li->li_val); if (dict_set_and_discard(dict, li->li_name, w) < 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) { PyObject *w = PyLong_FromUnsignedLong(uli->uli_val); if (dict_set_and_discard(dict, uli->uli_name, w) < 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) { PyObject *w; #if defined(HAVE_LONG_LONG) w = PyLong_FromLongLong(lli->lli_val); #else w = PyLong_FromLong(lli->lli_val); #endif if (dict_set_and_discard(dict, lli->lli_name, w) < 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) { PyObject *w; #if defined(HAVE_LONG_LONG) w = PyLong_FromUnsignedLongLong(ulli->ulli_val); #else w = PyLong_FromUnsignedLong(ulli->ulli_val); #endif if (dict_set_and_discard(dict, ulli->ulli_name, w) < 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) { PyObject *w = PyFloat_FromDouble(di->di_val); if (dict_set_and_discard(dict, di->di_name, w) < 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) { PyObject *obj; if (sipTypeIsEnum(td) || sipTypeIsScopedEnum(td)) { obj = sip_api_convert_from_enum(*(int *)cppPtr, td); } else { sipConvertFromFunc cfrom; cppPtr = resolve_proxy(td, cppPtr); cfrom = get_from_convertor(td); if (cfrom != NULL) obj = cfrom(cppPtr, NULL); else obj = wrap_simple_instance(cppPtr, td, NULL, initflags); } return dict_set_and_discard(dict, name, obj); } /* * 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 GIL is acquired. This is deprecated, use * sip_api_is_python_method_12_8() instead. */ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper *sipSelf, const char *cname, const char *mname) { return sip_api_is_py_method_12_8(gil, pymc, &sipSelf, cname, mname); } /* * Return a Python reimplementation corresponding to a C/C++ virtual function, * if any. If one was found then the GIL is acquired. */ static PyObject *sip_api_is_py_method_12_8(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper **sipSelfp, const char *cname, const char *mname) { sipSimpleWrapper *sipSelf; PyObject *mname_obj, *reimp, *mro, *cls; Py_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; #ifdef WITH_THREAD *gil = PyGILState_Ensure(); #endif /* Only read this when we have the GIL. */ sipSelf = *sipSelfp; /* * 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) sipSelf = deref_mixin(sipSelf); if (sipSelf == NULL) goto release_gil; /* * It's possible that the object's type's tp_mro is NULL. A possible * circumstance is when a type has been created dynamically and the only * reference to it is the single instance of the type which is in the * process of being garbage collected. */ cls = (PyObject *)Py_TYPE(sipSelf); mro = ((PyTypeObject *)cls)->tp_mro; if (mro == NULL) goto release_gil; /* Get any reimplementation. */ if ((mname_obj = PyUnicode_FromString(mname)) == NULL) goto release_gil; /* * 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). However that means we must explicitly check that the class * hierarchy is fully initialised. */ if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(sipSelf))->wt_td) < 0) { Py_DECREF(mname_obj); goto release_gil; } 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; } } assert(PyTuple_Check(mro)); reimp = NULL; for (i = 0; i < PyTuple_GET_SIZE(mro); ++i) { PyObject *cls_dict, *cls_attr; cls = PyTuple_GET_ITEM(mro, i); cls_dict = ((PyTypeObject *)cls)->tp_dict; /* * Check any possible reimplementation is not the wrapped C++ method or * a default special method implementation. */ if (cls_dict != NULL && (cls_attr = PyDict_GetItem(cls_dict, mname_obj)) != NULL && Py_TYPE(cls_attr) != &sipMethodDescr_Type && Py_TYPE(cls_attr) != &PyWrapperDescr_Type) { reimp = cls_attr; break; } } Py_DECREF(mname_obj); if (reimp != NULL) { /* * Emulate the behaviour of a descriptor to make sure we return a bound * 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 reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp), (PyObject *)sipSelf); } else if (PyFunction_Check(reimp)) { reimp = PyMethod_New(reimp, (PyObject *)sipSelf); } else if (Py_TYPE(reimp)->tp_descr_get) { /* It is a descriptor, so assume it will do the right thing. */ reimp = Py_TYPE(reimp)->tp_descr_get(reimp, (PyObject *)sipSelf, cls); } else { /* * We don't know what it is so just return and assume that an * appropriate exception will be raised later on. */ Py_INCREF(reimp); } } else { /* 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; release_gil: #ifdef WITH_THREAD PyGILState_Release(*gil); #endif return NULL; } /* * 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); } /* * The default access function. */ void *sip_api_get_address(sipSimpleWrapper *w) { return (w->access_func != NULL) ? w->access_func(w, GuardedPointer) : w->data; } /* * The access function for handwritten access functions. */ static void *explicit_access_func(sipSimpleWrapper *sw, AccessFuncOp op) { typedef void *(*explicitAccessFunc)(void); if (op == ReleaseGuard) return NULL; return ((explicitAccessFunc)(sw->data))(); } /* * The access function for indirect access. */ static void *indirect_access_func(sipSimpleWrapper *sw, AccessFuncOp op) { void *addr; switch (op) { case UnguardedPointer: addr = sw->data; break; case GuardedPointer: addr = *((void **)sw->data); break; default: addr = NULL; } return addr; } /* * Get the C/C++ pointer for a complex object. Note that not casting the C++ * pointer is a bug. However this would only ever be 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 = sip_api_get_address(sw); if (checkPointer(ptr, sw) < 0) return NULL; if (td != NULL) { if (PyObject_TypeCheck((PyObject *)sw, sipTypeAsPyTypeObject(td))) ptr = cast_cpp_ptr(ptr, Py_TYPE(sw), td); else ptr = NULL; 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)->wt_td)->ctd_cast; /* C structures and base classes 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, sipSimpleWrapper *sw) { if (ptr == NULL) { PyErr_Format(PyExc_RuntimeError, (sipWasCreated(sw) ? "wrapped C/C++ object of type %s has been deleted" : "super-class __init__() of type %s was never called"), Py_TYPE(sw)->tp_name); 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. */ 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 ((key_obj = PyLong_FromLong(key)) != 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); } } /* * Get an object that has an extra reference. */ static PyObject *sip_api_get_reference(PyObject *self, int key) { PyObject *dict, *key_obj, *obj; /* Get the extra references dictionary if there is one. */ if ((dict = ((sipSimpleWrapper *)self)->extra_refs) == NULL) return NULL; if ((key_obj = PyLong_FromLong(key)) == NULL) return NULL; obj = PyDict_GetItem(dict, key_obj); Py_DECREF(key_obj); Py_XINCREF(obj); return obj; } /* * Return TRUE if an object is owned by Python. Note that this isn't * implemented as a macro in sip.h because the position of the sw_flags field * is dependent on the version of Python. */ static int sip_api_is_owned_by_python(sipSimpleWrapper *sw) { return sipIsPyOwned(sw); } /* * Return TRUE if the type of a C++ instance is a derived class. Note that * this isn't implemented as a macro in sip.h because the position of the * sw_flags field is dependent on the version of Python. */ static int sip_api_is_derived_class(sipSimpleWrapper *sw) { return sipIsDerived(sw); } /* * Get the user defined object from a wrapped object. Note that this isn't * implemented as a macro in sip.h because the position of the user field is * dependent on the version of Python. */ static PyObject *sip_api_get_user_object(const sipSimpleWrapper *sw) { return sw->user; } /* * Set the user defined object in a wrapped object. Note that this isn't * implemented as a macro in sip.h because the position of the user field is * dependent on the version of Python. */ static void sip_api_set_user_object(sipSimpleWrapper *sw, PyObject *user) { sw->user = user; } /* * 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(td == NULL || sipTypeIsClass(td) || sipTypeIsMapped(td)); if (td == NULL) { /* * The type must be /External/ and the module that contains the * implementation hasn't been imported. */ ok = FALSE; } else 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. */ 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; sipConvertFromFunc cfrom; assert(sipTypeIsClass(td) || sipTypeIsMapped(td)); /* Handle None. */ if (cpp == NULL) { Py_INCREF(Py_None); return Py_None; } cpp = resolve_proxy(td, cpp); cfrom = get_from_convertor(td); if (cfrom != NULL) return cfrom(cpp, transferObj); /* * See if we have already wrapped it. Invoking sub-class code can be * expensive so we check the cache first, even though the sub-class code * might perform a down-cast. */ if ((py = sip_api_get_pyobject(cpp, td)) == NULL && sipTypeHasSCC(td)) { void *orig_cpp = cpp; const sipTypeDef *orig_td = td; /* Apply the sub-class convertor. */ td = convertSubClass(td, &cpp); /* * If the sub-class convertor has done something then check the cache * again using the modified values. */ if (cpp != orig_cpp || td != orig_td) py = sip_api_get_pyobject(cpp, td); } if (py != NULL) Py_INCREF(py); else if ((py = wrap_simple_instance(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; sipConvertFromFunc cfrom; /* Handle None. */ if (cpp == NULL) { Py_INCREF(Py_None); return Py_None; } cpp = resolve_proxy(td, cpp); cfrom = get_from_convertor(td); if (cfrom != NULL) { PyObject *res = 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 we are wrapping a * class. */ if (transferObj == NULL || transferObj == Py_None) release(cpp, td, 0); } return res; } /* 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 wrap_simple_instance(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 void *tdp = &module_searched->em_types[etd->et_nr]; if (tdp == 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 unscoped 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); } /* * 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 builtins module. */ if ((mod = PyDict_GetItemString(dictofmods, "builtins")) == 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_Call(hook, empty_tuple, 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) { /* Handle the trivial case. */ if (*cppPtr == NULL) return NULL; /* Try the conversions until told to stop. */ while (convertPass(&td, cppPtr)) ; return td; } /* * Do a single pass through the available convertors. */ static int convertPass(const sipTypeDef **tdp, void **cppPtr) { PyTypeObject *py_type = sipTypeAsPyTypeObject(*tdp); sipExportedModuleDef *em; /* * 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) { PyTypeObject *base_type = sipTypeAsPyTypeObject(scc->scc_basetype); /* * 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, base_type)) { void *ptr; const sipTypeDef *sub_td; ptr = cast_cpp_ptr(*cppPtr, py_type, scc->scc_basetype); if ((sub_td = (*scc->scc_convertor)(&ptr)) != NULL) { PyTypeObject *sub_type = sipTypeAsPyTypeObject(sub_td); /* * 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 (!PyType_IsSubtype(py_type, sub_type)) { *tdp = sub_td; *cppPtr = ptr; /* * Finally we allow the convertor to return a type that * is apparently unrelated to the current convertor. * This causes the whole process to be restarted with * the new values. The use case is PyQt's QLayoutItem. */ return !PyType_IsSubtype(sub_type, base_type); } } } ++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 FALSE; } /* * 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 = wrap_simple_instance(ptr, td, NULL, SIP_PY_OWNED); PyErr_SetObject((PyObject *)sipTypeAsPyTypeObject(td), self); Py_XDECREF(self); SIP_UNBLOCK_THREADS } /* * Return the generated type structure of an encoded type. */ static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc, sipExportedModuleDef *em) { if (enc->sc_module == 255) return em->em_types[enc->sc_type]; return em->em_imports[enc->sc_module].im_imported_types[enc->sc_type].it_td; } /* * Return the generated class type structure of a class's super-class. */ sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc, const sipClassTypeDef *ctd) { return (sipClassTypeDef *)getGeneratedType(enc, ctd->ctd_base.td_module); } /* * 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)) { const sipClassTypeDef *ctd; ctd = (sipClassTypeDef *)((sipWrapperType *)(py_type))->wt_td; slot = findSlotInClass(ctd, st); } 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 = findSlotInSlotList(etd->etd_pyslots, st); } return slot; } /* * Find a particular slot function in a class hierarchy. */ static void *findSlotInClass(const sipClassTypeDef *ctd, sipPySlotType st) { void *slot; if (ctd->ctd_pyslots != NULL) slot = findSlotInSlotList(ctd->ctd_pyslots, st); else slot = NULL; if (slot == NULL) { sipEncodedTypeDef *sup; /* Search any super-types. */ if ((sup = ctd->ctd_supers) != NULL) { do { const sipClassTypeDef *sup_ctd = sipGetGeneratedClassType( sup, ctd); slot = findSlotInClass(sup_ctd, st); } while (slot == NULL && !sup++->sc_flag); } } return slot; } /* * Find a particular slot function in a particular type. */ static void *findSlotInSlotList(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))->wt_td; return (sipNotInMap(self) ? NULL : sip_api_get_address(self)); } /* * 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 ((args = PyTuple_Pack(2, arg1, arg2)) == 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, Py_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) args = PyLong_FromSsize_t(arg1); else args = Py_BuildValue("(nO)", arg1, arg2); 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, Py_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) { assert(!sipTypeIsEnum(currentType)); ((sipWrapperType *)o)->wt_td = currentType; if (sipTypeIsClass(currentType)) { const sipClassTypeDef *ctd = (const sipClassTypeDef *)currentType; const char *docstring = ctd->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, ctd); /* Patch any mixin initialiser. */ if (ctd->ctd_init_mixin != NULL) ((PyTypeObject *)o)->tp_init = ctd->ctd_init_mixin; } } 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->wt_td == NULL) { PyTypeObject *base = ((PyTypeObject *)self)->tp_base; self->wt_user_type = TRUE; /* * 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)) { /* TODO: Deprecate this mechanism in favour of an event handler. */ sipNewUserTypeFunc new_user_type_handler; self->wt_td = ((sipWrapperType *)base)->wt_td; if (self->wt_td != NULL) { /* Call any new type handler. */ new_user_type_handler = find_new_user_type_handler( (sipWrapperType *)sipTypeAsPyTypeObject(self->wt_td)); if (new_user_type_handler != NULL) if (new_user_type_handler(self) < 0) return -1; } } } else { /* * We must be a generated type so remember the type object in the * generated type structure. */ assert(self->wt_td->td_py_type == NULL); self->wt_td->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)->wt_td) < 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)->wt_td) < 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) { sipTypeDef *td = wt->wt_td; (void)args; (void)kwds; /* 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 (add_all_lazy_attrs(td) < 0) 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(get_container(td), 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(get_container(td), td)); return NULL; } /* * See if the object is being created explicitly rather than being wrapped. */ if (!sipIsPending()) { /* * 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(get_container(td), td)); return NULL; } /* See if it is an abstract type. */ if (sipTypeIsAbstract(td) && !wt->wt_user_type && ((sipClassTypeDef *)td)->ctd_init_mixin == NULL) { PyErr_Format(PyExc_TypeError, "%s.%s represents a C++ abstract class and cannot be instantiated", sipNameOfModule(td->td_module), sipPyNameOfContainer(get_container(td), td)); return NULL; } } /* Call the standard super-type new. */ return PyBaseObject_Type.tp_new((PyTypeObject *)wt, empty_tuple, NULL); } /* * The instance init slot. */ static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args, PyObject *kwds) { void *sipNew; int sipFlags, from_cpp = TRUE; sipWrapper *owner; sipWrapperType *wt = (sipWrapperType *)Py_TYPE(self); sipTypeDef *td = wt->wt_td; sipClassTypeDef *ctd = (sipClassTypeDef *)td; PyObject *unused = NULL; sipFinalFunc final_func = find_finalisation(ctd); /* Check for an existing C++ instance waiting to be wrapped. */ if (sipGetPending(&sipNew, &owner, &sipFlags) < 0) return -1; if (sipNew == NULL) { PyObject *parseErr = NULL, **unused_p = NULL; /* See if we are interested in any unused keyword arguments. */ if (sipTypeCallSuperInit(&ctd->ctd_base) || final_func != NULL || kw_handler != NULL) unused_p = &unused; /* 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->wt_iextend; /* * 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, (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; } /* The instance was created from Python. */ from_cpp = FALSE; } /* Handler any owner if the type supports the concept. */ if (PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type)) { /* * The application may be doing something very unadvisable (like * calling __init__() for a second time), so make sure we don't already * have a parent. */ removeFromParent((sipWrapper *)self); if (owner != NULL) { assert(PyObject_TypeCheck((PyObject *)owner, (PyTypeObject *)&sipWrapper_Type)); addToParent((sipWrapper *)self, (sipWrapper *)owner); } } self->data = sipNew; self->sw_flags = sipFlags | SIP_CREATED; /* Set the access function. */ if (sipIsAccessFunc(self)) self->access_func = explicit_access_func; else if (sipIsIndirect(self)) self->access_func = indirect_access_func; else self->access_func = NULL; if (!sipNotInMap(self)) sipOMAddObject(&cppPyMap, self); /* If we are wrapping an instance returned from C/C++ then we are done. */ if (from_cpp) { /* * Invoke any event handlers for instances that are accessed directly. */ if (self->access_func == NULL) { sipEventHandler *eh; for (eh = event_handlers[sipEventWrappedInstance]; eh != NULL; eh = eh->next) { if (is_subtype(ctd, eh->ctd)) { sipWrappedInstanceEventHandler handler = (sipWrappedInstanceEventHandler)eh->handler; handler(sipNew); } } } return 0; } /* Call any finalisation code. */ if (final_func != NULL) { PyObject *new_unused = NULL, **new_unused_p; if (unused == NULL || unused != kwds) { /* * There are no unused arguments or we have already created a dict * containing the unused sub-set, so there is no need to create * another. */ new_unused_p = NULL; } else { /* * All of the keyword arguments are unused, so if some of them are * now going to be used then a new dict will be needed. */ new_unused_p = &new_unused; } if (final_func((PyObject *)self, sipNew, unused, new_unused_p) < 0) { Py_XDECREF(unused); return -1; } if (new_unused != NULL) { Py_DECREF(unused); unused = new_unused; } } /* Call the handler if we have one. */ if (kw_handler != NULL && unused != NULL && isQObject((PyObject *)self)) { int rc = kw_handler((PyObject *)self, sipNew, unused); /* * A handler will always consume all unused keyword arguments (or raise * an exception) so discard the dict now. */ Py_DECREF(unused); if (rc < 0) return -1; unused = NULL; } /* See if we should call the equivalent of super().__init__(). */ if (sipTypeCallSuperInit(&ctd->ctd_base)) { PyObject *next; /* Find the next type in the MRO. */ next = next_in_mro((PyObject *)self, (PyObject *)&sipSimpleWrapper_Type); /* * If the next type in the MRO is object then take a shortcut by not * calling super().__init__() but emulating object.__init__() instead. * This will be the most common case and also allows us to generate a * better exception message if there are unused keyword arguments. The * disadvantage is that the exception message will be different if * there is a mixin. */ if (next != (PyObject *)&PyBaseObject_Type) { int rc = super_init((PyObject *)self, empty_tuple, unused, next); Py_XDECREF(unused); return rc; } } if (unused_backdoor != NULL) { /* * We are being called by a mixin's __init__ so save any unused * arguments for it to pass on to the main class's __init__. */ *unused_backdoor = unused; } else if (unused != NULL) { /* We shouldn't have any unused keyword arguments. */ if (PyDict_Size(unused) != 0) { PyObject *key, *value; Py_ssize_t pos = 0; /* Just report one of the unused arguments. */ PyDict_Next(unused, &pos, &key, &value); PyErr_Format(PyExc_TypeError, "'%S' is an unknown keyword argument", key); Py_DECREF(unused); return -1; } Py_DECREF(unused); } return 0; } /* * Get the C++ address of a mixin. */ static void *sip_api_get_mixin_address(sipSimpleWrapper *w, const sipTypeDef *td) { PyObject *mixin; void *cpp; if ((mixin = PyObject_GetAttrString((PyObject *)w, sipTypeName(td))) == NULL) { PyErr_Clear(); return NULL; } cpp = sip_api_get_address((sipSimpleWrapper *)mixin); Py_DECREF(mixin); return cpp; } /* * Initialise a mixin. */ static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds, const sipClassTypeDef *ctd) { int rc; Py_ssize_t pos; PyObject *unused, *mixin, *mixin_name, *key, *value; PyTypeObject *self_wt = sipTypeAsPyTypeObject(((sipWrapperType *)Py_TYPE(self))->wt_td); PyTypeObject *wt = sipTypeAsPyTypeObject(&ctd->ctd_base); static PyObject *double_us = NULL; if (objectify("__", &double_us) < 0) return -1; /* If we are not a mixin to another wrapped class then behave as normal. */ if (PyType_IsSubtype(self_wt, wt)) return super_init(self, args, kwds, next_in_mro(self, (PyObject *)wt)); /* * Create the mixin instance. Retain the positional arguments for the * super-class. Remember that, even though the mixin appears after the * main class in the MRO, it appears before sipWrapperType where the main * class's arguments are actually parsed. */ unused = NULL; unused_backdoor = &unused; mixin = PyObject_Call((PyObject *)wt, empty_tuple, kwds); unused_backdoor = NULL; if (mixin == NULL) goto gc_unused; /* Make sure the mixin can find the main instance. */ ((sipSimpleWrapper *)mixin)->mixin_main = self; Py_INCREF(self); if ((mixin_name = PyUnicode_FromString(sipTypeName(&ctd->ctd_base))) == NULL) { Py_DECREF(mixin); goto gc_unused; } rc = PyObject_SetAttr(self, mixin_name, mixin); Py_DECREF(mixin); if (rc < 0) goto gc_mixin_name; /* Add the mixin's useful attributes to the main class. */ pos = 0; while (PyDict_Next(wt->tp_dict, &pos, &key, &value)) { /* Don't replace existing values. */ if (PyDict_Contains(Py_TYPE(self)->tp_dict, key) != 0) continue; /* Skip values with names that start with double underscore. */ if (!PyUnicode_Check(key)) continue; /* * Despite what the docs say this returns a Py_ssize_t - although the * docs are probably right. */ rc = (int)PyUnicode_Tailmatch(key, double_us, 0, 2, -1); if (rc < 0) goto gc_mixin_name; if (rc > 0) continue; if (PyObject_IsInstance(value, (PyObject *)&sipMethodDescr_Type)) { if ((value = sipMethodDescr_Copy(value, mixin_name)) == NULL) goto gc_mixin_name; } else if (PyObject_IsInstance(value, (PyObject *)&sipVariableDescr_Type)) { if ((value = sipVariableDescr_Copy(value, mixin_name)) == NULL) goto gc_mixin_name; } else { Py_INCREF(value); } rc = PyDict_SetItem(Py_TYPE(self)->tp_dict, key, value); Py_DECREF(value); if (rc < 0) goto gc_mixin_name; } Py_DECREF(mixin_name); /* Call the super-class's __init__ with any remaining arguments. */ rc = super_init(self, args, unused, next_in_mro(self, (PyObject *)wt)); Py_XDECREF(unused); return rc; gc_mixin_name: Py_DECREF(mixin_name); gc_unused: Py_XDECREF(unused); return -1; } /* * Return the next in the MRO of an instance after a given type. */ static PyObject *next_in_mro(PyObject *self, PyObject *after) { Py_ssize_t i; PyObject *mro; mro = Py_TYPE(self)->tp_mro; assert(PyTuple_Check(mro)); for (i = 0; i < PyTuple_GET_SIZE(mro); ++i) if (PyTuple_GET_ITEM(mro, i) == after) break; /* Assert that we have found ourself and that we are not the last. */ assert(i + 1 < PyTuple_GET_SIZE(mro)); return PyTuple_GET_ITEM(mro, i + 1); } /* * Call the equivalent of super()__init__() of an instance. */ static int super_init(PyObject *self, PyObject *args, PyObject *kwds, PyObject *type) { int i; PyObject *init, *init_args, *init_res; if ((init = PyObject_GetAttr(type, init_name)) == NULL) return -1; if ((init_args = PyTuple_New(1 + PyTuple_GET_SIZE(args))) == NULL) { Py_DECREF(init); return -1; } PyTuple_SET_ITEM(init_args, 0, self); Py_INCREF(self); for (i = 0; i < PyTuple_GET_SIZE(args); ++i) { PyObject *arg = PyTuple_GET_ITEM(args, i); PyTuple_SET_ITEM(init_args, 1 + i, arg); Py_INCREF(arg); } init_res = PyObject_Call(init, init_args, kwds); Py_DECREF(init_args); Py_DECREF(init); Py_XDECREF(init_res); return (init_res != NULL) ? 0 : -1; } /* * Find any finalisation function for a class, searching its super-classes if * necessary. */ static sipFinalFunc find_finalisation(sipClassTypeDef *ctd) { sipEncodedTypeDef *sup; if (ctd->ctd_final != NULL) return ctd->ctd_final; if ((sup = ctd->ctd_supers) != NULL) do { sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd); sipFinalFunc func; if ((func = find_finalisation(sup_ctd)) != NULL) return func; } while (!sup++->sc_flag); return NULL; } /* * Find any new user type handler function for a class, searching its * super-classes if necessary. */ static sipNewUserTypeFunc find_new_user_type_handler(sipWrapperType *wt) { sipEncodedTypeDef *sup; sipClassTypeDef *ctd; if (wt->wt_new_user_type_handler != NULL) return wt->wt_new_user_type_handler; ctd = (sipClassTypeDef *)wt->wt_td; if ((sup = ctd->ctd_supers) != NULL) { do { sipTypeDef *sup_td = getGeneratedType(sup, ctd->ctd_base.td_module); sipNewUserTypeFunc func; wt = (sipWrapperType *)sipTypeAsPyTypeObject(sup_td); if ((func = find_new_user_type_handler(wt)) != NULL) return func; } while (!sup++->sc_flag); } return NULL; } /* * The instance traverse slot. */ static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit, void *arg) { int vret; void *ptr; const sipClassTypeDef *ctd; /* Call any handwritten traverse code. */ if ((ptr = getPtrTypeDef(self, &ctd)) != NULL) if (ctd->ctd_traverse != NULL) if ((vret = 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; if (self->mixin_main != NULL) if ((vret = visit(self->mixin_main, 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 any handwritten clear code. */ if ((ptr = getPtrTypeDef(self, &ctd)) != NULL) if (ctd->ctd_clear != NULL) vret = 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); /* Remove any mixin main. */ tmp = self->mixin_main; self->mixin_main = NULL; Py_XDECREF(tmp); return vret; } /* * The instance get buffer slot. */ static int sipSimpleWrapper_getbuffer(sipSimpleWrapper *self, Py_buffer *buf, int flags) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return -1; if (sipTypeUseLimitedAPI(&ctd->ctd_base)) { sipGetBufferFuncLimited getbuffer = (sipGetBufferFuncLimited)ctd->ctd_getbuffer; sipBufferDef bd; /* * Ensure all fields have a default value. This means that extra * fields can be appended in the future that older handwritten code * doesn't know about. */ memset(&bd, 0, sizeof(sipBufferDef)); if (getbuffer((PyObject *)self, ptr, &bd) < 0) return -1; return PyBuffer_FillInfo(buf, (PyObject *)self, bd.bd_buffer, bd.bd_length, bd.bd_readonly, flags); } return ctd->ctd_getbuffer((PyObject *)self, ptr, buf, flags); } /* * The instance release buffer slot. */ static void sipSimpleWrapper_releasebuffer(sipSimpleWrapper *self, Py_buffer *buf) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return; if (sipTypeUseLimitedAPI(&ctd->ctd_base)) { sipReleaseBufferFuncLimited releasebuffer = (sipReleaseBufferFuncLimited)ctd->ctd_releasebuffer; releasebuffer((PyObject *)self, ptr); return; } ctd->ctd_releasebuffer((PyObject *)self, ptr, buf); } /* * The instance dealloc slot. */ static void sipSimpleWrapper_dealloc(sipSimpleWrapper *self) { PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); 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); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); } /* * The type call slot. */ static PyObject *slot_call(PyObject *self, PyObject *args, PyObject *kw) { PyObject *(*f)(PyObject *, PyObject *, PyObject *); f = (PyObject *(*)(PyObject *, PyObject *, PyObject *))findSlot(self, call_slot); assert(f != NULL); return f(self, args, kw); } /* * The sequence type item slot. */ static PyObject *slot_sq_item(PyObject *self, Py_ssize_t n) { PyObject *(*f)(PyObject *,PyObject *); PyObject *arg, *res; if ((arg = PyLong_FromSsize_t(n)) == 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, Py_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; default: /* Suppress a compiler warning. */ st = -1; } /* 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 __dict__ getter. */ static PyObject *sipSimpleWrapper_get_dict(sipSimpleWrapper *sw, void *closure) { (void)closure; /* 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(sipSimpleWrapper *sw, PyObject *value, void *closure) { (void)closure; /* 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__", (getter)sipSimpleWrapper_get_dict, (setter)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_as_async (Python v3.5), 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)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 */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }, { 0, /* am_await */ 0, /* am_aiter */ 0, /* am_anext */ }, { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ 0, /* nb_bool */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ 0, /* nb_and */ 0, /* nb_xor */ 0, /* nb_or */ 0, /* nb_int */ 0, /* nb_reserved */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ 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 */ 0, /* nb_index */ 0, /* nb_matrix_multiply */ 0, /* nb_inplace_matrix_multiply */ }, { 0, /* mp_length */ 0, /* mp_subscript */ 0, /* mp_ass_subscript */ }, { 0, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* was_sq_slice */ 0, /* sq_ass_item */ 0, /* was_sq_ass_slice */ 0, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }, { 0, /* bf_getbuffer */ 0, /* bf_releasebuffer */ }, 0, /* ht_name */ 0, /* ht_slots */ 0, /* ht_qualname */ 0, /* ht_cached_keys */ #if PY_VERSION_HEX >= 0x03090000 0, /* ht_module */ #endif #if !defined(STACKLESS) }, #endif 0, /* wt_user_type */ 0, /* wt_dict_complete */ 0, /* wt_unused */ 0, /* wt_td */ 0, /* wt_iextend */ 0, /* wt_new_user_type_handler */ 0, /* wt_user_data */ }; /* * 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) && !sipNotInMap(sw)) { void *tx = sip_api_get_address(sw); if (tx != NULL) { sipSlot *slot; void *context = NULL; assert (sipQtSupport->qt_find_sipslot); while ((slot = sipQtSupport->qt_find_sipslot(tx, &context)) != NULL) { sip_api_clear_any_slot_reference(slot); if (context == NULL) break; } } } /* Detach any children (which will be owned by C/C++). */ detachChildren(self); return vret; } /* * The wrapper dealloc slot. */ static void sipWrapper_dealloc(sipWrapper *self) { PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); /* * 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); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); } /* * 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. The map check is a bit of a * hack to work around PyQt4 problems with qApp and a user created * instance. qt_find_sipslot() will return the same slot information for * both causing the gc module to trigger assert() failures. */ if (sipQtSupport != NULL && sipQtSupport->qt_find_sipslot && !sipNotInMap(sw)) { void *tx = sip_api_get_address(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, const sipClassTypeDef *ctd) { PyHeapTypeObject *heap_to = &wt->super; PyBufferProcs *bp = &heap_to->as_buffer; /* Add the buffer interface. */ if (ctd->ctd_getbuffer != NULL) bp->bf_getbuffer = (getbufferproc)sipSimpleWrapper_getbuffer; if (ctd->ctd_releasebuffer != NULL) bp->bf_releasebuffer = (releasebufferproc)sipSimpleWrapper_releasebuffer; /* Add the slots for this type. */ if (ctd->ctd_pyslots != NULL) addTypeSlots(heap_to, 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; PyAsyncMethods *am; void *f; to = &heap_to->ht_type; nb = &heap_to->as_number; sq = &heap_to->as_sequence; mp = &heap_to->as_mapping; am = &heap_to->as_async; while ((f = slots->psd_func) != NULL) switch (slots++->psd_type) { case str_slot: to->tp_str = (reprfunc)f; break; case int_slot: nb->nb_int = (unaryfunc)f; break; case float_slot: nb->nb_float = (unaryfunc)f; break; case len_slot: mp->mp_length = (lenfunc)f; sq->sq_length = (lenfunc)f; break; case contains_slot: sq->sq_contains = (objobjproc)f; break; case add_slot: nb->nb_add = (binaryfunc)f; break; case concat_slot: sq->sq_concat = (binaryfunc)f; break; case sub_slot: nb->nb_subtract = (binaryfunc)f; break; case mul_slot: nb->nb_multiply = (binaryfunc)f; break; case repeat_slot: sq->sq_repeat = (ssizeargfunc)f; break; case div_slot: nb->nb_true_divide = (binaryfunc)f; break; case mod_slot: nb->nb_remainder = (binaryfunc)f; break; case floordiv_slot: nb->nb_floor_divide = (binaryfunc)f; break; case truediv_slot: nb->nb_true_divide = (binaryfunc)f; break; case and_slot: nb->nb_and = (binaryfunc)f; break; case or_slot: nb->nb_or = (binaryfunc)f; break; case xor_slot: nb->nb_xor = (binaryfunc)f; break; case lshift_slot: nb->nb_lshift = (binaryfunc)f; break; case rshift_slot: nb->nb_rshift = (binaryfunc)f; break; case iadd_slot: nb->nb_inplace_add = (binaryfunc)f; break; case iconcat_slot: sq->sq_inplace_concat = (binaryfunc)f; break; case isub_slot: nb->nb_inplace_subtract = (binaryfunc)f; break; case imul_slot: nb->nb_inplace_multiply = (binaryfunc)f; break; case irepeat_slot: sq->sq_inplace_repeat = (ssizeargfunc)f; break; case idiv_slot: nb->nb_inplace_true_divide = (binaryfunc)f; break; case imod_slot: nb->nb_inplace_remainder = (binaryfunc)f; break; case ifloordiv_slot: nb->nb_inplace_floor_divide = (binaryfunc)f; break; case itruediv_slot: nb->nb_inplace_true_divide = (binaryfunc)f; break; case iand_slot: nb->nb_inplace_and = (binaryfunc)f; break; case ior_slot: nb->nb_inplace_or = (binaryfunc)f; break; case ixor_slot: nb->nb_inplace_xor = (binaryfunc)f; break; case ilshift_slot: nb->nb_inplace_lshift = (binaryfunc)f; break; case irshift_slot: nb->nb_inplace_rshift = (binaryfunc)f; break; case invert_slot: nb->nb_invert = (unaryfunc)f; break; case call_slot: to->tp_call = slot_call; break; case getitem_slot: mp->mp_subscript = (binaryfunc)f; sq->sq_item = slot_sq_item; break; case setitem_slot: case delitem_slot: mp->mp_ass_subscript = slot_mp_ass_subscript; 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; case bool_slot: nb->nb_bool = (inquiry)f; break; case neg_slot: 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: nb->nb_positive = (unaryfunc)f; break; case abs_slot: nb->nb_absolute = (unaryfunc)f; break; case index_slot: nb->nb_index = (unaryfunc)f; break; case iter_slot: to->tp_iter = (getiterfunc)f; break; case next_slot: to->tp_iternext = (iternextfunc)f; break; case setattr_slot: to->tp_setattro = (setattrofunc)f; break; case matmul_slot: nb->nb_matrix_multiply = (binaryfunc)f; break; case imatmul_slot: nb->nb_inplace_matrix_multiply = (binaryfunc)f; break; case await_slot: am->am_await = (unaryfunc)f; break; case aiter_slot: am->am_aiter = (unaryfunc)f; break; case anext_slot: am->am_anext = (unaryfunc)f; break; /* Suppress a compiler warning. */ default: ; } } /* * Remove the object from the map and call the C/C++ dtor if we own the * instance. */ static void forgetObject(sipSimpleWrapper *sw) { sipEventHandler *eh; const sipClassTypeDef *ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(sw))->wt_td; /* Invoke any event handlers. */ for (eh = event_handlers[sipEventCollectingWrapper]; eh != NULL; eh = eh->next) { if (is_subtype(ctd, eh->ctd)) { sipCollectingWrapperEventHandler handler = (sipCollectingWrapperEventHandler)eh->handler; handler(sw); } } /* * This is needed because we might 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); /* * 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); if (sipInterpreter != NULL || destroy_on_exit) { const sipClassTypeDef *ctd; if (getPtrTypeDef(sw, &ctd) != NULL && ctd->ctd_dealloc != NULL) ctd->ctd_dealloc(sw); } clear_access_func(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 * would only be 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 would only * be 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, "bytes of length 1 expected not '%s'", 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, "bytes expected not '%s'", 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) ch = '\0'; return ch; } /* * Parse an ASCII character and return it. */ static int parseString_AsASCIIChar(PyObject *obj, char *ap) { if (parseString_AsEncodedChar(PyUnicode_AsASCIIString(obj), obj, ap) < 0) { /* Use the exception set if it was an encoding error. */ if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1) PyErr_SetString(PyExc_TypeError, "bytes or ASCII string of length 1 expected"); return -1; } return 0; } /* * 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) ch = '\0'; return ch; } /* * Parse a Latin-1 character and return it via a pointer. */ static int parseString_AsLatin1Char(PyObject *obj, char *ap) { if (parseString_AsEncodedChar(PyUnicode_AsLatin1String(obj), obj, ap) < 0) { /* Use the exception set if it was an encoding error. */ if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1) PyErr_SetString(PyExc_TypeError, "bytes or Latin-1 string of length 1 expected"); return -1; } return 0; } /* * 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) ch = '\0'; return ch; } /* * Parse a UTF-8 character and return it. */ static int parseString_AsUTF8Char(PyObject *obj, char *ap) { if (parseString_AsEncodedChar(PyUnicode_AsUTF8String(obj), obj, ap) < 0) { /* Use the exception set if it was an encoding error. */ if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1) PyErr_SetString(PyExc_TypeError, "bytes or UTF-8 string of length 1 expected"); return -1; } return 0; } /* * Parse an encoded character and return it. */ static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap) { Py_ssize_t size; if (bytes == NULL) { PyErr_Clear(); return parseBytes_AsChar(obj, ap); } size = PyBytes_GET_SIZE(bytes); if (size != 1) { Py_DECREF(bytes); return -1; } if (ap != NULL) *ap = *PyBytes_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, "bytes or ASCII string expected not '%s'", 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, "bytes or Latin-1 string expected not '%s'", 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, "bytes or UTF-8 string expected not '%s'", 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 = PyBytes_AS_STRING(bytes); return bytes; } /* Don't try anything else if there was an encoding error. */ if (PyUnicode_Check(obj)) return NULL; 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, Py_ssize_t *aszp) { const char *a; Py_ssize_t asz; if (obj == Py_None) { a = NULL; asz = 0; } else if (PyBytes_Check(obj)) { a = PyBytes_AS_STRING(obj); asz = PyBytes_GET_SIZE(obj); } else { Py_buffer view; if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0) return -1; a = view.buf; asz = view.len; PyBuffer_Release(&view); } if (ap != NULL) *ap = a; if (aszp != NULL) *aszp = asz; return 0; } /* * Parse a character and return it. */ static int parseBytes_AsChar(PyObject *obj, char *ap) { const char *chp; Py_ssize_t sz; if (PyBytes_Check(obj)) { chp = PyBytes_AS_STRING(obj); sz = PyBytes_GET_SIZE(obj); } else { Py_buffer view; if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0) return -1; chp = view.buf; sz = view.len; PyBuffer_Release(&view); } if (sz != 1) return -1; if (ap != NULL) *ap = *chp; return 0; } /* * Parse a character string and return it. */ static int parseBytes_AsString(PyObject *obj, const char **ap) { const char *a; Py_ssize_t sz; if (parseBytes_AsCharArray(obj, &a, &sz) < 0) return -1; if (ap != NULL) *ap = a; return 0; } #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, "string 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, "string 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, Py_ssize_t *aszp) { wchar_t *a; Py_ssize_t asz; if (obj == Py_None) { a = NULL; asz = 0; } else if (PyUnicode_Check(obj)) { if (convertToWCharArray(obj, &a, &asz) < 0) return -1; } else { return -1; } if (ap != NULL) *ap = a; if (aszp != NULL) *aszp = asz; return 0; } /* * Convert a Unicode object to a wide character array and return it's address * and length. */ static int convertToWCharArray(PyObject *obj, wchar_t **ap, Py_ssize_t *aszp) { Py_ssize_t ulen; wchar_t *wc; ulen = PyUnicode_GET_LENGTH(obj); if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL) return -1; if ((ulen = PyUnicode_AsWideChar(obj, wc, 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) { wchar_t a; if (PyUnicode_Check(obj)) { if (convertToWChar(obj, &a) < 0) return -1; } else { return -1; } if (ap != NULL) *ap = a; return 0; } /* * Convert a Unicode object to a wide character and return it. */ static int convertToWChar(PyObject *obj, wchar_t *ap) { if (PyUnicode_GET_LENGTH(obj) != 1) return -1; if (PyUnicode_AsWideChar(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) { wchar_t *a; if (obj == Py_None) { a = NULL; } else if (PyUnicode_Check(obj)) { if (convertToWCharString(obj, &a) < 0) return -1; } else { return -1; } if (ap != NULL) *ap = a; return 0; } /* * Convert a Unicode object to a wide character string and return a copy on * the heap. */ static int convertToWCharString(PyObject *obj, wchar_t **ap) { Py_ssize_t ulen; wchar_t *wc; ulen = PyUnicode_GET_LENGTH(obj); if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL) return -1; if ((ulen = PyUnicode_AsWideChar(obj, wc, 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, Py_ssize_t nitems) { sipEnumTypeObject *py_type; sipPySlotDef *psd; if (currentType == NULL) { PyErr_SetString(PyExc_TypeError, "enums cannot be sub-classed"); return NULL; } assert(sipTypeIsEnum(currentType)); /* 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->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); return (PyObject *)py_type; } /* * The enum type getattro slot. */ static PyObject *sipEnumType_getattro(PyObject *self, PyObject *name) { PyObject *res; sipEnumTypeDef *etd; sipExportedModuleDef *client; const sipEnumMemberDef *enm, *emd; int enum_nr, nr_members, m; const char *name_str; /* * Try a generic lookup first. This has the side effect of checking the * type of the name object. */ if ((res = PyObject_GenericGetAttr(self, name)) != NULL) return res; if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL; PyErr_Clear(); /* Get the member name. */ if ((name_str = PyUnicode_AsUTF8(name)) == NULL) return NULL; etd = (sipEnumTypeDef *)((sipEnumTypeObject *)self)->type; client = ((sipTypeDef *)etd)->td_module; /* Find the number of this enum. */ for (enum_nr = 0; enum_nr < client->em_nrtypes; ++enum_nr) if (client->em_types[enum_nr] == (sipTypeDef *)etd) break; /* Get the enum members in the same scope. */ if (etd->etd_scope < 0) { nr_members = client->em_nrenummembers; enm = client->em_enummembers; } else { const sipContainerDef *cod = get_container(client->em_types[etd->etd_scope]); nr_members = cod->cod_nrenummembers; enm = cod->cod_enummembers; } /* Find the enum member. */ for (emd = enm, m = 0; m < nr_members; ++m, ++emd) if (emd->em_enum == enum_nr && strcmp(emd->em_name, name_str) == 0) return sip_api_convert_from_enum(emd->em_val, (sipTypeDef *)etd); PyErr_Format(PyExc_AttributeError, "sip.enumtype object '%s' has no member '%s'", sipPyNameOfEnum(etd), name_str); return NULL; } /* * Check if an object is of the right type to convert to an encoded string. */ static int check_encoded_string(PyObject *obj) { Py_buffer view; if (obj == Py_None) return 0; if (PyUnicode_Check(obj)) return 0; if (PyBytes_Check(obj)) return 0; if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0) { PyErr_Clear(); } else { PyBuffer_Release(&view); return 0; } return -1; } /* * This is called by the atexit module. */ static PyObject *sip_exit(PyObject *self, PyObject *args) { (void)self; (void)args; /* Disable all Python reimplementations of virtuals. */ sipInterpreter = NULL; Py_INCREF(Py_None); return Py_None; } /* * Register an exit notifier with the atexit module. */ static int sip_api_register_exit_notifier(PyMethodDef *md) { static PyObject *register_func = NULL; PyObject *notifier, *res; if (register_func == NULL && (register_func = import_module_attr("atexit", "register")) == NULL) return -1; if ((notifier = PyCFunction_New(md, NULL)) == NULL) return -1; res = PyObject_CallFunctionObjArgs(register_func, notifier, NULL); Py_DECREF(notifier); if (res == NULL) return -1; Py_DECREF(res); return 0; } /* * Return the function that converts a C++ instance to a Python object. */ static sipConvertFromFunc get_from_convertor(const sipTypeDef *td) { if (sipTypeIsMapped(td)) return ((const sipMappedTypeDef *)td)->mtd_cfrom; assert(sipTypeIsClass(td)); if (autoconversion_disabled(td) != NULL) return NULL; return ((const sipClassTypeDef *)td)->ctd_cfrom; } /* * Enable or disable the auto-conversion. Returns the previous enabled state * or -1 on error. */ static int sip_api_enable_autoconversion(const sipTypeDef *td, int enable) { sipPyObject **pop; assert(sipTypeIsClass(td)); pop = autoconversion_disabled(td); /* See if there is anything to do. */ if (pop == NULL && enable) return TRUE; if (pop != NULL && !enable) return FALSE; if (pop != NULL) { /* Remove it from the list. */ sipPyObject *po = *pop; *pop = po->next; sip_api_free(po); } else { /* Add it to the list. */ if (addPyObjectToList(&sipDisabledAutoconversions, (PyObject *)sipTypeAsPyTypeObject(td)) < 0) return -1; } return !enable; } /* * Return a pointer to the entry in the list of disabled auto-conversions for a * type. */ static sipPyObject **autoconversion_disabled(const sipTypeDef *td) { PyObject *type = (PyObject *)sipTypeAsPyTypeObject(td); sipPyObject **pop; for (pop = &sipDisabledAutoconversions; *pop != NULL; pop = &(*pop)->next) if ((*pop)->object == type) return pop; return NULL; } /* * Enable or disable auto-conversion of a class that supports it. */ static PyObject *enableAutoconversion(PyObject *self, PyObject *args) { sipWrapperType *wt; int enable; (void)self; if (PyArg_ParseTuple(args, "O!i:enableautoconversion", &sipWrapperType_Type, &wt, &enable)) { sipTypeDef *td = wt->wt_td; int was_enabled; PyObject *res; if (!sipTypeIsClass(td) || ((sipClassTypeDef *)td)->ctd_cfrom == NULL) { PyErr_Format(PyExc_TypeError, "%s is not a wrapped class that supports optional auto-conversion", ((PyTypeObject *)wt)->tp_name); return NULL; } if ((was_enabled = sip_api_enable_autoconversion(td, enable)) < 0) return NULL; res = (was_enabled ? Py_True : Py_False); Py_INCREF(res); return res; } return NULL; } /* * Python copies the nb_inplace_add slot to the sq_inplace_concat slot and vice * versa if either are missing. This is a bug because they don't have the same * API. We therefore reverse this. */ static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd) { while (psd->psd_func != NULL) { if (psd->psd_type == iadd_slot && py_type->tp_as_sequence != NULL) py_type->tp_as_sequence->sq_inplace_concat = NULL; if (psd->psd_type == iconcat_slot && py_type->tp_as_number != NULL) py_type->tp_as_number->nb_inplace_add = NULL; ++psd; } } /* * Return the main instance for an object if it is a mixin. */ static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w) { return w->mixin_main != NULL ? (sipSimpleWrapper *)w->mixin_main : w; } /* * Convert a new C/C++ pointer to a Python instance. */ static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td, sipWrapper *owner, int flags) { return sipWrapInstance(cpp, sipTypeAsPyTypeObject(td), empty_tuple, owner, flags); } /* * Resolve a proxy, if applicable. */ static void *resolve_proxy(const sipTypeDef *td, void *proxy) { sipProxyResolver *pr; /* TODO: Deprecate this mechanism in favour of an event handler. */ for (pr = proxyResolvers; pr != NULL; pr = pr->next) if (pr->td == td) proxy = pr->resolver(proxy); return proxy; } /* * Clear a simple wrapper. */ static void clear_wrapper(sipSimpleWrapper *sw) { if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type)) removeFromParent((sipWrapper *)sw); /* * Transfer ownership to C++ so we don't try to release it when the * Python object is garbage collected. */ sipResetPyOwned(sw); sipOMRemoveObject(&cppPyMap, sw); clear_access_func(sw); } /* * Set the handler to invoke when a new user Python sub-class is defined and * return the old handler. */ static sipNewUserTypeFunc sip_api_set_new_user_type_handler( const sipTypeDef *td, sipNewUserTypeFunc handler) { sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td); sipNewUserTypeFunc old_handler = wt->wt_new_user_type_handler;; wt->wt_new_user_type_handler = handler; return old_handler; } /* * Set the user-specific type data. */ static void sip_api_set_type_user_data(sipWrapperType *wt, void *data) { wt->wt_user_data = data; } /* * Get the user-specific type data. */ static void *sip_api_get_type_user_data(const sipWrapperType *wt) { return wt->wt_user_data; } /* * Get a borrowed reference to the dict of a Python type (on behalf of the * limited API). This is deprecated in ABI v12.13 and must not be used with * Python v3.12 and later. */ static PyObject *sip_api_py_type_dict(const PyTypeObject *py_type) { PyErr_WarnEx(PyExc_DeprecationWarning, "sipPyTypeDict() is deprecated, the extension module should use " "sipPyTypeDictRef() instead", 1); return py_type->tp_dict; } /* * Get a new reference to the dict of a Python type (on behalf of the limited * API). */ static PyObject *sip_api_py_type_dict_ref(PyTypeObject *py_type) { #if PY_VERSION_HEX >= 0x030c0000 return PyType_GetDict(py_type); #else PyObject *ref = py_type->tp_dict; Py_XINCREF(ref); return ref; #endif } /* * Get the name of a Python type (on behalf of the limited API). */ static const char *sip_api_py_type_name(const PyTypeObject *py_type) { return py_type->tp_name; } /* * Check an object is a method and return TRUE and its component parts if it * is. */ static int sip_api_get_method(PyObject *obj, sipMethodDef *method) { if (!PyMethod_Check(obj)) return FALSE; if (method != NULL) { method->pm_self = PyMethod_GET_SELF(obj); method->pm_function = PyMethod_GET_FUNCTION(obj); } return TRUE; } /* * Create a method from its component parts. */ static PyObject *sip_api_from_method(const sipMethodDef *method) { return PyMethod_New(method->pm_function, method->pm_self); } /* * Check an object is a C function and return TRUE and its component parts if * it is. */ static int sip_api_get_c_function(PyObject *obj, sipCFunctionDef *c_function) { if (!PyCFunction_Check(obj)) return FALSE; if (c_function != NULL) { c_function->cf_function = ((PyCFunctionObject *)obj)->m_ml; c_function->cf_self = PyCFunction_GET_SELF(obj); } return TRUE; } /* * Check an object is a date and return TRUE and its component parts if it is. */ static int sip_api_get_date(PyObject *obj, sipDateDef *date) { if (!PyDateTimeAPI) PyDateTime_IMPORT; if (!PyDate_Check(obj)) return FALSE; if (date != NULL) { date->pd_year = PyDateTime_GET_YEAR(obj); date->pd_month = PyDateTime_GET_MONTH(obj); date->pd_day = PyDateTime_GET_DAY(obj); } return TRUE; } /* * Create a date from its component parts. */ static PyObject *sip_api_from_date(const sipDateDef *date) { if (!PyDateTimeAPI) PyDateTime_IMPORT; return PyDate_FromDate(date->pd_year, date->pd_month, date->pd_day); } /* * Check an object is a datetime and return TRUE and its component parts if it * is. */ static int sip_api_get_datetime(PyObject *obj, sipDateDef *date, sipTimeDef *time) { if (!PyDateTimeAPI) PyDateTime_IMPORT; if (!PyDateTime_Check(obj)) return FALSE; if (date != NULL) { date->pd_year = PyDateTime_GET_YEAR(obj); date->pd_month = PyDateTime_GET_MONTH(obj); date->pd_day = PyDateTime_GET_DAY(obj); } if (time != NULL) { time->pt_hour = PyDateTime_DATE_GET_HOUR(obj); time->pt_minute = PyDateTime_DATE_GET_MINUTE(obj); time->pt_second = PyDateTime_DATE_GET_SECOND(obj); time->pt_microsecond = PyDateTime_DATE_GET_MICROSECOND(obj); } return TRUE; } /* * Create a datetime from its component parts. */ static PyObject *sip_api_from_datetime(const sipDateDef *date, const sipTimeDef *time) { if (!PyDateTimeAPI) PyDateTime_IMPORT; return PyDateTime_FromDateAndTime(date->pd_year, date->pd_month, date->pd_day, time->pt_hour, time->pt_minute, time->pt_second, time->pt_microsecond); } /* * Check an object is a time and return TRUE and its component parts if it is. */ static int sip_api_get_time(PyObject *obj, sipTimeDef *time) { if (!PyDateTimeAPI) PyDateTime_IMPORT; if (!PyTime_Check(obj)) return FALSE; if (time != NULL) { time->pt_hour = PyDateTime_TIME_GET_HOUR(obj); time->pt_minute = PyDateTime_TIME_GET_MINUTE(obj); time->pt_second = PyDateTime_TIME_GET_SECOND(obj); time->pt_microsecond = PyDateTime_TIME_GET_MICROSECOND(obj); } return TRUE; } /* * Create a time from its component parts. */ static PyObject *sip_api_from_time(const sipTimeDef *time) { if (!PyDateTimeAPI) PyDateTime_IMPORT; return PyTime_FromTime(time->pt_hour, time->pt_minute, time->pt_second, time->pt_microsecond); } /* * See if a type is user defined. */ static int sip_api_is_user_type(const sipWrapperType *wt) { return wt->wt_user_type; } /* * Return a frame from the execution stack. Note that we use 'struct _frame' * rather than PyFrameObject because the latter wasn't exposed to the limited * API until Python v3.9. */ static struct _frame *sip_api_get_frame(int depth) { #if defined(PYPY_VERSION) /* PyPy only supports a depth of 0. */ return NULL; #else struct _frame *frame = PyEval_GetFrame(); while (frame != NULL && depth > 0) { #if PY_VERSION_HEX < 0x03090000 frame = frame->f_back; #else frame = PyFrame_GetBack(frame); /* Historically we return a borrowed reference. */ Py_XDECREF(frame); #endif --depth; } return frame; #endif } /* * Check if a type was generated using the given plugin. Note that, although * this is part of the public API it is undocumented on purpose. */ static int sip_api_check_plugin_for_type(const sipTypeDef *td, const char *name) { /* * The current thinking on plugins is that SIP v5 will look for a plugin * with a name derived from the name as the current module in the same * directory as the .sip defining the module (ie. no %Plugin directive). A * module hierachy may have multiple plugins but they must co-operate. If * a plugin generates user data then it should include a void* (and a * run-time API) so that other plugins can extend it further. This * approach means that a plugin's user data structure can be opaque. */ sipExportedModuleDef *em = td->td_module; sipImportedModuleDef *im; if (strcmp(sipNameOfModule(em), name) == 0) return TRUE; if ((im = em->em_imports) == NULL) return FALSE; while (im->im_name != NULL) { if (strcmp(im->im_name, name) == 0) return TRUE; ++im; } return FALSE; } /* * Create a new Unicode object and return the character size and buffer. */ static PyObject *sip_api_unicode_new(Py_ssize_t len, unsigned maxchar, int *kind, void **data) { PyObject *obj; if ((obj = PyUnicode_New(len, maxchar)) != NULL) { *kind = PyUnicode_KIND(obj); *data = PyUnicode_DATA(obj); } return obj; } /* * Update a new Unicode object with a new character. */ static void sip_api_unicode_write(int kind, void *data, int index, unsigned value) { PyUnicode_WRITE(kind, data, index, value); } /* * Get the address of the contents of a Unicode object, the character size and * the length. */ static void *sip_api_unicode_data(PyObject *obj, int *char_size, Py_ssize_t *len) { void *data; /* Assume there will be an error. */ *char_size = -1; if (PyUnicode_READY(obj) < 0) return NULL; *len = PyUnicode_GET_LENGTH(obj); switch (PyUnicode_KIND(obj)) { case PyUnicode_1BYTE_KIND: *char_size = 1; data = PyUnicode_1BYTE_DATA(obj); break; case PyUnicode_2BYTE_KIND: *char_size = 2; data = PyUnicode_2BYTE_DATA(obj); break; case PyUnicode_4BYTE_KIND: *char_size = 4; data = PyUnicode_4BYTE_DATA(obj); break; default: data = NULL; } return data; } /* * Get the buffer information supplied by an object that supports the buffer * protocol. */ static int sip_api_get_buffer_info(PyObject *obj, sipBufferInfoDef *bi) { int rc; Py_buffer *buffer; if (!PyObject_CheckBuffer(obj)) return 0; if (bi == NULL) return 1; if ((bi->bi_internal = sip_api_malloc(sizeof (Py_buffer))) == NULL) return -1; buffer = (Py_buffer *)bi->bi_internal; if (PyObject_GetBuffer(obj, buffer, PyBUF_FORMAT) < 0) return -1; if (buffer->ndim == 1) { bi->bi_buf = buffer->buf; bi->bi_obj = buffer->obj; bi->bi_len = buffer->len; bi->bi_format = buffer->format; rc = 1; } else { PyErr_SetString(PyExc_TypeError, "a 1-dimensional buffer is required"); PyBuffer_Release(buffer); rc = -1; } return rc; } /* * Release the buffer information obtained from a previous call to * sipGetBufferInfo(). */ static void sip_api_release_buffer_info(sipBufferInfoDef *bi) { if (bi->bi_internal != NULL) { PyBuffer_Release((Py_buffer *)bi->bi_internal); sip_api_free(bi->bi_internal); bi->bi_internal = NULL; } } /* * Import all the required types from an imported module. */ static int importTypes(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em) { const char *name; int i, e; /* * Look for each required type in turn. Both tables are sorted so a single * pass will find them all. */ for (i = e = 0; (name = im->im_imported_types[i].it_name) != NULL; ++i) { sipTypeDef *td = NULL; do { sipTypeDef *e_td; if (e >= em->em_nrtypes) { PyErr_Format(PyExc_RuntimeError, "%s cannot import type '%s' from %s", sipNameOfModule(client), name, sipNameOfModule(em)); return -1; } e_td = em->em_types[e++]; /* Ignore unresolved external types. */ if (e_td != NULL && strcmp(name, sipTypeName(e_td)) == 0) td = e_td; } while (td == NULL); im->im_imported_types[i].it_td = td; } return 0; } /* * Import all the required virtual error handlers from an imported module. */ static int importErrorHandlers(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em) { const char *name; int i; for (i = 0; (name = im->im_imported_veh[i].iveh_name) != NULL; ++i) { sipVirtErrorHandlerDef *veh = em->em_virterrorhandlers; sipVirtErrorHandlerFunc handler = NULL; if (veh != NULL) { while (veh->veh_name != NULL) { if (strcmp(veh->veh_name, name) == 0) { handler = veh->veh_handler; break; } ++veh; } } if (handler == NULL) { PyErr_Format(PyExc_RuntimeError, "%s cannot import virtual error handler '%s' from %s", sipNameOfModule(client), name, sipNameOfModule(em)); return -1; } im->im_imported_veh[i].iveh_handler = handler; } return 0; } /* * Import all the required exceptions from an imported module. */ static int importExceptions(sipExportedModuleDef *client, sipImportedModuleDef *im, sipExportedModuleDef *em) { const char *name; int i; for (i = 0; (name = im->im_imported_exceptions[i].iexc_name) != NULL; ++i) { PyObject **exc = em->em_exceptions; PyObject *exception = NULL; if (exc != NULL) { while (*exc != NULL) { if (strcmp(((PyTypeObject *)(*exc))->tp_name, name) == 0) { exception = *exc; break; } ++exc; } } if (exception == NULL) { PyErr_Format(PyExc_RuntimeError, "%s cannot import exception '%s' from %s", sipNameOfModule(client), name, sipNameOfModule(em)); return -1; } im->im_imported_exceptions[i].iexc_object = exception; } return 0; } /* * Enable or disable the garbage collector. Return the previous state or -1 if * there was an error. */ static int sip_api_enable_gc(int enable) { static PyObject *enable_func = NULL, *disable_func, *isenabled_func; PyObject *result; int was_enabled; /* * This may be -ve in the highly unusual event that a previous call failed. */ if (enable < 0) return -1; /* Get the functions if we haven't already got them. */ if (enable_func == NULL) { PyObject *gc_module; if ((gc_module = PyImport_ImportModule("gc")) == NULL) return -1; if ((enable_func = PyObject_GetAttrString(gc_module, "enable")) == NULL) { Py_DECREF(gc_module); return -1; } if ((disable_func = PyObject_GetAttrString(gc_module, "disable")) == NULL) { Py_DECREF(enable_func); Py_DECREF(gc_module); return -1; } if ((isenabled_func = PyObject_GetAttrString(gc_module, "isenabled")) == NULL) { Py_DECREF(disable_func); Py_DECREF(enable_func); Py_DECREF(gc_module); return -1; } Py_DECREF(gc_module); } /* Get the current state. */ if ((result = PyObject_Call(isenabled_func, empty_tuple, NULL)) == NULL) return -1; was_enabled = PyObject_IsTrue(result); Py_DECREF(result); if (was_enabled < 0) return -1; /* See if the state needs changing. */ if (!was_enabled != !enable) { /* Enable or disable as required. */ result = PyObject_Call((enable ? enable_func : disable_func), empty_tuple, NULL); Py_XDECREF(result); if (result != Py_None) return -1; } return was_enabled; } /* * A thin wrapper around PyObject_Print() usually used when debugging with the * limited API. */ static void sip_api_print_object(PyObject *o) { PyObject_Print(o, stdout, 0); } /* * Register a handler for a particular event. */ static int sip_api_register_event_handler(sipEventType type, const sipTypeDef *td, void *handler) { sipEventHandler *eh; assert(sipTypeIsClass(td)); if ((eh = sip_api_malloc(sizeof (sipEventHandler))) == NULL) return -1; eh->ctd = (const sipClassTypeDef *)td; eh->handler = handler; eh->next = event_handlers[(int)type]; event_handlers[(int)type] = eh; return 0; } /* * Returns TRUE if a generated class type is a sub-class of a base generated * class type. */ static int is_subtype(const sipClassTypeDef *ctd, const sipClassTypeDef *base_ctd) { const sipEncodedTypeDef *sup; /* Handle the trivial cases. */ if (ctd == base_ctd) return TRUE; if ((sup = ctd->ctd_supers) == NULL) return FALSE; /* Search the super-types. */ do { const sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd); if (is_subtype(sup_ctd, base_ctd)) return TRUE; } while (!sup++->sc_flag); return FALSE; } /* * Return an attribute of an imported module. */ static PyObject *import_module_attr(const char *module, const char *attr) { PyObject *mod_obj, *attr_obj; if ((mod_obj = PyImport_ImportModule(module)) == NULL) return NULL; attr_obj = PyObject_GetAttrString(mod_obj, attr); Py_DECREF(mod_obj); return attr_obj; } /* * Get the container for a generated type. */ static const sipContainerDef *get_container(const sipTypeDef *td) { if (sipTypeIsMapped(td)) return &((const sipMappedTypeDef *)td)->mtd_container; return &((const sipClassTypeDef *)td)->ctd_container; } /* * Get the __qualname__ of an object based on its enclosing scope. */ static PyObject *get_qualname(const sipTypeDef *td, PyObject *name) { PyTypeObject *scope_type; /* Get the type that is the scope. */ scope_type = sipTypeAsPyTypeObject(td); return PyUnicode_FromFormat("%U.%U", ((PyHeapTypeObject *)scope_type)->ht_qualname, name); } /* * Implement PySlice_GetIndicesEx() (or its subsequent replacement). */ int sip_api_convert_from_slice_object(PyObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength) { if (PySlice_Unpack(slice, start, stop, step) < 0) return -1; *slicelength = PySlice_AdjustIndices(length, start, stop, *step); return 0; } /* * Call a visitor function for every wrapped object. */ static void sip_api_visit_wrappers(sipWrapperVisitorFunc visitor, void *closure) { const sipHashEntry *he; unsigned long i; for (he = cppPyMap.hash_array, i = 0; i < cppPyMap.size; ++i, ++he) { if (he->key != NULL) { sipSimpleWrapper *sw; for (sw = he->first; sw != NULL; sw = sw->next) visitor(sw, closure); } } } /* * Return the next exception handler. The order is undefined. */ sipExceptionHandler sip_api_next_exception_handler(void **statep) { sipExportedModuleDef *em = *(sipExportedModuleDef **)statep; if (em != NULL) em = em->em_next; else em = moduleList; while (em->em_exception_handler == NULL) if ((em = em->em_next) == NULL) return NULL; *statep = em; return em->em_exception_handler; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/threads.c0000644000076500000240000001027114644214002014170 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * 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) 2024 Phil Thompson */ #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 /* * 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(int auto_alloc); #endif static pendingDef *get_pending(int auto_alloc); /* * Get the address etc. of any C/C++ object waiting to be wrapped. */ int sipGetPending(void **pp, sipWrapper **op, int *fp) { pendingDef *pd; if ((pd = get_pending(TRUE)) == NULL) return -1; *pp = pd->cpp; *op = pd->owner; *fp = pd->flags; /* Clear in case we execute Python code before finishing this wrapping. */ pd->cpp = NULL; return 0; } /* * Return TRUE if anything is pending. */ int sipIsPending(void) { pendingDef *pd; if ((pd = get_pending(FALSE)) == NULL) return FALSE; return (pd->cpp != NULL); } /* * Convert a new C/C++ pointer to a Python instance. */ PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args, sipWrapper *owner, int flags) { pendingDef old_pending, *pd; PyObject *self; if (cpp == 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. */ if ((pd = get_pending(TRUE)) == NULL) return NULL; old_pending = *pd; pd->cpp = cpp; pd->owner = owner; pd->flags = flags; self = PyObject_Call((PyObject *)py_type, args, NULL); *pd = old_pending; return self; } /* * Handle the termination of a thread. */ void sip_api_end_thread(void) { #ifdef WITH_THREAD threadDef *thread; PyGILState_STATE gil = PyGILState_Ensure(); if ((thread = currentThreadDef(FALSE)) != NULL) thread->thr_ident = 0; PyGILState_Release(gil); #endif } /* * Return the pending data for the current thread, allocating it if necessary, * or NULL if there was an error. */ static pendingDef *get_pending(int auto_alloc) { #ifdef WITH_THREAD threadDef *thread; if ((thread = currentThreadDef(auto_alloc)) == NULL) return NULL; return &thread->pending; #else static pendingDef pending; return &pending; #endif } #ifdef WITH_THREAD /* * Return the thread data for the current thread, allocating it if necessary, * or NULL if there was an error. */ static threadDef *currentThreadDef(int auto_alloc) { threadDef *thread, *empty = NULL; long ident = PyThread_get_thread_ident(); /* See if we already know about the thread. */ for (thread = threads; thread != NULL; thread = thread->next) { if (thread->thr_ident == ident) return thread; if (thread->thr_ident == 0) empty = thread; } if (!auto_alloc) { /* This is not an error. */ return NULL; } if (empty != NULL) { /* Use an empty entry in the list. */ thread = empty; } else if ((thread = sip_api_malloc(sizeof (threadDef))) == NULL) { return NULL; } else { thread->next = threads; threads = thread; } thread->thr_ident = ident; thread->pending.cpp = NULL; return thread; } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1720784898.0 PyQt5_sip-12.15.0/voidptr.c0000644000076500000240000004463614644214002014241 0ustar00philstaff/* SPDX-License-Identifier: BSD-2-Clause */ /* * This file implements the API for the voidptr type. * * Copyright (c) 2024 Phil Thompson */ /* Remove when Python v3.12 is no longer supported. */ #define PY_SSIZE_T_CLEAN #include #include #include #include "sipint.h" #include "sip_array.h" /* The object data structure. */ typedef struct { PyObject_HEAD void *voidptr; Py_ssize_t size; int rw; } sipVoidPtrObject; /* The structure used to hold the results of a voidptr conversion. */ struct vp_values { void *voidptr; Py_ssize_t size; int rw; }; static int check_size(PyObject *self); static int check_rw(PyObject *self); static int check_index(PyObject *self, Py_ssize_t idx); static void bad_key(PyObject *key); static int check_slice_size(Py_ssize_t size, Py_ssize_t value_size); static PyObject *make_voidptr(void *voidptr, Py_ssize_t size, int rw); static int vp_convertor(PyObject *arg, struct vp_values *vp); static Py_ssize_t get_size_from_arg(sipVoidPtrObject *v, Py_ssize_t size); /* * Implement ascapsule() for the type. */ static PyObject *sipVoidPtr_ascapsule(sipVoidPtrObject *v, PyObject *arg) { (void)arg; return PyCapsule_New(v->voidptr, NULL, NULL); } /* * Implement asarray() for the type. */ static PyObject *sipVoidPtr_asarray(sipVoidPtrObject *v, PyObject *args, PyObject *kw) { #if PY_VERSION_HEX >= 0x030d0000 static char * const kwlist[] = {"size", NULL}; #else static char *kwlist[] = {"size", NULL}; #endif Py_ssize_t size = -1; if (!PyArg_ParseTupleAndKeywords(args, kw, "|n:asarray", kwlist, &size)) return NULL; if ((size = get_size_from_arg(v, size)) < 0) return NULL; return sip_api_convert_to_array(v->voidptr, "B", size, (v->rw ? 0 : SIP_READ_ONLY)); } /* * Implement asstring() for the type. */ static PyObject *sipVoidPtr_asstring(sipVoidPtrObject *v, PyObject *args, PyObject *kw) { #if PY_VERSION_HEX >= 0x030d0000 static char * const kwlist[] = {"size", NULL}; #else static char *kwlist[] = {"size", NULL}; #endif Py_ssize_t size = -1; if (!PyArg_ParseTupleAndKeywords(args, kw, "|n:asstring", kwlist, &size)) return NULL; if ((size = get_size_from_arg(v, size)) < 0) return NULL; return PyBytes_FromStringAndSize(v->voidptr, size); } /* * Implement getsize() for the type. */ static PyObject *sipVoidPtr_getsize(sipVoidPtrObject *v, PyObject *arg) { (void)arg; return PyLong_FromSsize_t(v->size); } /* * Implement setsize() for the type. */ static PyObject *sipVoidPtr_setsize(sipVoidPtrObject *v, PyObject *arg) { Py_ssize_t size = PyLong_AsSsize_t(arg); 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) { (void)arg; return PyBool_FromLong(v->rw); } /* * Implement setwriteable() for the type. */ static PyObject *sipVoidPtr_setwriteable(sipVoidPtrObject *v, PyObject *arg) { int rw; if ((rw = PyObject_IsTrue(arg)) < 0) return NULL; v->rw = rw; Py_INCREF(Py_None); return Py_None; } /* The methods data structure. */ static PyMethodDef sipVoidPtr_Methods[] = { {"asarray", (PyCFunction)sipVoidPtr_asarray, METH_VARARGS|METH_KEYWORDS, NULL}, {"ascapsule", (PyCFunction)sipVoidPtr_ascapsule, METH_NOARGS, NULL}, {"asstring", (PyCFunction)sipVoidPtr_asstring, METH_VARARGS|METH_KEYWORDS, NULL}, {"getsize", (PyCFunction)sipVoidPtr_getsize, METH_NOARGS, NULL}, {"setsize", (PyCFunction)sipVoidPtr_setsize, METH_O, NULL}, {"getwriteable", (PyCFunction)sipVoidPtr_getwriteable, METH_NOARGS, NULL}, {"setwriteable", (PyCFunction)sipVoidPtr_setwriteable, METH_O, NULL}, {NULL, NULL, 0, NULL} }; /* * Implement bool() for the type. */ static int sipVoidPtr_bool(PyObject *self) { return (((sipVoidPtrObject *)self)->voidptr != NULL); } /* * Implement int() for the type. */ static PyObject *sipVoidPtr_int(PyObject *self) { return PyLong_FromVoidPtr(((sipVoidPtrObject *)self)->voidptr); } /* The number methods data structure. */ static PyNumberMethods sipVoidPtr_NumberMethods = { 0, /* nb_add */ 0, /* nb_subtract */ 0, /* nb_multiply */ 0, /* nb_remainder */ 0, /* nb_divmod */ 0, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ sipVoidPtr_bool, /* nb_bool */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ 0, /* nb_and */ 0, /* nb_xor */ 0, /* nb_or */ sipVoidPtr_int, /* nb_int */ 0, /* nb_reserved */ 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ 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 */ 0, /* nb_index */ 0, /* nb_matrix_multiply */ 0, /* nb_inplace_matrix_multiply */ }; /* * Implement len() for the type. */ static Py_ssize_t sipVoidPtr_length(PyObject *self) { if (check_size(self) < 0) return -1; return ((sipVoidPtrObject *)self)->size; } /* * Implement sequence item sub-script for the type. */ static PyObject *sipVoidPtr_item(PyObject *self, Py_ssize_t idx) { if (check_size(self) < 0 || check_index(self, idx) < 0) return NULL; return PyBytes_FromStringAndSize( (char *)((sipVoidPtrObject *)self)->voidptr + idx, 1); } /* The sequence methods data structure. */ static PySequenceMethods sipVoidPtr_SequenceMethods = { sipVoidPtr_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ sipVoidPtr_item, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ 0, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; /* * Implement mapping sub-script for the type. */ static PyObject *sipVoidPtr_subscript(PyObject *self, PyObject *key) { sipVoidPtrObject *v; if (check_size(self) < 0) return NULL; v = (sipVoidPtrObject *)self; if (PyIndex_Check(key)) { Py_ssize_t idx = PyNumber_AsSsize_t(key, PyExc_IndexError); if (idx == -1 && PyErr_Occurred()) return NULL; if (idx < 0) idx += v->size; return sipVoidPtr_item(self, idx); } if (PySlice_Check(key)) { Py_ssize_t start, stop, step, slicelength; if (sip_api_convert_from_slice_object(key, v->size, &start, &stop, &step, &slicelength) < 0) return NULL; if (step != 1) { PyErr_SetNone(PyExc_NotImplementedError); return NULL; } return make_voidptr((char *)v->voidptr + start, slicelength, v->rw); } bad_key(key); return NULL; } /* * Implement mapping assignment sub-script for the type. */ static int sipVoidPtr_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { sipVoidPtrObject *v; Py_ssize_t start, size; Py_buffer value_view; if (check_rw(self) < 0 || check_size(self) < 0) return -1; v = (sipVoidPtrObject *)self; if (PyIndex_Check(key)) { start = PyNumber_AsSsize_t(key, PyExc_IndexError); if (start == -1 && PyErr_Occurred()) return -1; if (start < 0) start += v->size; if (check_index(self, start) < 0) return -1; size = 1; } else if (PySlice_Check(key)) { Py_ssize_t stop, step; if (sip_api_convert_from_slice_object(key, v->size, &start, &stop, &step, &size) < 0) return -1; if (step != 1) { PyErr_SetNone(PyExc_NotImplementedError); return -1; } } else { bad_key(key); return -1; } if (PyObject_GetBuffer(value, &value_view, PyBUF_CONTIG_RO) < 0) return -1; /* We could allow any item size... */ if (value_view.itemsize != 1) { PyErr_Format(PyExc_TypeError, "'%s' must have an item size of 1", Py_TYPE(value_view.obj)->tp_name); PyBuffer_Release(&value_view); return -1; } if (check_slice_size(size, value_view.len) < 0) { PyBuffer_Release(&value_view); return -1; } memmove((char *)v->voidptr + start, value_view.buf, size); PyBuffer_Release(&value_view); return 0; } /* The mapping methods data structure. */ static PyMappingMethods sipVoidPtr_MappingMethods = { sipVoidPtr_length, /* mp_length */ sipVoidPtr_subscript, /* mp_subscript */ sipVoidPtr_ass_subscript, /* mp_ass_subscript */ }; /* * The buffer implementation for Python v2.6.3 and later. */ static int sipVoidPtr_getbuffer(PyObject *self, Py_buffer *buf, int flags) { sipVoidPtrObject *v; if (check_size(self) < 0) return -1; v = (sipVoidPtrObject *)self; return PyBuffer_FillInfo(buf, self, v->voidptr, v->size, !v->rw, flags); } /* The buffer methods data structure. */ static PyBufferProcs sipVoidPtr_BufferProcs = { sipVoidPtr_getbuffer, /* bf_getbuffer */ 0 /* bf_releasebuffer */ }; /* * Implement __new__ for the type. */ static PyObject *sipVoidPtr_new(PyTypeObject *subtype, PyObject *args, PyObject *kw) { #if PY_VERSION_HEX >= 0x030d0000 static char * const kwlist[] = {"address", "size", "writeable", NULL}; #else static char *kwlist[] = {"address", "size", "writeable", NULL}; #endif struct vp_values vp_conversion; Py_ssize_t size = -1; int rw = -1; PyObject *obj; if (!PyArg_ParseTupleAndKeywords(args, kw, "O&|ni:voidptr", 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; } /* 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 */ &sipVoidPtr_SequenceMethods, /* tp_as_sequence */ &sipVoidPtr_MappingMethods, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ &sipVoidPtr_BufferProcs, /* tp_as_buffer */ #if defined(Py_TPFLAGS_HAVE_NEWBUFFER) Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */ #else Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ #endif 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 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 */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ 0, /* tp_finalize */ 0, /* tp_vectorcall */ }; /* * A convenience function to convert a C/C++ void pointer from a Python object. */ void *sip_api_convert_to_void_ptr(PyObject *obj) { struct vp_values vp; if (obj == NULL) { PyErr_SetString(PyExc_TypeError, "sip.voidptr is NULL"); return NULL; } if (vp_convertor(obj, &vp)) return vp.voidptr; return PyLong_AsVoidPtr(obj); } /* * 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, Py_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, Py_ssize_t size) { return make_voidptr((void *)val, size, FALSE); } /* * Check that a void pointer has an explicit size and raise an exception if it * hasn't. */ static int check_size(PyObject *self) { if (((sipVoidPtrObject *)self)->size >= 0) return 0; PyErr_SetString(PyExc_IndexError, "sip.voidptr object has an unknown size"); return -1; } /* * Check that a void pointer is writable. */ static int check_rw(PyObject *self) { if (((sipVoidPtrObject *)self)->rw) return 0; PyErr_SetString(PyExc_TypeError, "cannot modify a read-only sip.voidptr object"); return -1; } /* * Check that an index is valid for a void pointer. */ static int check_index(PyObject *self, Py_ssize_t idx) { if (idx >= 0 && idx < ((sipVoidPtrObject *)self)->size) return 0; PyErr_SetString(PyExc_IndexError, "index out of bounds"); return -1; } /* * Raise an exception about a bad sub-script key. */ static void bad_key(PyObject *key) { PyErr_Format(PyExc_TypeError, "cannot index a sip.voidptr object using '%s'", Py_TYPE(key)->tp_name); } /* * Check that the size of a value is the same as the size of the slice it is * replacing. */ static int check_slice_size(Py_ssize_t size, Py_ssize_t value_size) { if (value_size == size) return 0; PyErr_SetString(PyExc_ValueError, "cannot modify the size of a sip.voidptr object"); return -1; } /* * Do the work of converting a void pointer. */ static PyObject *make_voidptr(void *voidptr, Py_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; Py_ssize_t size = -1; int rw = TRUE; if (arg == Py_None) { ptr = NULL; } else if (PyCapsule_CheckExact(arg)) { ptr = PyCapsule_GetPointer(arg, NULL); } else if (PyObject_TypeCheck(arg, &sipVoidPtr_Type)) { ptr = ((sipVoidPtrObject *)arg)->voidptr; size = ((sipVoidPtrObject *)arg)->size; rw = ((sipVoidPtrObject *)arg)->rw; } else if (PyObject_CheckBuffer(arg)) { Py_buffer view; if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) < 0) return 0; ptr = view.buf; size = view.len; rw = !view.readonly; PyBuffer_Release(&view); } else { PyErr_Clear(); ptr = PyLong_AsVoidPtr(arg); if (PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "a single integer, Capsule, None, bytes-like object or another sip.voidptr object is required"); return 0; } } vp->voidptr = ptr; vp->size = size; vp->rw = rw; return 1; } /* * Get a size possibly supplied as an argument, otherwise get it from the * object. Raise an exception if there was no size specified. */ static Py_ssize_t get_size_from_arg(sipVoidPtrObject *v, Py_ssize_t size) { /* Use the current size if one wasn't explicitly given. */ if (size < 0) size = v->size; if (size < 0) PyErr_SetString(PyExc_ValueError, "a size must be given or the sip.voidptr object must have a size"); return size; }