You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/python/sip/siplib/siplib.c

7903 lines
199 KiB

/*
* 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