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.
sip4-tqt/siplib/siplib.c

9922 lines
254 KiB

/*
* SIP-TQt library code.
*
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP-TQt.
*
* This copy of SIP-TQt is licensed for use under the terms of the SIP License
* Agreement. See the file LICENSE for more details.
*
* This copy of SIP-TQt may also used under the terms of the GNU General Public
* License v2 or v3 as published by the Free Software Foundation which can be
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
*
* SIP-TQt is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <Python.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include "sip-tqt.h"
#include "sipint.h"
/* There doesn't seem to be a standard way of checking for C99 support. */
#if !defined(va_copy)
#define va_copy(d, s) ((d) = (s))
#endif
/*
* The Python metatype for a C++ wrapper type. We inherit everything from the
* standard Python metatype except the init and getattro methods and the size
* of the type object created is increased to accomodate the extra information
* we associate with a wrapped type.
*/
static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems);
static PyObject *sipWrapperType_getattro(PyObject *self, PyObject *name);
static int sipWrapperType_init(sipWrapperType *self, PyObject *args,
PyObject *kwds);
static int sipWrapperType_setattro(PyObject *self, PyObject *name,
PyObject *value);
static PyTypeObject sipWrapperType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"sip_tqt.wrappertype", /* tp_name */
sizeof (sipWrapperType), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved (Python v3), tp_compare (Python v2) */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
sipWrapperType_getattro, /* tp_getattro */
sipWrapperType_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)sipWrapperType_init, /* tp_init */
sipWrapperType_alloc, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
};
/*
* The Python type that is the super-type for all C++ wrapper types that
* support parent/child relationships.
*/
static int sipWrapper_clear(sipWrapper *self);
static void sipWrapper_dealloc(sipWrapper *self);
static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg);
static sipWrapperType sipWrapper_Type = {
#if !defined(STACKLESS)
{
#endif
{
PyVarObject_HEAD_INIT(&sipWrapperType_Type, 0)
"sip_tqt.wrapper", /* tp_name */
sizeof (sipWrapper), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)sipWrapper_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved (Python v3), tp_compare (Python v2) */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)sipWrapper_traverse, /* tp_traverse */
(inquiry)sipWrapper_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
},
#if !defined(STACKLESS)
},
#endif
0,
0
};
static void sip_api_bad_catcher_result(PyObject *method);
static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen,
SIP_SSIZE_T slicelen);
static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...);
static PyObject *sip_api_call_method(int *isErr, PyObject *method,
const char *fmt, ...);
static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx,
SIP_SSIZE_T len);
static int sip_api_can_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
int flags);
static void *sip_api_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
PyObject *transferObj, int flags, int *statep, int *iserrp);
static void *sip_api_force_convert_to_type(PyObject *pyObj,
const sipTypeDef *td, PyObject *transferObj, int flags, int *statep,
int *iserrp);
static int sip_api_can_convert_to_enum(PyObject *pyObj, const sipTypeDef *td);
static void sip_api_release_type(void *cpp, const sipTypeDef *td, int state);
static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td,
PyObject *transferObj);
static int sip_api_get_state(PyObject *transferObj);
static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td);
static sipWrapperType *sip_api_map_int_to_class(int typeInt,
const sipIntTypeClassMap *map, int maplen);
static sipWrapperType *sip_api_map_string_to_class(const char *typeString,
const sipStringTypeClassMap *map, int maplen);
static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res,
const char *fmt, ...);
static void sip_api_trace(unsigned mask,const char *fmt,...);
static void sip_api_transfer_back(PyObject *self);
static void sip_api_transfer_to(PyObject *self, PyObject *owner);
static int sip_api_export_module(sipExportedModuleDef *client,
unsigned api_major, unsigned api_minor, void *unused);
static int sip_api_init_module(sipExportedModuleDef *client,
PyObject *mod_dict);
static int sip_api_parse_args(PyObject **parseErrp, PyObject *sipArgs,
const char *fmt, ...);
static int sip_api_parse_kwd_args(PyObject **parseErrp, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused,
const char *fmt, ...);
static int sip_api_parse_pair(PyObject **parseErrp, PyObject *sipArg0,
PyObject *sipArg1, const char *fmt, ...);
static void sip_api_no_function(PyObject *parseErr, const char *func,
const char *doc);
static void sip_api_no_method(PyObject *parseErr, const char *scope,
const char *method, const char *doc);
static void sip_api_abstract_method(const char *classname, const char *method);
static void sip_api_bad_class(const char *classname);
static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw);
static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc,
sipSimpleWrapper *sipSelf, const char *cname, const char *mname);
static void sip_api_call_hook(const char *hookname);
static void sip_api_raise_unknown_exception(void);
static void sip_api_raise_type_exception(const sipTypeDef *td, void *ptr);
static int sip_api_add_type_instance(PyObject *dict, const char *name,
void *cppPtr, const sipTypeDef *td);
static sipErrorState sip_api_bad_callable_arg(int arg_nr, PyObject *arg);
static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg,
sipPySlotType st);
static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod,
sipPySlotType st, const sipTypeDef *td, PyObject *arg0,
PyObject *arg1);
static void sip_api_add_delayed_dtor(sipSimpleWrapper *w);
static unsigned long sip_api_long_as_unsigned_long(PyObject *o);
static int sip_api_export_symbol(const char *name, void *sym);
static void *sip_api_import_symbol(const char *name);
static const sipTypeDef *sip_api_find_type(const char *type);
static sipWrapperType *sip_api_find_class(const char *type);
static const sipMappedType *sip_api_find_mapped_type(const char *type);
static PyTypeObject *sip_api_find_named_enum(const char *type);
static char sip_api_bytes_as_char(PyObject *obj);
static const char *sip_api_bytes_as_string(PyObject *obj);
static char sip_api_string_as_ascii_char(PyObject *obj);
static const char *sip_api_string_as_ascii_string(PyObject **obj);
static char sip_api_string_as_latin1_char(PyObject *obj);
static const char *sip_api_string_as_latin1_string(PyObject **obj);
static char sip_api_string_as_utf8_char(PyObject *obj);
static const char *sip_api_string_as_utf8_string(PyObject **obj);
#if defined(HAVE_WCHAR_H)
static wchar_t sip_api_unicode_as_wchar(PyObject *obj);
static wchar_t *sip_api_unicode_as_wstring(PyObject *obj);
#else
static int sip_api_unicode_as_wchar(PyObject *obj);
static int *sip_api_unicode_as_wstring(PyObject *obj);
#endif
static void sip_api_transfer_break(PyObject *self);
static int sip_api_deprecated(const char *classname, const char *method);
static int sip_api_register_py_type(PyTypeObject *supertype);
static PyObject *sip_api_convert_from_enum(int eval, const sipTypeDef *td);
static const sipTypeDef *sip_api_type_from_py_type_object(PyTypeObject *py_type);
static const sipTypeDef *sip_api_type_scope(const sipTypeDef *td);
static const char *sip_api_resolve_typedef(const char *name);
static int sip_api_register_attribute_getter(const sipTypeDef *td,
sipAttrGetterFunc getter);
static void sip_api_clear_any_slot_reference(sipSlot *slot);
static int sip_api_visit_slot(sipSlot *slot, visitproc visit, void *arg);
static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj);
static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp);
/*
* The data structure that represents the SIP-TQt API.
*/
static const sipAPIDef sip_api = {
/* This must be first. */
sip_api_export_module,
/*
* The following are part of the public API.
*/
(PyTypeObject *)&sipSimpleWrapper_Type,
(PyTypeObject *)&sipWrapper_Type,
&sipWrapperType_Type,
&sipVoidPtr_Type,
sip_api_bad_catcher_result,
sip_api_bad_length_for_slice,
sip_api_build_result,
sip_api_call_method,
sip_api_connect_rx,
sip_api_convert_from_sequence_index,
sip_api_can_convert_to_type,
sip_api_convert_to_type,
sip_api_force_convert_to_type,
sip_api_can_convert_to_enum,
sip_api_release_type,
sip_api_convert_from_type,
sip_api_convert_from_new_type,
sip_api_convert_from_enum,
sip_api_get_state,
sip_api_disconnect_rx,
sip_api_free,
sip_api_get_pyobject,
sip_api_malloc,
sip_api_parse_result,
sip_api_trace,
sip_api_transfer_back,
sip_api_transfer_to,
sip_api_transfer_break,
sip_api_long_as_unsigned_long,
sip_api_convert_from_void_ptr,
sip_api_convert_from_const_void_ptr,
sip_api_convert_from_void_ptr_and_size,
sip_api_convert_from_const_void_ptr_and_size,
sip_api_convert_to_void_ptr,
sip_api_export_symbol,
sip_api_import_symbol,
sip_api_find_type,
sip_api_register_py_type,
sip_api_type_from_py_type_object,
sip_api_type_scope,
sip_api_resolve_typedef,
sip_api_register_attribute_getter,
sip_api_is_api_enabled,
sip_api_bad_callable_arg,
sip_api_get_address,
/*
* The following are deprecated parts of the public API.
*/
sip_api_find_named_enum,
sip_api_find_mapped_type,
sip_api_find_class,
sip_api_map_int_to_class,
sip_api_map_string_to_class,
/*
* The following may be used by TQt support code but by no other handwritten
* code.
*/
sip_api_free_sipslot,
sip_api_same_slot,
sip_api_convert_rx,
sip_api_invoke_slot,
sip_api_save_slot,
sip_api_clear_any_slot_reference,
sip_api_visit_slot,
/*
* The following are not part of the public API.
*/
sip_api_init_module,
sip_api_parse_args,
sip_api_parse_pair,
sip_api_common_dtor,
sip_api_no_function,
sip_api_no_method,
sip_api_abstract_method,
sip_api_bad_class,
sip_api_get_cpp_ptr,
sip_api_get_complex_cpp_ptr,
sip_api_is_py_method,
sip_api_call_hook,
sip_api_start_thread,
sip_api_end_thread,
sip_api_raise_unknown_exception,
sip_api_raise_type_exception,
sip_api_add_type_instance,
sip_api_bad_operator_arg,
sip_api_pyslot_extend,
sip_api_add_delayed_dtor,
sip_api_bytes_as_char,
sip_api_bytes_as_string,
sip_api_string_as_ascii_char,
sip_api_string_as_ascii_string,
sip_api_string_as_latin1_char,
sip_api_string_as_latin1_string,
sip_api_string_as_utf8_char,
sip_api_string_as_utf8_string,
sip_api_unicode_as_wchar,
sip_api_unicode_as_wstring,
sip_api_deprecated,
sip_api_keep_reference,
sip_api_parse_kwd_args,
sip_api_add_exception
};
#define AUTO_DOCSTRING '\1' /* Marks an auto class docstring. */
/*
* These are the format flags supported by argument parsers.
*/
#define FMT_AP_DEREF 0x01 /* The pointer will be dereferenced. */
#define FMT_AP_TRANSFER 0x02 /* Implement /Transfer/. */
#define FMT_AP_TRANSFER_BACK 0x04 /* Implement /TransferBack/. */
#define FMT_AP_NO_CONVERTORS 0x08 /* Suppress any convertors. */
#define FMT_AP_TRANSFER_THIS 0x10 /* Support for /TransferThis/. */
/*
* These are the format flags supported by result parsers. Deprecated values
* have a _DEPR suffix.
*/
#define FMT_RP_DEREF 0x01 /* The pointer will be dereferenced. */
#define FMT_RP_FACTORY 0x02 /* /Factory/ or /TransferBack/. */
#define FMT_RP_MAKE_COPY 0x04 /* Return a copy of the value. */
#define FMT_RP_NO_STATE_DEPR 0x04 /* Don't return the C/C++ state. */
/*
* The different reasons for failing to parse an overload. These include
* internal (i.e. non-user) errors.
*/
typedef enum {
Ok, Unbound, TooFew, TooMany, UnknownKeyword, Duplicate, WrongType, Raised,
KeywordNotString, Exception
} sipParseFailureReason;
/*
* The description of a failure to parse an overload because of a user error.
*/
typedef struct _sipParseFailure {
sipParseFailureReason reason; /* The reason for the failure. */
const char *detail_str; /* The detail if a string. */
PyObject *detail_obj; /* The detail if a Python object. */
int arg_nr; /* The wrong positional argument. */
const char *arg_name; /* The wrong keyword argument. */
} sipParseFailure;
/*
* An entry in a linked list of name/symbol pairs.
*/
typedef struct _sipSymbol {
const char *name; /* The name. */
void *symbol; /* The symbol. */
struct _sipSymbol *next; /* The next in the list. */
} sipSymbol;
/*
* An entry in a linked list of Python objects.
*/
typedef struct _sipPyObject {
PyObject *object; /* The Python object. */
struct _sipPyObject *next; /* The next in the list. */
} sipPyObject;
/*
* An entry in the linked list of attribute getters.
*/
typedef struct _sipAttrGetter {
PyTypeObject *type; /* The Python type being handled. */
sipAttrGetterFunc getter; /* The getter. */
struct _sipAttrGetter *next; /* The next in the list. */
} sipAttrGetter;
/*****************************************************************************
* The structures to support a Python type to hold a named enum.
*****************************************************************************/
static PyObject *sipEnumType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems);
/*
* The type data structure. We inherit everything from the standard Python
* metatype and the size of the type object created is increased to accomodate
* the extra information we associate with a named enum type.
*/
static PyTypeObject sipEnumType_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"sip_tqt.enumtype", /* tp_name */
sizeof (sipEnumTypeObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved (Python v3), tp_compare (Python v2) */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
sipEnumType_alloc, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
};
sipTQtAPI *sipTQtSupport = NULL;
sipTypeDef *sipTQObjectType;
/*
* Various strings as Python objects created as and when needed.
*/
static PyObject *licenseName = NULL;
static PyObject *licenseeName = NULL;
static PyObject *typeName = NULL;
static PyObject *timestampName = NULL;
static PyObject *signatureName = NULL;
static sipObjectMap cppPyMap; /* The C/C++ to Python map. */
static sipExportedModuleDef *moduleList = NULL; /* List of registered modules. */
static unsigned traceMask = 0; /* The current trace mask. */
static sipTypeDef *currentType = NULL; /* The type being created. */
static PyObject *type_unpickler; /* The type unpickler function. */
static PyObject *enum_unpickler; /* The enum unpickler function. */
static sipSymbol *sipSymbolList = NULL; /* The list of published symbols. */
static sipAttrGetter *sipAttrGetters = NULL; /* The list of attribute getters. */
static sipPyObject *sipRegisteredPyTypes = NULL; /* Registered Python types. */
static PyInterpreterState *sipInterpreter = NULL; /* The interpreter. */
static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd);
static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots);
static void *findSlot(PyObject *self, sipPySlotType st);
static void *findSlotInType(sipPySlotDef *psd, sipPySlotType st);
static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2,
sipPySlotType st);
static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1,
PyObject *arg2, sipPySlotType st);
static PyObject *buildObject(PyObject *tup, const char *fmt, va_list va);
static int parseKwdArgs(PyObject **parseErrp, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused,
const char *fmt, va_list va_orig);
static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp,
int *selfargp, PyObject *sipArgs, PyObject *sipKwdArgs,
const char **kwdlist, PyObject **unused, const char *fmt, va_list va);
static int parsePass2(sipSimpleWrapper *self, int selfarg, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, const char *fmt,
va_list va);
static PyObject *signature_FromDocstring(const char *doc, SIP_SSIZE_T line);
static PyObject *detail_FromFailure(PyObject *failure_obj);
static int isTQObject(PyObject *obj);
static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td);
static int convertFromSequence(PyObject *seq, const sipTypeDef *td,
void **array, SIP_SSIZE_T *nr_elem);
static PyObject *convertToSequence(void *array, SIP_SSIZE_T nr_elem,
const sipTypeDef *td);
static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr,
sipSimpleWrapper **selfp);
static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm);
static int compareTypedefName(const void *key, const void *el);
static int checkPointer(void *ptr, sipSimpleWrapper *sw);
static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type,
const sipTypeDef *dst_type);
static void finalise(void);
static PyObject *getDefaultBases(void);
static PyObject *getScopeDict(sipTypeDef *td, PyObject *mod_dict,
sipExportedModuleDef *client);
static PyObject *createContainerType(sipContainerDef *cod, sipTypeDef *td,
PyObject *bases, PyObject *metatype, PyObject *mod_dict,
sipExportedModuleDef *client);
static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd,
PyObject *mod_dict);
static int createMappedType(sipExportedModuleDef *client,
sipMappedTypeDef *mtd, PyObject *mod_dict);
static sipExportedModuleDef *getModule(PyObject *mname_obj);
static PyObject *pickle_type(PyObject *obj, PyObject *);
static PyObject *unpickle_type(PyObject *, PyObject *args);
static PyObject *pickle_enum(PyObject *obj, PyObject *);
static PyObject *unpickle_enum(PyObject *, PyObject *args);
static int setReduce(PyTypeObject *type, PyMethodDef *pickler);
static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd,
PyObject *mod_dict);
static PyObject *createTypeDict(PyObject *mname);
static sipExportedModuleDef *getTypeModule(const sipEncodedTypeDef *enc,
sipExportedModuleDef *em);
static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc,
sipExportedModuleDef *em);
static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr);
static void *getPtrTypeDef(sipSimpleWrapper *self,
const sipClassTypeDef **ctd);
static int addInstances(PyObject *dict, sipInstancesDef *id);
static int addVoidPtrInstances(PyObject *dict, sipVoidPtrInstanceDef *vi);
static int addCharInstances(PyObject *dict, sipCharInstanceDef *ci);
static int addStringInstances(PyObject *dict, sipStringInstanceDef *si);
static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii);
static int addLongInstances(PyObject *dict, sipLongInstanceDef *li);
static int addUnsignedLongInstances(PyObject *dict,
sipUnsignedLongInstanceDef *uli);
static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli);
static int addUnsignedLongLongInstances(PyObject *dict,
sipUnsignedLongLongInstanceDef *ulli);
static int addDoubleInstances(PyObject *dict, sipDoubleInstanceDef *di);
static int addTypeInstances(PyObject *dict, sipTypeInstanceDef *ti);
static int addSingleTypeInstance(PyObject *dict, const char *name,
void *cppPtr, const sipTypeDef *td, int initflags);
static int addLicense(PyObject *dict, sipLicenseDef *lc);
static PyObject *cast(PyObject *self, PyObject *args);
static PyObject *callDtor(PyObject *self, PyObject *args);
static PyObject *dumpWrapper(PyObject *self, PyObject *args);
static PyObject *isDeleted(PyObject *self, PyObject *args);
static PyObject *isPyOwned(PyObject *self, PyObject *args);
static PyObject *setDeleted(PyObject *self, PyObject *args);
static PyObject *setTraceMask(PyObject *self, PyObject *args);
static PyObject *wrapInstance(PyObject *self, PyObject *args);
static PyObject *unwrapInstance(PyObject *self, PyObject *args);
static PyObject *transferBack(PyObject *self, PyObject *args);
static PyObject *transferTo(PyObject *self, PyObject *args);
static void print_object(const char *label, PyObject *obj);
static void addToParent(sipWrapper *self, sipWrapper *owner);
static void removeFromParent(sipWrapper *self);
static void release(void *addr, const sipTypeDef *td, int state);
static void callPyDtor(sipSimpleWrapper *self);
static int parseBytes_AsCharArray(PyObject *obj, const char **ap,
SIP_SSIZE_T *aszp);
static int parseBytes_AsChar(PyObject *obj, char *ap);
static int parseBytes_AsString(PyObject *obj, const char **ap);
static int parseString_AsASCIIChar(PyObject *obj, char *ap);
static PyObject *parseString_AsASCIIString(PyObject *obj, const char **ap);
static int parseString_AsLatin1Char(PyObject *obj, char *ap);
static PyObject *parseString_AsLatin1String(PyObject *obj, const char **ap);
static int parseString_AsUTF8Char(PyObject *obj, char *ap);
static PyObject *parseString_AsUTF8String(PyObject *obj, const char **ap);
static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap);
static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj,
const char **ap);
#if defined(HAVE_WCHAR_H)
static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp);
static int convertToWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp);
static int parseWChar(PyObject *obj, wchar_t *ap);
static int convertToWChar(PyObject *obj, wchar_t *ap);
static int parseWCharString(PyObject *obj, wchar_t **ap);
static int convertToWCharString(PyObject *obj, wchar_t **ap);
#else
static void raiseNoWChar();
#endif
static void *getComplexCppPtr(sipSimpleWrapper *w, const sipTypeDef *td);
static PyObject *findPyType(const char *name);
static int addPyObjectToList(sipPyObject **head, PyObject *object);
static PyObject *getDictFromObject(PyObject *obj);
static void forgetObject(sipSimpleWrapper *sw);
static int add_lazy_container_attrs(sipTypeDef *td, sipContainerDef *cod,
PyObject *dict);
static int add_lazy_attrs(sipTypeDef *td);
static int add_all_lazy_attrs(sipTypeDef *td);
static int objectify(const char *s, PyObject **objp);
static void add_failure(PyObject **parseErrp, sipParseFailure *failure);
static PyObject *bad_type_str(int arg_nr, PyObject *arg);
static sipExportedModuleDef *isModuleLoaded(sipExportedModuleDef *table,
char *name);
/*
* The Python module initialisation function.
*/
#define SIP_MODULE_ENTRY PyInit_sip_tqt
#define SIP_MODULE_TYPE PyObject *
#define SIP_MODULE_DISCARD(m) Py_DECREF(m)
#define SIP_FATAL(s) return NULL
#define SIP_MODULE_RETURN(m) return (m)
#if defined(SIP_STATIC_MODULE)
SIP_MODULE_TYPE SIP_MODULE_ENTRY(void)
#else
PyMODINIT_FUNC SIP_MODULE_ENTRY(void)
#endif
{
static PyMethodDef methods[] = {
{"cast", cast, METH_VARARGS, NULL},
{"delete", callDtor, METH_VARARGS, NULL},
{"dump", dumpWrapper, METH_VARARGS, NULL},
{"getapi", sipGetAPI, METH_VARARGS, NULL},
{"isdeleted", isDeleted, METH_VARARGS, NULL},
{"ispyowned", isPyOwned, METH_VARARGS, NULL},
{"setapi", sipSetAPI, METH_VARARGS, NULL},
{"setdeleted", setDeleted, METH_VARARGS, NULL},
{"settracemask", setTraceMask, METH_VARARGS, NULL},
{"transferback", transferBack, METH_VARARGS, NULL},
{"transferto", transferTo, METH_VARARGS, NULL},
{"wrapinstance", wrapInstance, METH_VARARGS, NULL},
{"unwrapinstance", unwrapInstance, METH_VARARGS, NULL},
{"_unpickle_type", unpickle_type, METH_VARARGS, NULL},
{"_unpickle_enum", unpickle_enum, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
"sip_tqt", /* m_name */
NULL, /* m_doc */
-1, /* m_size */
methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
int rc;
PyObject *mod, *mod_dict, *obj;
#ifdef WITH_THREAD
PyEval_InitThreads();
#endif
/* Initialise the types. */
sipWrapperType_Type.tp_base = &PyType_Type;
if (PyType_Ready(&sipWrapperType_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.wrappertype type");
if (PyType_Ready((PyTypeObject *)&sipSimpleWrapper_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.simplewrapper type");
if (sip_api_register_py_type((PyTypeObject *)&sipSimpleWrapper_Type) < 0)
SIP_FATAL("sip-tqt: Failed to register sip_tqt.simplewrapper type");
#if defined(STACKLESS)
sipWrapper_Type.super.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type;
#else
sipWrapper_Type.super.ht_type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type;
#endif
if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.wrapper type");
if (PyType_Ready(&sipMethodDescr_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.methoddescriptor type");
if (PyType_Ready(&sipVariableDescr_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.variabledescriptor type");
sipEnumType_Type.tp_base = &PyType_Type;
if (PyType_Ready(&sipEnumType_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.enumtype type");
if (PyType_Ready(&sipVoidPtr_Type) < 0)
SIP_FATAL("sip-tqt: Failed to initialise sip_tqt.voidptr type");
mod = PyModule_Create(&module_def);
if (mod == NULL)
SIP_FATAL("sip-tqt: Failed to intialise sip_tqt module");
mod_dict = PyModule_GetDict(mod);
/* Get a reference to the pickle helpers. */
type_unpickler = PyDict_GetItemString(mod_dict, "_unpickle_type");
enum_unpickler = PyDict_GetItemString(mod_dict, "_unpickle_enum");
if (type_unpickler == NULL || enum_unpickler == NULL)
{
SIP_MODULE_DISCARD(mod);
SIP_FATAL("sip-tqt: Failed to get pickle helpers");
}
/* Publish the SIP-TQt API. */
obj = PyCapsule_New((void *)&sip_api, "sip_tqt._C_API", NULL);
if (obj == NULL)
{
SIP_MODULE_DISCARD(mod);
SIP_FATAL("sip-tqt: Failed to create _C_API object");
}
rc = PyDict_SetItemString(mod_dict, "_C_API", obj);
Py_DECREF(obj);
if (rc < 0)
{
SIP_MODULE_DISCARD(mod);
SIP_FATAL("sip-tqt: Failed to add _C_API object to module dictionary");
}
/* Add the SIP-TQt version number, but don't worry about errors. */
obj = PyLong_FromLong(SIP_TQT_VERSION);
if (obj != NULL)
{
PyDict_SetItemString(mod_dict, "SIP_TQT_VERSION", obj);
Py_DECREF(obj);
}
obj = PyUnicode_FromString(SIP_TQT_VERSION_STR);
if (obj != NULL)
{
PyDict_SetItemString(mod_dict, "SIP_TQT_VERSION_STR", obj);
Py_DECREF(obj);
}
/* Add the type objects, but don't worry about errors. */
PyDict_SetItemString(mod_dict, "wrappertype",
(PyObject *)&sipWrapperType_Type);
PyDict_SetItemString(mod_dict, "simplewrapper",
(PyObject *)&sipSimpleWrapper_Type);
PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type);
PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type);
/* Initialise the module if it hasn't already been done. */
if (sipInterpreter == NULL)
{
Py_AtExit(finalise);
/* Initialise the object map. */
sipOMInit(&cppPyMap);
sipTQtSupport = NULL;
/*
* Get the current interpreter. This will be shared between all
* threads.
*/
sipInterpreter = PyThreadState_Get()->interp;
}
SIP_MODULE_RETURN(mod);
}
/*
* Display a printf() style message to stderr according to the current trace
* mask.
*/
static void sip_api_trace(unsigned mask, const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
if (mask & traceMask)
vfprintf(stderr, fmt, ap);
va_end(ap);
}
/*
* Set the trace mask.
*/
static PyObject *setTraceMask(PyObject *self, PyObject *args)
{
unsigned new_mask;
if (PyArg_ParseTuple(args, "I:settracemask", &new_mask))
{
traceMask = new_mask;
Py_INCREF(Py_None);
return Py_None;
}
return NULL;
}
/*
* Dump various bits of potentially useful information to stdout.
*/
static PyObject *dumpWrapper(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
if (PyArg_ParseTuple(args, "O!:dump", &sipSimpleWrapper_Type, &sw))
{
print_object(NULL, (PyObject *)sw);
printf(" Reference count: %" PY_FORMAT_SIZE_T "d\n", Py_REFCNT(sw));
printf(" Address of wrapped object: %p\n", sip_api_get_address(sw));
printf(" To be destroyed by: %s\n", (sipIsPyOwned(sw) ? "Python" : "C/C++"));
printf(" Derived class?: %s\n", (sipIsDerived(sw) ? "yes" : "no"));
if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type))
{
sipWrapper *w = (sipWrapper *)sw;
print_object("Parent wrapper", (PyObject *)w->parent);
print_object("Next sibling wrapper", (PyObject *)w->sibling_next);
print_object("Previous sibling wrapper",
(PyObject *)w->sibling_prev);
print_object("First child wrapper", (PyObject *)w->first_child);
}
Py_INCREF(Py_None);
return Py_None;
}
return NULL;
}
/*
* Write a reference to a wrapper to stdout.
*/
static void print_object(const char *label, PyObject *obj)
{
if (label != NULL)
printf(" %s: ", label);
if (obj != NULL)
PyObject_Print(obj, stdout, 0);
else
printf("NULL");
printf("\n");
}
/*
* Transfer the ownership of an instance to C/C++.
*/
static PyObject *transferTo(PyObject *self, PyObject *args)
{
PyObject *w, *owner;
if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner))
{
if (owner == Py_None)
owner = NULL;
else if (PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type))
{
PyErr_Format(PyExc_TypeError, "transferto() argument 2 must be sip.wrapper, not %s", Py_TYPE(owner)->tp_name);
return NULL;
}
sip_api_transfer_to(w, owner);
Py_INCREF(Py_None);
return Py_None;
}
return NULL;
}
/*
* Transfer the ownership of an instance to Python.
*/
static PyObject *transferBack(PyObject *self, PyObject *args)
{
PyObject *w;
if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w))
{
sip_api_transfer_back(w);
Py_INCREF(Py_None);
return Py_None;
}
return NULL;
}
/*
* Cast an instance to one of it's sub or super-classes by returning a new
* Python object with the superclass type wrapping the same C++ instance.
*/
static PyObject *cast(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
sipWrapperType *wt;
const sipTypeDef *td;
void *addr;
PyTypeObject *ft, *tt;
if (!PyArg_ParseTuple(args, "O!O!:cast", &sipSimpleWrapper_Type, &sw, &sipWrapperType_Type, &wt))
return NULL;
ft = Py_TYPE(sw);
tt = (PyTypeObject *)wt;
if (ft == tt || PyType_IsSubtype(tt, ft))
td = NULL;
else if (PyType_IsSubtype(ft, tt))
td = wt->type;
else
{
PyErr_SetString(PyExc_TypeError, "argument 1 of sip_tqt.cast() must be an instance of a sub or super-type of argument 2");
return NULL;
}
if ((addr = sip_api_get_cpp_ptr(sw, td)) == NULL)
return NULL;
/*
* We don't put this new object into the map so that the original object is
* always found. It would also totally confuse the map logic.
*/
return sipWrapSimpleInstance(addr, wt->type, NULL, (sw->flags | SIP_NOT_IN_MAP) & ~SIP_PY_OWNED);
}
/*
* Call an instance's dtor.
*/
static PyObject *callDtor(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
void *addr;
const sipClassTypeDef *ctd;
if (!PyArg_ParseTuple(args, "O!:delete", &sipSimpleWrapper_Type, &sw))
return NULL;
addr = getPtrTypeDef(sw, &ctd);
if (checkPointer(addr, sw) < 0)
return NULL;
if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type))
{
/*
* Transfer ownership to C++ so we don't try to release it again when
* the Python object is garbage collected.
*/
removeFromParent((sipWrapper *)sw);
sipResetPyOwned(sw);
}
release(addr, (const sipTypeDef *)ctd, sw->flags);
Py_INCREF(Py_None);
return Py_None;
}
/*
* Check if an instance still exists without raising an exception.
*/
static PyObject *isDeleted(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
PyObject *res;
if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipSimpleWrapper_Type, &sw))
return NULL;
res = (sip_api_get_address(sw) == NULL ? Py_True : Py_False);
Py_INCREF(res);
return res;
}
/*
* Check if an instance is owned by Python or C/C++.
*/
static PyObject *isPyOwned(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
PyObject *res;
if (!PyArg_ParseTuple(args, "O!:ispyowned", &sipSimpleWrapper_Type, &sw))
return NULL;
res = (sipIsPyOwned(sw) ? Py_True : Py_False);
Py_INCREF(res);
return res;
}
/*
* Mark an instance as having been deleted.
*/
static PyObject *setDeleted(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipSimpleWrapper_Type, &sw))
return NULL;
if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type))
{
/*
* Transfer ownership to C++ so we don't try to release it when the
* Python object is garbage collected.
*/
removeFromParent((sipWrapper *)sw);
sipResetPyOwned(sw);
}
sw->u.cppPtr = NULL;
Py_INCREF(Py_None);
return Py_None;
}
/*
* Unwrap an instance.
*/
static PyObject *unwrapInstance(PyObject *self, PyObject *args)
{
sipSimpleWrapper *sw;
if (PyArg_ParseTuple(args, "O!:unwrapinstance", &sipSimpleWrapper_Type, &sw))
{
void *addr;
/*
* We just get the pointer but don't try and cast it (which isn't
* needed and wouldn't work with the way casts are currently
* implemented if we are unwrapping something derived from a wrapped
* class).
*/
if ((addr = sip_api_get_cpp_ptr(sw, NULL)) == NULL)
return NULL;
return PyLong_FromVoidPtr(addr);
}
return NULL;
}
/*
* Wrap an instance.
*/
static PyObject *wrapInstance(PyObject *self, PyObject *args)
{
unsigned long addr;
sipWrapperType *wt;
if (PyArg_ParseTuple(args, "kO!:wrapinstance", &addr, &sipWrapperType_Type, &wt))
return sip_api_convert_from_type((void *)addr, wt->type, NULL);
return NULL;
}
/*
* Register a client module. A negative value is returned and an exception
* raised if there was an error.
*/
static int sip_api_export_module(sipExportedModuleDef *client,
unsigned api_major, unsigned api_minor, void *unused)
{
sipExportedModuleDef *em;
const char *full_name = sipNameOfModule(client);
/* Check that we can support it. */
if (api_major != SIP_TQT_API_MAJOR_NR || api_minor > SIP_TQT_API_MINOR_NR)
{
#if SIP_TQT_API_MINOR_NR > 0
PyErr_Format(PyExc_RuntimeError,
"the sip_tqt module implements API v%d.0 to v%d.%d but the %s module requires API v%d.%d",
SIP_TQT_API_MAJOR_NR, SIP_TQT_API_MAJOR_NR, SIP_TQT_API_MINOR_NR,
full_name, api_major, api_minor);
#else
PyErr_Format(PyExc_RuntimeError,
"the sip_tqt module implements API v%d.0 but the %s module requires API v%d.%d",
SIP_TQT_API_MAJOR_NR, full_name, api_major, api_minor);
#endif
return -1;
}
/* Import any required modules. */
if (client->em_imports != NULL)
{
sipImportedModuleDef *im = client->em_imports;
while (im->im_name != NULL)
{
PyObject *mod;
em = isModuleLoaded(moduleList, im->im_name);
if (em == NULL)
{
if ((mod = PyImport_ImportModule(im->im_name)) == NULL)
return -1;
em = isModuleLoaded(moduleList, im->im_name);
}
if (em == NULL)
{
PyErr_Format(PyExc_RuntimeError,
"the %s module failed to register with the sip_tqt module",
im->im_name);
return -1;
}
/* Check the versions are compatible. */
if (im->im_version >= 0 || em->em_version >= 0)
if (im->im_version != em->em_version)
{
PyErr_Format(PyExc_RuntimeError,
"the %s module is version %d but the %s module requires version %d",
sipNameOfModule(em), em->em_version, full_name,
im->im_version);
return -1;
}
/* Save the imported module. */
im->im_module = em;
++im;
}
}
for (em = moduleList; em != NULL; em = em->em_next)
{
/* SIP-TQt clients must have unique names. */
if (strcmp(sipNameOfModule(em), full_name) == 0)
{
PyErr_Format(PyExc_RuntimeError,
"the sip_tqt module has already registered a module called %s",
full_name);
return -1;
}
/* Only one module can claim to wrap TQObject. */
if (em->em_tqt_api != NULL && client->em_tqt_api != NULL)
{
PyErr_Format(PyExc_RuntimeError,
"the %s and %s modules both wrap the TQObject class",
full_name, sipNameOfModule(em));
return -1;
}
}
/* Convert the module name to an object. */
client->em_nameobj = PyUnicode_FromString(full_name);
if (client->em_nameobj == NULL)
return -1;
/* Add it to the list of client modules. */
client->em_next = moduleList;
moduleList = client;
return 0;
}
/*
* Find out if a client module has been loaded already.
*/
static sipExportedModuleDef *isModuleLoaded(sipExportedModuleDef *table,
char *name)
{
sipExportedModuleDef *em = table;
for (em = moduleList; em != NULL; em = em->em_next)
if (strcmp(sipNameOfModule(em), name) == 0)
return em;
return NULL;
}
/*
* Initialise the contents of a client module. By this time anything that
* this depends on should have been initialised. A negative value is returned
* and an exception raised if there was an error.
*/
static int sip_api_init_module(sipExportedModuleDef *client,
PyObject *mod_dict)
{
sipExportedModuleDef *em;
sipEnumMemberDef *emd;
int i;
/* Handle any API. */
if (sipInitAPI(client, mod_dict) < 0)
return -1;
/* Create the module's types. */
for (i = 0; i < client->em_nrtypes; ++i)
{
sipTypeDef *td = client->em_types[i];
/* Skip external classes. */
if (td == NULL)
continue;
/* Skip if already initialised. */
if (td->td_module != NULL)
continue;
/* If it is a stub then just set the module so we can get its name. */
if (sipTypeIsStub(td))
{
td->td_module = client;
continue;
}
if (sipTypeIsEnum(td))
{
sipEnumTypeDef *etd = (sipEnumTypeDef *)td;
if (td->td_version < 0 || sipIsRangeEnabled(client, td->td_version))
if (createEnumType(client, etd, mod_dict) < 0)
return -1;
/*
* Register the enum pickler for scoped enums (unscoped, ie. those
* not nested, don't need special treatment).
*/
if (etd->etd_scope >= 0)
{
static PyMethodDef md = {
"_pickle_enum", pickle_enum, METH_NOARGS, NULL
};
if (setReduce(sipTypeAsPyTypeObject(td), &md) < 0)
return -1;
}
}
else if (sipTypeIsMapped(td))
{
sipMappedTypeDef *mtd = (sipMappedTypeDef *)td;
/* If there is a name then we need a namespace. */
if (mtd->mtd_container.cod_name >= 0)
{
if (createMappedType(client, mtd, mod_dict) < 0)
return -1;
}
else
{
td->td_module = client;
}
}
else
{
sipClassTypeDef *ctd = (sipClassTypeDef *)td;
/* See if this is a namespace extender. */
if (ctd->ctd_container.cod_name < 0)
{
sipTypeDef *real_nspace;
sipClassTypeDef **last;
ctd->ctd_base.td_module = client;
real_nspace = getGeneratedType(&ctd->ctd_container.cod_scope,
client);
/* Append this type to the real one. */
last = &((sipClassTypeDef *)real_nspace)->ctd_nsextender;
while (*last != NULL)
last = &(*last)->ctd_nsextender;
*last = ctd;
/*
* Save the real namespace type so that it is the correct scope
* for any enums or classes defined in this module.
*/
client->em_types[i] = real_nspace;
}
else if (createClassType(client, ctd, mod_dict) < 0)
return -1;
}
}
/* Set any TQt support API. */
if (client->em_tqt_api != NULL)
{
sipTQtSupport = client->em_tqt_api;
sipTQObjectType = *sipTQtSupport->tqt_tqobject;
}
/* Append any initialiser extenders to the relevant classes. */
if (client->em_initextend != NULL)
{
sipInitExtenderDef *ie = client->em_initextend;
while (ie->ie_extender != NULL)
{
sipTypeDef *td = getGeneratedType(&ie->ie_class, client);
int enabled;
if (ie->ie_api_range < 0)
enabled = TRUE;
else
enabled = sipIsRangeEnabled(td->td_module, ie->ie_api_range);
if (enabled)
{
sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td);
ie->ie_next = wt->iextend;
wt->iextend = ie;
}
++ie;
}
}
/* Set the base class object for any sub-class convertors. */
if (client->em_convertors != NULL)
{
sipSubClassConvertorDef *scc = client->em_convertors;
while (scc->scc_convertor != NULL)
{
scc->scc_basetype = getGeneratedType(&scc->scc_base, client);
++scc;
}
}
/* Create the module's enum members. */
for (emd = client->em_enummembers, i = 0; i < client->em_nrenummembers; ++i, ++emd)
{
PyObject *mo;
if ((mo = sip_api_convert_from_enum(emd->em_val, client->em_types[emd->em_enum])) == NULL)
return -1;
if (PyDict_SetItemString(mod_dict, emd->em_name, mo) < 0)
return -1;
Py_DECREF(mo);
}
/*
* Add any class static instances. We need to do this once all types are
* fully formed because of potential interdependencies.
*/
for (i = 0; i < client->em_nrtypes; ++i)
{
sipTypeDef *td = client->em_types[i];
if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td))
if (addInstances((sipTypeAsPyTypeObject(td))->tp_dict, &((sipClassTypeDef *)td)->ctd_container.cod_instances) < 0)
return -1;
}
/* Add any global static instances. */
if (addInstances(mod_dict, &client->em_instances) < 0)
return -1;
/* Add any license. */
if (client->em_license != NULL && addLicense(mod_dict, client->em_license) < 0)
return -1;
/* See if the new module satisfies any outstanding external types. */
for (em = moduleList; em != NULL; em = em->em_next)
{
sipExternalTypeDef *etd;
if (em == client || em->em_external == NULL)
continue;
for (etd = em->em_external; etd->et_nr >= 0; ++etd)
{
if (etd->et_name == NULL)
continue;
for (i = 0; i < client->em_nrtypes; ++i)
{
sipTypeDef *td = client->em_types[i];
if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td))
{
const char *pyname = sipPyNameOfContainer(
&((sipClassTypeDef *)td)->ctd_container, td);
if (strcmp(etd->et_name, pyname) == 0)
{
em->em_types[etd->et_nr] = td;
etd->et_name = NULL;
break;
}
}
}
}
}
return 0;
}
/*
* Called by the interpreter to do any final clearing up, just in case the
* interpreter will re-start.
*/
static void finalise(void)
{
sipExportedModuleDef *em;
/* Mark the Python API as unavailable. */
sipInterpreter = NULL;
/* Handle any delayed dtors. */
for (em = moduleList; em != NULL; em = em->em_next)
if (em->em_ddlist != NULL)
{
em->em_delayeddtors(em->em_ddlist);
/* Free the list. */
do
{
sipDelayedDtor *dd = em->em_ddlist;
em->em_ddlist = dd->dd_next;
sip_api_free(dd);
}
while (em->em_ddlist != NULL);
}
licenseName = NULL;
licenseeName = NULL;
typeName = NULL;
timestampName = NULL;
signatureName = NULL;
/* Release all memory we've allocated directly. */
sipOMFinalise(&cppPyMap);
/* Re-initialise those globals that (might) need it. */
moduleList = NULL;
}
/*
* Register the given Python type.
*/
static int sip_api_register_py_type(PyTypeObject *type)
{
return addPyObjectToList(&sipRegisteredPyTypes, (PyObject *)type);
}
/*
* Find the registered type with the given name. Raise an exception if it
* couldn't be found.
*/
static PyObject *findPyType(const char *name)
{
sipPyObject *po;
for (po = sipRegisteredPyTypes; po != NULL; po = po->next)
{
PyObject *type = po->object;
if (strcmp(((PyTypeObject *)type)->tp_name, name) == 0)
return type;
}
PyErr_Format(PyExc_RuntimeError, "%s is not a registered type", name);
return NULL;
}
/*
* Add a wrapped C/C++ pointer to the list of delayed dtors.
*/
static void sip_api_add_delayed_dtor(sipSimpleWrapper *sw)
{
void *ptr;
const sipClassTypeDef *ctd;
sipExportedModuleDef *em;
if ((ptr = getPtrTypeDef(sw, &ctd)) == NULL)
return;
/* Find the defining module. */
for (em = moduleList; em != NULL; em = em->em_next)
{
int i;
for (i = 0; i < em->em_nrtypes; ++i)
if (em->em_types[i] == (const sipTypeDef *)ctd)
{
sipDelayedDtor *dd;
if ((dd = sip_api_malloc(sizeof (sipDelayedDtor))) == NULL)
return;
/* Add to the list. */
dd->dd_ptr = ptr;
dd->dd_name = sipPyNameOfContainer(&ctd->ctd_container,
(sipTypeDef *)ctd);
dd->dd_isderived = sipIsDerived(sw);
dd->dd_next = em->em_ddlist;
em->em_ddlist = dd;
return;
}
}
}
/*
* A wrapper around the Python memory allocater that will raise an exception if
* if the allocation fails.
*/
void *sip_api_malloc(size_t nbytes)
{
void *mem;
if ((mem = PyMem_RawMalloc(nbytes)) == NULL)
PyErr_NoMemory();
return mem;
}
/*
* A wrapper around the Python memory de-allocater.
*/
void sip_api_free(void *mem)
{
PyMem_RawFree(mem);
}
/*
* Extend a Python slot by looking in other modules to see if there is an
* extender function that can handle the arguments.
*/
static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod,
sipPySlotType st, const sipTypeDef *td, PyObject *arg0,
PyObject *arg1)
{
sipExportedModuleDef *em;
/* Go through each module. */
for (em = moduleList; em != NULL; em = em->em_next)
{
sipPySlotExtenderDef *ex;
/* Skip the module that couldn't handle the arguments. */
if (em == mod)
continue;
/* Skip if the module doesn't have any extenders. */
if (em->em_slotextend == NULL)
continue;
/* Go through each extender. */
for (ex = em->em_slotextend; ex->pse_func != NULL; ++ex)
{
PyObject *res;
/* Skip if not the right slot type. */
if (ex->pse_type != st)
continue;
/* Check against the type if one was given. */
if (td != NULL && td != getGeneratedType(&ex->pse_class, NULL))
continue;
PyErr_Clear();
res = ((binaryfunc)ex->pse_func)(arg0, arg1);
if (res != Py_NotImplemented)
return res;
}
}
/* The arguments couldn't handled anywhere. */
PyErr_Clear();
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
/*
* 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,"sipTQtBuildResult(): invalid format string \"%s\"",fmt);
else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL)
res = buildObject(res,fmt,va);
va_end(va);
if (res == NULL && isErr != NULL)
*isErr = TRUE;
return res;
}
/*
* Get the values off the stack and put them into an object.
*/
static PyObject *buildObject(PyObject *obj, const char *fmt, va_list va)
{
char ch, termch;
int i;
/*
* The format string has already been checked that it is properly formed if
* it is enclosed in parenthesis.
*/
if (*fmt == '(')
{
termch = ')';
++fmt;
}
else
termch = '\0';
i = 0;
while ((ch = *fmt++) != termch)
{
PyObject *el;
switch (ch)
{
case 'g':
{
char *s;
SIP_SSIZE_T l;
s = va_arg(va, char *);
l = va_arg(va, SIP_SSIZE_T);
if (s != NULL)
{
el = PyBytes_FromStringAndSize(s, l);
}
else
{
Py_INCREF(Py_None);
el = Py_None;
}
}
break;
case 'G':
#if defined(HAVE_WCHAR_H)
{
wchar_t *s;
SIP_SSIZE_T l;
s = va_arg(va, wchar_t *);
l = va_arg(va, SIP_SSIZE_T);
if (s != NULL)
el = PyUnicode_FromWideChar(s, l);
else
{
Py_INCREF(Py_None);
el = Py_None;
}
}
#else
raiseNoWChar();
el = NULL;
#endif
break;
case 'b':
el = PyBool_FromLong(va_arg(va,int));
break;
case 'c':
{
char c = va_arg(va, int);
el = PyBytes_FromStringAndSize(&c, 1);
}
break;
case 'a':
{
char c = va_arg(va, int);
el = PyUnicode_FromStringAndSize(&c, 1);
}
break;
case 'w':
#if defined(HAVE_WCHAR_H)
{
wchar_t c = va_arg(va, int);
el = PyUnicode_FromWideChar(&c, 1);
}
#else
raiseNoWChar();
el = NULL;
#endif
break;
case 'E':
{
/* This is deprecated. */
int ev = va_arg(va, int);
PyTypeObject *et = va_arg(va, PyTypeObject *);
el = sip_api_convert_from_enum(ev,
((const sipEnumTypeObject *)et)->type);
}
break;
case 'F':
{
int ev = va_arg(va, int);
const sipTypeDef *td = va_arg(va, const sipTypeDef *);
el = sip_api_convert_from_enum(ev, td);
}
break;
case 'd':
case 'f':
el = PyFloat_FromDouble(va_arg(va,double));
break;
case 'e':
case 'h':
case 'i':
el = PyLong_FromLong(va_arg(va, int));
break;
case 'l':
el = PyLong_FromLong(va_arg(va, long));
break;
case 'm':
el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
break;
case 'n':
#if defined(HAVE_LONG_LONG)
el = PyLong_FromLongLong(va_arg(va, PY_LONG_LONG));
#else
el = PyLong_FromLong(va_arg(va, long));
#endif
break;
case 'o':
#if defined(HAVE_LONG_LONG)
el = PyLong_FromUnsignedLongLong(va_arg(va, unsigned PY_LONG_LONG));
#else
el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
#endif
break;
case 's':
{
char *s = va_arg(va, char *);
if (s != NULL)
{
el = PyBytes_FromString(s);
}
else
{
Py_INCREF(Py_None);
el = Py_None;
}
}
break;
case 'A':
{
char *s = va_arg(va, char *);
if (s != NULL)
el = PyUnicode_FromString(s);
else
{
Py_INCREF(Py_None);
el = Py_None;
}
}
break;
case 'x':
#if defined(HAVE_WCHAR_H)
{
wchar_t *s = va_arg(va, wchar_t *);
if (s != NULL)
el = PyUnicode_FromWideChar(s, (SIP_SSIZE_T)wcslen(s));
else
{
Py_INCREF(Py_None);
el = Py_None;
}
}
#else
raiseNoWChar();
el = NULL;
#endif
break;
case 't':
case 'u':
el = PyLong_FromUnsignedLong(va_arg(va, unsigned));
break;
case 'B':
{
/* This is deprecated. */
void *p = va_arg(va,void *);
sipWrapperType *wt = va_arg(va, sipWrapperType *);
PyObject *xfer = va_arg(va, PyObject *);
el = sip_api_convert_from_new_type(p, wt->type, xfer);
}
break;
case 'N':
{
void *p = va_arg(va, void *);
const sipTypeDef *td = va_arg(va, const sipTypeDef *);
PyObject *xfer = va_arg(va, PyObject *);
el = sip_api_convert_from_new_type(p, td, xfer);
}
break;
case 'C':
{
/* This is deprecated. */
void *p = va_arg(va,void *);
sipWrapperType *wt = va_arg(va, sipWrapperType *);
PyObject *xfer = va_arg(va, PyObject *);
el = sip_api_convert_from_type(p, wt->type, xfer);
}
break;
case 'D':
{
void *p = va_arg(va, void *);
const sipTypeDef *td = va_arg(va, const sipTypeDef *);
PyObject *xfer = va_arg(va, PyObject *);
el = sip_api_convert_from_type(p, td, xfer);
}
break;
case 'r':
{
void *p = va_arg(va, void *);
SIP_SSIZE_T l = va_arg(va, SIP_SSIZE_T);
const sipTypeDef *td = va_arg(va, const sipTypeDef *);
el = convertToSequence(p, l, td);
}
break;
case 'R':
el = va_arg(va,PyObject *);
break;
case 'S':
el = va_arg(va,PyObject *);
Py_INCREF(el);
break;
case 'V':
el = sip_api_convert_from_void_ptr(va_arg(va, void *));
break;
default:
PyErr_Format(PyExc_SystemError,"buildObject(): invalid format character '%c'",ch);
el = NULL;
}
if (el == NULL)
{
Py_XDECREF(obj);
return NULL;
}
if (obj == NULL)
return el;
PyTuple_SET_ITEM(obj,i,el);
++i;
}
return obj;
}
/*
* Parse a result object based on a format string.
*/
static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res,
const char *fmt, ...)
{
int tupsz, rc = 0;
sipSimpleWrapper *self = NULL;
va_list va;
va_start(va,fmt);
/* Get self if it is provided. */
if (*fmt == 'S')
{
self = va_arg(va, sipSimpleWrapper *);
++fmt;
}
/* Basic validation of the format string. */
if (*fmt == '(')
{
char ch;
const char *cp = ++fmt;
tupsz = 0;
while ((ch = *cp++) != ')')
{
if (ch == '\0')
{
PyErr_Format(PyExc_SystemError, "sipTQtParseResult(): invalid format string \"%s\"", fmt - 1);
rc = -1;
break;
}
/*
* Some format characters have a sub-format so skip the character
* and count the sub-format character next time round.
*/
if (strchr("HDC", ch) == NULL)
++tupsz;
}
if (rc == 0)
if (!PyTuple_Check(res) || PyTuple_GET_SIZE(res) != tupsz)
{
sip_api_bad_catcher_result(method);
rc = -1;
}
}
else
tupsz = -1;
if (rc == 0)
{
char ch;
int i = 0;
while ((ch = *fmt++) != '\0' && ch != ')' && rc == 0)
{
PyObject *arg;
int invalid = FALSE;
if (tupsz > 0)
{
arg = PyTuple_GET_ITEM(res,i);
++i;
}
else
arg = res;
switch (ch)
{
case 'g':
{
const char **p = va_arg(va, const char **);
SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *);
if (parseBytes_AsCharArray(arg, p, szp) < 0)
invalid = TRUE;
}
break;
case 'G':
#if defined(HAVE_WCHAR_H)
{
wchar_t **p = va_arg(va, wchar_t **);
SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *);
if (parseWCharArray(arg, p, szp) < 0)
invalid = TRUE;
}
#else
raiseNoWChar();
invalid = TRUE;
#endif
break;
case 'b':
{
int v = PyLong_AsLong(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
sipSetBool(va_arg(va, void *), v);
}
break;
case 'c':
{
char *p = va_arg(va, char *);
if (parseBytes_AsChar(arg, p) < 0)
invalid = TRUE;
}
break;
case 'a':
{
char *p = va_arg(va, char *);
int enc;
switch (*fmt++)
{
case 'A':
enc = parseString_AsASCIIChar(arg, p);
break;
case 'L':
enc = parseString_AsLatin1Char(arg, p);
break;
case '8':
enc = parseString_AsUTF8Char(arg, p);
break;
default:
enc = -1;
}
if (enc < 0)
invalid = TRUE;
}
break;
case 'w':
#if defined(HAVE_WCHAR_H)
{
wchar_t *p = va_arg(va, wchar_t *);
if (parseWChar(arg, p) < 0)
invalid = TRUE;
}
#else
raiseNoWChar();
invalid = TRUE;
#endif
break;
case 'd':
{
double v = PyFloat_AsDouble(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va,double *) = v;
}
break;
case 'E':
{
/* This is deprecated. */
PyTypeObject *et = va_arg(va, PyTypeObject *);
int *p = va_arg(va, int *);
if (sip_api_can_convert_to_enum(arg, ((sipEnumTypeObject *)et)->type))
*p = PyLong_AsLong(arg);
else
invalid = TRUE;
}
break;
case 'F':
{
sipTypeDef *td = va_arg(va, sipTypeDef *);
int *p = va_arg(va, int *);
if (sip_api_can_convert_to_enum(arg, td))
*p = PyLong_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 = PyLong_AsLong(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va, short *) = v;
}
break;
case 't':
{
unsigned short v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va,unsigned short *) = v;
}
break;
case 'e':
case 'i':
{
int v = PyLong_AsLong(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va, int *) = v;
}
break;
case 'u':
{
unsigned v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va,unsigned *) = v;
}
break;
case 'l':
{
long v = PyLong_AsLong(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va,long *) = v;
}
break;
case 'm':
{
unsigned long v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va, unsigned long *) = v;
}
break;
case 'n':
{
#if defined(HAVE_LONG_LONG)
PY_LONG_LONG v = PyLong_AsLongLong(arg);
#else
long v = PyLong_AsLong(arg);
#endif
if (PyErr_Occurred())
invalid = TRUE;
else
#if defined(HAVE_LONG_LONG)
*va_arg(va, PY_LONG_LONG *) = v;
#else
*va_arg(va, long *) = v;
#endif
}
break;
case 'o':
{
#if defined(HAVE_LONG_LONG)
unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg);
#else
unsigned long v = PyLong_AsUnsignedLong(arg);
#endif
if (PyErr_Occurred())
invalid = TRUE;
else
#if defined(HAVE_LONG_LONG)
*va_arg(va, unsigned PY_LONG_LONG *) = v;
#else
*va_arg(va, unsigned long *) = v;
#endif
}
break;
case 's':
{
/* This is deprecated. */
const char **p = va_arg(va, const char **);
if (parseBytes_AsString(arg, p) < 0)
invalid = TRUE;
}
break;
case 'A':
{
int key = va_arg(va, int);
const char **p = va_arg(va, const char **);
PyObject *keep;
switch (*fmt++)
{
case 'A':
keep = parseString_AsASCIIString(arg, p);
break;
case 'L':
keep = parseString_AsLatin1String(arg, p);
break;
case '8':
keep = parseString_AsUTF8String(arg, p);
break;
default:
keep = NULL;
}
if (keep == NULL)
invalid = TRUE;
else
sip_api_keep_reference((PyObject *)self, key, keep);
}
break;
case 'B':
{
int key = va_arg(va, int);
const char **p = va_arg(va, const char **);
if (parseBytes_AsString(arg, p) < 0)
invalid = TRUE;
else
{
Py_INCREF(arg);
sip_api_keep_reference((PyObject *)self, key, arg);
}
}
break;
case 'x':
#if defined(HAVE_WCHAR_H)
{
wchar_t **p = va_arg(va, wchar_t **);
if (parseWCharString(arg, p) < 0)
invalid = TRUE;
}
#else
raiseNoWChar();
invalid = TRUE;
#endif
break;
case 'C':
{
/* This is deprecated. */
if (*fmt == '\0')
invalid = TRUE;
else
{
int flags = *fmt++ - '0';
int iserr = FALSE;
sipWrapperType *type;
void **cpp;
int *state;
type = va_arg(va, sipWrapperType *);
if (flags & FMT_RP_NO_STATE_DEPR)
state = NULL;
else
state = va_arg(va, int *);
cpp = va_arg(va, void **);
*cpp = sip_api_force_convert_to_type(arg, type->type, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr);
if (iserr)
invalid = TRUE;
}
}
break;
case 'D':
{
/* This is deprecated. */
if (*fmt == '\0')
invalid = TRUE;
else
{
int flags = *fmt++ - '0';
int iserr = FALSE;
const sipTypeDef *td;
void **cpp;
int *state;
td = va_arg(va, const sipTypeDef *);
if (flags & FMT_RP_NO_STATE_DEPR)
state = NULL;
else
state = va_arg(va, int *);
cpp = va_arg(va, void **);
*cpp = sip_api_force_convert_to_type(arg, td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr);
if (iserr)
invalid = TRUE;
}
}
break;
case 'H':
{
if (*fmt == '\0')
invalid = TRUE;
else
{
int flags = *fmt++ - '0';
int iserr = FALSE, state;
const sipTypeDef *td;
void *cpp, *val;
td = va_arg(va, const sipTypeDef *);
cpp = va_arg(va, void **);
val = sip_api_force_convert_to_type(arg, td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), &state, &iserr);
if (iserr)
{
invalid = TRUE;
}
else if (flags & FMT_RP_MAKE_COPY)
{
sipAssignFunc assign_helper;
if (sipTypeIsMapped(td))
assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign;
else
assign_helper = ((const sipClassTypeDef *)td)->ctd_assign;
assert(assign_helper != NULL);
assign_helper(cpp, 0, val);
sip_api_release_type(val, td, state);
}
else
{
*(void **)cpp = val;
}
}
}
break;
case 'N':
{
PyTypeObject *type = va_arg(va,PyTypeObject *);
PyObject **p = va_arg(va,PyObject **);
if (arg == Py_None || PyObject_TypeCheck(arg,type))
{
Py_INCREF(arg);
*p = arg;
}
else
invalid = TRUE;
}
break;
case 'O':
Py_INCREF(arg);
*va_arg(va,PyObject **) = arg;
break;
case 'T':
{
PyTypeObject *type = va_arg(va,PyTypeObject *);
PyObject **p = va_arg(va,PyObject **);
if (PyObject_TypeCheck(arg,type))
{
Py_INCREF(arg);
*p = arg;
}
else
invalid = TRUE;
}
break;
case 'V':
{
void *v = sip_api_convert_to_void_ptr(arg);
if (PyErr_Occurred())
invalid = TRUE;
else
*va_arg(va,void **) = v;
}
break;
case 'Z':
if (arg != Py_None)
invalid = TRUE;
break;
default:
PyErr_Format(PyExc_SystemError,"sipTQtParseResult(): 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)
{
return PyLong_AsUnsignedLong(o);
}
/*
* Parse the arguments to a C/C++ function without any side effects.
*/
static int sip_api_parse_args(PyObject **parseErrp, PyObject *sipArgs,
const char *fmt, ...)
{
int ok;
va_list va;
va_start(va, fmt);
ok = parseKwdArgs(parseErrp, sipArgs, NULL, NULL, NULL, fmt, va);
va_end(va);
return ok;
}
/*
* Parse the positional and/or keyword arguments to a C/C++ function without
* any side effects.
*/
static int sip_api_parse_kwd_args(PyObject **parseErrp, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused,
const char *fmt, ...)
{
int ok;
va_list va;
/* Initialise the return of any unused keyword arguments. */
if (unused != NULL)
*unused = NULL;
va_start(va, fmt);
ok = parseKwdArgs(parseErrp, sipArgs, sipKwdArgs, kwdlist, unused, fmt,
va);
va_end(va);
/* Release any unused arguments if the parse failed. */
if (!ok && unused != NULL)
{
Py_XDECREF(*unused);
}
return ok;
}
/*
* Parse the arguments to a C/C++ function without any side effects.
*/
static int parseKwdArgs(PyObject **parseErrp, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused,
const char *fmt, va_list va_orig)
{
int no_tmp_tuple, ok, selfarg;
sipSimpleWrapper *self;
PyObject *single_arg;
va_list va;
/* Previous second pass errors stop subsequent parses. */
if (*parseErrp != NULL && !PyList_Check(*parseErrp))
return FALSE;
/*
* See if we are parsing a single argument. In current versions we are
* told explicitly by the first character of the format string. In earlier
* versions we guessed (sometimes wrongly).
*/
if (*fmt == '1')
{
++fmt;
no_tmp_tuple = FALSE;
}
else
no_tmp_tuple = PyTuple_Check(sipArgs);
if (no_tmp_tuple)
{
Py_INCREF(sipArgs);
}
else if ((single_arg = PyTuple_New(1)) != NULL)
{
Py_INCREF(sipArgs);
PyTuple_SET_ITEM(single_arg, 0, sipArgs);
sipArgs = single_arg;
}
else
{
/* Stop all parsing and indicate an exception has been raised. */
Py_XDECREF(*parseErrp);
*parseErrp = Py_None;
Py_INCREF(Py_None);
return FALSE;
}
/*
* The first pass checks all the types and does conversions that are cheap
* and have no side effects.
*/
va_copy(va, va_orig);
ok = parsePass1(parseErrp, &self, &selfarg, sipArgs, sipKwdArgs, kwdlist,
unused, fmt, va);
va_end(va);
if (ok)
{
/*
* The second pass does any remaining conversions now that we know we
* have the right signature.
*/
va_copy(va, va_orig);
ok = parsePass2(self, selfarg, sipArgs, sipKwdArgs, kwdlist, fmt, va);
va_end(va);
/* Remove any previous failed parses. */
Py_XDECREF(*parseErrp);
if (ok)
{
*parseErrp = NULL;
}
else
{
/* Indicate that an exception has been raised. */
*parseErrp = Py_None;
Py_INCREF(Py_None);
}
}
Py_DECREF(sipArgs);
return ok;
}
/*
* Return a string as a Python object that describes an argument with an
* unexpected type.
*/
static PyObject *bad_type_str(int arg_nr, PyObject *arg)
{
return PyUnicode_FromFormat("argument %d has unexpected type '%s'", arg_nr,
Py_TYPE(arg)->tp_name);
}
/*
* Adds a failure about an argument with an incorrect type to the current list
* of exceptions.
*/
static sipErrorState sip_api_bad_callable_arg(int arg_nr, PyObject *arg)
{
PyObject *detail = bad_type_str(arg_nr + 1, arg);
if (detail == NULL)
return sipErrorFail;
PyErr_SetObject(PyExc_TypeError, detail);
Py_DECREF(detail);
return sipErrorContinue;
}
/*
* Adds the current exception to the current list of exceptions (if it is a
* user exception) or replace the current list of exceptions.
*/
static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp)
{
assert(*parseErrp == NULL);
if (es == sipErrorContinue)
{
sipParseFailure failure;
PyObject *e_type, *e_traceback;
/* Get the value of the exception. */
PyErr_Fetch(&e_type, &failure.detail_obj, &e_traceback);
Py_XDECREF(e_type);
Py_XDECREF(e_traceback);
failure.reason = Exception;
add_failure(parseErrp, &failure);
if (failure.reason == Raised)
{
Py_XDECREF(failure.detail_obj);
es = sipErrorFail;
}
}
if (es == sipErrorFail)
{
Py_XDECREF(*parseErrp);
*parseErrp = Py_None;
Py_INCREF(Py_None);
}
}
/*
* The dtor for parse failure wrapped in a Python object.
*/
static void failure_dtor(PyObject *capsule)
{
sipParseFailure *failure = (sipParseFailure *)PyCapsule_GetPointer(capsule, NULL);
Py_XDECREF(failure->detail_obj);
sip_api_free(failure);
}
/*
* Add a parse failure to the current list of exceptions.
*/
static void add_failure(PyObject **parseErrp, sipParseFailure *failure)
{
sipParseFailure *failure_copy;
PyObject *failure_obj;
/* Create the list if necessary. */
if (*parseErrp == NULL && (*parseErrp = PyList_New(0)) == NULL)
{
failure->reason = Raised;
return;
}
/*
* Make a copy of the failure, convert it to a Python object and add it to
* the list. We do it this way to make it as lightweight as possible.
*/
if ((failure_copy = sip_api_malloc(sizeof (sipParseFailure))) == NULL)
{
failure->reason = Raised;
return;
}
*failure_copy = *failure;
failure_obj = PyCapsule_New(failure_copy, NULL, failure_dtor);
if (failure_obj == NULL)
{
sip_api_free(failure_copy);
failure->reason = Raised;
return;
}
/* Ownership of any detail object is now with the wrapped failure. */
failure->detail_obj = NULL;
if (PyList_Append(*parseErrp, failure_obj) < 0)
{
Py_DECREF(failure_obj);
failure->reason = Raised;
return;
}
Py_DECREF(failure_obj);
}
/*
* Parse a pair of arguments to a C/C++ function without any side effects.
*/
static int sip_api_parse_pair(PyObject **parseErrp, PyObject *sipArg0,
PyObject *sipArg1, const char *fmt, ...)
{
int ok, selfarg;
sipSimpleWrapper *self;
PyObject *args;
va_list va;
/* Previous second pass errors stop subsequent parses. */
if (*parseErrp != NULL && !PyList_Check(*parseErrp))
return FALSE;
if ((args = PyTuple_New(2)) == NULL)
{
/* Stop all parsing and indicate an exception has been raised. */
Py_XDECREF(*parseErrp);
*parseErrp = Py_None;
Py_INCREF(Py_None);
return FALSE;
}
Py_INCREF(sipArg0);
PyTuple_SET_ITEM(args, 0, sipArg0);
Py_INCREF(sipArg1);
PyTuple_SET_ITEM(args, 1, sipArg1);
/*
* The first pass checks all the types and does conversions that are cheap
* and have no side effects.
*/
va_start(va, fmt);
ok = parsePass1(parseErrp, &self, &selfarg, args, NULL, NULL, NULL, fmt,
va);
va_end(va);
if (ok)
{
/*
* The second pass does any remaining conversions now that we know we
* have the right signature.
*/
va_start(va, fmt);
ok = parsePass2(self, selfarg, args, NULL, NULL, fmt, va);
va_end(va);
/* Remove any previous failed parses. */
Py_XDECREF(*parseErrp);
if (ok)
{
*parseErrp = NULL;
}
else
{
/* Indicate that an exception has been raised. */
*parseErrp = Py_None;
Py_INCREF(Py_None);
}
}
Py_DECREF(args);
return ok;
}
/*
* First pass of the argument parse, converting those that can be done so
* without any side effects. Return TRUE if the arguments matched.
*/
static int parsePass1(PyObject **parseErrp, sipSimpleWrapper **selfp,
int *selfargp, PyObject *sipArgs, PyObject *sipKwdArgs,
const char **kwdlist, PyObject **unused, const char *fmt, va_list va)
{
int compulsory, argnr, nr_args;
SIP_SSIZE_T nr_pos_args, nr_kwd_args, nr_kwd_args_used;
sipParseFailure failure;
failure.reason = Ok;
failure.detail_obj = NULL;
compulsory = TRUE;
argnr = 0;
nr_args = 0;
nr_pos_args = PyTuple_GET_SIZE(sipArgs);
nr_kwd_args = nr_kwd_args_used = 0;
if (sipKwdArgs != NULL)
{
assert(PyDict_Check(sipKwdArgs));
nr_kwd_args = PyDict_Size(sipKwdArgs);
}
/*
* Handle those format characters that deal with the "self" argument. They
* will always be the first one.
*/
*selfp = NULL;
*selfargp = FALSE;
switch (*fmt++)
{
case 'B':
case 'p':
{
PyObject *self;
sipTypeDef *td;
self = *va_arg(va, PyObject **);
td = va_arg(va, sipTypeDef *);
va_arg(va, void **);
if (self == NULL)
{
if (!getSelfFromArgs(td, sipArgs, argnr, selfp))
{
failure.reason = Unbound;
failure.detail_str = sipPyNameOfContainer(
&((sipClassTypeDef *)td)->ctd_container, td);
break;
}
*selfargp = TRUE;
++argnr;
}
else
*selfp = (sipSimpleWrapper *)self;
break;
}
case 'C':
*selfp = (sipSimpleWrapper *)va_arg(va,PyObject *);
break;
default:
--fmt;
}
/* Now handle the remaining arguments. */
while (failure.reason == Ok)
{
char ch;
PyObject *arg;
PyErr_Clear();
/* See if the following arguments are optional. */
if ((ch = *fmt++) == '|')
{
compulsory = FALSE;
ch = *fmt++;
}
/* See if we don't expect anything else. */
if (ch == '\0')
{
if (argnr < nr_pos_args)
{
/* There are still positional arguments. */
failure.reason = TooMany;
}
else if (nr_kwd_args_used != nr_kwd_args)
{
/*
* Take a shortcut if no keyword arguments were used and we are
* interested in them.
*/
if (nr_kwd_args_used == 0 && unused != NULL)
{
Py_INCREF(sipKwdArgs);
*unused = sipKwdArgs;
}
else
{
PyObject *key, *value, *unused_dict = NULL;
SIP_SSIZE_T pos = 0;
/*
* Go through the keyword arguments to find any that were
* duplicates of positional arguments. For the remaining
* ones remember the unused ones if we are interested.
*/
while (PyDict_Next(sipKwdArgs, &pos, &key, &value))
{
int a;
if (!PyUnicode_Check(key))
{
failure.reason = KeywordNotString;
failure.detail_obj = key;
Py_INCREF(key);
break;
}
if (kwdlist != NULL)
{
/* Get the argument's index if it is one. */
for (a = 0; a < nr_args; ++a)
{
const char *name = kwdlist[a];
if (name == NULL)
continue;
if (PyUnicode_CompareWithASCIIString(key, name) == 0)
break;
}
}
else
{
a = nr_args;
}
if (a == nr_args)
{
/*
* The name doesn't correspond to a keyword
* argument.
*/
if (unused == NULL)
{
/*
* It may correspond to a keyword argument of a
* different overload.
*/
failure.reason = UnknownKeyword;
failure.detail_obj = key;
Py_INCREF(key);
break;
}
/*
* Add it to the dictionary of unused arguments
* creating it if necessary. Note that if the
* unused arguments are actually used by a later
* overload then the parse will incorrectly
* succeed. This should be picked up (perhaps with
* a misleading exception) so long as the code that
* handles the unused arguments checks that it can
* handle them all.
*/
if (unused_dict == NULL && (*unused = unused_dict = PyDict_New()) == NULL)
{
failure.reason = Raised;
break;
}
if (PyDict_SetItem(unused_dict, key, value) < 0)
{
failure.reason = Raised;
break;
}
}
else if (a < nr_pos_args)
{
/*
* The argument has been given positionally and as
* a keyword.
*/
failure.reason = Duplicate;
failure.detail_obj = key;
Py_INCREF(key);
break;
}
}
}
}
break;
}
/* Get the next argument. */
arg = NULL;
failure.arg_nr = -1;
failure.arg_name = NULL;
if (argnr < nr_pos_args)
{
arg = PyTuple_GET_ITEM(sipArgs, argnr);
failure.arg_nr = argnr + 1;
}
else if (sipKwdArgs != NULL && kwdlist != NULL)
{
const char *name = kwdlist[argnr];
if (name != NULL)
{
arg = PyDict_GetItemString(sipKwdArgs, name);
if (arg != NULL)
++nr_kwd_args_used;
failure.arg_name = name;
}
}
++argnr;
++nr_args;
if (arg == NULL && compulsory)
{
if (ch == 'W')
{
/*
* A variable number of arguments was allowed but none were
* given.
*/
break;
}
/* An argument was required. */
failure.reason = TooFew;
/*
* Check if there were any unused keyword arguments so that we give
* a (possibly) more accurate diagnostic in the case that a keyword
* argument has been mis-spelled.
*/
if (unused == NULL && sipKwdArgs != NULL && nr_kwd_args_used != nr_kwd_args)
{
PyObject *key, *value;
SIP_SSIZE_T pos = 0;
while (PyDict_Next(sipKwdArgs, &pos, &key, &value))
{
int a;
if (!PyUnicode_Check(key))
{
failure.reason = KeywordNotString;
failure.detail_obj = key;
Py_INCREF(key);
break;
}
if (kwdlist != NULL)
{
/* Get the argument's index if it is one. */
for (a = 0; a < nr_args; ++a)
{
const char *name = kwdlist[a];
if (name == NULL)
continue;
if (PyUnicode_CompareWithASCIIString(key, name) == 0)
break;
}
}
else
{
a = nr_args;
}
if (a == nr_args)
{
failure.reason = UnknownKeyword;
failure.detail_obj = key;
Py_INCREF(key);
break;
}
}
}
break;
}
/*
* Handle the format character even if we don't have an argument so
* that we skip the right number of arguments.
*/
switch (ch)
{
case 'W':
/* Ellipsis. */
break;
case '@':
{
/* Implement /GetWrapper/. */
PyObject **p = va_arg(va, PyObject **);
if (arg != NULL)
*p = arg;
/* Process the same argument next time round. */
--argnr;
--nr_args;
break;
}
case 's':
{
/* String from a Python bytes or None. */
const char **p = va_arg(va, const char **);
if (arg != NULL && parseBytes_AsString(arg, p) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'A':
{
/* String from a Python string or None. */
PyObject **keep = va_arg(va, PyObject **);
const char **p = va_arg(va, const char **);
char sub_fmt = *fmt++;
if (arg != NULL)
{
PyObject *s;
switch (sub_fmt)
{
case 'A':
s = parseString_AsASCIIString(arg, p);
break;
case 'L':
s = parseString_AsLatin1String(arg, p);
break;
case '8':
s = parseString_AsUTF8String(arg, p);
break;
}
if (s == NULL)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*keep = s;
}
}
break;
}
case 'x':
#if defined(HAVE_WCHAR_H)
{
/* Wide string or None. */
wchar_t **p = va_arg(va, wchar_t **);
if (arg != NULL && parseWCharString(arg, p) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
#else
raiseNoWChar();
failure.reason = Raised;
break;
#endif
case 'U':
{
/* Slot name or callable, return the name or callable. */
char **sname = va_arg(va, char **);
PyObject **scall = va_arg(va, PyObject **);
if (arg != NULL)
{
*sname = NULL;
*scall = NULL;
if (PyBytes_Check(arg))
{
char *s = PyBytes_AS_STRING(arg);
if (*s == '1' || *s == '2' || *s == '9')
{
*sname = s;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
else if (PyCallable_Check(arg))
{
*scall = arg;
}
else if (arg != Py_None)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'S':
{
/* Slot name, return the name. */
char **p = va_arg(va, char **);
if (arg != NULL)
{
if (PyBytes_Check(arg))
{
char *s = PyBytes_AS_STRING(arg);
if (*s == '1' || *s == '2' || *s == '9')
{
*p = s;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'G':
{
/* Signal name, return the name. */
char **p = va_arg(va, char **);
if (arg != NULL)
{
if (PyBytes_Check(arg))
{
char *s = PyBytes_AS_STRING(arg);
if (*s == '2' || *s == '9')
{
*p = s;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'r':
{
/* Sequence of class or mapped type instances. */
const sipTypeDef *td;
td = va_arg(va, const sipTypeDef *);
va_arg(va, void **);
va_arg(va, SIP_SSIZE_T *);
if (arg != NULL && !canConvertFromSequence(arg, td))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'J':
{
/* Class or mapped type instance. */
char sub_fmt = *fmt++;
const sipTypeDef *td;
int flags = sub_fmt - '0';
int iflgs = 0;
td = va_arg(va, const sipTypeDef *);
va_arg(va, void **);
if (flags & FMT_AP_DEREF)
iflgs |= SIP_NOT_NONE;
if (flags & FMT_AP_TRANSFER_THIS)
va_arg(va, PyObject **);
if (flags & FMT_AP_NO_CONVERTORS)
iflgs |= SIP_NO_CONVERTORS;
else
va_arg(va, int *);
if (arg != NULL && !sip_api_can_convert_to_type(arg, td, iflgs))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'N':
{
/* Python object of given type or None. */
PyTypeObject *type = va_arg(va,PyTypeObject *);
PyObject **p = va_arg(va,PyObject **);
if (arg != NULL)
{
if (arg == Py_None || PyObject_TypeCheck(arg,type))
{
*p = arg;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'P':
{
/* Python object of any type with a sub-format. */
va_arg(va, PyObject **);
/* Skip the sub-format. */
++fmt;
break;
}
case 'T':
{
/* Python object of given type. */
PyTypeObject *type = va_arg(va, PyTypeObject *);
PyObject **p = va_arg(va, PyObject **);
if (arg != NULL)
{
if (PyObject_TypeCheck(arg,type))
{
*p = arg;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'R':
{
/* Sub-class of TQObject. */
PyObject **p = va_arg(va, PyObject **);
if (arg != NULL)
{
if (isTQObject(arg))
{
*p = arg;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'F':
{
/* Python callable object. */
PyObject **p = va_arg(va, PyObject **);
if (arg != NULL)
{
if (PyCallable_Check(arg))
{
*p = arg;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'H':
{
/* Python callable object or None. */
PyObject **p = va_arg(va, PyObject **);
if (arg != NULL)
{
if (arg == Py_None || PyCallable_Check(arg))
{
*p = arg;
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'q':
{
/* TQt receiver to connect. */
va_arg(va, char *);
va_arg(va, void **);
va_arg(va, const char **);
if (arg != NULL && !isTQObject(arg))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'Q':
{
/* TQt receiver to disconnect. */
va_arg(va, char *);
va_arg(va, void **);
va_arg(va, const char **);
if (arg != NULL && !isTQObject(arg))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'g':
case 'y':
{
/* Python slot to connect. */
va_arg(va, char *);
va_arg(va, void **);
va_arg(va, const char **);
if (arg != NULL && (sipTQtSupport == NULL || !PyCallable_Check(arg)))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'Y':
{
/* Python slot to disconnect. */
va_arg(va, char *);
va_arg(va, void **);
va_arg(va, const char **);
if (arg != NULL && (sipTQtSupport == NULL || !PyCallable_Check(arg)))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'k':
{
/* Char array or None. */
const char **p = va_arg(va, const char **);
SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *);
if (arg != NULL && parseBytes_AsCharArray(arg, p, szp) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'K':
#if defined(HAVE_WCHAR_H)
{
/* Wide char array or None. */
wchar_t **p = va_arg(va, wchar_t **);
SIP_SSIZE_T *szp = va_arg(va, SIP_SSIZE_T *);
if (arg != NULL && parseWCharArray(arg, p, szp) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
#else
raiseNoWChar();
failure.reason = Raised;
break
#endif
case 'c':
{
/* Character from a Python bytes. */
char *p = va_arg(va, char *);
if (arg != NULL && parseBytes_AsChar(arg, p) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'a':
{
/* Character from a Python string. */
char *p = va_arg(va, char *);
char sub_fmt = *fmt++;
if (arg != NULL)
{
int enc;
switch (sub_fmt)
{
case 'A':
enc = parseString_AsASCIIChar(arg, p);
break;
case 'L':
enc = parseString_AsLatin1Char(arg, p);
break;
case '8':
enc = parseString_AsUTF8Char(arg, p);
break;
}
if (enc < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
}
case 'w':
#if defined(HAVE_WCHAR_H)
{
/* Wide character. */
wchar_t *p = va_arg(va, wchar_t *);
if (arg != NULL && parseWChar(arg, p) < 0)
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
#else
raiseNoWChar();
failure.reason = Raised;
break
#endif
case 'b':
{
/* Bool. */
void *p = va_arg(va, void *);
if (arg != NULL)
{
int v = PyLong_AsLong(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
sipSetBool(p, v);
}
}
break;
}
case 'E':
{
/* Named enum or integer. */
sipTypeDef *td = va_arg(va, sipTypeDef *);
va_arg(va, int *);
if (arg != NULL && !sip_api_can_convert_to_enum(arg, td))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
break;
case 'e':
case 'i':
{
/* Integer or anonymous enum. */
int *p = va_arg(va, int *);
if (arg != NULL)
{
int v = PyLong_AsLong(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'u':
{
/* Unsigned integer. */
unsigned *p = va_arg(va, unsigned *);
if (arg != NULL)
{
unsigned v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'h':
{
/* Short integer. */
short *p = va_arg(va, short *);
if (arg != NULL)
{
short v = PyLong_AsLong(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 't':
{
/* Unsigned short integer. */
unsigned short *p = va_arg(va, unsigned short *);
if (arg != NULL)
{
unsigned short v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'l':
{
/* Long integer. */
long *p = va_arg(va, long *);
if (arg != NULL)
{
long v = PyLong_AsLong(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'm':
{
/* Unsigned long integer. */
unsigned long *p = va_arg(va, unsigned long *);
if (arg != NULL)
{
unsigned long v = sip_api_long_as_unsigned_long(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'n':
{
/* Long long integer. */
#if defined(HAVE_LONG_LONG)
PY_LONG_LONG *p = va_arg(va, PY_LONG_LONG *);
#else
long *p = va_arg(va, long *);
#endif
if (arg != NULL)
{
#if defined(HAVE_LONG_LONG)
PY_LONG_LONG v = PyLong_AsLongLong(arg);
#else
long v = PyLong_AsLong(arg);
#endif
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'o':
{
/* Unsigned long long integer. */
#if defined(HAVE_LONG_LONG)
unsigned PY_LONG_LONG *p = va_arg(va, unsigned PY_LONG_LONG *);
#else
unsigned long *p = va_arg(va, unsigned long *);
#endif
if (arg != NULL)
{
#if defined(HAVE_LONG_LONG)
unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg);
#else
unsigned long v = PyLong_AsUnsignedLong(arg);
#endif
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'f':
{
/* Float. */
float *p = va_arg(va, float *);
if (arg != NULL)
{
double v = PyFloat_AsDouble(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = (float)v;
}
}
break;
}
case 'X':
{
/* Constrained types. */
char sub_fmt = *fmt++;
if (sub_fmt == 'E')
{
/* Named enum. */
sipTypeDef *td = va_arg(va, sipTypeDef *);
va_arg(va, int *);
if (arg != NULL && !PyObject_TypeCheck(arg, sipTypeAsPyTypeObject(td)))
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
}
else
{
void *p = va_arg(va, void *);
if (arg != NULL)
{
switch (sub_fmt)
{
case 'b':
{
/* Boolean. */
if (PyBool_Check(arg))
{
sipSetBool(p, (arg == Py_True));
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'd':
{
/* Double float. */
if (PyFloat_Check(arg))
{
*(double *)p = PyFloat_AS_DOUBLE(arg);
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'f':
{
/* Float. */
if (PyFloat_Check(arg))
{
*(float *)p = (float)PyFloat_AS_DOUBLE(arg);
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
case 'i':
{
/* Integer. */
if (PyLong_Check(arg))
{
*(int *)p = PyLong_AS_LONG(arg);
}
else
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
break;
}
}
}
}
break;
}
case 'd':
{
/* Double float. */
double *p = va_arg(va,double *);
if (arg != NULL)
{
double v = PyFloat_AsDouble(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
case 'v':
{
/* Void pointer. */
void **p = va_arg(va, void **);
if (arg != NULL)
{
void *v = sip_api_convert_to_void_ptr(arg);
if (PyErr_Occurred())
{
failure.reason = WrongType;
failure.detail_obj = arg;
Py_INCREF(arg);
}
else
{
*p = v;
}
}
break;
}
}
if (failure.reason == Ok && ch == 'W')
{
/* An ellipsis matches everything and ends the parse. */
break;
}
}
/* Handle parse failures appropriately. */
if (failure.reason == Ok)
return TRUE;
if (failure.reason != Raised)
{
add_failure(parseErrp, &failure);
}
if (failure.reason == Raised)
{
Py_XDECREF(failure.detail_obj);
/*
* The error isn't a user error so don't bother with the detail of the
* overload.
*/
Py_XDECREF(*parseErrp);
*parseErrp = Py_None;
Py_INCREF(Py_None);
}
return FALSE;
}
/*
* Second pass of the argument parse, converting the remaining ones that might
* have side effects. Return TRUE if there was no error.
*/
static int parsePass2(sipSimpleWrapper *self, int selfarg, PyObject *sipArgs,
PyObject *sipKwdArgs, const char **kwdlist, const char *fmt,
va_list va)
{
int a, ok;
SIP_SSIZE_T nr_pos_args;
/* Handle the converions of "self" first. */
switch (*fmt++)
{
case 'B':
{
/*
* The address of a C++ instance when calling one of its public
* methods.
*/
const sipTypeDef *td;
void **p;
*va_arg(va, PyObject **) = (PyObject *)self;
td = va_arg(va, const sipTypeDef *);
p = va_arg(va, void **);
if ((*p = sip_api_get_cpp_ptr(self, td)) == NULL)
return FALSE;
break;
}
case 'p':
{
/*
* The address of a C++ instance when calling one of its protected
* methods.
*/
const sipTypeDef *td;
void **p;
*va_arg(va, PyObject **) = (PyObject *)self;
td = va_arg(va, const sipTypeDef *);
p = va_arg(va, void **);
if ((*p = getComplexCppPtr(self, td)) == NULL)
return FALSE;
break;
}
case 'C':
va_arg(va, PyObject *);
break;
default:
--fmt;
}
ok = TRUE;
nr_pos_args = PyTuple_GET_SIZE(sipArgs);
for (a = (selfarg ? 1 : 0); *fmt != '\0' && *fmt != 'W' && ok; ++a)
{
char ch;
PyObject *arg;
/* Skip the optional character. */
if ((ch = *fmt++) == '|')
ch = *fmt++;
/* Get the next argument. */
arg = NULL;
if (a < nr_pos_args)
{
arg = PyTuple_GET_ITEM(sipArgs, a);
}
else if (sipKwdArgs != NULL)
{
const char *name = kwdlist[a];
if (name != NULL)
arg = PyDict_GetItemString(sipKwdArgs, name);
}
/*
* Do the outstanding conversions. For most types it has already been
* done, so we are just skipping the parameters.
*/
switch (ch)
{
case '@':
/* Implement /GetWrapper/. */
va_arg(va, PyObject **);
/* Process the same argument next time round. */
--a;
break;
case 'q':
{
/* TQt receiver to connect. */
char *sig = va_arg(va, char *);
void **rx = va_arg(va, void **);
const char **slot = va_arg(va, const char **);
if (arg != NULL)
{
*rx = sip_api_convert_rx((sipWrapper *)self, sig, arg,
*slot, slot, 0);
if (*rx == NULL)
return FALSE;
}
break;
}
case 'Q':
{
/* TQt receiver to disconnect. */
char *sig = va_arg(va, char *);
void **rx = va_arg(va, void **);
const char **slot = va_arg(va, const char **);
if (arg != NULL)
*rx = sipGetRx(self, sig, arg, *slot, slot);
break;
}
case 'g':
{
/* Python single shot slot to connect. */
char *sig = va_arg(va, char *);
void **rx = va_arg(va, void **);
const char **slot = va_arg(va, const char **);
if (arg != NULL)
{
*rx = sip_api_convert_rx((sipWrapper *)self, sig, arg,
NULL, slot, SIP_SINGLE_SHOT);
if (*rx == NULL)
return FALSE;
}
break;
}
case 'y':
{
/* Python slot to connect. */
char *sig = va_arg(va, char *);
void **rx = va_arg(va, void **);
const char **slot = va_arg(va, const char **);
if (arg != NULL)
{
*rx = sip_api_convert_rx((sipWrapper *)self, sig, arg,
NULL, slot, 0);
if (*rx == NULL)
return FALSE;
}
break;
}
case 'Y':
{
/* Python slot to disconnect. */
char *sig = va_arg(va, char *);
void **rx = va_arg(va, void **);
const char **slot = va_arg(va, const char **);
if (arg != NULL)
*rx = sipGetRx(self, sig, arg, NULL, slot);
break;
}
case 'r':
{
/* Sequence of class or mapped type instances. */
const sipTypeDef *td;
void **array;
SIP_SSIZE_T *nr_elem;
td = va_arg(va, const sipTypeDef *);
array = va_arg(va, void **);
nr_elem = va_arg(va, SIP_SSIZE_T *);
if (arg != NULL && !convertFromSequence(arg, td, array, nr_elem))
return FALSE;
break;
}
case 'J':
{
/* Class or mapped type instance. */
int flags = *fmt++ - '0';
const sipTypeDef *td;
void **p;
int iflgs = 0;
int *state;
PyObject *xfer, **owner;
td = va_arg(va, const sipTypeDef *);
p = va_arg(va, void **);
if (flags & FMT_AP_TRANSFER)
xfer = (self ? (PyObject *)self : arg);
else if (flags & FMT_AP_TRANSFER_BACK)
xfer = Py_None;
else
xfer = NULL;
if (flags & FMT_AP_DEREF)
iflgs |= SIP_NOT_NONE;
if (flags & FMT_AP_TRANSFER_THIS)
owner = va_arg(va, PyObject **);
if (flags & FMT_AP_NO_CONVERTORS)
{
iflgs |= SIP_NO_CONVERTORS;
state = NULL;
}
else
{
state = va_arg(va, int *);
}
if (arg != NULL)
{
int iserr = FALSE;
*p = sip_api_convert_to_type(arg, td, xfer, iflgs, state,
&iserr);
if (iserr)
return FALSE;
if (flags & FMT_AP_TRANSFER_THIS && *p != NULL)
*owner = arg;
}
break;
}
case 'P':
{
/* Python object of any type with a sub-format. */
PyObject **p = va_arg(va, PyObject **);
int flags = *fmt++ - '0';
if (arg != NULL)
{
if (flags & FMT_AP_TRANSFER)
{
Py_XINCREF(arg);
}
else if (flags & FMT_AP_TRANSFER_BACK)
{
Py_XDECREF(arg);
}
*p = arg;
}
break;
}
case 'X':
{
/* Constrained types. */
va_arg(va, void *);
if (*fmt++ == 'E')
{
/* Named enum. */
int *p = va_arg(va, int *);
if (arg != NULL)
*p = PyLong_AsLong(arg);
}
break;
}
case 'E':
{
/* Named enum. */
int *p;
va_arg(va, sipTypeDef *);
p = va_arg(va, int *);
if (arg != NULL)
*p = PyLong_AsLong(arg);
break;
}
/*
* These need special handling because they have a sub-format
* character.
*/
case 'A':
va_arg(va, void *);
/* Drop through. */
case 'a':
va_arg(va, void *);
fmt++;
break;
/*
* Every other argument is a pointer and only differ in how many there
* are.
*/
case 'N':
case 'T':
case 'k':
case 'K':
va_arg(va, void *);
/* Drop through. */
default:
va_arg(va, void *);
}
}
/* Handle any ellipsis argument. */
if (*fmt == 'W')
{
PyObject *al;
int da = 0;
/* Create a tuple for any remaining arguments. */
if ((al = PyTuple_New(nr_pos_args - a)) == NULL)
return FALSE;
while (a < nr_pos_args)
{
PyObject *arg = PyTuple_GET_ITEM(sipArgs, a);
/* Add the remaining argument to the tuple. */
Py_INCREF(arg);
PyTuple_SET_ITEM(al, da, arg);
++a;
++da;
}
/* Return the tuple. */
*va_arg(va, PyObject **) = al;
}
return TRUE;
}
/*
* Return TRUE if an object is a TQObject.
*/
static int isTQObject(PyObject *obj)
{
return (sipTQtSupport != NULL && PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(sipTQObjectType)));
}
/*
* See if a Python object is a sequence of a particular type.
*/
static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td)
{
SIP_SSIZE_T i, size = PySequence_Size(seq);
if (size < 0)
return FALSE;
for (i = 0; i < size; ++i)
{
int ok;
PyObject *val_obj;
if ((val_obj = PySequence_GetItem(seq, i)) == NULL)
return FALSE;
ok = sip_api_can_convert_to_type(val_obj, td,
SIP_NO_CONVERTORS|SIP_NOT_NONE);
Py_DECREF(val_obj);
if (!ok)
return FALSE;
}
return TRUE;
}
/*
* Convert a Python sequence to an array that has already "passed"
* canConvertFromSequence(). Return TRUE if the conversion was successful.
*/
static int convertFromSequence(PyObject *seq, const sipTypeDef *td,
void **array, SIP_SSIZE_T *nr_elem)
{
int iserr = 0;
SIP_SSIZE_T i, size = PySequence_Size(seq);
sipArrayFunc array_helper;
sipAssignFunc assign_helper;
void *array_mem;
/* Get the type's helpers. */
if (sipTypeIsMapped(td))
{
array_helper = ((const sipMappedTypeDef *)td)->mtd_array;
assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign;
}
else
{
array_helper = ((const sipClassTypeDef *)td)->ctd_array;
assign_helper = ((const sipClassTypeDef *)td)->ctd_assign;
}
assert(array_helper != NULL);
assert(assign_helper != NULL);
/*
* Create the memory for the array of values. Note that this will leak if
* there is an error.
*/
array_mem = array_helper(size);
for (i = 0; i < size; ++i)
{
PyObject *val_obj;
void *val;
if ((val_obj = PySequence_GetItem(seq, i)) == NULL)
return FALSE;
val = sip_api_convert_to_type(val_obj, td, NULL,
SIP_NO_CONVERTORS|SIP_NOT_NONE, NULL, &iserr);
Py_DECREF(val_obj);
if (iserr)
return FALSE;
assign_helper(array_mem, i, val);
}
*array = array_mem;
*nr_elem = size;
return TRUE;
}
/*
* Convert an array of a type to a Python sequence.
*/
static PyObject *convertToSequence(void *array, SIP_SSIZE_T nr_elem,
const sipTypeDef *td)
{
SIP_SSIZE_T i;
PyObject *seq;
sipCopyFunc copy_helper;
/* Get the type's copy helper. */
if (sipTypeIsMapped(td))
copy_helper = ((const sipMappedTypeDef *)td)->mtd_copy;
else
copy_helper = ((const sipClassTypeDef *)td)->ctd_copy;
assert(copy_helper != NULL);
if ((seq = PyTuple_New(nr_elem)) == NULL)
return NULL;
for (i = 0; i < nr_elem; ++i)
{
void *el = copy_helper(array, i);
PyObject *el_obj = sip_api_convert_from_new_type(el, td, NULL);
if (el_obj == NULL)
{
release(el, td, 0);
Py_DECREF(seq);
}
PyTuple_SET_ITEM(seq, i, el_obj);
}
return seq;
}
/*
* Carry out actions common to all dtors.
*/
void sip_api_common_dtor(sipSimpleWrapper *sipSelf)
{
if (sipSelf != NULL && sipInterpreter != NULL)
{
PyObject *xtype, *xvalue, *xtb;
SIP_BLOCK_THREADS
/* We may be tidying up after an exception so preserve it. */
PyErr_Fetch(&xtype, &xvalue, &xtb);
callPyDtor(sipSelf);
PyErr_Restore(xtype, xvalue, xtb);
if (!sipNotInMap(sipSelf))
sipOMRemoveObject(&cppPyMap, sipSelf);
/* This no longer points to anything useful. */
sipSelf->u.cppPtr = NULL;
/*
* If C/C++ has a reference (and therefore no parent) then remove it.
* Otherwise remove the object from any parent.
*/
if (sipCppHasRef(sipSelf))
{
sipResetCppHasRef(sipSelf);
Py_DECREF(sipSelf);
}
else if (PyObject_TypeCheck((PyObject *)sipSelf, (PyTypeObject *)&sipWrapper_Type))
removeFromParent((sipWrapper *)sipSelf);
SIP_UNBLOCK_THREADS
}
}
/*
* Call self.__dtor__() if it is implemented.
*/
static void callPyDtor(sipSimpleWrapper *self)
{
sip_gilstate_t sipGILState;
char pymc = 0;
PyObject *meth;
meth = sip_api_is_py_method(&sipGILState, &pymc, self, NULL, "__dtor__");
if (meth != NULL)
{
PyObject *res = sip_api_call_method(0, meth, "", NULL);
Py_DECREF(meth);
/* Discard any result. */
Py_XDECREF(res);
/* Handle any error the best we can. */
if (PyErr_Occurred())
PyErr_Print();
SIP_RELEASE_GIL(sipGILState);
}
}
/*
* Add a wrapper to it's parent owner. The wrapper must not currently have a
* parent and, therefore, no siblings.
*/
static void addToParent(sipWrapper *self, sipWrapper *owner)
{
if (owner->first_child != NULL)
{
self->sibling_next = owner->first_child;
owner->first_child->sibling_prev = self;
}
owner->first_child = self;
self->parent = owner;
/*
* The owner holds a real reference so that the cyclic garbage collector
* works properly.
*/
Py_INCREF((sipSimpleWrapper *)self);
}
/*
* Remove a wrapper from it's parent if it has one.
*/
static void removeFromParent(sipWrapper *self)
{
if (self->parent != NULL)
{
if (self->parent->first_child == self)
self->parent->first_child = self->sibling_next;
if (self->sibling_next != NULL)
self->sibling_next->sibling_prev = self->sibling_prev;
if (self->sibling_prev != NULL)
self->sibling_prev->sibling_next = self->sibling_next;
self->parent = NULL;
self->sibling_next = NULL;
self->sibling_prev = NULL;
/*
* We must do this last, after all the pointers are correct, because
* this is used by the clear slot.
*/
Py_DECREF((sipSimpleWrapper *)self);
}
}
/*
* Convert a sequence index. Return the index or a negative value if there was
* an error.
*/
static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx,
SIP_SSIZE_T len)
{
/* Negative indices start from the other end. */
if (idx < 0)
idx = len + idx;
if (idx < 0 || idx >= len)
{
PyErr_Format(PyExc_IndexError, "sequence index out of range");
return -1;
}
return idx;
}
/*
* Return a tuple of the base classes of a type that has no explicit
* super-type.
*/
static PyObject *getDefaultBases(void)
{
static PyObject *default_bases = NULL;
/* Only do this once. */
if (default_bases == NULL)
{
default_bases = PyTuple_Pack(1, (PyObject *)&sipWrapper_Type);
if (default_bases == NULL)
return NULL;
}
Py_INCREF(default_bases);
return default_bases;
}
/*
* Return the dictionary of a type.
*/
static PyObject *getScopeDict(sipTypeDef *td, PyObject *mod_dict,
sipExportedModuleDef *client)
{
/*
* Initialise the scoping type if necessary. It will always be in the
* same module if it needs doing.
*/
if (sipTypeIsMapped(td))
{
if (createMappedType(client, (sipMappedTypeDef *)td, mod_dict) < 0)
return NULL;
/* Check that the mapped type can act as a container. */
assert(sipTypeAsPyTypeObject(td) != NULL);
}
else
{
if (createClassType(client, (sipClassTypeDef *)td, mod_dict) < 0)
return NULL;
}
return (sipTypeAsPyTypeObject(td))->tp_dict;
}
/*
* Create a container type and return a borrowed reference to it.
*/
static PyObject *createContainerType(sipContainerDef *cod, sipTypeDef *td,
PyObject *bases, PyObject *metatype, PyObject *mod_dict,
sipExportedModuleDef *client)
{
PyObject *py_type, *scope_dict, *typedict, *name, *args;
/* Get the dictionary to place the type in. */
if (cod->cod_scope.sc_flag)
{
scope_dict = mod_dict;
}
else if ((scope_dict = getScopeDict(getGeneratedType(&cod->cod_scope, client), mod_dict, client)) == NULL)
goto reterr;
/* Create the type dictionary. */
if ((typedict = createTypeDict(client->em_nameobj)) == NULL)
goto reterr;
/* Create an object corresponding to the type name. */
name = PyUnicode_FromString(sipPyNameOfContainer(cod, td));
if (name == NULL)
goto reldict;
/* Create the type by calling the metatype. */
args = PyTuple_Pack(3, name, bases, typedict);
if (args == NULL)
goto relname;
/* Pass the type via the back door. */
currentType = td;
if ((py_type = PyObject_Call(metatype, args, NULL)) == NULL)
goto relargs;
/* Add the type to the "parent" dictionary. */
if (PyDict_SetItem(scope_dict, name, py_type) < 0)
goto reltype;
Py_DECREF(args);
Py_DECREF(name);
Py_DECREF(typedict);
return py_type;
/* Unwind on error. */
reltype:
Py_DECREF(py_type);
relargs:
Py_DECREF(args);
relname:
Py_DECREF(name);
reldict:
Py_DECREF(typedict);
reterr:
currentType = NULL;
return NULL;
}
/*
* Create a single class type object.
*/
static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd,
PyObject *mod_dict)
{
PyObject *bases, *metatype, *py_type;
sipEncodedTypeDef *sup;
/* Handle the trivial case where we have already been initialised. */
if (ctd->ctd_base.td_module != NULL)
return 0;
/* Set this up now to gain access to the string pool. */
ctd->ctd_base.td_module = client;
/* Create the tuple of super-types. */
if ((sup = ctd->ctd_supers) == NULL)
{
if (ctd->ctd_supertype < 0)
{
bases = getDefaultBases();
}
else
{
PyObject *supertype;
const char *supertype_name = sipNameFromPool(client,
ctd->ctd_supertype);
if ((supertype = findPyType(supertype_name)) == NULL)
goto reterr;
bases = PyTuple_Pack(1, supertype);
}
if (bases == NULL)
goto reterr;
}
else
{
int i, nrsupers = 0;
do
++nrsupers;
while (!sup++->sc_flag);
if ((bases = PyTuple_New(nrsupers)) == NULL)
goto reterr;
for (sup = ctd->ctd_supers, i = 0; i < nrsupers; ++i, ++sup)
{
PyObject *st;
sipTypeDef *sup_td = getGeneratedType(sup, client);
/*
* Initialise the super-class if necessary. It will always be in
* the same module if it needs doing.
*/
if (createClassType(client, (sipClassTypeDef *)sup_td, mod_dict) < 0)
goto relbases;
st = (PyObject *)sipTypeAsPyTypeObject(sup_td);
Py_INCREF(st);
PyTuple_SET_ITEM(bases, i, st);
}
}
/*
* Use the explicit meta-type if there is one, otherwise use the meta-type
* of the first super-type.
*/
if (ctd->ctd_metatype >= 0)
{
const char *metatype_name = sipNameFromPool(client, ctd->ctd_metatype);
if ((metatype = findPyType(metatype_name)) == NULL)
goto relbases;
}
else
metatype = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(bases, 0));
if ((py_type = createContainerType(&ctd->ctd_container, (sipTypeDef *)ctd, bases, metatype, mod_dict, client)) == NULL)
goto relbases;
/* Handle the pickle function. */
if (ctd->ctd_pickle != NULL)
{
static PyMethodDef md = {
"_pickle_type", pickle_type, METH_NOARGS, NULL
};
if (setReduce((PyTypeObject *)py_type, &md) < 0)
goto reltype;
}
/* We can now release our references. */
Py_DECREF(bases);
return 0;
/* Unwind after an error. */
reltype:
Py_DECREF(py_type);
relbases:
Py_DECREF(bases);
reterr:
ctd->ctd_base.td_module = NULL;
return -1;
}
/*
* Create a single mapped type object.
*/
static int createMappedType(sipExportedModuleDef *client,
sipMappedTypeDef *mtd, PyObject *mod_dict)
{
PyObject *bases;
/* Handle the trivial case where we have already been initialised. */
if (mtd->mtd_base.td_module != NULL)
return 0;
/* Set this up now to gain access to the string pool. */
mtd->mtd_base.td_module = client;
/* Create the tuple of super-types. */
if ((bases = getDefaultBases()) == NULL)
goto reterr;
if (createContainerType(&mtd->mtd_container, (sipTypeDef *)mtd, bases, (PyObject *)&sipWrapperType_Type, mod_dict, client) == NULL)
goto relbases;
/* We can now release our references. */
Py_DECREF(bases);
return 0;
/* Unwind after an error. */
relbases:
Py_DECREF(bases);
reterr:
mtd->mtd_base.td_module = NULL;
return -1;
}
/*
* Return the module definition for a named module.
*/
static sipExportedModuleDef *getModule(PyObject *mname_obj)
{
PyObject *mod;
sipExportedModuleDef *em;
/* Make sure the module is imported. */
if ((mod = PyImport_Import(mname_obj)) == NULL)
return NULL;
/* Find the module definition. */
for (em = moduleList; em != NULL; em = em->em_next)
if (PyUnicode_Compare(mname_obj, em->em_nameobj) == 0)
break;
Py_DECREF(mod);
if (em == NULL)
{
PyErr_Format(PyExc_SystemError, "unable to find to find module: %U",
mname_obj);
}
return em;
}
/*
* The type unpickler.
*/
static PyObject *unpickle_type(PyObject *ignore, PyObject *args)
{
PyObject *mname_obj, *init_args;
const char *tname;
sipExportedModuleDef *em;
int i;
if (!PyArg_ParseTuple(args,
"UsO!:_unpickle_type",
&mname_obj, &tname, &PyTuple_Type, &init_args))
return NULL;
/* Get the module definition. */
if ((em = getModule(mname_obj)) == NULL)
return NULL;
/* Find the class type object. */
for (i = 0; i < em->em_nrtypes; ++i)
{
sipTypeDef *td = em->em_types[i];
if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td))
{
const char *pyname = sipPyNameOfContainer(
&((sipClassTypeDef *)td)->ctd_container, td);
if (strcmp(pyname, tname) == 0)
return PyObject_CallObject((PyObject *)sipTypeAsPyTypeObject(td), init_args);
}
}
PyErr_Format(PyExc_SystemError, "unable to find to find type: %s", tname);
return NULL;
}
/*
* The type pickler.
*/
static PyObject *pickle_type(PyObject *obj, PyObject *ignore)
{
sipExportedModuleDef *em;
/* Find the type definition and defining module. */
for (em = moduleList; em != NULL; em = em->em_next)
{
int i;
for (i = 0; i < em->em_nrtypes; ++i)
{
sipTypeDef *td = em->em_types[i];
if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td))
if (sipTypeAsPyTypeObject(td) == Py_TYPE(obj))
{
PyObject *init_args;
sipClassTypeDef *ctd = (sipClassTypeDef *)td;
const char *pyname = sipPyNameOfContainer(&ctd->ctd_container, td);
/*
* Ask the handwritten pickle code for the tuple of
* arguments that will recreate the object.
*/
init_args = ctd->ctd_pickle(sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, NULL));
if (!PyTuple_Check(init_args))
{
PyErr_Format(PyExc_TypeError,
"%%PickleCode for type %s.%s did not return a tuple",
sipNameOfModule(em), pyname);
return NULL;
}
return Py_BuildValue("O(OsN)", type_unpickler,
em->em_nameobj, pyname, init_args);
}
}
}
/* We should never get here. */
PyErr_Format(PyExc_SystemError, "attempt to pickle unknown type '%s'",
Py_TYPE(obj)->tp_name);
return NULL;
}
/*
* The enum unpickler.
*/
static PyObject *unpickle_enum(PyObject *ignore, PyObject *args)
{
PyObject *mname_obj, *evalue_obj;
const char *ename;
sipExportedModuleDef *em;
int i;
if (!PyArg_ParseTuple(args,
"UsO:_unpickle_enum",
&mname_obj, &ename, &evalue_obj))
return NULL;
/* Get the module definition. */
if ((em = getModule(mname_obj)) == NULL)
return NULL;
/* Find the enum type object. */
for (i = 0; i < em->em_nrtypes; ++i)
{
sipTypeDef *td = em->em_types[i];
if (td != NULL && !sipTypeIsStub(td) && sipTypeIsEnum(td))
if (strcmp(sipPyNameOfEnum((sipEnumTypeDef *)td), ename) == 0)
return PyObject_CallFunctionObjArgs((PyObject *)sipTypeAsPyTypeObject(td), evalue_obj, NULL);
}
PyErr_Format(PyExc_SystemError, "unable to find to find enum: %s", ename);
return NULL;
}
/*
* The enum pickler.
*/
static PyObject *pickle_enum(PyObject *obj, PyObject *ignore)
{
sipTypeDef *td = ((sipEnumTypeObject *)Py_TYPE(obj))->type;
return Py_BuildValue("O(Osi)", enum_unpickler, td->td_module->em_nameobj,
sipPyNameOfEnum((sipEnumTypeDef *)td),
(int)PyLong_AS_LONG(obj));
}
/*
* Set the __reduce__method for a type.
*/
static int setReduce(PyTypeObject *type, PyMethodDef *pickler)
{
static PyObject *rstr = NULL;
PyObject *descr;
int rc;
if (objectify("__reduce__", &rstr) < 0)
return -1;
/* Create the method descripter. */
if ((descr = PyDescr_NewMethod(type, pickler)) == NULL)
return -1;
/*
* Save the method. Note that we don't use PyObject_SetAttr() as we want
* to bypass any lazy attribute loading (which may not be safe yet).
*/
rc = PyType_Type.tp_setattro((PyObject *)type, rstr, descr);
Py_DECREF(descr);
return rc;
}
/*
* Create an enum type object.
*/
static int createEnumType(sipExportedModuleDef *client, sipEnumTypeDef *etd,
PyObject *mod_dict)
{
static PyObject *bases = NULL;
PyObject *name, *typedict, *args, *dict;
PyTypeObject *py_type;
etd->etd_base.td_module = client;
/* Get the dictionary into which the type will be placed. */
if (etd->etd_scope < 0)
dict = mod_dict;
else if ((dict = getScopeDict(client->em_types[etd->etd_scope], mod_dict, client)) == NULL)
goto reterr;
/* Create the base type tuple if it hasn't already been done. */
if (bases == NULL)
{
bases = PyTuple_Pack(1, (PyObject *)&PyLong_Type);
if (bases == NULL)
goto reterr;
}
/* Create an object corresponding to the type name. */
name = PyUnicode_FromString(sipPyNameOfEnum(etd));
if (name == NULL)
goto reterr;
/* Create the type dictionary. */
if ((typedict = createTypeDict(client->em_nameobj)) == NULL)
goto relname;
/* Create the type by calling the metatype. */
args = PyTuple_Pack(3, name, bases, typedict);
Py_DECREF(typedict);
if (args == NULL)
goto relname;
/* Pass the type via the back door. */
currentType = &etd->etd_base;
py_type = (PyTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type, args, NULL);
Py_DECREF(args);
if (py_type == NULL)
goto relname;
/* Add the type to the "parent" dictionary. */
if (PyDict_SetItem(dict, name, (PyObject *)py_type) < 0)
{
Py_DECREF((PyObject *)py_type);
goto relname;
}
/* We can now release our remaining references. */
Py_DECREF(name);
return 0;
/* Unwind after an error. */
relname:
Py_DECREF(name);
reterr:
etd->etd_base.td_module = client;
return -1;
}
/*
* Create a type dictionary for dynamic type being created in the module with
* the specified name.
*/
static PyObject *createTypeDict(PyObject *mname)
{
static PyObject *mstr = NULL;
PyObject *dict;
if (objectify("__module__", &mstr) < 0)
return NULL;
/* Create the dictionary. */
if ((dict = PyDict_New()) == NULL)
return NULL;
/* We need to set the module name as an attribute for dynamic types. */
if (PyDict_SetItem(dict, mstr, mname) < 0)
{
Py_DECREF(dict);
return NULL;
}
return dict;
}
/*
* Convert an ASCII string to a Python object if it hasn't already been done.
*/
static int objectify(const char *s, PyObject **objp)
{
if (*objp == NULL)
{
*objp = PyUnicode_FromString(s);
if (*objp == NULL)
return -1;
}
return 0;
}
/*
* Add a set of static instances to a dictionary.
*/
static int addInstances(PyObject *dict, sipInstancesDef *id)
{
if (id->id_type != NULL && addTypeInstances(dict, id->id_type) < 0)
return -1;
if (id->id_voidp != NULL && addVoidPtrInstances(dict,id->id_voidp) < 0)
return -1;
if (id->id_char != NULL && addCharInstances(dict,id->id_char) < 0)
return -1;
if (id->id_string != NULL && addStringInstances(dict,id->id_string) < 0)
return -1;
if (id->id_int != NULL && addIntInstances(dict, id->id_int) < 0)
return -1;
if (id->id_long != NULL && addLongInstances(dict,id->id_long) < 0)
return -1;
if (id->id_ulong != NULL && addUnsignedLongInstances(dict, id->id_ulong) < 0)
return -1;
if (id->id_llong != NULL && addLongLongInstances(dict, id->id_llong) < 0)
return -1;
if (id->id_ullong != NULL && addUnsignedLongLongInstances(dict, id->id_ullong) < 0)
return -1;
if (id->id_double != NULL && addDoubleInstances(dict,id->id_double) < 0)
return -1;
return 0;
}
/*
* Get "self" from the argument tuple for a method called as
* Class.Method(self, ...) rather than self.Method(...).
*/
static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr,
sipSimpleWrapper **selfp)
{
PyObject *self;
/* Get self from the argument tuple. */
if (argnr >= PyTuple_GET_SIZE(args))
return FALSE;
self = PyTuple_GET_ITEM(args, argnr);
if (!PyObject_TypeCheck(self, sipTypeAsPyTypeObject(td)))
return FALSE;
*selfp = (sipSimpleWrapper *)self;
return TRUE;
}
/*
* Populate a container's type dictionary.
*/
static int add_lazy_container_attrs(sipTypeDef *td, sipContainerDef *cod,
PyObject *dict)
{
int i;
PyMethodDef *pmd;
sipEnumMemberDef *enm;
sipVariableDef *vd;
/* Do the methods. */
pmd = cod->cod_methods;
for (i = 0; i < cod->cod_nrmethods; ++i)
{
int rc;
PyObject *descr;
if ((descr = sipMethodDescr_New(pmd)) == NULL)
return -1;
rc = PyDict_SetItemString(dict, pmd->ml_name, descr);
Py_DECREF(descr);
if (rc < 0)
return -1;
++pmd;
}
/* Do the enum members. */
enm = cod->cod_enummembers;
for (i = 0; i < cod->cod_nrenummembers; ++i)
{
int rc;
PyObject *val;
if ((val = createEnumMember(td, enm)) == NULL)
return -1;
rc = PyDict_SetItemString(dict, enm->em_name, val);
Py_DECREF(val);
if (rc < 0)
return -1;
++enm;
}
/* Do the variables. */
vd = cod->cod_variables;
for (i = 0; i < cod->cod_nrvariables; ++i)
{
int rc;
PyObject *descr;
if ((descr = sipVariableDescr_New(vd, td, cod)) == NULL)
return -1;
rc = PyDict_SetItemString(dict, vd->vd_name, descr);
Py_DECREF(descr);
if (rc < 0)
return -1;
++vd;
}
return 0;
}
/*
* Populate a type dictionary with all lazy attributes if it hasn't already
* been done.
*/
static int add_lazy_attrs(sipTypeDef *td)
{
sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td);
PyObject *dict;
sipAttrGetter *ag;
/* Handle the trivial case. */
if (wt->dict_complete)
return 0;
dict = ((PyTypeObject *)wt)->tp_dict;
if (sipTypeIsMapped(td))
{
if (add_lazy_container_attrs(td, &((sipMappedTypeDef *)td)->mtd_container, dict) < 0)
return -1;
}
else
{
sipClassTypeDef *nsx;
/* Search the possible linked list of namespace extenders. */
for (nsx = (sipClassTypeDef *)td; nsx != NULL; nsx = nsx->ctd_nsextender)
if (add_lazy_container_attrs((sipTypeDef *)nsx, &nsx->ctd_container, dict) < 0)
return -1;
}
/*
* Get any lazy attributes from registered getters. This must be done last
* to allow any existing attributes to be replaced.
*/
for (ag = sipAttrGetters; ag != NULL; ag = ag->next)
if (ag->type == NULL || PyType_IsSubtype((PyTypeObject *)wt, ag->type))
if (ag->getter(td, dict) < 0)
return -1;
wt->dict_complete = TRUE;
return 0;
}
/*
* Populate the type dictionary and all its super-types.
*/
static int add_all_lazy_attrs(sipTypeDef *td)
{
if (td == NULL)
return 0;
if (add_lazy_attrs(td) < 0)
return -1;
if (sipTypeIsClass(td))
{
sipClassTypeDef *ctd = (sipClassTypeDef *)td;
sipEncodedTypeDef *sup;
if ((sup = ctd->ctd_supers) != NULL)
do
{
sipTypeDef *sup_td = getGeneratedType(sup, td->td_module);
if (add_all_lazy_attrs(sup_td) < 0)
return -1;
}
while (!sup++->sc_flag);
}
return 0;
}
/*
* Return the generated type structure corresponding to the given Python type
* object.
*/
static const sipTypeDef *sip_api_type_from_py_type_object(PyTypeObject *py_type)
{
if (PyObject_TypeCheck((PyObject *)py_type, &sipWrapperType_Type))
return ((sipWrapperType *)py_type)->type;
if (PyObject_TypeCheck((PyObject *)py_type, &sipEnumType_Type))
return ((sipEnumTypeObject *)py_type)->type;
return NULL;
}
/*
* Return the generated type structure corresponding to the scope of the given
* type.
*/
static const sipTypeDef *sip_api_type_scope(const sipTypeDef *td)
{
if (sipTypeIsEnum(td))
{
const sipEnumTypeDef *etd = (const sipEnumTypeDef *)td;
if (etd->etd_scope >= 0)
return td->td_module->em_types[etd->etd_scope];
}
else
{
const sipContainerDef *cod;
if (sipTypeIsMapped(td))
cod = &((const sipMappedTypeDef *)td)->mtd_container;
else
cod = &((const sipClassTypeDef *)td)->ctd_container;
if (!cod->cod_scope.sc_flag)
return getGeneratedType(&cod->cod_scope, td->td_module);
}
return NULL;
}
/*
* Return TRUE if an object can be converted to a named enum.
*/
static int sip_api_can_convert_to_enum(PyObject *obj, const sipTypeDef *td)
{
assert(sipTypeIsEnum(td));
/* If the object is an enum then it must be the right enum. */
if (PyObject_TypeCheck((PyObject *)Py_TYPE(obj), &sipEnumType_Type))
return (PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(td)));
return PyLong_Check(obj);
}
/*
* Create a Python object for an enum member.
*/
static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm)
{
if (enm->em_enum < 0)
return PyLong_FromLong(enm->em_val);
return sip_api_convert_from_enum(enm->em_val,
td->td_module->em_types[enm->em_enum]);
}
/*
* Create a Python object for a member of a named enum.
*/
static PyObject *sip_api_convert_from_enum(int eval, const sipTypeDef *td)
{
assert(sipTypeIsEnum(td));
return PyObject_CallFunction((PyObject *)sipTypeAsPyTypeObject(td), "(i)",
eval);
}
/*
* Register a getter for unknown attributes.
*/
static int sip_api_register_attribute_getter(const sipTypeDef *td,
sipAttrGetterFunc getter)
{
sipAttrGetter *ag = sip_api_malloc(sizeof (sipAttrGetter));
if (ag == NULL)
return -1;
ag->type = sipTypeAsPyTypeObject(td);
ag->getter = getter;
ag->next = sipAttrGetters;
sipAttrGetters = ag;
return 0;
}
/*
* Report a function with invalid argument types.
*/
static void sip_api_no_function(PyObject *parseErr, const char *func,
const char *doc)
{
sip_api_no_method(parseErr, NULL, func, doc);
}
/*
* Report a method/function/signal with invalid argument types.
*/
static void sip_api_no_method(PyObject *parseErr, const char *scope,
const char *method, const char *doc)
{
const char *sep = ".";
if (scope == NULL)
scope = ++sep;
if (parseErr == NULL)
{
/*
* If we have got this far without trying a parse then there must be no
* overloads.
*/
PyErr_Format(PyExc_TypeError, "%s%s%s() is a private method", scope,
sep, method);
}
else if (PyList_Check(parseErr))
{
PyObject *exc;
/* There is an entry for each overload that was tried. */
if (PyList_GET_SIZE(parseErr) == 1)
{
PyObject *detail = detail_FromFailure(
PyList_GET_ITEM(parseErr, 0));
if (detail != NULL)
{
if (doc != NULL)
{
PyObject *doc_obj = signature_FromDocstring(doc, 0);
if (doc_obj != NULL)
{
exc = PyUnicode_FromFormat("%U: %U", doc_obj, detail);
Py_DECREF(doc_obj);
}
else
{
exc = NULL;
}
}
else
{
exc = PyUnicode_FromFormat("%s%s%s(): %U", scope, sep,
method, detail);
}
Py_DECREF(detail);
}
else
{
exc = NULL;
}
}
else
{
static const char *summary = "arguments did not match any overloaded call:";
SIP_SSIZE_T i;
if (doc != NULL)
{
exc = PyUnicode_FromString(summary);
}
else
{
exc = PyUnicode_FromFormat("%s%s%s(): %s", scope, sep, method,
summary);
}
for (i = 0; i < PyList_GET_SIZE(parseErr); ++i)
{
PyObject *failure;
PyObject *detail = detail_FromFailure(
PyList_GET_ITEM(parseErr, i));
if (detail != NULL)
{
if (doc != NULL)
{
PyObject *doc_obj = signature_FromDocstring(doc, i);
if (doc_obj != NULL)
{
failure = PyUnicode_FromFormat("\n %U: %U",
doc_obj, detail);
Py_DECREF(doc_obj);
}
else
{
Py_XDECREF(exc);
exc = NULL;
break;
}
}
else
{
failure = PyUnicode_FromFormat("\n overload %zd: %U",
i + 1, detail);
}
Py_DECREF(detail);
PyUnicode_AppendAndDel(&exc, failure);
}
else
{
Py_XDECREF(exc);
exc = NULL;
break;
}
}
}
if (exc != NULL)
{
PyErr_SetObject(PyExc_TypeError, exc);
Py_DECREF(exc);
}
}
else
{
/*
* None is used as a marker to say that an exception has already been
* raised. This won't show which overload we were parsing but it
* doesn't really matter as it is a fundamental problem rather than a
* user error.
*/
assert(parseErr == Py_None);
}
Py_XDECREF(parseErr);
}
/*
* Return a string/unicode object extracted from a particular line of a
* docstring.
*/
static PyObject *signature_FromDocstring(const char *doc, SIP_SSIZE_T line)
{
const char *eol;
SIP_SSIZE_T size = 0;
/*
* Find the start of the line. If there is a non-default versioned
* overload that has been enabled then it won't have an entry in the
* docstring. This means that the returned signature may be incorrect.
*/
while (line-- > 0)
{
const char *next = strchr(doc, '\n');
if (next == NULL)
break;
doc = next + 1;
}
/* Find the last closing parenthesis. */
for (eol = doc; *eol != '\n' && *eol != '\0'; ++eol)
if (*eol == ')')
size = eol - doc + 1;
return PyUnicode_FromStringAndSize(doc, size);
}
/*
* Return a string/unicode object that describes the given failure.
*/
static PyObject *detail_FromFailure(PyObject *failure_obj)
{
sipParseFailure *failure;
PyObject *detail;
failure = (sipParseFailure *)PyCapsule_GetPointer(failure_obj, NULL);
switch (failure->reason)
{
case Unbound:
detail = PyUnicode_FromFormat(
"first argument of unbound method must have type '%s'",
failure->detail_str);
break;
case TooFew:
detail = PyUnicode_FromString("not enough arguments");
break;
case TooMany:
detail = PyUnicode_FromString("too many arguments");
break;
case KeywordNotString:
detail = PyUnicode_FromFormat(
"%S keyword argument name is not a string",
failure->detail_obj);
break;
case UnknownKeyword:
detail = PyUnicode_FromFormat("'%U' is not a valid keyword argument",
failure->detail_obj);
break;
case Duplicate:
detail = PyUnicode_FromFormat(
"'%U' has already been given as a positional argument",
failure->detail_obj);
break;
case WrongType:
if (failure->arg_nr >= 0)
{
detail = bad_type_str(failure->arg_nr, failure->detail_obj);
}
else
{
detail = PyUnicode_FromFormat(
"keyword argument '%s' has unexpected type '%s'",
failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name);
}
break;
case Exception:
detail = failure->detail_obj;
if (detail)
{
Py_INCREF(detail);
break;
}
/* Drop through. */
default:
detail = PyUnicode_FromString("unknown reason");
}
return detail;
}
/*
* Report an abstract method called with an unbound self.
*/
static void sip_api_abstract_method(const char *classname, const char *method)
{
PyErr_Format(PyExc_TypeError,
"%s.%s() is abstract and cannot be called as an unbound method",
classname, method);
}
/*
* Report a deprecated class or method.
*/
static int sip_api_deprecated(const char *classname, const char *method)
{
char buf[100];
if (classname == NULL)
PyOS_snprintf(buf, sizeof (buf), "%s() is deprecated", method);
else if (method == NULL)
PyOS_snprintf(buf, sizeof (buf), "%s constructor is deprecated",
classname);
else
PyOS_snprintf(buf, sizeof (buf), "%s.%s() is deprecated", classname,
method);
return PyErr_WarnEx(PyExc_DeprecationWarning, buf, 1);
}
/*
* Report a bad operator argument. Only a small subset of operators need to
* be handled (those that don't return Py_NotImplemented).
*/
static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg,
sipPySlotType st)
{
const char *sn = NULL;
/* Try and get the text to match a Python exception. */
switch (st)
{
case concat_slot:
case iconcat_slot:
PyErr_Format(PyExc_TypeError,
"cannot concatenate '%s' and '%s' objects",
Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name);
break;
case repeat_slot:
sn = "*";
break;
case irepeat_slot:
sn = "*=";
break;
default:
sn = "unknown";
}
if (sn != NULL)
PyErr_Format(PyExc_TypeError,
"unsupported operand type(s) for %s: '%s' and '%s'", sn,
Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name);
}
/*
* Report a sequence length that does not match the length of a slice.
*/
static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen,
SIP_SSIZE_T slicelen)
{
PyErr_Format(PyExc_ValueError,
"attempt to assign sequence of size %zd to slice of size %zd",
seqlen, slicelen);
}
/*
* Report a Python object that cannot be converted to a particular class.
*/
static void sip_api_bad_class(const char *classname)
{
PyErr_Format(PyExc_TypeError,
"cannot convert Python object to an instance of %s", classname);
}
/*
* Report a Python member function with an unexpected return type.
*/
static void sip_api_bad_catcher_result(PyObject *method)
{
PyObject *mname;
/*
* This is part of the public API so we make no assumptions about the
* method object.
*/
if (!PyMethod_Check(method) ||
PyMethod_GET_FUNCTION(method) == NULL ||
!PyFunction_Check(PyMethod_GET_FUNCTION(method)) ||
PyMethod_GET_SELF(method) == NULL)
{
PyErr_Format(PyExc_TypeError,
"invalid argument to sipTQtBadCatcherResult()");
return;
}
mname = ((PyFunctionObject *)PyMethod_GET_FUNCTION(method))->func_name;
PyErr_Format(PyExc_TypeError, "invalid result type from %s.%U()",
Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname);
}
/*
* Transfer ownership of a class instance to Python from C/C++.
*/
static void sip_api_transfer_back(PyObject *self)
{
if (self != NULL && PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type))
{
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
if (sipCppHasRef(sw))
{
sipResetCppHasRef(sw);
Py_DECREF(sw);
}
else
removeFromParent((sipWrapper *)sw);
sipSetPyOwned(sw);
}
}
/*
* Break the association of a C++ owned Python object with any parent.
*/
static void sip_api_transfer_break(PyObject *self)
{
if (self != NULL && PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type))
{
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
if (sipCppHasRef(sw))
{
sipResetCppHasRef(sw);
Py_DECREF(sw);
}
else
removeFromParent((sipWrapper *)sw);
}
}
/*
* Transfer ownership of a class instance to C/C++ from Python.
*/
static void sip_api_transfer_to(PyObject *self, PyObject *owner)
{
/*
* There is a legitimate case where we try to transfer a PyObject that
* may not be a SIP-TQt generated class. The virtual handler code calls
* this function to keep the C/C++ instance alive when it gets rid of
* the Python object returned by the Python method. A class may have
* handwritten code that converts a regular Python type - so we can't
* assume that we can simply cast to sipWrapper.
*/
if (self != NULL &&
PyObject_TypeCheck(self, (PyTypeObject *)&sipWrapper_Type) &&
(owner == NULL ||
PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type)))
{
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
/*
* Keep the object alive while we do the transfer. If C++ has a
* reference then there is no need to increment it, just reset the flag
* and the following decrement will bring everything back to the way it
* should be.
*/
if (sipCppHasRef(sw))
sipResetCppHasRef(sw);
else
{
Py_INCREF(sw);
removeFromParent((sipWrapper *)sw);
}
if (owner != NULL)
addToParent((sipWrapper *)sw, (sipWrapper *)owner);
Py_DECREF(sw);
sipResetPyOwned(sw);
}
}
/*
* Add a license to a dictionary.
*/
static int addLicense(PyObject *dict,sipLicenseDef *lc)
{
int rc;
PyObject *ldict, *proxy, *o;
/* Convert the strings we use to objects if not already done. */
if (objectify("__license__", &licenseName) < 0)
return -1;
if (objectify("Licensee", &licenseeName) < 0)
return -1;
if (objectify("Type", &typeName) < 0)
return -1;
if (objectify("Timestamp", &timestampName) < 0)
return -1;
if (objectify("Signature", &signatureName) < 0)
return -1;
/* We use a dictionary to hold the license information. */
if ((ldict = PyDict_New()) == NULL)
return -1;
/* The license type is compulsory, the rest are optional. */
if (lc->lc_type == NULL)
goto deldict;
o = PyUnicode_FromString(lc->lc_type);
if (o == NULL)
goto deldict;
rc = PyDict_SetItem(ldict,typeName,o);
Py_DECREF(o);
if (rc < 0)
goto deldict;
if (lc->lc_licensee != NULL)
{
o = PyUnicode_FromString(lc->lc_licensee);
if (o == NULL)
goto deldict;
rc = PyDict_SetItem(ldict,licenseeName,o);
Py_DECREF(o);
if (rc < 0)
goto deldict;
}
if (lc->lc_timestamp != NULL)
{
o = PyUnicode_FromString(lc->lc_timestamp);
if (o == NULL)
goto deldict;
rc = PyDict_SetItem(ldict,timestampName,o);
Py_DECREF(o);
if (rc < 0)
goto deldict;
}
if (lc->lc_signature != NULL)
{
o = PyUnicode_FromString(lc->lc_signature);
if (o == NULL)
goto deldict;
rc = PyDict_SetItem(ldict,signatureName,o);
Py_DECREF(o);
if (rc < 0)
goto deldict;
}
/* Create a read-only proxy. */
if ((proxy = PyDictProxy_New(ldict)) == NULL)
goto deldict;
Py_DECREF(ldict);
rc = PyDict_SetItem(dict, licenseName, proxy);
Py_DECREF(proxy);
return rc;
deldict:
Py_DECREF(ldict);
return -1;
}
/*
* Add the void pointer instances to a dictionary.
*/
static int addVoidPtrInstances(PyObject *dict,sipVoidPtrInstanceDef *vi)
{
while (vi->vi_name != NULL)
{
int rc;
PyObject *w;
if ((w = sip_api_convert_from_void_ptr(vi->vi_val)) == NULL)
return -1;
rc = PyDict_SetItemString(dict,vi->vi_name,w);
Py_DECREF(w);
if (rc < 0)
return -1;
++vi;
}
return 0;
}
/*
* Add the char instances to a dictionary.
*/
static int addCharInstances(PyObject *dict, sipCharInstanceDef *ci)
{
while (ci->ci_name != NULL)
{
int rc;
PyObject *w;
switch (ci->ci_encoding)
{
case 'A':
w = PyUnicode_DecodeASCII(&ci->ci_val, 1, NULL);
break;
case 'L':
w = PyUnicode_DecodeLatin1(&ci->ci_val, 1, NULL);
break;
case '8':
w = PyUnicode_FromStringAndSize(&ci->ci_val, 1);
break;
default:
w = PyBytes_FromStringAndSize(&ci->ci_val, 1);
}
if (w == NULL)
return -1;
rc = PyDict_SetItemString(dict, ci->ci_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++ci;
}
return 0;
}
/*
* Add the string instances to a dictionary.
*/
static int addStringInstances(PyObject *dict, sipStringInstanceDef *si)
{
while (si->si_name != NULL)
{
int rc;
PyObject *w;
switch (si->si_encoding)
{
case 'A':
w = PyUnicode_DecodeASCII(si->si_val, strlen(si->si_val), NULL);
break;
case 'L':
w = PyUnicode_DecodeLatin1(si->si_val, strlen(si->si_val), NULL);
break;
case '8':
w = PyUnicode_FromString(si->si_val);
break;
default:
w = PyBytes_FromString(si->si_val);
}
if (w == NULL)
return -1;
rc = PyDict_SetItemString(dict, si->si_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++si;
}
return 0;
}
/*
* Add the int instances to a dictionary.
*/
static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii)
{
while (ii->ii_name != NULL)
{
int rc;
PyObject *w;
w = PyLong_FromLong(ii->ii_val);
if (w == NULL)
return -1;
rc = PyDict_SetItemString(dict, ii->ii_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++ii;
}
return 0;
}
/*
* Add the long instances to a dictionary.
*/
static int addLongInstances(PyObject *dict,sipLongInstanceDef *li)
{
while (li->li_name != NULL)
{
int rc;
PyObject *w;
if ((w = PyLong_FromLong(li->li_val)) == NULL)
return -1;
rc = PyDict_SetItemString(dict,li->li_name,w);
Py_DECREF(w);
if (rc < 0)
return -1;
++li;
}
return 0;
}
/*
* Add the unsigned long instances to a dictionary.
*/
static int addUnsignedLongInstances(PyObject *dict, sipUnsignedLongInstanceDef *uli)
{
while (uli->uli_name != NULL)
{
int rc;
PyObject *w;
if ((w = PyLong_FromUnsignedLong(uli->uli_val)) == NULL)
return -1;
rc = PyDict_SetItemString(dict, uli->uli_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++uli;
}
return 0;
}
/*
* Add the long long instances to a dictionary.
*/
static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli)
{
while (lli->lli_name != NULL)
{
int rc;
PyObject *w;
#if defined(HAVE_LONG_LONG)
if ((w = PyLong_FromLongLong(lli->lli_val)) == NULL)
#else
if ((w = PyLong_FromLong(lli->lli_val)) == NULL)
#endif
return -1;
rc = PyDict_SetItemString(dict, lli->lli_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++lli;
}
return 0;
}
/*
* Add the unsigned long long instances to a dictionary.
*/
static int addUnsignedLongLongInstances(PyObject *dict, sipUnsignedLongLongInstanceDef *ulli)
{
while (ulli->ulli_name != NULL)
{
int rc;
PyObject *w;
#if defined(HAVE_LONG_LONG)
if ((w = PyLong_FromUnsignedLongLong(ulli->ulli_val)) == NULL)
#else
if ((w = PyLong_FromUnsignedLong(ulli->ulli_val)) == NULL)
#endif
return -1;
rc = PyDict_SetItemString(dict, ulli->ulli_name, w);
Py_DECREF(w);
if (rc < 0)
return -1;
++ulli;
}
return 0;
}
/*
* Add the double instances to a dictionary.
*/
static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di)
{
while (di->di_name != NULL)
{
int rc;
PyObject *w;
if ((w = PyFloat_FromDouble(di->di_val)) == NULL)
return -1;
rc = PyDict_SetItemString(dict,di->di_name,w);
Py_DECREF(w);
if (rc < 0)
return -1;
++di;
}
return 0;
}
/*
* Wrap a set of type instances and add them to a dictionary.
*/
static int addTypeInstances(PyObject *dict, sipTypeInstanceDef *ti)
{
while (ti->ti_name != NULL)
{
if (addSingleTypeInstance(dict, ti->ti_name, ti->ti_ptr, *ti->ti_type, ti->ti_flags) < 0)
return -1;
++ti;
}
return 0;
}
/*
* Wrap a single type instance and add it to a dictionary.
*/
static int addSingleTypeInstance(PyObject *dict, const char *name,
void *cppPtr, const sipTypeDef *td, int initflags)
{
int rc;
PyObject *obj;
if (sipTypeIsClass(td))
{
obj = sipWrapSimpleInstance(cppPtr, td, NULL, initflags);
}
else if (sipTypeIsEnum(td))
{
obj = sip_api_convert_from_enum(*(int *)cppPtr, td);
}
else
{
assert(sipTypeIsMapped(td));
obj = ((const sipMappedTypeDef *)td)->mtd_cfrom(cppPtr, NULL);
}
if (obj == NULL)
return -1;
rc = PyDict_SetItemString(dict, name, obj);
Py_DECREF(obj);
return rc;
}
/*
* Convert a type instance and add it to a dictionary.
*/
static int sip_api_add_type_instance(PyObject *dict, const char *name,
void *cppPtr, const sipTypeDef *td)
{
return addSingleTypeInstance(getDictFromObject(dict), name, cppPtr, td, 0);
}
/*
* Return the instance dictionary for an object if it is a wrapped type.
* Otherwise assume that it is a module dictionary.
*/
static PyObject *getDictFromObject(PyObject *obj)
{
if (PyObject_TypeCheck(obj, (PyTypeObject *)&sipWrapperType_Type))
obj = ((PyTypeObject *)obj)->tp_dict;
return obj;
}
/*
* Return a Python reimplementation corresponding to a C/C++ virtual function,
* if any. If one was found then the Python lock is acquired.
*/
static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc,
sipSimpleWrapper *sipSelf, const char *cname, const char *mname)
{
PyObject *mname_obj, *reimp, *mro, *cls;
SIP_SSIZE_T i;
/*
* This is the most common case (where there is no Python reimplementation)
* so we take a fast shortcut without acquiring the GIL.
*/
if (*pymc != 0)
return NULL;
/* We might still have C++ going after the interpreter has gone. */
if (sipInterpreter == NULL)
return NULL;
/*
* It's possible that the Python object has been deleted but the underlying
* C++ instance is still working and trying to handle virtual functions.
* Alternatively, an instance has started handling virtual functions before
* its ctor has returned. In either case say there is no Python
* reimplementation.
*/
if (sipSelf == NULL)
return NULL;
/* Get any reimplementation. */
#ifdef WITH_THREAD
*gil = PyGILState_Ensure();
#endif
mname_obj = PyUnicode_FromString(mname);
if (mname_obj == NULL)
{
#ifdef WITH_THREAD
PyGILState_Release(*gil);
#endif
return NULL;
}
/*
* We don't use PyObject_GetAttr() because that might find the generated
* C function before a reimplementation defined in a mixin (ie. later in
* the MRO).
*/
if (sipSelf->dict != NULL)
{
/* Check the instance dictionary in case it has been monkey patched. */
if ((reimp = PyDict_GetItem(sipSelf->dict, mname_obj)) != NULL && PyCallable_Check(reimp))
{
Py_DECREF(mname_obj);
Py_INCREF(reimp);
return reimp;
}
}
cls = (PyObject *)Py_TYPE(sipSelf);
mro = ((PyTypeObject *)cls)->tp_mro;
assert(PyTuple_Check(mro));
reimp = NULL;
for (i = 0; i < PyTuple_GET_SIZE(mro); ++i)
{
PyObject *cls_dict;
cls = PyTuple_GET_ITEM(mro, i);
cls_dict = ((PyTypeObject *)cls)->tp_dict;
if (cls_dict != NULL && (reimp = PyDict_GetItem(cls_dict, mname_obj)) != NULL)
{
/*
* Check any reimplementation is Python code and is not the wrapped
* C++ method.
*/
if (PyMethod_Check(reimp))
{
/* It's already a method but make sure it is bound. */
if (PyMethod_GET_SELF(reimp) != NULL)
{
Py_INCREF(reimp);
}
else
{
reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp),
(PyObject *)sipSelf);
}
break;
}
if (PyFunction_Check(reimp))
{
reimp = PyMethod_New(reimp, (PyObject *)sipSelf);
break;
}
reimp = NULL;
}
}
Py_DECREF(mname_obj);
if (reimp == NULL)
{
/* Use the fast track in future. */
*pymc = 1;
if (cname != NULL)
{
/* Note that this will only be raised once per method. */
PyErr_Format(PyExc_NotImplementedError,
"%s.%s() is abstract and must be overridden", cname,
mname);
PyErr_Print();
}
#ifdef WITH_THREAD
PyGILState_Release(*gil);
#endif
}
return reimp;
}
/*
* Convert a C/C++ pointer to the object that wraps it.
*/
static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td)
{
return (PyObject *)sipOMFindObject(&cppPyMap, cppPtr, td);
}
/*
* Return the C/C++ pointer from a wrapper without any checks.
*/
void *sip_api_get_address(sipSimpleWrapper *sw)
{
if (sipIsAccessFunc(sw))
return (*sw->u.afPtr)();
if (sipIsIndirect(sw))
return *((void **)sw->u.cppPtr);
return sw->u.cppPtr;
}
/*
* Get the C/C++ pointer for a complex object. Note that not casting the C++
* pointer is a bug. However this is only ever called by PyTQt signal emitter
* code and PyTQt doesn't contain anything that multiply inherits from TQObject.
*/
static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw)
{
return getComplexCppPtr(sw, NULL);
}
/*
* Get the C/C++ pointer for a complex object and optionally cast it to the
* required type.
*/
static void *getComplexCppPtr(sipSimpleWrapper *sw, const sipTypeDef *td)
{
if (!sipIsDerived(sw))
{
PyErr_SetString(PyExc_RuntimeError,
"no access to protected functions or signals for objects not created from Python");
return NULL;
}
return sip_api_get_cpp_ptr(sw, td);
}
/*
* Get the C/C++ pointer from a wrapper and optionally cast it to the required
* type.
*/
void *sip_api_get_cpp_ptr(sipSimpleWrapper *sw, const sipTypeDef *td)
{
void *ptr = sip_api_get_address(sw);
if (checkPointer(ptr, sw) < 0)
return NULL;
if (td != NULL)
{
ptr = cast_cpp_ptr(ptr, Py_TYPE(sw), td);
if (ptr == NULL)
PyErr_Format(PyExc_TypeError, "could not convert '%s' to '%s'",
Py_TYPE(sw)->tp_name,
sipPyNameOfContainer(&((const sipClassTypeDef *)td)->ctd_container, td));
}
return ptr;
}
/*
* Cast a C/C++ pointer from a source type to a destination type.
*/
static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type,
const sipTypeDef *dst_type)
{
sipCastFunc cast = ((const sipClassTypeDef *)((sipWrapperType *)src_type)->type)->ctd_cast;
/* C structures don't have cast functions. */
if (cast != NULL)
ptr = (*cast)(ptr, dst_type);
return ptr;
}
/*
* Check that a pointer is non-NULL.
*/
static int checkPointer(void *ptr, sipSimpleWrapper *sw)
{
if (ptr == NULL)
{
PyErr_Format(PyExc_RuntimeError, (sipWasCreated(sw) ?
"wrapped C/C++ object of type %s has been deleted" :
"super-class __init__() of type %s was never called"),
Py_TYPE(sw)->tp_name);
return -1;
}
return 0;
}
/*
* Keep an extra reference to an object.
*/
static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj)
{
PyObject *dict, *key_obj;
/*
* If there isn't a "self" to keep the extra reference for later garbage
* collection then just take a reference and let it leak. This could
* happen, for example, if virtuals were still being called while Python
* was shutting down.
*/
if (self == NULL)
{
Py_XINCREF(obj);
return;
}
/* Create the extra references dictionary if needed. */
if ((dict = ((sipSimpleWrapper *)self)->extra_refs) == NULL)
{
if ((dict = PyDict_New()) == NULL)
return;
((sipSimpleWrapper *)self)->extra_refs = dict;
}
key_obj = PyLong_FromLong(key);
if (key_obj != NULL)
{
/* This can happen if the argument was optional. */
if (obj == NULL)
obj = Py_None;
PyDict_SetItem(dict, key_obj, obj);
Py_DECREF(key_obj);
}
}
/*
* Check to see if a Python object can be converted to a type.
*/
static int sip_api_can_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
int flags)
{
int ok;
assert(sipTypeIsClass(td) || sipTypeIsMapped(td));
/* None is handled outside the type checkers. */
if (pyObj == Py_None)
{
/* If the type explicitly handles None then ignore the flags. */
if (sipTypeAllowNone(td))
ok = TRUE;
else
ok = ((flags & SIP_NOT_NONE) == 0);
}
else
{
sipConvertToFunc cto;
if (sipTypeIsClass(td))
{
cto = ((const sipClassTypeDef *)td)->ctd_cto;
if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0)
ok = PyObject_TypeCheck(pyObj, sipTypeAsPyTypeObject(td));
else
ok = cto(pyObj, NULL, NULL, NULL);
}
else
{
cto = ((const sipMappedTypeDef *)td)->mtd_cto;
ok = cto(pyObj, NULL, NULL, NULL);
}
}
return ok;
}
/*
* Convert a Python object to a C/C++ pointer, assuming a previous call to
* sip_api_can_convert_to_type() has been successful. Allow ownership to be
* transferred and any type convertors to be disabled.
*/
static void *sip_api_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
PyObject *transferObj, int flags, int *statep, int *iserrp)
{
void *cpp = NULL;
int state = 0;
assert(sipTypeIsClass(td) || sipTypeIsMapped(td));
/* Don't convert if there has already been an error. */
if (!*iserrp)
{
/* Do the conversion. */
if (pyObj == Py_None && !sipTypeAllowNone(td))
cpp = NULL;
else
{
sipConvertToFunc cto;
if (sipTypeIsClass(td))
{
cto = ((const sipClassTypeDef *)td)->ctd_cto;
if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0)
{
if ((cpp = sip_api_get_cpp_ptr((sipSimpleWrapper *)pyObj, td)) == NULL)
*iserrp = TRUE;
else if (transferObj != NULL)
{
if (transferObj == Py_None)
sip_api_transfer_back(pyObj);
else
sip_api_transfer_to(pyObj, transferObj);
}
}
else
{
state = cto(pyObj, &cpp, iserrp, transferObj);
}
}
else
{
cto = ((const sipMappedTypeDef *)td)->mtd_cto;
state = cto(pyObj, &cpp, iserrp, transferObj);
}
}
}
if (statep != NULL)
*statep = state;
return cpp;
}
/*
* Convert a Python object to a C/C++ pointer and raise an exception if it
* can't be done.
*/
static void *sip_api_force_convert_to_type(PyObject *pyObj,
const sipTypeDef *td, PyObject *transferObj, int flags, int *statep,
int *iserrp)
{
/* Don't even try if there has already been an error. */
if (*iserrp)
return NULL;
/* See if the object's type can be converted. */
if (!sip_api_can_convert_to_type(pyObj, td, flags))
{
if (sipTypeIsMapped(td))
PyErr_Format(PyExc_TypeError,
"%s cannot be converted to a C/C++ %s in this context",
Py_TYPE(pyObj)->tp_name, sipTypeName(td));
else
PyErr_Format(PyExc_TypeError,
"%s cannot be converted to %s.%s in this context",
Py_TYPE(pyObj)->tp_name, sipNameOfModule(td->td_module),
sipPyNameOfContainer(&((const sipClassTypeDef *)td)->ctd_container, td));
if (statep != NULL)
*statep = 0;
*iserrp = TRUE;
return NULL;
}
/* Do the conversion. */
return sip_api_convert_to_type(pyObj, td, transferObj, flags, statep,
iserrp);
}
/*
* Release a possibly temporary C/C++ instance created by a type convertor.
*/
static void sip_api_release_type(void *cpp, const sipTypeDef *td, int state)
{
/* See if there is something to release. */
if (state & SIP_TEMPORARY)
release(cpp, td, state);
}
/*
* Release an instance.
*/
static void release(void *addr, const sipTypeDef *td, int state)
{
sipReleaseFunc rel;
if (sipTypeIsClass(td))
{
rel = ((const sipClassTypeDef *)td)->ctd_release;
/*
* If there is no release function then it must be a C structure and we
* can just free it.
*/
if (rel == NULL)
sip_api_free(addr);
}
else if (sipTypeIsMapped(td))
rel = ((const sipMappedTypeDef *)td)->mtd_release;
else
rel = NULL;
if (rel != NULL)
rel(addr, state);
}
/*
* Convert a C/C++ instance to a Python instance.
*/
PyObject *sip_api_convert_from_type(void *cpp, const sipTypeDef *td,
PyObject *transferObj)
{
PyObject *py;
assert(sipTypeIsClass(td) || sipTypeIsMapped(td));
/* Handle None. */
if (cpp == NULL)
{
Py_INCREF(Py_None);
return Py_None;
}
if (sipTypeIsMapped(td))
return ((const sipMappedTypeDef *)td)->mtd_cfrom(cpp, transferObj);
/* Apply any sub-class convertor. */
if (sipTypeHasSCC(td))
td = convertSubClass(td, &cpp);
/* See if we have already wrapped it. */
if ((py = sip_api_get_pyobject(cpp, td)) != NULL)
Py_INCREF(py);
else if ((py = sipWrapSimpleInstance(cpp, td, NULL, SIP_SHARE_MAP)) == NULL)
return NULL;
/* Handle any ownership transfer. */
if (transferObj != NULL)
{
if (transferObj == Py_None)
sip_api_transfer_back(py);
else
sip_api_transfer_to(py, transferObj);
}
return py;
}
/*
* Convert a new C/C++ instance to a Python instance.
*/
static PyObject *sip_api_convert_from_new_type(void *cpp, const sipTypeDef *td,
PyObject *transferObj)
{
sipWrapper *owner;
/* Handle None. */
if (cpp == NULL)
{
Py_INCREF(Py_None);
return Py_None;
}
if (sipTypeIsMapped(td))
{
PyObject *res = ((const sipMappedTypeDef *)td)->mtd_cfrom(cpp,
transferObj);
if (res != NULL)
{
/*
* We no longer need the C/C++ instance so we release it (unless
* its ownership is transferred). This means this call is
* semantically equivalent to the case where the type is a wrapped
* class.
*/
if (transferObj == NULL || transferObj == Py_None)
release(cpp, td, 0);
}
return res;
}
assert(sipTypeIsClass(td));
/* Apply any sub-class convertor. */
if (sipTypeHasSCC(td))
td = convertSubClass(td, &cpp);
/* Handle any ownership transfer. */
if (transferObj == NULL || transferObj == Py_None)
owner = NULL;
else
owner = (sipWrapper *)transferObj;
return sipWrapSimpleInstance(cpp, td, owner, (owner == NULL ? SIP_PY_OWNED : 0));
}
/*
* Implement the normal transfer policy for the result of %ConvertToTypeCode,
* ie. it is temporary unless it is being transferred from Python.
*/
int sip_api_get_state(PyObject *transferObj)
{
return (transferObj == NULL || transferObj == Py_None) ? SIP_TEMPORARY : 0;
}
/*
* This is set by sip_api_find_type() before calling bsearch() on the types
* table for the module. This is a hack that works around the problem of
* unresolved externally defined types.
*/
static sipExportedModuleDef *module_searched;
/*
* The bsearch() helper function for searching the types table.
*/
static int compareTypeDef(const void *key, const void *el)
{
const char *s1 = (const char *)key;
const char *s2 = NULL;
const sipTypeDef *td;
char ch1, ch2;
/* Allow for unresolved externally defined types. */
td = *(const sipTypeDef **)el;
if (td != NULL)
s2 = sipTypeName(td);
else
{
sipExternalTypeDef *etd = module_searched->em_external;
assert(etd != NULL);
/* Find which external type it is. */
while (etd->et_nr >= 0)
{
const sipTypeDef **tdp = &module_searched->em_types[etd->et_nr];
if (tdp == (const sipTypeDef **)el)
{
s2 = etd->et_name;
break;
}
++etd;
}
assert(s2 != NULL);
}
/*
* Compare while ignoring spaces so that we don't impose a rigorous naming
* standard. This only really affects template-based mapped types.
*/
do
{
while ((ch1 = *s1++) == ' ')
;
while ((ch2 = *s2++) == ' ')
;
/* We might be looking for a pointer or a reference. */
if ((ch1 == '*' || ch1 == '&' || ch1 == '\0') && ch2 == '\0')
return 0;
}
while (ch1 == ch2);
return (ch1 < ch2 ? -1 : 1);
}
/*
* Return the type structure for a particular type.
*/
static const sipTypeDef *sip_api_find_type(const char *type)
{
sipExportedModuleDef *em;
for (em = moduleList; em != NULL; em = em->em_next)
{
sipTypeDef **tdp;
/* The backdoor to the comparison helper. */
module_searched = em;
tdp = (sipTypeDef **)bsearch((const void *)type,
(const void *)em->em_types, em->em_nrtypes,
sizeof (sipTypeDef *), compareTypeDef);
if (tdp != NULL)
{
/*
* Note that this will be NULL for unresolved externally defined
* types.
*/
return *tdp;
}
}
return NULL;
}
/*
* Return the mapped type structure for a particular mapped type. This is
* deprecated.
*/
static const sipMappedType *sip_api_find_mapped_type(const char *type)
{
const sipTypeDef *td = sip_api_find_type(type);
if (td != NULL && sipTypeIsMapped(td))
return (const sipMappedType *)td;
return NULL;
}
/*
* Return the type structure for a particular class. This is deprecated.
*/
static sipWrapperType *sip_api_find_class(const char *type)
{
const sipTypeDef *td = sip_api_find_type(type);
if (td != NULL && sipTypeIsClass(td))
return (sipWrapperType *)sipTypeAsPyTypeObject(td);
return NULL;
}
/*
* Return the type structure for a particular named enum. This is deprecated.
*/
static PyTypeObject *sip_api_find_named_enum(const char *type)
{
const sipTypeDef *td = sip_api_find_type(type);
if (td != NULL && sipTypeIsEnum(td))
return sipTypeAsPyTypeObject(td);
return NULL;
}
/*
* Save the components of a Python method.
*/
void sipSaveMethod(sipPyMethod *pm, PyObject *meth)
{
pm->mfunc = PyMethod_GET_FUNCTION(meth);
pm->mself = PyMethod_GET_SELF(meth);
}
/*
* Call a hook.
*/
static void sip_api_call_hook(const char *hookname)
{
PyObject *dictofmods, *mod, *dict, *hook, *res;
/* Get the dictionary of modules. */
if ((dictofmods = PyImport_GetModuleDict()) == NULL)
return;
/* Get the __builtin__ module. */
if ((mod = PyDict_GetItemString(dictofmods, "__builtin__")) == NULL)
return;
/* Get it's dictionary. */
if ((dict = PyModule_GetDict(mod)) == NULL)
return;
/* Get the function hook. */
if ((hook = PyDict_GetItemString(dict, hookname)) == NULL)
return;
/* Call the hook and discard any result. */
res = PyObject_CallObject(hook, NULL);
Py_XDECREF(res);
}
/*
* Call any sub-class convertors for a given type returning a pointer to the
* sub-type object, and possibly modifying the C++ address (in the case of
* multiple inheritence).
*/
static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr)
{
PyTypeObject *py_type = sipTypeAsPyTypeObject(td);
sipExportedModuleDef *em;
if (*cppPtr == NULL)
return NULL;
/*
* Note that this code depends on the fact that a module appears in the
* list of modules before any module it imports, ie. sub-class convertors
* will be invoked for more specific types first.
*/
for (em = moduleList; em != NULL; em = em->em_next)
{
sipSubClassConvertorDef *scc;
if ((scc = em->em_convertors) == NULL)
continue;
while (scc->scc_convertor != NULL)
{
/*
* The base type is the "root" class that may have a number of
* convertors each handling a "branch" of the derived tree of
* classes. The "root" normally implements the base function that
* provides the RTTI used by the convertors and is re-implemented
* by derived classes. We therefore see if the target type is a
* sub-class of the root, ie. see if the convertor might be able to
* convert the target type to something more specific.
*/
if (PyType_IsSubtype(py_type, sipTypeAsPyTypeObject(scc->scc_basetype)))
{
void *ptr;
const sipTypeDef *subtype;
ptr = cast_cpp_ptr(*cppPtr, py_type, scc->scc_basetype);
subtype = (*scc->scc_convertor)(&ptr);
/*
* We are only interested in types that are not super-classes
* of the target. This happens either because it is in an
* earlier convertor than the one that handles the type or it
* is in a later convertor that handles a different branch of
* the hierarchy. Either way, the ordering of the modules
* ensures that there will be no more than one and that it will
* be the right one.
*/
if (subtype != NULL && !PyType_IsSubtype(py_type, sipTypeAsPyTypeObject(subtype)))
{
*cppPtr = ptr;
return subtype;
}
}
++scc;
}
}
/*
* We haven't found the exact type, so return the most specific type that
* it must be. This can happen legitimately if the wrapped library is
* returning an internal class that is down-cast to a more generic class.
* Also we want this function to be safe when a class doesn't have any
* convertors.
*/
return td;
}
/*
* The bsearch() helper function for searching a sorted string map table.
*/
static int compareStringMapEntry(const void *key,const void *el)
{
return strcmp((const char *)key,((const sipStringTypeClassMap *)el)->typeString);
}
/*
* A convenience function for %ConvertToSubClassCode for types represented as a
* string. Returns the Python class object or NULL if the type wasn't
* recognised. This is deprecated.
*/
static sipWrapperType *sip_api_map_string_to_class(const char *typeString,
const sipStringTypeClassMap *map, int maplen)
{
sipStringTypeClassMap *me;
me = (sipStringTypeClassMap *)bsearch((const void *)typeString,
(const void *)map,maplen,
sizeof (sipStringTypeClassMap),
compareStringMapEntry);
return ((me != NULL) ? *me->pyType : NULL);
}
/*
* The bsearch() helper function for searching a sorted integer map table.
*/
static int compareIntMapEntry(const void *keyp,const void *el)
{
int key = *(int *)keyp;
if (key > ((const sipIntTypeClassMap *)el)->typeInt)
return 1;
if (key < ((const sipIntTypeClassMap *)el)->typeInt)
return -1;
return 0;
}
/*
* A convenience function for %ConvertToSubClassCode for types represented as
* an integer. Returns the Python class object or NULL if the type wasn't
* recognised. This is deprecated.
*/
static sipWrapperType *sip_api_map_int_to_class(int typeInt,
const sipIntTypeClassMap *map, int maplen)
{
sipIntTypeClassMap *me;
me = (sipIntTypeClassMap *)bsearch((const void *)&typeInt,
(const void *)map,maplen,
sizeof (sipIntTypeClassMap),
compareIntMapEntry);
return ((me != NULL) ? *me->pyType : NULL);
}
/*
* Raise an unknown exception. Make no assumptions about the GIL.
*/
static void sip_api_raise_unknown_exception(void)
{
static PyObject *mobj = NULL;
SIP_BLOCK_THREADS
objectify("unknown", &mobj);
PyErr_SetObject(PyExc_Exception, mobj);
SIP_UNBLOCK_THREADS
}
/*
* Raise an exception implemented as a type. Make no assumptions about the
* GIL.
*/
static void sip_api_raise_type_exception(const sipTypeDef *td, void *ptr)
{
PyObject *self;
assert(sipTypeIsClass(td));
SIP_BLOCK_THREADS
self = sipWrapSimpleInstance(ptr, td, NULL, SIP_PY_OWNED);
PyErr_SetObject((PyObject *)sipTypeAsPyTypeObject(td), self);
Py_XDECREF(self);
SIP_UNBLOCK_THREADS
}
/*
* Return the module of an encoded type.
*/
static sipExportedModuleDef *getTypeModule(const sipEncodedTypeDef *enc,
sipExportedModuleDef *em)
{
if (enc->sc_module != 255)
em = em->em_imports[enc->sc_module].im_module;
return em;
}
/*
* Return the generated type structure of an encoded type.
*/
static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc,
sipExportedModuleDef *em)
{
return getTypeModule(enc, em)->em_types[enc->sc_type];
}
/*
* Find a particular slot function for a type.
*/
static void *findSlot(PyObject *self, sipPySlotType st)
{
void *slot;
PyTypeObject *py_type = Py_TYPE(self);
/* See if it is a wrapper. */
if (PyObject_TypeCheck((PyObject *)py_type, &sipWrapperType_Type))
{
sipClassTypeDef *ctd;
ctd = (sipClassTypeDef *)((sipWrapperType *)(py_type))->type;
if (ctd->ctd_pyslots != NULL)
slot = findSlotInType(ctd->ctd_pyslots, st);
else
slot = NULL;
if (slot == NULL)
{
sipEncodedTypeDef *sup;
/* Search any super-types. */
if ((sup = ctd->ctd_supers) != NULL)
{
sipClassTypeDef *sup_ctd;
do
{
sup_ctd = (sipClassTypeDef *)getGeneratedType(sup,
ctd->ctd_base.td_module);
if (sup_ctd->ctd_pyslots != NULL)
slot = findSlotInType(sup_ctd->ctd_pyslots, st);
}
while (slot == NULL && !sup++->sc_flag);
}
}
}
else
{
sipEnumTypeDef *etd;
/* If it is not a wrapper then it must be an enum. */
assert(PyObject_TypeCheck((PyObject *)py_type, &sipEnumType_Type));
etd = (sipEnumTypeDef *)((sipEnumTypeObject *)(py_type))->type;
assert(etd->etd_pyslots != NULL);
slot = findSlotInType(etd->etd_pyslots, st);
}
return slot;
}
/*
* Find a particular slot function in a particular type.
*/
static void *findSlotInType(sipPySlotDef *psd, sipPySlotType st)
{
while (psd->psd_func != NULL)
{
if (psd->psd_type == st)
return psd->psd_func;
++psd;
}
return NULL;
}
/*
* Return the C/C++ address and the generated class structure for a wrapper.
*/
static void *getPtrTypeDef(sipSimpleWrapper *self, const sipClassTypeDef **ctd)
{
*ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(self))->type;
return (sipNotInMap(self) ? NULL : self->u.cppPtr);
}
/*
* Handle an objobjargproc slot.
*/
static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2,
sipPySlotType st)
{
int (*f)(PyObject *, PyObject *);
int res;
f = (int (*)(PyObject *, PyObject *))findSlot(self, st);
if (f != NULL)
{
PyObject *args;
/*
* Slot handlers require a single PyObject *. The second argument is
* optional.
*/
if (arg2 == NULL)
{
args = arg1;
Py_INCREF(args);
}
else
{
args = PyTuple_Pack(2, arg1, arg2);
if (args == NULL)
return -1;
}
res = f(self, args);
Py_DECREF(args);
}
else
{
PyErr_SetNone(PyExc_NotImplementedError);
res = -1;
}
return res;
}
/*
* Handle an ssizeobjargproc slot.
*/
static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1,
PyObject *arg2, sipPySlotType st)
{
int (*f)(PyObject *, PyObject *);
int res;
f = (int (*)(PyObject *, PyObject *))findSlot(self, st);
if (f != NULL)
{
PyObject *args;
/*
* Slot handlers require a single PyObject *. The second argument is
* optional.
*/
if (arg2 == NULL)
args = PyLong_FromSsize_t(arg1);
else
args = Py_BuildValue("(nO)", arg1, arg2);
if (args == NULL)
return -1;
res = f(self, args);
Py_DECREF(args);
}
else
{
PyErr_SetNone(PyExc_NotImplementedError);
res = -1;
}
return res;
}
/*
* The metatype alloc slot.
*/
static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems)
{
PyObject *o;
/* Call the standard super-metatype alloc. */
if ((o = PyType_Type.tp_alloc(self, nitems)) == NULL)
return NULL;
/*
* Consume any extra type specific information and use it to initialise the
* slots. This only happens for directly wrapped classes (and not
* programmer written sub-classes). This must be done in the alloc
* function because it is the only place we can break out of the default
* new() function before PyType_Ready() is called.
*/
if (currentType != NULL)
{
((sipWrapperType *)o)->type = currentType;
if (sipTypeIsClass(currentType))
{
const char *docstring = ((sipClassTypeDef *)currentType)->ctd_docstring;
/*
* Skip the marker that identifies the docstring as being
* automatically generated.
*/
if (docstring != NULL && *docstring == AUTO_DOCSTRING)
++docstring;
((PyTypeObject *)o)->tp_doc = docstring;
addClassSlots((sipWrapperType *)o, (sipClassTypeDef *)currentType);
}
currentType = NULL;
}
return o;
}
/*
* The metatype init slot.
*/
static int sipWrapperType_init(sipWrapperType *self, PyObject *args,
PyObject *kwds)
{
/* Call the standard super-metatype init. */
if (PyType_Type.tp_init((PyObject *)self, args, kwds) < 0)
return -1;
/*
* If we don't yet have any extra type specific information (because we are
* a programmer defined sub-class) then get it from the (first) super-type.
*/
if (self->type == NULL)
{
PyTypeObject *base = ((PyTypeObject *)self)->tp_base;
/*
* We allow the class to use this as a meta-type without being derived
* from a class that uses it. This allows mixin classes that need
* their own meta-type to work so long as their meta-type is derived
* from this meta-type. This condition is indicated by the pointer to
* the generated type structure being NULL.
*/
if (base != NULL && PyObject_TypeCheck((PyObject *)base, (PyTypeObject *)&sipWrapperType_Type))
self->type = ((sipWrapperType *)base)->type;
}
else
{
/*
* We must be a generated type so remember the type object in the
* generated type structure.
*/
assert(self->type->u.td_py_type == NULL);
self->type->u.td_py_type = (PyTypeObject *)self;
}
return 0;
}
/*
* The metatype getattro slot.
*/
static PyObject *sipWrapperType_getattro(PyObject *self, PyObject *name)
{
if (add_all_lazy_attrs(((sipWrapperType *)self)->type) < 0)
return NULL;
return PyType_Type.tp_getattro(self, name);
}
/*
* The metatype setattro slot.
*/
static int sipWrapperType_setattro(PyObject *self, PyObject *name,
PyObject *value)
{
if (add_all_lazy_attrs(((sipWrapperType *)self)->type) < 0)
return -1;
return PyType_Type.tp_setattro(self, name, value);
}
/*
* The instance new slot.
*/
static PyObject *sipSimpleWrapper_new(sipWrapperType *wt, PyObject *args,
PyObject *kwds)
{
static PyObject *noargs = NULL;
sipTypeDef *td = wt->type;
sipContainerDef *cod;
/* Check the base types are not being used directly. */
if (wt == &sipSimpleWrapper_Type || wt == &sipWrapper_Type)
{
PyErr_Format(PyExc_TypeError,
"the %s type cannot be instantiated or sub-classed",
((PyTypeObject *)wt)->tp_name);
return NULL;
}
if (sipTypeIsMapped(td))
cod = &((sipMappedTypeDef *)td)->mtd_container;
else
cod = &((sipClassTypeDef *)td)->ctd_container;
/* We need an empty tuple for an empty argument list. */
if (noargs == NULL)
{
noargs = PyTuple_New(0);
if (noargs == NULL)
return NULL;
}
/* See if it is a mapped type. */
if (sipTypeIsMapped(td))
{
PyErr_Format(PyExc_TypeError,
"%s.%s represents a mapped type and cannot be instantiated",
sipNameOfModule(td->td_module),
sipPyNameOfContainer(cod, td));
return NULL;
}
/* See if it is a namespace. */
if (sipTypeIsNamespace(td))
{
PyErr_Format(PyExc_TypeError,
"%s.%s represents a C++ namespace and cannot be instantiated",
sipNameOfModule(td->td_module),
sipPyNameOfContainer(cod, td));
return NULL;
}
/*
* See if the object is being created explicitly rather than being wrapped.
*/
if (sipGetPending(NULL, NULL) == NULL)
{
/*
* See if it cannot be instantiated or sub-classed from Python, eg.
* it's an opaque class. Some restrictions might be overcome with
* better SIP-TQt support.
*/
if (((sipClassTypeDef *)td)->ctd_init == NULL)
{
PyErr_Format(PyExc_TypeError,
"%s.%s cannot be instantiated or sub-classed",
sipNameOfModule(td->td_module),
sipPyNameOfContainer(cod, td));
return NULL;
}
/* See if it is an abstract type. */
if (sipTypeIsAbstract(td) && sipIsExactWrappedType(wt))
{
PyErr_Format(PyExc_TypeError,
"%s.%s represents a C++ abstract class and cannot be instantiated",
sipNameOfModule(td->td_module),
sipPyNameOfContainer(cod, td));
return NULL;
}
}
/* Call the standard super-type new. */
return PyBaseObject_Type.tp_new((PyTypeObject *)wt, noargs, NULL);
}
/*
* The instance init slot.
*/
static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args,
PyObject *kwds)
{
void *sipNew;
int sipFlags;
sipWrapper *owner;
sipWrapperType *wt = (sipWrapperType *)Py_TYPE(self);
sipTypeDef *td = wt->type;
sipClassTypeDef *ctd = (sipClassTypeDef *)td;
PyObject *unused, **unused_p;
static int got_kw_handler = FALSE;
static int (*kw_handler)(PyObject *, void *, PyObject *);
/*
* Get any keyword handler if necessary. In SIP-TQt v5 this will be
* generalised and not PyTQt specific.
*/
if (!got_kw_handler)
{
kw_handler = sip_api_import_symbol("pytqt_kw_handler");
got_kw_handler = TRUE;
}
/*
* We are interested in unused keyword arguments if we are creating a
* TQObject and we have a handler.
*/
unused_p = (kw_handler != NULL && isTQObject((PyObject *)self)) ? &unused : NULL;
unused = NULL;
/* Check there is no existing C++ instance waiting to be wrapped. */
if ((sipNew = sipGetPending(&owner, &sipFlags)) == NULL)
{
PyObject *parseErr = NULL;
/* Call the C++ ctor. */
owner = NULL;
sipNew = ctd->ctd_init(self, args, kwds, unused_p, (PyObject **)&owner,
&parseErr);
if (sipNew != NULL)
{
sipFlags = SIP_DERIVED_CLASS;
}
else if (parseErr == NULL)
{
/*
* The C++ ctor must have raised an exception which has been
* translated to a Python exception.
*/
return -1;
}
else
{
sipInitExtenderDef *ie = wt->iextend;
assert(parseErr != NULL);
/*
* If we have not found an appropriate overload then try any
* extenders.
*/
while (PyList_Check(parseErr) && ie != NULL)
{
sipNew = ie->ie_extender(self, args, kwds, unused_p,
(PyObject **)&owner, &parseErr);
if (sipNew != NULL)
break;
ie = ie->ie_next;
}
if (sipNew == NULL)
{
const char *docstring = ctd->ctd_docstring;
/*
* Use the docstring for errors if it was automatically
* generated.
*/
if (docstring != NULL)
{
if (*docstring == AUTO_DOCSTRING)
++docstring;
else
docstring = NULL;
}
sip_api_no_function(parseErr,
sipPyNameOfContainer(&ctd->ctd_container, td),
docstring);
return -1;
}
sipFlags = 0;
}
if (owner == NULL)
sipFlags |= SIP_PY_OWNED;
else if ((PyObject *)owner == Py_None)
{
/* This is the hack that means that C++ owns the new instance. */
sipFlags |= SIP_CPP_HAS_REF;
Py_INCREF(self);
owner = NULL;
}
}
/*
* If there is an owner then we assume that the wrapper supports the
* concept.
*/
if (owner != NULL)
{
assert(PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type));
addToParent((sipWrapper *)self, (sipWrapper *)owner);
}
self->u.cppPtr = sipNew;
self->flags = sipFlags | SIP_CREATED;
if (!sipNotInMap(self))
sipOMAddObject(&cppPyMap, self);
/* If we have unused keyword arguments then we know how to handle them. */
if (unused != NULL)
{
int rc;
rc = kw_handler((PyObject *)self, sipNew, unused);
Py_DECREF(unused);
if (rc < 0)
return -1;
}
return 0;
}
/*
* The instance traverse slot.
*/
static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit,
void *arg)
{
int vret;
void *ptr;
const sipClassTypeDef *ctd;
/* Call the nearest handwritten traverse code in the class hierachy. */
if ((ptr = getPtrTypeDef(self, &ctd)) != NULL)
{
const sipClassTypeDef *sup_ctd = ctd;
if (ctd->ctd_traverse == NULL)
{
sipEncodedTypeDef *sup;
if ((sup = ctd->ctd_supers) != NULL)
do
sup_ctd = (sipClassTypeDef *)getGeneratedType(sup, ctd->ctd_base.td_module);
while (sup_ctd->ctd_traverse == NULL && !sup++->sc_flag);
}
if (sup_ctd->ctd_traverse != NULL)
if ((vret = sup_ctd->ctd_traverse(ptr, visit, arg)) != 0)
return vret;
}
if (self->dict != NULL)
if ((vret = visit(self->dict, arg)) != 0)
return vret;
if (self->extra_refs != NULL)
if ((vret = visit(self->extra_refs, arg)) != 0)
return vret;
if (self->user != NULL)
if ((vret = visit(self->user, arg)) != 0)
return vret;
return 0;
}
/*
* The instance clear slot.
*/
static int sipSimpleWrapper_clear(sipSimpleWrapper *self)
{
int vret = 0;
void *ptr;
const sipClassTypeDef *ctd;
PyObject *tmp;
/* Call the nearest handwritten clear code in the class hierachy. */
if ((ptr = getPtrTypeDef(self, &ctd)) != NULL)
{
const sipClassTypeDef *sup_ctd = ctd;
if (ctd->ctd_clear == NULL)
{
sipEncodedTypeDef *sup;
if ((sup = ctd->ctd_supers) != NULL)
do
sup_ctd = (sipClassTypeDef *)getGeneratedType(sup, ctd->ctd_base.td_module);
while (sup_ctd->ctd_clear == NULL && !sup++->sc_flag);
}
if (sup_ctd->ctd_clear != NULL)
vret = sup_ctd->ctd_clear(ptr);
}
/* Remove the instance dictionary. */
tmp = self->dict;
self->dict = NULL;
Py_XDECREF(tmp);
/* Remove any extra references dictionary. */
tmp = self->extra_refs;
self->extra_refs = NULL;
Py_XDECREF(tmp);
/* Remove any user object. */
tmp = self->user;
self->user = NULL;
Py_XDECREF(tmp);
return vret;
}
/*
* The instance get buffer slot for Python v3.
*/
static int sipSimpleWrapper_getbuffer(sipSimpleWrapper *self, Py_buffer *buf,
int flags)
{
void *ptr;
const sipClassTypeDef *ctd;
if ((ptr = getPtrTypeDef(self, &ctd)) == NULL)
return -1;
return ctd->ctd_getbuffer((PyObject *)self, ptr, buf, flags);
}
/*
* The instance release buffer slot for Python v3.
*/
static void sipSimpleWrapper_releasebuffer(sipSimpleWrapper *self,
Py_buffer *buf)
{
void *ptr;
const sipClassTypeDef *ctd;
if ((ptr = getPtrTypeDef(self, &ctd)) == NULL)
return -1;
return ctd->ctd_releasebuffer((PyObject *)self, ptr, buf);
}
/*
* The instance dealloc slot.
*/
static void sipSimpleWrapper_dealloc(sipSimpleWrapper *self)
{
forgetObject(self);
/*
* Now that the C++ object no longer exists we can tidy up the Python
* object. We used to do this first but that meant lambda slots were
* removed too soon (if they were connected to TQObject.destroyed()).
*/
sipSimpleWrapper_clear(self);
/* Call the standard super-type dealloc. */
PyBaseObject_Type.tp_dealloc((PyObject *)self);
}
/*
* The type call slot. Note that keyword arguments aren't supported.
*/
static PyObject *slot_call(PyObject *self,PyObject *args,PyObject *kw)
{
PyObject *(*f)(PyObject *,PyObject *);
f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, call_slot);
assert(f != NULL);
return f(self,args);
}
/*
* The sequence type item slot.
*/
static PyObject *slot_sq_item(PyObject *self, SIP_SSIZE_T n)
{
PyObject *(*f)(PyObject *,PyObject *);
PyObject *arg, *res;
arg = PyLong_FromSsize_t(n);
if (arg == NULL)
return NULL;
f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, getitem_slot);
assert(f != NULL);
res = f(self,arg);
Py_DECREF(arg);
return res;
}
/*
* The mapping type assign subscript slot.
*/
static int slot_mp_ass_subscript(PyObject *self, PyObject *key,
PyObject *value)
{
return objobjargprocSlot(self, key, value,
(value != NULL ? setitem_slot : delitem_slot));
}
/*
* The sequence type assign item slot.
*/
static int slot_sq_ass_item(PyObject *self, SIP_SSIZE_T i, PyObject *o)
{
return ssizeobjargprocSlot(self, i, o,
(o != NULL ? setitem_slot : delitem_slot));
}
/*
* The type rich compare slot.
*/
static PyObject *slot_richcompare(PyObject *self, PyObject *arg, int op)
{
PyObject *(*f)(PyObject *,PyObject *);
sipPySlotType st;
/* Convert the operation to a slot type. */
switch (op)
{
case Py_LT:
st = lt_slot;
break;
case Py_LE:
st = le_slot;
break;
case Py_EQ:
st = eq_slot;
break;
case Py_NE:
st = ne_slot;
break;
case Py_GT:
st = gt_slot;
break;
case Py_GE:
st = ge_slot;
break;
}
/* It might not exist if not all the above have been implemented. */
if ((f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self, st)) == NULL)
{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
return f(self, arg);
}
/*
* The instance getattro slot.
*/
static PyObject *sipSimpleWrapper_getattro(PyObject *self, PyObject *name)
{
if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(self))->type) < 0)
return NULL;
return PyObject_GenericGetAttr(self, name);
}
/*
* The instance setattro slot.
*/
static int sipSimpleWrapper_setattro(PyObject *self, PyObject *name,
PyObject *value)
{
if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(self))->type) < 0)
return -1;
return PyObject_GenericSetAttr(self, name, value);
}
/*
* The __dict__ getter.
*/
static PyObject *sipSimpleWrapper_get_dict(PyObject *self, void *closure)
{
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
/* Create the dictionary if needed. */
if (sw->dict == NULL)
{
sw->dict = PyDict_New();
if (sw->dict == NULL)
return NULL;
}
Py_INCREF(sw->dict);
return sw->dict;
}
/*
* The __dict__ setter.
*/
static int sipSimpleWrapper_set_dict(PyObject *self, PyObject *value,
void *closure)
{
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
/* Check that any new value really is a dictionary. */
if (value != NULL && !PyDict_Check(value))
{
PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, not a '%s'",
Py_TYPE(value)->tp_name);
return -1;
}
Py_XDECREF(sw->dict);
Py_XINCREF(value);
sw->dict = value;
return 0;
}
/*
* The table of getters and setters.
*/
static PyGetSetDef sipSimpleWrapper_getset[] = {
{(char *)"__dict__", sipSimpleWrapper_get_dict, sipSimpleWrapper_set_dict,
NULL, NULL},
{NULL, NULL, NULL, NULL, NULL}
};
/*
* The type data structure. Note that we pretend to be a mapping object and a
* sequence object at the same time. Python will choose one over another,
* depending on the context, but we implement as much as we can and don't make
* assumptions about which Python will choose.
*/
sipWrapperType sipSimpleWrapper_Type = {
#if !defined(STACKLESS)
{
#endif
{
PyVarObject_HEAD_INIT(&sipWrapperType_Type, 0)
"sip_tqt.simplewrapper", /* tp_name */
sizeof (sipSimpleWrapper), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)sipSimpleWrapper_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved (Python v3), tp_compare (Python v2) */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
sipSimpleWrapper_getattro, /* tp_getattro */
sipSimpleWrapper_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)sipSimpleWrapper_traverse, /* tp_traverse */
(inquiry)sipSimpleWrapper_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
sipSimpleWrapper_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(sipSimpleWrapper, dict), /* tp_dictoffset */
(initproc)sipSimpleWrapper_init, /* tp_init */
0, /* tp_alloc */
(newfunc)sipSimpleWrapper_new, /* tp_new */
0, /* tp_free */
},
#if !defined(STACKLESS)
},
#endif
0,
0
};
/*
* The wrapper clear slot.
*/
static int sipWrapper_clear(sipWrapper *self)
{
int vret;
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
vret = sipSimpleWrapper_clear(sw);
/* Remove any slots connected via a proxy. */
if (sipTQtSupport != NULL && sipPossibleProxy(sw))
{
void *tx = sip_api_get_address(sw);
if (tx != NULL)
{
sipSlot *slot;
void *context = NULL;
while ((slot = sipTQtSupport->tqt_find_sipslot(tx, &context)) != NULL)
{
sip_api_clear_any_slot_reference(slot);
if (context == NULL)
break;
}
}
}
/* Detach children (which will be owned by C/C++). */
while ((sw = (sipSimpleWrapper *)self->first_child) != NULL)
{
/*
* Although this object is being garbage collected it doesn't follow
* that it's children should be. So we make sure that the child stays
* alive and remember we have done so.
*/
Py_INCREF(sw);
sipSetCppHasRef(sw);
removeFromParent(self->first_child);
}
return vret;
}
/*
* The wrapper dealloc slot.
*/
static void sipWrapper_dealloc(sipWrapper *self)
{
/*
* We can't simply call the super-type because things have to be done in a
* certain order. The first thing is to get rid of the wrapped instance.
*/
forgetObject((sipSimpleWrapper *)self);
sipWrapper_clear(self);
/* Skip the super-type's dealloc. */
PyBaseObject_Type.tp_dealloc((PyObject *)self);
}
/*
* The wrapper traverse slot.
*/
static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg)
{
int vret;
sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
sipWrapper *w;
if ((vret = sipSimpleWrapper_traverse(sw, visit, arg)) != 0)
return vret;
/* This should be handwritten code in PyTQt. */
if (sipTQtSupport != NULL)
{
void *tx = sip_api_get_address(sw);
if (tx != NULL)
{
sipSlot *slot;
void *context = NULL;
while ((slot = sipTQtSupport->tqt_find_sipslot(tx, &context)) != NULL)
{
if ((vret = sip_api_visit_slot(slot, visit, arg)) != 0)
return vret;
if (context == NULL)
break;
}
}
}
for (w = self->first_child; w != NULL; w = w->sibling_next)
{
/*
* We don't traverse if the wrapper is a child of itself. We do this
* so that wrapped objects returned by virtual methods with the
* /Factory/ don't have those objects collected. This then means that
* plugins implemented in Python have a chance of working.
*/
if (w != self)
if ((vret = visit((PyObject *)w, arg)) != 0)
return vret;
}
return 0;
}
/*
* Add the slots for a class type and all its super-types.
*/
static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd)
{
/* Add the buffer interface. */
if (ctd->ctd_getbuffer != NULL)
wt->super.as_buffer.bf_getbuffer = (getbufferproc)sipSimpleWrapper_getbuffer;
if (ctd->ctd_releasebuffer != NULL)
wt->super.as_buffer.bf_releasebuffer = (releasebufferproc)sipSimpleWrapper_releasebuffer;
/* Add the slots for this type. */
if (ctd->ctd_pyslots != NULL)
addTypeSlots(&wt->super, ctd->ctd_pyslots);
}
/*
* Add the slot handler for each slot present in the type.
*/
static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots)
{
PyTypeObject *to;
PyNumberMethods *nb;
PySequenceMethods *sq;
PyMappingMethods *mp;
void *f;
to = (PyTypeObject *)heap_to;
nb = &heap_to->as_number;
sq = &heap_to->as_sequence;
mp = &heap_to->as_mapping;
while ((f = slots->psd_func) != NULL)
switch (slots++->psd_type)
{
case str_slot:
to->tp_str = (reprfunc)f;
break;
case int_slot:
if (nb != NULL)
nb->nb_int = (unaryfunc)f;
break;
case float_slot:
if (nb != NULL)
nb->nb_float = (unaryfunc)f;
break;
case len_slot:
if (mp != NULL)
mp->mp_length = (lenfunc)f;
if (sq != NULL)
sq->sq_length = (lenfunc)f;
break;
case contains_slot:
if (sq != NULL)
sq->sq_contains = (objobjproc)f;
break;
case add_slot:
if (nb != NULL)
nb->nb_add = (binaryfunc)f;
break;
case concat_slot:
if (sq != NULL)
sq->sq_concat = (binaryfunc)f;
break;
case sub_slot:
if (nb != NULL)
nb->nb_subtract = (binaryfunc)f;
break;
case mul_slot:
if (nb != NULL)
nb->nb_multiply = (binaryfunc)f;
break;
case repeat_slot:
if (sq != NULL)
sq->sq_repeat = (ssizeargfunc)f;
break;
case div_slot:
if (nb != NULL)
{
nb->nb_true_divide = (binaryfunc)f;
}
break;
case mod_slot:
if (nb != NULL)
nb->nb_remainder = (binaryfunc)f;
break;
case floordiv_slot:
if (nb != NULL)
nb->nb_floor_divide = (binaryfunc)f;
break;
case truediv_slot:
if (nb != NULL)
nb->nb_true_divide = (binaryfunc)f;
break;
case and_slot:
if (nb != NULL)
nb->nb_and = (binaryfunc)f;
break;
case or_slot:
if (nb != NULL)
nb->nb_or = (binaryfunc)f;
break;
case xor_slot:
if (nb != NULL)
nb->nb_xor = (binaryfunc)f;
break;
case lshift_slot:
if (nb != NULL)
nb->nb_lshift = (binaryfunc)f;
break;
case rshift_slot:
if (nb != NULL)
nb->nb_rshift = (binaryfunc)f;
break;
case iadd_slot:
if (nb != NULL)
nb->nb_inplace_add = (binaryfunc)f;
break;
case iconcat_slot:
if (sq != NULL)
sq->sq_inplace_concat = (binaryfunc)f;
break;
case isub_slot:
if (nb != NULL)
nb->nb_inplace_subtract = (binaryfunc)f;
break;
case imul_slot:
if (nb != NULL)
nb->nb_inplace_multiply = (binaryfunc)f;
break;
case irepeat_slot:
if (sq != NULL)
sq->sq_inplace_repeat = (ssizeargfunc)f;
break;
case idiv_slot:
if (nb != NULL)
{
nb->nb_inplace_true_divide = (binaryfunc)f;
}
break;
case imod_slot:
if (nb != NULL)
nb->nb_inplace_remainder = (binaryfunc)f;
break;
case ifloordiv_slot:
if (nb != NULL)
nb->nb_inplace_floor_divide = (binaryfunc)f;
break;
case itruediv_slot:
if (nb != NULL)
nb->nb_inplace_true_divide = (binaryfunc)f;
break;
case iand_slot:
if (nb != NULL)
nb->nb_inplace_and = (binaryfunc)f;
break;
case ior_slot:
if (nb != NULL)
nb->nb_inplace_or = (binaryfunc)f;
break;
case ixor_slot:
if (nb != NULL)
nb->nb_inplace_xor = (binaryfunc)f;
break;
case ilshift_slot:
if (nb != NULL)
nb->nb_inplace_lshift = (binaryfunc)f;
break;
case irshift_slot:
if (nb != NULL)
nb->nb_inplace_rshift = (binaryfunc)f;
break;
case invert_slot:
if (nb != NULL)
nb->nb_invert = (unaryfunc)f;
break;
case call_slot:
to->tp_call = slot_call;
break;
case getitem_slot:
if (mp != NULL)
mp->mp_subscript = (binaryfunc)f;
if (sq != NULL)
sq->sq_item = slot_sq_item;
break;
case setitem_slot:
case delitem_slot:
if (mp != NULL)
mp->mp_ass_subscript = slot_mp_ass_subscript;
if (sq != NULL)
sq->sq_ass_item = slot_sq_ass_item;
break;
case lt_slot:
case le_slot:
case eq_slot:
case ne_slot:
case gt_slot:
case ge_slot:
to->tp_richcompare = slot_richcompare;
break;
case bool_slot:
if (nb != NULL)
nb->nb_bool = (inquiry)f;
break;
case neg_slot:
if (nb != NULL)
nb->nb_negative = (unaryfunc)f;
break;
case repr_slot:
to->tp_repr = (reprfunc)f;
break;
case hash_slot:
to->tp_hash = (hashfunc)f;
break;
case pos_slot:
if (nb != NULL)
nb->nb_positive = (unaryfunc)f;
break;
case abs_slot:
if (nb != NULL)
nb->nb_absolute = (unaryfunc)f;
break;
case index_slot:
if (nb != NULL)
nb->nb_index = (unaryfunc)f;
break;
case iter_slot:
to->tp_iter = (getiterfunc)f;
break;
case next_slot:
to->tp_iternext = (iternextfunc)f;
break;
}
}
/*
* Remove the object from the map and call the C/C++ dtor if we own the
* instance.
*/
static void forgetObject(sipSimpleWrapper *sw)
{
const sipClassTypeDef *ctd;
/*
* This is needed because we release the GIL when calling a C++ dtor.
* Without it the cyclic garbage collector can be invoked from another
* thread resulting in a crash.
*/
PyObject_GC_UnTrack((PyObject *)sw);
if (getPtrTypeDef(sw, &ctd) != NULL)
{
/*
* Remove the object from the map before calling the class specific
* dealloc code. This code calls the C++ dtor and may result in
* further calls that pass the instance as an argument. If this is
* still in the map then it's reference count would be increased (to
* one) and bad things happen when it drops back to zero again. (An
* example is PyTQt events generated during the dtor call being passed
* to an event filter implemented in Python.) By removing it from the
* map first we ensure that a new Python object is created.
*/
sipOMRemoveObject(&cppPyMap, sw);
/* Call the C++ dtor if there is one. */
if (ctd->ctd_dealloc != NULL)
ctd->ctd_dealloc(sw);
}
}
/*
* If the given name is that of a typedef then the corresponding type is
* returned.
*/
static const char *sip_api_resolve_typedef(const char *name)
{
const sipExportedModuleDef *em;
/*
* Note that if the same name is defined as more than one type (which is
* possible if more than one completely independent modules are being
* used) then we might pick the wrong one.
*/
for (em = moduleList; em != NULL; em = em->em_next)
{
if (em->em_nrtypedefs > 0)
{
sipTypedefDef *tdd;
tdd = (sipTypedefDef *)bsearch(name, em->em_typedefs,
em->em_nrtypedefs, sizeof (sipTypedefDef),
compareTypedefName);
if (tdd != NULL)
return tdd->tdd_type_name;
}
}
return NULL;
}
/*
* The bsearch() helper function for searching a sorted typedef table.
*/
static int compareTypedefName(const void *key, const void *el)
{
return strcmp((const char *)key, ((const sipTypedefDef *)el)->tdd_name);
}
/*
* Add the given Python object to the given list. Return 0 if there was no
* error.
*/
static int addPyObjectToList(sipPyObject **head, PyObject *object)
{
sipPyObject *po;
if ((po = sip_api_malloc(sizeof (sipPyObject))) == NULL)
return -1;
po->object = object;
po->next = *head;
*head = po;
return 0;
}
/*
* Register a symbol with a name. A negative value is returned if the name was
* already registered.
*/
static int sip_api_export_symbol(const char *name, void *sym)
{
sipSymbol *ss;
if (sip_api_import_symbol(name) != NULL)
return -1;
if ((ss = sip_api_malloc(sizeof (sipSymbol))) == NULL)
return -1;
ss->name = name;
ss->symbol = sym;
ss->next = sipSymbolList;
sipSymbolList = ss;
return 0;
}
/*
* Return the symbol registered with the given name. NULL is returned if the
* name was not registered.
*/
static void *sip_api_import_symbol(const char *name)
{
sipSymbol *ss;
for (ss = sipSymbolList; ss != NULL; ss = ss->next)
if (strcmp(ss->name, name) == 0)
return ss->symbol;
return NULL;
}
/*
* Visit a slot connected to an object for the cyclic garbage collector. This
* is only called externally by PyTQt.
*/
static int sip_api_visit_slot(sipSlot *slot, visitproc visit, void *arg)
{
/* See if the slot has an extra reference. */
if (slot->weakSlot == Py_True && slot->pyobj != Py_None)
return visit(slot->pyobj, arg);
return 0;
}
/*
* Clear a slot if it has an extra reference to keep it alive. This is only
* called externally by PyTQt.
*/
static void sip_api_clear_any_slot_reference(sipSlot *slot)
{
if (slot->weakSlot == Py_True)
{
PyObject *xref = slot->pyobj;
/*
* Replace the slot with None. We don't use NULL as this has another
* meaning.
*/
Py_INCREF(Py_None);
slot->pyobj = Py_None;
Py_DECREF(xref);
}
}
/*
* Convert a Python object to a character and raise an exception if there was
* an error.
*/
static char sip_api_bytes_as_char(PyObject *obj)
{
char ch;
if (parseBytes_AsChar(obj, &ch) < 0)
{
PyErr_Format(PyExc_TypeError,
"bytes of length 1 expected not '%s'",
Py_TYPE(obj)->tp_name);
return '\0';
}
return ch;
}
/*
* Convert a Python object to a string and raise an exception if there was
* an error.
*/
static const char *sip_api_bytes_as_string(PyObject *obj)
{
const char *a;
if (parseBytes_AsString(obj, &a) < 0)
{
PyErr_Format(PyExc_TypeError,
"bytes expected not '%s'",
Py_TYPE(obj)->tp_name);
return NULL;
}
return a;
}
/*
* Convert a Python ASCII string object to a character and raise an exception
* if there was an error.
*/
static char sip_api_string_as_ascii_char(PyObject *obj)
{
char ch;
if (parseString_AsASCIIChar(obj, &ch) < 0)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
PyErr_Format(PyExc_TypeError,
"bytes or ASCII string of length 1 expected not '%s'",
Py_TYPE(obj)->tp_name);
return '\0';
}
return ch;
}
/*
* Parse an ASCII character and return it.
*/
static int parseString_AsASCIIChar(PyObject *obj, char *ap)
{
return parseString_AsEncodedChar(PyUnicode_AsASCIIString(obj), obj, ap);
}
/*
* Convert a Python Latin-1 string object to a character and raise an exception
* if there was an error.
*/
static char sip_api_string_as_latin1_char(PyObject *obj)
{
char ch;
if (parseString_AsLatin1Char(obj, &ch) < 0)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
PyErr_Format(PyExc_TypeError,
"bytes or Latin-1 string of length 1 expected not '%s'",
Py_TYPE(obj)->tp_name);
return '\0';
}
return ch;
}
/*
* Parse a Latin-1 character and return it.
*/
static int parseString_AsLatin1Char(PyObject *obj, char *ap)
{
return parseString_AsEncodedChar(PyUnicode_AsLatin1String(obj), obj, ap);
}
/*
* Convert a Python UTF-8 string object to a character and raise an exception
* if there was an error.
*/
static char sip_api_string_as_utf8_char(PyObject *obj)
{
char ch;
if (parseString_AsUTF8Char(obj, &ch) < 0)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
PyErr_Format(PyExc_TypeError,
"bytes or UTF-8 string of length 1 expected not '%s'",
Py_TYPE(obj)->tp_name);
return '\0';
}
return ch;
}
/*
* Parse a UTF-8 character and return it.
*/
static int parseString_AsUTF8Char(PyObject *obj, char *ap)
{
return parseString_AsEncodedChar(PyUnicode_AsUTF8String(obj), obj, ap);
}
/*
* Parse an encoded character and return it.
*/
static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap)
{
SIP_SSIZE_T size;
if (bytes == NULL)
{
PyErr_Clear();
return parseBytes_AsChar(obj, ap);
}
size = PyBytes_GET_SIZE(bytes);
if (size != 1)
{
Py_DECREF(bytes);
return -1;
}
*ap = *PyBytes_AS_STRING(bytes);
Py_DECREF(bytes);
return 0;
}
/*
* Convert a Python ASCII string object to a string and raise an exception if
* there was an error. The object is updated with the one that owns the
* string. Note that None is considered an error.
*/
static const char *sip_api_string_as_ascii_string(PyObject **obj)
{
PyObject *s = *obj;
const char *a;
if (s == Py_None || (*obj = parseString_AsASCIIString(s, &a)) == NULL)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(s))
PyErr_Format(PyExc_TypeError,
"bytes or ASCII string expected not '%s'",
Py_TYPE(s)->tp_name);
return NULL;
}
return a;
}
/*
* Parse an ASCII string and return it and a new reference to the object that
* owns the string.
*/
static PyObject *parseString_AsASCIIString(PyObject *obj, const char **ap)
{
return parseString_AsEncodedString(PyUnicode_AsASCIIString(obj), obj, ap);
}
/*
* Convert a Python Latin-1 string object to a string and raise an exception if
* there was an error. The object is updated with the one that owns the
* string. Note that None is considered an error.
*/
static const char *sip_api_string_as_latin1_string(PyObject **obj)
{
PyObject *s = *obj;
const char *a;
if (s == Py_None || (*obj = parseString_AsLatin1String(s, &a)) == NULL)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(s))
PyErr_Format(PyExc_TypeError,
"bytes or Latin-1 string expected not '%s'",
Py_TYPE(s)->tp_name);
return NULL;
}
return a;
}
/*
* Parse a Latin-1 string and return it and a new reference to the object that
* owns the string.
*/
static PyObject *parseString_AsLatin1String(PyObject *obj, const char **ap)
{
return parseString_AsEncodedString(PyUnicode_AsLatin1String(obj), obj, ap);
}
/*
* Convert a Python UTF-8 string object to a string and raise an exception if
* there was an error. The object is updated with the one that owns the
* string. Note that None is considered an error.
*/
static const char *sip_api_string_as_utf8_string(PyObject **obj)
{
PyObject *s = *obj;
const char *a;
if (s == Py_None || (*obj = parseString_AsUTF8String(s, &a)) == NULL)
{
/* Use the exception set if it was an encoding error. */
if (!PyUnicode_Check(s))
PyErr_Format(PyExc_TypeError,
"bytes or UTF-8 string expected not '%s'",
Py_TYPE(s)->tp_name);
return NULL;
}
return a;
}
/*
* Parse a UTF-8 string and return it and a new reference to the object that
* owns the string.
*/
static PyObject *parseString_AsUTF8String(PyObject *obj, const char **ap)
{
return parseString_AsEncodedString(PyUnicode_AsUTF8String(obj), obj, ap);
}
/*
* Parse an encoded string and return it and a new reference to the object that
* owns the string.
*/
static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj,
const char **ap)
{
if (bytes != NULL)
{
*ap = PyBytes_AS_STRING(bytes);
return bytes;
}
PyErr_Clear();
if (parseBytes_AsString(obj, ap) < 0)
return NULL;
Py_INCREF(obj);
return obj;
}
/*
* Parse a character array and return it's address and length.
*/
static int parseBytes_AsCharArray(PyObject *obj, const char **ap,
SIP_SSIZE_T *aszp)
{
if (obj == Py_None)
{
*ap = NULL;
*aszp = 0;
}
else if (PyBytes_Check(obj))
{
*ap = PyBytes_AS_STRING(obj);
*aszp = PyBytes_GET_SIZE(obj);
}
else if (PyObject_AsCharBuffer(obj, ap, aszp) < 0)
return -1;
return 0;
}
/*
* Parse a character and return it.
*/
static int parseBytes_AsChar(PyObject *obj, char *ap)
{
const char *chp;
SIP_SSIZE_T sz;
if (PyBytes_Check(obj))
{
chp = PyBytes_AS_STRING(obj);
sz = PyBytes_GET_SIZE(obj);
}
else if (PyObject_AsCharBuffer(obj, &chp, &sz) < 0)
return -1;
if (sz != 1)
return -1;
*ap = *chp;
return 0;
}
/*
* Parse a character string and return it.
*/
static int parseBytes_AsString(PyObject *obj, const char **ap)
{
SIP_SSIZE_T sz;
return parseBytes_AsCharArray(obj, ap, &sz);
}
#if defined(HAVE_WCHAR_H)
/*
* Convert a Python object to a wide character.
*/
static wchar_t sip_api_unicode_as_wchar(PyObject *obj)
{
wchar_t ch;
if (parseWChar(obj, &ch) < 0)
{
PyErr_Format(PyExc_ValueError,
"string"
" of length 1 expected, not %s", Py_TYPE(obj)->tp_name);
return L'\0';
}
return ch;
}
/*
* Convert a Python object to a wide character string on the heap.
*/
static wchar_t *sip_api_unicode_as_wstring(PyObject *obj)
{
wchar_t *p;
if (parseWCharString(obj, &p) < 0)
{
PyErr_Format(PyExc_ValueError,
"string expected, not %s", Py_TYPE(obj)->tp_name);
return NULL;
}
return p;
}
/*
* Parse a wide character array and return it's address and length.
*/
static int parseWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp)
{
if (obj == Py_None)
{
*ap = NULL;
*aszp = 0;
return 0;
}
if (PyUnicode_Check(obj))
return convertToWCharArray(obj, ap, aszp);
return -1;
}
/*
* Convert a Unicode object to a wide character array and return it's address
* and length.
*/
static int convertToWCharArray(PyObject *obj, wchar_t **ap, SIP_SSIZE_T *aszp)
{
SIP_SSIZE_T ulen;
wchar_t *wc;
ulen = PyUnicode_GET_LENGTH(obj);
if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL)
return -1;
ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen);
if (ulen < 0)
{
sip_api_free(wc);
return -1;
}
*ap = wc;
*aszp = ulen;
return 0;
}
/*
* Parse a wide character and return it.
*/
static int parseWChar(PyObject *obj, wchar_t *ap)
{
if (PyUnicode_Check(obj))
return convertToWChar(obj, ap);
return -1;
}
/*
* Convert a Unicode object to a wide character and return it.
*/
static int convertToWChar(PyObject *obj, wchar_t *ap)
{
if (PyUnicode_GET_LENGTH(obj) != 1)
return -1;
if (PyUnicode_AsWideChar((PyUnicodeObject *)obj, ap, 1) != 1)
return -1;
return 0;
}
/*
* Parse a wide character string and return a copy on the heap.
*/
static int parseWCharString(PyObject *obj, wchar_t **ap)
{
if (obj == Py_None)
{
*ap = NULL;
return 0;
}
if (PyUnicode_Check(obj))
return convertToWCharString(obj, ap);
return -1;
}
/*
* Convert a Unicode object to a wide character string and return a copy on
* the heap.
*/
static int convertToWCharString(PyObject *obj, wchar_t **ap)
{
SIP_SSIZE_T ulen;
wchar_t *wc;
ulen = PyUnicode_GET_LENGTH(obj);
if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL)
return -1;
ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen);
if (ulen < 0)
{
sip_api_free(wc);
return -1;
}
wc[ulen] = L'\0';
*ap = wc;
return 0;
}
#else
/*
* Convert a Python object to a wide character.
*/
static int sip_api_unicode_as_wchar(PyObject *obj)
{
raiseNoWChar();
return 0;
}
/*
* Convert a Python object to a wide character.
*/
static int *sip_api_unicode_as_wstring(PyObject *obj)
{
raiseNoWChar();
return NULL;
}
/*
* Report the need for absent wide character support.
*/
static void raiseNoWChar()
{
PyErr_SetString(PyExc_SystemError, "sip-tqt built without wchar_t support");
}
#endif
/*
* The enum type alloc slot.
*/
static PyObject *sipEnumType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems)
{
sipEnumTypeObject *py_type;
sipPySlotDef *psd;
assert(currentType != NULL);
/* Call the standard super-metatype alloc. */
if ((py_type = (sipEnumTypeObject *)PyType_Type.tp_alloc(self, nitems)) == NULL)
return NULL;
/*
* Set the links between the Python type object and the generated type
* structure. Strictly speaking this doesn't need to be done here.
*/
py_type->type = currentType;
currentType->u.td_py_type = (PyTypeObject *)py_type;
/*
* Initialise any slots. This must be done here, after the type is
* allocated but before PyType_Ready() is called.
*/
if ((psd = ((sipEnumTypeDef *)currentType)->etd_pyslots) != NULL)
addTypeSlots(&py_type->super, psd);
currentType = NULL;
return (PyObject *)py_type;
}