You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
10502 lines
268 KiB
10502 lines
268 KiB
/*
|
|
* SIP library code.
|
|
*
|
|
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com>
|
|
*
|
|
* 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 <Python.h>
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#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
|
|