text: /*
   * SIP library code.
   *
   * Copyright (c) 2020 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 <datetime.h>
  #include <frameobject.h>
  
  #include <assert.h>
  #include <stdio.h>
  #include <stdarg.h>
  #include <stddef.h>
  #include <string.h>
  
  #include "sip.h"
  #include "sipint.h"
  #include "array.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, Py_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_as_async (Python v3.5), 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 */
      0,                      /* tp_is_gc */
      0,                      /* tp_bases */
      0,                      /* tp_mro */
      0,                      /* tp_cache */
      0,                      /* tp_subclasses */
      0,                      /* tp_weaklist */
      0,                      /* tp_del */
      0,                      /* tp_version_tag */
      0,                      /* tp_finalize */
  #if PY_VERSION_HEX >= 0x03080000
      0,                      /* tp_vectorcall */
  #endif
  };
  
  
  /*
   * 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_as_async (Python v3.5), 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 */
              0,              /* tp_is_gc */
              0,              /* tp_bases */
              0,              /* tp_mro */
              0,              /* tp_cache */
              0,              /* tp_subclasses */
              0,              /* tp_weaklist */
              0,              /* tp_del */
              0,              /* tp_version_tag */
              0,              /* tp_finalize */
  #if PY_VERSION_HEX >= 0x03080000
              0,              /* tp_vectorcall */
  #endif
          },
          {
              0,              /* am_await */
              0,              /* am_aiter */
              0,              /* am_anext */
          },
          {
              0,              /* nb_add */
              0,              /* nb_subtract */
              0,              /* nb_multiply */
              0,              /* nb_remainder */
              0,              /* nb_divmod */
              0,              /* nb_power */
              0,              /* nb_negative */
              0,              /* nb_positive */
              0,              /* nb_absolute */
              0,              /* nb_bool */
              0,              /* nb_invert */
              0,              /* nb_lshift */
              0,              /* nb_rshift */
              0,              /* nb_and */
              0,              /* nb_xor */
              0,              /* nb_or */
              0,              /* nb_int */
              0,              /* nb_reserved */
              0,              /* nb_float */
              0,              /* nb_inplace_add */
              0,              /* nb_inplace_subtract */
              0,              /* nb_inplace_multiply */
              0,              /* nb_inplace_remainder */
              0,              /* nb_inplace_power */
              0,              /* nb_inplace_lshift */
              0,              /* nb_inplace_rshift */
              0,              /* nb_inplace_and */
              0,              /* nb_inplace_xor */
              0,              /* nb_inplace_or */
              0,              /* nb_floor_divide */
              0,              /* nb_true_divide */
              0,              /* nb_inplace_floor_divide */
              0,              /* nb_inplace_true_divide */
              0,              /* nb_index */
              0,              /* nb_matrix_multiply */
              0,              /* nb_inplace_matrix_multiply */
          },
          {
              0,              /* mp_length */
              0,              /* mp_subscript */
              0,              /* mp_ass_subscript */
          },
          {
              0,              /* sq_length */
              0,              /* sq_concat */
              0,              /* sq_repeat */
              0,              /* sq_item */
              0,              /* was_sq_slice */
              0,              /* sq_ass_item */
              0,              /* was_sq_ass_slice */
              0,              /* sq_contains */
              0,              /* sq_inplace_concat */
              0,              /* sq_inplace_repeat */
          },
          {
              0,              /* bf_getbuffer */
              0,              /* bf_releasebuffer */
          },
          0,                  /* ht_name */
          0,                  /* ht_slots */
          0,                  /* ht_qualname */
          0,                  /* ht_cached_keys */
  #if !defined(STACKLESS)
      },
  #endif
      0,                      /* wt_user_type */
      0,                      /* wt_dict_complete */
      0,                      /* wt_unused */
      0,                      /* wt_td */
      0,                      /* wt_iextend */
      0,                      /* wt_new_user_type_handler */
      0,                      /* wt_user_data */
  };
  
  
  static void sip_api_bad_catcher_result(PyObject *method);
  static void sip_api_bad_length_for_slice(Py_ssize_t seqlen,
          Py_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 void sip_api_call_procedure_method(sip_gilstate_t gil_state,
          sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self,
          PyObject *method, const char *fmt, ...);
  static Py_ssize_t sip_api_convert_from_sequence_index(Py_ssize_t idx,
          Py_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 int sip_api_can_convert_to_enum(PyObject *pyObj, const sipTypeDef *td);
  static int sip_api_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 PyObject *sip_api_convert_from_new_pytype(void *cpp,
          PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp,
          const char *fmt, ...);
  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_ex(sip_gilstate_t gil_state,
          sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self,
          PyObject *method, PyObject *res, const char *fmt, ...);
  static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res,
          const char *fmt, ...);
  static void sip_api_call_error_handler(sipVirtErrorHandlerFunc error_handler,
          sipSimpleWrapper *py_self, sip_gilstate_t gil_state);
  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 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_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 PyObject *sip_api_get_reference(PyObject *self, int key);
  static int sip_api_is_owned_by_python(sipSimpleWrapper *sw);
  static int sip_api_is_derived_class(sipSimpleWrapper *sw);
  static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp);
  static void sip_api_set_destroy_on_exit(int value);
  static int sip_api_enable_autoconversion(const sipTypeDef *td, int enable);
  static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds,
          const sipClassTypeDef *ctd);
  static void *sip_api_get_mixin_address(sipSimpleWrapper *w,
          const sipTypeDef *td);
  static int sip_api_register_proxy_resolver(const sipTypeDef *td,
          sipProxyResolverFunc resolver);
  static PyInterpreterState *sip_api_get_interpreter(void);
  static sipNewUserTypeFunc sip_api_set_new_user_type_handler(
          const sipTypeDef *td, sipNewUserTypeFunc handler);
  static void sip_api_set_type_user_data(sipWrapperType *wt, void *data);
  static void *sip_api_get_type_user_data(const sipWrapperType *wt);
  static PyObject *sip_api_py_type_dict(const PyTypeObject *py_type);
  static const char *sip_api_py_type_name(const PyTypeObject *py_type);
  static int sip_api_get_method(PyObject *obj, sipMethodDef *method);
  static PyObject *sip_api_from_method(const sipMethodDef *method);
  static int sip_api_get_c_function(PyObject *obj, sipCFunctionDef *c_function);
  static int sip_api_get_date(PyObject *obj, sipDateDef *date);
  static PyObject *sip_api_from_date(const sipDateDef *date);
  static int sip_api_get_datetime(PyObject *obj, sipDateDef *date,
          sipTimeDef *time);
  static PyObject *sip_api_from_datetime(const sipDateDef *date,
          const sipTimeDef *time);
  static int sip_api_get_time(PyObject *obj, sipTimeDef *time);
  static PyObject *sip_api_from_time(const sipTimeDef *time);
  static int sip_api_is_user_type(const sipWrapperType *wt);
  static struct _frame *sip_api_get_frame(int);
  static int sip_api_check_plugin_for_type(const sipTypeDef *td,
          const char *name);
  static PyObject *sip_api_unicode_new(Py_ssize_t len, unsigned maxchar,
          int *kind, void **data);
  static void sip_api_unicode_write(int kind, void *data, int index,
          unsigned value);
  static void *sip_api_unicode_data(PyObject *obj, int *char_size,
          Py_ssize_t *len);
  static int sip_api_get_buffer_info(PyObject *obj, sipBufferInfoDef *bi);
  static void sip_api_release_buffer_info(sipBufferInfoDef *bi);
  static PyObject *sip_api_get_user_object(const sipSimpleWrapper *sw);
  static void sip_api_set_user_object(sipSimpleWrapper *sw, PyObject *user);
  static int sip_api_enable_gc(int enable);
  static void sip_api_print_object(PyObject *o);
  static int sip_api_register_event_handler(sipEventType type,
          const sipTypeDef *td, void *handler);
  static void sip_api_instance_destroyed_ex(sipSimpleWrapper **sipSelfp);
  static void sip_api_visit_wrappers(sipWrapperVisitorFunc visitor,
          void *closure);
  static int sip_api_register_exit_notifier(PyMethodDef *md);
  
  
  /*
   * 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_call_procedure_method,
      sip_api_connect_rx,
      sip_api_convert_from_sequence_index,
      sip_api_can_convert_to_type,
      sip_api_convert_to_type,
      sip_api_force_convert_to_type,
      sip_api_can_convert_to_enum,
      sip_api_release_type,
      sip_api_convert_from_type,
      sip_api_convert_from_new_type,
      sip_api_convert_from_enum,
      sip_api_get_state,
      sip_api_disconnect_rx,
      sip_api_free,
      sip_api_get_pyobject,
      sip_api_malloc,
      sip_api_parse_result,
      sip_api_trace,
      sip_api_transfer_back,
      sip_api_transfer_to,
      sip_api_transfer_break,
      sip_api_long_as_unsigned_long,
      sip_api_convert_from_void_ptr,
      sip_api_convert_from_const_void_ptr,
      sip_api_convert_from_void_ptr_and_size,
      sip_api_convert_from_const_void_ptr_and_size,
      sip_api_convert_to_void_ptr,
      sip_api_export_symbol,
      sip_api_import_symbol,
      sip_api_find_type,
      sip_api_register_py_type,
      sip_api_type_from_py_type_object,
      sip_api_type_scope,
      sip_api_resolve_typedef,
      sip_api_register_attribute_getter,
      sip_api_is_api_enabled,
      sip_api_bad_callable_arg,
      sip_api_get_address,
      sip_api_set_destroy_on_exit,
      sip_api_enable_autoconversion,
      sip_api_get_mixin_address,
      sip_api_convert_from_new_pytype,
      sip_api_convert_to_typed_array,
      sip_api_convert_to_array,
      sip_api_register_proxy_resolver,
      sip_api_get_interpreter,
      sip_api_set_new_user_type_handler,
      sip_api_set_type_user_data,
      sip_api_get_type_user_data,
      sip_api_py_type_dict,
      sip_api_py_type_name,
      sip_api_get_method,
      sip_api_from_method,
      sip_api_get_c_function,
      sip_api_get_date,
      sip_api_from_date,
      sip_api_get_datetime,
      sip_api_from_datetime,
      sip_api_get_time,
      sip_api_from_time,
      sip_api_is_user_type,
      sip_api_get_frame,
      sip_api_check_plugin_for_type,
      sip_api_unicode_new,
      sip_api_unicode_write,
      sip_api_unicode_data,
      sip_api_get_buffer_info,
      sip_api_release_buffer_info,
      sip_api_get_user_object,
      sip_api_set_user_object,
      /*
       * The following are not part of the public API.
       */
      sip_api_init_module,
      sip_api_parse_args,
      sip_api_parse_pair,
      /*
       * The following are part of the public API.
       */
      sip_api_instance_destroyed,
      /*
       * The following are not part of the public API.
       */
      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_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,
      sip_api_parse_result_ex,
      sip_api_call_error_handler,
      sip_api_init_mixin,
      sip_api_get_reference,
      /*
       * The following are part of the public API.
       */
      sip_api_is_owned_by_python,
      /*
       * The following are not part of the public API.
       */
      sip_api_is_derived_class,
      /*
       * The following may be used by Qt 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_invoke_slot_ex,
      sip_api_save_slot,
      sip_api_clear_any_slot_reference,
      sip_api_visit_slot,
      /*
       * 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 are part of the public API.
       */
      sip_api_enable_gc,
      sip_api_print_object,
      sip_api_register_event_handler,
      sip_api_convert_to_enum,
      sip_api_convert_to_bool,
      sip_api_enable_overflow_checking,
      sip_api_long_as_char,
      sip_api_long_as_signed_char,
      sip_api_long_as_unsigned_char,
      sip_api_long_as_short,
      sip_api_long_as_unsigned_short,
      sip_api_long_as_int,
      sip_api_long_as_unsigned_int,
      sip_api_long_as_long,
  #if defined(HAVE_LONG_LONG)
      sip_api_long_as_long_long,
      sip_api_long_as_unsigned_long_long,
  #else
      0,
      0,
  #endif
      /*
       * The following are not part of the public API.
       */
      sip_api_instance_destroyed_ex,
      /*
       * The following are part of the public API.
       */
      sip_api_convert_from_slice_object,
      sip_api_long_as_size_t,
      sip_api_visit_wrappers,
      sip_api_register_exit_notifier,
  };
  
  
  #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, Overflow
  } 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. */
      int overflow_arg_nr;            /* The overflowed positional argument. */
      const char *overflow_arg_name;  /* The overflowed 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;
  
  
  /*
   * An entry in the linked list of proxy resolvers.
   */
  typedef struct _sipProxyResolver {
      const sipTypeDef *td;           /* The type the resolver handles. */
      sipProxyResolverFunc resolver;  /* The resolver. */
      struct _sipProxyResolver *next; /* The next in the list. */
  } sipProxyResolver;
  
  
  /*
   * An entry in the linked list of event handlers.
   */
  typedef struct _sipEventHandler {
      const sipClassTypeDef *ctd;     /* The type the handler handles. */
      void *handler;                  /* The handler. */
      struct _sipEventHandler *next;  /* The next in the list. */
  } sipEventHandler;
  
  
  /*****************************************************************************
   * The structures to support a Python type to hold a named enum.
   *****************************************************************************/
  
  static PyObject *sipEnumType_alloc(PyTypeObject *self, Py_ssize_t nitems);
  static PyObject *sipEnumType_getattro(PyObject *self, PyObject *name);
  
  
  /*
   * 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_as_async (Python v3.5), 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 */
      sipEnumType_getattro,   /* 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 */
      0,                      /* tp_is_gc */
      0,                      /* tp_bases */
      0,                      /* tp_mro */
      0,                      /* tp_cache */
      0,                      /* tp_subclasses */
      0,                      /* tp_weaklist */
      0,                      /* tp_del */
      0,                      /* tp_version_tag */
      0,                      /* tp_finalize */
  #if PY_VERSION_HEX >= 0x03080000
      0,                      /* tp_vectorcall */
  #endif
  };
  
  
  /*
   * Remove these in SIP v5.
   */
  sipQtAPI *sipQtSupport = NULL;
  sipTypeDef *sipQObjectType;
  
  static int got_kw_handler = FALSE;
  static int (*kw_handler)(PyObject *, void *, PyObject *);
  
  
  /*
   * 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 **unused_backdoor = NULL;   /* For passing dict of unused arguments. */
  
  static PyObject *init_name = NULL;      /* '__init__'. */
  static PyObject *empty_tuple;           /* The empty tuple. */
  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 sipProxyResolver *proxyResolvers = NULL; /* The list of proxy resolvers. */
  static sipPyObject *sipRegisteredPyTypes = NULL;    /* Registered Python types. */
  static sipPyObject *sipDisabledAutoconversions = NULL;  /* Python types whose auto-conversion is disabled. */
  static PyInterpreterState *sipInterpreter = NULL;   /* The interpreter. */
  static int destroy_on_exit = TRUE;      /* Destroy owned objects on exit. */
  static sipEventHandler *event_handlers[sipEventNrEvents];   /* The event handler lists. */
  
  static void addClassSlots(sipWrapperType *wt, const sipClassTypeDef *ctd);
  static void addTypeSlots(PyHeapTypeObject *heap_to, sipPySlotDef *slots);
  static void *findSlot(PyObject *self, sipPySlotType st);
  static void *findSlotInClass(const sipClassTypeDef *psd, sipPySlotType st);
  static void *findSlotInSlotList(sipPySlotDef *psd, sipPySlotType st);
  static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2,
          sipPySlotType st);
  static int ssizeobjargprocSlot(PyObject *self, Py_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 int parseResult(PyObject *method, PyObject *res,
          sipSimpleWrapper *py_self, const char *fmt, va_list va);
  static PyObject *signature_FromDocstring(const char *doc, Py_ssize_t line);
  static PyObject *detail_FromFailure(PyObject *failure_obj);
  static int isQObject(PyObject *obj);
  static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td);
  static int convertFromSequence(PyObject *seq, const sipTypeDef *td,
          void **array, Py_ssize_t *nr_elem);
  static PyObject *convertToSequence(void *array, Py_ssize_t nr_elem,
          const sipTypeDef *td);
  static int getSelfFromArgs(sipTypeDef *td, PyObject *args, int argnr,
          sipSimpleWrapper **selfp);
  static int compareTypedefName(const void *key, const void *el);
  static int checkPointer(void *ptr, sipSimpleWrapper *sw);
  static void *cast_cpp_ptr(void *ptr, PyTypeObject *src_type,
          const sipTypeDef *dst_type);
  static void finalise(void);
  static PyObject *getDefaultBase(void);
  static PyObject *getDefaultSimpleBase(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,
          PyObject *type_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 *args);
  static PyObject *unpickle_type(PyObject *obj, PyObject *args);
  static PyObject *pickle_enum(PyObject *obj, PyObject *args);
  static PyObject *unpickle_enum(PyObject *obj, PyObject *args);
  static int setReduce(PyTypeObject *type, PyMethodDef *pickler);
  static int createEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd,
          int enum_nr, PyObject *mod_dict);
  static PyObject *createUnscopedEnum(sipExportedModuleDef *client,
          sipEnumTypeDef *etd, PyObject *name);
  static PyObject *createScopedEnum(sipExportedModuleDef *client,
          sipEnumTypeDef *etd, int enum_nr, PyObject *name);
  static PyObject *createTypeDict(sipExportedModuleDef *em);
  static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc,
          sipExportedModuleDef *em);
  static const sipTypeDef *convertSubClass(const sipTypeDef *td, void **cppPtr);
  static int convertPass(const sipTypeDef **tdp, 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 *assign(PyObject *self, PyObject *args);
  static PyObject *cast(PyObject *self, PyObject *args);
  static PyObject *callDtor(PyObject *self, PyObject *args);
  static PyObject *dumpWrapper(PyObject *self, PyObject *arg);
  static PyObject *enableAutoconversion(PyObject *self, PyObject *args);
  static PyObject *isDeleted(PyObject *self, PyObject *args);
  static PyObject *isPyCreated(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 PyObject *setDestroyOnExit(PyObject *self, PyObject *args);
  static void clear_wrapper(sipSimpleWrapper *sw);
  static void print_object(const char *label, PyObject *obj);
  static void addToParent(sipWrapper *self, sipWrapper *owner);
  static void removeFromParent(sipWrapper *self);
  static void detachChildren(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,
          Py_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, Py_ssize_t *aszp);
  static int convertToWCharArray(PyObject *obj, wchar_t **ap, Py_ssize_t *aszp);
  static int parseWChar(PyObject *obj, wchar_t *ap);
  static int convertToWChar(PyObject *obj, wchar_t *ap);
  static int parseWCharString(PyObject *obj, wchar_t **ap);
  static int convertToWCharString(PyObject *obj, wchar_t **ap);
  #else
  static void raiseNoWChar();
  #endif
  static void *getComplexCppPtr(sipSimpleWrapper *w, const sipTypeDef *td);
  static PyObject *findPyType(const char *name);
  static int addPyObjectToList(sipPyObject **head, PyObject *object);
  static PyObject *getDictFromObject(PyObject *obj);
  static void forgetObject(sipSimpleWrapper *sw);
  static int add_lazy_container_attrs(sipTypeDef *td, sipContainerDef *cod,
          PyObject *dict);
  static int add_lazy_attrs(sipTypeDef *td);
  static int add_all_lazy_attrs(sipTypeDef *td);
  static int objectify(const char *s, PyObject **objp);
  static void add_failure(PyObject **parseErrp, sipParseFailure *failure);
  static PyObject *bad_type_str(int arg_nr, PyObject *arg);
  static void *explicit_access_func(sipSimpleWrapper *sw, AccessFuncOp op);
  static void *indirect_access_func(sipSimpleWrapper *sw, AccessFuncOp op);
  static void clear_access_func(sipSimpleWrapper *sw);
  static int check_encoded_string(PyObject *obj);
  static int isNonlazyMethod(PyMethodDef *pmd);
  static int addMethod(PyObject *dict, PyMethodDef *pmd);
  static PyObject *create_property(sipVariableDef *vd);
  static PyObject *create_function(PyMethodDef *ml);
  static PyObject *sip_exit(PyObject *self, PyObject *args);
  static sipConvertFromFunc get_from_convertor(const sipTypeDef *td);
  static sipPyObject **autoconversion_disabled(const sipTypeDef *td);
  static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd);
  static sipFinalFunc find_finalisation(sipClassTypeDef *ctd);
  static sipNewUserTypeFunc find_new_user_type_handler(sipWrapperType *wt);
  static PyObject *next_in_mro(PyObject *self, PyObject *after);
  static int super_init(PyObject *self, PyObject *args, PyObject *kwds,
          PyObject *type);
  static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w);
  static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td,
          sipWrapper *owner, int flags);
  static void *resolve_proxy(const sipTypeDef *td, void *proxy);
  static PyObject *call_method(PyObject *method, const char *fmt, va_list va);
  static int importTypes(sipExportedModuleDef *client, sipImportedModuleDef *im,
          sipExportedModuleDef *em);
  static int importErrorHandlers(sipExportedModuleDef *client,
          sipImportedModuleDef *im, sipExportedModuleDef *em);
  static int importExceptions(sipExportedModuleDef *client,
          sipImportedModuleDef *im, sipExportedModuleDef *em);
  static int is_subtype(const sipClassTypeDef *ctd,
          const sipClassTypeDef *base_ctd);
  static PyObject *import_module_attr(const char *module, const char *attr);
  static const sipContainerDef *get_container(const sipTypeDef *td);
  static PyObject *get_qualname(const sipTypeDef *td, PyObject *name);
  static int convert_to_enum(PyObject *obj, const sipTypeDef *td, int allow_int);
  static void handle_failed_int_conversion(sipParseFailure *pf, PyObject *arg);
  static void enum_expected(PyObject *obj, const sipTypeDef *td);
  static int long_as_nonoverflow_int(PyObject *val_obj);
  static int dict_set_and_discard(PyObject *dict, const char *name,
          PyObject *obj);
  
  
  /*
   * Initialise the module as a library.
   */
  const sipAPIDef *sip_init_library(PyObject *mod_dict)
  {
      static PyMethodDef methods[] = {
          /* This must be first. */
          {"_unpickle_enum", unpickle_enum, METH_VARARGS, NULL},
          /* This must be second. */
          {"_unpickle_type", unpickle_type, METH_VARARGS, NULL},
          {"assign", assign, METH_VARARGS, NULL},
          {"cast", cast, METH_VARARGS, NULL},
          {"delete", callDtor, METH_VARARGS, NULL},
          {"dump", dumpWrapper, METH_O, NULL},
          {"enableautoconversion", enableAutoconversion, METH_VARARGS, NULL},
          {"enableoverflowchecking", sipEnableOverflowChecking, METH_VARARGS, NULL},
          {"getapi", sipGetAPI, METH_VARARGS, NULL},
          {"isdeleted", isDeleted, METH_VARARGS, NULL},
          {"ispycreated", isPyCreated, METH_VARARGS, NULL},
          {"ispyowned", isPyOwned, METH_VARARGS, NULL},
          {"setapi", sipSetAPI, METH_VARARGS, NULL},
          {"setdeleted", setDeleted, METH_VARARGS, NULL},
          {"setdestroyonexit", setDestroyOnExit, 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},
          {NULL, NULL, 0, NULL}
      };
  
      static PyMethodDef sip_exit_md = {
          "_sip_exit", sip_exit, METH_NOARGS, NULL
      };
  
      PyObject *obj;
      PyMethodDef *md;
  
      /*
       * Remind ourselves to add support for capsule variables when we have
       * another reason to move to the next major version number.
       */
  #if SIP_API_MAJOR_NR > 12
  #error "Add support for capsule variables"
  #endif
  
  #ifdef WITH_THREAD
      PyEval_InitThreads();
  #endif
  
      /* Add the SIP version number. */
      obj = PyLong_FromLong(SIP_VERSION);
  
      if (dict_set_and_discard(mod_dict, "SIP_VERSION", obj) < 0)
          return NULL;
  
      obj = PyUnicode_FromString(SIP_VERSION_STR);
  
      if (dict_set_and_discard(mod_dict, "SIP_VERSION_STR", obj) < 0)
          return NULL;
  
      /* Add the methods. */
      for (md = methods; md->ml_name != NULL; ++md)
      {
          PyObject *meth = PyCFunction_New(md, NULL);
  
          if (dict_set_and_discard(mod_dict, md->ml_name, meth) < 0)
              return NULL;
  
          if (md == &methods[0])
          {
              Py_INCREF(meth);
              enum_unpickler = meth;
          }
          else if (md == &methods[1])
          {
              Py_INCREF(meth);
              type_unpickler = meth;
          }
      }
  
      /* Initialise the types. */
      sipWrapperType_Type.tp_base = &PyType_Type;
  
      if (PyType_Ready(&sipWrapperType_Type) < 0)
          return NULL;
  
      if (PyType_Ready((PyTypeObject *)&sipSimpleWrapper_Type) < 0)
          return NULL;
  
      if (sip_api_register_py_type((PyTypeObject *)&sipSimpleWrapper_Type) < 0)
          return NULL;
  
  #if defined(STACKLESS)
      sipWrapper_Type.super.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type;
  #else
      sipWrapper_Type.super.ht_type.tp_base = (PyTypeObject *)&sipSimpleWrapper_Type;
  #endif
  
      if (PyType_Ready((PyTypeObject *)&sipWrapper_Type) < 0)
          return NULL;
  
      if (PyType_Ready(&sipMethodDescr_Type) < 0)
          return NULL;
  
      if (PyType_Ready(&sipVariableDescr_Type) < 0)
          return NULL;
  
      sipEnumType_Type.tp_base = &PyType_Type;
  
      if (PyType_Ready(&sipEnumType_Type) < 0)
          return NULL;
  
      if (PyType_Ready(&sipVoidPtr_Type) < 0)
          return NULL;
  
      if (PyType_Ready(&sipArray_Type) < 0)
          return NULL;
  
      /* Add the public types. */
      if (PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type) < 0)
          return NULL;
  
      if (PyDict_SetItemString(mod_dict, "simplewrapper", (PyObject *)&sipSimpleWrapper_Type) < 0)
          return NULL;
  
      if (PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type) < 0)
          return NULL;
  
      if (PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type) < 0)
          return NULL;
  
      /* These will always be needed. */
      if (objectify("__init__", &init_name) < 0)
          return NULL;
  
      if ((empty_tuple = PyTuple_New(0)) == NULL)
          return NULL;
  
      /* Initialise the object map. */
      sipOMInit(&cppPyMap);
  
      /* Make sure we are notified at the end of the exit process. */
      if (Py_AtExit(finalise) < 0)
          return NULL;
  
      /* Make sure we are notified at the start of the exit process. */
      if (sip_api_register_exit_notifier(&sip_exit_md) < 0)
          return NULL;
  
      /*
       * Get the current interpreter.  This will be shared between all threads.
       */
      sipInterpreter = PyThreadState_Get()->interp;
  
      return &sip_api;
  }
  
  
  /*
   * Set a dictionary item and discard the reference to the item even if there
   * was an error.
   */
  static int dict_set_and_discard(PyObject *dict, const char *name, PyObject *obj)
  {
      int rc;
  
      if (obj == NULL)
          return -1;
  
      rc = PyDict_SetItemString(dict, name, obj);
  
      Py_DECREF(obj);
  
      return rc;
  }
  
  
  #if _SIP_MODULE_SHARED
  /*
   * The Python module initialisation function.
   */
  #if defined(SIP_STATIC_MODULE)
  PyObject *_SIP_MODULE_ENTRY(void)
  #else
  PyMODINIT_FUNC _SIP_MODULE_ENTRY(void)
  #endif
  {
      static PyModuleDef module_def = {
          PyModuleDef_HEAD_INIT,
          _SIP_MODULE_FQ_NAME,    /* m_name */
          NULL,                   /* m_doc */
          -1,                     /* m_size */
          NULL,                   /* m_methods */
          NULL,                   /* m_reload */
          NULL,                   /* m_traverse */
          NULL,                   /* m_clear */
          NULL,                   /* m_free */
      };
  
      const sipAPIDef *api;
      PyObject *mod, *mod_dict, *api_obj;
  
      /* Create the module. */
      if ((mod = PyModule_Create(&module_def)) == NULL)
          return NULL;
  
      mod_dict = PyModule_GetDict(mod);
  
      /* Initialise the module dictionary and static variables. */
      if ((api = sip_init_library(mod_dict)) == NULL)
          return NULL;
  
      /* Publish the SIP API. */
      api_obj = PyCapsule_New((void *)api, _SIP_MODULE_FQ_NAME "._C_API", NULL);
  
      if (dict_set_and_discard(mod_dict, "_C_API", api_obj) < 0)
      {
          Py_DECREF(mod);
          return NULL;
      }
  
  #if _SIP_MODULE_LEGACY
      {
          /*
           * Also install the package-specific module at the top level for
           * backwards compatibility.
           */
          PyObject *modules = PySys_GetObject("modules");
  
          if (modules != NULL)
              PyDict_SetItemString(modules, "sip", mod);
      }
  #endif
  
      return mod;
  }
  #endif
  
  
  /*
   * Return the current interpreter, if there is one.
   */
  static PyInterpreterState *sip_api_get_interpreter(void)
  {
      return sipInterpreter;
  }
  
  
  /*
   * 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;
  
      (void)self;
  
      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.  Note that we
   * use the same calling convention as sys.getrefcount() so that it has the
   * same caveat regarding the reference count.
   */
  static PyObject *dumpWrapper(PyObject *self, PyObject *arg)
  {
      sipSimpleWrapper *sw;
  
      (void)self;
  
      if (!PyObject_TypeCheck(arg, (PyTypeObject *)&sipSimpleWrapper_Type))
      {
          PyErr_Format(PyExc_TypeError,
                  "dump() argument 1 must be sip.simplewrapper, not %s",
                  Py_TYPE(arg)->tp_name);
          return NULL;
      }
  
      sw = (sipSimpleWrapper *)arg;
  
      print_object(NULL, (PyObject *)sw);
  
      printf("    Reference count: %" PY_FORMAT_SIZE_T "d\n", Py_REFCNT(sw));
      printf("    Address of wrapped object: %p\n", sip_api_get_address(sw));
      printf("    Created by: %s\n", (sipIsDerived(sw) ? "Python" : "C/C++"));
      printf("    To be destroyed by: %s\n", (sipIsPyOwned(sw) ? "Python" : "C/C++"));
  
      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;
  }
  
  
  /*
   * 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;
  
      (void)self;
  
      if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner))
      {
          if (owner == Py_None)
          {
              /*
               * Note that the Python API is different to the C API when the
               * owner is 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;
  
      (void)self;
  
      if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w))
      {
          sip_api_transfer_back(w);
  
          Py_INCREF(Py_None);
          return Py_None;
      }
  
      return NULL;
  }
  
  
  /*
   * Invoke the assignment operator for a C++ instance.
   */
  static PyObject *assign(PyObject *self, PyObject *args)
  {
      sipSimpleWrapper *dst, *src;
      PyTypeObject *dst_type, *src_type;
      const sipTypeDef *td, *super_td;
      sipAssignFunc assign_helper;
      void *dst_addr, *src_addr;
  
      (void)self;
  
      if (!PyArg_ParseTuple(args, "O!O!:assign", &sipSimpleWrapper_Type, &dst, &sipSimpleWrapper_Type, &src))
          return NULL;
  
      /* Get the assignment helper. */
      dst_type = Py_TYPE(dst);
      td = ((sipWrapperType *)dst_type)->wt_td;
  
      if (sipTypeIsMapped(td))
          assign_helper = ((const sipMappedTypeDef *)td)->mtd_assign;
      else
          assign_helper = ((const sipClassTypeDef *)td)->ctd_assign;
  
      if (assign_helper == NULL)
      {
          PyErr_SetString(PyExc_TypeError,
                  "argument 1 of assign() does not support assignment");
          return NULL;
      }
  
      /* Check the types are compatible. */
      src_type = Py_TYPE(src);
  
      if (src_type == dst_type)
      {
          super_td = NULL;
      }
      else if (PyType_IsSubtype(src_type, dst_type))
      {
          super_td = td;
      }
      else
      {
          PyErr_SetString(PyExc_TypeError,
                  "type of argument 1 of assign() must be a super-type of type of argument 2");
          return NULL;
      }
  
      /* Get the addresses. */
      if ((dst_addr = sip_api_get_cpp_ptr(dst, NULL)) == NULL)
          return NULL;
  
      if ((src_addr = sip_api_get_cpp_ptr(src, super_td)) == NULL)
          return NULL;
  
      /* Do the assignment. */
      assign_helper(dst_addr, 0, src_addr);
  
      Py_INCREF(Py_None);
      return Py_None;
  }
  
  
  /*
   * 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;
  
      (void)self;
  
      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->wt_td;
      else
      {
          PyErr_SetString(PyExc_TypeError, "argument 1 of 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 wrap_simple_instance(addr, wt->wt_td, NULL,
              (sw->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;
  
      (void)self;
  
      if (!PyArg_ParseTuple(args, "O!:delete", &sipSimpleWrapper_Type, &sw))
          return NULL;
  
      addr = getPtrTypeDef(sw, &ctd);
  
      if (checkPointer(addr, sw) < 0)
          return NULL;
  
      clear_wrapper(sw);
  
      release(addr, (const sipTypeDef *)ctd, sw->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;
  
      (void)self;
  
      if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipSimpleWrapper_Type, &sw))
          return NULL;
  
      res = (sip_api_get_address(sw) == NULL ? Py_True : Py_False);
  
      Py_INCREF(res);
      return res;
  }
  
  
  /*
   * Check if an instance was created by Python.
   */
  static PyObject *isPyCreated(PyObject *self, PyObject *args)
  {
      sipSimpleWrapper *sw;
      PyObject *res;
  
      (void)self;
  
      if (!PyArg_ParseTuple(args, "O!:ispycreated", &sipSimpleWrapper_Type, &sw))
          return NULL;
  
      /* sipIsDerived() is a misnomer. */
      res = (sipIsDerived(sw) ? 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;
  
      (void)self;
  
      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;
  
      (void)self;
  
      if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipSimpleWrapper_Type, &sw))
          return NULL;
  
      clear_wrapper(sw);
  
      Py_INCREF(Py_None);
      return Py_None;
  }
  
  
  /*
   * Unwrap an instance.
   */
  static PyObject *unwrapInstance(PyObject *self, PyObject *args)
  {
      sipSimpleWrapper *sw;
  
      (void)self;
  
      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 PY_LONG_LONG addr;
      sipWrapperType *wt;
  
      (void)self;
  
      if (PyArg_ParseTuple(args, "KO!:wrapinstance", &addr, &sipWrapperType_Type, &wt))
          return sip_api_convert_from_type((void *)addr, wt->wt_td, NULL);
  
      return NULL;
  }
  
  
  /*
   * Set the destroy on exit flag from Python code.
   */
  static PyObject *setDestroyOnExit(PyObject *self, PyObject *args)
  {
      (void)self;
  
      if (PyArg_ParseTuple(args, "i:setdestroyonexit", &destroy_on_exit))
      {
          Py_INCREF(Py_None);
          return Py_None;
      }
  
      return NULL;
  }
  
  
  /*
   * Set the destroy on exit flag from C++ code.
   */
  static void sip_api_set_destroy_on_exit(int value)
  {
      destroy_on_exit = value;
  }
  
  
  /*
   * 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);
  
      (void)unused;
  
      /* 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;
              }
  
              if (im->im_imported_types != NULL && importTypes(client, im, em) < 0)
                  return -1;
  
              if (im->im_imported_veh != NULL && importErrorHandlers(client, im, em) < 0)
                  return -1;
  
              if (im->im_imported_exceptions != NULL && importExceptions(client, im, em) < 0)
                  return -1;
  
              ++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 QObject. */
          if (em->em_qt_api != NULL && client->em_qt_api != NULL)
          {
              PyErr_Format(PyExc_RuntimeError,
                      "the %s and %s modules both wrap the QObject class",
                      full_name, sipNameOfModule(em));
  
              return -1;
          }
      }
  
      /* Convert the module name to an object. */
      if ((client->em_nameobj = PyUnicode_FromString(full_name)) == NULL)
          return -1;
  
      /* Add it to the list of client modules. */
      client->em_next = moduleList;
      moduleList = client;
  
      /* Get any keyword handler.  Remove this in SIP v5. */
      if (!got_kw_handler)
      {
          kw_handler = sip_api_import_symbol("pyqt_kw_handler");
          got_kw_handler = TRUE;
      }
  
      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) || sipTypeIsScopedEnum(td))
          {
              sipEnumTypeDef *etd = (sipEnumTypeDef *)td;
  
              if (td->td_version < 0 || sipIsRangeEnabled(client, td->td_version))
                  if (createEnum(client, etd, i, mod_dict) < 0)
                      return -1;
  
              /*
               * Register the enum pickler for nested enums (non-nested enums
               * don't need special treatment).
               */
              if (sipTypeIsEnum(td) && 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 Qt support API. */
      if (client->em_qt_api != NULL)
      {
          sipQtSupport = client->em_qt_api;
          sipQObjectType = *sipQtSupport->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->wt_iextend;
                  wt->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)
      {
          sipTypeDef *etd = client->em_types[emd->em_enum];
          PyObject *mo;
  
          if (sipTypeIsScopedEnum(etd))
              continue;
  
          mo = sip_api_convert_from_enum(emd->em_val, etd);
  
          if (dict_set_and_discard(mod_dict, emd->em_name, mo) < 0)
              return -1;
      }
  
  
      /*
       * 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.  This should already have been done,
       * but just in case...
       */
      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;
  }
  
  
  /*
   * Convert a new C/C++ instance to a Python instance of a specific Python type..
   */
  static PyObject *sip_api_convert_from_new_pytype(void *cpp,
          PyTypeObject *py_type, sipWrapper *owner, sipSimpleWrapper **selfp,
          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 = sipWrapInstance(cpp, py_type, args, owner,
                  (selfp != NULL ? SIP_DERIVED_CLASS : 0));
  
          /* Initialise the rest of an instance of a derived class. */
          if (selfp != NULL)
              *selfp = (sipSimpleWrapper *)res;
      }
      else
      {
          res = NULL;
      }
  
      Py_XDECREF(args);
  
      va_end(va);
  
      return res;
  }
  
  
  /*
   * Call a method and return the result.
   */
  static PyObject *call_method(PyObject *method, const char *fmt, va_list va)
  {
      PyObject *args, *res;
  
      if ((args = PyTuple_New(strlen(fmt))) == NULL)
          return NULL;
  
      if (buildObject(args, fmt, va) != NULL)
          res = PyEval_CallObject(method, args);
      else
          res = NULL;
  
      Py_DECREF(args);
  
      return res;
  }
  
  
  /*
   * Call the Python re-implementation of a C++ virtual that does not return a
   * value and handle the result..
   */
  static void sip_api_call_procedure_method(sip_gilstate_t gil_state,
          sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self,
          PyObject *method, const char *fmt, ...)
  {
      PyObject *res;
      va_list va;
  
      va_start(va, fmt);
      res = call_method(method, fmt, va);
      va_end(va);
  
      if (res != NULL)
      {
          Py_DECREF(res);
  
          if (res != Py_None)
          {
              sip_api_bad_catcher_result(method);
              res = NULL;
          }
      }
  
      Py_DECREF(method);
  
      if (res == NULL)
          sip_api_call_error_handler(error_handler, py_self, gil_state);
  
      SIP_RELEASE_GIL(gil_state);
  }
  
  
  /*
   * Call the Python re-implementation of a C++ virtual.
   */
  static PyObject *sip_api_call_method(int *isErr, PyObject *method,
          const char *fmt, ...)
  {
      PyObject *res;
      va_list va;
  
      va_start(va, fmt);
      res = call_method(method, fmt, va);
      va_end(va);
  
      if (res == NULL && isErr != NULL)
          *isErr = TRUE;
  
      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 = (int)(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;
                  Py_ssize_t l;
  
                  s = va_arg(va, char *);
                  l = va_arg(va, Py_ssize_t);
  
                  if (s != NULL)
                  {
                      el = PyBytes_FromStringAndSize(s, l);
                  }
                  else
                  {
                      Py_INCREF(Py_None);
                      el = Py_None;
                  }
              }
  
              break;
  
          case 'G':
  #if defined(HAVE_WCHAR_H)
              {
                  wchar_t *s;
                  Py_ssize_t l;
  
                  s = va_arg(va, wchar_t *);
                  l = va_arg(va, Py_ssize_t);
  
                  if (s != NULL)
                      el = PyUnicode_FromWideChar(s, l);
                  else
                  {
                      Py_INCREF(Py_None);
                      el = Py_None;
                  }
              }
  #else
              raiseNoWChar();
              el = NULL;
  #endif
  
              break;
  
          case 'b':
              el = PyBool_FromLong(va_arg(va,int));
              break;
  
          case 'c':
              {
                  char c = va_arg(va, int);
  
                  el = PyBytes_FromStringAndSize(&c, 1);
              }
  
              break;
  
          case 'a':
              {
                  char c = va_arg(va, int);
  
                  el = PyUnicode_FromStringAndSize(&c, 1);
              }
  
              break;
  
          case 'w':
  #if defined(HAVE_WCHAR_H)
              {
                  wchar_t c = va_arg(va, int);
  
                  el = PyUnicode_FromWideChar(&c, 1);
              }
  #else
              raiseNoWChar();
              el = NULL;
  #endif
  
              break;
  
          case 'E':
              {
                  /* Remove in v5.1. */
  
                  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':
          case 'L':
              el = PyLong_FromLong(va_arg(va, int));
              break;
  
          case 'l':
              el = PyLong_FromLong(va_arg(va, long));
              break;
  
          case 'm':
              el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
              break;
  
          case 'n':
  #if defined(HAVE_LONG_LONG)
              el = PyLong_FromLongLong(va_arg(va, PY_LONG_LONG));
  #else
              el = PyLong_FromLong(va_arg(va, long));
  #endif
              break;
  
          case 'o':
  #if defined(HAVE_LONG_LONG)
              el = PyLong_FromUnsignedLongLong(va_arg(va, unsigned PY_LONG_LONG));
  #else
              el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
  #endif
              break;
  
          case 's':
              {
                  char *s = va_arg(va, char *);
  
                  if (s != NULL)
                  {
                      el = PyBytes_FromString(s);
                  }
                  else
                  {
                      Py_INCREF(Py_None);
                      el = Py_None;
                  }
              }
  
              break;
  
          case 'A':
              {
                  char *s = va_arg(va, char *);
  
                  if (s != NULL)
                  {
                      el = PyUnicode_FromString(s);
                  }
                  else
                  {
                      Py_INCREF(Py_None);
                      el = Py_None;
                  }
              }
  
              break;
  
          case 'x':
  #if defined(HAVE_WCHAR_H)
              {
                  wchar_t *s = va_arg(va, wchar_t *);
  
                  if (s != NULL)
                      el = PyUnicode_FromWideChar(s, (Py_ssize_t)wcslen(s));
                  else
                  {
                      Py_INCREF(Py_None);
                      el = Py_None;
                  }
              }
  #else
              raiseNoWChar();
              el = NULL;
  #endif
  
              break;
  
          case 't':
          case 'u':
          case 'M':
              el = PyLong_FromUnsignedLong(va_arg(va, unsigned));
              break;
  
          case '=':
              el = PyLong_FromUnsignedLong(va_arg(va, size_t));
              break;
  
          case 'B':
              {
                  /* Remove in v5.1. */
  
                  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->wt_td, 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':
              {
                  /* Remove in v5.1. */
  
                  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->wt_td, 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 *);
                  Py_ssize_t l = va_arg(va, Py_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;
  
          case 'z':
              {
                  const char *name = va_arg(va, const char *);
                  void *p = va_arg(va, void *);
  
                  if (p == NULL)
                  {
                      el = Py_None;
                      Py_INCREF(el);
                  }
                  else
                  {
                      el = PyCapsule_New(p, name, NULL);
                  }
              }
  
              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.  As of v9.0 of the API this
   * is only ever called by handwritten code.
   */
  static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res,
          const char *fmt, ...)
  {
      int rc;
      va_list va;
  
      va_start(va, fmt);
      rc = parseResult(method, res, NULL, fmt, va);
      va_end(va);
  
      if (isErr != NULL && rc < 0)
          *isErr = TRUE;
  
      return rc;
  }
  
  
  /*
   * Parse a result object based on a format string.
   */
  static int sip_api_parse_result_ex(sip_gilstate_t gil_state,
          sipVirtErrorHandlerFunc error_handler, sipSimpleWrapper *py_self,
          PyObject *method, PyObject *res, const char *fmt, ...)
  {
      int rc;
  
      if (res != NULL)
      {
          va_list va;
  
          va_start(va, fmt);
          rc = parseResult(method, res, deref_mixin(py_self), fmt, va);
          va_end(va);
  
          Py_DECREF(res);
      }
      else
      {
          rc = -1;
      }
  
      Py_DECREF(method);
  
      if (rc < 0)
          sip_api_call_error_handler(error_handler, py_self, gil_state);
  
      SIP_RELEASE_GIL(gil_state);
  
      return rc;
  }
  
  
  /*
   * Call a virtual error handler.  This is called with the GIL and from the
   * thread that raised the error.
   */
  static void sip_api_call_error_handler(sipVirtErrorHandlerFunc error_handler,
          sipSimpleWrapper *py_self, sip_gilstate_t sipGILState)
  {
      if (error_handler != NULL)
          error_handler(deref_mixin(py_self), sipGILState);
      else
          PyErr_Print();
  }
  
  
  /*
   * Do the main work of parsing a result object based on a format string.
   */
  static int parseResult(PyObject *method, PyObject *res,
          sipSimpleWrapper *py_self, const char *fmt, va_list va)
  {
      int tupsz, rc = 0;
  
      /* We rely on PyErr_Occurred(). */
      PyErr_Clear();
  
      /* Get self if it is provided as an argument. */
      if (*fmt == 'S')
      {
          py_self = va_arg(va, sipSimpleWrapper *);
          ++fmt;
      }
  
      /* Basic validation of the format string. */
      if (*fmt == '(')
      {
          char ch;
          const char *cp = ++fmt;
          int sub_format = FALSE;
  
          tupsz = 0;
  
          while ((ch = *cp++) != ')')
          {
              if (ch == '\0')
              {
                  PyErr_Format(PyExc_SystemError, "sipParseResult(): invalid format string \"%s\"", fmt - 1);
                  rc = -1;
  
                  break;
              }
  
              if (sub_format)
              {
                  sub_format = FALSE;
              }
              else
              {
                  ++tupsz;
  
                  /* Some format characters have a sub-format. */
                  if (strchr("aAHDC", ch) != NULL)
                      sub_format = TRUE;
              }
          }
  
          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 **);
                      Py_ssize_t *szp = va_arg(va, Py_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 **);
                      Py_ssize_t *szp = va_arg(va, Py_ssize_t *);
  
                      if (parseWCharArray(arg, p, szp) < 0)
                          invalid = TRUE;
                  }
  #else
                  raiseNoWChar();
                  invalid = TRUE;
  #endif
  
                  break;
  
              case 'b':
                  {
                      char *p = va_arg(va, void *);
                      int v = sip_api_convert_to_bool(arg);
  
                      if (v < 0)
                          invalid = TRUE;
                      else if (p != NULL)
                          sipSetBool(p, 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 *p = va_arg(va, double *);
                      double v = PyFloat_AsDouble(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'E':
                  {
                      /* Remove in v5.1. */
  
                      PyTypeObject *et = va_arg(va, PyTypeObject *);
                      int *p = va_arg(va, int *);
                      int v = sip_api_convert_to_enum(arg, ((sipEnumTypeObject *)et)->type);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'F':
                  {
                      sipTypeDef *td = va_arg(va, sipTypeDef *);
                      int *p = va_arg(va, int *);
                      int v = sip_api_convert_to_enum(arg, td);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'f':
                  {
                      float *p = va_arg(va, float *);
                      float v = (float)PyFloat_AsDouble(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'L':
                  {
                      signed char *p = va_arg(va, signed char *);
                      signed char v = sip_api_long_as_signed_char(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'M':
                  {
                      unsigned char *p = va_arg(va, unsigned char *);
                      unsigned char v = sip_api_long_as_unsigned_char(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'h':
                  {
                      signed short *p = va_arg(va, signed short *);
                      signed short v = sip_api_long_as_short(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 't':
                  {
                      unsigned short *p = va_arg(va, unsigned short *);
                      unsigned short v = sip_api_long_as_unsigned_short(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'e':
                  {
                      int *p = va_arg(va, int *);
                      int v = long_as_nonoverflow_int(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'i':
                  {
                      int *p = va_arg(va, int *);
                      int v = sip_api_long_as_int(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'u':
                  {
                      unsigned *p = va_arg(va, unsigned *);
                      unsigned v = sip_api_long_as_unsigned_int(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case '=':
                  {
                      size_t *p = va_arg(va, size_t *);
                      size_t v = sip_api_long_as_size_t(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'l':
                  {
                      long *p = va_arg(va, long *);
                      long v = sip_api_long_as_long(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'm':
                  {
                      unsigned long *p = va_arg(va, unsigned long *);
                      unsigned long v = sip_api_long_as_unsigned_long(arg);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'n':
                  {
  #if defined(HAVE_LONG_LONG)
                      PY_LONG_LONG *p = va_arg(va, PY_LONG_LONG *);
                      PY_LONG_LONG v = sip_api_long_as_long_long(arg);
  #else
                      long *p = va_arg(va, long *);
                      long v = sip_api_long_as_long(arg);
  #endif
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'o':
                  {
  #if defined(HAVE_LONG_LONG)
                      unsigned PY_LONG_LONG *p = va_arg(va, unsigned PY_LONG_LONG *);
                      unsigned PY_LONG_LONG v = sip_api_long_as_unsigned_long_long(arg);
  #else
                      unsigned long *p = va_arg(va, unsigned long *);
                      unsigned long v = sip_api_long_as_unsigned_long(arg);
  #endif
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 's':
                  {
                      /* Remove in v5.1. */
  
                      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 *)py_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
                          sip_api_keep_reference((PyObject *)py_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':
                  {
                      /* Remove in v5.1. */
  
                      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->wt_td, (flags & FMT_RP_FACTORY ? arg : NULL), (flags & FMT_RP_DEREF ? SIP_NOT_NONE : 0), state, &iserr);
  
                          if (iserr)
                              invalid = TRUE;
                      }
                  }
  
                  break;
  
              case 'D':
                  {
                      /* Remove in v5.1. */
  
                      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);
  
                              if (cpp != NULL)
                                  assign_helper(cpp, 0, val);
  
                              sip_api_release_type(val, td, state);
                          }
                          else if (cpp != NULL)
                          {
                              *(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))
                      {
                          if (p != NULL)
                          {
                              Py_INCREF(arg);
                              *p = arg;
                          }
                      }
                      else
                      {
                          invalid = TRUE;
                      }
                  }
  
                  break;
  
              case 'O':
                  {
                      PyObject **p = va_arg(va, PyObject **);
  
                      if (p != NULL)
                      {
                          Py_INCREF(arg);
                          *p = arg;
                      }
                  }
  
                  break;
  
              case 'T':
                  {
                      PyTypeObject *type = va_arg(va, PyTypeObject *);
                      PyObject **p = va_arg(va, PyObject **);
  
                      if (PyObject_TypeCheck(arg, type))
                      {
                          if (p != NULL)
                          {
                              Py_INCREF(arg);
                              *p = arg;
                          }
                      }
                      else
                      {
                          invalid = TRUE;
                      }
                  }
  
                  break;
  
              case 'V':
                  {
                      void *v = sip_api_convert_to_void_ptr(arg);
                      void **p = va_arg(va, void **);
  
                      if (PyErr_Occurred())
                          invalid = TRUE;
                      else if (p != NULL)
                          *p = v;
                  }
  
                  break;
  
              case 'z':
                  {
                      const char *name = va_arg(va, const char *);
                      void **p = va_arg(va, void **);
  
                      if (arg == Py_None)
                      {
                          if (p != NULL)
                              *p = NULL;
                      }
                      else
                      {
  #if defined(SIP_USE_CAPSULE)
                          void *v = PyCapsule_GetPointer(arg, name);
  #else
                          void *v = sip_api_convert_to_void_ptr(arg);
  
                          (void)name;
  #endif
  
                          if (PyErr_Occurred())
                              invalid = TRUE;
                          else if (p != NULL)
                              *p = v;
                      }
                  }
  
                  break;
  
              case 'Z':
                  if (arg != Py_None)
                      invalid = TRUE;
  
                  break;
  
              case '!':
                  {
                      PyObject **p = va_arg(va, PyObject **);
  
                      if (PyObject_CheckBuffer(arg))
                      {
                          if (p != NULL)
                          {
                              Py_INCREF(arg);
                              *p = arg;
                          }
                      }
                      else
                      {
                          invalid = TRUE;
                      }
                  }
  
                  break;
  
              case '$':
                  {
                      PyObject **p = va_arg(va, PyObject **);
  
                      if (arg == Py_None || PyObject_CheckBuffer(arg))
                      {
                          if (p != NULL)
                          {
                              Py_INCREF(arg);
                              *p = arg;
                          }
                      }
                      else
                      {
                          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;
              }
          }
      }
  
      return rc;
  }
  
  
  /*
   * 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;
  
      if (unused != NULL)
      {
          /*
           * Initialise the return of any unused keyword arguments.  This is
           * used by any ctor overload.
           */
          *unused = NULL;
      }
  
      va_start(va, fmt);
      ok = parseKwdArgs(parseErrp, sipArgs, sipKwdArgs, kwdlist, unused, fmt,
              va);
      va_end(va);
  
      /* Release any unused arguments if the parse failed. */
      if (!ok && unused != NULL)
      {
          Py_XDECREF(*unused);
      }
  
      return ok;
  }
  
  
  /*
   * Parse the arguments to a C/C++ function without any side effects.
   */
  static int parseKwdArgs(PyObject **parseErrp, PyObject *sipArgs,
          PyObject *sipKwdArgs, const char **kwdlist, PyObject **unused,
          const char *fmt, va_list va_orig)
  {
      int no_tmp_tuple, ok, selfarg;
      sipSimpleWrapper *self;
      PyObject *single_arg;
      va_list va;
  
      /* Previous second pass errors stop subsequent parses. */
      if (*parseErrp != NULL && !PyList_Check(*parseErrp))
          return FALSE;
  
      /*
       * See if we are parsing a single argument.  In current versions we are
       * told explicitly by the first character of the format string.  In earlier
       * versions we guessed (sometimes wrongly).
       */
      if (*fmt == '1')
      {
          ++fmt;
          no_tmp_tuple = FALSE;
      }
      else
          no_tmp_tuple = PyTuple_Check(sipArgs);
  
      if (no_tmp_tuple)
      {
          Py_INCREF(sipArgs);
      }
      else if ((single_arg = PyTuple_New(1)) != NULL)
      {
          Py_INCREF(sipArgs);
          PyTuple_SET_ITEM(single_arg, 0, sipArgs);
  
          sipArgs = single_arg;
      }
      else
      {
          /* Stop all parsing and indicate an exception has been raised. */
          Py_XDECREF(*parseErrp);
          *parseErrp = Py_None;
          Py_INCREF(Py_None);
  
          return FALSE;
      }
  
      /*
       * The first pass checks all the types and does conversions that are cheap
       * and have no side effects.
       */
      va_copy(va, va_orig);
      ok = parsePass1(parseErrp, &self, &selfarg, sipArgs, sipKwdArgs, kwdlist,
              unused, fmt, va);
      va_end(va);
  
      if (ok)
      {
          /*
           * The second pass does any remaining conversions now that we know we
           * have the right signature.
           */
          va_copy(va, va_orig);
          ok = parsePass2(self, selfarg, sipArgs, sipKwdArgs, kwdlist, fmt, va);
          va_end(va);
  
          /* Remove any previous failed parses. */
          Py_XDECREF(*parseErrp);
  
          if (ok)
          {
              *parseErrp = NULL;
          }
          else
          {
              /* Indicate that an exception has been raised. */
              *parseErrp = Py_None;
              Py_INCREF(Py_None);
          }
      }
  
      Py_DECREF(sipArgs);
  
      return ok;
  }
  
  
  /*
   * Return a string as a Python object that describes an argument with an
   * unexpected type.
   */
  static PyObject *bad_type_str(int arg_nr, PyObject *arg)
  {
      return PyUnicode_FromFormat("argument %d has unexpected type '%s'", arg_nr,
              Py_TYPE(arg)->tp_name);
  }
  
  
  /*
   * Adds a failure about an argument with an incorrect type to the current list
   * of exceptions.
   */
  static sipErrorState sip_api_bad_callable_arg(int arg_nr, PyObject *arg)
  {
      PyObject *detail = bad_type_str(arg_nr + 1, arg);
  
      if (detail == NULL)
          return sipErrorFail;
  
      PyErr_SetObject(PyExc_TypeError, detail);
      Py_DECREF(detail);
  
      return sipErrorContinue;
  }
  
  
  /*
   * Adds the current exception to the current list of exceptions (if it is a
   * user exception) or replace the current list of exceptions.
   */
  static void sip_api_add_exception(sipErrorState es, PyObject **parseErrp)
  {
      assert(*parseErrp == NULL);
  
      if (es == sipErrorContinue)
      {
          sipParseFailure failure;
          PyObject *e_type, *e_traceback;
  
          /* Get the value of the exception. */
          PyErr_Fetch(&e_type, &failure.detail_obj, &e_traceback);
          Py_XDECREF(e_type);
          Py_XDECREF(e_traceback);
  
          failure.reason = Exception;
  
          add_failure(parseErrp, &failure);
  
          if (failure.reason == Raised)
          {
              Py_XDECREF(failure.detail_obj);
              es = sipErrorFail;
          }
      }
  
      if (es == sipErrorFail)
      {
          Py_XDECREF(*parseErrp);
          *parseErrp = Py_None;
          Py_INCREF(Py_None);
      }
  }
  
  
  /*
   * The dtor for parse failure wrapped in a Python object.
   */
  static void failure_dtor(PyObject *capsule)
  {
      sipParseFailure *failure = (sipParseFailure *)PyCapsule_GetPointer(capsule, NULL);
  
      Py_XDECREF(failure->detail_obj);
  
      sip_api_free(failure);
  }
  
  
  /*
   * Add a parse failure to the current list of exceptions.
   */
  static void add_failure(PyObject **parseErrp, sipParseFailure *failure)
  {
      sipParseFailure *failure_copy;
      PyObject *failure_obj;
  
      /* Create the list if necessary. */
      if (*parseErrp == NULL && (*parseErrp = PyList_New(0)) == NULL)
      {
          failure->reason = Raised;
          return;
      }
  
      /*
       * Make a copy of the failure, convert it to a Python object and add it to
       * the list.  We do it this way to make it as lightweight as possible.
       */
      if ((failure_copy = sip_api_malloc(sizeof (sipParseFailure))) == NULL)
      {
          failure->reason = Raised;
          return;
      }
  
      *failure_copy = *failure;
  
      if ((failure_obj = PyCapsule_New(failure_copy, NULL, failure_dtor)) == 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 one or 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(sipArg1 != NULL ? 2 : 1)) == 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);
  
      if (sipArg1 != NULL)
      {
          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;
      Py_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.  We continue to parse if we get an
       * overflow because that is, strictly speaking, a second pass error.
       */
      while (failure.reason == Ok || failure.reason == Overflow)
      {
          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;
                      Py_ssize_t pos = 0;
  
                      /*
                       * Go through the keyword arguments to find any that were
                       * duplicates of positional arguments.  For the remaining
                       * ones remember the unused ones if we are interested.
                       */
                      while (PyDict_Next(sipKwdArgs, &pos, &key, &value))
                      {
                          int a;
  
                          if (!PyUnicode_Check(key))
                          {
                              failure.reason = KeywordNotString;
                              failure.detail_obj = key;
                              Py_INCREF(key);
                              break;
                          }
  
                          if (kwdlist != NULL)
                          {
                              /* Get the argument's index if it is one. */
                              for (a = 0; a < nr_args; ++a)
                              {
                                  const char *name = kwdlist[a];
  
                                  if (name == NULL)
                                      continue;
  
                                  if (PyUnicode_CompareWithASCIIString(key, name) == 0)
                                      break;
                              }
                          }
                          else
                          {
                              a = nr_args;
                          }
  
                          if (a == nr_args)
                          {
                              /*
                               * The name doesn't correspond to a keyword
                               * argument.
                               */
                              if (unused == NULL)
                              {
                                  /*
                                   * It may correspond to a keyword argument of a
                                   * different overload.
                                   */
                                  failure.reason = UnknownKeyword;
                                  failure.detail_obj = key;
                                  Py_INCREF(key);
  
                                  break;
                              }
  
                              /*
                               * Add it to the dictionary of unused arguments
                               * creating it if necessary.  Note that if the
                               * unused arguments are actually used by a later
                               * overload then the parse will incorrectly
                               * succeed.  This should be picked up (perhaps with
                               * a misleading exception) so long as the code that
                               * handles the unused arguments checks that it can
                               * handle them all.
                               */
                              if (unused_dict == NULL && (*unused = unused_dict = PyDict_New()) == NULL)
                              {
                                  failure.reason = Raised;
                                  break;
                              }
  
                              if (PyDict_SetItem(unused_dict, key, value) < 0)
                              {
                                  failure.reason = Raised;
                                  break;
                              }
                          }
                          else if (a < nr_pos_args - *selfargp)
                          {
                              /*
                               * 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 (nr_kwd_args != 0 && kwdlist != NULL)
          {
              const char *name = kwdlist[argnr - *selfargp];
  
              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;
                  Py_ssize_t pos = 0;
  
                  while (PyDict_Next(sipKwdArgs, &pos, &key, &value))
                  {
                      int a;
  
                      if (!PyUnicode_Check(key))
                      {
                          failure.reason = KeywordNotString;
                          failure.detail_obj = key;
                          Py_INCREF(key);
                          break;
                      }
  
                      if (kwdlist != NULL)
                      {
                          /* Get the argument's index if it is one. */
                          for (a = 0; a < nr_args; ++a)
                          {
                              const char *name = kwdlist[a];
  
                              if (name == NULL)
                                  continue;
  
                              if (PyUnicode_CompareWithASCIIString(key, name) == 0)
                                  break;
                          }
                      }
                      else
                      {
                          a = nr_args;
                      }
  
                      if (a == nr_args)
                      {
                          failure.reason = UnknownKeyword;
                          failure.detail_obj = key;
                          Py_INCREF(key);
  
                          break;
                      }
                  }
              }
  
              break;
          }
  
          /*
           * Handle the format character even if we don't have an argument so
           * that we skip the right number of arguments.
           */
          switch (ch)
          {
          case 'W':
              /* Ellipsis. */
              break;
  
          case '@':
              {
                  /* Implement /GetWrapper/. */
  
                  PyObject **p = va_arg(va, PyObject **);
  
                  if (arg != NULL)
                      *p = arg;
  
                  /* Process the same argument next time round. */
                  --argnr;
                  --nr_args;
  
                  break;
              }
  
          case 's':
              {
                  /* String from a Python bytes or None. */
  
                  const char **p = va_arg(va, const char **);
  
                  if (arg != NULL && parseBytes_AsString(arg, p) < 0)
                  {
                      failure.reason = WrongType;
                      failure.detail_obj = arg;
                      Py_INCREF(arg);
                  }
  
                  break;
              }
  
          case 'A':
              {
                  /* String from a Python string or None. */
  
                  va_arg(va, PyObject **);
                  va_arg(va, const char **);
                  fmt++;
  
                  if (arg != NULL && check_encoded_string(arg) < 0)
                  {
                      failure.reason = WrongType;
                      failure.detail_obj = arg;
                      Py_INCREF(arg);
                  }
  
                  break;
              }
  
          case 'a':
              {
                  /* Character from a Python string. */
  
                  va_arg(va, char *);
                  fmt++;
  
                  if (arg != NULL && check_encoded_string(arg) < 0)
                  {
                      failure.reason = WrongType;
                      failure.detail_obj = arg;
                      Py_INCREF(arg);
                  }
  
                  break;
              }
  
          case 'x':
  #if defined(HAVE_WCHAR_H)
              {
                  /* Wide string or None. */
  
                  wchar_t **p = va_arg(va, wchar_t **);
  
                  if (arg != NULL && parseWCharString(arg, p) < 0)
                  {
                      failure.reason = WrongType;
                      failure.detail_obj = arg;
                      Py_INCREF(arg);
                  }
  
                  break;
              }
  #else
              raiseNoWChar();
              failure.reason = Raised;
              break;
  #endif
  
          case 'U':
              {
                  /* Slot name or callable, return the name or callable. */
  
                  char **sname = va_arg(va, char **);
                  PyObject **scall = va_arg(va, PyObject **);
  
                  if (arg != NULL)
                  {
                      *sname = NULL;
                      *scall = NULL;
  
                      if (PyBytes_Check(arg))
                      {
                          char *s = PyBytes_AS_STRING(arg);
  
                          if (*s == '1' || *s == '2' || *s == '9')
                          {
                              *sname = s;
                          }
                          else
                          {
                              failure.reason = WrongType;
                              failure.detail_obj = arg;
                              Py_INCREF(arg);
                          }
                      }
                      else if (PyCallable_Check(arg))
                      {
                           *scall = arg;
                      }
                      else if (arg != Py_None)
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                  }
  
                  break;
              }
  
          case 'S':
              {
                  /* Slot name, return the name. */
  
                  char **p = va_arg(va, char **);
  
                  if (arg != NULL)
                  {
                      if (PyBytes_Check(arg))
                      {
                          char *s = PyBytes_AS_STRING(arg);
  
                          if (*s == '1' || *s == '2' || *s == '9')
                          {
                              *p = s;
                          }
                          else
                          {
                              failure.reason = WrongType;
                              failure.detail_obj = arg;
                              Py_INCREF(arg);
                          }
                      }
                      else
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                  }
  
                  break;
              }
  
          case 'G':
              {
                  /* Signal name, return the name. */
  
                  char **p = va_arg(va, char **);
  
                  if (arg != NULL)
                  {
                      if (PyBytes_Check(arg))
                      {
                          char *s = PyBytes_AS_STRING(arg);
  
                          if (*s == '2' || *s == '9')
                          {
                              *p = s;
                          }
                          else
                          {
                              failure.reason = WrongType;
                              failure.detail_obj = arg;
                              Py_INCREF(arg);
                          }
                      }
                      else
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                  }
  
                  break;
              }
  
          case 'r':
              {
                  /* Sequence of class or mapped type instances. */
  
                  const sipTypeDef *td;
  
                  td = va_arg(va, const sipTypeDef *);
                  va_arg(va, void **);
                  va_arg(va, Py_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 QObject. */
  
                  PyObject **p = va_arg(va, PyObject **);
  
                  if (arg != NULL)
                  {
                      if (isQObject(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 '!':
              {
                  /* Python object that implements the buffer protocol. */
   
                  PyObject **p = va_arg(va, PyObject **);
  
                  if (arg != NULL)
                  {
                      if (PyObject_CheckBuffer(arg))
                      {
                          *p = arg;
                      }
                      else
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                  }
   
                  break;
              }
  
          case '$':
              {
                  /*
                   * Python object that implements the buffer protocol or None.
                   */
   
                  PyObject **p = va_arg(va, PyObject **);
  
                  if (arg != NULL)
                  {
                      if (arg == Py_None || PyObject_CheckBuffer(arg))
                      {
                          *p = arg;
                      }
                      else
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                  }
   
                  break;
              }
  
          case 'q':
              {
                  /* Qt receiver to connect. */
  
                  va_arg(va, char *);
                  va_arg(va, void **);
                  va_arg(va, const char **);
  
                  if (arg != NULL && !isQObject(arg))
                  {
                      failure.reason = WrongType;
                      failure.detail_obj = arg;
                      Py_INCREF(arg);
                  }
  
                  break;
              }
  
          case 'Q':
              {
                  /* Qt receiver to disconnect. */
  
                  va_arg(va, char *);
                  va_arg(va, void **);
                  va_arg(va, const char **);
  
                  if (arg != NULL && !isQObject(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 && (sipQtSupport == 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 && (sipQtSupport == 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 **);
                  Py_ssize_t *szp = va_arg(va, Py_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 **);
                  Py_ssize_t *szp = va_arg(va, Py_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 '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 = sip_api_convert_to_bool(arg);
  
                      if (v < 0)
                      {
                          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 *);
                  int *p = va_arg(va, int *);
  
                  if (arg != NULL)
                  {
                      int v = sip_api_convert_to_enum(arg, td);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
              }
  
              break;
  
          case 'e':
              {
                  /* Anonymous enum. */
  
                  int *p = va_arg(va, int *);
  
                  if (arg != NULL)
                  {
                      int v = long_as_nonoverflow_int(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
              }
  
              break;
  
          case 'i':
              {
                  /* Integer. */
  
                  int *p = va_arg(va, int *);
  
                  if (arg != NULL)
                  {
                      int v = sip_api_long_as_int(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, 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_int(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
  
                  break;
              }
  
          case '=':
              {
                  /* size_t integer. */
  
                  size_t *p = va_arg(va, size_t *);
  
                  if (arg != NULL)
                  {
                      size_t v = sip_api_long_as_size_t(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
  
                  break;
              }
  
          case 'L':
              {
                  /* Signed char. */
  
                  signed char *p = va_arg(va, signed char *);
  
                  if (arg != NULL)
                  {
                      signed char v = sip_api_long_as_signed_char(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
  
                  break;
              }
  
          case 'M':
              {
                  /* Unsigned char. */
  
                  unsigned char *p = va_arg(va, unsigned char *);
  
                  if (arg != NULL)
                  {
                      unsigned char v = sip_api_long_as_unsigned_char(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
  
                  break;
              }
  
          case 'h':
              {
                  /* Short integer. */
  
                  signed short *p = va_arg(va, signed short *);
  
                  if (arg != NULL)
                  {
                      signed short v = sip_api_long_as_short(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, 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_short(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, arg);
                      else
                          *p = v;
                  }
  
                  break;
              }
  
          case 'l':
              {
                  /* Long integer. */
  
                  long *p = va_arg(va, long *);
  
                  if (arg != NULL)
                  {
                      long v = sip_api_long_as_long(arg);
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, 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())
                          handle_failed_int_conversion(&failure, 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 = sip_api_long_as_long_long(arg);
  #else
                      long v = sip_api_long_as_long(arg);
  #endif
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, 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 = sip_api_long_as_unsigned_long_long(arg);
  #else
                      unsigned long v = sip_api_long_as_unsigned_long(arg);
  #endif
  
                      if (PyErr_Occurred())
                          handle_failed_int_conversion(&failure, 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 *);
                      int *p = va_arg(va, int *);
  
                      if (arg != NULL)
                      {
                          *p = convert_to_enum(arg, td, FALSE);
  
                          if (PyErr_Occurred())
                              handle_failed_int_conversion(&failure, arg);
                      }
                  }
                  else
                  {
                      void *p = va_arg(va, void *);
  
                      if (arg != NULL)
                      {
                          switch (sub_fmt)
                          {
                          case 'b':
                              {
                                  /* Boolean. */
  
                                  if (PyBool_Check(arg))
                                  {
                                      sipSetBool(p, (arg == Py_True));
                                  }
                                  else
                                  {
                                      failure.reason = WrongType;
                                      failure.detail_obj = arg;
                                      Py_INCREF(arg);
                                  }
  
                                  break;
                              }
  
                          case 'd':
                              {
                                  /* Double float. */
  
                                  if (PyFloat_Check(arg))
                                  {
                                      *(double *)p = PyFloat_AS_DOUBLE(arg);
                                  }
                                  else
                                  {
                                      failure.reason = WrongType;
                                      failure.detail_obj = arg;
                                      Py_INCREF(arg);
                                  }
  
                                  break;
                              }
  
                          case 'f':
                              {
                                  /* Float. */
  
                                  if (PyFloat_Check(arg))
                                  {
                                      *(float *)p = (float)PyFloat_AS_DOUBLE(arg);
                                  }
                                  else
                                  {
                                      failure.reason = WrongType;
                                      failure.detail_obj = arg;
                                      Py_INCREF(arg);
                                  }
  
                                  break;
                              }
  
                          case 'i':
                              {
                                  /* Integer. */
  
                                  if (PyLong_Check(arg))
                                  {
                                      *(int *)p = sip_api_long_as_int(arg);
  
                                      if (PyErr_Occurred())
                                          handle_failed_int_conversion(&failure,
                                                  arg);
                                  }
                                  else
                                  {
                                      failure.reason = WrongType;
                                      failure.detail_obj = arg;
                                      Py_INCREF(arg);
                                  }
  
                                  break;
                              }
                          }
                      }
                  }
  
                  break;
              }
  
          case 'd':
              {
                  /* Double float. */
  
                  double *p = va_arg(va,double *);
  
                  if (arg != NULL)
                  {
                      double v = PyFloat_AsDouble(arg);
  
                      if (PyErr_Occurred())
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                      else
                      {
                          *p = v;
                      }
                  }
  
                  break;
              }
  
          case 'v':
              {
                  /* Void pointer. */
  
                  void **p = va_arg(va, void **);
  
                  if (arg != NULL)
                  {
                      void *v = sip_api_convert_to_void_ptr(arg);
  
                      if (PyErr_Occurred())
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                      else
                      {
                          *p = v;
                      }
                  }
  
                  break;
              }
  
          case 'z':
              {
                  /* Void pointer as a capsule. */
  
                  const char *name = va_arg(va, const char *);
                  void **p = va_arg(va, void **);
  
                  if (arg == Py_None)
                  {
                      *p = NULL;
                  }
                  else if (arg != NULL)
                  {
                      void *v = PyCapsule_GetPointer(arg, name);
  
                      if (PyErr_Occurred())
                      {
                          failure.reason = WrongType;
                          failure.detail_obj = arg;
                          Py_INCREF(arg);
                      }
                      else
                      {
                          *p = v;
                      }
                  }
  
                  break;
              }
          }
  
          if ((failure.reason == Ok || failure.reason == Overflow) && ch == 'W')
          {
              /* An ellipsis matches everything and ends the parse. */
              break;
          }
      }
  
      /* Handle parse failures appropriately. */
  
      if (failure.reason == Ok)
          return TRUE;
  
      if (failure.reason == Overflow)
      {
          /*
           * We have successfully parsed the signature but one of the arguments
           * has been found to overflow.  Raise an appropriate exception and
           * ensure we don't parse any subsequent overloads.
           */
          if (failure.overflow_arg_nr >= 0)
          {
              PyErr_Format(PyExc_OverflowError, "argument %d overflowed: %S",
                      failure.overflow_arg_nr, failure.detail_obj);
          }
          else
          {
              PyErr_Format(PyExc_OverflowError, "argument '%s' overflowed: %S",
                      failure.overflow_arg_name, failure.detail_obj);
          }
  
          /* The overflow exception has now been raised. */
          failure.reason = Raised;
      }
  
      if (failure.reason != Raised)
          add_failure(parseErrp, &failure);
  
      if (failure.reason == Raised)
      {
          Py_XDECREF(failure.detail_obj);
  
          /*
           * Discard any previous errors and flag that the exception we want the
           * user to see has been raised.
           */
          Py_XDECREF(*parseErrp);
          *parseErrp = Py_None;
          Py_INCREF(Py_None);
      }
  
      return FALSE;
  }
  
  
  /*
   * Called after a failed conversion of an integer.
   */
  static void handle_failed_int_conversion(sipParseFailure *pf, PyObject *arg)
  {
      PyObject *xtype, *xvalue, *xtb;
  
      assert(pf->reason == Ok || pf->reason == Overflow);
  
      PyErr_Fetch(&xtype, &xvalue, &xtb);
  
      if (PyErr_GivenExceptionMatches(xtype, PyExc_OverflowError) && xvalue != NULL)
      {
          /* Remove any previous overflow exception. */
          Py_XDECREF(pf->detail_obj);
  
          pf->reason = Overflow;
          pf->overflow_arg_nr = pf->arg_nr;
          pf->overflow_arg_name = pf->arg_name;
          pf->detail_obj = xvalue;
          Py_INCREF(xvalue);
      }
      else
      {
          pf->reason = WrongType;
          pf->detail_obj = arg;
          Py_INCREF(arg);
      }
  
      PyErr_Restore(xtype, xvalue, xtb);
  }
  
  
  /*
   * 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;
      Py_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 - selfarg];
  
              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':
              {
                  /* Qt receiver to connect. */
  
                  char *sig = va_arg(va, char *);
                  void **rx = va_arg(va, void **);
                  const char **slot = va_arg(va, const char **);
  
                  if (arg != NULL)
                  {
                      *rx = sip_api_convert_rx((sipWrapper *)self, sig, arg,
                              *slot, slot, 0);
  
                      if (*rx == NULL)
                          return FALSE;
                  }
  
                  break;
              }
  
          case 'Q':
              {
                  /* Qt receiver to disconnect. */
  
                  char *sig = va_arg(va, char *);
                  void **rx = va_arg(va, void **);
                  const char **slot = va_arg(va, const char **);
  
                  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;
                  Py_ssize_t *nr_elem;
  
                  td = va_arg(va, const sipTypeDef *);
                  array = va_arg(va, void **);
                  nr_elem = va_arg(va, Py_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. */
  
                  if (*fmt++ == 'E')
                      va_arg(va, void *);
  
                  va_arg(va, void *);
  
                  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 = NULL;
  
                      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)
                          return FALSE;
  
                      *keep = s;
                  }
  
                  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)
                          return FALSE;
                  }
  
                  break;
              }
  
          /*
           * Every other argument is a pointer and only differ in how many there
           * are.
           */
          case 'N':
          case 'T':
          case 'k':
          case 'K':
          case 'U':
          case 'E':
              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 QObject.
   */
  static int isQObject(PyObject *obj)
  {
      return (sipQtSupport != NULL && PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(sipQObjectType)));
  }
  
  
  /*
   * See if a Python object is a sequence of a particular type.
   */
  static int canConvertFromSequence(PyObject *seq, const sipTypeDef *td)
  {
      Py_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, Py_ssize_t *nr_elem)
  {
      int iserr = 0;
      Py_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, Py_ssize_t nr_elem,
          const sipTypeDef *td)
  {
      Py_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;
  }
  
  
  /*
   * Perform housekeeping after a C++ instance has been destroyed.
   */
  void sip_api_instance_destroyed(sipSimpleWrapper *sw)
  {
      sip_api_instance_destroyed_ex(&sw);
  }
  
  
  /*
   * Carry out actions common to all dtors.
   */
  static void sip_api_instance_destroyed_ex(sipSimpleWrapper **sipSelfp)
  {
      /* If there is no interpreter just to the minimum and get out. */
      if (sipInterpreter == NULL)
      {
          *sipSelfp = NULL;
          return;
      }
  
      SIP_BLOCK_THREADS
  
      sipSimpleWrapper *sipSelf = *sipSelfp;
  
      if (sipSelf != NULL)
      {
          PyObject *xtype, *xvalue, *xtb;
  
          /* We may be tidying up after an exception so preserve it. */
          PyErr_Fetch(&xtype, &xvalue, &xtb);
          callPyDtor(sipSelf);
          PyErr_Restore(xtype, xvalue, xtb);
  
          sipOMRemoveObject(&cppPyMap, sipSelf);
  
          /*
           * This no longer points to anything useful.  Actually it might do as
           * the partialy destroyed C++ instance may still be trying to invoke
           * reimplemented virtuals.
           */
          clear_access_func(sipSelf);
  
          /*
           * 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);
          }
  
          /*
           * Normally this is done in the generated dealloc function.  However
           * this is only called if the pointer/access function has not been
           * reset (which it has).  It acts as a guard to prevent any further
           * invocations of reimplemented virtuals.
           */
          *sipSelfp = NULL;
      }
  
      SIP_UNBLOCK_THREADS
  }
  
  
  /*
   * Clear any access function so that sip_api_get_address() will always return a
   * NULL pointer.
   */
  static void clear_access_func(sipSimpleWrapper *sw)
  {
      if (sw->access_func != NULL)
      {
          sw->access_func(sw, ReleaseGuard);
          sw->access_func = NULL;
      }
  
      sw->data = NULL;
  }
  
  
  /*
   * 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);
      }
  }
  
  
  /*
   * Detach and children of a parent.
   */
  static void detachChildren(sipWrapper *self)
  {
      while (self->first_child != NULL)
          removeFromParent(self->first_child);
  }
  
  
  /*
   * Convert a sequence index.  Return the index or a negative value if there was
   * an error.
   */
  static Py_ssize_t sip_api_convert_from_sequence_index(Py_ssize_t idx,
          Py_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 class of a type that has no explicit super-type.
   */
  static PyObject *getDefaultBase(void)
  {
      static PyObject *default_base = NULL;
  
      /* Only do this once. */
      if (default_base == NULL)
      {
          if ((default_base = PyTuple_Pack(1, (PyObject *)&sipWrapper_Type)) == NULL)
              return NULL;
      }
  
      Py_INCREF(default_base);
  
      return default_base;
  }
  
  
  /*
   * Return a tuple of the base class of a simple type that has no explicit
   * super-type.
   */
  static PyObject *getDefaultSimpleBase(void)
  {
      static PyObject *default_simple_base = NULL;
  
      /* Only do this once. */
      if (default_simple_base == NULL)
      {
          if ((default_simple_base = PyTuple_Pack(1, (PyObject *)&sipSimpleWrapper_Type)) == NULL)
              return NULL;
      }
  
      Py_INCREF(default_simple_base);
  
      return default_simple_base;
  }
  
  
  /*
   * 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,
          PyObject *type_dict, sipExportedModuleDef *client)
  {
      PyObject *py_type, *scope_dict, *name, *args;
      sipTypeDef *scope_td;
  
      /* Get the dictionary to place the type in. */
      if (cod->cod_scope.sc_flag)
      {
          scope_td = NULL;
          scope_dict = mod_dict;
      }
      else
      {
          scope_td = getGeneratedType(&cod->cod_scope, client);
          scope_dict = getScopeDict(scope_td, mod_dict, client);
  
          if (scope_dict == NULL)
              goto reterr;
      }
  
      /* Create an object corresponding to the type name. */
      if ((name = PyUnicode_FromString(sipPyNameOfContainer(cod, td))) == NULL)
          goto reterr;
  
      /* Create the type by calling the metatype. */
      if ((args = PyTuple_Pack(3, name, bases, type_dict)) == NULL)
          goto relname;
  
      /* Pass the type via the back door. */
      assert(currentType == NULL);
      currentType = td;
      py_type = PyObject_Call(metatype, args, NULL);
      currentType = NULL;
  
      if (py_type == NULL)
          goto relargs;
  
      /* Fix __qualname__ if there is a scope. */
      if (scope_td != NULL)
      {
          PyHeapTypeObject *ht;
          PyObject *qualname = get_qualname(scope_td, name);
  
          if (qualname == NULL)
              goto reltype;
  
          ht = (PyHeapTypeObject *)py_type;
  
          Py_CLEAR(ht->ht_qualname);
          ht->ht_qualname = qualname;
      }
  
      /* Add the type to the "parent" dictionary. */
      if (PyDict_SetItem(scope_dict, name, py_type) < 0)
          goto reltype;
  
      Py_DECREF(args);
      Py_DECREF(name);
  
      return py_type;
  
      /* Unwind on error. */
  
  reltype:
      Py_DECREF(py_type);
  
  relargs:
      Py_DECREF(args);
  
  relname:
      Py_DECREF(name);
  
  reterr:
      return NULL;
  }
  
  
  /*
   * Create a single class type object.
   */
  static int createClassType(sipExportedModuleDef *client, sipClassTypeDef *ctd,
          PyObject *mod_dict)
  {
      PyObject *bases, *metatype, *py_type, *type_dict;
      sipEncodedTypeDef *sup;
      int i;
  
      /* 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 = (sipTypeIsNamespace(&ctd->ctd_base) ? getDefaultSimpleBase() : getDefaultBase());
          }
          else
          {
              PyObject *supertype;
              const char *supertype_name = sipNameFromPool(client,
                      ctd->ctd_supertype);
  
              if ((supertype = findPyType(supertype_name)) == NULL)
                  goto reterr;
  
              bases = PyTuple_Pack(1, supertype);
          }
  
          if (bases == NULL)
              goto reterr;
      }
      else
      {
          int 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);
  
              /*
               * Inherit any garbage collector code rather than look for it each
               * time it is needed.
               */
              if (ctd->ctd_traverse == NULL)
                  ctd->ctd_traverse = ((sipClassTypeDef *)sup_td)->ctd_traverse;
  
              if (ctd->ctd_clear == NULL)
                  ctd->ctd_clear = ((sipClassTypeDef *)sup_td)->ctd_clear;
          }
      }
  
      /*
       * 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));
  
      /* Create the type dictionary and populate it with any non-lazy methods. */
      if ((type_dict = createTypeDict(client)) == NULL)
          goto relbases;
  
      if (sipTypeHasNonlazyMethod(&ctd->ctd_base))
      {
          PyMethodDef *pmd = ctd->ctd_container.cod_methods;
  
          for (i = 0; i < ctd->ctd_container.cod_nrmethods; ++i)
          {
              if (isNonlazyMethod(pmd) && addMethod(type_dict, pmd) < 0)
                  goto reldict;
  
              ++pmd;
          }
      }
  
      if ((py_type = createContainerType(&ctd->ctd_container, (sipTypeDef *)ctd, bases, metatype, mod_dict, type_dict, client)) == NULL)
          goto reldict;
  
      if (ctd->ctd_pyslots != NULL)
          fix_slots((PyTypeObject *)py_type, ctd->ctd_pyslots);
  
      /* 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);
      Py_DECREF(type_dict);
  
      return 0;
  
      /* Unwind after an error. */
  
  reltype:
      Py_DECREF(py_type);
  
  reldict:
      Py_DECREF(type_dict);
  
  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, *type_dict;
  
      /* 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 = getDefaultBase()) == NULL)
          goto reterr;
  
      /* Create the type dictionary. */
      if ((type_dict = createTypeDict(client)) == NULL)
          goto relbases;
  
      if (createContainerType(&mtd->mtd_container, (sipTypeDef *)mtd, bases, (PyObject *)&sipWrapperType_Type, mod_dict, type_dict, client) == NULL)
          goto reldict;
  
      /* We can now release our references. */
      Py_DECREF(bases);
      Py_DECREF(type_dict);
  
      return 0;
  
      /* Unwind after an error. */
  
  reldict:
      Py_DECREF(type_dict);
  
  relbases:
      Py_DECREF(bases);
  
  reterr:
      mtd->mtd_base.td_module = NULL;
      return -1;
  }
  
  
  /*
   * Return the module definition for a named module.
   */
  static sipExportedModuleDef *getModule(PyObject *mname_obj)
  {
      PyObject *mod;
      sipExportedModuleDef *em;
  
      /* Make sure the module is imported. */
      if ((mod = PyImport_Import(mname_obj)) == NULL)
          return NULL;
  
      /* Find the module definition. */
      for (em = moduleList; em != NULL; em = em->em_next)
          if (PyUnicode_Compare(mname_obj, em->em_nameobj) == 0)
              break;
  
      Py_DECREF(mod);
  
      if (em == NULL)
          PyErr_Format(PyExc_SystemError, "unable to find to find module: %U",
                  mname_obj);
  
      return em;
  }
  
  
  /*
   * The type unpickler.
   */
  static PyObject *unpickle_type(PyObject *obj, PyObject *args)
  {
      PyObject *mname_obj, *init_args;
      const char *tname;
      sipExportedModuleDef *em;
      int i;
  
      (void)obj;
  
      if (!PyArg_ParseTuple(args, "UsO!:_unpickle_type", &mname_obj, &tname, &PyTuple_Type, &init_args))
          return NULL;
  
      /* Get the module definition. */
      if ((em = getModule(mname_obj)) == NULL)
          return NULL;
  
      /* Find the class type object. */
      for (i = 0; i < em->em_nrtypes; ++i)
      {
          sipTypeDef *td = em->em_types[i];
  
          if (td != NULL && !sipTypeIsStub(td) && sipTypeIsClass(td))
          {
              const char *pyname = sipPyNameOfContainer(
                      &((sipClassTypeDef *)td)->ctd_container, td);
  
              if (strcmp(pyname, tname) == 0)
                  return PyObject_CallObject((PyObject *)sipTypeAsPyTypeObject(td), init_args);
          }
      }
  
      PyErr_Format(PyExc_SystemError, "unable to find to find type: %s", tname);
  
      return NULL;
  }
  
  
  /*
   * The type pickler.
   */
  static PyObject *pickle_type(PyObject *obj, PyObject *args)
  {
      sipExportedModuleDef *em;
  
      (void)args;
  
      /* 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 (init_args == NULL)
                          return 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 *obj, PyObject *args)
  {
      PyObject *mname_obj, *evalue_obj;
      const char *ename;
      sipExportedModuleDef *em;
      int i;
  
      (void)obj;
  
      if (!PyArg_ParseTuple(args, "UsO:_unpickle_enum", &mname_obj, &ename, &evalue_obj))
          return NULL;
  
      /* Get the module definition. */
      if ((em = getModule(mname_obj)) == NULL)
          return NULL;
  
      /* Find the enum type object. */
      for (i = 0; i < em->em_nrtypes; ++i)
      {
          sipTypeDef *td = em->em_types[i];
  
          if (td != NULL && !sipTypeIsStub(td) && sipTypeIsEnum(td))
              if (strcmp(sipPyNameOfEnum((sipEnumTypeDef *)td), ename) == 0)
                  return PyObject_CallFunctionObjArgs((PyObject *)sipTypeAsPyTypeObject(td), evalue_obj, NULL);
      }
  
      PyErr_Format(PyExc_SystemError, "unable to find to find enum: %s", ename);
  
      return NULL;
  }
  
  
  /*
   * The enum pickler.
   */
  static PyObject *pickle_enum(PyObject *obj, PyObject *args)
  {
      sipTypeDef *td = ((sipEnumTypeObject *)Py_TYPE(obj))->type;
  
      (void)args;
  
      return Py_BuildValue("O(Osi)", enum_unpickler, td->td_module->em_nameobj,
              sipPyNameOfEnum((sipEnumTypeDef *)td), (int)PyLong_AS_LONG(obj));
  }
  
  
  /*
   * Set the __reduce__method for a type.
   */
  static int setReduce(PyTypeObject *type, PyMethodDef *pickler)
  {
      static PyObject *rstr = NULL;
      PyObject *descr;
      int rc;
  
      if (objectify("__reduce__", &rstr) < 0)
          return -1;
  
      /* Create the method descripter. */
      if ((descr = PyDescr_NewMethod(type, pickler)) == NULL)
          return -1;
  
      /*
       * Save the method.  Note that we don't use PyObject_SetAttr() as we want
       * to bypass any lazy attribute loading (which may not be safe yet).
       */
      rc = PyType_Type.tp_setattro((PyObject *)type, rstr, descr);
  
      Py_DECREF(descr);
  
      return rc;
  }
  
  
  /*
   * Create an enum object.
   */
  static int createEnum(sipExportedModuleDef *client, sipEnumTypeDef *etd,
          int enum_nr, PyObject *mod_dict)
  {
      int rc;
      PyObject *name, *dict, *enum_obj;
  
      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)
          return -1;
  
      /* Create an object corresponding to the type name. */
      if ((name = PyUnicode_FromString(sipPyNameOfEnum(etd))) == NULL)
          return -1;
  
      /* Create the enum. */
      if (sipTypeIsEnum(&etd->etd_base))
          enum_obj = createUnscopedEnum(client, etd, name);
      else
          enum_obj = createScopedEnum(client, etd, enum_nr, name);
  
      if (enum_obj == NULL)
      {
          Py_DECREF(name);
          return -1;
      }
  
      /* Add the enum to the "parent" dictionary. */
      rc = PyDict_SetItem(dict, name, enum_obj);
  
      /* We can now release our remaining references. */
      Py_DECREF(name);
      Py_DECREF(enum_obj);
  
      return rc;
  }
  
  
  /*
   * Create an unscoped enum.
   */
  static PyObject *createUnscopedEnum(sipExportedModuleDef *client,
          sipEnumTypeDef *etd, PyObject *name)
  {
      static PyObject *bases = NULL;
      PyObject *type_dict, *args;
      sipEnumTypeObject *eto;
  
      /* Create the base type tuple if it hasn't already been done. */
      if (bases == NULL)
          if ((bases = PyTuple_Pack(1, (PyObject *)&PyLong_Type)) == NULL)
              return NULL;
  
      /* Create the type dictionary. */
      if ((type_dict = createTypeDict(client)) == NULL)
          return NULL;
  
      /* Create the type by calling the metatype. */
      args = PyTuple_Pack(3, name, bases, type_dict);
  
      Py_DECREF(type_dict);
  
      if (args == NULL)
          return NULL;
  
      /* Pass the type via the back door. */
      assert(currentType == NULL);
      currentType = &etd->etd_base;
      eto = (sipEnumTypeObject *)PyObject_Call((PyObject *)&sipEnumType_Type,
              args, NULL);
      currentType = NULL;
  
      Py_DECREF(args);
  
      if (eto == NULL)
          return NULL;
  
      if (etd->etd_pyslots != NULL)
          fix_slots((PyTypeObject *)eto, etd->etd_pyslots);
  
      /*
       * If the enum has a scope then the default __qualname__ will be incorrect.
       */
       if (etd->etd_scope >= 0)
       {
          /* Append the name of the enum to the scope's __qualname__. */
          Py_CLEAR(eto->super.ht_qualname);
          eto->super.ht_qualname = get_qualname(
                  client->em_types[etd->etd_scope], name);
  
          if (eto->super.ht_qualname == NULL)
          {
              Py_DECREF((PyObject *)eto);
              return NULL;
          }
      }
  
      return (PyObject *)eto;
  }
  
  
  /*
   * Create a scoped enum.
   */
  static PyObject *createScopedEnum(sipExportedModuleDef *client,
          sipEnumTypeDef *etd, int enum_nr, PyObject *name)
  {
      static PyObject *enum_type = NULL, *module_arg = NULL;
      static PyObject *qualname_arg = NULL;
      int i, nr_members;
      sipEnumMemberDef *enm;
      PyObject *members, *enum_obj, *args, *kw_args;
  
      /* Get the enum type if we haven't done so already. */
      if (enum_type == NULL)
      {
          if ((enum_type = import_module_attr("enum", "IntEnum")) == NULL)
              goto ret_err;
      }
  
      /* Create a dict of the members. */
      if ((members = PyDict_New()) == NULL)
          goto ret_err;
  
      /*
       * Note that the current structures for defining scoped enums are not ideal
       * as we are re-using the ones used for unscoped enums (which are designed
       * to support lazy implementations).
       */
      if (etd->etd_scope < 0)
      {
          nr_members = client->em_nrenummembers;
          enm = client->em_enummembers;
      }
      else
      {
          const sipContainerDef *cod = get_container(client->em_types[etd->etd_scope]);
  
          nr_members = cod->cod_nrenummembers;
          enm = cod->cod_enummembers;
      }
  
      for (i = 0; i < nr_members; ++i)
      {
          if (enm->em_enum == enum_nr)
          {
              PyObject *val = PyLong_FromLong(enm->em_val);
  
              if (dict_set_and_discard(members, enm->em_name, val) < 0)
                  goto rel_members;
          }
  
          ++enm;
      }
  
      if ((args = PyTuple_Pack(2, name, members)) == NULL)
          goto rel_members;
  
      if ((kw_args = PyDict_New()) == NULL)
          goto rel_args;
  
      if (objectify("module", &module_arg) < 0)
          goto rel_kw_args;
  
      if (PyDict_SetItem(kw_args, module_arg, client->em_nameobj) < 0)
          goto rel_kw_args;
  
      /*
       * If the enum has a scope then the default __qualname__ will be incorrect.
       */
       if (etd->etd_scope >= 0)
       {
          int rc;
          PyObject *qualname;
  
          if (objectify("qualname", &qualname_arg) < 0)
              goto rel_kw_args;
  
          if ((qualname = get_qualname(client->em_types[etd->etd_scope], name)) == NULL)
              goto rel_kw_args;
  
          rc = PyDict_SetItem(kw_args, qualname_arg, qualname);
  
          Py_DECREF(qualname);
  
          if (rc < 0)
              goto rel_kw_args;
      }
  
      if ((enum_obj = PyObject_Call(enum_type, args, kw_args)) == NULL)
          goto rel_kw_args;
  
      Py_DECREF(kw_args);
      Py_DECREF(args);
      Py_DECREF(members);
  
      /* Note that it isn't actually a PyTypeObject. */
      etd->etd_base.td_py_type = (PyTypeObject *)enum_obj;
  
      return enum_obj;
  
      /* Unwind on errors. */
  
  rel_kw_args:
      Py_DECREF(kw_args);
  
  rel_args:
      Py_DECREF(args);
  
  rel_members:
      Py_DECREF(members);
  
  ret_err:
      return NULL;
  }
  
  
  /*
   * Create a type dictionary for dynamic type being created in a module.
   */
  static PyObject *createTypeDict(sipExportedModuleDef *em)
  {
      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, em->em_nameobj) < 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 ((*objp = PyUnicode_FromString(s)) == 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;
  }
  
  
  /*
   * Return non-zero if a method is non-lazy, ie. it must be added to the type
   * when it is created.
   */
  static int isNonlazyMethod(PyMethodDef *pmd)
  {
      static const char *lazy[] = {
          "__getattribute__",
          "__getattr__",
          "__enter__",
          "__exit__",
          "__aenter__",
          "__aexit__",
          NULL
      };  
  
      const char **l;
  
      for (l = lazy; *l != NULL; ++l)
          if (strcmp(pmd->ml_name, *l) == 0)
              return TRUE;
  
      return FALSE;
  }
  
  
  /*
   * Add a method to a dictionary.
   */
  static int addMethod(PyObject *dict, PyMethodDef *pmd)
  {
      PyObject *descr = sipMethodDescr_New(pmd);
  
      return dict_set_and_discard(dict, pmd->ml_name, descr);
  }
  
  
  /*
   * 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. */
      for (pmd = cod->cod_methods, i = 0; i < cod->cod_nrmethods; ++i, ++pmd)
      {
          /* Non-lazy methods will already have been handled. */
          if (!sipTypeHasNonlazyMethod(td) || !isNonlazyMethod(pmd))
          {
              if (addMethod(dict, pmd) < 0)
                  return -1;
          }
      }
  
      /* Do the unscoped enum members. */
      for (enm = cod->cod_enummembers, i = 0; i < cod->cod_nrenummembers; ++i, ++enm)
      {
          PyObject *val;
  
          if (enm->em_enum < 0)
          {
              /* It's an unnamed unscoped enum. */
              val = PyLong_FromLong(enm->em_val);
          }
          else
          {
              sipTypeDef *etd = td->td_module->em_types[enm->em_enum];
  
              if (sipTypeIsScopedEnum(etd))
                  continue;
  
              val = sip_api_convert_from_enum(enm->em_val, etd);
          }
  
          if (dict_set_and_discard(dict, enm->em_name, val) < 0)
              return -1;
      }
  
      /* Do the variables. */
      for (vd = cod->cod_variables, i = 0; i < cod->cod_nrvariables; ++i, ++vd)
      {
          PyObject *descr;
  
          if (vd->vd_type == PropertyVariable)
              descr = create_property(vd);
          else
              descr = sipVariableDescr_New(vd, td, cod);
  
          if (dict_set_and_discard(dict, vd->vd_name, descr) < 0)
              return -1;
      }
  
      return 0;
  }
  
  
  /*
   * Create a Python property object from the SIP generated structure.
   */
  static PyObject *create_property(sipVariableDef *vd)
  {
      PyObject *descr, *fget, *fset, *fdel, *doc;
  
      descr = fget = fset = fdel = doc = NULL;
  
      if ((fget = create_function(vd->vd_getter)) == NULL)
          goto done;
  
      if ((fset = create_function(vd->vd_setter)) == NULL)
          goto done;
  
      if ((fdel = create_function(vd->vd_deleter)) == NULL)
          goto done;
  
      if (vd->vd_docstring == NULL)
      {
          doc = Py_None;
          Py_INCREF(doc);
      }
      else if ((doc = PyUnicode_FromString(vd->vd_docstring)) == NULL)
      {
          goto done;
      }
  
      descr = PyObject_CallFunctionObjArgs((PyObject *)&PyProperty_Type, fget,
              fset, fdel, doc, NULL);
  
  done:
      Py_XDECREF(fget);
      Py_XDECREF(fset);
      Py_XDECREF(fdel);
      Py_XDECREF(doc);
  
      return descr;
  }
  
  
  /*
   * Return a PyCFunction as an object or Py_None if there isn't one.
   */
  static PyObject *create_function(PyMethodDef *ml)
  {
      if (ml != NULL)
          return PyCFunction_New(ml, NULL);
  
      Py_INCREF(Py_None);
      return Py_None;
  }
  
  
  /*
   * 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->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.
       */
      /* TODO: Deprecate this mechanism in favour of an event handler. */
      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->wt_dict_complete = TRUE;
  
      PyType_Modified((PyTypeObject *)wt);
  
      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)->wt_td;
  
      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) || sipTypeIsScopedEnum(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)
  {
      /* Remove in v5.1. */
  
      assert(sipTypeIsEnum(td));
  
      /* If the object is an enum then it must be the right enum. */
      if (PyObject_TypeCheck((PyObject *)Py_TYPE(obj), &sipEnumType_Type))
          return (PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(td)));
  
      return PyLong_Check(obj);
  }
  
  
  /*
   * Convert a Python object implementing a named enum to an integer value.
   */
  static int sip_api_convert_to_enum(PyObject *obj, const sipTypeDef *td)
  {
      return convert_to_enum(obj, td, TRUE);
  }
  
  
  /*
   * Convert a Python object implementing a named enum (or, optionally, an int)
   * to an integer value.
   */
  static int convert_to_enum(PyObject *obj, const sipTypeDef *td, int allow_int)
  {
      int val;
  
      assert(sipTypeIsEnum(td) || sipTypeIsScopedEnum(td));
  
      if (sipTypeIsScopedEnum(td))
      {
          static PyObject *value = NULL;
          PyObject *val_obj;
  
          if (PyObject_IsInstance(obj, (PyObject *)sipTypeAsPyTypeObject(td)) <= 0)
          {
              enum_expected(obj, td);
              return -1;
          }
  
          if (objectify("value", &value) < 0)
              return -1;
  
          if ((val_obj = PyObject_GetAttr(obj, value)) == NULL)
              return -1;
  
          /* This will never overflow. */
          val = long_as_nonoverflow_int(val_obj);
  
          Py_DECREF(val_obj);
      }
      else
      {
          if (PyObject_TypeCheck((PyObject *)Py_TYPE(obj), &sipEnumType_Type))
          {
              if (!PyObject_TypeCheck(obj, sipTypeAsPyTypeObject(td)))
              {
                  enum_expected(obj, td);
                  return -1;
              }
  
              /* This will never overflow. */
              val = long_as_nonoverflow_int(obj);
          }
          else if (allow_int && PyLong_Check(obj))
          {
              val = long_as_nonoverflow_int(obj);
          }
          else
          {
              enum_expected(obj, td);
              return -1;
          }
      }
  
      return val;
  }
  
  
  /*
   * Raise an exception when failing to convert an enum because of its type.
   */
  static void enum_expected(PyObject *obj, const sipTypeDef *td)
  {
      PyErr_Format(PyExc_TypeError, "a member of enum '%s' is expected not '%s'",
              sipPyNameOfEnum((sipEnumTypeDef *)td), Py_TYPE(obj)->tp_name);
  }
  
  
  /* Convert to a C/C++ int while checking for overflow. */
  static int long_as_nonoverflow_int(PyObject *val_obj)
  {
      int old_overflow, val;
  
      old_overflow = sip_api_enable_overflow_checking(TRUE);
      val = sip_api_long_as_int(val_obj);
      sip_api_enable_overflow_checking(old_overflow);
  
      return val;
  }
  
  
  /*
   * 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) || sipTypeIsScopedEnum(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;
  }
  
  
  /*
   * Register a proxy resolver.
   */
  static int sip_api_register_proxy_resolver(const sipTypeDef *td,
          sipProxyResolverFunc resolver)
  {
      sipProxyResolver *pr = sip_api_malloc(sizeof (sipProxyResolver));
  
      if (pr == NULL)
          return -1;
  
      pr->td = td;
      pr->resolver = resolver;
      pr->next = proxyResolvers;
  
      proxyResolvers = pr;
  
      return 0;
  }
  
  
  /*
   * Report a function with invalid argument types.
   */
  static void sip_api_no_function(PyObject *parseErr, const char *func,
          const char *doc)
  {
      sip_api_no_method(parseErr, NULL, func, doc);
  }
  
  
  /*
   * Report a method/function/signal with invalid argument types.
   */
  static void sip_api_no_method(PyObject *parseErr, const char *scope,
          const char *method, const char *doc)
  {
      const char *sep = ".";
  
      if (scope == NULL)
          scope = ++sep;
  
      if (parseErr == NULL)
      {
          /*
           * If we have got this far without trying a parse then there must be no
           * overloads.
           */
          PyErr_Format(PyExc_TypeError, "%s%s%s() is a private method", scope,
                  sep, method);
      }
      else if (PyList_Check(parseErr))
      {
          PyObject *exc;
  
          /* There is an entry for each overload that was tried. */
          if (PyList_GET_SIZE(parseErr) == 1)
          {
              PyObject *detail = detail_FromFailure(
                      PyList_GET_ITEM(parseErr, 0));
  
              if (detail != NULL)
              {
                  if (doc != NULL)
                  {
                      PyObject *doc_obj = signature_FromDocstring(doc, 0);
  
                      if (doc_obj != NULL)
                      {
                          exc = PyUnicode_FromFormat("%U: %U", doc_obj, detail);
                          Py_DECREF(doc_obj);
                      }
                      else
                      {
                          exc = NULL;
                      }
                  }
                  else
                  {
                      exc = PyUnicode_FromFormat("%s%s%s(): %U", scope, sep,
                              method, detail);
                  }
  
                  Py_DECREF(detail);
              }
              else
              {
                  exc = NULL;
              }
          }
          else
          {
              static const char *summary = "arguments did not match any overloaded call:";
  
              Py_ssize_t i;
  
              if (doc != NULL)
                  exc = PyUnicode_FromString(summary);
              else
                  exc = PyUnicode_FromFormat("%s%s%s(): %s", scope, sep, method,
                          summary);
  
              for (i = 0; i < PyList_GET_SIZE(parseErr); ++i)
              {
                  PyObject *failure;
                  PyObject *detail = detail_FromFailure(
                          PyList_GET_ITEM(parseErr, i));
  
                  if (detail != NULL)
                  {
                      if (doc != NULL)
                      {
                          PyObject *doc_obj = signature_FromDocstring(doc, i);
  
                          if (doc_obj != NULL)
                          {
                              failure = PyUnicode_FromFormat("\n  %U: %U",
                                      doc_obj, detail);
  
                              Py_DECREF(doc_obj);
                          }
                          else
                          {
                              Py_XDECREF(exc);
                              exc = NULL;
                              break;
                          }
                      }
                      else
                      {
                          failure = PyUnicode_FromFormat("\n  overload %zd: %U",
                                  i + 1, detail);
                      }
  
                      Py_DECREF(detail);
  
                      PyUnicode_AppendAndDel(&exc, failure);
                  }
                  else
                  {
                      Py_XDECREF(exc);
                      exc = NULL;
                      break;
                  }
              }
          }
  
          if (exc != NULL)
          {
              PyErr_SetObject(PyExc_TypeError, exc);
              Py_DECREF(exc);
          }
      }
      else
      {
          /*
           * None is used as a marker to say that an exception has already been
           * raised.
           */
          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, Py_ssize_t line)
  {
      const char *eol;
      Py_ssize_t size = 0;
  
      /*
       * Find the start of the line.  If there is a non-default versioned
       * overload that has been enabled then it won't have an entry in the
       * docstring.  This means that the returned signature may be incorrect.
       */
      while (line-- > 0)
      {
          const char *next = strchr(doc, '\n');
  
          if (next == NULL)
              break;
  
          doc = next + 1;
      }
  
      /* Find the last closing parenthesis. */
      for (eol = doc; *eol != '\n' && *eol != '\0'; ++eol)
          if (*eol == ')')
              size = eol - doc + 1;
  
      return PyUnicode_FromStringAndSize(doc, size);
  }
  
  
  /*
   * Return a string/unicode object that describes the given failure.
   */
  static PyObject *detail_FromFailure(PyObject *failure_obj)
  {
      sipParseFailure *failure;
      PyObject *detail;
  
      failure = (sipParseFailure *)PyCapsule_GetPointer(failure_obj, NULL);
  
      switch (failure->reason)
      {
      case Unbound:
          detail = PyUnicode_FromFormat(
                  "first argument of unbound method must have type '%s'",
                  failure->detail_str);
          break;
  
      case TooFew:
          detail = PyUnicode_FromString("not enough arguments");
          break;
  
      case TooMany:
          detail = PyUnicode_FromString("too many arguments");
          break;
  
      case KeywordNotString:
          detail = PyUnicode_FromFormat(
                  "%S keyword argument name is not a string",
                  failure->detail_obj);
          break;
  
      case UnknownKeyword:
          detail = PyUnicode_FromFormat("'%U' is not a valid keyword argument",
                  failure->detail_obj);
          break;
  
      case Duplicate:
          detail = PyUnicode_FromFormat(
                  "'%U' has already been given as a positional argument",
                  failure->detail_obj);
          break;
  
      case WrongType:
          if (failure->arg_nr >= 0)
              detail = bad_type_str(failure->arg_nr, failure->detail_obj);
          else
              detail = PyUnicode_FromFormat(
                      "argument '%s' has unexpected type '%s'",
                      failure->arg_name, Py_TYPE(failure->detail_obj)->tp_name);
  
          break;
  
      case Exception:
          detail = failure->detail_obj;
  
          if (detail)
          {
              Py_INCREF(detail);
              break;
          }
  
          /* Drop through. */
  
      default:
          detail = PyUnicode_FromString("unknown reason");
      }
  
      return detail;
  }
  
  
  /*
   * Report an abstract method called with an unbound self.
   */
  static void sip_api_abstract_method(const char *classname, const char *method)
  {
      PyErr_Format(PyExc_TypeError,
              "%s.%s() is abstract and cannot be called as an unbound method",
              classname, method);
  }
  
  
  /*
   * Report a deprecated class or method.
   */
  int sip_api_deprecated(const char *classname, const char *method)
  {
      char buf[100];
  
      if (classname == NULL)
          PyOS_snprintf(buf, sizeof (buf), "%s() is deprecated", method);
      else if (method == NULL)
          PyOS_snprintf(buf, sizeof (buf), "%s constructor is deprecated",
                  classname);
      else
          PyOS_snprintf(buf, sizeof (buf), "%s.%s() is deprecated", classname,
                  method);
  
      return PyErr_WarnEx(PyExc_DeprecationWarning, buf, 1);
  }
  
  
  /*
   * Report a bad operator argument.  Only a small subset of operators need to
   * be handled (those that don't return Py_NotImplemented).
   */
  static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg,
          sipPySlotType st)
  {
      const char *sn = NULL;
  
      /* Try and get the text to match a Python exception. */
  
      switch (st)
      {
      case concat_slot:
      case iconcat_slot:
          PyErr_Format(PyExc_TypeError,
                  "cannot concatenate '%s' and '%s' objects",
                  Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name);
          break;
  
      case repeat_slot:
          sn = "*";
          break;
  
      case irepeat_slot:
          sn = "*=";
          break;
  
      default:
          sn = "unknown";
      }
  
      if (sn != NULL)
          PyErr_Format(PyExc_TypeError,
                  "unsupported operand type(s) for %s: '%s' and '%s'", sn,
                  Py_TYPE(self)->tp_name, Py_TYPE(arg)->tp_name);
  }
  
  
  /*
   * Report a sequence length that does not match the length of a slice.
   */
  static void sip_api_bad_length_for_slice(Py_ssize_t seqlen,
          Py_ssize_t slicelen)
  {
      PyErr_Format(PyExc_ValueError,
              "attempt to assign sequence of size %zd to slice of size %zd",
              seqlen, slicelen);
  }
  
  
  /*
   * Report a Python object that cannot be converted to a particular class.
   */
  static void sip_api_bad_class(const char *classname)
  {
      PyErr_Format(PyExc_TypeError,
              "cannot convert Python object to an instance of %s", classname);
  }
  
  
  /*
   * Report a Python member function with an unexpected result.
   */
  static void sip_api_bad_catcher_result(PyObject *method)
  {
      PyObject *mname, *etype, *evalue, *etraceback;
  
      /*
       * Get the current exception object if there is one.  Its string
       * representation will be used as the detail of a new exception.
       */
      PyErr_Fetch(&etype, &evalue, &etraceback);
      PyErr_NormalizeException(&etype, &evalue, &etraceback);
      Py_XDECREF(etraceback);
  
      /*
       * 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 (evalue != NULL)
      {
          PyErr_Format(etype, "invalid result from %s.%U(), %S",
                  Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname, evalue);
          Py_DECREF(evalue);
      }
      else
      {
          PyErr_Format(PyExc_TypeError, "invalid result from %s.%U()",
                  Py_TYPE(PyMethod_GET_SELF(method))->tp_name, mname);
      }
  
      Py_XDECREF(etype);
  }
  
  
  /*
   * 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.  This is
   * deprecated because it is the equivalent of sip_api_transfer_to(self, NULL).
   */
  static void sip_api_transfer_break(PyObject *self)
  {
      /* Remove in v5.1. */
  
      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))
      {
          sipSimpleWrapper *sw = (sipSimpleWrapper *)self;
  
          if (owner == NULL)
          {
              /* There is no owner. */
  
              if (sipCppHasRef(sw))
              {
                  sipResetCppHasRef(sw);
              }
              else
              {
                  Py_INCREF(sw);
                  removeFromParent((sipWrapper *)sw);
                  sipResetPyOwned(sw);
              }
  
              Py_DECREF(sw);
          }
          else if (owner == Py_None)
          {
              /*
               * The owner is a C++ instance and not a Python object (ie. there
               * is no parent) so there is an explicit extra reference to keep
               * this Python object alive.  Note that there is no way to
               * specify this from a .sip file - it is useful when embedding in
               * C/C++ applications.
               */
  
              if (!sipCppHasRef(sw))
              {
                  Py_INCREF(sw);
                  removeFromParent((sipWrapper *)sw);
                  sipResetPyOwned(sw);
  
                  sipSetCppHasRef(sw);
              }
          }
          else if (PyObject_TypeCheck(owner, (PyTypeObject *)&sipWrapper_Type))
          {
              /*
               * The owner is a Python object (ie. the C++ instance that the
               * Python object wraps).
               */
  
              if (sipCppHasRef(sw))
              {
                  sipResetCppHasRef(sw);
              }
              else
              {
                  Py_INCREF(sw);
                  removeFromParent((sipWrapper *)sw);
                  sipResetPyOwned(sw);
              }
  
              addToParent((sipWrapper *)sw, (sipWrapper *)owner);
  
              Py_DECREF(sw);
          }
      }
  }
  
  
  /*
   * Add a license to a dictionary.
   */
  static int addLicense(PyObject *dict,sipLicenseDef *lc)
  {
      int rc;
      PyObject *ldict, *proxy, *o;
  
      /* Convert the strings we use to objects if not already done. */
  
      if (objectify("__license__", &licenseName) < 0)
          return -1;
  
      if (objectify("Licensee", &licenseeName) < 0)
          return -1;
  
      if (objectify("Type", &typeName) < 0)
          return -1;
  
      if (objectify("Timestamp", &timestampName) < 0)
          return -1;
  
      if (objectify("Signature", &signatureName) < 0)
          return -1;
  
      /* We use a dictionary to hold the license information. */
      if ((ldict = PyDict_New()) == NULL)
          return -1;
  
      /* The license type is compulsory, the rest are optional. */
      if (lc->lc_type == NULL)
          goto deldict;
  
      if ((o = PyUnicode_FromString(lc->lc_type)) == NULL)
          goto deldict;
  
      rc = PyDict_SetItem(ldict,typeName,o);
      Py_DECREF(o);
  
      if (rc < 0)
          goto deldict;
  
      if (lc->lc_licensee != NULL)
      {
          if ((o = PyUnicode_FromString(lc->lc_licensee)) == NULL)
              goto deldict;
  
          rc = PyDict_SetItem(ldict,licenseeName,o);
          Py_DECREF(o);
  
          if (rc < 0)
              goto deldict;
      }
  
      if (lc->lc_timestamp != NULL)
      {
          if ((o = PyUnicode_FromString(lc->lc_timestamp)) == NULL)
              goto deldict;
  
          rc = PyDict_SetItem(ldict,timestampName,o);
          Py_DECREF(o);
  
          if (rc < 0)
              goto deldict;
      }
  
      if (lc->lc_signature != NULL)
      {
          if ((o = PyUnicode_FromString(lc->lc_signature)) == NULL)
              goto deldict;
  
          rc = PyDict_SetItem(ldict,signatureName,o);
          Py_DECREF(o);
  
          if (rc < 0)
              goto deldict;
      }
  
      /* Create a read-only proxy. */
      if ((proxy = PyDictProxy_New(ldict)) == NULL)
          goto deldict;
  
      Py_DECREF(ldict);
  
      rc = PyDict_SetItem(dict, licenseName, proxy);
      Py_DECREF(proxy);
  
      return rc;
  
  deldict:
      Py_DECREF(ldict);
  
      return -1;
  }
  
  
  /*
   * Add the void pointer instances to a dictionary.
   */
  static int addVoidPtrInstances(PyObject *dict,sipVoidPtrInstanceDef *vi)
  {
      while (vi->vi_name != NULL)
      {
          PyObject *w = sip_api_convert_from_void_ptr(vi->vi_val);
  
          if (dict_set_and_discard(dict, vi->vi_name, w) < 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)
      {
          PyObject *w;
  
          switch (ci->ci_encoding)
          {
          case 'A':
              w = PyUnicode_DecodeASCII(&ci->ci_val, 1, NULL);
              break;
  
          case 'L':
              w = PyUnicode_DecodeLatin1(&ci->ci_val, 1, NULL);
              break;
  
          case '8':
              w = PyUnicode_FromStringAndSize(&ci->ci_val, 1);
              break;
  
          default:
              w = PyBytes_FromStringAndSize(&ci->ci_val, 1);
          }
  
          if (dict_set_and_discard(dict, ci->ci_name, w) < 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)
      {
          PyObject *w;
  
          switch (si->si_encoding)
          {
          case 'A':
              w = PyUnicode_DecodeASCII(si->si_val, strlen(si->si_val), NULL);
              break;
  
          case 'L':
              w = PyUnicode_DecodeLatin1(si->si_val, strlen(si->si_val), NULL);
              break;
  
          case '8':
              w = PyUnicode_FromString(si->si_val);
              break;
  
          case 'w':
              /* The hack for wchar_t. */
  #if defined(HAVE_WCHAR_H)
              w = PyUnicode_FromWideChar((const wchar_t *)si->si_val, 1);
              break;
  #else
              raiseNoWChar();
              return -1;
  #endif
  
          case 'W':
              /* The hack for wchar_t*. */
  #if defined(HAVE_WCHAR_H)
              w = PyUnicode_FromWideChar((const wchar_t *)si->si_val,
                      wcslen((const wchar_t *)si->si_val));
              break;
  #else
              raiseNoWChar();
              return -1;
  #endif
  
          default:
              w = PyBytes_FromString(si->si_val);
          }
  
          if (dict_set_and_discard(dict, si->si_name, w) < 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)
      {
          PyObject *w = PyLong_FromLong(ii->ii_val);
  
          if (dict_set_and_discard(dict, ii->ii_name, w) < 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)
      {
          PyObject *w = PyLong_FromLong(li->li_val);
  
          if (dict_set_and_discard(dict, li->li_name, w) < 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)
      {
          PyObject *w = PyLong_FromUnsignedLong(uli->uli_val);
  
          if (dict_set_and_discard(dict, uli->uli_name, w) < 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)
      {
          PyObject *w;
  
  #if defined(HAVE_LONG_LONG)
          w = PyLong_FromLongLong(lli->lli_val);
  #else
          w = PyLong_FromLong(lli->lli_val);
  #endif
  
          if (dict_set_and_discard(dict, lli->lli_name, w) < 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)
      {
          PyObject *w;
  
  #if defined(HAVE_LONG_LONG)
          w = PyLong_FromUnsignedLongLong(ulli->ulli_val);
  #else
          w = PyLong_FromUnsignedLong(ulli->ulli_val);
  #endif
  
          if (dict_set_and_discard(dict, ulli->ulli_name, w) < 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)
      {
          PyObject *w = PyFloat_FromDouble(di->di_val);
  
          if (dict_set_and_discard(dict, di->di_name, w) < 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)
  {
      PyObject *obj;
  
      if (sipTypeIsEnum(td) || sipTypeIsScopedEnum(td))
      {
          obj = sip_api_convert_from_enum(*(int *)cppPtr, td);
      }
      else
      {
          sipConvertFromFunc cfrom;
  
          cppPtr = resolve_proxy(td, cppPtr);
  
          cfrom = get_from_convertor(td);
  
          if (cfrom != NULL)
              obj = cfrom(cppPtr, NULL);
          else
              obj = wrap_simple_instance(cppPtr, td, NULL, initflags);
      }
  
      return dict_set_and_discard(dict, name, obj);
  }
  
  
  /*
   * 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 GIL 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;
      Py_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;
  
  #ifdef WITH_THREAD
      *gil = PyGILState_Ensure();
  #endif
  
      /*
       * 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)
          sipSelf = deref_mixin(sipSelf);
  
      if (sipSelf == NULL)
          goto release_gil;
  
      /*
       * It's possible that the object's type's tp_mro is NULL.  A possible
       * circumstance is when a type has been created dynamically and the only
       * reference to it is the single instance of the type which is in the
       * process of being garbage collected.
       */
      cls = (PyObject *)Py_TYPE(sipSelf);
      mro = ((PyTypeObject *)cls)->tp_mro;
  
      if (mro == NULL)
          goto release_gil;
  
      /* Get any reimplementation. */
  
      if ((mname_obj = PyUnicode_FromString(mname)) == NULL)
          goto release_gil;
  
      /*
       * 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).  However that means we must explicitly check that the class
       * hierarchy is fully initialised.
       */
      if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(sipSelf))->wt_td) < 0)
      {
          Py_DECREF(mname_obj);
          goto release_gil;
      }
  
      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;
          }
      }
  
      assert(PyTuple_Check(mro));
  
      reimp = NULL;
  
      for (i = 0; i < PyTuple_GET_SIZE(mro); ++i)
      {
          PyObject *cls_dict, *cls_attr;
  
          cls = PyTuple_GET_ITEM(mro, i);
  
          cls_dict = ((PyTypeObject *)cls)->tp_dict;
  
          /*
           * Check any possible reimplementation is not the wrapped C++ method or
           * a default special method implementation.
           */
          if (cls_dict != NULL && (cls_attr = PyDict_GetItem(cls_dict, mname_obj)) != NULL && Py_TYPE(cls_attr) != &sipMethodDescr_Type && Py_TYPE(cls_attr) != &PyWrapperDescr_Type)
          {
              reimp = cls_attr;
              break;
          }
      }
  
      Py_DECREF(mname_obj);
  
      if (reimp != NULL)
      {
          /*
           * Emulate the behaviour of a descriptor to make sure we return a bound
           * method.
           */
          if (PyMethod_Check(reimp))
          {
              /* It's already a method but make sure it is bound. */
              if (PyMethod_GET_SELF(reimp) != NULL)
                  Py_INCREF(reimp);
              else
                  reimp = PyMethod_New(PyMethod_GET_FUNCTION(reimp),
                          (PyObject *)sipSelf);
          }
          else if (PyFunction_Check(reimp))
          {
              reimp = PyMethod_New(reimp, (PyObject *)sipSelf);
          }
          else if (Py_TYPE(reimp)->tp_descr_get)
          {
              /* It is a descriptor, so assume it will do the right thing. */
              reimp = Py_TYPE(reimp)->tp_descr_get(reimp, (PyObject *)sipSelf,
                      cls);
          }
          else
          {
              /*
               * We don't know what it is so just return and assume that an
               * appropriate exception will be raised later on.
               */
              Py_INCREF(reimp);
          }
      }
      else
      {
          /* 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;
  
  release_gil:
  #ifdef WITH_THREAD
      PyGILState_Release(*gil);
  #endif
      return NULL;
  }
  
  
  /*
   * Convert a C/C++ pointer to the object that wraps it.
   */
  static PyObject *sip_api_get_pyobject(void *cppPtr, const sipTypeDef *td)
  {
      return (PyObject *)sipOMFindObject(&cppPyMap, cppPtr, td);
  }
  
  
  /*
   * The default access function.
   */
  void *sip_api_get_address(sipSimpleWrapper *w)
  {
      return (w->access_func != NULL) ? w->access_func(w, GuardedPointer) : w->data;
  }
  
  
  /*
   * The access function for handwritten access functions.
   */
  static void *explicit_access_func(sipSimpleWrapper *sw, AccessFuncOp op)
  {
      typedef void *(*explicitAccessFunc)(void);
  
      if (op == ReleaseGuard)
          return NULL;
  
      return ((explicitAccessFunc)(sw->data))();
  }
  
  
  /*
   * The access function for indirect access.
   */
  static void *indirect_access_func(sipSimpleWrapper *sw, AccessFuncOp op)
  {
      void *addr;
  
      switch (op)
      {
      case UnguardedPointer:
          addr = sw->data;
          break;
  
      case GuardedPointer:
          addr = *((void **)sw->data);
          break;
  
      default:
          addr = NULL;
      }
  
      return addr;
  }
  
  
  /*
   * Get the C/C++ pointer for a complex object.  Note that not casting the C++
   * pointer is a bug.  However this would only ever be called by PyQt3 signal
   * emitter code and PyQt doesn't contain anything that multiply inherits from
   * QObject.
   */
  static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw)
  {
      return getComplexCppPtr(sw, NULL);
  }
  
  
  /*
   * Get the C/C++ pointer for a complex object and optionally cast it to the
   * required type.
   */
  static void *getComplexCppPtr(sipSimpleWrapper *sw, const sipTypeDef *td)
  {
      if (!sipIsDerived(sw))
      {
          PyErr_SetString(PyExc_RuntimeError,
                  "no access to protected functions or signals for objects not created from Python");
  
          return NULL;
      }
  
      return sip_api_get_cpp_ptr(sw, td);
  }
  
  
  /*
   * Get the C/C++ pointer from a wrapper and optionally cast it to the required
   * type.
   */
  void *sip_api_get_cpp_ptr(sipSimpleWrapper *sw, const sipTypeDef *td)
  {
      void *ptr = sip_api_get_address(sw);
  
      if (checkPointer(ptr, sw) < 0)
          return NULL;
  
      if (td != NULL)
      {
          if (PyObject_TypeCheck((PyObject *)sw, sipTypeAsPyTypeObject(td)))
              ptr = cast_cpp_ptr(ptr, Py_TYPE(sw), td);
          else
              ptr = NULL;
  
          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)->wt_td)->ctd_cast;
  
      /* C structures and base classes don't have cast functions. */
      if (cast != NULL)
          ptr = (*cast)(ptr, dst_type);
  
      return ptr;
  }
  
  
  /*
   * Check that a pointer is non-NULL.
   */
  static int checkPointer(void *ptr, sipSimpleWrapper *sw)
  {
      if (ptr == NULL)
      {
          PyErr_Format(PyExc_RuntimeError, (sipWasCreated(sw) ?
                          "wrapped C/C++ object of type %s has been deleted" :
                          "super-class __init__() of type %s was never called"),
                  Py_TYPE(sw)->tp_name);
          return -1;
      }
  
      return 0;
  }
  
  
  /*
   * Keep an extra reference to an object.
   */
  static void sip_api_keep_reference(PyObject *self, int key, PyObject *obj)
  {
      PyObject *dict, *key_obj;
  
      /*
       * If there isn't a "self" to keep the extra reference for later garbage
       * collection then just take a reference and let it leak.
       */
      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 ((key_obj = PyLong_FromLong(key)) != 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);
      }
  }
  
  
  /*
   * Get an object that has an extra reference.
   */
  static PyObject *sip_api_get_reference(PyObject *self, int key)
  {
      PyObject *dict, *key_obj, *obj;
  
      /* Get the extra references dictionary if there is one. */
      if ((dict = ((sipSimpleWrapper *)self)->extra_refs) == NULL)
          return NULL;
  
      if ((key_obj = PyLong_FromLong(key)) == NULL)
          return NULL;
  
      obj = PyDict_GetItem(dict, key_obj);
      Py_DECREF(key_obj);
      Py_XINCREF(obj);
  
      return obj;
  }
  
  
  /*
   * Return TRUE if an object is owned by Python.  Note that this isn't
   * implemented as a macro in sip.h because the position of the sw_flags field
   * is dependent on the version of Python.
   */
  static int sip_api_is_owned_by_python(sipSimpleWrapper *sw)
  {
      return sipIsPyOwned(sw);
  }
  
  
  /*
   * Return TRUE if the type of a C++ instance is a derived class.  Note that
   * this isn't implemented as a macro in sip.h because the position of the
   * sw_flags field is dependent on the version of Python.
   */
  static int sip_api_is_derived_class(sipSimpleWrapper *sw)
  {
      return sipIsDerived(sw);
  }
  
  
  /*
   * Get the user defined object from a wrapped object.  Note that this isn't
   * implemented as a macro in sip.h because the position of the user field is
   * dependent on the version of Python.
   */
  static PyObject *sip_api_get_user_object(const sipSimpleWrapper *sw)
  {
      return sw->user;
  }
  
  
  /*
   * Set the user defined object in a wrapped object.  Note that this isn't
   * implemented as a macro in sip.h because the position of the user field is
   * dependent on the version of Python.
   */
  static void sip_api_set_user_object(sipSimpleWrapper *sw, PyObject *user)
  {
      sw->user = user;
  }
  
  
  /*
   * 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(td == NULL || sipTypeIsClass(td) || sipTypeIsMapped(td));
  
      if (td == NULL)
      {
          /*
           * The type must be /External/ and the module that contains the
           * implementation hasn't been imported.
           */
          ok = FALSE;
      }
      else 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.
   */
  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;
      sipConvertFromFunc cfrom;
  
      assert(sipTypeIsClass(td) || sipTypeIsMapped(td));
  
      /* Handle None. */
      if (cpp == NULL)
      {
          Py_INCREF(Py_None);
          return Py_None;
      }
  
      cpp = resolve_proxy(td, cpp);
  
      cfrom = get_from_convertor(td);
  
      if (cfrom != NULL)
          return cfrom(cpp, transferObj);
  
      /*
       * See if we have already wrapped it.  Invoking sub-class code can be
       * expensive so we check the cache first, even though the sub-class code
       * might perform a down-cast.
       */
      if ((py = sip_api_get_pyobject(cpp, td)) == NULL && sipTypeHasSCC(td))
      {
          void *orig_cpp = cpp;
          const sipTypeDef *orig_td = td;
  
          /* Apply the sub-class convertor. */
          td = convertSubClass(td, &cpp);
  
          /*
           * If the sub-class convertor has done something then check the cache
           * again using the modified values.
           */
          if (cpp != orig_cpp || td != orig_td)
              py = sip_api_get_pyobject(cpp, td);
      }
  
      if (py != NULL)
          Py_INCREF(py);
      else if ((py = wrap_simple_instance(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;
      sipConvertFromFunc cfrom;
  
      /* Handle None. */
      if (cpp == NULL)
      {
          Py_INCREF(Py_None);
          return Py_None;
      }
  
      cpp = resolve_proxy(td, cpp);
  
      cfrom = get_from_convertor(td);
  
      if (cfrom != NULL)
      {
          PyObject *res = 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 we are wrapping a
               * class.
               */
              if (transferObj == NULL || transferObj == Py_None)
                  release(cpp, td, 0);
          }
  
          return res;
      }
  
      /* 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 wrap_simple_instance(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 void *tdp = &module_searched->em_types[etd->et_nr];
  
              if (tdp == 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)
  {
      /* Remove in v5.1. */
  
      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)
  {
      /* Remove in v5.1. */
  
      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 unscoped enum.  This is
   * deprecated.
   */
  static PyTypeObject *sip_api_find_named_enum(const char *type)
  {
      /* Remove in v5.1. */
  
      const sipTypeDef *td = sip_api_find_type(type);
  
      if (td != NULL && sipTypeIsEnum(td))
          return sipTypeAsPyTypeObject(td);
  
      return NULL;
  }
  
  
  /*
   * Save the components of a Python method.
   */
  void sipSaveMethod(sipPyMethod *pm, PyObject *meth)
  {
      pm->mfunc = PyMethod_GET_FUNCTION(meth);
      pm->mself = PyMethod_GET_SELF(meth);
  }
  
  
  /*
   * Call a hook.
   */
  static void sip_api_call_hook(const char *hookname)
  {
      PyObject *dictofmods, *mod, *dict, *hook, *res;
   
      /* Get the dictionary of modules. */
      if ((dictofmods = PyImport_GetModuleDict()) == NULL)
          return;
   
      /* Get the builtins module. */
      if ((mod = PyDict_GetItemString(dictofmods, "builtins")) == 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_Call(hook, empty_tuple, 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)
  {
      /* Handle the trivial case. */
      if (*cppPtr == NULL)
          return NULL;
  
      /* Try the conversions until told to stop. */
      while (convertPass(&td, cppPtr))
          ;
  
      return td;
  }
  
  
  /*
   * Do a single pass through the available convertors.
   */
  static int convertPass(const sipTypeDef **tdp, void **cppPtr)
  {
      PyTypeObject *py_type = sipTypeAsPyTypeObject(*tdp);
      sipExportedModuleDef *em;
  
      /*
       * 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)
          {
              PyTypeObject *base_type = sipTypeAsPyTypeObject(scc->scc_basetype);
  
              /*
               * 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, base_type))
              {
                  void *ptr;
                  const sipTypeDef *sub_td;
  
                  ptr = cast_cpp_ptr(*cppPtr, py_type, scc->scc_basetype);
  
                  if ((sub_td = (*scc->scc_convertor)(&ptr)) != NULL)
                  {
                      PyTypeObject *sub_type = sipTypeAsPyTypeObject(sub_td);
  
                      /*
                       * 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 (!PyType_IsSubtype(py_type, sub_type))
                      {
                          *tdp = sub_td;
                          *cppPtr = ptr;
  
                          /*
                           * Finally we allow the convertor to return a type that
                           * is apparently unrelated to the current convertor.
                           * This causes the whole process to be restarted with
                           * the new values.  The use case is PyQt's QLayoutItem.
                           */
                          return !PyType_IsSubtype(sub_type, base_type);
                      }
                  }
              }
  
              ++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 FALSE;
  }
  
  
  /*
   * 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)
  {
      /* Remove in v5.1. */
  
      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)
  {
      /* Remove in v5.1. */
  
      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 = wrap_simple_instance(ptr, td, NULL, SIP_PY_OWNED);
  
      PyErr_SetObject((PyObject *)sipTypeAsPyTypeObject(td), self);
  
      Py_XDECREF(self);
  
      SIP_UNBLOCK_THREADS
  }
  
  
  /*
   * Return the generated type structure of an encoded type.
   */
  static sipTypeDef *getGeneratedType(const sipEncodedTypeDef *enc,
          sipExportedModuleDef *em)
  {
      if (enc->sc_module == 255)
          return em->em_types[enc->sc_type];
  
      return em->em_imports[enc->sc_module].im_imported_types[enc->sc_type].it_td;
  }
  
  
  /*
   * Return the generated class type structure of a class's super-class.
   */
  sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc,
          const sipClassTypeDef *ctd)
  {
      return (sipClassTypeDef *)getGeneratedType(enc, ctd->ctd_base.td_module);
  }
  
  
  /*
   * 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))
      {
          const sipClassTypeDef *ctd;
  
          ctd = (sipClassTypeDef *)((sipWrapperType *)(py_type))->wt_td;
  
          slot = findSlotInClass(ctd, st);
      }
      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 = findSlotInSlotList(etd->etd_pyslots, st);
      }
  
      return slot;
  }
  
  
  /*
   * Find a particular slot function in a class hierarchy.
   */
  static void *findSlotInClass(const sipClassTypeDef *ctd, sipPySlotType st)
  {
      void *slot;
  
      if (ctd->ctd_pyslots != NULL)
          slot = findSlotInSlotList(ctd->ctd_pyslots, st);
      else
          slot = NULL;
  
      if (slot == NULL)
      {
          sipEncodedTypeDef *sup;
  
          /* Search any super-types. */
          if ((sup = ctd->ctd_supers) != NULL)
          {
              do
              {
                  const sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(
                          sup, ctd);
  
                  slot = findSlotInClass(sup_ctd, st);
              }
              while (slot == NULL && !sup++->sc_flag);
          }
      }
  
      return slot;
  }
  
  
  /*
   * Find a particular slot function in a particular type.
   */
  static void *findSlotInSlotList(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))->wt_td;
  
      return (sipNotInMap(self) ? NULL : sip_api_get_address(self));
  }
  
  
  /*
   * 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 ((args = PyTuple_Pack(2, arg1, arg2)) == 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, Py_ssize_t arg1,
          PyObject *arg2, sipPySlotType st)
  {
      int (*f)(PyObject *, PyObject *);
      int res;
  
      f = (int (*)(PyObject *, PyObject *))findSlot(self, st);
  
      if (f != NULL)
      {
          PyObject *args;
  
          /*
           * Slot handlers require a single PyObject *.  The second argument is
           * optional.
           */
          if (arg2 == NULL)
              args = PyLong_FromSsize_t(arg1);
          else
              args = Py_BuildValue("(nO)", arg1, arg2);
  
          if (args == NULL)
              return -1;
  
          res = f(self, args);
          Py_DECREF(args);
      }
      else
      {
          PyErr_SetNone(PyExc_NotImplementedError);
          res = -1;
      }
  
      return res;
  }
  
  
  /*
   * The metatype alloc slot.
   */
  static PyObject *sipWrapperType_alloc(PyTypeObject *self, Py_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)
      {
          assert(!sipTypeIsEnum(currentType));
  
          ((sipWrapperType *)o)->wt_td = currentType;
  
          if (sipTypeIsClass(currentType))
          {
              const sipClassTypeDef *ctd = (const sipClassTypeDef *)currentType;
              const char *docstring = ctd->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, ctd);
  
              /* Patch any mixin initialiser. */
              if (ctd->ctd_init_mixin != NULL)
                  ((PyTypeObject *)o)->tp_init = ctd->ctd_init_mixin;
          }
      }
  
      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->wt_td == NULL)
      {
          PyTypeObject *base = ((PyTypeObject *)self)->tp_base;
  
          self->wt_user_type = TRUE;
  
          /*
           * 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))
          {
              /* TODO: Deprecate this mechanism in favour of an event handler. */
              sipNewUserTypeFunc new_user_type_handler;
  
              self->wt_td = ((sipWrapperType *)base)->wt_td;
  
              if (self->wt_td != NULL)
              {
                  /* Call any new type handler. */
                  new_user_type_handler = find_new_user_type_handler(
                          (sipWrapperType *)sipTypeAsPyTypeObject(self->wt_td));
  
                  if (new_user_type_handler != NULL)
                      if (new_user_type_handler(self) < 0)
                          return -1;
              }
          }
      }
      else
      {
          /*
           * We must be a generated type so remember the type object in the
           * generated type structure.
           */
          assert(self->wt_td->td_py_type == NULL);
  
          self->wt_td->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)->wt_td) < 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)->wt_td) < 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)
  {
      sipTypeDef *td = wt->wt_td;
  
      (void)args;
      (void)kwds;
  
      /* 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 (add_all_lazy_attrs(td) < 0)
          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(get_container(td), 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(get_container(td), td));
  
          return NULL;
      }
  
      /*
       * See if the object is being created explicitly rather than being wrapped.
       */
      if (!sipIsPending())
      {
          /*
           * 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(get_container(td), td));
  
              return NULL;
          }
  
          /* See if it is an abstract type. */
          if (sipTypeIsAbstract(td) && !wt->wt_user_type && ((sipClassTypeDef *)td)->ctd_init_mixin == NULL)
          {
              PyErr_Format(PyExc_TypeError,
                      "%s.%s represents a C++ abstract class and cannot be instantiated",
                      sipNameOfModule(td->td_module),
                      sipPyNameOfContainer(get_container(td), td));
  
              return NULL;
          }
      }
  
      /* Call the standard super-type new. */
      return PyBaseObject_Type.tp_new((PyTypeObject *)wt, empty_tuple, NULL);
  }
  
  
  /*
   * The instance init slot.
   */
  static int sipSimpleWrapper_init(sipSimpleWrapper *self, PyObject *args,
          PyObject *kwds)
  {
      void *sipNew;
      int sipFlags, from_cpp = TRUE;
      sipWrapper *owner;
      sipWrapperType *wt = (sipWrapperType *)Py_TYPE(self);
      sipTypeDef *td = wt->wt_td;
      sipClassTypeDef *ctd = (sipClassTypeDef *)td;
      PyObject *unused = NULL;
      sipFinalFunc final_func = find_finalisation(ctd);
  
      /* Check for an existing C++ instance waiting to be wrapped. */
      if (sipGetPending(&sipNew, &owner, &sipFlags) < 0)
          return -1;
  
      if (sipNew == NULL)
      {
          PyObject *parseErr = NULL, **unused_p = NULL;
  
          /* See if we are interested in any unused keyword arguments. */
          if (sipTypeCallSuperInit(&ctd->ctd_base) || final_func != NULL || kw_handler != NULL)
              unused_p = &unused;
  
          /* 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->wt_iextend;
  
              /*
               * 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,
                          (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;
          }
  
          /* The instance was created from Python. */
          from_cpp = FALSE;
      }
  
      /* Handler any owner if the type supports the concept. */
      if (PyObject_TypeCheck((PyObject *)self, (PyTypeObject *)&sipWrapper_Type))
      {
          /*
           * The application may be doing something very unadvisable (like
           * calling __init__() for a second time), so make sure we don't already
           * have a parent.
           */
          removeFromParent((sipWrapper *)self);
  
          if (owner != NULL)
          {
              assert(PyObject_TypeCheck((PyObject *)owner, (PyTypeObject *)&sipWrapper_Type));
  
              addToParent((sipWrapper *)self, (sipWrapper *)owner);
          }
      }
  
      self->data = sipNew;
      self->sw_flags = sipFlags | SIP_CREATED;
  
      /* Set the access function. */
      if (sipIsAccessFunc(self))
          self->access_func = explicit_access_func;
      else if (sipIsIndirect(self))
          self->access_func = indirect_access_func;
      else
          self->access_func = NULL;
  
      if (!sipNotInMap(self))
          sipOMAddObject(&cppPyMap, self);
  
      /* If we are wrapping an instance returned from C/C++ then we are done. */
      if (from_cpp)
      {
          /*
           * Invoke any event handlers for instances that are accessed directly.
           */
          if (self->access_func == NULL)
          {
              sipEventHandler *eh;
  
              for (eh = event_handlers[sipEventWrappedInstance]; eh != NULL; eh = eh->next)
              {
                  if (is_subtype(ctd, eh->ctd))
                  {
                      sipWrappedInstanceEventHandler handler = (sipWrappedInstanceEventHandler)eh->handler;
  
                      handler(sipNew);
                  }
              }
          }
  
          return 0;
      }
  
      /* Call any finalisation code. */
      if (final_func != NULL)
      {
          PyObject *new_unused = NULL, **new_unused_p;
  
          if (unused == NULL || unused != kwds)
          {
              /*
               * There are no unused arguments or we have already created a dict
               * containing the unused sub-set, so there is no need to create
               * another.
               */
              new_unused_p = NULL;
          }
          else
          {
              /*
               * All of the keyword arguments are unused, so if some of them are
               * now going to be used then a new dict will be needed.
               */
              new_unused_p = &new_unused;
          }
              
          if (final_func((PyObject *)self, sipNew, unused, new_unused_p) < 0)
          {
              Py_XDECREF(unused);
              return -1;
          }
  
          if (new_unused != NULL)
          {
              Py_DECREF(unused);
              unused = new_unused;
          }
      }
  
      /* Call the handler if we have one.  Remove this in SIP v5. */
      if (kw_handler != NULL && unused != NULL && isQObject((PyObject *)self))
      {
          int rc = kw_handler((PyObject *)self, sipNew, unused);
  
          /*
           * A handler will always consume all unused keyword arguments (or raise
           * an exception) so discard the dict now.
           */
          Py_DECREF(unused);
  
          if (rc < 0)
              return -1;
  
          unused = NULL;
      }
  
      /* See if we should call the equivalent of super().__init__(). */
      if (sipTypeCallSuperInit(&ctd->ctd_base))
      {
          PyObject *next;
  
          /* Find the next type in the MRO. */
          next = next_in_mro((PyObject *)self,
                  (PyObject *)&sipSimpleWrapper_Type);
  
          /*
           * If the next type in the MRO is object then take a shortcut by not
           * calling super().__init__() but emulating object.__init__() instead.
           * This will be the most common case and also allows us to generate a
           * better exception message if there are unused keyword arguments.  The
           * disadvantage is that the exception message will be different if
           * there is a mixin.
           */
          if (next != (PyObject *)&PyBaseObject_Type)
          {
              int rc = super_init((PyObject *)self, empty_tuple, unused, next);
  
              Py_XDECREF(unused);
  
              return rc;
          }
      }
  
      if (unused_backdoor != NULL)
      {
          /*
           * We are being called by a mixin's __init__ so save any unused
           * arguments for it to pass on to the main class's __init__.
           */
          *unused_backdoor = unused;
      }
      else if (unused != NULL)
      {
          /* We shouldn't have any unused keyword arguments. */
          if (PyDict_Size(unused) != 0)
          {
              PyObject *key, *value;
              Py_ssize_t pos = 0;
  
              /* Just report one of the unused arguments. */
              PyDict_Next(unused, &pos, &key, &value);
  
              PyErr_Format(PyExc_TypeError,
                      "'%S' is an unknown keyword argument", key);
  
              Py_DECREF(unused);
  
              return -1;
          }
  
          Py_DECREF(unused);
      }
  
      return 0;
  }
  
  
  /*
   * Get the C++ address of a mixin.
   */
  static void *sip_api_get_mixin_address(sipSimpleWrapper *w,
          const sipTypeDef *td)
  {
      PyObject *mixin;
      void *cpp;
  
      if ((mixin = PyObject_GetAttrString((PyObject *)w, sipTypeName(td))) == NULL)
      {
          PyErr_Clear();
          return NULL;
      }
  
      cpp = sip_api_get_address((sipSimpleWrapper *)mixin);
  
      Py_DECREF(mixin);
  
      return cpp;
  }
  
  
  /*
   * Initialise a mixin.
   */
  static int sip_api_init_mixin(PyObject *self, PyObject *args, PyObject *kwds,
          const sipClassTypeDef *ctd)
  {
      int rc;
      Py_ssize_t pos;
      PyObject *unused, *mixin, *mixin_name, *key, *value;
      PyTypeObject *self_wt = sipTypeAsPyTypeObject(((sipWrapperType *)Py_TYPE(self))->wt_td);
      PyTypeObject *wt = sipTypeAsPyTypeObject(&ctd->ctd_base);
  
      static PyObject *double_us = NULL;
  
      if (objectify("__", &double_us) < 0)
          return -1;
  
      /* If we are not a mixin to another wrapped class then behave as normal. */
      if (PyType_IsSubtype(self_wt, wt))
          return super_init(self, args, kwds, next_in_mro(self, (PyObject *)wt));
  
      /*
       * Create the mixin instance.  Retain the positional arguments for the
       * super-class.  Remember that, even though the mixin appears after the
       * main class in the MRO, it appears before sipWrapperType where the main
       * class's arguments are actually parsed.
       */
      unused = NULL;
      unused_backdoor = &unused;
      mixin = PyObject_Call((PyObject *)wt, empty_tuple, kwds);
      unused_backdoor = NULL;
  
      if (mixin == NULL)
          goto gc_unused;
  
      /* Make sure the mixin can find the main instance. */
      ((sipSimpleWrapper *)mixin)->mixin_main = self;
      Py_INCREF(self);
  
      if ((mixin_name = PyUnicode_FromString(sipTypeName(&ctd->ctd_base))) == NULL)
      {
          Py_DECREF(mixin);
          goto gc_unused;
      }
  
      rc = PyObject_SetAttr(self, mixin_name, mixin);
      Py_DECREF(mixin);
  
      if (rc < 0)
          goto gc_mixin_name;
  
      /* Add the mixin's useful attributes to the main class. */
      pos = 0;
  
      while (PyDict_Next(wt->tp_dict, &pos, &key, &value))
      {
          /* Don't replace existing values. */
          if (PyDict_Contains(Py_TYPE(self)->tp_dict, key) != 0)
              continue;
  
          /* Skip values with names that start with double underscore. */
          if (!PyUnicode_Check(key))
              continue;
  
          /*
           * Despite what the docs say this returns a Py_ssize_t - although the
           * docs are probably right.
           */
          rc = (int)PyUnicode_Tailmatch(key, double_us, 0, 2, -1);
  
          if (rc < 0)
              goto gc_mixin_name;
  
          if (rc > 0)
              continue;
  
          if (PyObject_IsInstance(value, (PyObject *)&sipMethodDescr_Type))
          {
              if ((value = sipMethodDescr_Copy(value, mixin_name)) == NULL)
                  goto gc_mixin_name;
          }
          else if (PyObject_IsInstance(value, (PyObject *)&sipVariableDescr_Type))
          {
              if ((value = sipVariableDescr_Copy(value, mixin_name)) == NULL)
                  goto gc_mixin_name;
          }
          else
          {
              Py_INCREF(value);
          }
  
          rc = PyDict_SetItem(Py_TYPE(self)->tp_dict, key, value);
  
          Py_DECREF(value);
  
          if (rc < 0)
              goto gc_mixin_name;
      }
  
      Py_DECREF(mixin_name);
  
      /* Call the super-class's __init__ with any remaining arguments. */
      rc = super_init(self, args, unused, next_in_mro(self, (PyObject *)wt));
      Py_XDECREF(unused);
  
      return rc;
  
  gc_mixin_name:
      Py_DECREF(mixin_name);
  
  gc_unused:
      Py_XDECREF(unused);
  
      return -1;
  }
  
  
  /*
   * Return the next in the MRO of an instance after a given type.
   */
  static PyObject *next_in_mro(PyObject *self, PyObject *after)
  {
      Py_ssize_t i;
      PyObject *mro;
  
      mro = Py_TYPE(self)->tp_mro;
      assert(PyTuple_Check(mro));
  
      for (i = 0; i < PyTuple_GET_SIZE(mro); ++i)
          if (PyTuple_GET_ITEM(mro, i) == after)
              break;
  
      /* Assert that we have found ourself and that we are not the last. */
      assert(i + 1 < PyTuple_GET_SIZE(mro));
  
      return PyTuple_GET_ITEM(mro, i + 1);
  }
  
  
  /*
   * Call the equivalent of super()__init__() of an instance.
   */
  static int super_init(PyObject *self, PyObject *args, PyObject *kwds,
          PyObject *type)
  {
      int i;
      PyObject *init, *init_args, *init_res;
  
      if ((init = PyObject_GetAttr(type, init_name)) == NULL)
          return -1;
  
      if ((init_args = PyTuple_New(1 + PyTuple_GET_SIZE(args))) == NULL)
      {
          Py_DECREF(init);
          return -1;
      }
  
      PyTuple_SET_ITEM(init_args, 0, self);
      Py_INCREF(self);
  
      for (i = 0; i < PyTuple_GET_SIZE(args); ++i)
      {
          PyObject *arg = PyTuple_GET_ITEM(args, i);
  
          PyTuple_SET_ITEM(init_args, 1 + i, arg);
          Py_INCREF(arg);
      }
  
      init_res = PyObject_Call(init, init_args, kwds);
      Py_DECREF(init_args);
      Py_DECREF(init);
      Py_XDECREF(init_res);
  
      return (init_res != NULL) ? 0 : -1;
  }
  
  
  /*
   * Find any finalisation function for a class, searching its super-classes if
   * necessary.
   */
  static sipFinalFunc find_finalisation(sipClassTypeDef *ctd)
  {
      sipEncodedTypeDef *sup;
  
      if (ctd->ctd_final != NULL)
          return ctd->ctd_final;
  
      if ((sup = ctd->ctd_supers) != NULL)
          do
          {
              sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd);
              sipFinalFunc func;
  
              if ((func = find_finalisation(sup_ctd)) != NULL)
                  return func;
          }
          while (!sup++->sc_flag);
  
      return NULL;
  }
  
  
  /*
   * Find any new user type handler function for a class, searching its
   * super-classes if necessary.
   */
  static sipNewUserTypeFunc find_new_user_type_handler(sipWrapperType *wt)
  {
      sipEncodedTypeDef *sup;
      sipClassTypeDef *ctd;
  
      if (wt->wt_new_user_type_handler != NULL)
          return wt->wt_new_user_type_handler;
  
      ctd = (sipClassTypeDef *)wt->wt_td;
  
      if ((sup = ctd->ctd_supers) != NULL)
      {
          do
          {
              sipTypeDef *sup_td = getGeneratedType(sup, ctd->ctd_base.td_module);
              sipNewUserTypeFunc func;
  
              wt = (sipWrapperType *)sipTypeAsPyTypeObject(sup_td);
  
              if ((func = find_new_user_type_handler(wt)) != NULL)
                  return func;
          }
          while (!sup++->sc_flag);
      }
  
      return NULL;
  }
  
  
  /*
   * The instance traverse slot.
   */
  static int sipSimpleWrapper_traverse(sipSimpleWrapper *self, visitproc visit,
          void *arg)
  {
      int vret;
      void *ptr;
      const sipClassTypeDef *ctd;
  
      /* Call any handwritten traverse code. */
      if ((ptr = getPtrTypeDef(self, &ctd)) != NULL)
          if (ctd->ctd_traverse != NULL)
              if ((vret = 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;
  
      if (self->mixin_main != NULL)
          if ((vret = visit(self->mixin_main, 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 any handwritten clear code. */
      if ((ptr = getPtrTypeDef(self, &ctd)) != NULL)
          if (ctd->ctd_clear != NULL)
              vret = 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);
  
      /* Remove any mixin main. */
      tmp = self->mixin_main;
      self->mixin_main = NULL;
      Py_XDECREF(tmp);
  
      return vret;
  }
  
  
  /*
   * The instance get buffer slot.
   */
  static int sipSimpleWrapper_getbuffer(sipSimpleWrapper *self, Py_buffer *buf,
          int flags)
  {
      void *ptr;
      const sipClassTypeDef *ctd;
  
      if ((ptr = getPtrTypeDef(self, &ctd)) == NULL)
          return -1;
  
      if (sipTypeUseLimitedAPI(&ctd->ctd_base))
      {
          sipGetBufferFuncLimited getbuffer = (sipGetBufferFuncLimited)ctd->ctd_getbuffer;
          sipBufferDef bd;
  
          /*
           * Ensure all fields have a default value.  This means that extra
           * fields can be appended in the future that older handwritten code
           * doesn't know about.
           */
          memset(&bd, 0, sizeof(sipBufferDef));
  
          if (getbuffer((PyObject *)self, ptr, &bd) < 0)
              return -1;
  
          return PyBuffer_FillInfo(buf, (PyObject *)self, bd.bd_buffer,
                  bd.bd_length, bd.bd_readonly, flags);
      }
  
      return ctd->ctd_getbuffer((PyObject *)self, ptr, buf, flags);
  }
  
  
  /*
   * The instance release buffer slot.
   */
  static void sipSimpleWrapper_releasebuffer(sipSimpleWrapper *self,
          Py_buffer *buf)
  {
      void *ptr;
      const sipClassTypeDef *ctd;
  
      if ((ptr = getPtrTypeDef(self, &ctd)) == NULL)
          return;
  
      if (sipTypeUseLimitedAPI(&ctd->ctd_base))
      {
          sipReleaseBufferFuncLimited releasebuffer = (sipReleaseBufferFuncLimited)ctd->ctd_releasebuffer;
  
          releasebuffer((PyObject *)self, ptr);
  
          return;
      }
  
      ctd->ctd_releasebuffer((PyObject *)self, ptr, buf);
  }
  
  
  /*
   * The instance dealloc slot.
   */
  static void sipSimpleWrapper_dealloc(sipSimpleWrapper *self)
  {
      forgetObject(self);
  
      /*
       * Now that the C++ object no longer exists we can tidy up the Python
       * object.  We used to do this first but that meant lambda slots were
       * removed too soon (if they were connected to QObject.destroyed()).
       */
      sipSimpleWrapper_clear(self);
  
      /* Call the standard super-type dealloc. */
      PyBaseObject_Type.tp_dealloc((PyObject *)self);
  }
  
  
  /*
   * The type call slot.
   */
  static PyObject *slot_call(PyObject *self, PyObject *args, PyObject *kw)
  {
      PyObject *(*f)(PyObject *, PyObject *, PyObject *);
  
      f = (PyObject *(*)(PyObject *, PyObject *, PyObject *))findSlot(self, call_slot);
  
      assert(f != NULL);
  
      return f(self, args, kw);
  }
  
  
  /*
   * The sequence type item slot.
   */
  static PyObject *slot_sq_item(PyObject *self, Py_ssize_t n)
  {
      PyObject *(*f)(PyObject *,PyObject *);
      PyObject *arg, *res;
  
      if ((arg = PyLong_FromSsize_t(n)) == 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, Py_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 __dict__ getter.
   */
  static PyObject *sipSimpleWrapper_get_dict(sipSimpleWrapper *sw, void *closure)
  {
      (void)closure;
  
      /* 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(sipSimpleWrapper *sw, PyObject *value,
          void *closure)
  {
      (void)closure;
  
      /* 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__", (getter)sipSimpleWrapper_get_dict,
              (setter)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_as_async (Python v3.5), 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)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 */
              0,              /* tp_is_gc */
              0,              /* tp_bases */
              0,              /* tp_mro */
              0,              /* tp_cache */
              0,              /* tp_subclasses */
              0,              /* tp_weaklist */
              0,              /* tp_del */
              0,              /* tp_version_tag */
              0,              /* tp_finalize */
  #if PY_VERSION_HEX >= 0x03080000
              0,              /* tp_vectorcall */
  #endif
          },
          {
              0,              /* am_await */
              0,              /* am_aiter */
              0,              /* am_anext */
          },
          {
              0,              /* nb_add */
              0,              /* nb_subtract */
              0,              /* nb_multiply */
              0,              /* nb_remainder */
              0,              /* nb_divmod */
              0,              /* nb_power */
              0,              /* nb_negative */
              0,              /* nb_positive */
              0,              /* nb_absolute */
              0,              /* nb_bool */
              0,              /* nb_invert */
              0,              /* nb_lshift */
              0,              /* nb_rshift */
              0,              /* nb_and */
              0,              /* nb_xor */
              0,              /* nb_or */
              0,              /* nb_int */
              0,              /* nb_reserved */
              0,              /* nb_float */
              0,              /* nb_inplace_add */
              0,              /* nb_inplace_subtract */
              0,              /* nb_inplace_multiply */
              0,              /* nb_inplace_remainder */
              0,              /* nb_inplace_power */
              0,              /* nb_inplace_lshift */
              0,              /* nb_inplace_rshift */
              0,              /* nb_inplace_and */
              0,              /* nb_inplace_xor */
              0,              /* nb_inplace_or */
              0,              /* nb_floor_divide */
              0,              /* nb_true_divide */
              0,              /* nb_inplace_floor_divide */
              0,              /* nb_inplace_true_divide */
              0,              /* nb_index */
              0,              /* nb_matrix_multiply */
              0,              /* nb_inplace_matrix_multiply */
          },
          {
              0,              /* mp_length */
              0,              /* mp_subscript */
              0,              /* mp_ass_subscript */
          },
          {
              0,              /* sq_length */
              0,              /* sq_concat */
              0,              /* sq_repeat */
              0,              /* sq_item */
              0,              /* was_sq_slice */
              0,              /* sq_ass_item */
              0,              /* was_sq_ass_slice */
              0,              /* sq_contains */
              0,              /* sq_inplace_concat */
              0,              /* sq_inplace_repeat */
          },
          {
              0,              /* bf_getbuffer */
              0,              /* bf_releasebuffer */
          },
          0,                  /* ht_name */
          0,                  /* ht_slots */
          0,                  /* ht_qualname */
          0,                  /* ht_cached_keys */
  #if !defined(STACKLESS)
      },
  #endif
      0,                      /* wt_user_type */
      0,                      /* wt_dict_complete */
      0,                      /* wt_unused */
      0,                      /* wt_td */
      0,                      /* wt_iextend */
      0,                      /* wt_new_user_type_handler */
      0,                      /* wt_user_data */
  };
  
  
  /*
   * 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 (sipQtSupport != NULL && sipPossibleProxy(sw) && !sipNotInMap(sw))
      {
          void *tx = sip_api_get_address(sw);
  
          if (tx != NULL)
          {
              sipSlot *slot;
              void *context = NULL;
  
              assert (sipQtSupport->qt_find_sipslot);
  
              while ((slot = sipQtSupport->qt_find_sipslot(tx, &context)) != NULL)
              {
                  sip_api_clear_any_slot_reference(slot);
  
                  if (context == NULL)
                      break;
              }
          }
      }
  
      /* Detach any children (which will be owned by C/C++). */
      detachChildren(self);
  
      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 PyQt.  The map check is a bit of a
       * hack to work around PyQt4 problems with qApp and a user created
       * instance.  qt_find_sipslot() will return the same slot information for
       * both causing the gc module to trigger assert() failures.
       */
      if (sipQtSupport != NULL && sipQtSupport->qt_find_sipslot && !sipNotInMap(sw))
      {
          void *tx = sip_api_get_address(sw);
  
          if (tx != NULL)
          {
              sipSlot *slot;
              void *context = NULL;
  
              while ((slot = sipQtSupport->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, const sipClassTypeDef *ctd)
  {
      PyHeapTypeObject *heap_to = &wt->super;
      PyBufferProcs *bp = &heap_to->as_buffer;
  
      /* Add the buffer interface. */
      if (ctd->ctd_getbuffer != NULL)
          bp->bf_getbuffer = (getbufferproc)sipSimpleWrapper_getbuffer;
  
      if (ctd->ctd_releasebuffer != NULL)
          bp->bf_releasebuffer = (releasebufferproc)sipSimpleWrapper_releasebuffer;
  
      /* Add the slots for this type. */
      if (ctd->ctd_pyslots != NULL)
          addTypeSlots(heap_to, 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;
      PyAsyncMethods *am;
      void *f;
  
      to = &heap_to->ht_type;
      nb = &heap_to->as_number;
      sq = &heap_to->as_sequence;
      mp = &heap_to->as_mapping;
      am = &heap_to->as_async;
  
      while ((f = slots->psd_func) != NULL)
          switch (slots++->psd_type)
          {
          case str_slot:
              to->tp_str = (reprfunc)f;
              break;
  
          case int_slot:
              nb->nb_int = (unaryfunc)f;
              break;
  
          case float_slot:
              nb->nb_float = (unaryfunc)f;
              break;
  
          case len_slot:
              mp->mp_length = (lenfunc)f;
              sq->sq_length = (lenfunc)f;
              break;
  
          case contains_slot:
              sq->sq_contains = (objobjproc)f;
              break;
  
          case add_slot:
              nb->nb_add = (binaryfunc)f;
              break;
  
          case concat_slot:
              sq->sq_concat = (binaryfunc)f;
              break;
  
          case sub_slot:
              nb->nb_subtract = (binaryfunc)f;
              break;
  
          case mul_slot:
              nb->nb_multiply = (binaryfunc)f;
              break;
  
          case repeat_slot:
              sq->sq_repeat = (ssizeargfunc)f;
              break;
  
          case div_slot:
              nb->nb_true_divide = (binaryfunc)f;
              break;
  
          case mod_slot:
              nb->nb_remainder = (binaryfunc)f;
              break;
  
          case floordiv_slot:
              nb->nb_floor_divide = (binaryfunc)f;
              break;
  
          case truediv_slot:
              nb->nb_true_divide = (binaryfunc)f;
              break;
  
          case and_slot:
              nb->nb_and = (binaryfunc)f;
              break;
  
          case or_slot:
              nb->nb_or = (binaryfunc)f;
              break;
  
          case xor_slot:
              nb->nb_xor = (binaryfunc)f;
              break;
  
          case lshift_slot:
              nb->nb_lshift = (binaryfunc)f;
              break;
  
          case rshift_slot:
              nb->nb_rshift = (binaryfunc)f;
              break;
  
          case iadd_slot:
              nb->nb_inplace_add = (binaryfunc)f;
              break;
  
          case iconcat_slot:
              sq->sq_inplace_concat = (binaryfunc)f;
              break;
  
          case isub_slot:
              nb->nb_inplace_subtract = (binaryfunc)f;
              break;
  
          case imul_slot:
              nb->nb_inplace_multiply = (binaryfunc)f;
              break;
  
          case irepeat_slot:
              sq->sq_inplace_repeat = (ssizeargfunc)f;
              break;
  
          case idiv_slot:
              nb->nb_inplace_true_divide = (binaryfunc)f;
              break;
  
          case imod_slot:
              nb->nb_inplace_remainder = (binaryfunc)f;
              break;
  
          case ifloordiv_slot:
              nb->nb_inplace_floor_divide = (binaryfunc)f;
              break;
  
          case itruediv_slot:
              nb->nb_inplace_true_divide = (binaryfunc)f;
              break;
  
          case iand_slot:
              nb->nb_inplace_and = (binaryfunc)f;
              break;
  
          case ior_slot:
              nb->nb_inplace_or = (binaryfunc)f;
              break;
  
          case ixor_slot:
              nb->nb_inplace_xor = (binaryfunc)f;
              break;
  
          case ilshift_slot:
              nb->nb_inplace_lshift = (binaryfunc)f;
              break;
  
          case irshift_slot:
              nb->nb_inplace_rshift = (binaryfunc)f;
              break;
  
          case invert_slot:
              nb->nb_invert = (unaryfunc)f;
              break;
  
          case call_slot:
              to->tp_call = slot_call;
              break;
  
          case getitem_slot:
              mp->mp_subscript = (binaryfunc)f;
              sq->sq_item = slot_sq_item;
              break;
  
          case setitem_slot:
          case delitem_slot:
              mp->mp_ass_subscript = slot_mp_ass_subscript;
              sq->sq_ass_item = slot_sq_ass_item;
              break;
  
          case lt_slot:
          case le_slot:
          case eq_slot:
          case ne_slot:
          case gt_slot:
          case ge_slot:
              to->tp_richcompare = slot_richcompare;
              break;
  
          case bool_slot:
              nb->nb_bool = (inquiry)f;
              break;
  
          case neg_slot:
              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:
              nb->nb_positive = (unaryfunc)f;
              break;
  
          case abs_slot:
              nb->nb_absolute = (unaryfunc)f;
              break;
  
          case index_slot:
              nb->nb_index = (unaryfunc)f;
              break;
  
          case iter_slot:
              to->tp_iter = (getiterfunc)f;
              break;
  
          case next_slot:
              to->tp_iternext = (iternextfunc)f;
              break;
  
          case setattr_slot:
              to->tp_setattro = (setattrofunc)f;
              break;
  
          case matmul_slot:
              nb->nb_matrix_multiply = (binaryfunc)f;
              break;
  
          case imatmul_slot:
              nb->nb_inplace_matrix_multiply = (binaryfunc)f;
              break;
  
          case await_slot:
              am->am_await = (unaryfunc)f;
              break;
  
          case aiter_slot:
              am->am_aiter = (unaryfunc)f;
              break;
  
          case anext_slot:
              am->am_anext = (unaryfunc)f;
              break;
  
          /* Suppress a compiler warning. */
          default:
              ;
          }
  }
  
  
  /*
   * Remove the object from the map and call the C/C++ dtor if we own the
   * instance.
   */
  static void forgetObject(sipSimpleWrapper *sw)
  {
      sipEventHandler *eh;
      const sipClassTypeDef *ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(sw))->wt_td;
  
      /* Invoke any event handlers. */
      for (eh = event_handlers[sipEventCollectingWrapper]; eh != NULL; eh = eh->next)
      {
          if (is_subtype(ctd, eh->ctd))
          {
              sipCollectingWrapperEventHandler handler = (sipCollectingWrapperEventHandler)eh->handler;
  
              handler(sw);
          }
      }
  
      /*
       * This is needed because we might 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);
  
      /*
       * Remove the object from the map before calling the class specific dealloc
       * code.  This code calls the C++ dtor and may result in further calls that
       * pass the instance as an argument.  If this is still in the map then it's
       * reference count would be increased (to one) and bad things happen when
       * it drops back to zero again.  (An example is PyQt events generated
       * during the dtor call being passed to an event filter implemented in
       * Python.)  By removing it from the map first we ensure that a new Python
       * object is created.
       */
      sipOMRemoveObject(&cppPyMap, sw);
  
      if (sipInterpreter != NULL || destroy_on_exit)
      {
          const sipClassTypeDef *ctd;
  
          if (getPtrTypeDef(sw, &ctd) != NULL && ctd->ctd_dealloc != NULL)
              ctd->ctd_dealloc(sw);
      }
  
      clear_access_func(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
   * would only be called externally by PyQt3.
   */
  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 would only
   * be called externally by PyQt3.
   */
  static void sip_api_clear_any_slot_reference(sipSlot *slot)
  {
      if (slot->weakSlot == Py_True)
      {
          PyObject *xref = slot->pyobj;
  
          /*
           * Replace the slot with None.  We don't use NULL as this has another
           * meaning.
           */
          Py_INCREF(Py_None);
          slot->pyobj = Py_None;
  
          Py_DECREF(xref);
      }
  }
  
  
  /*
   * Convert a Python object to a character and raise an exception if there was
   * an error.
   */
  static char sip_api_bytes_as_char(PyObject *obj)
  {
      char ch;
  
      if (parseBytes_AsChar(obj, &ch) < 0)
      {
          PyErr_Format(PyExc_TypeError, "bytes of length 1 expected not '%s'",
                  Py_TYPE(obj)->tp_name);
  
          return '\0';
      }
  
      return ch;
  }
  
  
  /*
   * Convert a Python object to a string and raise an exception if there was
   * an error.
   */
  static const char *sip_api_bytes_as_string(PyObject *obj)
  {
      const char *a;
  
      if (parseBytes_AsString(obj, &a) < 0)
      {
          PyErr_Format(PyExc_TypeError, "bytes expected not '%s'",
                  Py_TYPE(obj)->tp_name);
  
          return NULL;
      }
  
      return a;
  }
  
  
  /*
   * Convert a Python ASCII string object to a character and raise an exception
   * if there was an error.
   */
  static char sip_api_string_as_ascii_char(PyObject *obj)
  {
      char ch;
  
      if (parseString_AsASCIIChar(obj, &ch) < 0)
          ch = '\0';
  
      return ch;
  }
  
  
  /*
   * Parse an ASCII character and return it.
   */
  static int parseString_AsASCIIChar(PyObject *obj, char *ap)
  {
      if (parseString_AsEncodedChar(PyUnicode_AsASCIIString(obj), obj, ap) < 0)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
              PyErr_SetString(PyExc_TypeError,
                      "bytes or ASCII string of length 1 expected");
  
          return -1;
      }
  
      return 0;
  }
  
  
  /*
   * 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)
          ch = '\0';
  
      return ch;
  }
  
  
  /*
   * Parse a Latin-1 character and return it via a pointer.
   */
  static int parseString_AsLatin1Char(PyObject *obj, char *ap)
  {
      if (parseString_AsEncodedChar(PyUnicode_AsLatin1String(obj), obj, ap) < 0)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
              PyErr_SetString(PyExc_TypeError,
                      "bytes or Latin-1 string of length 1 expected");
  
          return -1;
      }
  
      return 0;
  }
  
  
  /*
   * 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)
          ch = '\0';
  
      return ch;
  }
  
  
  /*
   * Parse a UTF-8 character and return it.
   */
  static int parseString_AsUTF8Char(PyObject *obj, char *ap)
  {
      if (parseString_AsEncodedChar(PyUnicode_AsUTF8String(obj), obj, ap) < 0)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(obj) || PyUnicode_GET_LENGTH(obj) != 1)
              PyErr_SetString(PyExc_TypeError,
                      "bytes or UTF-8 string of length 1 expected");
  
          return -1;
      }
  
      return 0;
  }
  
  
  /*
   * Parse an encoded character and return it.
   */
  static int parseString_AsEncodedChar(PyObject *bytes, PyObject *obj, char *ap)
  {
      Py_ssize_t size;
  
      if (bytes == NULL)
      {
          PyErr_Clear();
  
          return parseBytes_AsChar(obj, ap);
      }
  
      size = PyBytes_GET_SIZE(bytes);
  
      if (size != 1)
      {
          Py_DECREF(bytes);
          return -1;
      }
  
      if (ap != NULL)
          *ap = *PyBytes_AS_STRING(bytes);
  
      Py_DECREF(bytes);
  
      return 0;
  }
  
  
  /*
   * Convert a Python ASCII string object to a string and raise an exception if
   * there was an error.  The object is updated with the one that owns the
   * string.  Note that None is considered an error.
   */
  static const char *sip_api_string_as_ascii_string(PyObject **obj)
  {
      PyObject *s = *obj;
      const char *a;
  
      if (s == Py_None || (*obj = parseString_AsASCIIString(s, &a)) == NULL)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(s))
              PyErr_Format(PyExc_TypeError,
                      "bytes or ASCII string expected not '%s'",
                      Py_TYPE(s)->tp_name);
  
          return NULL;
      }
  
      return a;
  }
  
  
  /*
   * Parse an ASCII string and return it and a new reference to the object that
   * owns the string.
   */
  static PyObject *parseString_AsASCIIString(PyObject *obj, const char **ap)
  {
      return parseString_AsEncodedString(PyUnicode_AsASCIIString(obj), obj, ap);
  }
  
  
  /*
   * Convert a Python Latin-1 string object to a string and raise an exception if
   * there was an error.  The object is updated with the one that owns the
   * string.  Note that None is considered an error.
   */
  static const char *sip_api_string_as_latin1_string(PyObject **obj)
  {
      PyObject *s = *obj;
      const char *a;
  
      if (s == Py_None || (*obj = parseString_AsLatin1String(s, &a)) == NULL)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(s))
              PyErr_Format(PyExc_TypeError,
                      "bytes or Latin-1 string expected not '%s'",
                      Py_TYPE(s)->tp_name);
  
          return NULL;
      }
  
      return a;
  }
  
  
  /*
   * Parse a Latin-1 string and return it and a new reference to the object that
   * owns the string.
   */
  static PyObject *parseString_AsLatin1String(PyObject *obj, const char **ap)
  {
      return parseString_AsEncodedString(PyUnicode_AsLatin1String(obj), obj, ap);
  }
  
  
  /*
   * Convert a Python UTF-8 string object to a string and raise an exception if
   * there was an error.  The object is updated with the one that owns the
   * string.  Note that None is considered an error.
   */
  static const char *sip_api_string_as_utf8_string(PyObject **obj)
  {
      PyObject *s = *obj;
      const char *a;
  
      if (s == Py_None || (*obj = parseString_AsUTF8String(s, &a)) == NULL)
      {
          /* Use the exception set if it was an encoding error. */
          if (!PyUnicode_Check(s))
              PyErr_Format(PyExc_TypeError,
                      "bytes or UTF-8 string expected not '%s'",
                      Py_TYPE(s)->tp_name);
  
          return NULL;
      }
  
      return a;
  }
  
  
  /*
   * Parse a UTF-8 string and return it and a new reference to the object that
   * owns the string.
   */
  static PyObject *parseString_AsUTF8String(PyObject *obj, const char **ap)
  {
      return parseString_AsEncodedString(PyUnicode_AsUTF8String(obj), obj, ap);
  }
  
  
  /*
   * Parse an encoded string and return it and a new reference to the object that
   * owns the string.
   */
  static PyObject *parseString_AsEncodedString(PyObject *bytes, PyObject *obj,
          const char **ap)
  {
      if (bytes != NULL)
      {
          *ap = PyBytes_AS_STRING(bytes);
  
          return bytes;
      }
  
      /* Don't try anything else if there was an encoding error. */
      if (PyUnicode_Check(obj))
          return NULL;
  
      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,
          Py_ssize_t *aszp)
  {
      const char *a;
      Py_ssize_t asz;
  
      if (obj == Py_None)
      {
          a = NULL;
          asz = 0;
      }
      else if (PyBytes_Check(obj))
      {
          a = PyBytes_AS_STRING(obj);
          asz = PyBytes_GET_SIZE(obj);
      }
      else
      {
          Py_buffer view;
  
          if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0)
              return -1;
  
          a = view.buf;
          asz = view.len;
  
          PyBuffer_Release(&view);
      }
  
      if (ap != NULL)
          *ap = a;
  
      if (aszp != NULL)
          *aszp = asz;
  
      return 0;
  }
  
  
  /*
   * Parse a character and return it.
   */
  static int parseBytes_AsChar(PyObject *obj, char *ap)
  {
      const char *chp;
      Py_ssize_t sz;
  
      if (PyBytes_Check(obj))
      {
          chp = PyBytes_AS_STRING(obj);
          sz = PyBytes_GET_SIZE(obj);
      }
      else
      {
          Py_buffer view;
  
          if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0)
              return -1;
  
          chp = view.buf;
          sz = view.len;
  
          PyBuffer_Release(&view);
      }
  
      if (sz != 1)
          return -1;
  
      if (ap != NULL)
          *ap = *chp;
  
      return 0;
  }
  
  
  /*
   * Parse a character string and return it.
   */
  static int parseBytes_AsString(PyObject *obj, const char **ap)
  {
      const char *a;
      Py_ssize_t sz;
  
      if (parseBytes_AsCharArray(obj, &a, &sz) < 0)
          return -1;
  
      if (ap != NULL)
          *ap = a;
  
      return 0;
  }
  
  
  #if defined(HAVE_WCHAR_H)
  /*
   * Convert a Python object to a wide character.
   */
  static wchar_t sip_api_unicode_as_wchar(PyObject *obj)
  {
      wchar_t ch;
  
      if (parseWChar(obj, &ch) < 0)
      {
          PyErr_Format(PyExc_ValueError,
                  "string of length 1 expected, not %s", Py_TYPE(obj)->tp_name);
  
          return L'\0';
      }
  
      return ch;
  }
  
  
  /*
   * Convert a Python object to a wide character string on the heap.
   */
  static wchar_t *sip_api_unicode_as_wstring(PyObject *obj)
  {
      wchar_t *p;
  
      if (parseWCharString(obj, &p) < 0)
      {
          PyErr_Format(PyExc_ValueError,
                  "string expected, not %s", Py_TYPE(obj)->tp_name);
  
          return NULL;
      }
  
      return p;
  }
  
  
  /*
   * Parse a wide character array and return it's address and length.
   */
  static int parseWCharArray(PyObject *obj, wchar_t **ap, Py_ssize_t *aszp)
  {
      wchar_t *a;
      Py_ssize_t asz;
  
      if (obj == Py_None)
      {
          a = NULL;
          asz = 0;
      }
      else if (PyUnicode_Check(obj))
      {
          if (convertToWCharArray(obj, &a, &asz) < 0)
              return -1;
      }
      else
      {
          return -1;
      }
  
      if (ap != NULL)
          *ap = a;
  
      if (aszp != NULL)
          *aszp = asz;
  
      return 0;
  }
  
  
  /*
   * Convert a Unicode object to a wide character array and return it's address
   * and length.
   */
  static int convertToWCharArray(PyObject *obj, wchar_t **ap, Py_ssize_t *aszp)
  {
      Py_ssize_t ulen;
      wchar_t *wc;
  
      ulen = PyUnicode_GET_LENGTH(obj);
  
      if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL)
          return -1;
  
      if ((ulen = PyUnicode_AsWideChar(obj, wc, 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)
  {
      wchar_t a;
  
      if (PyUnicode_Check(obj))
      {
          if (convertToWChar(obj, &a) < 0)
              return -1;
      }
      else
      {
          return -1;
      }
  
      if (ap != NULL)
          *ap = a;
  
      return 0;
  }
  
  
  /*
   * Convert a Unicode object to a wide character and return it.
   */
  static int convertToWChar(PyObject *obj, wchar_t *ap)
  {
      if (PyUnicode_GET_LENGTH(obj) != 1)
          return -1;
  
      if (PyUnicode_AsWideChar(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)
  {
      wchar_t *a;
  
      if (obj == Py_None)
      {
          a = NULL;
      }
      else if (PyUnicode_Check(obj))
      {
          if (convertToWCharString(obj, &a) < 0)
              return -1;
      }
      else
      {
          return -1;
      }
  
      if (ap != NULL)
          *ap = a;
  
      return 0;
  }
  
  
  /*
   * Convert a Unicode object to a wide character string and return a copy on
   * the heap.
   */
  static int convertToWCharString(PyObject *obj, wchar_t **ap)
  {
      Py_ssize_t ulen;
      wchar_t *wc;
  
      ulen = PyUnicode_GET_LENGTH(obj);
  
      if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL)
          return -1;
  
      if ((ulen = PyUnicode_AsWideChar(obj, wc, 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, Py_ssize_t nitems)
  {
      sipEnumTypeObject *py_type;
      sipPySlotDef *psd;
  
      assert(currentType != NULL);
      assert(sipTypeIsEnum(currentType));
  
      /* 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->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);
  
      return (PyObject *)py_type;
  }
  
  
  /*
   * The enum type getattro slot.
   */
  static PyObject *sipEnumType_getattro(PyObject *self, PyObject *name)
  {
      PyObject *res;
      sipEnumTypeDef *etd;
      sipExportedModuleDef *client;
      const sipEnumMemberDef *enm, *emd;
      int enum_nr, nr_members, m;
      const char *name_str;
  
      /*
       * Try a generic lookup first.  This has the side effect of checking the
       * type of the name object.
       */
      if ((res = PyObject_GenericGetAttr(self, name)) != NULL)
          return res;
  
      if (!PyErr_ExceptionMatches(PyExc_AttributeError))
          return NULL;
  
      PyErr_Clear();
  
      /* Get the member name. */
      if ((name_str = PyUnicode_AsUTF8(name)) == NULL)
          return NULL;
  
      etd = (sipEnumTypeDef *)((sipEnumTypeObject *)self)->type;
      client = ((sipTypeDef *)etd)->td_module;
  
      /* Find the number of this enum. */
      for (enum_nr = 0; enum_nr < client->em_nrtypes; ++enum_nr)
          if (client->em_types[enum_nr] == (sipTypeDef *)etd)
              break;
  
      /* Get the enum members in the same scope. */
      if (etd->etd_scope < 0)
      {
          nr_members = client->em_nrenummembers;
          enm = client->em_enummembers;
      }
      else
      {
          const sipContainerDef *cod = get_container(client->em_types[etd->etd_scope]);
  
          nr_members = cod->cod_nrenummembers;
          enm = cod->cod_enummembers;
      }
  
      /* Find the enum member. */
      for (emd = enm, m = 0; m < nr_members; ++m, ++emd)
          if (emd->em_enum == enum_nr && strcmp(emd->em_name, name_str) == 0)
              return sip_api_convert_from_enum(emd->em_val, (sipTypeDef *)etd);
  
      PyErr_Format(PyExc_AttributeError,
              "sip.enumtype object '%s' has no member '%s'",
              sipPyNameOfEnum(etd), name_str);
  
      return NULL;
  }
  
  
  /*
   * Check if an object is of the right type to convert to an encoded string.
   */
  static int check_encoded_string(PyObject *obj)
  {
      Py_buffer view;
  
      if (obj == Py_None)
          return 0;
  
      if (PyUnicode_Check(obj))
          return 0;
  
      if (PyBytes_Check(obj))
          return 0;
  
      if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) < 0)
      {
          PyErr_Clear();
      }
      else
      {
          PyBuffer_Release(&view);
          return 0;
      }
  
      return -1;
  }
  
  
  /*
   * This is called by the atexit module.
   */
  static PyObject *sip_exit(PyObject *self, PyObject *args)
  {
      (void)self;
      (void)args;
  
      /* Disable all Python reimplementations of virtuals. */
      sipInterpreter = NULL;
  
      Py_INCREF(Py_None);
      return Py_None;
  }
  
  
  /*
   * Register an exit notifier with the atexit module.
   */
  static int sip_api_register_exit_notifier(PyMethodDef *md)
  {
      static PyObject *register_func = NULL;
      PyObject *notifier, *res;
  
      if (register_func == NULL && (register_func = import_module_attr("atexit", "register")) == NULL)
          return -1;
  
      if ((notifier = PyCFunction_New(md, NULL)) == NULL)
          return -1;
  
      res = PyObject_CallFunctionObjArgs(register_func, notifier, NULL);
  
      Py_DECREF(notifier);
  
      if (res == NULL)
          return -1;
  
      Py_DECREF(res);
  
      return 0;
  }
  
  
  /*
   * Return the function that converts a C++ instance to a Python object.
   */
  static sipConvertFromFunc get_from_convertor(const sipTypeDef *td)
  {
      if (sipTypeIsMapped(td))
          return ((const sipMappedTypeDef *)td)->mtd_cfrom;
  
      assert(sipTypeIsClass(td));
  
      if (autoconversion_disabled(td) != NULL)
          return NULL;
  
      return ((const sipClassTypeDef *)td)->ctd_cfrom;
  }
  
  
  /*
   * Enable or disable the auto-conversion.  Returns the previous enabled state
   * or -1 on error.
   */
  static int sip_api_enable_autoconversion(const sipTypeDef *td, int enable)
  {
      sipPyObject **pop;
  
      assert(sipTypeIsClass(td));
  
      pop = autoconversion_disabled(td);
  
      /* See if there is anything to do. */
      if (pop == NULL && enable)
          return TRUE;
  
      if (pop != NULL && !enable)
          return FALSE;
  
      if (pop != NULL)
      {
          /* Remove it from the list. */
          sipPyObject *po = *pop;
  
          *pop = po->next;
          sip_api_free(po);
      }
      else
      {
          /* Add it to the list. */
          if (addPyObjectToList(&sipDisabledAutoconversions, (PyObject *)sipTypeAsPyTypeObject(td)) < 0)
              return -1;
      }
  
      return !enable;
  }
  
  
  /*
   * Return a pointer to the entry in the list of disabled auto-conversions for a
   * type.
   */
  static sipPyObject **autoconversion_disabled(const sipTypeDef *td)
  {
      PyObject *type = (PyObject *)sipTypeAsPyTypeObject(td);
      sipPyObject **pop;
  
      for (pop = &sipDisabledAutoconversions; *pop != NULL; pop = &(*pop)->next)
          if ((*pop)->object == type)
              return pop;
  
      return NULL;
  }
  
  
  /*
   * Enable or disable auto-conversion of a class that supports it.
   */
  static PyObject *enableAutoconversion(PyObject *self, PyObject *args)
  {
      sipWrapperType *wt;
      int enable;
  
      (void)self;
  
      if (PyArg_ParseTuple(args, "O!i:enableautoconversion", &sipWrapperType_Type, &wt, &enable))
      {
          sipTypeDef *td = wt->wt_td;
          int was_enabled;
          PyObject *res;
  
          if (!sipTypeIsClass(td) || ((sipClassTypeDef *)td)->ctd_cfrom == NULL)
          {
              PyErr_Format(PyExc_TypeError,
                      "%s is not a wrapped class that supports optional auto-conversion", ((PyTypeObject *)wt)->tp_name);
  
              return NULL;
          }
  
          if ((was_enabled = sip_api_enable_autoconversion(td, enable)) < 0)
              return NULL;
  
          res = (was_enabled ? Py_True : Py_False);
  
          Py_INCREF(res);
          return res;
      }
  
      return NULL;
  }
  
  
  /*
   * Python copies the nb_inplace_add slot to the sq_inplace_concat slot and vice
   * versa if either are missing.  This is a bug because they don't have the same
   * API.  We therefore reverse this.
   */
  static void fix_slots(PyTypeObject *py_type, sipPySlotDef *psd)
  {
      while (psd->psd_func != NULL)
      {
          if (psd->psd_type == iadd_slot && py_type->tp_as_sequence != NULL)
              py_type->tp_as_sequence->sq_inplace_concat = NULL;
  
          if (psd->psd_type == iconcat_slot && py_type->tp_as_number != NULL)
              py_type->tp_as_number->nb_inplace_add = NULL;
  
          ++psd;
      }
  }
  
  
  /*
   * Return the main instance for an object if it is a mixin.
   */
  static sipSimpleWrapper *deref_mixin(sipSimpleWrapper *w)
  {
      return w->mixin_main != NULL ? (sipSimpleWrapper *)w->mixin_main : w;
  }
  
  
  /*
   * Convert a new C/C++ pointer to a Python instance.
   */
  static PyObject *wrap_simple_instance(void *cpp, const sipTypeDef *td,
          sipWrapper *owner, int flags)
  {
      return sipWrapInstance(cpp, sipTypeAsPyTypeObject(td), empty_tuple, owner,
              flags);
  }
  
  
  /*
   * Resolve a proxy, if applicable.
   */
  static void *resolve_proxy(const sipTypeDef *td, void *proxy)
  {
      sipProxyResolver *pr;
  
      /* TODO: Deprecate this mechanism in favour of an event handler. */
      for (pr = proxyResolvers; pr != NULL; pr = pr->next)
          if (pr->td == td)
              proxy = pr->resolver(proxy);
  
      return proxy;
  }
  
  
  /*
   * Clear a simple wrapper.
   */
  static void clear_wrapper(sipSimpleWrapper *sw)
  {
      if (PyObject_TypeCheck((PyObject *)sw, (PyTypeObject *)&sipWrapper_Type))
          removeFromParent((sipWrapper *)sw);
  
      /*
       * Transfer ownership to C++ so we don't try to release it when the
       * Python object is garbage collected.
       */
      sipResetPyOwned(sw);
  
      sipOMRemoveObject(&cppPyMap, sw);
  
      clear_access_func(sw);
  }
  
  
  /*
   * Set the handler to invoke when a new user Python sub-class is defined and
   * return the old handler.
   */
  static sipNewUserTypeFunc sip_api_set_new_user_type_handler(
          const sipTypeDef *td, sipNewUserTypeFunc handler)
  {
      sipWrapperType *wt = (sipWrapperType *)sipTypeAsPyTypeObject(td);
      sipNewUserTypeFunc old_handler = wt->wt_new_user_type_handler;;
  
      wt->wt_new_user_type_handler = handler;
  
      return old_handler;
  }
  
  
  /*
   * Set the user-specific type data.
   */
  static void sip_api_set_type_user_data(sipWrapperType *wt, void *data)
  {
      wt->wt_user_data = data;
  }
  
  
  /*
   * Get the user-specific type data.
   */
  static void *sip_api_get_type_user_data(const sipWrapperType *wt)
  {
      return wt->wt_user_data;
  }
  
  
  /*
   * Get the dict of a Python type (on behalf of the limited API).
   */
  static PyObject *sip_api_py_type_dict(const PyTypeObject *py_type)
  {
      return py_type->tp_dict;
  }
  
  
  /*
   * Get the name of a Python type (on behalf of the limited API).
   */
  static const char *sip_api_py_type_name(const PyTypeObject *py_type)
  {
      return py_type->tp_name;
  }
  
  
  /*
   * Check an object is a method and return TRUE and its component parts if it
   * is.
   */
  static int sip_api_get_method(PyObject *obj, sipMethodDef *method)
  {
      if (!PyMethod_Check(obj))
          return FALSE;
  
      if (method != NULL)
      {
          method->pm_self = PyMethod_GET_SELF(obj);
          method->pm_function = PyMethod_GET_FUNCTION(obj);
      }
  
      return TRUE;
  }
  
  
  /*
   * Create a method from its component parts.
   */
  static PyObject *sip_api_from_method(const sipMethodDef *method)
  {
      return PyMethod_New(method->pm_function, method->pm_self);
  }
  
  
  /*
   * Check an object is a C function and return TRUE and its component parts if
   * it is.
   */
  static int sip_api_get_c_function(PyObject *obj, sipCFunctionDef *c_function)
  {
      if (!PyCFunction_Check(obj))
          return FALSE;
  
      if (c_function != NULL)
      {
          c_function->cf_function = ((PyCFunctionObject *)obj)->m_ml;
          c_function->cf_self = PyCFunction_GET_SELF(obj);
      }
  
      return TRUE;
  }
  
  
  /*
   * Check an object is a date and return TRUE and its component parts if it is.
   */
  static int sip_api_get_date(PyObject *obj, sipDateDef *date)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      if (!PyDate_Check(obj))
          return FALSE;
  
      if (date != NULL)
      {
          date->pd_year = PyDateTime_GET_YEAR(obj);
          date->pd_month = PyDateTime_GET_MONTH(obj);
          date->pd_day = PyDateTime_GET_DAY(obj);
      }
  
      return TRUE;
  }
  
  
  /*
   * Create a date from its component parts.
   */
  static PyObject *sip_api_from_date(const sipDateDef *date)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      return PyDate_FromDate(date->pd_year, date->pd_month, date->pd_day);
  }
  
  
  /*
   * Check an object is a datetime and return TRUE and its component parts if it
   * is.
   */
  static int sip_api_get_datetime(PyObject *obj, sipDateDef *date,
          sipTimeDef *time)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      if (!PyDateTime_Check(obj))
          return FALSE;
  
      if (date != NULL)
      {
          date->pd_year = PyDateTime_GET_YEAR(obj);
          date->pd_month = PyDateTime_GET_MONTH(obj);
          date->pd_day = PyDateTime_GET_DAY(obj);
      }
  
      if (time != NULL)
      {
          time->pt_hour = PyDateTime_DATE_GET_HOUR(obj);
          time->pt_minute = PyDateTime_DATE_GET_MINUTE(obj);
          time->pt_second = PyDateTime_DATE_GET_SECOND(obj);
          time->pt_microsecond = PyDateTime_DATE_GET_MICROSECOND(obj);
      }
  
      return TRUE;
  }
  
  
  /*
   * Create a datetime from its component parts.
   */
  static PyObject *sip_api_from_datetime(const sipDateDef *date,
          const sipTimeDef *time)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      return PyDateTime_FromDateAndTime(date->pd_year, date->pd_month,
              date->pd_day, time->pt_hour, time->pt_minute, time->pt_second,
              time->pt_microsecond);
  }
  
  
  /*
   * Check an object is a time and return TRUE and its component parts if it is.
   */
  static int sip_api_get_time(PyObject *obj, sipTimeDef *time)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      if (!PyTime_Check(obj))
          return FALSE;
  
      if (time != NULL)
      {
          time->pt_hour = PyDateTime_TIME_GET_HOUR(obj);
          time->pt_minute = PyDateTime_TIME_GET_MINUTE(obj);
          time->pt_second = PyDateTime_TIME_GET_SECOND(obj);
          time->pt_microsecond = PyDateTime_TIME_GET_MICROSECOND(obj);
      }
  
      return TRUE;
  }
  
  
  /*
   * Create a time from its component parts.
   */
  static PyObject *sip_api_from_time(const sipTimeDef *time)
  {
      if (!PyDateTimeAPI)
          PyDateTime_IMPORT;
  
      return PyTime_FromTime(time->pt_hour, time->pt_minute, time->pt_second,
              time->pt_microsecond);
  }
  
  
  /*
   * See if a type is user defined.
   */
  static int sip_api_is_user_type(const sipWrapperType *wt)
  {
      return wt->wt_user_type;
  }
  
  
  /*
   * Return a frame from the execution stack.
   */
  static struct _frame *sip_api_get_frame(int depth)
  {
      struct _frame *frame = PyEval_GetFrame();
  
      while (frame != NULL && depth > 0)
      {
          frame = frame->f_back;
          --depth;
      }
  
      return frame;
  }
  
  
  /*
   * Check if a type was generated using the given plugin.  Note that, although
   * this is part of the public API it is undocumented on purpose.
   */
  static int sip_api_check_plugin_for_type(const sipTypeDef *td,
          const char *name)
  {
      /*
       * The current thinking on plugins is that SIP v5 will look for a plugin
       * with a name derived from the name as the current module in the same
       * directory as the .sip defining the module (ie. no %Plugin directive).  A
       * module hierachy may have multiple plugins but they must co-operate.  If
       * a plugin generates user data then it should include a void* (and a
       * run-time API) so that other plugins can extend it further.  This
       * approach means that a plugin's user data structure can be opaque.
       */
  
      sipExportedModuleDef *em = td->td_module;
      sipImportedModuleDef *im;
  
      if (strcmp(sipNameOfModule(em), name) == 0)
          return TRUE;
  
      if ((im = em->em_imports) == NULL)
          return FALSE;
  
      while (im->im_name != NULL)
      {
          if (strcmp(im->im_name, name) == 0)
              return TRUE;
  
          ++im;
      }
  
      return FALSE;
  }
  
  
  /*
   * Create a new Unicode object and return the character size and buffer.
   */
  static PyObject *sip_api_unicode_new(Py_ssize_t len, unsigned maxchar,
          int *kind, void **data)
  {
      PyObject *obj;
  
      if ((obj = PyUnicode_New(len, maxchar)) != NULL)
      {
          *kind = PyUnicode_KIND(obj);
          *data = PyUnicode_DATA(obj);
      }
  
      return obj;
  }
  
  
  /*
   * Update a new Unicode object with a new character.
   */
  static void sip_api_unicode_write(int kind, void *data, int index,
          unsigned value)
  {
      PyUnicode_WRITE(kind, data, index, value);
  }
  
  
  /*
   * Get the address of the contents of a Unicode object, the character size and
   * the length.
   */
  static void *sip_api_unicode_data(PyObject *obj, int *char_size,
          Py_ssize_t *len)
  {
      void *data;
  
      /* Assume there will be an error. */
      *char_size = -1;
  
      if (PyUnicode_READY(obj) < 0)
          return NULL;
  
      *len = PyUnicode_GET_LENGTH(obj);
  
      switch (PyUnicode_KIND(obj))
      {
      case PyUnicode_1BYTE_KIND:
          *char_size = 1;
          data = PyUnicode_1BYTE_DATA(obj);
          break;
  
      case PyUnicode_2BYTE_KIND:
          *char_size = 2;
          data = PyUnicode_2BYTE_DATA(obj);
          break;
  
      case PyUnicode_4BYTE_KIND:
          *char_size = 4;
          data = PyUnicode_4BYTE_DATA(obj);
          break;
  
      default:
          data = NULL;
      }
  
      return data;
  }
  
  
  /*
   * Get the buffer information supplied by an object that supports the buffer
   * protocol.
   */
  static int sip_api_get_buffer_info(PyObject *obj, sipBufferInfoDef *bi)
  {
      int rc;
      Py_buffer *buffer;
  
      if (!PyObject_CheckBuffer(obj))
          return 0;
  
      if (bi == NULL)
          return 1;
  
      if ((bi->bi_internal = sip_api_malloc(sizeof (Py_buffer))) == NULL)
          return -1;
  
      buffer = (Py_buffer *)bi->bi_internal;
  
      if (PyObject_GetBuffer(obj, buffer, PyBUF_FORMAT) < 0)
          return -1;
  
      if (buffer->ndim == 1)
      {
          bi->bi_buf = buffer->buf;
          bi->bi_obj = buffer->obj;
          bi->bi_len = buffer->len;
          bi->bi_format = buffer->format;
  
          rc = 1;
      }
      else
      {
          PyErr_SetString(PyExc_TypeError, "a 1-dimensional buffer is required");
          PyBuffer_Release(buffer);
          rc = -1;
      }
  
      return rc;
  }
  
  
  /*
   * Release the buffer information obtained from a previous call to
   * sipGetBufferInfo().
   */
  static void sip_api_release_buffer_info(sipBufferInfoDef *bi)
  {
      if (bi->bi_internal != NULL)
      {
          PyBuffer_Release((Py_buffer *)bi->bi_internal);
          sip_api_free(bi->bi_internal);
          bi->bi_internal = NULL;
      }
  }
  
  
  /*
   * Import all the required types from an imported module.
   */
  static int importTypes(sipExportedModuleDef *client, sipImportedModuleDef *im,
          sipExportedModuleDef *em)
  {
      const char *name;
      int i, e;
  
      /*
       * Look for each required type in turn.  Both tables are sorted so a single
       * pass will find them all.
       */
      for (i = e = 0; (name = im->im_imported_types[i].it_name) != NULL; ++i)
      {
          sipTypeDef *td = NULL;
  
          do
          {
              sipTypeDef *e_td;
  
              if (e >= em->em_nrtypes)
              {
                  PyErr_Format(PyExc_RuntimeError,
                          "%s cannot import type '%s' from %s",
                          sipNameOfModule(client), name, sipNameOfModule(em));
  
                  return -1;
              }
  
              e_td = em->em_types[e++];
  
              /* Ignore unresolved external types. */
              if (e_td != NULL && strcmp(name, sipTypeName(e_td)) == 0)
                  td = e_td;
          }
          while (td == NULL);
  
          im->im_imported_types[i].it_td = td;
      }
  
      return 0;
  }
  
  
  /*
   * Import all the required virtual error handlers from an imported module.
   */
  static int importErrorHandlers(sipExportedModuleDef *client,
          sipImportedModuleDef *im, sipExportedModuleDef *em)
  {
      const char *name;
      int i;
  
      for (i = 0; (name = im->im_imported_veh[i].iveh_name) != NULL; ++i)
      {
          sipVirtErrorHandlerDef *veh = em->em_virterrorhandlers;
          sipVirtErrorHandlerFunc handler = NULL;
  
          if (veh != NULL)
          {
              while (veh->veh_name != NULL)
              {
                  if (strcmp(veh->veh_name, name) == 0)
                  {
                      handler = veh->veh_handler;
                      break;
                  }
  
                  ++veh;
              }
          }
  
          if (handler == NULL)
          {
              PyErr_Format(PyExc_RuntimeError,
                      "%s cannot import virtual error handler '%s' from %s",
                      sipNameOfModule(client), name, sipNameOfModule(em));
  
              return -1;
          }
  
          im->im_imported_veh[i].iveh_handler = handler;
      }
  
      return 0;
  }
  
  
  /*
   * Import all the required exceptions from an imported module.
   */
  static int importExceptions(sipExportedModuleDef *client,
          sipImportedModuleDef *im, sipExportedModuleDef *em)
  {
      const char *name;
      int i;
  
      for (i = 0; (name = im->im_imported_exceptions[i].iexc_name) != NULL; ++i)
      {
          PyObject **exc = em->em_exceptions;
          PyObject *exception = NULL;
  
          if (exc != NULL)
          {
              while (*exc != NULL)
              {
                  if (strcmp(((PyTypeObject *)(*exc))->tp_name, name) == 0)
                  {
                      exception = *exc;
                      break;
                  }
  
                  ++exc;
              }
          }
  
          if (exception == NULL)
          {
              PyErr_Format(PyExc_RuntimeError,
                      "%s cannot import exception '%s' from %s",
                      sipNameOfModule(client), name, sipNameOfModule(em));
  
              return -1;
          }
  
          im->im_imported_exceptions[i].iexc_object = exception;
      }
  
      return 0;
  }
  
  
  /*
   * Enable or disable the garbage collector.  Return the previous state or -1 if
   * there was an error.
   */
  static int sip_api_enable_gc(int enable)
  {
      static PyObject *enable_func = NULL, *disable_func, *isenabled_func;
      PyObject *result;
      int was_enabled;
  
      /*
       * This may be -ve in the highly unusual event that a previous call failed.
       */
      if (enable < 0)
          return -1;
  
      /* Get the functions if we haven't already got them. */
      if (enable_func == NULL)
      {
          PyObject *gc_module;
  
          if ((gc_module = PyImport_ImportModule("gc")) == NULL)
              return -1;
  
          if ((enable_func = PyObject_GetAttrString(gc_module, "enable")) == NULL)
          {
              Py_DECREF(gc_module);
              return -1;
          }
  
          if ((disable_func = PyObject_GetAttrString(gc_module, "disable")) == NULL)
          {
              Py_DECREF(enable_func);
              Py_DECREF(gc_module);
              return -1;
          }
  
          if ((isenabled_func = PyObject_GetAttrString(gc_module, "isenabled")) == NULL)
          {
              Py_DECREF(disable_func);
              Py_DECREF(enable_func);
              Py_DECREF(gc_module);
              return -1;
          }
  
          Py_DECREF(gc_module);
      }
  
      /* Get the current state. */
      if ((result = PyObject_Call(isenabled_func, empty_tuple, NULL)) == NULL)
          return -1;
  
      was_enabled = PyObject_IsTrue(result);
      Py_DECREF(result);
  
      if (was_enabled < 0)
          return -1;
  
      /* See if the state needs changing. */
      if (!was_enabled != !enable)
      {
          /* Enable or disable as required. */
          result = PyObject_Call((enable ? enable_func : disable_func),
                  empty_tuple, NULL);
  
          Py_XDECREF(result);
  
          if (result != Py_None)
              return -1;
      }
  
      return was_enabled;
  }
  
  
  /*
   * A thin wrapper around PyObject_Print() usually used when debugging with the
   * limited API.
   */
  static void sip_api_print_object(PyObject *o)
  {
      PyObject_Print(o, stdout, 0);
  }
  
  
  /*
   * Register a handler for a particular event.
   */
  static int sip_api_register_event_handler(sipEventType type,
          const sipTypeDef *td, void *handler)
  {
      sipEventHandler *eh;
  
      assert(sipTypeIsClass(td));
  
      if ((eh = sip_api_malloc(sizeof (sipEventHandler))) == NULL)
          return -1;
  
      eh->ctd = (const sipClassTypeDef *)td;
      eh->handler = handler;
  
      eh->next = event_handlers[(int)type];
      event_handlers[(int)type] = eh;
  
      return 0;
  }
  
  
  /*
   * Returns TRUE if a generated class type is a sub-class of a base generated
   * class type.
   */
  static int is_subtype(const sipClassTypeDef *ctd,
          const sipClassTypeDef *base_ctd)
  {
      const sipEncodedTypeDef *sup;
  
      /* Handle the trivial cases. */
      if (ctd == base_ctd)
          return TRUE;
  
      if ((sup = ctd->ctd_supers) == NULL)
          return FALSE;
  
      /* Search the super-types. */
      do
      {
          const sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd);
  
          if (is_subtype(sup_ctd, base_ctd))
              return TRUE;
      }
      while (!sup++->sc_flag);
  
      return FALSE;
  }
  
  
  /*
   * Return an attribute of an imported module.
   */
  static PyObject *import_module_attr(const char *module, const char *attr)
  {
      PyObject *mod_obj, *attr_obj;
  
      if ((mod_obj = PyImport_ImportModule(module)) == NULL)
          return NULL;
  
      attr_obj = PyObject_GetAttrString(mod_obj, attr);
  
      Py_DECREF(mod_obj);
  
      return attr_obj;
  }
  
  
  /*
   * Get the container for a generated type.
   */
  static const sipContainerDef *get_container(const sipTypeDef *td)
  {
      if (sipTypeIsMapped(td))
          return &((const sipMappedTypeDef *)td)->mtd_container;
  
      return &((const sipClassTypeDef *)td)->ctd_container;
  }
  
  
  /*
   * Get the __qualname__ of an object based on its enclosing scope.
   */
  static PyObject *get_qualname(const sipTypeDef *td, PyObject *name)
  {
      PyTypeObject *scope_type;
  
      /* Get the type that is the scope. */
      scope_type = sipTypeAsPyTypeObject(td);
  
      return PyUnicode_FromFormat("%U.%U",
              ((PyHeapTypeObject *)scope_type)->ht_qualname, name);
  }
  
  
  /*
   * Implement PySlice_GetIndicesEx() (or its subsequent replacement).
   */
  int sip_api_convert_from_slice_object(PyObject *slice, Py_ssize_t length,
          Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
          Py_ssize_t *slicelength)
  {
  #if PY_VERSION_HEX >= 0x03070000
      if (PySlice_Unpack(slice, start, stop, step) < 0)
          return -1;
  
      *slicelength = PySlice_AdjustIndices(length, start, stop, *step);
  
      return 0;
  #else
      return PySlice_GetIndicesEx(slice, length, start, stop, step, slicelength);
  #endif
  }
  
  
  /*
   * Call a visitor function for every wrapped object.
   */
  static void sip_api_visit_wrappers(sipWrapperVisitorFunc visitor,
          void *closure)
  {
      const sipHashEntry *he;
      unsigned long i;
  
      for (he = cppPyMap.hash_array, i = 0; i < cppPyMap.size; ++i, ++he)
      {
          if (he->key != NULL)
          {
              sipSimpleWrapper *sw;
  
              for (sw = he->first; sw != NULL; sw = sw->next)
                  visitor(sw, closure);
          }
      }
  }
  