diff options
Diffstat (limited to 'python/sip/siplib/siplib.c')
-rw-r--r-- | python/sip/siplib/siplib.c | 7902 |
1 files changed, 7902 insertions, 0 deletions
diff --git a/python/sip/siplib/siplib.c b/python/sip/siplib/siplib.c new file mode 100644 index 00000000..d546522c --- /dev/null +++ b/python/sip/siplib/siplib.c @@ -0,0 +1,7902 @@ +/* + * SIP library code. + * + * Copyright (c) 2007 + * Riverbank Computing Limited <info@riverbankcomputing.co.uk> + * + * This file is part of SIP. + * + * This copy of SIP is licensed for use under the terms of the SIP License + * Agreement. See the file LICENSE for more details. + * + * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include <Python.h> +#include <stdio.h> +#include <stdarg.h> +#include <stddef.h> +#include <string.h> + +#include "sip.h" +#include "sipint.h" + + +/* + * These are the functions that make up the public and private SIP API. + */ +static void sip_api_bad_catcher_result(PyObject *method); +static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen, + SIP_SSIZE_T slicelen); +static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...); +static PyObject *sip_api_call_method(int *isErr, PyObject *method, + const char *fmt, ...); +static PyObject *sip_api_class_name(PyObject *self); +static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx, + SIP_SSIZE_T len); +static int sip_api_can_convert_to_instance(PyObject *pyObj, + sipWrapperType *type, int flags); +static int sip_api_can_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, int flags); +static void *sip_api_convert_to_instance(PyObject *pyObj, sipWrapperType *type, + PyObject *transferObj, int flags, int *statep, int *iserrp); +static void *sip_api_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, PyObject *transferObj, int flags, int *statep, + int *iserrp); +static void *sip_api_force_convert_to_instance(PyObject *pyObj, + sipWrapperType *type, PyObject *transferObj, int flags, int *statep, + int *iserrp); +static void *sip_api_force_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, PyObject *transferObj, int flags, int *statep, + int *iserrp); +static void sip_api_release_instance(void *cpp, sipWrapperType *type, + int state); +static void sip_api_release_mapped_type(void *cpp, const sipMappedType *mt, + int state); +static PyObject *sip_api_convert_from_new_instance(void *cpp, + sipWrapperType *type, PyObject *transferObj); +static PyObject *sip_api_convert_from_mapped_type(void *cpp, + const sipMappedType *mt, PyObject *transferObj); +static void *sip_api_convert_to_cpp(PyObject *sipSelf, sipWrapperType *type, + int *iserrp); +static int sip_api_get_state(PyObject *transferObj); +static const sipMappedType *sip_api_find_mapped_type(const char *type); +static PyObject *sip_api_get_wrapper(void *cppPtr, sipWrapperType *type); +static sipWrapperType *sip_api_map_int_to_class(int typeInt, + const sipIntTypeClassMap *map, int maplen); +static sipWrapperType *sip_api_map_string_to_class(const char *typeString, + const sipStringTypeClassMap *map, int maplen); +static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, + const char *fmt, ...); +static void sip_api_trace(unsigned mask,const char *fmt,...); +static void sip_api_transfer(PyObject *self, int toCpp); +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, PyObject *mod_dict); +static int sip_api_parse_args(int *argsParsedp, PyObject *sipArgs, + const char *fmt, ...); +static int sip_api_parse_pair(int *argsParsedp, PyObject *sipArg0, + PyObject *sipArg1, const char *fmt, ...); +static void sip_api_common_ctor(sipMethodCache *cache, int nrmeths); +static void sip_api_common_dtor(sipWrapper *sipSelf); +static void *sip_api_convert_to_void_ptr(PyObject *obj); +static void sip_api_no_function(int argsParsed, const char *func); +static void sip_api_no_method(int argsParsed, const char *classname, + const char *method); +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_bad_set_type(const char *classname, const char *var); +static void *sip_api_get_complex_cpp_ptr(sipWrapper *w); +static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, + sipMethodCache *pymc, sipWrapper *sipSelf, char *cname, char *mname); +static void sip_api_call_hook(const char *hookname); +static void sip_api_raise_unknown_exception(void); +static void sip_api_raise_class_exception(sipWrapperType *type, void *ptr); +static void sip_api_raise_sub_class_exception(sipWrapperType *type, void *ptr); +static int sip_api_add_class_instance(PyObject *dict, const char *name, + void *cppPtr, sipWrapperType *wt); +static int sip_api_add_mapped_type_instance(PyObject *dict, const char *name, + void *cppPtr, const sipMappedType *mt); +static int sip_api_add_enum_instance(PyObject *dict, const char *name, + int value, PyTypeObject *type); +static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg, + sipPySlotType st); +static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, + sipPySlotType st, sipWrapperType *type, PyObject *arg0, + PyObject *arg1); +static void sip_api_add_delayed_dtor(sipWrapper *w); +static unsigned long sip_api_long_as_unsigned_long(PyObject *o); +static int sip_api_export_symbol(const char *name, void *sym); +static void *sip_api_import_symbol(const char *name); +static int sip_api_register_int_types(PyObject *args); +static sipWrapperType *sip_api_find_class(const char *type); +static PyTypeObject *sip_api_find_named_enum(const char *type); +static char sip_api_string_as_char(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 + + +/* + * 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. + */ + sip_api_bad_catcher_result, + sip_api_bad_length_for_slice, + sip_api_build_result, + sip_api_call_method, + sip_api_class_name, + sip_api_connect_rx, + sip_api_convert_from_sequence_index, + sip_api_can_convert_to_instance, + sip_api_can_convert_to_mapped_type, + sip_api_convert_to_instance, + sip_api_convert_to_mapped_type, + sip_api_force_convert_to_instance, + sip_api_force_convert_to_mapped_type, + sip_api_release_instance, + sip_api_release_mapped_type, + sip_api_convert_from_instance, + sip_api_convert_from_new_instance, + sip_api_convert_from_mapped_type, + sip_api_convert_to_cpp, + sip_api_get_state, + sip_api_find_mapped_type, + sip_api_disconnect_rx, + sip_api_emit_signal, + sip_api_free, + sip_api_get_sender, + sip_api_get_wrapper, + sip_api_malloc, + sip_api_map_int_to_class, + sip_api_map_string_to_class, + sip_api_parse_result, + sip_api_trace, + sip_api_transfer, + sip_api_transfer_back, + sip_api_transfer_to, + sip_api_wrapper_check, + sip_api_long_as_unsigned_long, + /* + * The following may be used by Qt support code but by no other handwritten + * code. + */ + sip_api_convert_from_named_enum, + sip_api_convert_from_void_ptr, + sip_api_free_connection, + sip_api_emit_to_slot, + sip_api_same_connection, + sip_api_convert_rx, + /* + * The following are not part of the public API. + */ + sip_api_parse_args, + sip_api_parse_pair, + sip_api_common_ctor, + sip_api_common_dtor, + sip_api_convert_to_void_ptr, + sip_api_no_function, + sip_api_no_method, + sip_api_abstract_method, + sip_api_bad_class, + sip_api_bad_set_type, + sip_api_get_cpp_ptr, + sip_api_get_complex_cpp_ptr, + sip_api_is_py_method, + sip_api_call_hook, + sip_api_start_thread, + sip_api_end_thread, + sip_api_raise_unknown_exception, + sip_api_raise_class_exception, + sip_api_raise_sub_class_exception, + sip_api_add_class_instance, + sip_api_add_enum_instance, + sip_api_bad_operator_arg, + sip_api_pyslot_extend, + sip_api_add_delayed_dtor, + sip_api_add_mapped_type_instance, + /* + * The following are part of the public API. + */ + sip_api_export_symbol, + sip_api_import_symbol, + /* + * The following may be used by Qt support code but by no other handwritten + * code. + */ + sip_api_register_int_types, + sip_api_parse_signature, + /* + * The following are part of the public API. + */ + sip_api_find_class, + sip_api_find_named_enum, + /* + * The following are not part of the public API. + */ + sip_api_string_as_char, + sip_api_unicode_as_wchar, + sip_api_unicode_as_wstring, +}; + + +#define PARSE_OK 0x00000000 /* Parse is Ok so far. */ +#define PARSE_MANY 0x10000000 /* Too many arguments. */ +#define PARSE_FEW 0x20000000 /* Too few arguments. */ +#define PARSE_TYPE 0x30000000 /* Argument with a bad type. */ +#define PARSE_UNBOUND 0x40000000 /* Unbound method. */ +#define PARSE_FORMAT 0x50000000 /* Bad format character. */ +#define PARSE_RAISED 0x60000000 /* Exception already raised. */ +#define PARSE_STICKY 0x80000000 /* The error sticks. */ +#define PARSE_MASK 0xf0000000 + +/* + * Note that some of the following flags safely share values because they + * cannot be used at the same time. + */ +#define FORMAT_DEREF 0x01 /* The pointer will be dereferenced. */ +#define FORMAT_FACTORY 0x02 /* Implement /Factory/ in a VH. */ +#define FORMAT_TRANSFER 0x02 /* Implement /Transfer/. */ +#define FORMAT_NO_STATE 0x04 /* Don't return the C/C++ state. */ +#define FORMAT_TRANSFER_BACK 0x04 /* Implement /TransferBack/. */ +#define FORMAT_GET_WRAPPER 0x08 /* Implement /GetWrapper/. */ +#define FORMAT_NO_CONVERTORS 0x10 /* Suppress any convertors. */ +#define FORMAT_TRANSFER_THIS 0x20 /* Support for /TransferThis/. */ + +#define SIP_MC_FOUND 0x01 /* If we have looked for the method. */ +#define SIP_MC_ISMETH 0x02 /* If we looked and there was one. */ + +#define sipFoundMethod(m) ((m)->mcflags & SIP_MC_FOUND) +#define sipSetFoundMethod(m) ((m)->mcflags |= SIP_MC_FOUND) +#define sipIsMethod(m) ((m)->mcflags & SIP_MC_ISMETH) +#define sipSetIsMethod(m) ((m)->mcflags |= SIP_MC_ISMETH) + + +/* + * 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; + + +static PyTypeObject sipWrapperType_Type; +static sipWrapperType sipWrapper_Type; +static PyTypeObject sipVoidPtr_Type; + +PyInterpreterState *sipInterpreter = NULL; +sipQtAPI *sipQtSupport = NULL; +sipWrapperType *sipQObjectClass; +sipPyObject *sipRegisteredIntTypes = NULL; +sipSymbol *sipSymbolList = NULL; + + +/* + * 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 *clientList = NULL; /* List of registered clients. */ +static unsigned traceMask = 0; /* The current trace mask. */ + +static sipTypeDef *currentType = NULL; /* The type being created. */ + + +static void addSlots(sipWrapperType *wt, sipTypeDef *td); +static void initSlots(PyTypeObject *to, PyNumberMethods *nb, + PySequenceMethods *sq, PyMappingMethods *mp, sipPySlotDef *slots, + int force); +static void *findSlot(PyObject *self, sipPySlotType st); +static void *findSlotInType(sipTypeDef *td, sipPySlotType st); +static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2, + sipPySlotType st); +static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1, + PyObject *arg2, sipPySlotType st); +static PyObject *buildObject(PyObject *tup, const char *fmt, va_list va); +static int parsePass1(sipWrapper **selfp, int *selfargp, int *argsParsedp, + PyObject *sipArgs, const char *fmt, va_list va); +static int parsePass2(sipWrapper *self, int selfarg, int nrargs, + PyObject *sipArgs, const char *fmt, va_list va); +static int getSelfFromArgs(sipWrapperType *type, PyObject *args, int argnr, + sipWrapper **selfp); +static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm); +static PyObject *handleGetLazyAttr(PyObject *nameobj, sipWrapperType *wt, + sipWrapper *w); +static int handleSetLazyAttr(PyObject *nameobj, PyObject *valobj, + sipWrapperType *wt, sipWrapper *w); +static int getNonStaticVariables(sipWrapperType *wt, sipWrapper *w, + PyObject **ndict); +static void findLazyAttr(sipWrapperType *wt, char *name, PyMethodDef **pmdp, + sipEnumMemberDef **enmp, PyMethodDef **vmdp, sipTypeDef **in); +static int compareMethodName(const void *key, const void *el); +static int compareEnumMemberName(const void *key, const void *el); +static int checkPointer(void *ptr); +static void *cast_cpp_ptr(void *ptr, sipWrapperType *src_type, + sipWrapperType *dst_type); +static void badArgs(int argsParsed, const char *classname, const char *method); +static void finalise(void); +static sipWrapperType *createType(sipExportedModuleDef *client, + sipTypeDef *type, PyObject *mod_dict); +static PyTypeObject *createEnum(sipExportedModuleDef *client, sipEnumDef *ed, + PyObject *mod_dict); +static const char *getBaseName(const char *name); +static PyObject *getBaseNameObject(const char *name); +static PyObject *createTypeDict(PyObject *mname); +static sipExportedModuleDef *getClassModule(sipEncodedClassDef *enc, + sipExportedModuleDef *em); +static sipWrapperType *getClassType(sipEncodedClassDef *enc, + sipExportedModuleDef *em); +static sipWrapperType *convertSubClass(sipWrapperType *type, void **cppPtr); +static void *getPtrTypeDef(sipWrapper *self, sipTypeDef **td); +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 addEnumInstances(PyObject *dict, sipEnumInstanceDef *ei); +static int addSingleEnumInstance(PyObject *dict, const char *name, int value, + PyTypeObject *type); +static int addClassInstances(PyObject *dict, sipClassInstanceDef *ci); +static int addSingleClassInstance(PyObject *dict, const char *name, + void *cppPtr, sipWrapperType *wt, int initflags); +static int addLicense(PyObject *dict, sipLicenseDef *lc); +static PyObject *cast(PyObject *self, PyObject *args); +static PyObject *callDtor(PyObject *self, PyObject *args); +static PyObject *isDeleted(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 *transfer(PyObject *self, PyObject *args); +static PyObject *transferBack(PyObject *self, PyObject *args); +static PyObject *transferTo(PyObject *self, PyObject *args); +static int sipWrapperType_Check(PyObject *op); +static void addToParent(sipWrapper *self, sipWrapper *owner); +static void removeFromParent(sipWrapper *self); +static sipWrapperType *findClass(sipExportedModuleDef *emd, const char *name, + size_t len); +static int findClassArg(sipExportedModuleDef *emd, const char *name, + size_t len, sipSigArg *at, int indir); +static int findMtypeArg(sipMappedType **mttab, const char *name, size_t len, + sipSigArg *at, int indir); +static PyTypeObject *findEnum(sipExportedModuleDef *emd, const char *name, + size_t len); +static int findEnumArg(sipExportedModuleDef *emd, const char *name, size_t len, + sipSigArg *at, int indir); +static int sameScopedName(const char *pyname, const char *name, size_t len); +static int nameEq(const char *with, const char *name, size_t len); +static int isExactWrappedType(sipWrapperType *wt); +static void release(void *addr, sipTypeDef *td, int state); +static void callPyDtor(sipWrapper *self); +static int qt_and_sip_api_3_4(void); +static int visitSlot(sipSlot *slot, visitproc visit, void *arg); +static void clearAnyLambda(sipSlot *slot); +static int parseCharArray(PyObject *obj, char **ap, int *aszp); +static int parseChar(PyObject *obj, char *ap); +static int parseCharString(PyObject *obj, char **ap); +#if defined(HAVE_WCHAR_H) +static int parseWCharArray(PyObject *obj, wchar_t **ap, int *aszp); +static int parseWChar(PyObject *obj, wchar_t *ap); +static int parseWCharString(PyObject *obj, wchar_t **ap); +#else +static void raiseNoWChar(); +#endif + + +/* + * The Python module initialisation function. + */ +#if defined(SIP_STATIC_MODULE) +void initsip(void) +#else +PyMODINIT_FUNC initsip(void) +#endif +{ + static PyMethodDef methods[] = { + {"cast", cast, METH_VARARGS, NULL}, + {"delete", callDtor, METH_VARARGS, NULL}, + {"isdeleted", isDeleted, METH_VARARGS, NULL}, + {"setdeleted", setDeleted, METH_VARARGS, NULL}, + {"settracemask", setTraceMask, METH_VARARGS, NULL}, + {"transfer", transfer, 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} + }; + + int rc; + PyObject *mod, *mod_dict, *obj; + +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + + /* Initialise the types. */ + sipWrapperType_Type.tp_base = &PyType_Type; + + if (PyType_Ready(&sipWrapperType_Type) < 0) + Py_FatalError("sip: Failed to initialise sip.wrappertype type"); + + if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0) + Py_FatalError("sip: Failed to initialise sip.wrapper type"); + + if (PyType_Ready(&sipVoidPtr_Type) < 0) + Py_FatalError("sip: Failed to initialise sip.voidptr type"); + + mod = Py_InitModule("sip", methods); + mod_dict = PyModule_GetDict(mod); + + /* Publish the SIP API. */ + if ((obj = PyCObject_FromVoidPtr((void *)&sip_api, NULL)) == NULL) + Py_FatalError("sip: Failed to create _C_API object"); + + rc = PyDict_SetItemString(mod_dict, "_C_API", obj); + Py_DECREF(obj); + + if (rc < 0) + Py_FatalError("sip: Failed to add _C_API object to module dictionary"); + + /* Add the SIP version number, but don't worry about errors. */ + if ((obj = PyInt_FromLong(SIP_VERSION)) != NULL) + { + PyDict_SetItemString(mod_dict, "SIP_VERSION", obj); + Py_DECREF(obj); + } + + if ((obj = PyString_FromString(SIP_VERSION_STR)) != NULL) + { + PyDict_SetItemString(mod_dict, "SIP_VERSION_STR", obj); + Py_DECREF(obj); + } + + /* Add the type objects, but don't worry about errors. */ + PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type); + PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type); + PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type); + + /* Initialise the module if it hasn't already been done. */ + if (sipInterpreter == NULL) + { + Py_AtExit(finalise); + + /* Initialise the object map. */ + sipOMInit(&cppPyMap); + + sipQtSupport = NULL; + + /* + * Get the current interpreter. This will be shared between all + * threads. + */ + sipInterpreter = PyThreadState_Get()->interp; + } +} + + +/* + * Display a printf() style message to stderr according to the current trace + * mask. + */ +static void sip_api_trace(unsigned mask, const char *fmt, ...) +{ + va_list ap; + + va_start(ap,fmt); + + if (mask & traceMask) + vfprintf(stderr, fmt, ap); + + va_end(ap); +} + + +/* + * Set the trace mask. + */ +static PyObject *setTraceMask(PyObject *self, PyObject *args) +{ + unsigned new_mask; + + if (PyArg_ParseTuple(args, "I:settracemask", &new_mask)) + { + traceMask = new_mask; + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Transfer the ownership of an instance to C/C++. + */ +static PyObject *transferTo(PyObject *self, PyObject *args) +{ + PyObject *w, *owner; + + if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner)) + { + if (owner == Py_None) + owner = NULL; + else if (!sip_api_wrapper_check(owner)) + { + PyErr_Format(PyExc_TypeError, "transferto() argument 2 must be sip.wrapper, not %s", owner->ob_type->tp_name); + return NULL; + } + + sip_api_transfer_to(w, owner); + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Transfer the ownership of an instance to Python. + */ +static PyObject *transferBack(PyObject *self, PyObject *args) +{ + PyObject *w; + + if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w)) + { + sip_api_transfer_back(w); + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Transfer the ownership of an instance. This is deprecated. + */ +static PyObject *transfer(PyObject *self, PyObject *args) +{ + PyObject *w; + int toCpp; + + if (PyArg_ParseTuple(args, "O!i:transfer", &sipWrapper_Type, &w, &toCpp)) + { + if (toCpp) + sip_api_transfer_to(w, NULL); + else + sip_api_transfer_back(w); + + Py_INCREF(Py_None); + return Py_None; + } + + return NULL; +} + + +/* + * Cast an instance to one of it's sub or super-classes by returning a new + * Python object with the superclass type wrapping the same C++ instance. + */ +static PyObject *cast(PyObject *self, PyObject *args) +{ + sipWrapper *w; + sipWrapperType *wt, *type; + void *addr; + PyTypeObject *ft, *tt; + + if (!PyArg_ParseTuple(args, "O!O!:cast", &sipWrapper_Type, &w, &sipWrapperType_Type, &wt)) + return NULL; + + ft = ((PyObject *)w)->ob_type; + tt = (PyTypeObject *)wt; + + if (ft == tt || PyType_IsSubtype(tt, ft)) + type = NULL; + else if (PyType_IsSubtype(ft, tt)) + type = wt; + else + { + PyErr_SetString(PyExc_TypeError, "argument 1 of sip.cast() must be an instance of a sub or super-type of argument 2"); + return NULL; + } + + if ((addr = sip_api_get_cpp_ptr(w, type)) == NULL) + return NULL; + + /* + * We don't put this new object into the map so that the original object is + * always found. It would also totally confuse the map logic. + */ + return sipWrapSimpleInstance(addr, wt, NULL, (w->flags | SIP_NOT_IN_MAP) & ~SIP_PY_OWNED); +} + + +/* + * Call an instance's dtor. + */ +static PyObject *callDtor(PyObject *self, PyObject *args) +{ + sipWrapper *w; + void *addr; + sipTypeDef *td; + + if (!PyArg_ParseTuple(args, "O!:delete", &sipWrapper_Type, &w)) + return NULL; + + addr = getPtrTypeDef(w, &td); + + if (checkPointer(addr) < 0) + return NULL; + + /* + * Transfer ownership to C++ so we don't try to release it again when the + * Python object is garbage collected. + */ + removeFromParent(w); + sipResetPyOwned(w); + + release(addr, td, w->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) +{ + sipWrapper *w; + PyObject *res; + + if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipWrapper_Type, &w)) + return NULL; + + res = (sipGetAddress(w) == NULL ? Py_True : Py_False); + + Py_INCREF(res); + return res; +} + + +/* + * Mark an instance as having been deleted. + */ +static PyObject *setDeleted(PyObject *self, PyObject *args) +{ + sipWrapper *w; + + if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipWrapper_Type, &w)) + return NULL; + + /* + * Transfer ownership to C++ so we don't try to release it when the Python + * object is garbage collected. + */ + removeFromParent(w); + sipResetPyOwned(w); + + w->u.cppPtr = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Unwrap an instance. + */ +static PyObject *unwrapInstance(PyObject *self, PyObject *args) +{ + sipWrapper *w; + + if (PyArg_ParseTuple(args, "O!:unwrapinstance", &sipWrapper_Type, &w)) + { + 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(w, NULL)) == NULL) + return NULL; + + return PyLong_FromVoidPtr(addr); + } + + return NULL; +} + + +/* + * Wrap an instance. + */ +static PyObject *wrapInstance(PyObject *self, PyObject *args) +{ + unsigned long addr; + sipWrapperType *wt; + + if (PyArg_ParseTuple(args, "kO!:wrapinstance", &addr, &sipWrapperType_Type, &wt)) + return sip_api_convert_from_instance((void *)addr, wt, NULL); + + return NULL; +} + + +/* + * Register a client module. A negative value is returned and an exception + * raised if there was an error. Not normally needed by handwritten code. + */ +static int sip_api_export_module(sipExportedModuleDef *client, + unsigned api_major, unsigned api_minor, PyObject *mod_dict) +{ + sipExportedModuleDef *em; + sipImportedModuleDef *im; + sipSubClassConvertorDef *scc; + sipWrapperType **mw; + sipEnumMemberDef *emd; + sipInitExtenderDef *ie; + int i; + + /* 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 supports 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, client->em_name, api_major,api_minor); +#else + PyErr_Format(PyExc_RuntimeError, "the sip module supports API v%d.0 but the %s module requires API v%d.%d", SIP_API_MAJOR_NR, client->em_name, api_major,api_minor); +#endif + + return -1; + } + + /* Convert the module name to an object. */ + if ((client->em_nameobj = PyString_FromString(client->em_name)) == NULL) + return -1; + + for (em = clientList; em != NULL; em = em->em_next) + { + /* SIP clients must have unique names. */ + if (strcmp(em->em_name, client->em_name) == 0) + { + PyErr_Format(PyExc_RuntimeError, "the sip module has already registered a module called %s", client->em_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", client->em_name, em->em_name); + + return -1; + } + } + + /* Import any required modules. */ + if ((im = client->em_imports) != NULL) + { + while (im->im_name != NULL) + { + PyObject *mod; + + if ((mod = PyImport_ImportModule(im->im_name)) == NULL) + return -1; + + for (em = clientList; em != NULL; em = em->em_next) + if (strcmp(em->em_name, im->im_name) == 0) + break; + + if (em == NULL) + { + PyErr_Format(PyExc_RuntimeError, "the %s module failed to register with the sip module", im->im_name); + + return -1; + } + + /* Check the versions are compatible. */ + if (im->im_version >= 0 || em->em_version >= 0) + if (im->im_version != em->em_version) + { + PyErr_Format(PyExc_RuntimeError, "the %s module is version %d but the %s module requires version %d", em->em_name, em->em_version, client->em_name, im->im_version); + + return -1; + } + + /* Save the imported module. */ + im->im_module = em; + + ++im; + } + } + + /* Create the module's classes. */ + if ((mw = client->em_types) != NULL) + for (i = 0; i < client->em_nrtypes; ++i, ++mw) + { + sipTypeDef *td = (sipTypeDef *)*mw; + + /* Skip external classes. */ + if (td == NULL) + continue; + + /* See if this is a namespace extender. */ + if (td->td_name == NULL) + { + sipTypeDef **last; + sipWrapperType *wt = getClassType(&td->td_scope, client); + + /* Append this type to the real one. */ + last = &wt->type->td_nsextender; + + while (*last != NULL) + last = &(*last)->td_nsextender; + + *last = td; + + /* + * Set this so that the extender's original + * module can be found. + */ + td->td_module = client; + + /* + * Save the real namespace type so that it is + * the correct scope for any enums or classes + * defined in this module. + */ + *mw = wt; + } + else if ((*mw = createType(client, td, mod_dict)) == NULL) + return -1; + } + + /* Set any Qt support API. */ + if (client->em_qt_api != NULL) + { + sipQtSupport = client->em_qt_api; + sipQObjectClass = *sipQtSupport->qt_qobject; + } + + /* Append any initialiser extenders to the relevant classes. */ + if ((ie = client->em_initextend) != NULL) + while (ie->ie_extender != NULL) + { + sipWrapperType *wt = getClassType(&ie->ie_class, client); + + ie->ie_next = wt->iextend; + wt->iextend = ie; + + ++ie; + } + + /* Set the base class object for any sub-class convertors. */ + if ((scc = client->em_convertors) != NULL) + while (scc->scc_convertor != NULL) + { + scc->scc_basetype = getClassType(&scc->scc_base, client); + + ++scc; + } + + /* Create the module's enums. */ + if (client->em_nrenums != 0) + { + if ((client->em_enums = sip_api_malloc(client->em_nrenums * sizeof (PyTypeObject *))) == NULL) + return -1; + + for (i = 0; i < client->em_nrenums; ++i) + if ((client->em_enums[i] = createEnum(client, &client->em_enumdefs[i], mod_dict)) == NULL) + return -1; + } + + for (emd = client->em_enummembers, i = 0; i < client->em_nrenummembers; ++i, ++emd) + { + PyObject *mo; + + if ((mo = sip_api_convert_from_named_enum(emd->em_val, client->em_enums[emd->em_enum])) == NULL) + return -1; + + if (PyDict_SetItemString(mod_dict, emd->em_name, mo) < 0) + return -1; + + Py_DECREF(mo); + } + + + /* + * Add any class static instances. We need to do this once all types are + * fully formed because of potential interdependencies. + */ + if ((mw = client->em_types) != NULL) + for (i = 0; i < client->em_nrtypes; ++i) + { + sipWrapperType *wt; + + if ((wt = *mw++) != NULL && addInstances(((PyTypeObject *)wt)->tp_dict, &wt->type->td_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 = clientList; em != NULL; em = em->em_next) + { + sipExternalTypeDef *etd; + + if (em->em_external == NULL) + continue; + + for (etd = em->em_external; etd->et_nr >= 0; ++etd) + { + if (etd->et_name == NULL) + continue; + + mw = client->em_types; + + for (i = 0; i < client->em_nrtypes; ++i) + { + sipWrapperType *wt; + const char *tname; + + if ((wt = *mw++) == NULL) + continue; + + tname = strchr(wt->type->td_name, '.') + 1; + + if (strcmp(etd->et_name, tname) == 0) + { + em->em_types[etd->et_nr] = wt; + etd->et_name = NULL; + + break; + } + } + } + } + + /* Add to the list of client modules. */ + client->em_next = clientList; + clientList = client; + + return 0; +} + + +/* + * Called by the interpreter to do any final clearing up, just in case the + * interpreter will re-start. + */ +static void finalise(void) +{ + sipExportedModuleDef *em; + + /* Mark the Python API as unavailable. */ + sipInterpreter = NULL; + + /* Handle any delayed dtors. */ + for (em = clientList; 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. */ + clientList = NULL; +} + + +/* + * Add a wrapped C/C++ pointer to the list of delayed dtors. + */ +static void sip_api_add_delayed_dtor(sipWrapper *w) +{ + void *ptr; + sipTypeDef *td; + sipExportedModuleDef *em; + + if ((ptr = getPtrTypeDef(w, &td)) == NULL) + return; + + /* Find the defining module. */ + for (em = clientList; em != NULL; em = em->em_next) + { + int i; + + for (i = 0; i < em->em_nrtypes; ++i) + if (em->em_types[i] != NULL && em->em_types[i]->type == td) + { + sipDelayedDtor *dd; + + if ((dd = sip_api_malloc(sizeof (sipDelayedDtor))) == NULL) + return; + + /* Add to the list. */ + dd->dd_ptr = ptr; + dd->dd_name = getBaseName(td->td_name); + dd->dd_isderived = sipIsDerived(w); + dd->dd_next = em->em_ddlist; + + em->em_ddlist = dd; + + return; + } + } +} + + +/* + * A wrapper around the Python memory allocater that will raise an exception if + * if the allocation fails. + */ +void *sip_api_malloc(size_t nbytes) +{ + void *mem; + + if ((mem = PyMem_Malloc(nbytes)) == NULL) + PyErr_NoMemory(); + + return mem; +} + + +/* + * A wrapper around the Python memory de-allocater. + */ +void sip_api_free(void *mem) +{ + PyMem_Free(mem); +} + + +/* + * Extend a Python slot by looking in other modules to see if there is an + * extender function that can handle the arguments. + */ +static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, + sipPySlotType st, sipWrapperType *type, + PyObject *arg0, PyObject *arg1) +{ + sipExportedModuleDef *em; + + /* Go through each module. */ + for (em = clientList; 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 (type != NULL && type != getClassType(&ex->pse_class, NULL)) + continue; + + PyErr_Clear(); + + res = ((binaryfunc)ex->pse_func)(arg0, arg1); + + if (res != Py_NotImplemented) + return res; + } + } + + /* The arguments couldn't handled anywhere. */ + PyErr_Clear(); + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +/* + * Call the Python re-implementation of a C++ virtual. + */ +static PyObject *sip_api_call_method(int *isErr, PyObject *method, + const char *fmt, ...) +{ + PyObject *args, *res; + va_list va; + + va_start(va,fmt); + + if ((args = PyTuple_New(strlen(fmt))) != NULL && buildObject(args,fmt,va) != NULL) + res = PyEval_CallObject(method,args); + else + { + res = NULL; + + if (isErr != NULL) + *isErr = TRUE; + } + + Py_XDECREF(args); + + va_end(va); + + return res; +} + + +/* + * Build a result object based on a format string. + */ +static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...) +{ + PyObject *res = NULL; + int badfmt, tupsz; + va_list va; + + va_start(va,fmt); + + /* Basic validation of the format string. */ + + badfmt = FALSE; + + if (*fmt == '(') + { + char *ep; + + if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0') + badfmt = TRUE; + else + tupsz = ep - fmt - 1; + } + else if (strlen(fmt) == 1) + tupsz = -1; + else + badfmt = TRUE; + + if (badfmt) + PyErr_Format(PyExc_SystemError,"sipBuildResult(): invalid format string \"%s\"",fmt); + else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL) + res = buildObject(res,fmt,va); + + va_end(va); + + if (res == NULL && isErr != NULL) + *isErr = TRUE; + + return res; +} + + +/* + * Get the values off the stack and put them into an object. + */ +static PyObject *buildObject(PyObject *obj, const char *fmt, va_list va) +{ + char ch, termch; + int i; + + /* + * The format string has already been checked that it is properly + * formed if it is enclosed in parenthesis. + */ + if (*fmt == '(') + { + termch = ')'; + ++fmt; + } + else + termch = '\0'; + + i = 0; + + while ((ch = *fmt++) != termch) + { + PyObject *el; + + switch (ch) + { + case 'a': + { + char *s; + int l; + + s = va_arg(va, char *); + l = va_arg(va, int); + + if (s != NULL) + el = PyString_FromStringAndSize(s, (SIP_SSIZE_T)l); + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } + + break; + + case 'A': +#if defined(HAVE_WCHAR_H) + { + wchar_t *s; + int l; + + s = va_arg(va, wchar_t *); + l = va_arg(va, int); + + if (s != NULL) + el = PyUnicode_FromWideChar(s, (SIP_SSIZE_T)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 = PyString_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': + el = PyInt_FromLong(va_arg(va,int)); + break; + + case 'E': + { + int ev = va_arg(va, int); + PyTypeObject *et = va_arg(va, PyTypeObject *); + + el = sip_api_convert_from_named_enum(ev, et); + } + + break; + + case 'd': + case 'f': + el = PyFloat_FromDouble(va_arg(va,double)); + break; + + case 'h': + case 'i': + el = PyInt_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 = PyString_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, (SIP_SSIZE_T)wcslen(s)); + else + { + Py_INCREF(Py_None); + el = Py_None; + } + } +#else + raiseNoWChar(); + el = NULL; +#endif + + break; + + case 't': + case 'u': + el = PyLong_FromUnsignedLong(va_arg(va, unsigned)); + break; + + case 'B': + { + void *p = va_arg(va,void *); + sipWrapperType *wt = va_arg(va, sipWrapperType *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_new_instance(p, wt, 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_instance(p, wt, xfer); + } + + break; + + case 'D': + { + void *p = va_arg(va, void *); + const sipMappedType *mt = va_arg(va, const sipMappedType *); + PyObject *xfer = va_arg(va, PyObject *); + + el = sip_api_convert_from_mapped_type(p, mt, xfer); + } + + break; + + case 'M': + case 'O': + { + void *sipCpp = va_arg(va,void *); + sipWrapperType *wt = va_arg(va,sipWrapperType *); + + el = sip_api_convert_from_instance(sipCpp,wt,NULL); + } + + break; + + case 'N': + case 'P': + { + void *sipCpp = va_arg(va,void *); + sipWrapperType *wt = va_arg(va,sipWrapperType *); + + el = sip_api_convert_from_new_instance(sipCpp,wt,NULL); + } + + break; + + case 'R': + el = va_arg(va,PyObject *); + break; + + case 'S': + el = va_arg(va,PyObject *); + Py_INCREF(el); + break; + + case 'T': + { + void *sipCpp = va_arg(va,void *); + sipConvertFromFunc func = va_arg(va,sipConvertFromFunc); + + el = func(sipCpp, NULL); + } + + break; + + case 'V': + el = sip_api_convert_from_void_ptr(va_arg(va,void *)); + break; + + default: + PyErr_Format(PyExc_SystemError,"buildObject(): invalid format character '%c'",ch); + el = NULL; + } + + if (el == NULL) + { + Py_XDECREF(obj); + return NULL; + } + + if (obj == NULL) + return el; + + PyTuple_SET_ITEM(obj,i,el); + ++i; + } + + return obj; +} + + +/* + * Parse a result object based on a format string. + */ +static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res, + const char *fmt, ...) +{ + int tupsz, rc = 0; + va_list va; + + va_start(va,fmt); + + /* Basic validation of the format string. */ + + if (*fmt == '(') + { + char *ep; + + if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0') + { + PyErr_Format(PyExc_SystemError, "sipParseResult(): invalid format string \"%s\"", fmt); + rc = -1; + } + else + { + tupsz = ep - ++fmt; + + if (tupsz >= 0 && (!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 'a': + { + char **p = va_arg(va, char **); + int *szp = va_arg(va, int *); + + if (parseCharArray(arg, p, szp) < 0) + invalid = TRUE; + } + + break; + + case 'A': +#if defined(HAVE_WCHAR_H) + { + wchar_t **p = va_arg(va, wchar_t **); + int *szp = va_arg(va, int *); + + if (parseWCharArray(arg, p, szp) < 0) + invalid = TRUE; + } +#else + raiseNoWChar(); + invalid = TRUE; +#endif + + break; + + case 'b': + { + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + sipSetBool(va_arg(va,void *),v); + } + + break; + + case 'c': + { + char *p = va_arg(va, char *); + + if (parseChar(arg, p) < 0) + invalid = TRUE; + } + + break; + + case 'w': +#if defined(HAVE_WCHAR_H) + { + wchar_t *p = va_arg(va, wchar_t *); + + if (parseWChar(arg, p) < 0) + invalid = TRUE; + } +#else + raiseNoWChar(); + invalid = TRUE; +#endif + + break; + + case 'd': + { + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,double *) = v; + } + + break; + + case 'e': + { + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,int *) = v; + } + + break; + + case 'E': + { + PyTypeObject *et = va_arg(va, PyTypeObject *); + int *p = va_arg(va, int *); + + if (PyObject_TypeCheck(arg, et)) + *p = PyInt_AsLong(arg); + else + invalid = TRUE; + } + + break; + + case 'f': + { + float v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,float *) = v; + } + + break; + + case 'h': + { + short v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,short *) = v; + } + + break; + + case 't': + { + unsigned short v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,unsigned short *) = v; + } + + break; + + case 'i': + { + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,int *) = v; + } + + break; + + case 'u': + { + unsigned v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,unsigned *) = v; + } + + break; + + case 'l': + { + long v = PyLong_AsLong(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,long *) = v; + } + + break; + + case 'm': + { + unsigned long v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va, unsigned long *) = v; + } + + break; + + case 'n': + { +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG v = PyLong_AsLongLong(arg); +#else + long v = PyLong_AsLong(arg); +#endif + + if (PyErr_Occurred()) + invalid = TRUE; + else +#if defined(HAVE_LONG_LONG) + *va_arg(va, PY_LONG_LONG *) = v; +#else + *va_arg(va, long *) = v; +#endif + } + + break; + + case 'o': + { +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg); +#else + unsigned long v = PyLong_AsUnsignedLong(arg); +#endif + + if (PyErr_Occurred()) + invalid = TRUE; + else +#if defined(HAVE_LONG_LONG) + *va_arg(va, unsigned PY_LONG_LONG *) = v; +#else + *va_arg(va, unsigned long *) = v; +#endif + } + + break; + + case 's': + { + char **p = va_arg(va, char **); + + if (parseCharString(arg, p) < 0) + invalid = TRUE; + } + + 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 & FORMAT_NO_STATE) + state = NULL; + else + state = va_arg(va, int *); + + cpp = va_arg(va, void **); + + *cpp = sip_api_force_convert_to_instance(arg, type, (flags & FORMAT_FACTORY ? arg : NULL), (flags & FORMAT_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 sipMappedType *mt; + void **cpp; + int *state; + + mt = va_arg(va, const sipMappedType *); + + if (flags & FORMAT_NO_STATE) + state = NULL; + else + state = va_arg(va, int *); + + cpp = va_arg(va, void **); + + *cpp = sip_api_force_convert_to_mapped_type(arg, mt, (flags & FORMAT_FACTORY ? arg : NULL), (flags & FORMAT_DEREF ? SIP_NOT_NONE : 0), state, &iserr); + + if (iserr) + invalid = TRUE; + } + } + + break; + + case 'L': + { + sipForceConvertToFunc func = va_arg(va,sipForceConvertToFunc); + void **sipCpp = va_arg(va,void **); + int iserr = FALSE; + + *sipCpp = func(arg,&iserr); + + if (iserr) + invalid = TRUE; + } + + break; + + case 'M': + { + sipForceConvertToFunc func = va_arg(va,sipForceConvertToFunc); + void **sipCpp = va_arg(va,void **); + int iserr = FALSE; + + *sipCpp = func(arg,&iserr); + + if (iserr || *sipCpp == NULL) + invalid = TRUE; + } + + break; + + case 'N': + { + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (arg == Py_None || PyObject_TypeCheck(arg,type)) + { + Py_INCREF(arg); + *p = arg; + } + else + invalid = TRUE; + } + + break; + + case 'O': + Py_INCREF(arg); + *va_arg(va,PyObject **) = arg; + break; + + case 'T': + { + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (PyObject_TypeCheck(arg,type)) + { + Py_INCREF(arg); + *p = arg; + } + else + invalid = TRUE; + } + + break; + + case 'V': + { + void *v = sip_api_convert_to_void_ptr(arg); + + if (PyErr_Occurred()) + invalid = TRUE; + else + *va_arg(va,void **) = v; + } + + break; + + case 'Z': + if (arg != Py_None) + invalid = TRUE; + + break; + + default: + PyErr_Format(PyExc_SystemError,"sipParseResult(): invalid format character '%c'",ch); + rc = -1; + } + + if (invalid) + { + sip_api_bad_catcher_result(method); + rc = -1; + break; + } + } + } + + va_end(va); + + if (isErr != NULL && rc < 0) + *isErr = TRUE; + + return rc; +} + + +/* + * A thin wrapper around PyLong_AsUnsignedLong() that works around a bug in + * Python versions prior to v2.4 where an integer (or a named enum) causes an + * error. + */ +static unsigned long sip_api_long_as_unsigned_long(PyObject *o) +{ +#if PY_VERSION_HEX < 0x02040000 + if (o != NULL && !PyLong_Check(o) && PyInt_Check(o)) + { + long v = PyInt_AsLong(o); + + if (v < 0) + { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned long"); + + return (unsigned long)-1; + } + + return v; + } +#endif + + return PyLong_AsUnsignedLong(o); +} + + +/* + * Parse the arguments to a C/C++ function without any side effects. + */ +static int sip_api_parse_args(int *argsParsedp, PyObject *sipArgs, + const char *fmt, ...) +{ + int valid, nrargs, selfarg; + sipWrapper *self; + PyObject *single_arg; + va_list va; + + /* Previous sticky errors stop subsequent parses. */ + if (*argsParsedp & PARSE_STICKY) + return 0; + + /* See if we are parsing a tuple or a single argument. */ + if (PyTuple_Check(sipArgs)) + { + Py_INCREF(sipArgs); + nrargs = PyTuple_GET_SIZE(sipArgs); + } + else if ((single_arg = PyTuple_New(1)) != NULL) + { + Py_INCREF(sipArgs); + PyTuple_SET_ITEM(single_arg,0,sipArgs); + + sipArgs = single_arg; + nrargs = 1; + } + else + return 0; + + /* + * The first pass checks all the types and does conversions that are + * cheap and have no side effects. + */ + va_start(va,fmt); + valid = parsePass1(&self,&selfarg,&nrargs,sipArgs,fmt,va); + va_end(va); + + if (valid != PARSE_OK) + { + int pvalid, pnrargs; + + /* + * Use this error if there was no previous error, or if we + * have parsed more arguments this time, or if the previous + * error was that there were too many arguments. + */ + pvalid = (*argsParsedp & PARSE_MASK); + pnrargs = (*argsParsedp & ~PARSE_MASK); + + if (pvalid == PARSE_OK || pnrargs < nrargs || + (pnrargs == nrargs && pvalid == PARSE_MANY)) + *argsParsedp = valid | nrargs; + + Py_DECREF(sipArgs); + + return 0; + } + + /* + * The second pass does any remaining conversions now that we know we + * have the right signature. + */ + va_start(va,fmt); + valid = parsePass2(self,selfarg,nrargs,sipArgs,fmt,va); + va_end(va); + + if (valid != PARSE_OK) + { + *argsParsedp = valid | PARSE_STICKY; + + Py_DECREF(sipArgs); + + return 0; + } + + *argsParsedp = nrargs; + + Py_DECREF(sipArgs); + + return 1; +} + + +/* + * Parse a pair of arguments to a C/C++ function without any side effects. + */ +static int sip_api_parse_pair(int *argsParsedp, PyObject *sipArg0, + PyObject *sipArg1, const char *fmt, ...) +{ + int valid, nrargs, selfarg; + sipWrapper *self; + PyObject *args; + va_list va; + + /* Previous sticky errors stop subsequent parses. */ + if (*argsParsedp & PARSE_STICKY) + return 0; + + if ((args = PyTuple_New(2)) == NULL) + return 0; + + Py_INCREF(sipArg0); + PyTuple_SET_ITEM(args, 0, sipArg0); + + Py_INCREF(sipArg1); + PyTuple_SET_ITEM(args, 1, sipArg1); + + nrargs = 2; + + /* + * The first pass checks all the types and does conversions that are + * cheap and have no side effects. + */ + va_start(va,fmt); + valid = parsePass1(&self,&selfarg,&nrargs,args,fmt,va); + va_end(va); + + if (valid != PARSE_OK) + { + int pvalid, pnrargs; + + /* + * Use this error if there was no previous error, or if we + * have parsed more arguments this time, or if the previous + * error was that there were too many arguments. + */ + pvalid = (*argsParsedp & PARSE_MASK); + pnrargs = (*argsParsedp & ~PARSE_MASK); + + if (pvalid == PARSE_OK || pnrargs < nrargs || + (pnrargs == nrargs && pvalid == PARSE_MANY)) + *argsParsedp = valid | nrargs; + + Py_DECREF(args); + + return 0; + } + + /* + * The second pass does any remaining conversions now that we know we + * have the right signature. + */ + va_start(va,fmt); + valid = parsePass2(self,selfarg,nrargs,args,fmt,va); + va_end(va); + + if (valid != PARSE_OK) + { + *argsParsedp = valid | PARSE_STICKY; + + Py_DECREF(args); + + return 0; + } + + *argsParsedp = nrargs; + + Py_DECREF(args); + + return 1; +} + + +/* + * First pass of the argument parse, converting those that can be done so + * without any side effects. Return PARSE_OK if the arguments matched. + */ +static int parsePass1(sipWrapper **selfp, int *selfargp, int *argsParsedp, + PyObject *sipArgs, const char *fmt, va_list va) +{ + int valid, compulsory, nrargs, argnr, nrparsed; + + valid = PARSE_OK; + nrargs = *argsParsedp; + nrparsed = 0; + compulsory = TRUE; + argnr = 0; + + /* + * Handle those format characters that deal with the "self" argument. + * They will always be the first one. + */ + *selfp = NULL; + *selfargp = FALSE; + + switch (*fmt++) + { + case 'B': + case 'p': + { + PyObject *self; + sipWrapperType *type; + + self = *va_arg(va,PyObject **); + type = va_arg(va,sipWrapperType *); + va_arg(va,void **); + + if (self == NULL) + { + if ((valid = getSelfFromArgs(type,sipArgs,argnr,selfp)) != PARSE_OK) + break; + + *selfargp = TRUE; + ++nrparsed; + ++argnr; + } + else + *selfp = (sipWrapper *)self; + + break; + } + + case 'C': + *selfp = (sipWrapper *)va_arg(va,PyObject *); + break; + + default: + --fmt; + } + + /* Now handle the remaining arguments. */ + while (valid == PARSE_OK) + { + char ch; + PyObject *arg; + + PyErr_Clear(); + + /* See if the following arguments are optional. */ + if ((ch = *fmt++) == '|') + { + compulsory = FALSE; + ch = *fmt++; + } + + /* See if we don't expect anything else. */ + + if (ch == '\0') + { + /* Invalid if there are still arguments. */ + if (argnr < nrargs) + valid = PARSE_MANY; + + break; + } + + /* See if we have run out of arguments. */ + + if (argnr == nrargs) + { + /* + * It is an error if we are still expecting compulsory + * arguments unless the current argume is an ellipsis. + */ + if (ch != 'W' && ch != '\0' && compulsory) + valid = PARSE_FEW; + + break; + } + + /* Get the next argument. */ + arg = PyTuple_GET_ITEM(sipArgs,argnr); + ++argnr; + + switch (ch) + { + case 'W': + /* Ellipsis. */ + break; + + case 's': + { + /* String or None. */ + + char **p = va_arg(va, char **); + + if (parseCharString(arg, p) < 0) + valid = PARSE_TYPE; + + break; + } + + case 'x': +#if defined(HAVE_WCHAR_H) + { + /* Wide string or None. */ + + wchar_t **p = va_arg(va, wchar_t **); + + if (parseWCharString(arg, p) < 0) + valid = PARSE_TYPE; + + break; + } +#else + raiseNoWChar(); + valid = PARSE_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 **); + + *sname = NULL; + *scall = NULL; + + if (PyString_Check(arg)) + { + char *s = PyString_AS_STRING(arg); + + if (*s == '1' || *s == '2' || *s == '9') + *sname = s; + else + valid = PARSE_TYPE; + } + else if (PyCallable_Check(arg)) + *scall = arg; + else if (arg != Py_None) + valid = PARSE_TYPE; + + break; + } + + case 'S': + { + /* Slot name, return the name. */ + + if (PyString_Check(arg)) + { + char *s = PyString_AS_STRING(arg); + + if (*s == '1' || *s == '2' || *s == '9') + *va_arg(va,char **) = s; + else + valid = PARSE_TYPE; + } + else + valid = PARSE_TYPE; + + break; + } + + case 'G': + { + /* Signal name, return the name. */ + + if (PyString_Check(arg)) + { + char *s = PyString_AS_STRING(arg); + + if (*s == '2' || *s == '9') + *va_arg(va,char **) = s; + else + valid = PARSE_TYPE; + } + else + valid = PARSE_TYPE; + + break; + } + + case 'J': + { + /* Class instance. */ + + if (*fmt == '\0') + valid = PARSE_FORMAT; + else + { + int flags = *fmt++ - '0'; + sipWrapperType *type; + int iflgs = 0; + + type = va_arg(va,sipWrapperType *); + va_arg(va,void **); + + if (flags & FORMAT_DEREF) + iflgs |= SIP_NOT_NONE; + + if (flags & (FORMAT_GET_WRAPPER|FORMAT_TRANSFER_THIS)) + va_arg(va,PyObject **); + + if (flags & FORMAT_NO_CONVERTORS) + iflgs |= SIP_NO_CONVERTORS; + else + va_arg(va, int *); + + if (!sip_api_can_convert_to_instance(arg, type, iflgs)) + valid = PARSE_TYPE; + } + + break; + } + + case 'M': + { + /* Mapped type instance. */ + + if (*fmt == '\0') + valid = PARSE_FORMAT; + else + { + int flags = *fmt++ - '0'; + sipMappedType *mt; + int iflgs = 0; + + mt = va_arg(va, sipMappedType *); + va_arg(va, void **); + va_arg(va, int *); + + if (flags & FORMAT_DEREF) + iflgs |= SIP_NOT_NONE; + + if (!sip_api_can_convert_to_mapped_type(arg, mt, iflgs)) + valid = PARSE_TYPE; + } + + break; + } + + + case 'N': + { + /* Python object of given type or None. */ + + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (arg == Py_None || PyObject_TypeCheck(arg,type)) + *p = arg; + else + valid = PARSE_TYPE; + + break; + } + + case 'P': + { + /* + * Python object of any type with a + * sub-format. + */ + + *va_arg(va,PyObject **) = arg; + + /* Skip the sub-format. */ + if (*fmt++ == '\0') + valid = PARSE_FORMAT; + + break; + } + + case 'T': + { + /* Python object of given type. */ + + PyTypeObject *type = va_arg(va,PyTypeObject *); + PyObject **p = va_arg(va,PyObject **); + + if (PyObject_TypeCheck(arg,type)) + *p = arg; + else + valid = PARSE_TYPE; + + break; + } + + case 'R': + { + /* Sub-class of QObject. */ + + if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass)) + valid = PARSE_TYPE; + else + *va_arg(va,PyObject **) = arg; + + break; + } + + case 'F': + { + /* Python callable object. */ + + if (PyCallable_Check(arg)) + *va_arg(va,PyObject **) = arg; + else + valid = PARSE_TYPE; + + break; + } + + case 'H': + { + /* Python callable object or None. */ + + if (arg == Py_None || PyCallable_Check(arg)) + *va_arg(va,PyObject **) = arg; + else + valid = PARSE_TYPE; + + break; + } + + case 'q': + { + /* Qt receiver to connect. */ + + va_arg(va,char *); + va_arg(va,void **); + va_arg(va,const char **); + + if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass)) + valid = PARSE_TYPE; + + break; + } + + case 'Q': + { + /* Qt receiver to disconnect. */ + + va_arg(va,char *); + va_arg(va,void **); + va_arg(va,const char **); + + if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass)) + valid = PARSE_TYPE; + + break; + } + + case 'y': + { + /* Python slot to connect. */ + + va_arg(va,char *); + va_arg(va,void **); + va_arg(va,const char **); + + if (sipQtSupport == NULL || !PyCallable_Check(arg)) + valid = PARSE_TYPE; + + break; + } + + case 'Y': + { + /* Python slot to disconnect. */ + + va_arg(va,char *); + va_arg(va,void **); + va_arg(va,const char **); + + if (sipQtSupport == NULL || !PyCallable_Check(arg)) + valid = PARSE_TYPE; + + break; + } + + case 'a': + { + /* Char array or None. */ + + char **p = va_arg(va, char **); + int *szp = va_arg(va, int *); + + if (parseCharArray(arg, p, szp) < 0) + valid = PARSE_TYPE; + + break; + } + + case 'A': +#if defined(HAVE_WCHAR_H) + { + /* Wide char array or None. */ + + wchar_t **p = va_arg(va, wchar_t **); + int *szp = va_arg(va, int *); + + if (parseWCharArray(arg, p, szp) < 0) + valid = PARSE_TYPE; + + break; + } +#else + raiseNoWChar(); + valid = PARSE_RAISED; + break +#endif + + case 'c': + { + /* Character. */ + + char *p = va_arg(va, char *); + + if (parseChar(arg, p) < 0) + valid = PARSE_TYPE; + + break; + } + + case 'w': +#if defined(HAVE_WCHAR_H) + { + /* Wide character. */ + + wchar_t *p = va_arg(va, wchar_t *); + + if (parseWChar(arg, p) < 0) + valid = PARSE_TYPE; + + break; + } +#else + raiseNoWChar(); + valid = PARSE_RAISED; + break +#endif + + case 'b': + { + /* Bool. */ + + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + sipSetBool(va_arg(va,void *),v); + + break; + } + + case 'e': + { + /* Anonymous enum. */ + + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,int *) = v; + + break; + } + + case 'E': + { + /* Named enum. */ + + PyTypeObject *et = va_arg(va, PyTypeObject *); + + va_arg(va, int *); + + if (!PyObject_TypeCheck(arg, et)) + valid = PARSE_TYPE; + } + + break; + + case 'i': + { + /* Integer. */ + + int v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,int *) = v; + + break; + } + + case 'u': + { + /* Unsigned integer. */ + + unsigned v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va, unsigned *) = v; + + break; + } + + case 'h': + { + /* Short integer. */ + + short v = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,short *) = v; + + break; + } + + case 't': + { + /* Unsigned short integer. */ + + unsigned short v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va, unsigned short *) = v; + + break; + } + + case 'l': + { + /* Long integer. */ + + long v = PyLong_AsLong(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,long *) = v; + + break; + } + + case 'm': + { + /* Unsigned long integer. */ + + unsigned long v = sip_api_long_as_unsigned_long(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va, unsigned long *) = v; + + break; + } + + case 'n': + { + /* Long long integer. */ + +#if defined(HAVE_LONG_LONG) + PY_LONG_LONG v = PyLong_AsLongLong(arg); +#else + long v = PyLong_AsLong(arg); +#endif + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else +#if defined(HAVE_LONG_LONG) + *va_arg(va, PY_LONG_LONG *) = v; +#else + *va_arg(va, long *) = v; +#endif + + break; + } + + case 'o': + { + /* Unsigned long long integer. */ + +#if defined(HAVE_LONG_LONG) + unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg); +#else + unsigned long v = PyLong_AsUnsignedLong(arg); +#endif + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else +#if defined(HAVE_LONG_LONG) + *va_arg(va, unsigned PY_LONG_LONG *) = v; +#else + *va_arg(va, unsigned long *) = v; +#endif + + break; + } + + case 'f': + { + /* Float. */ + + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,float *) = (float)v; + + break; + } + + case 'X': + { + /* Constrained (ie. exact) types. */ + + switch (*fmt++) + { + case 'b': + { + /* Boolean. */ + + if (PyBool_Check(arg)) + sipSetBool(va_arg(va,void *),(arg == Py_True)); + else + valid = PARSE_TYPE; + + break; + } + + case 'd': + { + /* Double float. */ + + if (PyFloat_Check(arg)) + *va_arg(va,double *) = PyFloat_AS_DOUBLE(arg); + else + valid = PARSE_TYPE; + + break; + } + + case 'f': + { + /* Float. */ + + if (PyFloat_Check(arg)) + *va_arg(va,float *) = (float)PyFloat_AS_DOUBLE(arg); + else + valid = PARSE_TYPE; + + break; + } + + case 'i': + { + /* Integer. */ + + if (PyInt_Check(arg)) + *va_arg(va,int *) = PyInt_AS_LONG(arg); + else + valid = PARSE_TYPE; + + break; + } + + default: + valid = PARSE_FORMAT; + } + + break; + } + + case 'd': + { + /* Double float. */ + + double v = PyFloat_AsDouble(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,double *) = v; + + break; + } + + case 'v': + { + /* Void pointer. */ + + void *v = sip_api_convert_to_void_ptr(arg); + + if (PyErr_Occurred()) + valid = PARSE_TYPE; + else + *va_arg(va,void **) = v; + + break; + } + + default: + valid = PARSE_FORMAT; + } + + if (valid == PARSE_OK) + { + if (ch == 'W') + { + /* + * An ellipsis matches everything and ends the + * parse. + */ + nrparsed = nrargs; + break; + } + + ++nrparsed; + } + } + + *argsParsedp = nrparsed; + + return valid; +} + + +/* + * Second pass of the argument parse, converting the remaining ones that might + * have side effects. Return PARSE_OK if there was no error. + */ +static int parsePass2(sipWrapper *self, int selfarg, int nrargs, + PyObject *sipArgs, const char *fmt, va_list va) +{ + int a, valid; + + valid = PARSE_OK; + + /* Handle the converions of "self" first. */ + switch (*fmt++) + { + case 'B': + { + /* + * The address of a C++ instance when calling one of + * its public methods. + */ + + sipWrapperType *type; + void **p; + + *va_arg(va,PyObject **) = (PyObject *)self; + type = va_arg(va,sipWrapperType *); + p = va_arg(va,void **); + + if ((*p = sip_api_get_cpp_ptr(self,type)) == NULL) + valid = PARSE_RAISED; + + break; + } + + case 'p': + { + /* + * The address of a C++ instance when calling one of + * its protected methods. + */ + + void **p; + + *va_arg(va,PyObject **) = (PyObject *)self; + va_arg(va,sipWrapperType *); + p = va_arg(va,void **); + + if ((*p = sip_api_get_complex_cpp_ptr(self)) == NULL) + valid = PARSE_RAISED; + + break; + } + + case 'C': + va_arg(va,PyObject *); + break; + + default: + --fmt; + } + + for (a = (selfarg ? 1 : 0); a < nrargs && *fmt != 'W' && valid == PARSE_OK; ++a) + { + char ch; + PyObject *arg = PyTuple_GET_ITEM(sipArgs,a); + + /* Skip the optional character. */ + if ((ch = *fmt++) == '|') + ch = *fmt++; + + /* + * Do the outstanding conversions. For most types it has + * already been done, so we are just skipping the parameters. + */ + switch (ch) + { + 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 ((*rx = sip_api_convert_rx(self,sig,arg,*slot,slot)) == NULL) + valid = PARSE_RAISED; + + 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 **); + + *rx = sipGetRx(self,sig,arg,*slot,slot); + 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 ((*rx = sip_api_convert_rx(self,sig,arg,NULL,slot)) == NULL) + valid = PARSE_RAISED; + + 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 **); + + *rx = sipGetRx(self,sig,arg,NULL,slot); + break; + } + + case 'J': + { + /* Class instance. */ + + int flags = *fmt++ - '0'; + sipWrapperType *type; + void **p; + int iflgs = 0; + int iserr = FALSE; + int *state; + PyObject *xfer, **wrapper; + + type = va_arg(va,sipWrapperType *); + p = va_arg(va,void **); + + if (flags & FORMAT_TRANSFER) + xfer = (self ? (PyObject *)self : arg); + else if (flags & FORMAT_TRANSFER_BACK) + xfer = Py_None; + else + xfer = NULL; + + if (flags & FORMAT_DEREF) + iflgs |= SIP_NOT_NONE; + + if (flags & (FORMAT_GET_WRAPPER|FORMAT_TRANSFER_THIS)) + wrapper = va_arg(va, PyObject **); + + if (flags & FORMAT_NO_CONVERTORS) + { + iflgs |= SIP_NO_CONVERTORS; + state = NULL; + } + else + state = va_arg(va, int *); + + *p = sip_api_convert_to_instance(arg, type, xfer, iflgs, state, &iserr); + + if (iserr) + valid = PARSE_RAISED; + + if (flags & FORMAT_GET_WRAPPER) + *wrapper = (*p != NULL ? arg : NULL); + else if (flags & FORMAT_TRANSFER_THIS && *p != NULL) + *wrapper = arg; + + break; + } + + case 'M': + { + /* Mapped type instance. */ + + int flags = *fmt++ - '0'; + sipMappedType *mt; + void **p; + int iflgs = 0; + int iserr = FALSE; + int *state; + PyObject *xfer; + + mt = va_arg(va, sipMappedType *); + p = va_arg(va, void **); + state = va_arg(va, int *); + + if (flags & FORMAT_TRANSFER) + xfer = (self ? (PyObject *)self : arg); + else if (flags & FORMAT_TRANSFER_BACK) + xfer = Py_None; + else + xfer = NULL; + + if (flags & FORMAT_DEREF) + iflgs |= SIP_NOT_NONE; + + *p = sip_api_convert_to_mapped_type(arg, mt, xfer, iflgs, state, &iserr); + + if (iserr) + valid = PARSE_RAISED; + + break; + } + + case 'P': + { + /* + * Python object of any type with a + * sub-format. + */ + + PyObject **p = va_arg(va,PyObject **); + int flags = *fmt++ - '0'; + + if (flags & FORMAT_TRANSFER) + { + Py_XINCREF(*p); + } + else if (flags & FORMAT_TRANSFER_BACK) + { + Py_XDECREF(*p); + } + + break; + } + + case 'X': + { + /* Constrained (ie. exact) type. */ + + ++fmt; + va_arg(va,void *); + + break; + } + + + case 'E': + { + /* Named enum. */ + + int *p; + + va_arg(va, PyTypeObject *); + p = va_arg(va, int *); + + *p = PyInt_AsLong(arg); + + break; + } + + /* + * Every other argument is a pointer and only differ in how + * many there are. + */ + case 'N': + case 'T': + case 'a': + case 'A': + va_arg(va,void *); + + /* Drop through. */ + + default: + va_arg(va,void *); + } + } + + /* Handle any ellipsis argument. */ + if (*fmt == 'W' && valid == PARSE_OK) + { + PyObject *al; + + /* Create a tuple for any remaining arguments. */ + if ((al = PyTuple_New(nrargs - a)) != NULL) + { + int da = 0; + + while (a < nrargs) + { + 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; + } + else + valid = PARSE_RAISED; + } + + return valid; +} + + +/* + * Carry out actions common to all ctors. + */ +static void sip_api_common_ctor(sipMethodCache *cache,int nrmeths) +{ + /* This is thread safe. */ + while (nrmeths-- > 0) + cache++->mcflags = 0; +} + + +/* + * Carry out actions common to all dtors. + */ +static void sip_api_common_dtor(sipWrapper *sipSelf) +{ + if (sipSelf != NULL && sipInterpreter != NULL) + { + SIP_BLOCK_THREADS + + callPyDtor(sipSelf); + + if (!sipNotInMap(sipSelf)) + sipOMRemoveObject(&cppPyMap,sipSelf); + + /* This no longer points to anything useful. */ + sipSelf->u.cppPtr = NULL; + + /* + * If C/C++ has a reference (and therefore no parent) then remove it. + * Otherwise remove the object from any parent. + */ + if (sipCppHasRef(sipSelf)) + { + sipResetCppHasRef(sipSelf); + Py_DECREF(sipSelf); + } + else + removeFromParent(sipSelf); + + SIP_UNBLOCK_THREADS + } +} + + +/* + * Call self.__dtor__() if it is implemented. + */ +static void callPyDtor(sipWrapper *self) +{ + sip_gilstate_t sipGILState; + sipMethodCache pymc; + PyObject *meth; + + /* No need to cache the method, it will only be called once. */ + pymc.mcflags = 0; + meth = sip_api_is_py_method(&sipGILState, &pymc, self, NULL, "__dtor__"); + + if (meth != NULL) + { + PyObject *res = sip_api_call_method(0, meth, "", NULL); + + Py_DECREF(meth); + + /* Discard any result. */ + Py_XDECREF(res); + + SIP_RELEASE_GIL(sipGILState); + } +} + + +/* + * Add a wrapper to it's parent owner if it has one. The wrapper must not + * currently have a parent and, therefore, no siblings. + */ +static void addToParent(sipWrapper *self, sipWrapper *owner) +{ + if (owner != NULL) + { + 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(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(self); + } +} + + +/* + * Convert a sequence index. Return the index or a negative value if there was + * an error. + */ +static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx, + SIP_SSIZE_T len) +{ + /* Negative indices start from the other end. */ + if (idx < 0) + idx = len + idx; + + if (idx < 0 || idx >= len) + { + PyErr_Format(PyExc_IndexError, "sequence index out of range"); + return -1; + } + + return idx; +} + + +/* + * Create and return a single type object. + */ +static sipWrapperType *createType(sipExportedModuleDef *client, + sipTypeDef *type, PyObject *mod_dict) +{ + PyObject *name, *bases, *typedict, *args, *dict; + sipEncodedClassDef *sup; + sipWrapperType *wt; + + /* Create an object corresponding to the type name. */ + if ((name = getBaseNameObject(type->td_name)) == NULL) + goto reterr; + + /* Create the tuple of super types. */ + if ((sup = type->td_supers) == NULL) + { + static PyObject *nobases = NULL; + + if (nobases == NULL && (nobases = Py_BuildValue("(O)",&sipWrapper_Type)) == NULL) + goto relname; + + Py_INCREF(nobases); + bases = nobases; + } + else + { + int i, nrsupers = 0; + + do + ++nrsupers; + while (!sup++->sc_flag); + + if ((bases = PyTuple_New(nrsupers)) == NULL) + goto relname; + + for (sup = type->td_supers, i = 0; i < nrsupers; ++i, ++sup) + { + PyObject *st = (PyObject *)getClassType(sup, client); + + Py_INCREF(st); + PyTuple_SET_ITEM(bases,i,st); + } + } + + /* Create the type dictionary. */ + if ((typedict = createTypeDict(client->em_nameobj)) == NULL) + goto relbases; + + /* Initialise the rest of the type and pass it via the back door. */ + type->td_module = client; + currentType = type; + + /* Create the type by calling the metatype. */ + if ((args = Py_BuildValue("OOO",name,bases,typedict)) == NULL) + goto reldict; + + if ((wt = (sipWrapperType *)PyObject_Call((PyObject *)&sipWrapperType_Type,args,NULL)) == NULL) + goto relargs; + + /* Get the dictionary into which the type will be placed. */ + if (type->td_scope.sc_flag) + dict = mod_dict; + else + dict = ((PyTypeObject *)getClassType(&type->td_scope, client))->tp_dict; + + /* Add the type to the "parent" dictionary. */ + if (PyDict_SetItem(dict,name,(PyObject *)wt) < 0) + goto reltype; + + /* We can now release our references. */ + Py_DECREF(args); + Py_DECREF(typedict); + Py_DECREF(bases); + Py_DECREF(name); + + return wt; + + /* Unwind after an error. */ + +reltype: + Py_DECREF((PyObject *)wt); + +relargs: + Py_DECREF(args); + +reldict: + Py_DECREF(typedict); + +relbases: + Py_DECREF(bases); + +relname: + Py_DECREF(name); + +reterr: + return NULL; +} + + +/* + * Create and return an enum type object. + */ +static PyTypeObject *createEnum(sipExportedModuleDef *client, sipEnumDef *ed, + PyObject *mod_dict) +{ + static PyObject *bases = NULL; + PyObject *name, *typedict, *args, *dict; + PyTypeObject *et; + + /* Get the module and dictionary into which the type will be placed. */ + if (ed->e_scope < 0) + dict = mod_dict; + else + dict = ((PyTypeObject *)client->em_types[ed->e_scope])->tp_dict; + + /* Create the base type tuple if it hasn't already been done. */ + if (bases == NULL && (bases = Py_BuildValue("(O)",&PyInt_Type)) == NULL) + goto reterr; + + /* Create an object corresponding to the type name. */ + if ((name = getBaseNameObject(ed->e_name)) == NULL) + goto reterr; + + /* Create the type dictionary. */ + if ((typedict = createTypeDict(client->em_nameobj)) == NULL) + goto relname; + + /* Create the type by calling the metatype. */ + if ((args = Py_BuildValue("OOO",name,bases,typedict)) == NULL) + goto reldict; + + if ((et = (PyTypeObject *)PyObject_Call((PyObject *)&PyType_Type,args,NULL)) == NULL) + goto relargs; + + /* Initialise any slots. */ + if (ed->e_pyslots != NULL) + initSlots(et, et->tp_as_number, et->tp_as_sequence, et->tp_as_mapping, ed->e_pyslots, TRUE); + + /* Add the type to the "parent" dictionary. */ + if (PyDict_SetItem(dict,name,(PyObject *)et) < 0) + goto reltype; + + /* We can now release our references. */ + Py_DECREF(args); + Py_DECREF(typedict); + Py_DECREF(name); + + return et; + + /* Unwind after an error. */ + +reltype: + Py_DECREF((PyObject *)et); + +relargs: + Py_DECREF(args); + +reldict: + Py_DECREF(typedict); + +relname: + Py_DECREF(name); + +reterr: + return NULL; +} + + +/* + * Return a pointer to the basename of a Python "pathname". + */ +static const char *getBaseName(const char *name) +{ + const char *bn; + + if ((bn = strrchr(name, '.')) != NULL) + ++bn; + else + bn = name; + + return bn; +} + + +/* + * Create a Python object corresponding to the basename of a Python "pathname". + */ +static PyObject *getBaseNameObject(const char *name) +{ + return PyString_FromString(getBaseName(name)); +} + + +/* + * Create a type dictionary for dynamic type being created in the module with + * the specified name. + */ +static PyObject *createTypeDict(PyObject *mname) +{ + static PyObject *proto = NULL; + static PyObject *mstr = NULL; + PyObject *dict; + + /* Create a prototype dictionary. */ + if (proto == NULL) + { + if ((proto = PyDict_New()) == NULL) + return NULL; + + /* + * These tell pickle that SIP generated classes can't be + * pickled. + */ + if (PyDict_SetItemString(proto, "__reduce_ex__", Py_None) < 0 || + PyDict_SetItemString(proto, "__reduce__", Py_None) < 0) + { + Py_DECREF(proto); + proto = NULL; + + return NULL; + } + } + + /* Create an object for "__module__". */ + if (mstr == NULL && (mstr = PyString_FromString("__module__")) == NULL) + return NULL; + + if ((dict = PyDict_Copy(proto)) == NULL) + return NULL; + + /* We need to set the module name as an attribute for dynamic types. */ + if (PyDict_SetItem(dict, mstr, mname) < 0) + { + Py_DECREF(dict); + return NULL; + } + + return dict; +} + + +/* + * Add a set of static instances to a dictionary. + */ +static int addInstances(PyObject *dict,sipInstancesDef *id) +{ + if (id->id_class != NULL && addClassInstances(dict,id->id_class) < 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; + + if (id->id_enum != NULL && addEnumInstances(dict,id->id_enum) < 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(sipWrapperType *type, PyObject *args, int argnr, + sipWrapper **selfp) +{ + PyObject *self; + + /* Get self from the argument tuple. */ + + if (argnr >= PyTuple_GET_SIZE(args)) + return PARSE_UNBOUND; + + self = PyTuple_GET_ITEM(args, argnr); + + if (!PyObject_TypeCheck(self, (PyTypeObject *)type)) + return PARSE_UNBOUND; + + *selfp = (sipWrapper *)self; + + return PARSE_OK; +} + + +/* + * Handle the result of a call to the class/instance setattro methods. + */ +static int handleSetLazyAttr(PyObject *nameobj,PyObject *valobj, + sipWrapperType *wt,sipWrapper *w) +{ + char *name; + PyMethodDef *pmd, *vmd; + sipEnumMemberDef *enm; + + /* See if it was a lazy attribute. */ + if ((name = PyString_AsString(nameobj)) == NULL) + return -1; + + pmd = NULL; + enm = NULL; + vmd = NULL; + + findLazyAttr(wt,name,&pmd,&enm,&vmd,NULL); + + if (vmd != NULL) + { + if (valobj == NULL) + { + PyErr_Format(PyExc_ValueError,"%s.%s cannot be deleted",wt->type->td_name,name); + + return -1; + } + + if ((vmd->ml_flags & METH_STATIC) != 0 || w != NULL) + { + PyObject *res; + + if ((res = (*vmd->ml_meth)((PyObject *)w,valobj)) == NULL) + return -1; + + /* Ignore the result (which should be Py_None). */ + Py_DECREF(res); + + return 0; + } + + PyErr_SetObject(PyExc_AttributeError,nameobj); + + return -1; + } + + /* It isn't a variable. */ + return 1; +} + + +/* + * Handle the result of a call to the class/instance getattro methods. + */ +static PyObject *handleGetLazyAttr(PyObject *nameobj,sipWrapperType *wt, + sipWrapper *w) +{ + char *name; + PyMethodDef *pmd, *vmd; + sipEnumMemberDef *enm; + sipTypeDef *in; + + /* If it was an error, propagate it. */ + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + + PyErr_Clear(); + + /* See if it was a lazy attribute. */ + if ((name = PyString_AsString(nameobj)) == NULL) + return NULL; + + pmd = NULL; + enm = NULL; + vmd = NULL; + + findLazyAttr(wt,name,&pmd,&enm,&vmd,&in); + + if (pmd != NULL) + return PyCFunction_New(pmd,(PyObject *)w); + + if (enm != NULL) + { + PyObject *attr; + + /* + * Convert the value to an object. Note that we cannot cache + * it in the type dictionary because a sub-type might have a + * lazy attribute of the same name. In this case (because we + * call the standard getattro code first) this one would be + * wrongly found in preference to the one in the sub-class. + * The example in PyQt is QScrollView::ResizePolicy and + * QListView::WidthMode both having a member called Manual. + * One way around this might be to cache them in a separate + * dictionary and search that before doing the binary search + * through the lazy enum table. + */ + if ((attr = createEnumMember(in, enm)) == NULL) + return NULL; + + return attr; + } + + if (vmd != NULL) + if ((vmd->ml_flags & METH_STATIC) != 0 || w != NULL) + return (*vmd->ml_meth)((PyObject *)w,NULL); + + PyErr_SetObject(PyExc_AttributeError,nameobj); + + return NULL; +} + + +/* + * Create a Python object for an enum member. + */ +static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm) +{ + if (enm->em_enum < 0) + return PyInt_FromLong(enm->em_val); + + return sip_api_convert_from_named_enum(enm->em_val, td->td_module->em_enums[enm->em_enum]); +} + + +/* + * Create a Python object for a member of a named enum. + */ +PyObject *sip_api_convert_from_named_enum(int eval, PyTypeObject *et) +{ + PyObject *args, *mo; + + if ((args = Py_BuildValue("(i)", eval)) == NULL) + return NULL; + + mo = PyObject_Call((PyObject *)et, args, NULL); + + Py_DECREF(args); + + return mo; +} + + +/* + * Find definition for a lazy class attribute. + */ +static void findLazyAttr(sipWrapperType *wt,char *name,PyMethodDef **pmdp, + sipEnumMemberDef **enmp,PyMethodDef **vmdp, + sipTypeDef **in) +{ + sipTypeDef *td, *nsx; + sipEncodedClassDef *sup; + + /* The base type doesn't have any type information. */ + if ((td = wt->type) == NULL) + return; + + /* Search the possible linked list of namespace extenders. */ + nsx = td; + + do + { + /* Try the methods. */ + if (nsx->td_nrmethods > 0 && + (*pmdp = (PyMethodDef *)bsearch(name, nsx->td_methods, nsx->td_nrmethods, sizeof (PyMethodDef), compareMethodName)) != NULL) + return; + + /* Try the enum members. */ + if (nsx->td_nrenummembers > 0 && + (*enmp = (sipEnumMemberDef *)bsearch(name, nsx->td_enummembers, nsx->td_nrenummembers, sizeof (sipEnumMemberDef), compareEnumMemberName)) != NULL) + { + if (in != NULL) + *in = nsx; + + return; + } + + /* Try the variables. Note, these aren't sorted. */ + if (nsx->td_variables != NULL) + { + PyMethodDef *md; + + for (md = nsx->td_variables; md->ml_name != NULL; ++md) + if (strcmp(name, md->ml_name) == 0) + { + *vmdp = md; + return; + } + } + + nsx = nsx->td_nsextender; + } + while (nsx != NULL); + + /* Check the base classes. */ + if ((sup = td->td_supers) != NULL) + do + { + findLazyAttr(getClassType(sup, td->td_module), name, pmdp, enmp, vmdp, in); + + if (*pmdp != NULL || *enmp != NULL || *vmdp != NULL) + break; + } + while (!sup++->sc_flag); +} + + +/* + * The bsearch() helper function for searching a sorted method table. + */ +static int compareMethodName(const void *key,const void *el) +{ + return strcmp((const char *)key,((const PyMethodDef *)el)->ml_name); +} + + +/* + * The bsearch() helper function for searching a sorted enum member table. + */ +static int compareEnumMemberName(const void *key,const void *el) +{ + return strcmp((const char *)key,((const sipEnumMemberDef *)el)->em_name); +} + + +/* + * Report a function with invalid argument types. + */ +static void sip_api_no_function(int argsParsed, const char *func) +{ + badArgs(argsParsed,NULL,func); +} + + +/* + * Report a method/function/signal with invalid argument types. + */ +static void sip_api_no_method(int argsParsed, const char *classname, const char *method) +{ + badArgs(argsParsed,classname,method); +} + + +/* + * 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); +} + + +/* + * Handle error reporting for bad arguments to various things. + */ +static void badArgs(int argsParsed, const char *classname, const char *method) +{ + char *sep; + int nrparsed = argsParsed & ~PARSE_MASK; + + if (classname != NULL) + sep = "."; + else + { + classname = ""; + sep = ""; + } + + switch (argsParsed & PARSE_MASK) + { + case PARSE_FEW: + PyErr_Format(PyExc_TypeError,"insufficient number of arguments to %s%s%s()",classname,sep,method); + break; + + case PARSE_MANY: + PyErr_Format(PyExc_TypeError,"too many arguments to %s%s%s(), %d at most expected",classname,sep,method,nrparsed); + break; + + case PARSE_TYPE: + PyErr_Format(PyExc_TypeError,"argument %d of %s%s%s() has an invalid type",nrparsed + 1,classname,sep,method); + break; + + case PARSE_FORMAT: + PyErr_Format(PyExc_TypeError,"invalid format to sipParseArgs() from %s%s%s()",classname,sep,method); + break; + + case PARSE_UNBOUND: + PyErr_Format(PyExc_TypeError,"first argument of unbound method %s%s%s() must be a %s instance",classname,sep,method,classname); + break; + + case PARSE_RAISED: + /* It has already been taken care of. */ + + break; + + case PARSE_OK: + /* This is raised by a private re-implementation. */ + PyErr_Format(PyExc_AttributeError,"%s%s%s is a private method",classname,sep,method); + break; + } +} + + +/* + * 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", self->ob_type->tp_name, arg->ob_type->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, self->ob_type->tp_name, arg->ob_type->tp_name); +} + + +/* + * Report a sequence length that does not match the length of a slice. + */ +static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen, + SIP_SSIZE_T slicelen) +{ + PyErr_Format(PyExc_ValueError, +#if PY_VERSION_HEX >= 0x02050000 + "attempt to assign sequence of size %zd to slice of size %zd", +#else + "attempt to assign sequence of size %d to slice of size %d", +#endif + seqlen, slicelen); +} + + +/* + * Report a Python object that cannot be converted to a particular class. + */ +static void sip_api_bad_class(const char *classname) +{ + PyErr_Format(PyExc_TypeError,"cannot convert Python object to an instance of %s",classname); +} + + +/* + * Report a Python class variable with an unexpected type. + */ +static void sip_api_bad_set_type(const char *classname,const char *var) +{ + PyErr_Format(PyExc_TypeError,"invalid type for variable %s.%s",classname,var); +} + + +/* + * Report a Python member function with an unexpected return type. + */ +static void sip_api_bad_catcher_result(PyObject *method) +{ + const char *cname; + char *mname; + + /* + * This is part of the public API so we make no assumptions about the + * method object. + */ + if (!PyMethod_Check(method) || + PyMethod_GET_FUNCTION(method) == NULL || + !PyFunction_Check(PyMethod_GET_FUNCTION(method)) || + PyMethod_GET_SELF(method) == NULL) + { + PyErr_Format(PyExc_TypeError,"invalid argument to sipBadCatcherResult()"); + return; + } + + mname = PyString_AsString(((PyFunctionObject *)PyMethod_GET_FUNCTION(method))->func_name); + + if (mname == NULL) + return; + + cname = PyMethod_GET_SELF(method)->ob_type->tp_name; + + PyErr_Format(PyExc_TypeError,"invalid result type from %s.%s()",cname,mname); +} + + +/* + * Return the name of the class corresponding to a wrapper object. This comes + * with a reference. + */ +static PyObject *sip_api_class_name(PyObject *self) +{ + return PyString_FromString(self->ob_type->tp_name); +} + + +/* + * Return non-zero if the object is a C++ instance wrapper. + */ +int sip_api_wrapper_check(PyObject *o) +{ + return PyObject_TypeCheck(o,(PyTypeObject *)&sipWrapper_Type); +} + + +/* + * Return non-zero if the object is a C++ instance wrapper type. + */ +static int sipWrapperType_Check(PyObject *op) +{ + return PyObject_TypeCheck(op,(PyTypeObject *)&sipWrapperType_Type); +} + + +/* + * Transfer ownership of a class instance to Python from C/C++. + */ +static void sip_api_transfer_back(PyObject *self) +{ + if (self != NULL && sip_api_wrapper_check(self)) + { + sipWrapper *w = (sipWrapper *)self; + + if (sipCppHasRef(w)) + { + sipResetCppHasRef(w); + Py_DECREF(w); + } + else + removeFromParent(w); + + sipSetPyOwned(w); + } +} + + +/* + * 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 && sip_api_wrapper_check(self) && (owner == NULL || sip_api_wrapper_check(owner))) + { + sipWrapper *w = (sipWrapper *)self; + + /* + * Keep the object alive while we do the transfer. If C++ has a + * reference then there is no need to increment it, just reset the flag + * and the following decrement will bring everything back to the way it + * should be. + */ + if (sipCppHasRef(w)) + sipResetCppHasRef(w); + else + { + Py_INCREF(self); + removeFromParent(w); + } + + addToParent(w, (sipWrapper *)owner); + + Py_DECREF(self); + + sipResetPyOwned(w); + } +} + + +/* + * Transfer ownership of a class instance from Python to C/C++, or vice versa. + * This is deprecated. + */ +static void sip_api_transfer(PyObject *self, int toCpp) +{ + if (toCpp) + sip_api_transfer_to(self, self); + else + sip_api_transfer_back(self); +} + + +/* + * 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 (licenseName == NULL && (licenseName = PyString_FromString("__license__")) == NULL) + return -1; + + if (licenseeName == NULL && (licenseeName = PyString_FromString("Licensee")) == NULL) + return -1; + + if (typeName == NULL && (typeName = PyString_FromString("Type")) == NULL) + return -1; + + if (timestampName == NULL && (timestampName = PyString_FromString("Timestamp")) == NULL) + return -1; + + if (signatureName == NULL && (signatureName = PyString_FromString("Signature")) == NULL) + 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 || (o = PyString_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 = PyString_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 = PyString_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 = PyString_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) + { + int rc; + PyObject *w; + + if ((w = sip_api_convert_from_void_ptr(vi->vi_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,vi->vi_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++vi; + } + + return 0; +} + + +/* + * Add the char instances to a dictionary. + */ +static int addCharInstances(PyObject *dict,sipCharInstanceDef *ci) +{ + while (ci->ci_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyString_FromStringAndSize(&ci->ci_val,1)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,ci->ci_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ci; + } + + return 0; +} + + +/* + * Add the string instances to a dictionary. + */ +static int addStringInstances(PyObject *dict,sipStringInstanceDef *si) +{ + while (si->si_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyString_FromString(si->si_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,si->si_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++si; + } + + return 0; +} + + +/* + * Add the int instances to a dictionary. + */ +static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii) +{ + while (ii->ii_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyInt_FromLong(ii->ii_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, ii->ii_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ii; + } + + return 0; +} + + +/* + * Add the long instances to a dictionary. + */ +static int addLongInstances(PyObject *dict,sipLongInstanceDef *li) +{ + while (li->li_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyLong_FromLong(li->li_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,li->li_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++li; + } + + return 0; +} + + +/* + * Add the unsigned long instances to a dictionary. + */ +static int addUnsignedLongInstances(PyObject *dict, sipUnsignedLongInstanceDef *uli) +{ + while (uli->uli_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyLong_FromUnsignedLong(uli->uli_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, uli->uli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++uli; + } + + return 0; +} + + +/* + * Add the long long instances to a dictionary. + */ +static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli) +{ + while (lli->lli_name != NULL) + { + int rc; + PyObject *w; + +#if defined(HAVE_LONG_LONG) + if ((w = PyLong_FromLongLong(lli->lli_val)) == NULL) +#else + if ((w = PyLong_FromLong(lli->lli_val)) == NULL) +#endif + return -1; + + rc = PyDict_SetItemString(dict, lli->lli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++lli; + } + + return 0; +} + + +/* + * Add the unsigned long long instances to a dictionary. + */ +static int addUnsignedLongLongInstances(PyObject *dict, sipUnsignedLongLongInstanceDef *ulli) +{ + while (ulli->ulli_name != NULL) + { + int rc; + PyObject *w; + +#if defined(HAVE_LONG_LONG) + if ((w = PyLong_FromUnsignedLongLong(ulli->ulli_val)) == NULL) +#else + if ((w = PyLong_FromUnsignedLong(ulli->ulli_val)) == NULL) +#endif + return -1; + + rc = PyDict_SetItemString(dict, ulli->ulli_name, w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++ulli; + } + + return 0; +} + + +/* + * Add the double instances to a dictionary. + */ +static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di) +{ + while (di->di_name != NULL) + { + int rc; + PyObject *w; + + if ((w = PyFloat_FromDouble(di->di_val)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,di->di_name,w); + Py_DECREF(w); + + if (rc < 0) + return -1; + + ++di; + } + + return 0; +} + + +/* + * Wrap a set of enum instances and add them to a dictionary. + */ +static int addEnumInstances(PyObject *dict, sipEnumInstanceDef *ei) +{ + while (ei->ei_name != NULL) + { + if (addSingleEnumInstance(dict, ei->ei_name, ei->ei_val, *ei->ei_type) < 0) + return -1; + + ++ei; + } + + return 0; +} + + +/* + * Wrap a single enum instance and add it to a dictionary. + */ +static int addSingleEnumInstance(PyObject *dict, const char *name, int value, + PyTypeObject *type) +{ + int rc; + PyObject *w; + + if ((w = sip_api_convert_from_named_enum(value, type)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, name, w); + Py_DECREF(w); + + return rc; +} + + +/* + * Wrap an enum instance and add it to a dictionary. + */ +static int sip_api_add_enum_instance(PyObject *dict, const char *name, + int value, PyTypeObject *type) +{ + /* If this is a wrapped type then get the type dictionary. */ + if (sipWrapperType_Check(dict)) + dict = ((PyTypeObject *)dict)->tp_dict; + + return addSingleEnumInstance(dict, name, value, type); +} + + +/* + * Wrap a set of class instances and add them to a dictionary. + */ +static int addClassInstances(PyObject *dict, sipClassInstanceDef *ci) +{ + while (ci->ci_name != NULL) + { + if (addSingleClassInstance(dict, ci->ci_name, ci->ci_ptr, *ci->ci_type, ci->ci_flags) < 0) + return -1; + + ++ci; + } + + return 0; +} + + +/* + * Wrap a single class instance and add it to a dictionary. + */ +static int addSingleClassInstance(PyObject *dict, const char *name, + void *cppPtr, sipWrapperType *wt, int initflags) +{ + int rc; + PyObject *w; + + if ((w = sipWrapSimpleInstance(cppPtr,wt,NULL,initflags)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,name,w); + Py_DECREF(w); + + return rc; +} + + +/* + * Wrap a class instance and add it to a dictionary. + */ +static int sip_api_add_class_instance(PyObject *dict, const char *name, + void *cppPtr, sipWrapperType *wt) +{ + /* If this is a wrapped type then get the type dictionary. */ + if (sipWrapperType_Check(dict)) + dict = ((PyTypeObject *)dict)->tp_dict; + + return addSingleClassInstance(dict, name, cppPtr, wt, 0); +} + + +/* + * Wrap a mapped type instance and add it to a dictionary. + */ +static int sip_api_add_mapped_type_instance(PyObject *dict, const char *name, + void *cppPtr, const sipMappedType *mt) +{ + int rc; + PyObject *w; + + /* If this is a wrapped type then get the type dictionary. */ + if (sipWrapperType_Check(dict)) + dict = ((PyTypeObject *)dict)->tp_dict; + + if ((w = mt->mt_cfrom(cppPtr, NULL)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict, name, w); + Py_DECREF(w); + + return rc; +} + + +/* + * Get the C/C++ pointer for a complex object. + */ +static void *sip_api_get_complex_cpp_ptr(sipWrapper *w) +{ + if (!sipIsDerived(w)) + { + PyErr_SetString(PyExc_RuntimeError,"no access to protected functions or signals for objects not created from Python"); + + return NULL; + } + + if (checkPointer(w->u.cppPtr) < 0) + return NULL; + + return w->u.cppPtr; +} + + +/* + * Return the Python member function corresponding to a C/C++ virtual function, + * if any. If one was found then the Python lock is acquired. + */ +static PyObject *sip_api_is_py_method(sip_gilstate_t *gil,sipMethodCache *pymc, + sipWrapper *sipSelf,char *cname, + char *mname) +{ + /* We might still have C++ going after the interpreter has gone. */ + if (sipInterpreter == NULL) + return NULL; + + /* + * It's possible that the Python object has been deleted but the + * underlying (complex) C/C++ instance is still working and trying to + * handle virtual functions. Or an instance has started handling + * virtual functions before its ctor has returned. In either case say + * there is no Python method. + */ + if (sipSelf == NULL) + return NULL; + +#ifdef WITH_THREAD + *gil = PyGILState_Ensure(); +#endif + + /* See if we have already looked for the Python method. */ + if (!sipFoundMethod(pymc)) + { + PyObject *methobj; + + /* + * Using PyMethod_Check() rather than PyCallable_Check() has + * the added benefits of ensuring the (common) case of there + * being no Python method is handled as a direct call to C/C++ + * (rather than converted to Python and then back to C/C++) and + * makes sure that abstract virtuals are trapped. + */ + if ((methobj = PyObject_GetAttrString((PyObject *)sipSelf,mname)) != NULL) + { + if (PyMethod_Check(methobj)) + { + sipSetIsMethod(pymc); + sipSaveMethod(&pymc->pyMethod,methobj); + } + + Py_DECREF(methobj); + } + + PyErr_Clear(); + + sipSetFoundMethod(pymc); + } + else if (sipIsMethod(pymc)) + PyErr_Clear(); + + if (sipIsMethod(pymc)) + return PyMethod_New(pymc->pyMethod.mfunc,pymc->pyMethod.mself,pymc->pyMethod.mclass); + + if (cname != NULL) + PyErr_Format(PyExc_NotImplementedError,"%s.%s() is abstract and must be overridden",cname,mname); + +#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_wrapper(void *cppPtr,sipWrapperType *type) +{ + return (PyObject *)sipOMFindObject(&cppPyMap,cppPtr,type); +} + + +/* + * Return the C/C++ pointer from a wrapper without any checks. + */ +void *sipGetAddress(sipWrapper *w) +{ + if (sipIsAccessFunc(w)) + return (*w->u.afPtr)(); + + if (sipIsIndirect(w)) + return *((void **)w->u.cppPtr); + + return w->u.cppPtr; +} + + +/* + * Get the C/C++ pointer from a wrapper and optionally cast it to the required + * type. + */ +void *sip_api_get_cpp_ptr(sipWrapper *w,sipWrapperType *type) +{ + void *ptr = sipGetAddress(w); + + if (checkPointer(ptr) < 0) + return NULL; + + if (type != NULL) + ptr = cast_cpp_ptr(ptr, (sipWrapperType *)w->ob_type, type); + + return ptr; +} + + +/* + * Cast a C/C++ pointer from a source type to a destination type. + */ +static void *cast_cpp_ptr(void *ptr, sipWrapperType *src_type, + sipWrapperType *dst_type) +{ + sipCastFunc cast = src_type->type->td_cast; + + /* C structures don't have cast functions. */ + if (cast != NULL) + ptr = (*cast)(ptr, dst_type); + + return ptr; +} + + +/* + * Check that a pointer is non-NULL. + */ +static int checkPointer(void *ptr) +{ + if (ptr == NULL) + { + PyErr_SetString(PyExc_RuntimeError,"underlying C/C++ object has been deleted"); + return -1; + } + + return 0; +} + + +/* + * Check to see if a Python object can be converted to a wrapped type. + */ +static int sip_api_can_convert_to_instance(PyObject *pyObj, + sipWrapperType *type, int flags) +{ + int ok; + sipConvertToFunc cto = type->type->td_cto; + + /* None is handled outside the type checkers. */ + if (pyObj == Py_None) + ok = ((flags & SIP_NOT_NONE) == 0); + else if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0) + ok = PyObject_TypeCheck(pyObj, (PyTypeObject *)type); + else + ok = cto(pyObj, NULL, NULL, NULL); + + return ok; +} + + +/* + * Check to see if a Python object can be converted to a mapped type. + */ +static int sip_api_can_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, + int flags) +{ + int ok; + + /* None is handled outside the type checkers. */ + if (pyObj == Py_None) + ok = ((flags & SIP_NOT_NONE) == 0); + else + ok = mt->mt_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_instance() has been successful. Allow ownership to + * be transferred and any type convertors to be disabled. + */ +static void *sip_api_convert_to_instance(PyObject *pyObj, sipWrapperType *type, + PyObject *transferObj, int flags, + int *statep, int *iserrp) +{ + void *cpp = NULL; + int state = 0; + sipConvertToFunc cto = type->type->td_cto; + + /* Don't convert if there has already been an error. */ + if (!*iserrp) + { + /* Do the conversion. */ + if (pyObj == Py_None) + cpp = NULL; + else if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0) + { + if ((cpp = sip_api_get_cpp_ptr((sipWrapper *)pyObj, type)) == 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); + } + + if (statep != NULL) + *statep = state; + + return cpp; +} + + +/* + * Convert a Python object to a C/C++ pointer, assuming a previous call to + * sip_api_can_convert_to_mapped_type() has been successful. Allow ownership + * to be transferred. + */ +static void *sip_api_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, + PyObject *transferObj, int flags, + int *statep, int *iserrp) +{ + void *cpp = NULL; + int state = 0; + + /* Don't convert if there has already been an error. */ + if (!*iserrp) + if (pyObj == Py_None) + cpp = NULL; + else + state = mt->mt_cto(pyObj, &cpp, iserrp, transferObj); + + if (statep != NULL) + *statep = state; + + return cpp; +} + + +/* + * Convert a Python object to a C/C++ pointer and raise an exception if it + * can't be done. + */ +static void *sip_api_force_convert_to_instance(PyObject *pyObj, + sipWrapperType *type, + 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_instance(pyObj, type, flags)) + { + PyErr_Format(PyExc_TypeError, "%s cannot be converted to %s in this context", pyObj->ob_type->tp_name, type->type->td_name); + + if (statep != NULL) + *statep = 0; + + *iserrp = TRUE; + return NULL; + } + + /* Do the conversion. */ + return sip_api_convert_to_instance(pyObj, type, transferObj, flags, statep, iserrp); +} + + +/* + * Convert a Python object to a C/C++ pointer and raise an exception if it + * can't be done. + */ +static void *sip_api_force_convert_to_mapped_type(PyObject *pyObj, + const sipMappedType *mt, + 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_mapped_type(pyObj, mt, flags)) + { + PyErr_Format(PyExc_TypeError, "%s cannot be converted to %s in this context", pyObj->ob_type->tp_name, mt->mt_name); + + if (statep != NULL) + *statep = 0; + + *iserrp = TRUE; + return NULL; + } + + /* Do the conversion. */ + return sip_api_convert_to_mapped_type(pyObj, mt, transferObj, flags, statep, iserrp); +} + + +/* + * Release a possibly temporary instance created by a type convertor. + */ +static void sip_api_release_instance(void *cpp, sipWrapperType *type, int state) +{ + /* See if there is something to release. */ + if (state & SIP_TEMPORARY) + release(cpp, type->type, state); +} + + +/* + * Release an instance. + */ +static void release(void *addr, sipTypeDef *td, int state) +{ + sipReleaseFunc rel = td->td_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 + rel(addr, state); +} + + +/* + * Release a possibly temporary mapped type created by a type convertor. + */ +static void sip_api_release_mapped_type(void *cpp, const sipMappedType *mt, + int state) +{ + /* See if there is something to release. */ + if (state & SIP_TEMPORARY) + { + sipReleaseFunc rel = mt->mt_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(cpp); + else + rel(cpp, state); + } +} + + +/* + * Convert a C/C++ instance to a Python instance. + */ +PyObject *sip_api_convert_from_instance(void *cpp, sipWrapperType *type, + PyObject *transferObj) +{ + PyObject *py; + + /* Handle None. */ + if (cpp == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + /* Apply any sub-class convertor. */ + if (sipTypeHasSCC(type)) + type = convertSubClass(type, &cpp); + + /* See if we have already wrapped it. */ + if ((py = sip_api_get_wrapper(cpp, type)) != NULL) + Py_INCREF(py); + else if ((py = sipWrapSimpleInstance(cpp, type, 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_instance(void *cpp, + sipWrapperType *type, + PyObject *transferObj) +{ + sipWrapper *owner; + + /* Handle None. */ + if (cpp == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + /* Apply any sub-class convertor. */ + if (sipTypeHasSCC(type)) + type = convertSubClass(type, &cpp); + + /* Handle any ownership transfer. */ + if (transferObj != NULL && transferObj != Py_None) + owner = (sipWrapper *)transferObj; + else + owner = NULL; + + return sipWrapSimpleInstance(cpp, type, owner, (owner == NULL ? SIP_PY_OWNED : 0)); +} + + +/* + * Convert a C/C++ instance implemented as a mapped type to a Python object. + */ +static PyObject *sip_api_convert_from_mapped_type(void *cpp, + const sipMappedType *mt, + PyObject *transferObj) +{ + /* Handle None. */ + if (cpp == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + return mt->mt_cfrom(cpp, transferObj); +} + + +/* + * Convert a Python instance of a class to a C/C++ object pointer, checking + * that the instance's class is derived from a given base type. + */ +static void *sip_api_convert_to_cpp(PyObject *sipSelf,sipWrapperType *type, + int *iserrp) +{ + return sip_api_convert_to_instance(sipSelf, type, NULL, SIP_NO_CONVERTORS, NULL, iserrp); +} + + +/* + * 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; +} + + +/* + * Return the mapped type structure for a particular mapped type. + */ +static const sipMappedType *sip_api_find_mapped_type(const char *type) +{ + sipExportedModuleDef *em; + + for (em = clientList; em != NULL; em = em->em_next) + { + sipMappedType **mtypes, *mt; + + if ((mtypes = em->em_mappedtypes) == NULL) + continue; + + while ((mt = *mtypes++) != NULL) + { + const char *s1 = mt->mt_name, *s2 = type; + + /* + * Compare while ignoring spaces so that we don't impose a rigorous + * naming standard. + */ + do + { + while (*s1 == ' ') + ++s1; + + while (*s2 == ' ') + ++s2; + + if (*s1 == '\0' && *s2 == '\0') + return mt; + } + while (*s1++ == *s2++); + } + } + + return NULL; +} + + +/* + * Return the type structure for a particular class. + */ +static sipWrapperType *sip_api_find_class(const char *type) +{ + sipExportedModuleDef *em; + size_t type_len = strlen(type); + + for (em = clientList; em != NULL; em = em->em_next) + { + sipWrapperType *wt = findClass(em, type, type_len); + + if (wt != NULL) + return wt; + } + + return NULL; +} + + +/* + * Return the type structure for a particular named enum. + */ +static PyTypeObject *sip_api_find_named_enum(const char *type) +{ + sipExportedModuleDef *em; + size_t type_len = strlen(type); + + for (em = clientList; em != NULL; em = em->em_next) + { + PyTypeObject *py = findEnum(em, type, type_len); + + if (py != NULL) + return py; + } + + 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); + pm->mclass = PyMethod_GET_CLASS(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 __builtin__ module. */ + if ((mod = PyDict_GetItemString(dictofmods,"__builtin__")) == NULL) + return; + + /* Get it's dictionary. */ + if ((dict = PyModule_GetDict(mod)) == NULL) + return; + + /* Get the function hook. */ + if ((hook = PyDict_GetItemString(dict,hookname)) == NULL) + return; + + /* Call the hook and discard any result. */ + res = PyObject_CallObject(hook,NULL); + + Py_XDECREF(res); +} + + +/* + * Call any sub-class convertors for a given type returning a pointer to the + * sub-type object, and possibly modifying the C++ address (in the case of + * multiple inheritence). + */ +static sipWrapperType *convertSubClass(sipWrapperType *type, void **cppPtr) +{ + sipExportedModuleDef *em; + + if (*cppPtr == NULL) + return NULL; + + /* + * Note that this code depends on the fact that a module appears in the + * list of modules before any module it imports, ie. sub-class convertors + * will be invoked for more specific types first. + */ + for (em = clientList; em != NULL; em = em->em_next) + { + sipSubClassConvertorDef *scc; + + if ((scc = em->em_convertors) == NULL) + continue; + + while (scc->scc_convertor != NULL) + { + /* + * The base type is the "root" class that may have a number of + * convertors each handling a "branch" of the derived tree of + * classes. The "root" normally implements the base function that + * provides the RTTI used by the convertors and is re-implemented + * by derived classes. We therefore see if the target type is a + * sub-class of the root, ie. see if the convertor might be able to + * convert the target type to something more specific. + */ + if (PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)scc->scc_basetype)) + { + void *ptr; + sipWrapperType *subtype; + + ptr = cast_cpp_ptr(*cppPtr, type, scc->scc_basetype); + subtype = (*scc->scc_convertor)(&ptr); + + /* + * We are only interested in types that are not super-classes + * of the target. This happens either because it is in an + * earlier convertor than the one that handles the type or it + * is in a later convertor that handles a different branch of + * the hierarchy. Either way, the ordering of the modules + * ensures that there will be no more than one and that it will + * be the right one. + */ + if (subtype != NULL && !PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)subtype)) + { + *cppPtr = ptr; + return subtype; + } + } + + ++scc; + } + } + + /* + * We haven't found the exact type, so return the most specific type that + * it must be. This can happen legitimately if the wrapped library is + * returning an internal class that is down-cast to a more generic class. + * Also we want this function to be safe when a class doesn't have any + * convertors. + */ + return type; +} + + +/* + * 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. + */ +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. + */ +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 + + if (mobj == NULL) + mobj = PyString_FromString("unknown"); + + PyErr_SetObject(PyExc_Exception, mobj); + + SIP_UNBLOCK_THREADS +} + + +/* + * Raise an exception implemented as a class. Make no assumptions about the + * GIL. + */ +static void sip_api_raise_class_exception(sipWrapperType *type,void *ptr) +{ + PyObject *self; + + SIP_BLOCK_THREADS + + self = sipWrapSimpleInstance(ptr,type,NULL,SIP_PY_OWNED); + + PyErr_SetObject((PyObject *)type,self); + + Py_XDECREF(self); + + SIP_UNBLOCK_THREADS +} + + +/* + * Raise an exception implemented as a class or sub-class. Make no assumptions + * about the GIL. + */ +static void sip_api_raise_sub_class_exception(sipWrapperType *type,void *ptr) +{ + PyObject *self; + + SIP_BLOCK_THREADS + + self = sipWrapSimpleInstance(ptr,type,NULL,SIP_PY_OWNED); + + PyErr_SetObject((PyObject *)type,self); + + Py_XDECREF(self); + + SIP_UNBLOCK_THREADS +} + + +/* + * Return the module of an encoded class. + */ +static sipExportedModuleDef *getClassModule(sipEncodedClassDef *enc, + sipExportedModuleDef *em) +{ + if (enc->sc_module != 255) + em = em->em_imports[enc->sc_module].im_module; + + return em; +} + + +/* + * Return the type of an encoded class. + */ +static sipWrapperType *getClassType(sipEncodedClassDef *enc, + sipExportedModuleDef *em) +{ + return getClassModule(enc, em)->em_types[enc->sc_class]; +} + + +/* + * Find a particular slot function for a wrapper. + */ +static void *findSlot(PyObject *self,sipPySlotType st) +{ + sipTypeDef *td = ((sipWrapperType *)(self->ob_type))->type; + sipEncodedClassDef *sup; + void *slot; + + /* Check the immediate type. */ + if ((slot = findSlotInType(td, st)) != NULL) + return slot; + + /* Check the super-types, if there are any. */ + if ((sup = td->td_supers) != NULL) + do + if ((slot = findSlotInType(getClassType(sup, td->td_module)->type, st)) != NULL) + return slot; + while (!sup++->sc_flag); + + /* This should never happen. */ + return NULL; +} + + +/* + * Find a particular slot function in a type. + */ +static void *findSlotInType(sipTypeDef *td, sipPySlotType st) +{ + sipPySlotDef *psd; + + if ((psd = td->td_pyslots) != NULL) + while (psd->psd_func != NULL) + { + if (psd->psd_type == st) + return psd->psd_func; + + ++psd; + } + + return NULL; +} + + +/* + * Return the C/C++ address and the basic type information for a wrapper. + */ +static void *getPtrTypeDef(sipWrapper *self, sipTypeDef **td) +{ + *td = ((sipWrapperType *)self->ob_type)->type; + + return (sipNotInMap(self) ? NULL : self->u.cppPtr); +} + + +/* + * Handle an objobjargproc slot. + */ +static int objobjargprocSlot(PyObject *self,PyObject *arg1,PyObject *arg2, + sipPySlotType st) +{ + int (*f)(PyObject *,PyObject *); + PyObject *args; + int res; + + /* + * Slot handlers require a single PyObject *. The second argument is + * optional. + */ + if (arg2 == NULL) + args = arg1; + else if (PyTuple_Check(arg1)) + { + int i; + + /* + * It's already a tuple so we need to copy it and append the + * value. + */ + if ((args = PyTuple_New(PyTuple_GET_SIZE(arg1) + 1)) == NULL) + return -1; + + for (i = 0; i < PyTuple_GET_SIZE(arg1); ++i) + { + PyObject *o = PyTuple_GET_ITEM(arg1,i); + + PyTuple_SET_ITEM(args,i,o); + Py_INCREF(o); + } + + PyTuple_SET_ITEM(args,i,arg2); + Py_INCREF(arg2); + } + else if ((args = Py_BuildValue("(OO)",arg1,arg2)) == NULL) + return -1; + + f = (int (*)(PyObject *,PyObject *))findSlot(self,st); + + res = f(self,args); + + if (arg2 != NULL) + { + Py_DECREF(args); + } + + return res; +} + + +/* + * Handle an ssizeobjargproc slot. + */ +static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1, + PyObject *arg2, sipPySlotType st) +{ + int (*f)(PyObject *,PyObject *); + PyObject *args; + int res; + + /* + * Slot handlers require a single PyObject *. The second argument is + * optional. + */ + if (arg2 == NULL) +#if PY_VERSION_HEX >= 0x02050000 + args = PyInt_FromSsize_t(arg1); +#else + args = PyInt_FromLong(arg1); +#endif + else +#if PY_VERSION_HEX >= 0x02050000 + args = Py_BuildValue("(nO)", arg1, arg2); +#else + args = Py_BuildValue("(iO)", arg1, arg2); +#endif + + if (args == NULL) + return -1; + + f = (int (*)(PyObject *,PyObject *))findSlot(self,st); + + res = f(self,args); + + Py_DECREF(args); + + return res; +} + + +/***************************************************************************** + * The functions, data types and structures to support a Python type to hold a + * void * that can be converted to an integer. + *****************************************************************************/ + +/* The object data structure. */ +typedef struct { + PyObject_HEAD + void *voidptr; +} sipVoidPtr; + + +/* + * Implement __new__ for the type. + */ +static PyObject *sipVoidPtr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) +{ + PyObject *obj; + void *ptr; + int nargs, bad; + + /* We don't support keyword arguments. */ + if (kwds != NULL) + { + PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); + return NULL; + } + + /* Get the single argument. */ + if ((nargs = PyTuple_Size(args)) < 0) + return NULL; + + bad = FALSE; + + if (nargs == 1) + { + PyObject *arg = PyTuple_GET_ITEM(args, 0); + + if (arg == Py_None) + ptr = NULL; + else if (PyCObject_Check(arg)) + ptr = PyCObject_AsVoidPtr(arg); + else if (arg->ob_type == &sipVoidPtr_Type) + { + /* + * The type is immutable so just return the argument. + */ + Py_INCREF(arg); + return arg; + } + else + { + ptr = (void *)PyInt_AsLong(arg); + + if (PyErr_Occurred()) + bad = TRUE; + } + } + else + bad = TRUE; + + if (bad) + { + PyErr_SetString(PyExc_TypeError, "a single integer, CObject, None or another voidptr is required"); + return NULL; + } + + /* Create the instance. */ + if ((obj = subtype->tp_alloc(subtype, 0)) == NULL) + return NULL; + + /* Save the pointer. */ + ((sipVoidPtr *)obj)->voidptr = ptr; + + return obj; +} + + +/* + * Implement int() for the type. + */ +static PyObject *sipVoidPtr_int(sipVoidPtr *v) +{ + return PyInt_FromLong((long)v->voidptr); +} + + +/* + * Implement hex() for the type. + */ +static PyObject *sipVoidPtr_hex(sipVoidPtr *v) +{ + char buf[2 + 16 + 1]; + + PyOS_snprintf(buf, sizeof (buf), "0x%.*lx", (int)(sizeof (void *) * 2), (unsigned long)v->voidptr); + + return PyString_FromString(buf); +} + + +/* + * Implement ascobject() for the type. + */ +static PyObject *sipVoidPtr_ascobject(sipVoidPtr *v, PyObject *arg) +{ + return PyCObject_FromVoidPtr(v->voidptr, NULL); +} + + +/* + * Implement asstring() for the type. + */ +static PyObject *sipVoidPtr_asstring(sipVoidPtr *v,PyObject *arg) +{ + long nbytes = PyInt_AsLong(arg); + + if (PyErr_Occurred()) + return NULL; + + return PyString_FromStringAndSize(v->voidptr,nbytes); +} + + +/* The methods data structure. */ +static PyMethodDef sipVoidPtr_Methods[] = { + {"ascobject", (PyCFunction)sipVoidPtr_ascobject, METH_NOARGS, NULL}, + {"asstring", (PyCFunction)sipVoidPtr_asstring, METH_O, NULL}, + {NULL} +}; + + +/* The number methods data structure. */ +PyNumberMethods sipVoidPtr_NumberMethods = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ + 0, /* nb_coerce */ + (unaryfunc)sipVoidPtr_int, /* nb_int */ + 0, /* nb_long */ + 0, /* nb_float */ + 0, /* nb_oct */ + (unaryfunc)sipVoidPtr_hex, /* nb_hex */ +}; + + +/* The type data structure. */ +static PyTypeObject sipVoidPtr_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "sip.voidptr", /* tp_name */ + sizeof (sipVoidPtr), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + &sipVoidPtr_NumberMethods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 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 */ + sipVoidPtr_Methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + sipVoidPtr_new, /* tp_new */ +}; + + +/* + * A convenience function to convert a C/C++ void pointer from a Python object. + */ +static void *sip_api_convert_to_void_ptr(PyObject *obj) +{ + if (obj == NULL) + { + PyErr_SetString(PyExc_TypeError,"sip.voidptr is NULL"); + return NULL; + } + + if (obj == Py_None) + return NULL; + + /* Save a conversion if it's not a sub-type. */ + if (obj->ob_type == &sipVoidPtr_Type) + return ((sipVoidPtr *)obj)->voidptr; + + return (void *)PyInt_AsLong(obj); +} + + +/* + * A convenience function to convert a C/C++ void pointer to a Python object. + */ +PyObject *sip_api_convert_from_void_ptr(void *val) +{ + sipVoidPtr *self; + + if (val == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + if ((self = PyObject_NEW(sipVoidPtr,&sipVoidPtr_Type)) == NULL) + return NULL; + + self->voidptr = val; + + return (PyObject *)self; +} + + +/* + * Return TRUE if a type is a wrapped type, rather than a sub-type implemented + * in Python or the super-type. + */ +static int isExactWrappedType(sipWrapperType *wt) +{ + char *name; + + /* + * We check by comparing the actual type name with the name used to create + * the original wrapped type. + */ +#if PY_VERSION_HEX >= 0x02050000 + if ((name = PyString_AsString(wt->super.ht_name)) == NULL) +#else + if ((name = PyString_AsString(wt->super.name)) == NULL) +#endif + return FALSE; + + return (strcmp(name, getBaseName(wt->type->td_name)) == 0); +} + + +/***************************************************************************** + * The Python metatype for a C++ wrapper type. + *****************************************************************************/ + +/* + * The type alloc slot. + */ +static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems) +{ + PyObject *o; + + /* Call the standard super-metatype alloc. */ + if ((o = PyType_Type.tp_alloc(self, nitems)) == NULL) + return NULL; + + /* + * Consume any extra type specific information and use it to initialise + * the slots. This only happens for directly wrapped classes (and not + * programmer written sub-classes). This must be done in the alloc + * function because it is the only place we can break out of the + * default new() function before PyType_Ready() is called. + */ + if (currentType != NULL) + { + ((sipWrapperType *)o)->type = currentType; + addSlots((sipWrapperType *)o, currentType); + currentType = NULL; + } + + return o; +} + + +/* + * The type init slot. + */ +static int sipWrapperType_init(sipWrapperType *self, PyObject *args, + PyObject *kwds) +{ + /* Call the standard super-metatype init. */ + if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + + /* + * If we don't yet have any extra type specific information (because we are + * a programmer defined sub-class) then get it from the (first) super-type. + */ + if (self->type == NULL) + { + PyTypeObject *sc = ((PyTypeObject *)self)->tp_base; + + /* + * Make sure that the type is derived from sip.wrapper. It might not + * if the type specifies sip.wrappertype as the __metaclass__. + */ + if (sc == NULL || !sipWrapperType_Check((PyObject *)sc)) + { + PyErr_Format(PyExc_TypeError, + "type %s must be derived from sip.wrapper", + ((PyTypeObject *)self)->tp_name); + + return -1; + } + + self->type = ((sipWrapperType *)sc)->type; + } + + return 0; +} + + +/* + * The type getattro slot. + */ +static PyObject *sipWrapperType_getattro(PyObject *obj,PyObject *name) +{ + char *nm; + PyObject *attr; + sipWrapperType *wt = (sipWrapperType *)obj; + + /* + * If we are getting the type dictionary for a base wrapped type then we + * don't want the super-metatype to handle it. + */ + if ((nm = PyString_AsString(name)) == NULL) + return NULL; + + if (strcmp(nm, "__dict__") == 0) + { + int i; + sipTypeDef *td; + sipEnumMemberDef *enm; + PyObject *dict; + PyMethodDef *pmd; + + dict = ((PyTypeObject *)wt)->tp_dict; + + /* The base type doesn't have any type information. */ + if ((td = wt->type) == NULL || !isExactWrappedType(wt)) + { + Py_INCREF(dict); + return dict; + } + + /* + * We can't cache the methods or variables so we need to make a + * temporary copy of the type dictionary and return that (so + * that it will get garbage collected immediately afterwards). + */ + if ((dict = PyDict_Copy(dict)) == NULL) + return NULL; + + /* Search the possible linked list of namespace extenders. */ + do + { + /* + * Add the type's lazy enums. It doesn't matter if + * they are already there. + */ + enm = td->td_enummembers; + + for (i = 0; i < td->td_nrenummembers; ++i) + { + int rc; + PyObject *val; + + if ((val = createEnumMember(td, enm)) == NULL) + return NULL; + + rc = PyDict_SetItemString(dict, enm->em_name, val); + + Py_DECREF(val); + + if (rc < 0) + return NULL; + + ++enm; + } + + /* Do the methods. */ + pmd = td->td_methods; + + for (i = 0; i < td->td_nrmethods; ++i) + { + int rc; + PyObject *meth; + + if ((meth = PyCFunction_New(pmd, NULL)) == NULL) + { + Py_DECREF(dict); + return NULL; + } + + rc = PyDict_SetItemString(dict, pmd->ml_name, meth); + + Py_DECREF(meth); + + if (rc < 0) + { + Py_DECREF(dict); + return NULL; + } + + ++pmd; + } + + /* Do the static variables. */ + if ((pmd = td->td_variables) != NULL) + while (pmd->ml_name != NULL) + { + if ((pmd->ml_flags & METH_STATIC) != 0) + { + int rc; + PyObject *val; + + if ((val = (*pmd->ml_meth)(NULL, NULL)) == NULL) + { + Py_DECREF(dict); + return NULL; + } + + rc = PyDict_SetItemString(dict, pmd->ml_name, val); + + Py_DECREF(val); + + if (rc < 0) + { + Py_DECREF(dict); + return NULL; + } + } + + ++pmd; + } + + td = td->td_nsextender; + } + while (td != NULL); + + return dict; + } + + /* Now try the super-metatype's method. */ + if ((attr = PyType_Type.tp_getattro(obj,name)) != NULL) + return attr; + + return handleGetLazyAttr(name,wt,NULL); +} + + +/* + * The type setattro slot. + */ +static int sipWrapperType_setattro(PyObject *obj,PyObject *name,PyObject *value) +{ + int rc; + + rc = handleSetLazyAttr(name,value,(sipWrapperType *)obj,NULL); + + if (rc <= 0) + return rc; + + /* Try the super-type's method last. */ + return PyType_Type.tp_setattro(obj,name,value); +} + + +/* + * The type data structure. 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 PyTypeObject sipWrapperType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "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_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 */ + sipWrapperType_getattro, /* tp_getattro */ + sipWrapperType_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)sipWrapperType_init, /* tp_init */ + sipWrapperType_alloc, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + + +/***************************************************************************** + * The Python type that is the super-type for all C++ wrapper types. + *****************************************************************************/ + +/* + * The instance new slot. + */ +static PyObject *sipWrapper_new(sipWrapperType *wt,PyObject *args,PyObject *kwds) +{ + /* See if it is a namespace. */ + if (wt->type->td_fcto == NULL) + { + PyErr_Format(PyExc_TypeError, "%s represents a C++ namespace that cannot be instantiated", wt->type->td_name); + + return NULL; + } + + /* + * See if the object is being created explicitly rather than being wrapped. + */ + if (sipGetPending(NULL, NULL) == NULL) + { + /* + * See if it cannot be instantiated or sub-classed from Python, eg. + * it's an opaque class. Some restrictions might be overcome with + * better SIP support. + */ + if (wt->type->td_init == NULL) + { + PyErr_Format(PyExc_TypeError,"%s cannot be instantiated or sub-classed", wt->type->td_name); + + return NULL; + } + + /* See if it is an abstract type. */ + if (sipTypeIsAbstract(wt) && strcmp(strchr(wt->type->td_name, '.') + 1, ((PyTypeObject *)wt)->tp_name) == 0) + { + PyErr_Format(PyExc_TypeError, "%s represents a C++ abstract class and cannot be instantiated", wt->type->td_name); + + return NULL; + } + } + + /* Call the standard super-type new. */ + return PyBaseObject_Type.tp_new((PyTypeObject *)wt, args, kwds); +} + + +/* + * The instance init slot. + */ +static int sipWrapper_init(sipWrapper *self,PyObject *args,PyObject *kwds) +{ + void *sipNew; + int sipFlags; + sipWrapper *owner; + + if (self->ob_type == (PyTypeObject *)&sipWrapper_Type) + { + PyErr_SetString(PyExc_TypeError,"the sip.wrapper type cannot be instantiated"); + return -1; + } + + if (kwds != NULL) + { + PyErr_SetString(PyExc_TypeError,"keyword arguments are not supported"); + return -1; + } + + /* Check there is no existing C++ instance waiting to be wrapped. */ + if ((sipNew = sipGetPending(&owner, &sipFlags)) == NULL) + { + int argsparsed = 0; + sipWrapperType *wt = (sipWrapperType *)self->ob_type; + + /* Call the C++ ctor. */ + owner = NULL; + + if ((sipNew = wt->type->td_init(self, args, &owner, &argsparsed)) != NULL) + sipFlags = SIP_DERIVED_CLASS; + else + { + int pstate = argsparsed & PARSE_MASK; + sipInitExtenderDef *ie = wt->iextend; + + /* + * While we just have signature errors, try any initialiser + * extenders. + */ + while (ie != NULL && (pstate == PARSE_MANY || pstate == PARSE_FEW || pstate == PARSE_TYPE)) + { + argsparsed = 0; + + if ((sipNew = ie->ie_extender(self, args, &owner, &argsparsed)) != NULL) + break; + + pstate = argsparsed & PARSE_MASK; + ie = ie->ie_next; + } + + if (sipNew == NULL) + { + /* + * If the arguments were parsed without error then assume an + * exception has already been raised for why the instance + * wasn't created. + */ + if (pstate == PARSE_OK) + argsparsed = PARSE_RAISED; + + badArgs(argsparsed, NULL, getBaseName(wt->type->td_name)); + return -1; + } + + sipFlags = 0; + } + + if (owner == NULL) + sipFlags |= SIP_PY_OWNED; + } + + addToParent(self, owner); + + self->u.cppPtr = sipNew; + self->flags = sipFlags; + + if (!sipNotInMap(self)) + sipOMAddObject(&cppPyMap,self); + + return 0; +} + + +/* + * The instance traverse slot. + */ +static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg) +{ + int vret; + void *ptr; + sipTypeDef *td; + sipWrapper *w; + sipPySig *ps; + + /* Call the nearest handwritten traverse code in the class hierachy. */ + if ((ptr = getPtrTypeDef(self, &td)) != NULL) + { + sipTypeDef *ctd = td; + + if (td->td_traverse == NULL) + { + sipEncodedClassDef *sup; + + if ((sup = td->td_supers) != NULL) + do + ctd = getClassType(sup, td->td_module)->type; + while (ctd->td_traverse == NULL && !sup++->sc_flag); + } + + if (ctd->td_traverse != NULL) + if ((vret = ctd->td_traverse(ptr, visit, arg)) != 0) + return vret; + } + + if (qt_and_sip_api_3_4()) + { + void *tx = sipGetAddress(self); + + if (tx != NULL) + { + sipSlotConnection *conn; + void *context = NULL; + + while ((conn = sipQtSupport->qt_find_connection(tx, &context)) != NULL) + { + if ((vret = visitSlot(&conn->sc_slot, visit, arg)) != 0) + return vret; + + if (context == NULL) + break; + } + } + } + + for (ps = self->pySigList; ps != NULL; ps = ps->next) + { + sipSlotList *psrx; + + for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next) + if ((vret = visitSlot(&psrx->rx, visit, arg)) != 0) + return vret; + } + + if (self->user != NULL) + if ((vret = visit(self->user, arg)) != 0) + return vret; + + if (self->dict != NULL) + if ((vret = visit(self->dict, arg)) != 0) + return vret; + + 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; +} + + +/* + * The instance clear slot. + */ +static int sipWrapper_clear(sipWrapper *self) +{ + int vret = 0; + void *ptr; + sipTypeDef *td; + PyObject *tmp; + sipPySig *ps; + + /* Call the nearest handwritten clear code in the class hierachy. */ + if ((ptr = getPtrTypeDef(self, &td)) != NULL) + { + sipTypeDef *ctd = td; + + if (td->td_clear == NULL) + { + sipEncodedClassDef *sup; + + if ((sup = td->td_supers) != NULL) + do + ctd = getClassType(sup, td->td_module)->type; + while (ctd->td_clear == NULL && !sup++->sc_flag); + } + + if (ctd->td_clear != NULL) + vret = ctd->td_clear(ptr); + } + + /* Remove any lambda slots connected via a proxy. */ + if (qt_and_sip_api_3_4()) + { + void *tx = sipGetAddress(self); + + if (tx != NULL) + { + sipSlotConnection *conn; + void *context = NULL; + + while ((conn = sipQtSupport->qt_find_connection(tx, &context)) != NULL) + { + clearAnyLambda(&conn->sc_slot); + + if (context == NULL) + break; + } + } + } + + /* Remove any lambda slots connected to PyQt v3 Python signals. */ + for (ps = self->pySigList; ps != NULL; ps = ps->next) + { + sipSlotList *psrx; + + for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next) + clearAnyLambda(&psrx->rx); + } + + /* Remove any user object. */ + tmp = self->user; + self->user = NULL; + Py_XDECREF(tmp); + + /* Remove the instance dictionary. */ + tmp = self->dict; + self->dict = NULL; + Py_XDECREF(tmp); + + /* Detach children (which will be owned by C/C++. */ + while (self->first_child != NULL) + { + /* + * Although this object is being garbage collected it doesn't follow + * that it's children should be. So we make sure that the child stays + * alive and remember we have done so. + */ + Py_INCREF(self->first_child); + sipSetCppHasRef(self->first_child); + + removeFromParent(self->first_child); + } + + return vret; +} + + +/* + * The instance read buffer slot. + */ +static SIP_SSIZE_T sipWrapper_getreadbuffer(sipWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + sipTypeDef *td; + + if ((ptr = getPtrTypeDef(self, &td)) == NULL) + return -1; + + return td->td_readbuffer((PyObject *)self, ptr, segment, ptrptr); +} + + +/* + * The instance write buffer slot. + */ +static SIP_SSIZE_T sipWrapper_getwritebuffer(sipWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + sipTypeDef *td; + + if ((ptr = getPtrTypeDef(self, &td)) == NULL) + return -1; + + return td->td_writebuffer((PyObject *)self, ptr, segment, ptrptr); +} + + +/* + * The instance segment count slot. + */ +static SIP_SSIZE_T sipWrapper_getsegcount(sipWrapper *self, SIP_SSIZE_T *lenp) +{ + void *ptr; + sipTypeDef *td; + + if ((ptr = getPtrTypeDef(self, &td)) == NULL) + return 0; + + return td->td_segcount((PyObject *)self, ptr, lenp); +} + + +/* + * The instance char buffer slot. + */ +static SIP_SSIZE_T sipWrapper_getcharbuffer(sipWrapper *self, + SIP_SSIZE_T segment, void **ptrptr) +{ + void *ptr; + sipTypeDef *td; + + if ((ptr = getPtrTypeDef(self, &td)) == NULL) + return -1; + + return td->td_charbuffer((PyObject *)self, ptr, segment, ptrptr); +} + + +/* + * The instance dealloc slot. + */ +static void sipWrapper_dealloc(sipWrapper *self) +{ + sipTypeDef *td; + + if (getPtrTypeDef(self, &td) != NULL) + { + /* + * Remove the object from the map before calling the class specific + * dealloc code. This code calls the C++ dtor and may result in + * further calls that pass the instance as an argument. If this is + * still in the map then it's reference count would be increased (to + * one) and bad things happen when it drops back to zero again. (An + * example is PyQt events generated during the dtor call being passed + * to an event filter implemented in Python.) By removing it from the + * map first we ensure that a new Python object is created. + */ + sipOMRemoveObject(&cppPyMap, self); + + /* Call the C++ dtor if there is one. */ + if (td->td_dealloc != NULL) + td->td_dealloc(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()). + */ + sipWrapper_clear(self); + + while (self->pySigList != NULL) + { + sipPySig *ps; + sipSlotList *psrx; + + /* Take this one out of the list. */ + ps = self->pySigList; + self->pySigList = ps->next; + + while ((psrx = ps->rxlist) != NULL) + { + ps->rxlist = psrx->next; + sipFreeSlotList(psrx); + } + + sip_api_free(ps->name); + sip_api_free(ps); + } + + /* Call the standard super-type dealloc. */ + PyBaseObject_Type.tp_dealloc((PyObject *)self); +} + + +/* + * The instance call slot. Note that keyword arguments aren't supported. + */ +static PyObject *sipWrapper_call(PyObject *self,PyObject *args,PyObject *kw) +{ + PyObject *(*f)(PyObject *,PyObject *); + + f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,call_slot); + + return f(self,args); +} + + +/* + * The sequence instance item slot. + */ +static PyObject *sipWrapper_sq_item(PyObject *self, SIP_SSIZE_T n) +{ + PyObject *(*f)(PyObject *,PyObject *); + PyObject *arg, *res; + +#if PY_VERSION_HEX >= 0x02050000 + if ((arg = PyInt_FromSsize_t(n)) == NULL) +#else + if ((arg = PyInt_FromLong(n)) == NULL) +#endif + return NULL; + + f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,getitem_slot); + + res = f(self,arg); + + Py_DECREF(arg); + + return res; +} + + +/* + * The mapping instance assign subscript slot. + */ +static int sipWrapper_mp_ass_subscript(PyObject *self,PyObject *key, + PyObject *value) +{ + return objobjargprocSlot(self,key,value,(value != NULL ? setitem_slot : delitem_slot)); +} + + +/* + * The sequence instance assign item slot. + */ +static int sipWrapper_sq_ass_item(PyObject *self, SIP_SSIZE_T i, PyObject *o) +{ + return ssizeobjargprocSlot(self, i, o, (o != NULL ? setitem_slot : delitem_slot)); +} + + +/* + * The instance rich compare slot. + */ +static PyObject *sipWrapper_richcompare(PyObject *self,PyObject *arg,int op) +{ + PyObject *(*f)(PyObject *,PyObject *); + sipPySlotType st; + + /* Convert the operation to a slot type. */ + switch (op) + { + case Py_LT: + st = lt_slot; + break; + + case Py_LE: + st = le_slot; + break; + + case Py_EQ: + st = eq_slot; + break; + + case Py_NE: + st = ne_slot; + break; + + case Py_GT: + st = gt_slot; + break; + + case Py_GE: + st = ge_slot; + break; + } + + /* It might not exist if not all the above have been implemented. */ + if ((f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,st)) == NULL) + { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + return f(self,arg); +} + + +/* + * The instance getattro slot. + */ +static PyObject *sipWrapper_getattro(PyObject *obj,PyObject *name) +{ + char *nm; + PyObject *attr; + sipWrapperType *wt = (sipWrapperType *)obj->ob_type; + sipWrapper *w = (sipWrapper *)obj; + + /* + * If we are getting the instance dictionary of a base wrapper type + * then we don't want the metatype to handle it. + */ + if ((nm = PyString_AsString(name)) == NULL) + return NULL; + + if (strcmp(nm, "__dict__") == 0) + { + PyObject *tmpdict = NULL; + + if (isExactWrappedType(wt) && getNonStaticVariables(wt, w, &tmpdict) < 0) + { + Py_XDECREF(tmpdict); + return NULL; + } + + /* + * If a copy of the instance dictionary wasn't created then + * just return the original. Note that Python doesn't want a + * proxy. + */ + if (tmpdict == NULL) + if ((tmpdict = w->dict) == NULL) + tmpdict = PyDict_New(); + else + Py_INCREF(tmpdict); + + return tmpdict; + } + + /* Try the super-type's method first. */ + if ((attr = PyBaseObject_Type.tp_getattro(obj,name)) != NULL) + return attr; + + return handleGetLazyAttr(name,wt,w); +} + + +/* + * Add the values of all non-static variables to a dictionary (first making a + * copy of the dictionary if needed). + */ +static int getNonStaticVariables(sipWrapperType *wt,sipWrapper *w, + PyObject **ndict) +{ + PyMethodDef *pmd; + + if ((pmd = wt->type->td_variables) != NULL) + while (pmd->ml_name != NULL) + { + if ((pmd->ml_flags & METH_STATIC) == 0) + { + int rc; + PyObject *val, *dict; + + /* + * Create a copy of the original dictionary if + * it hasn't already been done. + */ + if ((dict = *ndict) == NULL) + { + if ((dict = PyDict_Copy(w->dict)) == NULL) + return -1; + + *ndict = dict; + } + + if ((val = (*pmd->ml_meth)((PyObject *)w,NULL)) == NULL) + return -1; + + rc = PyDict_SetItemString(dict,pmd->ml_name,val); + + Py_DECREF(val); + + if (rc < 0) + return -1; + } + + ++pmd; + } + + return 0; +} + + +/* + * The instance setattro slot. + */ +static int sipWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value) +{ + int rc; + + rc = handleSetLazyAttr(name,value,(sipWrapperType *)obj->ob_type,(sipWrapper *)obj); + + if (rc <= 0) + return rc; + + /* Try the super-type's method last. */ + return PyBaseObject_Type.tp_setattro(obj,name,value); +} + + +/* + * 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. + */ +static sipWrapperType sipWrapper_Type = { + { + { + PyObject_HEAD_INIT(&sipWrapperType_Type) + 0, /* ob_size */ + "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_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 */ + sipWrapper_getattro, /* tp_getattro */ + sipWrapper_setattro, /* 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 */ + offsetof(sipWrapper,dict), /* tp_dictoffset */ + (initproc)sipWrapper_init, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)sipWrapper_new, /* tp_new */ + 0, /* tp_free */ + }, + }, + 0, + 0 +}; + + +/* + * Add the slots for a type and all its super-types. + */ +static void addSlots(sipWrapperType *wt, sipTypeDef *td) +{ + sipEncodedClassDef *sup; + + /* Add the buffer interface. */ + if (td->td_readbuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getreadbuffer = (readbufferproc)sipWrapper_getreadbuffer; +#else + wt->super.as_buffer.bf_getreadbuffer = (getreadbufferproc)sipWrapper_getreadbuffer; +#endif + + if (td->td_writebuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getwritebuffer = (writebufferproc)sipWrapper_getwritebuffer; +#else + wt->super.as_buffer.bf_getwritebuffer = (getwritebufferproc)sipWrapper_getwritebuffer; +#endif + + if (td->td_segcount != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getsegcount = (segcountproc)sipWrapper_getsegcount; +#else + wt->super.as_buffer.bf_getsegcount = (getsegcountproc)sipWrapper_getsegcount; +#endif + + if (td->td_charbuffer != NULL) +#if PY_VERSION_HEX >= 0x02050000 + wt->super.as_buffer.bf_getcharbuffer = (charbufferproc)sipWrapper_getcharbuffer; +#else + wt->super.as_buffer.bf_getcharbuffer = (getcharbufferproc)sipWrapper_getcharbuffer; +#endif + + /* Add the slots for this type. */ + if (td->td_pyslots != NULL) + initSlots((PyTypeObject *)wt, &wt->super.as_number, &wt->super.as_sequence, &wt->super.as_mapping, td->td_pyslots, FALSE); + + /* Recurse through any super-types. */ + if ((sup = td->td_supers) != NULL) + do + addSlots(wt, getClassType(sup, td->td_module)->type); + while (!sup++->sc_flag); +} + + +/* + * Add the slot handler for each slot present in the type, optionally replacing + * any that have already been defined. + */ +static void initSlots(PyTypeObject *to, PyNumberMethods *nb, PySequenceMethods *sq, PyMappingMethods *mp, sipPySlotDef *slots, int force) +{ + void *f; + + while ((f = slots->psd_func) != NULL) + switch (slots++->psd_type) + { + case str_slot: + if (force || to->tp_str == NULL) + to->tp_str = (reprfunc)f; + break; + + case int_slot: + if (nb != NULL) + if (force || nb->nb_int == NULL) + nb->nb_int = (unaryfunc)f; + break; + + case long_slot: + if (nb != NULL) + if (force || nb->nb_long == NULL) + nb->nb_long = (unaryfunc)f; + break; + + case float_slot: + if (nb != NULL) + if (force || nb->nb_float == NULL) + nb->nb_float = (unaryfunc)f; + break; + + case len_slot: + if (mp != NULL) + if (force || mp->mp_length == NULL) +#if PY_VERSION_HEX >= 0x02050000 + mp->mp_length = (lenfunc)f; +#else + mp->mp_length = (inquiry)f; +#endif + if (sq != NULL) + if (force || sq->sq_length == NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_length = (lenfunc)f; +#else + sq->sq_length = (inquiry)f; +#endif + break; + + case contains_slot: + if (sq != NULL) + if (force || sq->sq_contains == NULL) + sq->sq_contains = (objobjproc)f; + break; + + case add_slot: + if (nb != NULL) + if (force || nb->nb_add == NULL) + nb->nb_add = (binaryfunc)f; + break; + + case concat_slot: + if (sq != NULL) + if (force || sq->sq_concat == NULL) + sq->sq_concat = (binaryfunc)f; + break; + + case sub_slot: + if (nb != NULL) + if (force || nb->nb_subtract == NULL) + nb->nb_subtract = (binaryfunc)f; + break; + + case mul_slot: + if (nb != NULL) + if (force || nb->nb_multiply == NULL) + nb->nb_multiply = (binaryfunc)f; + break; + + case repeat_slot: + if (sq != NULL) + if (force || sq->sq_repeat == NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_repeat = (ssizeargfunc)f; +#else + sq->sq_repeat = (intargfunc)f; +#endif + break; + + case div_slot: + if (nb != NULL) + { + if (force || nb->nb_divide == NULL) + nb->nb_divide = (binaryfunc)f; + + if (force || nb->nb_true_divide == NULL) + nb->nb_true_divide = (binaryfunc)f; + } + break; + + case mod_slot: + if (nb != NULL) + if (force || nb->nb_remainder == NULL) + nb->nb_remainder = (binaryfunc)f; + break; + + case and_slot: + if (nb != NULL) + if (force || nb->nb_and == NULL) + nb->nb_and = (binaryfunc)f; + break; + + case or_slot: + if (nb != NULL) + if (force || nb->nb_or == NULL) + nb->nb_or = (binaryfunc)f; + break; + + case xor_slot: + if (nb != NULL) + if (force || nb->nb_xor == NULL) + nb->nb_xor = (binaryfunc)f; + break; + + case lshift_slot: + if (nb != NULL) + if (force || nb->nb_lshift == NULL) + nb->nb_lshift = (binaryfunc)f; + break; + + case rshift_slot: + if (nb != NULL) + if (force || nb->nb_rshift == NULL) + nb->nb_rshift = (binaryfunc)f; + break; + + case iadd_slot: + if (nb != NULL) + if (force || nb->nb_inplace_add == NULL) + nb->nb_inplace_add = (binaryfunc)f; + break; + + case iconcat_slot: + if (sq != NULL) + if (force || sq->sq_inplace_concat == NULL) + sq->sq_inplace_concat = (binaryfunc)f; + break; + + case isub_slot: + if (nb != NULL) + if (force || nb->nb_inplace_subtract == NULL) + nb->nb_inplace_subtract = (binaryfunc)f; + break; + + case imul_slot: + if (nb != NULL) + if (force || nb->nb_inplace_multiply == NULL) + nb->nb_inplace_multiply = (binaryfunc)f; + break; + + case irepeat_slot: + if (sq != NULL) + if (force || sq->sq_inplace_repeat == NULL) +#if PY_VERSION_HEX >= 0x02050000 + sq->sq_inplace_repeat = (ssizeargfunc)f; +#else + sq->sq_inplace_repeat = (intargfunc)f; +#endif + break; + + case idiv_slot: + if (nb != NULL) + { + if (force || nb->nb_inplace_divide == NULL) + nb->nb_inplace_divide = (binaryfunc)f; + + if (force || nb->nb_inplace_true_divide == NULL) + nb->nb_inplace_true_divide = (binaryfunc)f; + } + break; + + case imod_slot: + if (nb != NULL) + if (force || nb->nb_inplace_remainder == NULL) + nb->nb_inplace_remainder = (binaryfunc)f; + break; + + case iand_slot: + if (nb != NULL) + if (force || nb->nb_inplace_and == NULL) + nb->nb_inplace_and = (binaryfunc)f; + break; + + case ior_slot: + if (nb != NULL) + if (force || nb->nb_inplace_or == NULL) + nb->nb_inplace_or = (binaryfunc)f; + break; + + case ixor_slot: + if (nb != NULL) + if (force || nb->nb_inplace_xor == NULL) + nb->nb_inplace_xor = (binaryfunc)f; + break; + + case ilshift_slot: + if (nb != NULL) + if (force || nb->nb_inplace_lshift == NULL) + nb->nb_inplace_lshift = (binaryfunc)f; + break; + + case irshift_slot: + if (nb != NULL) + if (force || nb->nb_inplace_rshift == NULL) + nb->nb_inplace_rshift = (binaryfunc)f; + break; + + case invert_slot: + if (nb != NULL) + if (force || nb->nb_invert == NULL) + nb->nb_invert = (unaryfunc)f; + break; + + case call_slot: + if (force || to->tp_call == NULL) + to->tp_call = sipWrapper_call; + break; + + case getitem_slot: + if (mp != NULL) + if (force || mp->mp_subscript == NULL) + mp->mp_subscript = (binaryfunc)f; + if (sq != NULL) + if (force || sq->sq_item == NULL) + sq->sq_item = sipWrapper_sq_item; + break; + + case setitem_slot: + case delitem_slot: + if (mp != NULL) + if (force || mp->mp_ass_subscript == NULL) + mp->mp_ass_subscript = sipWrapper_mp_ass_subscript; + if (sq != NULL) + if (force || sq->sq_ass_item == NULL) + sq->sq_ass_item = sipWrapper_sq_ass_item; + break; + + case lt_slot: + case le_slot: + case eq_slot: + case ne_slot: + case gt_slot: + case ge_slot: + if (force || to->tp_richcompare == NULL) + to->tp_richcompare = sipWrapper_richcompare; + break; + + case cmp_slot: + if (force || to->tp_compare == NULL) + to->tp_compare = (cmpfunc)f; + break; + + case nonzero_slot: + if (nb != NULL) + if (force || nb->nb_nonzero == NULL) + nb->nb_nonzero = (inquiry)f; + break; + + case neg_slot: + if (nb != NULL) + if (force || nb->nb_negative == NULL) + nb->nb_negative = (unaryfunc)f; + break; + + case repr_slot: + if (force || to->tp_repr == NULL) + to->tp_repr = (reprfunc)f; + break; + + case hash_slot: + if (force || to->tp_hash == NULL) + to->tp_hash = (hashfunc)f; + break; + + case pos_slot: + if (nb != NULL) + if (force || nb->nb_positive == NULL) + nb->nb_positive = (unaryfunc)f; + break; + + case abs_slot: + if (nb != NULL) + if (force || nb->nb_absolute == NULL) + nb->nb_absolute = (unaryfunc)f; + break; + } +} + + +/* + * Search for a named class and return the wrapper type. + */ +static sipWrapperType *findClass(sipExportedModuleDef *emd, const char *name, + size_t len) +{ + int i; + sipWrapperType **wtp = emd->em_types; + + for (i = 0; i < emd->em_nrtypes; ++i) + { + sipWrapperType *wt; + + if ((wt = *wtp++) == NULL) + continue; + + if (wt->type->td_cname != NULL) + { + if (!nameEq(wt->type->td_cname, name, len)) + continue; + } + else if (!sameScopedName(wt->type->td_name, name, len)) + continue; + + return wt; + } + + return NULL; +} + + +/* + * Search for a named class and return TRUE and the necessary information to + * create an instance of it if it was found. + */ +static int findClassArg(sipExportedModuleDef *emd, const char *name, + size_t len, sipSigArg *at, int indir) +{ + sipWrapperType *wt = findClass(emd, name, len); + + if (wt == NULL) + return FALSE; + + if (indir == 0) + at->atype = class_sat; + else if (indir == 1) + at->atype = classp_sat; + else + at->atype = unknown_sat; + + at->u.wt = wt; + + return TRUE; +} + + +/* + * Search for a mapped type and return TRUE and the necessary information to + * create an instance of it if it was found. + */ +static int findMtypeArg(sipMappedType **mttab, const char *name, size_t len, + sipSigArg *at, int indir) +{ + sipMappedType *mt; + + while ((mt = *mttab++) != NULL) + if (nameEq(mt->mt_name, name, len)) + { + if (indir == 0) + at->atype = mtype_sat; + else if (indir == 1) + at->atype = mtypep_sat; + else + at->atype = unknown_sat; + + at->u.mt = mt; + + return TRUE; + } + + return FALSE; +} + + +/* + * Search for a named enum in a particular module and return the corresponding + * type object. + */ +static PyTypeObject *findEnum(sipExportedModuleDef *emd, const char *name, + size_t len) +{ + int i; + sipEnumDef *ed; + + for (ed = emd->em_enumdefs, i = 0; i < emd->em_nrenums; ++i, ++ed) + { + if (ed->e_cname != NULL) + { + if (!nameEq(ed->e_cname, name, len)) + continue; + } + else if (!sameScopedName(ed->e_name, name, len)) + continue; + + return emd->em_enums[i]; + } + + return NULL; +} + + +/* + * Search for a named enum and return TRUE and the necessary information to + * create an instance of it if it was found. + */ +static int findEnumArg(sipExportedModuleDef *emd, const char *name, size_t len, + sipSigArg *at, int indir) +{ + PyTypeObject *py = findEnum(emd, name, len); + + if (py == NULL) + return FALSE; + + if (indir == 0) + at->atype = enum_sat; + else + at->atype = unknown_sat; + + at->u.et = py; + + return TRUE; +} + + +/* + * Search for a named type and the necessary information to create an instance + * of it. + */ +void sipFindSigArgType(const char *name, size_t len, sipSigArg *at, int indir) +{ + sipExportedModuleDef *em; + sipPyObject *po; + + at->atype = unknown_sat; + + for (em = clientList; em != NULL; em = em->em_next) + { + sipTypedefDef *tdd; + + /* Search for a typedef. */ + if ((tdd = em->em_typedefs) != NULL) + while (tdd->tdd_name != NULL) + { + if (nameEq(tdd->tdd_name, name, len)) + { + sipExportedModuleDef *tem; + const char *tn; + size_t tnlen; + + at->atype = tdd->tdd_type; + + /* Done with the simple cases. */ + if ((tn = tdd->tdd_type_name) == NULL) + return; + + /* + * Find the module that this class, mapped type or enum is + * defined in. + */ + if (tdd->tdd_mod_name == NULL) + tem = em; + else + for (tem = clientList; tem != NULL; tem = tem->em_next) + if (strcmp(tem->em_name, tdd->tdd_mod_name) == 0) + break; + + tnlen = strlen(tn); + + switch (tdd->tdd_type) + { + case class_sat: + findClassArg(tem, tn, tnlen, at, indir); + break; + + case mtype_sat: + findMtypeArg(tem->em_mappedtypes, tn, tnlen, at, indir); + break; + + case enum_sat: + findEnumArg(tem, tn, tnlen, at, indir); + break; + } + + /* We should have found it by now. */ + return; + } + + ++tdd; + } + + /* Search for a class. */ + if (em->em_types != NULL && findClassArg(em, name, len, at, indir)) + return; + + /* Search for a mapped type. */ + if (em->em_mappedtypes != NULL && findMtypeArg(em->em_mappedtypes, name, len, at, indir)) + return; + + /* Search for an enum. */ + if (em->em_enums != NULL && findEnumArg(em, name, len, at, indir)) + return; + } + + /* Search for a dynamically registered int type. */ + for (po = sipRegisteredIntTypes; po != NULL; po = po->next) + { + int i; + + for (i = 0; i < PyTuple_GET_SIZE(po->object); ++i) + { + char *int_nm = PyString_AsString(PyTuple_GET_ITEM(po->object, i)); + + if (int_nm == NULL) + continue; + + if (nameEq(int_nm, name, len)) + { + at->atype = int_sat; + return; + } + } + } +} + + +/* + * Compare a '\0' terminated string with the first len characters of a second + * and return a non-zero value if they are equal. + */ +static int nameEq(const char *with, const char *name, size_t len) +{ + return (strlen(with) == len && strncmp(with, name, len) == 0); +} + + +/* + * Return TRUE if a Python scoped name and a fixed length C++ scoped name + * match. + */ +static int sameScopedName(const char *pyname, const char *name, size_t len) +{ + char ch; + + /* Skip the module name from the Python name. */ + pyname = strchr(pyname, '.') + 1; + + while ((ch = *pyname++) != '\0' && len) + if (ch == '.') + { + if (len < 2 || name[0] != ':' || name[1] != ':') + return FALSE; + + name += 2; + len -= 2; + } + else if (ch == name[0]) + { + ++name; + --len; + } + else + return FALSE; + + return (ch == '\0' && len == 0); +} + + +/* + * Register a Python tuple of type names that will be interpreted as ints if + * they are seen as signal arguments. + */ +static int sip_api_register_int_types(PyObject *args) +{ + sipPyObject *po; + int bad_args = FALSE; + + /* Raise an exception if the arguments are bad. */ + if (PyTuple_Check(args)) + { + int i; + + for (i = 0; i < PyTuple_GET_SIZE(args); ++i) + if (!PyString_Check(PyTuple_GET_ITEM(args, i))) + { + bad_args = TRUE; + break; + } + } + else + bad_args = TRUE; + + if (bad_args) + { + PyErr_SetString(PyExc_TypeError, "all arguments must be strings"); + return -1; + } + + if ((po = sip_api_malloc(sizeof (sipPyObject))) == NULL) + return -1; + + Py_INCREF(args); + + po->object = args; + po->next = sipRegisteredIntTypes; + + sipRegisteredIntTypes = 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; +} + + +/* + * Returns TRUE if the Qt support is present and conforms to the v3.4 or later + * of the SIP API. + */ +static int qt_and_sip_api_3_4(void) +{ + return (sipQtSupport != NULL && sipQObjectClass->type->td_module->em_api_minor >= 4); +} + + +/* + * Visit a slot connected to an object for the cyclic garbage collector. + */ +static int visitSlot(sipSlot *slot, visitproc visit, void *arg) +{ + if (slot->pyobj != NULL && sipLambdaSlot(slot->pyobj)) + return visit(slot->pyobj, arg); + + return 0; +} + + +/* + * Clear a slot if it is a lambda function. + */ +static void clearAnyLambda(sipSlot *slot) +{ + PyObject *lam = slot->pyobj; + + if (lam != NULL && sipLambdaSlot(lam)) + { + /* + * Replace the lambda function with None. We don't use NULL as this + * has another meaning. + */ + Py_INCREF(Py_None); + slot->pyobj = Py_None; + + Py_DECREF(lam); + } +} + + +/* + * Convert a Python object to a character. + */ +static char sip_api_string_as_char(PyObject *obj) +{ + char ch; + + if (parseChar(obj, &ch) < 0) + { + PyErr_SetString(PyExc_ValueError, "string of length 1 expected"); + + return '\0'; + } + + return ch; +} + + +/* + * Parse a character array and return it's address and length. + */ +static int parseCharArray(PyObject *obj, char **ap, int *aszp) +{ + if (obj == Py_None) + { + *ap = NULL; + *aszp = 0; + } + else if (PyString_Check(obj)) + { + *ap = PyString_AS_STRING(obj); + *aszp = (int)PyString_GET_SIZE(obj); + } + else + return -1; + + return 0; +} + + +/* + * Parse a character and return it. + */ +static int parseChar(PyObject *obj, char *ap) +{ + if (!PyString_Check(obj) || PyString_GET_SIZE(obj) != 1) + return -1; + + *ap = *PyString_AS_STRING(obj); + + return 0; +} + + +/* + * Parse a character string and return it. + */ +static int parseCharString(PyObject *obj, char **ap) +{ + if (obj == Py_None) + *ap = NULL; + else if (PyString_Check(obj)) + *ap = PyString_AS_STRING(obj); + else + return -1; + + 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_SetString(PyExc_ValueError, "unicode string of length 1 expected"); + + 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_SetString(PyExc_ValueError, "unicode string expected"); + + return NULL; + } + + return p; +} + + +/* + * Parse a wide character array and return it's address and length. + */ +static int parseWCharArray(PyObject *obj, wchar_t **ap, int *aszp) +{ + if (obj == Py_None) + { + *ap = NULL; + *aszp = 0; + } + else if (PyUnicode_Check(obj)) + { + SIP_SSIZE_T ulen; + wchar_t *wc; + + ulen = PyUnicode_GET_SIZE(obj); + + if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL) + return -1; + + ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); + + if (ulen < 0) + { + sip_api_free(wc); + return -1; + } + + *ap = wc; + *aszp = (int)ulen; + } + else + return -1; + + return 0; +} + + +/* + * Parse a wide character and return it. + */ +static int parseWChar(PyObject *obj, wchar_t *ap) +{ + if (!PyUnicode_Check(obj) || PyUnicode_GET_SIZE(obj) != 1) + return -1; + + if (PyUnicode_AsWideChar((PyUnicodeObject *)obj, ap, 1) != 1) + return -1; + + return 0; +} + + +/* + * Parse a wide character string and return it. + */ +static int parseWCharString(PyObject *obj, wchar_t **ap) +{ + if (obj == Py_None) + *ap = NULL; + else if (PyUnicode_Check(obj)) + { + SIP_SSIZE_T ulen; + wchar_t *wc; + + ulen = PyUnicode_GET_SIZE(obj); + + if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL) + return -1; + + ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); + + if (ulen < 0) + { + sip_api_free(wc); + return -1; + } + + wc[ulen] = L'\0'; + + *ap = wc; + } + else + return -1; + + 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 |