/* * SIP library code. * * Copyright (c) 2010 Riverbank Computing Limited * * This file is part of SIP. * * This copy of SIP is licensed for use under the terms of the SIP License * Agreement. See the file LICENSE for more details. * * This copy of SIP 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 is supplied WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include "sip.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.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.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 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, /* * 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.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); 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); /* * The Python module initialisation function. */ #if PY_MAJOR_VERSION >= 3 #define SIP_MODULE_ENTRY PyInit_sip #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) #else #define SIP_MODULE_ENTRY initsip #define SIP_MODULE_TYPE void #define SIP_MODULE_DISCARD(m) #define SIP_FATAL(s) Py_FatalError(s) #define SIP_MODULE_RETURN(m) #endif #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} }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "sip", /* m_name */ NULL, /* m_doc */ -1, /* m_size */ methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; #endif 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: Failed to initialise sip.wrappertype type"); if (PyType_Ready((PyTypeObject *)&sipSimpleWrapper_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.simplewrapper type"); if (sip_api_register_py_type((PyTypeObject *)&sipSimpleWrapper_Type) < 0) SIP_FATAL("sip: Failed to register sip.simplewrapper type"); #if defined(STACKLESS) sipWrapper_Type.super.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; #elif PY_VERSION_HEX >= 0x02050000 sipWrapper_Type.super.ht_type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; #else sipWrapper_Type.super.type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type; #endif if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.wrapper type"); if (PyType_Ready(&sipMethodDescr_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.methoddescriptor type"); if (PyType_Ready(&sipVariableDescr_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.variabledescriptor type"); sipEnumType_Type.tp_base = &PyType_Type; if (PyType_Ready(&sipEnumType_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.enumtype type"); if (PyType_Ready(&sipVoidPtr_Type) < 0) SIP_FATAL("sip: Failed to initialise sip.voidptr type"); #if PY_MAJOR_VERSION >= 3 mod = PyModule_Create(&module_def); #else mod = Py_InitModule("sip", methods); #endif if (mod == NULL) SIP_FATAL("sip: Failed to intialise sip 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: Failed to get pickle helpers"); } /* Publish the SIP API. */ #if defined(SIP_USE_PYCAPSULE) obj = PyCapsule_New((void *)&sip_api, "sip._C_API", NULL); #else obj = PyCObject_FromVoidPtr((void *)&sip_api, NULL); #endif if (obj == NULL) { SIP_MODULE_DISCARD(mod); SIP_FATAL("sip: 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: Failed to add _C_API object to module dictionary"); } /* Add the SIP version number, but don't worry about errors. */ #if PY_MAJOR_VERSION >= 3 obj = PyLong_FromLong(SIP_VERSION); #else obj = PyInt_FromLong(SIP_VERSION); #endif if (obj != NULL) { PyDict_SetItemString(mod_dict, "SIP_VERSION", obj); Py_DECREF(obj); } #if PY_MAJOR_VERSION >= 3 obj = PyUnicode_FromString(SIP_VERSION_STR); #else obj = PyString_FromString(SIP_VERSION_STR); #endif if (obj != NULL) { PyDict_SetItemString(mod_dict, "SIP_VERSION_STR", obj); Py_DECREF(obj); } /* Add the type objects, but don't worry about errors. */ PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type); PyDict_SetItemString(mod_dict, "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); #if PY_VERSION_HEX >= 0x02050000 printf(" Reference count: %" PY_FORMAT_SIZE_T "d\n", Py_REFCNT(sw)); #else printf(" Reference count: %d\n", Py_REFCNT(sw)); #endif printf(" Address of wrapped object: %p\n", sipGetAddress(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.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) < 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 = (sipGetAddress(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_API_MAJOR_NR || api_minor > SIP_API_MINOR_NR) { #if SIP_API_MINOR_NR > 0 PyErr_Format(PyExc_RuntimeError, "the sip module implements API v%d.0 to v%d.%d but the %s module requires API v%d.%d", SIP_API_MAJOR_NR, SIP_API_MAJOR_NR, SIP_API_MINOR_NR, full_name, api_major, api_minor); #else PyErr_Format(PyExc_RuntimeError, "the sip module implements API v%d.0 but the %s module requires API v%d.%d", SIP_API_MAJOR_NR, full_name, api_major, api_minor); #endif return -1; } /* Import any required modules. */ if (client->em_imports != NULL) { sipImportedModuleDef *im = client->em_imports; while (im->im_name != NULL) { PyObject *mod; if ((mod = PyImport_ImportModule(im->im_name)) == NULL) return -1; for (em = moduleList; em != NULL; em = em->em_next) if (strcmp(sipNameOfModule(em), im->im_name) == 0) break; if (em == NULL) { PyErr_Format(PyExc_RuntimeError, "the %s module failed to register with the sip module", im->im_name); return -1; } /* 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 clients must have unique names. */ if (strcmp(sipNameOfModule(em), full_name) == 0) { PyErr_Format(PyExc_RuntimeError, "the sip module has already registered a module called %s", full_name); return -1; } /* Only one module can claim to wrap TQObject. */ if (em->em_qt_api != NULL && client->em_qt_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. */ #if PY_MAJOR_VERSION >= 3 client->em_nameobj = PyUnicode_FromString(full_name); #else client->em_nameobj = PyString_FromString(full_name); #endif if (client->em_nameobj == NULL) return -1; /* Add it to the list of client modules. */ client->em_next = moduleList; moduleList = client; return 0; } /* * Initialise the contents of a client module. By this time anything that * this depends on should have been initialised. A negative value is returned * and an exception raised if there was an error. */ static int sip_api_init_module(sipExportedModuleDef *client, PyObject *mod_dict) { sipExportedModuleDef *em; sipEnumMemberDef *emd; int i; /* Handle any API. */ if (sipInitAPI(client, mod_dict) < 0) return -1; /* Create the module's types. */ for (i = 0; i < client->em_nrtypes; ++i) { sipTypeDef *td = client->em_types[i]; /* Skip external classes. */ if (td == NULL) continue; /* Skip if already initialised. */ if (td->td_module != NULL) continue; /* If it is a stub then just set the module so we can get its name. */ if (sipTypeIsStub(td)) { td->td_module = client; continue; } if (sipTypeIsEnum(td)) { 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_qt_api != NULL) { sipTQtSupport = client->em_qt_api; sipTQObjectType = *sipTQtSupport->qt_qobject; } /* Append any initialiser extenders to the relevant classes. */ if (client->em_initextend != NULL) { sipInitExtenderDef *ie = client->em_initextend; while (ie->ie_extender != NULL) { sipTypeDef *td = getGeneratedType(&ie->ie_class, client); int enabled; if (ie->ie_api_range < 0) enabled = TRUE; else enabled = sipIsRangeEnabled(td->td_module, ie->ie_api_range); if (enabled) { sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td); ie->ie_next = wt->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_Malloc(nbytes)) == NULL) PyErr_NoMemory(); return mem; } /* * A wrapper around the Python memory de-allocater. */ void sip_api_free(void *mem) { PyMem_Free(mem); } /* * Extend a Python slot by looking in other modules to see if there is an * extender function that can handle the arguments. */ static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod, sipPySlotType st, 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,"sipBuildResult(): invalid format string \"%s\"",fmt); else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL) res = buildObject(res,fmt,va); va_end(va); if (res == NULL && isErr != NULL) *isErr = TRUE; return res; } /* * Get the values off the stack and put them into an object. */ static PyObject *buildObject(PyObject *obj, const char *fmt, va_list va) { char ch, termch; int i; /* * The format string has already been checked that it is properly formed if * it is enclosed in parenthesis. */ if (*fmt == '(') { termch = ')'; ++fmt; } else termch = '\0'; i = 0; while ((ch = *fmt++) != termch) { PyObject *el; switch (ch) { case 'g': { char *s; SIP_SSIZE_T l; s = va_arg(va, char *); l = va_arg(va, SIP_SSIZE_T); if (s != NULL) { el = SIPBytes_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 = SIPBytes_FromStringAndSize(&c, 1); } break; case 'a': { char c = va_arg(va, int); #if PY_MAJOR_VERSION >= 3 el = PyUnicode_FromStringAndSize(&c, 1); #else el = PyString_FromStringAndSize(&c, 1); #endif } 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': #if PY_MAJOR_VERSION >= 3 el = PyLong_FromLong(va_arg(va, int)); #else el = PyInt_FromLong(va_arg(va, int)); #endif 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 = SIPBytes_FromString(s); } else { Py_INCREF(Py_None); el = Py_None; } } break; case 'A': { char *s = va_arg(va, char *); if (s != NULL) #if PY_MAJOR_VERSION >= 3 el = PyUnicode_FromString(s); #else el = PyString_FromString(s); #endif 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, "sipParseResult(): 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 = SIPLong_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 = SIPLong_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 = SIPLong_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 = SIPLong_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 = SIPLong_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,"sipParseResult(): invalid format character '%c'",ch); rc = -1; } if (invalid) { sip_api_bad_catcher_result(method); rc = -1; break; } } } va_end(va); if (isErr != NULL && rc < 0) *isErr = TRUE; return rc; } /* * A thin wrapper around PyLong_AsUnsignedLong() that works around a bug in * Python versions prior to v2.4 where an integer (or a named enum) causes an * error. */ static unsigned long sip_api_long_as_unsigned_long(PyObject *o) { #if PY_VERSION_HEX < 0x02040000 if (o != NULL && !PyLong_Check(o) && PyInt_Check(o)) { long v = PyInt_AsLong(o); if (v < 0) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned long"); return (unsigned long)-1; } return v; } #endif return PyLong_AsUnsignedLong(o); } /* * Parse the arguments to a C/C++ function without any side effects. */ static int sip_api_parse_args(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) { #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromFormat("argument %d has unexpected type '%s'", arg_nr, Py_TYPE(arg)->tp_name); #else return PyString_FromFormat("argument %d has unexpected type '%s'", arg_nr, Py_TYPE(arg)->tp_name); #endif } /* * 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. */ #if defined(SIP_USE_PYCAPSULE) static void failure_dtor(PyObject *capsule) { sipParseFailure *failure = (sipParseFailure *)PyCapsule_GetPointer(capsule, NULL); Py_XDECREF(failure->detail_obj); sip_api_free(failure); } #else static void failure_dtor(void *ptr) { sipParseFailure *failure = (sipParseFailure *)ptr; Py_XDECREF(failure->detail_obj); sip_api_free(failure); } #endif /* * Add a parse failure to the current list of exceptions. */ static void add_failure(PyObject **parseErrp, sipParseFailure *failure) { sipParseFailure *failure_copy; PyObject *failure_obj; /* Create the list if necessary. */ if (*parseErrp == NULL && (*parseErrp = PyList_New(0)) == NULL) { failure->reason = Raised; return; } /* * Make a copy of the failure, convert it to a Python object and add it to * the list. We do it this way to make it as lightweight as possible. */ if ((failure_copy = sip_api_malloc(sizeof (sipParseFailure))) == NULL) { failure->reason = Raised; return; } *failure_copy = *failure; #if defined(SIP_USE_PYCAPSULE) failure_obj = PyCapsule_New(failure_copy, NULL, failure_dtor); #else failure_obj = PyCObject_FromVoidPtr(failure_copy, failure_dtor); #endif 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 PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(key)) #else if (!PyString_Check(key)) #endif { 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 PY_MAJOR_VERSION >= 3 if (PyUnicode_CompareWithASCIIString(key, name) == 0) #else if (strcmp(PyString_AS_STRING(key), name) == 0) #endif 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 PY_MAJOR_VERSION >= 3 if (!PyUnicode_Check(key)) #else if (!PyString_Check(key)) #endif { 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 PY_MAJOR_VERSION >= 3 if (PyUnicode_CompareWithASCIIString(key, name) == 0) #else if (strcmp(PyString_AS_STRING(key), name) == 0) #endif 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 (SIPBytes_Check(arg)) { char *s = SIPBytes_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 (SIPBytes_Check(arg)) { char *s = SIPBytes_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 (SIPBytes_Check(arg)) { char *s = SIPBytes_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 = SIPLong_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 = SIPLong_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 = SIPLong_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 PY_MAJOR_VERSION >= 3 if (PyLong_Check(arg)) { *(int *)p = PyLong_AS_LONG(arg); } #else if (PyInt_Check(arg)) { *(int *)p = PyInt_AS_LONG(arg); } #endif 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 = SIPLong_AsLong(arg); } break; } case 'E': { /* Named enum. */ int *p; va_arg(va, sipTypeDef *); p = va_arg(va, int *); if (arg != NULL) *p = SIPLong_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) { #if PY_VERSION_HEX >= 0x02040000 default_bases = PyTuple_Pack(1, (PyObject *)&sipWrapper_Type); #else default_bases = Py_BuildValue("(O)", &sipWrapper_Type); #endif 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. */ #if PY_MAJOR_VERSION >= 3 name = PyUnicode_FromString(sipPyNameOfContainer(cod, td)); #else name = PyString_FromString(sipPyNameOfContainer(cod, td)); #endif if (name == NULL) goto reldict; /* Create the type by calling the metatype. */ #if PY_VERSION_HEX >= 0x02040000 args = PyTuple_Pack(3, name, bases, typedict); #else args = Py_BuildValue("OOO", name, bases, typedict); #endif 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; #if PY_VERSION_HEX >= 0x02040000 bases = PyTuple_Pack(1, supertype); #else bases = Py_BuildValue("(O)", supertype); #endif } 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 PY_MAJOR_VERSION >= 3 if (PyUnicode_Compare(mname_obj, em->em_nameobj) == 0) #else if (strcmp(PyString_AS_STRING(mname_obj), sipNameOfModule(em)) == 0) #endif break; Py_DECREF(mod); if (em == NULL) { #if PY_MAJOR_VERSION >= 3 PyErr_Format(PyExc_SystemError, "unable to find to find module: %U", mname_obj); #else PyErr_Format(PyExc_SystemError, "unable to find to find module: %s", PyString_AS_STRING(mname_obj)); #endif } 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, #if PY_MAJOR_VERSION >= 3 "UsO!:_unpickle_type", #else "SsO!:_unpickle_type", #endif &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, #if PY_MAJOR_VERSION >= 3 "UsO:_unpickle_enum", #else "SsO:_unpickle_enum", #endif &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), #if PY_MAJOR_VERSION >= 3 (int)PyLong_AS_LONG(obj) #else (int)PyInt_AS_LONG(obj) #endif ); } /* * 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) { #if PY_MAJOR_VERSION >= 3 bases = PyTuple_Pack(1, (PyObject *)&PyLong_Type); #elif PY_VERSION_HEX >= 0x02040000 bases = PyTuple_Pack(1, (PyObject *)&PyInt_Type); #else bases = Py_BuildValue("(O)", &PyInt_Type); #endif if (bases == NULL) goto reterr; } /* Create an object corresponding to the type name. */ #if PY_MAJOR_VERSION >= 3 name = PyUnicode_FromString(sipPyNameOfEnum(etd)); #else name = PyString_FromString(sipPyNameOfEnum(etd)); #endif 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. */ #if PY_VERSION_HEX >= 0x02040000 args = PyTuple_Pack(3, name, bases, typedict); #else args = Py_BuildValue("OOO", name, bases, typedict); #endif 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) { #if PY_MAJOR_VERSION >= 3 *objp = PyUnicode_FromString(s); #else *objp = PyString_FromString(s); #endif 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))); #if PY_MAJOR_VERSION >= 3 return PyLong_Check(obj); #else return PyInt_Check(obj); #endif } /* * Create a Python object for an enum member. */ static PyObject *createEnumMember(sipTypeDef *td, sipEnumMemberDef *enm) { if (enm->em_enum < 0) #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(enm->em_val); #else return PyInt_FromLong(enm->em_val); #endif 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) { #if PY_MAJOR_VERSION >= 3 exc = PyUnicode_FromFormat("%U: %U", doc_obj, detail); #else exc = PyString_FromFormat("%s: %s", PyString_AS_STRING(doc_obj), PyString_AS_STRING(detail)); #endif Py_DECREF(doc_obj); } else { exc = NULL; } } else { #if PY_MAJOR_VERSION >= 3 exc = PyUnicode_FromFormat("%s%s%s(): %U", scope, sep, method, detail); #else exc = PyString_FromFormat("%s%s%s(): %s", scope, sep, method, PyString_AS_STRING(detail)); #endif } 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) { #if PY_MAJOR_VERSION >= 3 exc = PyUnicode_FromString(summary); #else exc = PyString_FromString(summary); #endif } else { #if PY_MAJOR_VERSION >= 3 exc = PyUnicode_FromFormat("%s%s%s(): %s", scope, sep, method, summary); #else exc = PyString_FromFormat("%s%s%s(): %s", scope, sep, method, summary); #endif } 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) { #if PY_MAJOR_VERSION >= 3 failure = PyUnicode_FromFormat("\n %U: %U", doc_obj, detail); #else failure = PyString_FromFormat("\n %s: %s", PyString_AS_STRING(doc_obj), PyString_AS_STRING(detail)); #endif Py_DECREF(doc_obj); } else { Py_XDECREF(exc); exc = NULL; break; } } else { #if PY_MAJOR_VERSION >= 3 failure = PyUnicode_FromFormat("\n overload %zd: %U", i + 1, detail); #elif PY_VERSION_HEX >= 0x02050000 failure = PyString_FromFormat("\n overload %zd: %s", i + 1, PyString_AS_STRING(detail)); #else failure = PyString_FromFormat("\n overload %d: %s", i + 1, PyString_AS_STRING(detail)); #endif } Py_DECREF(detail); #if PY_MAJOR_VERSION >= 3 PyUnicode_AppendAndDel(&exc, failure); #else PyString_ConcatAndDel(&exc, failure); #endif } 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; #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromStringAndSize(doc, size); #else return PyString_FromStringAndSize(doc, size); #endif } /* * Return a string/unicode object that describes the given failure. */ static PyObject *detail_FromFailure(PyObject *failure_obj) { sipParseFailure *failure; PyObject *detail; #if defined(SIP_USE_PYCAPSULE) failure = (sipParseFailure *)PyCapsule_GetPointer(failure_obj, NULL); #else failure = (sipParseFailure *)PyCObject_AsVoidPtr(failure_obj); #endif switch (failure->reason) { case Unbound: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromFormat( "first argument of unbound method must have type '%s'", failure->detail_str); #else detail = PyString_FromFormat( "first argument of unbound method must have type '%s'", failure->detail_str); #endif break; case TooFew: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromString("not enough arguments"); #else detail = PyString_FromString("not enough arguments"); #endif break; case TooMany: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromString("too many arguments"); #else detail = PyString_FromString("too many arguments"); #endif break; case KeywordNotString: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromFormat( "%S keyword argument name is not a string", failure->detail_obj); #else { PyObject *str = PyObject_Str(failure->detail_obj); if (str != NULL) { detail = PyString_FromFormat( "%s keyword argument name is not a string", PyString_AsString(str)); Py_DECREF(str); } else { detail = NULL; } } #endif break; case UnknownKeyword: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromFormat("'%U' is not a valid keyword argument", failure->detail_obj); #else detail = PyString_FromFormat("'%s' is not a valid keyword argument", PyString_AS_STRING(failure->detail_obj)); #endif break; case Duplicate: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromFormat( "'%U' has already been given as a positional argument", failure->detail_obj); #else detail = PyString_FromFormat( "'%s' has already been given as a positional argument", PyString_AS_STRING(failure->detail_obj)); #endif break; case WrongType: if (failure->arg_nr >= 0) { detail = bad_type_str(failure->arg_nr, failure->detail_obj); } else { #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromFormat( "keyword argument '%s' has unexpected type '%s'", failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name); #else detail = PyString_FromFormat( "keyword argument '%s' has unexpected type '%s'", failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name); #endif } break; case Exception: detail = failure->detail_obj; if (detail) { Py_INCREF(detail); break; } /* Drop through. */ default: #if PY_MAJOR_VERSION >= 3 detail = PyUnicode_FromString("unknown reason"); #else detail = PyString_FromString("unknown reason"); #endif } 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); #if PY_VERSION_HEX >= 0x02050000 return PyErr_WarnEx(PyExc_DeprecationWarning, buf, 1); #else return PyErr_Warn(PyExc_DeprecationWarning, buf); #endif } /* * 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, #if PY_VERSION_HEX >= 0x02050000 "attempt to assign sequence of size %zd to slice of size %zd", #else "attempt to assign sequence of size %d to slice of size %d", #endif seqlen, slicelen); } /* * Report a Python object that cannot be converted to a particular class. */ static void sip_api_bad_class(const char *classname) { PyErr_Format(PyExc_TypeError, "cannot convert Python object to an instance of %s", classname); } /* * Report a Python 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 sipBadCatcherResult()"); return; } mname = ((PyFunctionObject *)PyMethod_GET_FUNCTION(method))->func_name; #if PY_MAJOR_VERSION >= 3 PyErr_Format(PyExc_TypeError, "invalid result type from %s.%U()", Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname); #else PyErr_Format(PyExc_TypeError, "invalid result type from %s.%s()", Py_TYPE(PyMethod_GET_SELF(method))->tp_name, PyString_AsString(mname)); #endif } /* * 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 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", ×tampName) < 0) return -1; if (objectify("Signature", &signatureName) < 0) return -1; /* We use a dictionary to hold the license information. */ if ((ldict = PyDict_New()) == NULL) return -1; /* The license type is compulsory, the rest are optional. */ if (lc->lc_type == NULL) goto deldict; #if PY_MAJOR_VERSION >= 3 o = PyUnicode_FromString(lc->lc_type); #else o = PyString_FromString(lc->lc_type); #endif if (o == NULL) goto deldict; rc = PyDict_SetItem(ldict,typeName,o); Py_DECREF(o); if (rc < 0) goto deldict; if (lc->lc_licensee != NULL) { #if PY_MAJOR_VERSION >= 3 o = PyUnicode_FromString(lc->lc_licensee); #else o = PyString_FromString(lc->lc_licensee); #endif if (o == NULL) goto deldict; rc = PyDict_SetItem(ldict,licenseeName,o); Py_DECREF(o); if (rc < 0) goto deldict; } if (lc->lc_timestamp != NULL) { #if PY_MAJOR_VERSION >= 3 o = PyUnicode_FromString(lc->lc_timestamp); #else o = PyString_FromString(lc->lc_timestamp); #endif if (o == NULL) goto deldict; rc = PyDict_SetItem(ldict,timestampName,o); Py_DECREF(o); if (rc < 0) goto deldict; } if (lc->lc_signature != NULL) { #if PY_MAJOR_VERSION >= 3 o = PyUnicode_FromString(lc->lc_signature); #else o = PyString_FromString(lc->lc_signature); #endif 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': #if PY_MAJOR_VERSION >= 3 w = PyUnicode_FromStringAndSize(&ci->ci_val, 1); #else w = PyUnicode_DecodeUTF8(&ci->ci_val, 1, NULL); #endif break; default: w = SIPBytes_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': #if PY_MAJOR_VERSION >= 3 w = PyUnicode_FromString(si->si_val); #else w = PyUnicode_DecodeUTF8(si->si_val, strlen(si->si_val), NULL); #endif break; default: w = SIPBytes_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; #if PY_MAJOR_VERSION >= 3 w = PyLong_FromLong(ii->ii_val); #else w = PyInt_FromLong(ii->ii_val); #endif 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 #if PY_MAJOR_VERSION >= 3 mname_obj = PyUnicode_FromString(mname); #else mname_obj = PyString_FromString(mname); #endif 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); #if PY_MAJOR_VERSION >= 3 cls_dict = ((PyTypeObject *)cls)->tp_dict; #else // Allow for classic classes as mixins. if (PyClass_Check(cls)) cls_dict = ((PyClassObject *)cls)->cl_dict; else cls_dict = ((PyTypeObject *)cls)->tp_dict; #endif 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 { #if PY_MAJOR_VERSION >= 3 reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp), (PyObject *)sipSelf); #else reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp), (PyObject *)sipSelf, PyMethod_GET_CLASS(reimp)); #endif } break; } if (PyFunction_Check(reimp)) { #if PY_MAJOR_VERSION >= 3 reimp = PyMethod_New(reimp, (PyObject *)sipSelf); #else reimp = PyMethod_New(reimp, (PyObject *)sipSelf, cls); #endif 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 *sipGetAddress(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 PyTQt3 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 = sipGetAddress(sw); if (checkPointer(ptr) < 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) { if (ptr == NULL) { PyErr_SetString(PyExc_RuntimeError, "underlying C/C++ object has been deleted"); 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; } #if PY_MAJOR_VERSION >= 3 key_obj = PyLong_FromLong(key); #else key_obj = PyInt_FromLong(key); #endif 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); #if PY_MAJOR_VERSION < 3 pm->mclass = PyMethod_GET_CLASS(meth); #endif } /* * 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 { #if PY_VERSION_HEX >= 0x02040000 args = PyTuple_Pack(2, arg1, arg2); #else args = Py_BuildValue("(OO)", arg1, arg2); #endif 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) #if PY_MAJOR_VERSION >= 3 args = PyLong_FromSsize_t(arg1); #elif PY_VERSION_HEX >= 0x02050000 args = PyInt_FromSsize_t(arg1); #else args = PyInt_FromLong(arg1); #endif else #if PY_VERSION_HEX >= 0x02050000 args = Py_BuildValue("(nO)", arg1, arg2); #else args = Py_BuildValue("(iO)", arg1, arg2); #endif if (args == NULL) return -1; 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 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 v5 this will be * generalised and not PyTQt specific. */ if (!got_kw_handler) { kw_handler = sip_api_import_symbol("pyqt_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; 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; } #if PY_MAJOR_VERSION >= 3 /* * 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); } #endif #if PY_MAJOR_VERSION >= 3 /* * 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); } #endif #if PY_MAJOR_VERSION < 3 /* * The instance read buffer slot for Python v2. */ static SIP_SSIZE_T sipSimpleWrapper_getreadbuffer(sipSimpleWrapper *self, SIP_SSIZE_T segment, void **ptrptr) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return -1; return ctd->ctd_readbuffer((PyObject *)self, ptr, segment, ptrptr); } #endif #if PY_MAJOR_VERSION < 3 /* * The instance write buffer slot for Python v2. */ static SIP_SSIZE_T sipSimpleWrapper_getwritebuffer(sipSimpleWrapper *self, SIP_SSIZE_T segment, void **ptrptr) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return -1; return ctd->ctd_writebuffer((PyObject *)self, ptr, segment, ptrptr); } #endif #if PY_MAJOR_VERSION < 3 /* * The instance segment count slot for Python v2. */ static SIP_SSIZE_T sipSimpleWrapper_getsegcount(sipSimpleWrapper *self, SIP_SSIZE_T *lenp) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return 0; return ctd->ctd_segcount((PyObject *)self, ptr, lenp); } #endif #if PY_MAJOR_VERSION < 3 /* * The instance char buffer slot for Python v2. */ static SIP_SSIZE_T sipSimpleWrapper_getcharbuffer(sipSimpleWrapper *self, SIP_SSIZE_T segment, void **ptrptr) { void *ptr; const sipClassTypeDef *ctd; if ((ptr = getPtrTypeDef(self, &ctd)) == NULL) return -1; return ctd->ctd_charbuffer((PyObject *)self, ptr, segment, ptrptr); } #endif /* * 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; #if PY_MAJOR_VERSION >= 3 arg = PyLong_FromSsize_t(n); #elif PY_VERSION_HEX >= 0x02050000 arg = PyInt_FromSsize_t(n); #else arg = PyInt_FromLong(n); #endif 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.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 = sipGetAddress(sw); if (tx != NULL) { sipSlot *slot; void *context = NULL; while ((slot = sipTQtSupport->qt_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 = sipGetAddress(sw); if (tx != NULL) { sipSlot *slot; void *context = NULL; while ((slot = sipTQtSupport->qt_find_sipslot(tx, &context)) != NULL) { if ((vret = sip_api_visit_slot(slot, visit, arg)) != 0) return vret; if (context == NULL) break; } } } for (w = self->first_child; w != NULL; w = w->sibling_next) { /* * We don't traverse if the wrapper is a child of itself. We do this * so that wrapped objects returned by virtual methods with the * /Factory/ don't have those objects collected. This then means that * plugins implemented in Python have a chance of working. */ if (w != self) if ((vret = visit((PyObject *)w, arg)) != 0) return vret; } return 0; } /* * Add the slots for a class type and all its super-types. */ static void addClassSlots(sipWrapperType *wt, sipClassTypeDef *ctd) { /* Add the buffer interface. */ #if PY_MAJOR_VERSION >= 3 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; #else if (ctd->ctd_readbuffer != NULL) #if PY_VERSION_HEX >= 0x02050000 wt->super.as_buffer.bf_getreadbuffer = (readbufferproc)sipSimpleWrapper_getreadbuffer; #else wt->super.as_buffer.bf_getreadbuffer = (getreadbufferproc)sipSimpleWrapper_getreadbuffer; #endif if (ctd->ctd_writebuffer != NULL) #if PY_VERSION_HEX >= 0x02050000 wt->super.as_buffer.bf_getwritebuffer = (writebufferproc)sipSimpleWrapper_getwritebuffer; #else wt->super.as_buffer.bf_getwritebuffer = (getwritebufferproc)sipSimpleWrapper_getwritebuffer; #endif if (ctd->ctd_segcount != NULL) #if PY_VERSION_HEX >= 0x02050000 wt->super.as_buffer.bf_getsegcount = (segcountproc)sipSimpleWrapper_getsegcount; #else wt->super.as_buffer.bf_getsegcount = (getsegcountproc)sipSimpleWrapper_getsegcount; #endif if (ctd->ctd_charbuffer != NULL) #if PY_VERSION_HEX >= 0x02050000 wt->super.as_buffer.bf_getcharbuffer = (charbufferproc)sipSimpleWrapper_getcharbuffer; #else wt->super.as_buffer.bf_getcharbuffer = (getcharbufferproc)sipSimpleWrapper_getcharbuffer; #endif #endif /* 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; #if PY_MAJOR_VERSION < 3 case long_slot: if (nb != NULL) nb->nb_long = (unaryfunc)f; break; #endif case float_slot: if (nb != NULL) nb->nb_float = (unaryfunc)f; break; case len_slot: if (mp != NULL) #if PY_VERSION_HEX >= 0x02050000 mp->mp_length = (lenfunc)f; #else mp->mp_length = (inquiry)f; #endif if (sq != NULL) #if PY_VERSION_HEX >= 0x02050000 sq->sq_length = (lenfunc)f; #else sq->sq_length = (inquiry)f; #endif break; case contains_slot: if (sq != NULL) 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) #if PY_VERSION_HEX >= 0x02050000 sq->sq_repeat = (ssizeargfunc)f; #else sq->sq_repeat = (intargfunc)f; #endif break; case div_slot: if (nb != NULL) { nb->nb_true_divide = (binaryfunc)f; #if PY_MAJOR_VERSION < 3 nb->nb_divide = (binaryfunc)f; #endif } 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) #if PY_VERSION_HEX >= 0x02050000 sq->sq_inplace_repeat = (ssizeargfunc)f; #else sq->sq_inplace_repeat = (intargfunc)f; #endif break; case idiv_slot: if (nb != NULL) { nb->nb_inplace_true_divide = (binaryfunc)f; #if PY_MAJOR_VERSION < 3 nb->nb_inplace_divide = (binaryfunc)f; #endif } 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; #if PY_MAJOR_VERSION < 3 case cmp_slot: to->tp_compare = (cmpfunc)f; break; #endif case bool_slot: if (nb != NULL) #if PY_MAJOR_VERSION >= 3 nb->nb_bool = (inquiry)f; #else nb->nb_nonzero = (inquiry)f; #endif 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; #if PY_VERSION_HEX >= 0x02050000 case index_slot: if (nb != NULL) nb->nb_index = (unaryfunc)f; break; #endif 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 PyTQt3. */ 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 PyTQt3. */ 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, #if PY_MAJOR_VERSION >= 3 "bytes of length 1 expected not '%s'", #else "string of length 1 expected not '%s'", #endif 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, #if PY_MAJOR_VERSION >= 3 "bytes expected not '%s'", #else "string expected not '%s'", #endif 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_SIZE(obj) != 1) PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "bytes or ASCII string of length 1 expected not '%s'", #else "string or ASCII unicode of length 1 expected not '%s'", #endif 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_SIZE(obj) != 1) PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "bytes or Latin-1 string of length 1 expected not '%s'", #else "string or Latin-1 unicode of length 1 expected not '%s'", #endif 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_SIZE(obj) != 1) PyErr_Format(PyExc_TypeError, #if PY_MAJOR_VERSION >= 3 "bytes or UTF-8 string of length 1 expected not '%s'", #else "string or UTF-8 unicode of length 1 expected not '%s'", #endif 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 = SIPBytes_GET_SIZE(bytes); if (size != 1) { Py_DECREF(bytes); return -1; } *ap = *SIPBytes_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, #if PY_MAJOR_VERSION >= 3 "bytes or ASCII string expected not '%s'", #else "string or ASCII unicode expected not '%s'", #endif 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, #if PY_MAJOR_VERSION >= 3 "bytes or Latin-1 string expected not '%s'", #else "string or Latin-1 unicode expected not '%s'", #endif 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, #if PY_MAJOR_VERSION >= 3 "bytes or UTF-8 string expected not '%s'", #else "string or UTF-8 unicode expected not '%s'", #endif 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 = SIPBytes_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 (SIPBytes_Check(obj)) { *ap = SIPBytes_AS_STRING(obj); *aszp = SIPBytes_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 (SIPBytes_Check(obj)) { chp = SIPBytes_AS_STRING(obj); sz = SIPBytes_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, #if PY_MAJOR_VERSION >= 3 "string" #else "unicode string" #endif " 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, #if PY_MAJOR_VERSION >= 3 "string" #else "unicode string" #endif " 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); #if PY_MAJOR_VERSION < 3 if (PyString_Check(obj)) { int rc; PyObject *uobj; if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; rc = convertToWCharArray(uobj, ap, aszp); Py_DECREF(uobj); return rc; } #endif 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_SIZE(obj); if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL) return -1; ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); if (ulen < 0) { sip_api_free(wc); return -1; } *ap = wc; *aszp = 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); #if PY_MAJOR_VERSION < 3 if (PyString_Check(obj)) { int rc; PyObject *uobj; if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; rc = convertToWChar(uobj, ap); Py_DECREF(uobj); return rc; } #endif return -1; } /* * Convert a Unicode object to a wide character and return it. */ static int convertToWChar(PyObject *obj, wchar_t *ap) { if (PyUnicode_GET_SIZE(obj) != 1) return -1; if (PyUnicode_AsWideChar((PyUnicodeObject *)obj, ap, 1) != 1) return -1; return 0; } /* * Parse a wide character string and return 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); #if PY_MAJOR_VERSION < 3 if (PyString_Check(obj)) { int rc; PyObject *uobj; if ((uobj = PyUnicode_FromObject(obj)) == NULL) return -1; rc = convertToWCharString(uobj, ap); Py_DECREF(uobj); return rc; } #endif 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_SIZE(obj); if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL) return -1; ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen); if (ulen < 0) { sip_api_free(wc); return -1; } wc[ulen] = L'\0'; *ap = wc; return 0; } #else /* * Convert a Python object to a wide character. */ static int sip_api_unicode_as_wchar(PyObject *obj) { raiseNoWChar(); return 0; } /* * Convert a Python object to a wide character. */ static int *sip_api_unicode_as_wstring(PyObject *obj) { raiseNoWChar(); return NULL; } /* * Report the need for absent wide character support. */ static void raiseNoWChar() { PyErr_SetString(PyExc_SystemError, "sip built without wchar_t support"); } #endif /* * The enum type alloc slot. */ static PyObject *sipEnumType_alloc(PyTypeObject *self, 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; }