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.
7903 lines
199 KiB
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
|