/*
 * SIP library code.
 *
 * Copyright (c) 2005
 * 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
 * 
 * This file is part of SIP.
 * 
 * This copy of SIP is licensed for use under the terms of the SIP License
 * Agreement.  See the file LICENSE for more details.
 * 
 * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */


#include <Python.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>

#include "sip.h"
#include "sipint.h"


/*
 * These are the functions that make up the public and private SIP API.
 */
static void sip_api_bad_catcher_result(PyObject *method);
static void sip_api_bad_length_for_slice(int seqlen,int slicelen);
static PyObject *sip_api_build_result(int *isErr,char *fmt,...);
static PyObject *sip_api_call_method(int *isErr,PyObject *method,char *fmt,
				     ...);
static PyObject *sip_api_class_name(PyObject *self);
static int sip_api_convert_from_sequence_index(int idx,int len);
static void *sip_api_convert_to_cpp(PyObject *sipSelf,sipWrapperType *type,
				    int *iserrp);
static PyObject *sip_api_get_wrapper(void *cppPtr,sipWrapperType *type);
static sipWrapperType *sip_api_map_int_to_class(int typeInt,
						const sipIntTypeClassMap *map,
						int maplen);
static sipWrapperType *sip_api_map_string_to_class(const char *typeString,
						   const sipStringTypeClassMap *map,
						   int maplen);
static int sip_api_parse_result(int *isErr,PyObject *method,PyObject *res,
				char *fmt,...);
static void sip_api_trace(unsigned mask,const char *fmt,...);
static void sip_api_transfer(PyObject *self,int toCpp);
static int sip_api_export_module(sipExportedModuleDef *client,
				 unsigned api_major,unsigned api_minor,
				 PyObject *mod_dict);
static int sip_api_parse_args(int *argsParsedp,PyObject *sipArgs,char *fmt,
			      ...);
static void sip_api_common_ctor(sipMethodCache *cache,int nrmeths);
static void sip_api_common_dtor(sipWrapper *sipSelf);
static void *sip_api_convert_to_void_ptr(PyObject *obj);
static void sip_api_no_ctor(int argsParsed,char *classname);
static void sip_api_no_function(int argsParsed,char *func);
static void sip_api_no_method(int argsParsed,char *classname,char *method);
static void sip_api_bad_class(const char *classname);
static void sip_api_bad_set_type(const char *classname,const char *var);
static void *sip_api_get_complex_cpp_ptr(sipWrapper *w);
static PyObject *sip_api_is_py_method(sip_gilstate_t *gil,sipMethodCache *pymc,
				      sipWrapper *sipSelf,char *cname,
				      char *mname);
static PyObject *sip_api_new_cpp_to_self_sub_class(void *cppPtr,
						   sipWrapperType *type,
						   int flags);
static PyObject *sip_api_map_cpp_to_self(void *cppPtr,sipWrapperType *type);
static void sip_api_call_hook(char *hookname);
static void sip_api_raise_unknown_exception(void);
static void sip_api_raise_class_exception(sipWrapperType *type,void *ptr);
static void sip_api_raise_sub_class_exception(sipWrapperType *type,void *ptr);
static int sip_api_add_class_instance(PyObject *dict,char *name,void *cppPtr,
				      sipWrapperType *wt);


/*
 * The data structure that represents the SIP API.
 */
static const sipAPIDef sip_api = {
	/*
	 * The following are part of the public API.
	 */
	sip_api_bad_catcher_result,
	sip_api_bad_length_for_slice,
	sip_api_build_result,
	sip_api_call_method,
	sip_api_class_name,
#if defined(SIP_QT_SUPPORT)
	sip_api_connect_rx,
#else
	NULL,
#endif
	sip_api_convert_from_sequence_index,
	sip_api_convert_to_cpp,
#if defined(SIP_QT_SUPPORT)
	sip_api_disconnect_rx,
	sip_api_emit_signal,
#else
	NULL,
	NULL,
#endif
	sip_api_free,
#if defined(SIP_QT_SUPPORT)
	sip_api_get_sender,
#else
	NULL,
#endif
	sip_api_get_wrapper,
	sip_api_malloc,
	sip_api_map_int_to_class,
	sip_api_map_string_to_class,
	sip_api_parse_result,
	sip_api_trace,
	sip_api_transfer,
	/*
	 * The following are not part of the public API.
	 */
	sip_api_export_module,
	sip_api_parse_args,
	sip_api_common_ctor,
	sip_api_common_dtor,
	sip_api_convert_from_void_ptr,
	sip_api_convert_to_void_ptr,
	sip_api_no_ctor,
	sip_api_no_function,
	sip_api_no_method,
	sip_api_bad_class,
	sip_api_bad_set_type,
	sip_api_get_cpp_ptr,
	sip_api_get_complex_cpp_ptr,
	sip_api_is_py_method,
	sip_api_map_cpp_to_self,
	sip_api_map_cpp_to_self_sub_class,
	sip_api_new_cpp_to_self,
	sip_api_new_cpp_to_self_sub_class,
	sip_api_call_hook,
	sip_api_start_thread,
	sip_api_end_thread,
	sip_api_raise_unknown_exception,
	sip_api_raise_class_exception,
	sip_api_raise_sub_class_exception,
	sip_api_add_class_instance,
	sip_api_convert_from_named_enum,
};


#define	PARSE_OK	0x00000000		/* Parse is Ok so far. */
#define	PARSE_MANY	0x10000000		/* Too many arguments. */
#define	PARSE_FEW	0x20000000		/* Too few arguments. */
#define	PARSE_TYPE	0x30000000		/* Argument with a bad type. */
#define	PARSE_UNBOUND	0x40000000		/* Unbound method. */
#define	PARSE_FORMAT	0x50000000		/* Bad format character. */
#define	PARSE_RAISED	0x60000000		/* Exception already raised. */
#define	PARSE_STICKY	0x80000000		/* The error sticks. */
#define	PARSE_MASK	0xf0000000

#define	FORMAT_DEREF		0x01	/* The pointer will be dereferenced. */
#define	FORMAT_TRANSFER		0x02	/* Implement /Transfer/. */
#define	FORMAT_TRANSFER_BACK	0x04	/* Implement /TransferBack/. */
#define	FORMAT_GET_WRAPPER	0x08	/* Implement /GetWrapper/. */

#define	SIP_MC_FOUND	0x01		/* If we have looked for the method. */
#define	SIP_MC_ISMETH	0x02		/* If we looked and there was one. */

#define	sipFoundMethod(m)	((m) -> mcflags & SIP_MC_FOUND)
#define	sipSetFoundMethod(m)	((m) -> mcflags |= SIP_MC_FOUND)
#define	sipIsMethod(m)		((m) -> mcflags & SIP_MC_ISMETH)
#define	sipSetIsMethod(m)	((m) -> mcflags |= SIP_MC_ISMETH)


typedef PyObject *(*convfromfunc)(void *);	/* From convertor function. */
typedef int (*convfunc)(PyObject *,void **,int *);/* To convertor function. */
typedef void *(*forceconvfunc)(PyObject *,int *);/* Force to convertor function. */


static PyTypeObject sipWrapperType_Type;
static sipWrapperType sipWrapper_Type;
static PyTypeObject sipVoidPtr_Type;

PyInterpreterState *sipInterpreter = NULL;

#if defined(SIP_QT_SUPPORT)
sipWrapperType *sipQObjectClass = NULL;
#endif


/*
 * Various strings as Python objects created as and when needed.
 */
static PyObject *licenseName = NULL;
static PyObject *licenseeName = NULL;
static PyObject *typeName = NULL;
static PyObject *timestampName = NULL;
static PyObject *signatureName = NULL;

static sipObjectMap cppPyMap;			/* The C/C++ to Python map. */
static sipExportedModuleDef *clientList = NULL;	/* List of registered clients. */
static unsigned traceMask = 0;			/* The current trace mask. */

static sipTypeDef *currentType = NULL;		/* The type being created. */


static void addSlots(sipWrapperType *wt, sipTypeDef *td);
static void initSlots(sipWrapperType *wt, sipPySlotDef *slots);
static void *findSlot(PyObject *self,sipPySlotType st);
static int objobjargprocSlot(PyObject *self,PyObject *arg1,PyObject *arg2,
			     sipPySlotType st);
static int intobjargprocSlot(PyObject *self,int arg1,PyObject *arg2,
			     sipPySlotType st);
static PyObject *buildObject(PyObject *tup,char *fmt,va_list va);
static int parsePass1(sipWrapper **selfp,int *selfargp,int *argsParsedp,
		      PyObject *sipArgs,char *fmt,va_list va);
static int parsePass2(sipWrapper *self,int selfarg,int nrargs,
		      PyObject *sipArgs,char *fmt,va_list va);
static int getSelfFromArgs(sipWrapperType *type,PyObject *args,int argnr,
			   sipWrapper **selfp);
static PyObject *createEnumMember(sipWrapperType *wt, sipEnumMemberDef *enm);
static PyObject *handleGetLazyAttr(PyObject *nameobj,sipWrapperType *wt,
				   sipWrapper *w);
static int handleSetLazyAttr(PyObject *nameobj,PyObject *valobj,
			     sipWrapperType *wt,sipWrapper *w);
static int getNonStaticVariables(sipWrapperType *wt,sipWrapper *w,
				 PyObject **ndict);
static void findLazyAttr(sipWrapperType *wt,char *name,PyMethodDef **pmdp,
			 sipEnumMemberDef **enmp,PyMethodDef **vmdp,
			 sipWrapperType **in);
static int compareMethodName(const void *key,const void *el);
static int compareEnumMemberName(const void *key,const void *el);
static int checkPointer(void *ptr);
static void setBadNone(int a);
static void badArgs(int argsParsed,char *classname,char *method);
static void finalise(void);
static sipWrapperType *createType(sipExportedModuleDef *client,
				  PyObject *mname, sipTypeDef *type,
				  PyObject *mod_dict);
static PyTypeObject *createEnum(sipExportedModuleDef *client, PyObject *mname,
				sipEnumDef *ed, PyObject *mod_dict);
static PyObject *createBaseName(const char *name);
static PyObject *createTypeDict(PyObject *mname);
static sipExportedModuleDef *getClassModule(sipSuperClassDef *sup,
					    sipExportedModuleDef *em);
static sipWrapperType *convertSubClass(sipWrapperType *type,void *cppPtr);
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 addLongInstances(PyObject *dict,sipLongInstanceDef *li);
static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di);
static int addEnumInstances(PyObject *dict,sipEnumInstanceDef *ei);
static int addClassInstances(PyObject *dict,sipClassInstanceDef *ci);
static int addSingleClassInstance(PyObject *dict,char *name,void *cppPtr,
				  sipWrapperType *wt,int initflags);
static int addLicense(PyObject *dict,sipLicenseDef *lc);
static PyObject *cast(PyObject *self,PyObject *args);
static PyObject *setTraceMask(PyObject *self,PyObject *args);
static PyObject *wrapInstance(PyObject *self,PyObject *args);
static PyObject *unwrapInstance(PyObject *self,PyObject *args);
static PyObject *transfer(PyObject *self,PyObject *args);
static int sipWrapperType_Check(PyObject *op);

#if defined(SIP_QT_SUPPORT)
static int findClassArg(sipWrapperType **wttab, const char *name, size_t len,
			sipSigArg *at);
static int findMtypeArg(sipMappedTypeDef **mttab, const char *name, size_t len,
			sipSigArg *at);
static int findEnumArg(sipExportedModuleDef *emd, const char *name, size_t len,
		       sipSigArg *at);
static int sameScopedName(const char *pyname, const char *name, size_t len);
#endif


/*
 * The Python module initialisation function.
 */
#if defined(SIP_STATIC_MODULE)
void initsip(void)
#else
PyMODINIT_FUNC initsip(void)
#endif
{
	static PyMethodDef methods[] = {
		{"cast", cast, METH_VARARGS, NULL},
		{"settracemask", setTraceMask, METH_VARARGS, NULL},
		{"transfer", transfer, METH_VARARGS, NULL},
		{"wrapinstance", wrapInstance, METH_VARARGS, NULL},
		{"unwrapinstance", unwrapInstance, METH_VARARGS, NULL},
		{NULL, NULL, 0, NULL}
	};

	int rc;
	PyObject *mod, *mod_dict, *obj;

#ifdef WITH_THREAD
	PyEval_InitThreads();
#endif

	/* Initialise the types. */
	sipWrapperType_Type.tp_base = &PyType_Type;

	if (PyType_Ready(&sipWrapperType_Type) < 0)
		Py_FatalError("sip: Failed to initialise sip.wrappertype type");

	if (PyType_Ready(&sipWrapper_Type.super.type) < 0)
		Py_FatalError("sip: Failed to initialise sip.wrapper type");

	if (PyType_Ready(&sipVoidPtr_Type) < 0)
		Py_FatalError("sip: Failed to initialise sip.voidptr type");

	mod = Py_InitModule("sip",methods);
	mod_dict = PyModule_GetDict(mod);

	/* Publish the SIP API. */
	if ((obj = PyCObject_FromVoidPtr((void *)&sip_api,NULL)) == NULL)
		Py_FatalError("sip: Failed to create _C_API object");

	rc = PyDict_SetItemString(mod_dict,"_C_API",obj);
	Py_DECREF(obj);

	if (rc < 0)
		Py_FatalError("sip: Failed to add _C_API object to module dictionary");

	/* Add the SIP version number, but don't worry about errors. */
	if ((obj = PyInt_FromLong(SIP_VERSION)) != NULL)
	{
		PyDict_SetItemString(mod_dict, "SIP_VERSION", obj);
		Py_DECREF(obj);
	}

	/* Add the type objects, but don't worry about errors. */
	PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type);
	PyDict_SetItemString(mod_dict, "wrapper", (PyObject *)&sipWrapper_Type);
	PyDict_SetItemString(mod_dict, "voidptr", (PyObject *)&sipVoidPtr_Type);

	/* Initialise the module if it hasn't already been done. */
	if (sipInterpreter == NULL)
	{
		Py_AtExit(finalise);

		/* Initialise the object map. */
		sipOMInit(&cppPyMap);

#if defined(SIP_QT_SUPPORT)
		sipQObjectClass = NULL;
#endif

		/*
		 * Get the current interpreter.  This will be shared between
		 * all threads.
		 */
		sipInterpreter = PyThreadState_Get() -> interp;
	}
}


/*
 * Display a printf() style message to stderr according to the current trace
 * mask.
 */
static void sip_api_trace(unsigned mask,const char *fmt,...)
{
	va_list ap;

	va_start(ap,fmt);

	if (mask & traceMask)
		vfprintf(stderr,fmt,ap);

	va_end(ap);
}


/*
 * Set the trace mask.
 */
static PyObject *setTraceMask(PyObject *self,PyObject *args)
{
	unsigned new_mask;

	if (PyArg_ParseTuple(args,"I:settracemask",&new_mask))
	{
		traceMask = new_mask;

		Py_INCREF(Py_None);
		return Py_None;
	}

	return NULL;
}


/*
 * Transfer the ownership of an instance.
 */
static PyObject *transfer(PyObject *self,PyObject *args)
{
	sipWrapper *w;
	int toCpp;

	if (PyArg_ParseTuple(args,"O!i:transfer",&sipWrapper_Type,&w,&toCpp))
	{
		/*
		 * Note that we don't call sip_api_transfer() because we are
		 * handling the extra reference differently.  This is done so
		 * that a transfer to C++ allows the corresponding Python
		 * to be garbage collected.  We just do the reverse for a
		 * transfer to Python.
		 */
		if (toCpp)
		{
			sipResetPyOwned(w);

			if (sipIsExtraRef(w))
			{
				sipResetIsExtraRef(w);
				Py_DECREF(self);
			}
		}
		else
		{
			sipSetPyOwned(w);

			if (!sipIsExtraRef(w))
			{
				sipSetIsExtraRef(w);
				Py_INCREF(self);
			}
		}

		Py_INCREF(Py_None);
		return Py_None;
	}

	return NULL;
}


/*
 * Cast an instance to one of it's sub or super-classes by returning a new
 * Python object with the superclass type wrapping the same C++ instance.
 */
static PyObject *cast(PyObject *self,PyObject *args)
{
	sipWrapper *w;
	sipWrapperType *wt;
	void *addr;
	PyTypeObject *ft, *tt;

	if (!PyArg_ParseTuple(args,"O!O!:cast",&sipWrapper_Type,&w,&sipWrapperType_Type,&wt))
		return NULL;

	ft = ((PyObject *)w) -> ob_type;
	tt = (PyTypeObject *)wt;

	if (!PyType_IsSubtype(tt, ft) && ft != tt && !PyType_IsSubtype(ft, tt))
	{
		PyErr_SetString(PyExc_TypeError,"argument 1 of sip.cast() must be an instance of a sub or super-type of argument 2");
		return NULL;
	}

	if ((addr = sip_api_get_cpp_ptr(w,wt)) == 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 sip_api_new_cpp_to_self(addr,wt,SIP_NOT_IN_MAP);
}


/*
 * Unwrap an instance.
 */
static PyObject *unwrapInstance(PyObject *self,PyObject *args)
{
	sipWrapper *w;

	if (PyArg_ParseTuple(args,"O!:unwrapinstance",&sipWrapper_Type,&w))
	{
		void *addr;

		/*
		 * We just get the pointer but don't try and cast it (which
		 * isn't needed and wouldn't work with the way casts are
		 * currently implemented if we are unwrapping something derived
		 * from a wrapped class).
		 */
		if ((addr = sip_api_get_cpp_ptr(w,NULL)) == NULL)
			return NULL;

		return PyLong_FromVoidPtr(addr);
	}

	return NULL;
}


/*
 * Wrap an instance.
 */
static PyObject *wrapInstance(PyObject *self,PyObject *args)
{
	unsigned long addr;
	sipWrapperType *wt;

	if (PyArg_ParseTuple(args,"kO!:wrapinstance",&addr,&sipWrapperType_Type,&wt))
		return sip_api_map_cpp_to_self_sub_class((void *)addr,wt);

	return NULL;
}


/*
 * Register a client module.  A negative value is returned and an exception
 * raised if there was an error.  Not normally needed by handwritten code.
 */
static int sip_api_export_module(sipExportedModuleDef *client,
				 unsigned api_major,unsigned api_minor,
				 PyObject *mod_dict)
{
	sipExportedModuleDef *em;
	sipImportedModuleDef *im;
	sipSubClassConvertorDef *scc;
	sipWrapperType **mw;
	sipEnumMemberDef *emd;
	PyObject *mname;
	int i;

	/* Check that we can support it. */

	if (api_major != SIP_API_MAJOR_NR || api_minor > SIP_API_MINOR_NR)
	{
		PyErr_Format(PyExc_RuntimeError,"the sip module supports API v%d.0 to v%d.%d but the %s module requires API v%d.%d",SIP_API_MAJOR_NR,SIP_API_MAJOR_NR,SIP_API_MINOR_NR,client -> em_name,api_major,api_minor);

		return -1;
	}

#if !defined(SIP_QT_SUPPORT)
	if (client -> em_qobject_class >= 0)
	{
		PyErr_Format(PyExc_RuntimeError,"the sip module has not been built with the Qt support needed by the %s module",client -> em_name);

		return -1;
	}
#endif

	for (em = clientList; em != NULL; em = em -> em_next)
	{
		/* SIP clients must have unique names. */
		if (strcmp(em -> em_name,client -> em_name) == 0)
		{
			PyErr_Format(PyExc_RuntimeError,"the sip module has already registered a module called %s",client -> em_name);

			return -1;
		}

#if defined(SIP_QT_SUPPORT)
		/* Only one module can claim to wrap QObject. */
		if (em -> em_qobject_class >= 0 && client -> em_qobject_class >= 0)
		{
			PyErr_Format(PyExc_RuntimeError,"the %s and %s modules both wrap the QObject class",client -> em_name,em -> em_name);

			return -1;
		}
#endif
	}

	/* Import any required modules. */
	if ((im = client -> em_imports) != NULL)
	{
		while (im -> im_name != NULL)
		{
			PyObject *mod;

			if ((mod = PyImport_ImportModule(im -> im_name)) == NULL)
				return -1;

			for (em = clientList; em != NULL; em = em -> em_next)
				if (strcmp(em -> em_name,im -> im_name) == 0)
					break;

			if (em == NULL)
			{
				PyErr_Format(PyExc_RuntimeError,"the %s module failed to register with the sip module",im -> im_name);

				return -1;
			}

			/* Check the versions are compatible. */
			if (im -> im_version >= 0 || em -> em_version >= 0)
				if (im -> im_version != em -> em_version)
				{
					PyErr_Format(PyExc_RuntimeError,"the %s module is version %d but the %s module requires version %d",em -> em_name,em -> em_version,client -> em_name,im -> im_version);

					return -1;
				}

			/* Save the imported module. */
			im -> im_module = em;

			++im;
		}
	}

	/* Convert the module name to an object. */
	if ((mname = PyString_FromString(client -> em_name)) == NULL)
		return -1;

	/* Create the module's classes. */
	if ((mw = client -> em_types) != NULL)
	{
		sipTypeDef *td;

		while ((td = (sipTypeDef *)*mw) != NULL)
			if ((*mw++ = createType(client,mname,td,mod_dict)) == NULL)
				return -1;
	}

#if defined(SIP_QT_SUPPORT)
	/* Get the QObject class pointer. */
	if (client -> em_qobject_class >= 0)
		sipQObjectClass = client -> em_types[client -> em_qobject_class];
#endif

	/* Set the base class object for any sub-class convertors. */
	if ((scc = client -> em_convertors) != NULL)
		while (scc -> scc_convertor != NULL)
		{
			em = getClassModule(&scc -> scc_base,client);

			scc -> scc_basetype = em -> em_types[scc -> scc_base.sc_class];

			++scc;
		}

	/* Create the module's enums. */
	if (client -> em_nrenums != 0)
	{
		if ((client -> em_enums = sip_api_malloc(client -> em_nrenums * sizeof (PyTypeObject *))) == NULL)
			return -1;

		for (i = 0; i < client -> em_nrenums; ++i)
			if ((client -> em_enums[i] = createEnum(client,mname,&client -> em_enumdefs[i],mod_dict)) == NULL)
				return -1;
	}

	for (emd = client -> em_enummembers, i = 0; i < client -> em_nrenummembers; ++i, ++emd)
	{
		PyObject *mo;

		if ((mo = sip_api_convert_from_named_enum(emd -> em_val, client -> em_enums[emd -> em_enum])) == NULL)
			return -1;

		if (PyDict_SetItemString(mod_dict, emd -> em_name, mo) < 0)
			return -1;

		Py_DECREF(mo);
	}


	/*
	 * Add any class static instances.  We need to do this once all types
	 * are fully formed because of potential interdependencies.
	 */
	if ((mw = client -> em_types) != NULL)
	{
		sipWrapperType *wt;

		while ((wt = *mw++) != NULL)
			if (addInstances(wt -> super.type.tp_dict,&wt -> type -> td_instances) < 0)
				return -1;
	}

	/* Add any global static instances. */
	if (addInstances(mod_dict,&client -> em_instances) < 0)
		return -1;

	/* Add any license. */
	if (client -> em_license != NULL && addLicense(mod_dict,client -> em_license) < 0)
		return -1;

	/* Add to the list of client modules. */
	client -> em_next = clientList;
	clientList = client;

	/* Garbage collect. */
	Py_DECREF(mname);

	return 0;
}


/*
 * Called by the interpreter to do any final clearing up, just in case the
 * interpreter will re-start.
 */
static void finalise(void)
{
	Py_XDECREF(licenseName);
	licenseName = NULL;

	Py_XDECREF(licenseeName);
	licenseeName = NULL;

	Py_XDECREF(typeName);
	typeName = NULL;

	Py_XDECREF(timestampName);
	timestampName = NULL;

	Py_XDECREF(signatureName);
	signatureName = NULL;

	/* Release all memory we've allocated directly. */
	sipOMFinalise(&cppPyMap);

	/* Re-initialise those globals that (might) need it. */
	clientList = NULL;
	sipInterpreter = NULL;
}


/*
 * 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);
}


/*
 * Call the Python re-implementation of a C++ virtual.
 */
static PyObject *sip_api_call_method(int *isErr,PyObject *method,char *fmt,...)
{
	PyObject *args, *res;
	va_list va;

	va_start(va,fmt);

	if ((args = PyTuple_New(strlen(fmt))) != NULL && buildObject(args,fmt,va) != NULL)
		res = PyEval_CallObject(method,args);
	else
	{
		res = NULL;

		if (isErr != NULL)
			*isErr = TRUE;
	}

	Py_XDECREF(args);

	va_end(va);

	return res;
}


/*
 * Build a result object based on a format string.
 */
static PyObject *sip_api_build_result(int *isErr,char *fmt,...)
{
	PyObject *res = NULL;
	int badfmt, tupsz;
	va_list va;

	va_start(va,fmt);

	/* Basic validation of the format string. */

	badfmt = FALSE;

	if (*fmt == '(')
	{
		char *ep;

		if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0')
			badfmt = TRUE;
		else
			tupsz = ep - fmt - 1;
	}
	else if (strlen(fmt) == 1)
		tupsz = -1;
	else
		badfmt = TRUE;

	if (badfmt)
		PyErr_Format(PyExc_SystemError,"sipBuildResult(): invalid format string \"%s\"",fmt);
	else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL)
		res = buildObject(res,fmt,va);

	va_end(va);

	if (res == NULL && isErr != NULL)
		*isErr = TRUE;

	return res;
}


/*
 * Get the values off the stack and put them into an object.
 */
static PyObject *buildObject(PyObject *obj,char *fmt,va_list va)
{
	char ch, termch;
	int i;

	/*
	 * The format string has already been checked that it is properly
	 * formed if it is enclosed in parenthesis.
	 */
	if (*fmt == '(')
	{
		termch = ')';
		++fmt;
	}
	else
		termch = '\0';

	i = 0;

	while ((ch = *fmt++) != termch)
	{
		PyObject *el;

		switch (ch)
		{
		case 'a':
			{
				char *s;
				int l;

				s = va_arg(va,char *);
				l = va_arg(va,int);

				if (s != NULL)
					el = PyString_FromStringAndSize(s,l);
				else
				{
					Py_INCREF(Py_None);
					el = Py_None;
				}
			}

			break;

		case 'b':
			el = PyBool_FromLong((long)va_arg(va,int));
			break;

		case 'c':
			{
				char c = (char)va_arg(va,int);

				el = PyString_FromStringAndSize(&c,1);
			}

			break;

		case 'e':
			el = PyInt_FromLong(va_arg(va,int));
			break;

		case 'E':
			{
				int ev = va_arg(va, int);
				PyTypeObject *et = va_arg(va, PyTypeObject *);

				el = sip_api_convert_from_named_enum(ev, et);
			}

			break;

		case 'd':
		case 'f':
			el = PyFloat_FromDouble(va_arg(va,double));
			break;

		case 'h':
		case 'i':
			el = PyInt_FromLong(va_arg(va,int));
			break;

		case 'l':
			el = PyInt_FromLong(va_arg(va,long));
			break;

		case 's':
			{
				char *s = va_arg(va,char *);

				if (s != NULL)
					el = PyString_FromString(s);
				else
				{
					Py_INCREF(Py_None);
					el = Py_None;
				}
			}

			break;

		case 'M':
			{
				void *sipCpp = va_arg(va,void *);
				sipWrapperType *wt = va_arg(va,sipWrapperType *);

				el = sip_api_map_cpp_to_self_sub_class(sipCpp,wt);
			}

			break;

		case 'N':
			{
				void *sipCpp = va_arg(va,void *);
				sipWrapperType *wt = va_arg(va,sipWrapperType *);

				el = sip_api_new_cpp_to_self_sub_class(sipCpp,wt,SIP_PY_OWNED|SIP_SIMPLE);
			}

			break;

		case 'O':
			{
				void *sipCpp = va_arg(va,void *);
				sipWrapperType *wt = va_arg(va,sipWrapperType *);

				el = sip_api_map_cpp_to_self(sipCpp,wt);
			}

			break;

		case 'P':
			{
				void *sipCpp = va_arg(va,void *);
				sipWrapperType *wt = va_arg(va,sipWrapperType *);

				el = sip_api_new_cpp_to_self(sipCpp,wt,SIP_PY_OWNED|SIP_SIMPLE);
			}

			break;

		case 'R':
			el = va_arg(va,PyObject *);
			break;

		case 'S':
			el = va_arg(va,PyObject *);
			Py_INCREF(el);
			break;

		case 'T':
			{
				void *sipCpp = va_arg(va,void *);
				convfromfunc func = va_arg(va,convfromfunc);

				el = func(sipCpp);
			}

			break;

		case 'V':
			el = sip_api_convert_from_void_ptr(va_arg(va,void *));
			break;

		default:
			PyErr_Format(PyExc_SystemError,"buildObject(): invalid format character '%c'",ch);
			el = NULL;
		}

		if (el == NULL)
		{
			Py_XDECREF(obj);
			return NULL;
		}

		if (obj == NULL)
			return el;

		PyTuple_SET_ITEM(obj,i,el);
		++i;
	}

	return obj;
}


/*
 * Parse a result object based on a format string.
 */
static int sip_api_parse_result(int *isErr,PyObject *method,PyObject *res,char *fmt,...)
{
	int badfmt, tupsz, rc = 0;
	va_list va;

	va_start(va,fmt);

	/* Basic validation of the format string. */

	badfmt = FALSE;

	if (*fmt == '(')
	{
		char *ep;

		if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0')
			badfmt = TRUE;
		else
			tupsz = ep - ++fmt;
	}
	else if (strlen(fmt) == 1)
		tupsz = -1;
	else
		badfmt = TRUE;

	if (badfmt)
	{
		PyErr_Format(PyExc_SystemError,"sipParseResult(): invalid format string \"%s\"",fmt);
		rc = -1;
	}
	else if (tupsz >= 0 && (!PyTuple_Check(res) || PyTuple_GET_SIZE(res) != tupsz))
	{
		sip_api_bad_catcher_result(method);
		rc = -1;
	}
	else
	{
		char ch;
		int i = 0;

		while ((ch = *fmt++) != '\0' && ch != ')' && rc == 0)
		{
			PyObject *arg;
			int invalid = FALSE;

			if (tupsz > 0)
			{
				arg = PyTuple_GET_ITEM(res,i);
				++i;
			}
			else
				arg = res;

			switch (ch)
			{
			case 'a':
				{
					char **p = va_arg(va,char **);
					int *szp = va_arg(va,int *);

					if (arg == Py_None)
					{
						*p = NULL;
						*szp = 0;
					}
					else if (PyString_Check(arg))
					{
						*p = PyString_AS_STRING(arg);
						*szp = PyString_GET_SIZE(arg);
					}
					else
						invalid = TRUE;
				}

				break;

			case 'b':
				{
					long v = PyInt_AsLong(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						sipSetBool(va_arg(va,void *),(int)v);
				}

				break;

			case 'c':
				{
					if (PyString_Check(arg) && PyString_GET_SIZE(arg) == 1)
						*va_arg(va,char *) = *PyString_AS_STRING(arg);
					else
						invalid = TRUE;
				}

				break;

			case 'd':
				{
					double v = PyFloat_AsDouble(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,double *) = v;
				}

				break;

			case 'e':
				{
					long v = PyInt_AsLong(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,int *) = (int)v;
				}

				break;

			case 'E':
				{
					PyTypeObject *et = va_arg(va, PyTypeObject *);
					int *p = va_arg(va, int *);

					if (PyObject_TypeCheck(arg, et))
						*p = PyInt_AsLong(arg);
					else
						invalid = TRUE;
				}

				break;

			case 'f':
				{
					double v = PyFloat_AsDouble(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,float *) = (float)v;
				}

				break;

			case 'h':
				{
					long v = PyInt_AsLong(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,short *) = (short)v;
				}

				break;

			case 'i':
				{
					long v = PyInt_AsLong(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,int *) = (int)v;
				}

				break;

			case 'l':
				{
					long v = PyInt_AsLong(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,long *) = v;
				}

				break;

			case 's':
				{
					char **p = va_arg(va,char **);

					if (arg == Py_None)
						*p = NULL;
					else if (PyString_Check(arg))
						*p = PyString_AS_STRING(arg);
					else
						invalid = TRUE;
				}

				break;

			case 'L':
				{
					forceconvfunc func = va_arg(va,forceconvfunc);
					void **sipCpp = va_arg(va,void **);
					int iserr = FALSE;

					*sipCpp = func(arg,&iserr);

					if (iserr)
						invalid = TRUE;
				}

				break;

			case 'M':
				{
					forceconvfunc func = va_arg(va,forceconvfunc);
					void **sipCpp = va_arg(va,void **);
					int iserr = FALSE;

					*sipCpp = func(arg,&iserr);

					if (iserr || *sipCpp == NULL)
						invalid = TRUE;
				}

				break;

			case 'N':
				{
					PyTypeObject *type = va_arg(va,PyTypeObject *);
					PyObject **p = va_arg(va,PyObject **);

					if (arg == Py_None || PyObject_TypeCheck(arg,type))
					{
						Py_INCREF(arg);
						*p = arg;
					}
					else
						invalid = TRUE;
				}

				break;

			case 'O':
				Py_INCREF(arg);
				*va_arg(va,PyObject **) = arg;
				break;

			case 'T':
				{
					PyTypeObject *type = va_arg(va,PyTypeObject *);
					PyObject **p = va_arg(va,PyObject **);

					if (PyObject_TypeCheck(arg,type))
					{
						Py_INCREF(arg);
						*p = arg;
					}
					else
						invalid = TRUE;
				}

				break;

			case 'V':
				{
					void *v = sip_api_convert_to_void_ptr(arg);

					if (PyErr_Occurred())
						invalid = TRUE;
					else
						*va_arg(va,void **) = v;
				}

				break;

			case 'Z':
				if (arg != Py_None)
					invalid = TRUE;

				break;

			default:
				PyErr_Format(PyExc_SystemError,"sipParseResult(): invalid format character '%c'",ch);
				rc = -1;
			}

			if (invalid)
			{
				sip_api_bad_catcher_result(method);
				rc = -1;
				break;
			}
		}
	}

	va_end(va);

	if (isErr != NULL && rc < 0)
		*isErr = TRUE;

	return rc;
}


/*
 * Parse the arguments to a C/C++ function without any side effects.
 */
static int sip_api_parse_args(int *argsParsedp,PyObject *sipArgs,char *fmt,...)
{
	int valid, nrargs, selfarg;
	sipWrapper *self;
	PyObject *single_arg;
	va_list va;

	/* Previous sticky errors stop subsequent parses. */
	if (*argsParsedp & PARSE_STICKY)
		return 0;

	/* See if we are parsing a tuple or a single argument. */
	if (PyTuple_Check(sipArgs))
	{
		Py_INCREF(sipArgs);
		nrargs = PyTuple_GET_SIZE(sipArgs);
	}
	else if ((single_arg = PyTuple_New(1)) != NULL)
	{
		Py_INCREF(sipArgs);
		PyTuple_SET_ITEM(single_arg,0,sipArgs);

		sipArgs = single_arg;
		nrargs = 1;
	}
	else
		return 0;

	/*
	 * The first pass checks all the types and does conversions that are
	 * cheap and have no side effects.
	 */
	va_start(va,fmt);
	valid = parsePass1(&self,&selfarg,&nrargs,sipArgs,fmt,va);
	va_end(va);

	if (valid != PARSE_OK)
	{
		int pvalid, pnrargs;

		/*
		 * Use this error if there was no previous error, or if we
		 * have parsed more arguments this time, or if the previous
		 * error was that there were too many arguments.
		 */
		pvalid = (*argsParsedp & PARSE_MASK);
		pnrargs = (*argsParsedp & ~PARSE_MASK);

		if (pvalid == PARSE_OK || pnrargs < nrargs ||
		    (pnrargs == nrargs && pvalid == PARSE_MANY))
			*argsParsedp = valid | nrargs;

		Py_DECREF(sipArgs);

		return 0;
	}

	/*
	 * The second pass does any remaining conversions now that we know we
	 * have the right signature.
	 */
	va_start(va,fmt);
	valid = parsePass2(self,selfarg,nrargs,sipArgs,fmt,va);
	va_end(va);

	if (valid != PARSE_OK)
	{
		*argsParsedp = valid | PARSE_STICKY;

		Py_DECREF(sipArgs);

		return 0;
	}

	*argsParsedp = nrargs;

	Py_DECREF(sipArgs);

	return 1;
}


/*
 * First pass of the argument parse, converting those that can be done so
 * without any side effects.  Return PARSE_OK if the arguments matched.
 */
static int parsePass1(sipWrapper **selfp,int *selfargp,int *argsParsedp,
		      PyObject *sipArgs,char *fmt,va_list va)
{
	int valid, compulsory, nrargs, argnr, nrparsed;

	valid = PARSE_OK;
	nrargs = *argsParsedp;
	nrparsed = 0;
	compulsory = TRUE;
	argnr = 0;

	/*
	 * Handle those format characters that deal with the "self" argument.
	 * They will always be the first one.
	 */
	*selfp = NULL;
	*selfargp = FALSE;

	switch (*fmt++)
	{
	case 'm':
	case 'p':
		{
			PyObject *self;
			sipWrapperType *type;

			self = va_arg(va,PyObject *);
			type = va_arg(va,sipWrapperType *);
			va_arg(va,void **);

			if (self == NULL)
			{
				if ((valid = getSelfFromArgs(type,sipArgs,argnr,selfp)) != PARSE_OK)
					break;

				*selfargp = TRUE;
				++nrparsed;
				++argnr;
			}
			else
				*selfp = (sipWrapper *)self;

			break;
		}

	case 'C':
		*selfp = (sipWrapper *)va_arg(va,PyObject *);
		break;

	default:
		--fmt;
	}

	if (*fmt == 't')
	{
		/* Return self. */
		*va_arg(va,PyObject **) = (PyObject *)*selfp;
		++fmt;
	}

	/* Now handle the remaining arguments. */
	while (valid == PARSE_OK)
	{
		char ch;
		PyObject *arg;

		PyErr_Clear();

		/* See if the following arguments are optional. */
		if ((ch = *fmt++) == '|')
		{
			compulsory = FALSE;
			ch = *fmt++;
		}

		/* See if we don't expect anything else. */

		if (ch == '\0')
		{
			/* Invalid if there are still arguments. */
			if (argnr < nrargs)
				valid = PARSE_MANY;

			break;
		}

		/* See if we have run out of arguments. */

		if (argnr == nrargs)
		{
			/* Invalid if we still expect compulsory arguments. */
			if (ch != '\0' && compulsory)
				valid = PARSE_FEW;

			break;
		}

		/* Get the next argument. */
		arg = PyTuple_GET_ITEM(sipArgs,argnr);
		++argnr;

		switch (ch)
		{
		case 's':
			{
				/* String or None. */

				char **p = va_arg(va,char **);

				if (arg == Py_None)
					*p = NULL;
				else if (PyString_Check(arg))
					*p = PyString_AS_STRING(arg);
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'S':
			{
				/* Slot name, return the name. */

				if (PyString_Check(arg))
				{
					char *s = PyString_AS_STRING(arg);

					if (*s == '1' || *s == '2' || *s == '9')
						*va_arg(va,char **) = s;
					else
						valid = PARSE_TYPE;
				}
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'G':
			{
				/* Signal name, return the name. */

				if (PyString_Check(arg))
				{
					char *s = PyString_AS_STRING(arg);

					if (*s == '2' || *s == '9')
						*va_arg(va,char **) = s;
					else
						valid = PARSE_TYPE;
				}
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'J':
			{
				/* Class instance with no convertors. */

				sipWrapperType *type;

				type = va_arg(va,sipWrapperType *);
				va_arg(va,void **);

				if (arg != Py_None && !PyObject_TypeCheck(arg,&type -> super.type))
					valid = PARSE_TYPE;

				/* Handle the sub-format. */
				if (*fmt == '\0')
					valid = PARSE_FORMAT;
				else
				{
					int flags = *fmt++ - '0';

					if (flags & FORMAT_GET_WRAPPER)
						va_arg(va,PyObject **);
				}

				break;
			}

		case 'M':
			{
				/* Class instance with convertors. */

				convfunc func;

				func = va_arg(va,convfunc);
				va_arg(va,void **);
				va_arg(va,int *);

				/*
				 * Passing NULL as the last parameter to the
				 * convertor function tells it to only check
				 * the type and not do any conversion.
				 */
				if (arg != Py_None && !func(arg,NULL,NULL))
					valid = PARSE_TYPE;

				/* Skip the sub-format. */
				if (*fmt++ == '\0')
					valid = PARSE_FORMAT;

				break;
			}


		case 'N':
			{
				/* Python object of given type or None. */

				PyTypeObject *type = va_arg(va,PyTypeObject *);
				PyObject **p = va_arg(va,PyObject **);

				if (arg == Py_None || PyObject_TypeCheck(arg,type))
					*p = arg;
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'P':
			{
				/*
				 * Python object of any type with a
				 * sub-format.
				 */

				*va_arg(va,PyObject **) = arg;

				/* Skip the sub-format. */
				if (*fmt++ == '\0')
					valid = PARSE_FORMAT;

				break;
			}

		case 'T':
			{
				/* Python object of given type. */

				PyTypeObject *type = va_arg(va,PyTypeObject *);
				PyObject **p = va_arg(va,PyObject **);

				if (PyObject_TypeCheck(arg,type))
					*p = arg;
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'R':
			{
#if defined(SIP_QT_SUPPORT)
				/* Sub-class of QObject. */

				if (PyObject_TypeCheck(arg,&sipQObjectClass -> super.type))
					*va_arg(va,PyObject **) = arg;
				else
					valid = PARSE_TYPE;
#else
				valid = PARSE_TYPE;
#endif

				break;
			}

		case 'F':
			{
				/* Python callable object. */
 
				if (PyCallable_Check(arg))
					*va_arg(va,PyObject **) = arg;
				else
					valid = PARSE_TYPE;
 
				break;
			}

		case 'H':
			{
				/* Python callable object or None. */
 
				if (arg == Py_None || PyCallable_Check(arg))
					*va_arg(va,PyObject **) = arg;
				else
					valid = PARSE_TYPE;
 
				break;
			}

		case 'q':
			{
#if defined(SIP_QT_SUPPORT)
				/* Qt receiver to connect. */

				va_arg(va,char *);
				va_arg(va,void **);
				va_arg(va,const char **);

				if (!PyObject_TypeCheck(arg,(PyTypeObject *)sipQObjectClass))
					valid = PARSE_TYPE;
#else
				valid = PARSE_TYPE;
#endif

				break;
			}

		case 'Q':
			{
#if defined(SIP_QT_SUPPORT)
				/* Qt receiver to disconnect. */

				va_arg(va,char *);
				va_arg(va,void **);
				va_arg(va,const char **);

				if (!PyObject_TypeCheck(arg,(PyTypeObject *)sipQObjectClass))
					valid = PARSE_TYPE;
#else
				valid = PARSE_TYPE;
#endif

				break;
			}

		case 'y':
			{
#if defined(SIP_QT_SUPPORT)
				/* Python slot to connect. */

				va_arg(va,char *);
				va_arg(va,void **);
				va_arg(va,const char **);

				if (!PyCallable_Check(arg))
					valid = PARSE_TYPE;
#else
				valid = PARSE_TYPE;
#endif

				break;
			}

		case 'Y':
			{
#if defined(SIP_QT_SUPPORT)
				/* Python slot to disconnect. */

				va_arg(va,char *);
				va_arg(va,void **);
				va_arg(va,const char **);

				if (!PyCallable_Check(arg))
					valid = PARSE_TYPE;
#else
				valid = PARSE_TYPE;
#endif

				break;
			}

		case 'a':
			{
				/* Byte array or None. */

				char **p = va_arg(va,char **);
				int *szp = va_arg(va,int *);

				if (arg == Py_None)
				{
					*p = NULL;
					*szp = 0;
				}
				else if (PyString_Check(arg))
				{
					*p = PyString_AS_STRING(arg);
					*szp = PyString_GET_SIZE(arg);
				}
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'c':
			{
				/* Character. */

				if (PyString_Check(arg) && PyString_GET_SIZE(arg) == 1)
					*va_arg(va,char *) = *PyString_AS_STRING(arg);
				else
					valid = PARSE_TYPE;

				break;
			}

		case 'b':
			{
				/* Bool. */

				long v = PyInt_AsLong(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					sipSetBool(va_arg(va,void *),(int)v);

				break;
			}

		case 'e':
			{
				/* Anonymous enum. */

				long v = PyInt_AsLong(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,int *) = (int)v;

				break;
			}

		case 'E':
			{
				/* Named enum. */

				PyTypeObject *et = va_arg(va, PyTypeObject *);

				va_arg(va, int *);

				if (!PyObject_TypeCheck(arg, et))
					valid = PARSE_TYPE;
			}

			break;

		case 'i':
			{
				/* Integer. */

				long v = PyInt_AsLong(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,int *) = (int)v;

				break;
			}

		case 'h':
			{
				/* Short integer. */

				long v = PyInt_AsLong(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,short *) = (short)v;

				break;
			}

		case 'l':
			{
				/* Long integer. */

				long v = PyInt_AsLong(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,long *) = v;

				break;
			}

		case 'f':
			{
				/* Float. */

				double v = PyFloat_AsDouble(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,float *) = (float)v;

				break;
			}

		case 'X':
			{
				/* Constrained (ie. exact) types. */

				switch (*fmt++)
				{
				case 'd':
					{
						/* Double float. */

						if (PyFloat_Check(arg))
							*va_arg(va,double *) = PyFloat_AS_DOUBLE(arg);
						else
							valid = PARSE_TYPE;

						break;
					}

				case 'f':
					{
						/* Float. */

						if (PyFloat_Check(arg))
							*va_arg(va,float *) = (float)PyFloat_AS_DOUBLE(arg);
						else
							valid = PARSE_TYPE;

						break;
					}

				case 'i':
					{
						/* Integer. */

						if (PyInt_Check(arg))
							*va_arg(va,int *) = (int)PyInt_AS_LONG(arg);
						else
							valid = PARSE_TYPE;

						break;
					}

				default:
					valid = PARSE_FORMAT;
				}

				break;
			}

		case 'd':
			{
				/* Double float. */

				double v = PyFloat_AsDouble(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,double *) = v;

				break;
			}

		case 'v':
			{
				/* Void pointer. */

				void *v = sip_api_convert_to_void_ptr(arg);

				if (PyErr_Occurred())
					valid = PARSE_TYPE;
				else
					*va_arg(va,void **) = v;

				break;
			}

		default:
			valid = PARSE_FORMAT;
		}

		if (valid == PARSE_OK)
			++nrparsed;
	}

	*argsParsedp = nrparsed;

	return valid;
}


/*
 * Second pass of the argument parse, converting the remaining ones that might
 * have side effects.  Return PARSE_OK if there was no error.
 */
static int parsePass2(sipWrapper *self,int selfarg,int nrargs,
		      PyObject *sipArgs,char *fmt,va_list va)
{
	int a, valid;

	valid = PARSE_OK;

	/* Handle the converions of "self" first. */
	switch (*fmt++)
	{
	case 'm':
		{
			/*
			 * The address of a C++ instance when calling one of
			 * its public methods.
			 */

			sipWrapperType *type;
			void **p;

			va_arg(va,PyObject *);
			type = va_arg(va,sipWrapperType *);
			p = va_arg(va,void **);

			if ((*p = sip_api_get_cpp_ptr(self,type)) == NULL)
				valid = PARSE_RAISED;

			break;
		}

	case 'p':
		{
			/*
			 * The address of a C++ instance when calling one of
			 * its protected methods.
			 */

			void **p;

			va_arg(va,PyObject *);
			va_arg(va,sipWrapperType *);
			p = va_arg(va,void **);

			if ((*p = sip_api_get_complex_cpp_ptr(self)) == NULL)
				valid = PARSE_RAISED;

			break;
		}

	case 'C':
		va_arg(va,PyObject *);
		break;

	default:
		--fmt;
	}

	if (*fmt == 't')
	{
		va_arg(va,PyObject **);
		++fmt;
	}

	for (a = (selfarg ? 1 : 0); a < nrargs && valid == PARSE_OK; ++a)
	{
		char ch;
		PyObject *arg = PyTuple_GET_ITEM(sipArgs,a);

		/* Skip the optional character. */
		if ((ch = *fmt++) == '|')
			ch = *fmt++;

		/*
		 * Do the outstanding conversions.  For most types it has
		 * already been done, so we are just skipping the parameters.
		 */
		switch (ch)
		{
		case 'q':
			{
#if defined(SIP_QT_SUPPORT)
				/* Qt receiver to connect. */

				char *sig = va_arg(va,char *);
				void **rx = va_arg(va,void **);
				const char **slot = va_arg(va,const char **);

				if ((*rx = sipConvertRx(self,sig,arg,*slot,slot)) == NULL)
					valid = PARSE_RAISED;
#endif

				break;
			}

		case 'Q':
			{
#if defined(SIP_QT_SUPPORT)
				/* 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 ((*rx = sipGetRx(self,sig,arg,*slot,slot)) == NULL)
					valid = PARSE_RAISED;
#endif

				break;
			}

		case 'y':
			{
#if defined(SIP_QT_SUPPORT)
				/* Python slot to connect. */

				char *sig = va_arg(va,char *);
				void **rx = va_arg(va,void **);
				const char **slot = va_arg(va,const char **);

				if ((*rx = sipConvertRx(self,sig,arg,NULL,slot)) == NULL)
					valid = PARSE_RAISED;
#endif

				break;
			}

		case 'Y':
			{
#if defined(SIP_QT_SUPPORT)
				/* 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 ((*rx = sipGetRx(self,sig,arg,NULL,slot)) == NULL)
					valid = PARSE_RAISED;
#endif

				break;
			}

		case 'J':
			{
				/* Class instance with no convertors. */

				sipWrapperType *type = va_arg(va,sipWrapperType *);
				void **p = va_arg(va,void **);
				int flags = *fmt++ - '0';
				int iserr = FALSE;

				if (flags & FORMAT_GET_WRAPPER)
					*va_arg(va,PyObject **) = arg;

				*p = sip_api_convert_to_cpp(arg,type,&iserr);

				if (iserr)
					valid = PARSE_RAISED;
				else if (*p == NULL && (flags & FORMAT_DEREF))
				{
					setBadNone(a);
					valid = PARSE_RAISED;
				}
				else if (flags & FORMAT_TRANSFER)
					sip_api_transfer(arg,1);
				else if (flags & FORMAT_TRANSFER_BACK)
					sip_api_transfer(arg,0);

				break;
			}

		case 'K':
			{
				/*
				 * Class instance with no convertors and return
				 * the original Python class instance as well.
				 */

				sipWrapperType *type = va_arg(va,sipWrapperType *);
				void **p = va_arg(va,void **);
				PyObject **pobj = va_arg(va,PyObject **);
				int iserr = FALSE;

				*p = sip_api_convert_to_cpp(arg,type,&iserr);

				if (iserr)
					valid = PARSE_RAISED;
				else
					*pobj = arg;

				break;
			}

		case 'M':
			{
				/* Class instance with convertors. */

				convfunc func = va_arg(va,convfunc);
				void **p = va_arg(va,void **);
				int *heap = va_arg(va,int *);
				int flags = *fmt++ - '0';
				int iserr = FALSE;

				*heap = func(arg,p,&iserr);

				if (iserr)
					valid = PARSE_RAISED;
				else if (*p == NULL && (flags & FORMAT_DEREF))
				{
					setBadNone(a);
					valid = PARSE_RAISED;
				}
				else if (flags & FORMAT_TRANSFER)
					sip_api_transfer(arg,1);
				else if (flags & FORMAT_TRANSFER_BACK)
					sip_api_transfer(arg,0);

				break;
			}

		case 'P':
			{
				/*
				 * Python object of any type with a
				 * sub-format.
				 */

				PyObject **p = va_arg(va,PyObject **);
				int flags = *fmt++ - '0';

				if (flags & FORMAT_TRANSFER)
				{
					Py_XINCREF(*p);
				}
				else if (flags & FORMAT_TRANSFER_BACK)
				{
					Py_XDECREF(*p);
				}

				break;
			}

		case 'X':
			{
				/* Constrained (ie. exact) type. */

				++fmt;
				va_arg(va,void *);

				break;
			}


		case 'E':
			{
				/* Named enum. */

				int *p;

				va_arg(va, PyTypeObject *);
				p = va_arg(va, int *);

				*p = PyInt_AsLong(arg);

				break;
			}

		/*
		 * Every other argument is a pointer and only differ in how
		 * many there are.
		 */
		case 'N':
		case 'T':
		case 'a':
			va_arg(va,void *);

			/* Drop through. */

		default:
			va_arg(va,void *);
		}
	}

	return valid;
}


/*
 * Carry out actions common to all ctors.
 */
static void sip_api_common_ctor(sipMethodCache *cache,int nrmeths)
{
	/* This is thread safe. */
	while (nrmeths-- > 0)
		cache++ -> mcflags = 0;
}


/*
 * Carry out actions common to all dtors.
 */
static void sip_api_common_dtor(sipWrapper *sipSelf)
{
	if (sipSelf != NULL && sipInterpreter != NULL)
	{
		SIP_BLOCK_THREADS

		if (!sipNotInMap(sipSelf))
			sipOMRemoveObject(&cppPyMap,sipSelf);

		/* This no longer points to anything useful. */
		sipSelf -> u.cppPtr = NULL;

		/* Delete any extra reference. */
		if (sipIsExtraRef(sipSelf))
		{
			Py_DECREF(sipSelf);
		}

		SIP_UNBLOCK_THREADS
	}
}


/*
 * Convert a sequence index.  Return the index or a negative value if there was
 * an error.
 */
static int sip_api_convert_from_sequence_index(int idx,int len)
{
	/* Negative indices start from the other end. */
	if (idx < 0)
		idx = len + idx;

	if (idx < 0 || idx >= len)
	{
		PyErr_Format(PyExc_IndexError,"list index out of range");
		return -1;
	}

	return idx;
}


/*
 * Create and return a single type object.
 */
static sipWrapperType *createType(sipExportedModuleDef *client,
				  PyObject *mname, sipTypeDef *type,
				  PyObject *mod_dict)
{
	PyObject *name, *bases, *typedict, *args, *dict;
	sipSuperClassDef *sup;
	sipWrapperType *wt;

	/* Create an object corresponding to the type name. */
	if ((name = createBaseName(type -> td_name)) == NULL)
		goto reterr;

	/* Create the tuple of super types. */
	if ((sup = type -> td_supers) == NULL)
	{
		static PyObject *nobases = NULL;

		if (nobases == NULL && (nobases = Py_BuildValue("(O)",&sipWrapper_Type)) == NULL)
			goto relname;

		Py_INCREF(nobases);
		bases = nobases;
	}
	else
	{
		int i, nrsupers = 0;

		do
			++nrsupers;
		while (!sup++ -> sc_last);

		if ((bases = PyTuple_New(nrsupers)) == NULL)
			goto relname;

		for (sup = type -> td_supers, i = 0; i < nrsupers; ++i, ++sup)
		{
			sipExportedModuleDef *em = getClassModule(sup,client);
			PyObject *st = (PyObject *)em -> em_types[sup -> sc_class];

			Py_INCREF(st);
			PyTuple_SET_ITEM(bases,i,st);
		}
	}

	/* Create the type dictionary. */
	if ((typedict = createTypeDict(mname)) == NULL)
		goto relbases;

	/* Initialise the rest of the type and pass it via the back door. */
	type -> td_module = client;
	currentType = type;

	/* Create the type by calling the metatype. */
	if ((args = Py_BuildValue("OOO",name,bases,typedict)) == NULL)
		goto reldict;

	if ((wt = (sipWrapperType *)PyObject_Call((PyObject *)&sipWrapperType_Type,args,NULL)) == NULL)
		goto relargs;

	/* Get the dictionary into which the type will be placed. */
	if (type -> td_scope >= 0)
		dict = client -> em_types[type -> td_scope] -> super.type.tp_dict;
	else
		dict = mod_dict;

	/* Add the type to the "parent" dictionary. */
	if (PyDict_SetItem(dict,name,(PyObject *)wt) < 0)
		goto reltype;

	/* We can now release our references. */
	Py_DECREF(args);
	Py_DECREF(typedict);
	Py_DECREF(bases);
	Py_DECREF(name);

	return wt;

	/* Unwind after an error. */

reltype:
	Py_DECREF((PyObject *)wt);

relargs:
	Py_DECREF(args);

reldict:
	Py_DECREF(typedict);

relbases:
	Py_DECREF(bases);

relname:
	Py_DECREF(name);

reterr:
	return NULL;
}


/*
 * Create and return an enum type object.
 */
static PyTypeObject *createEnum(sipExportedModuleDef *client, PyObject *mname,
				sipEnumDef *ed, PyObject *mod_dict)
{
	static PyObject *bases = NULL;
	PyObject *name, *typedict, *args, *dict;
	PyTypeObject *et;

	/* Create the base type tuple if it hasn't already been done. */
	if (bases == NULL && (bases = Py_BuildValue("(O)",&PyInt_Type)) == NULL)
		goto reterr;

	/* Create an object corresponding to the type name. */
	if ((name = createBaseName(ed -> e_name)) == NULL)
		goto reterr;

	/* Create the type dictionary. */
	if ((typedict = createTypeDict(mname)) == NULL)
		goto relname;

	/* Create the type by calling the metatype. */
	if ((args = Py_BuildValue("OOO",name,bases,typedict)) == NULL)
		goto reldict;

	if ((et = (PyTypeObject *)PyObject_Call((PyObject *)&PyType_Type,args,NULL)) == NULL)
		goto relargs;

	/* Get the dictionary into which the type will be placed. */
	if (ed -> e_scope >= 0)
		dict = client -> em_types[ed -> e_scope] -> super.type.tp_dict;
	else
		dict = mod_dict;

	/* Add the type to the "parent" dictionary. */
	if (PyDict_SetItem(dict,name,(PyObject *)et) < 0)
		goto reltype;

	/* We can now release our references. */
	Py_DECREF(args);
	Py_DECREF(typedict);
	Py_DECREF(name);

	return et;

	/* Unwind after an error. */

reltype:
	Py_DECREF((PyObject *)et);

relargs:
	Py_DECREF(args);

reldict:
	Py_DECREF(typedict);

relname:
	Py_DECREF(name);

reterr:
	return NULL;
}


/*
 * Create a Python object corresponding to the basename of a Python "pathname".
 */
static PyObject *createBaseName(const char *name)
{
	const char *bn;

	if ((bn = strrchr(name, '.')) != NULL)
		++bn;
	else
		bn = name;

	return PyString_FromString(bn);
}


/*
 * Create a type dictionary for dynamic type being created in the module with
 * the specified name.
 */
static PyObject *createTypeDict(PyObject *mname)
{
	static PyObject *mstr = NULL;
	PyObject *dict;

	/* Create an object for "__module__". */
	if (mstr == NULL && (mstr = PyString_FromString("__module__")) == NULL)
		return NULL;

	if ((dict = PyDict_New()) == NULL)
		return NULL;

	/* We need to set the module name as an attribute for dynamic types. */
	if (PyDict_SetItem(dict, mstr, mname) < 0)
	{
		Py_DECREF(dict);
		return NULL;
	}

	return dict;
}


/*
 * Add a set of static instances to a dictionary.
 */
static int addInstances(PyObject *dict,sipInstancesDef *id)
{
	if (id -> id_class != NULL && addClassInstances(dict,id -> id_class) < 0)
		return -1;

	if (id -> id_voidp != NULL && addVoidPtrInstances(dict,id -> id_voidp) < 0)
		return -1;

	if (id -> id_char != NULL && addCharInstances(dict,id -> id_char) < 0)
		return -1;

	if (id -> id_string != NULL && addStringInstances(dict,id -> id_string) < 0)
		return -1;

	if (id -> id_long != NULL && addLongInstances(dict,id -> id_long) < 0)
		return -1;

	if (id -> id_double != NULL && addDoubleInstances(dict,id -> id_double) < 0)
		return -1;

	if (id -> id_enum != NULL && addEnumInstances(dict,id -> id_enum) < 0)
		return -1;

	return 0;
}


/*
 * Get "self" from the argument tuple for a method called as
 * Class.Method(self,...) rather than self.Method(...).
 */
static int getSelfFromArgs(sipWrapperType *type,PyObject *args,int argnr,
			   sipWrapper **selfp)
{
	PyObject *self;

	/* Get self from the argument tuple. */

	if (argnr >= PyTuple_GET_SIZE(args))
		return PARSE_UNBOUND;

	self = PyTuple_GET_ITEM(args,argnr);

	if (!PyObject_TypeCheck(self,&type -> super.type))
		return PARSE_UNBOUND;

	*selfp = (sipWrapper *)self;

	return PARSE_OK;
}


/*
 * Handle the result of a call to the class/instance setattro methods.
 */
static int handleSetLazyAttr(PyObject *nameobj,PyObject *valobj,
			     sipWrapperType *wt,sipWrapper *w)
{
	char *name;
	PyMethodDef *pmd, *vmd;
	sipEnumMemberDef *enm;
	PyObject *attr;

	/* See if it was a lazy attribute. */
	if ((name = PyString_AsString(nameobj)) == NULL)
		return -1;

	pmd = NULL;
	enm = NULL;
	vmd = NULL;

	findLazyAttr(wt,name,&pmd,&enm,&vmd,NULL);

	if (vmd != NULL)
	{
		if (valobj == NULL)
		{
			PyErr_Format(PyExc_ValueError,"%s.%s cannot be deleted",wt -> type -> td_name,name);

			return -1;
		}

		if ((vmd -> ml_flags & METH_STATIC) != 0 || w != NULL)
		{
			PyObject *res;

			if ((res = (*vmd -> ml_meth)((PyObject *)w,valobj)) == NULL)
				return -1;

			/* Ignore the result (which should be Py_None). */
			Py_DECREF(res);

			return 0;
		}

		PyErr_SetObject(PyExc_AttributeError,nameobj);

		return -1;
	}

	/* It isn't a variable. */
	return 1;
}


/*
 * Handle the result of a call to the class/instance getattro methods.
 */
static PyObject *handleGetLazyAttr(PyObject *nameobj,sipWrapperType *wt,
				   sipWrapper *w)
{
	char *name;
	PyMethodDef *pmd, *vmd;
	sipEnumMemberDef *enm;
	sipWrapperType *in;

	/* If it was an error, propagate it. */
	if (!PyErr_ExceptionMatches(PyExc_AttributeError))
		return NULL;

	PyErr_Clear();

	/* See if it was a lazy attribute. */
	if ((name = PyString_AsString(nameobj)) == NULL)
		return NULL;

	pmd = NULL;
	enm = NULL;
	vmd = NULL;

	findLazyAttr(wt,name,&pmd,&enm,&vmd,&in);

	if (pmd != NULL)
		return PyCFunction_New(pmd,(PyObject *)w);

	if (enm != NULL)
	{
		PyObject *attr;

		/*
		 * Convert the value to an object and cache it in the correct
		 * type dictionary.
		 */
		if ((attr = createEnumMember(in, enm)) == NULL)
			return NULL;

		if (PyDict_SetItem(in -> super.type.tp_dict,nameobj,attr) < 0)
		{
			Py_DECREF(attr);
			return NULL;
		}

		return attr;
	}

	if (vmd != NULL)
		if ((vmd -> ml_flags & METH_STATIC) != 0 || w != NULL)
			return (*vmd -> ml_meth)((PyObject *)w,NULL);

	PyErr_SetObject(PyExc_AttributeError,nameobj);

	return NULL;
}


/*
 * Create a Python object for an enum member.
 */
static PyObject *createEnumMember(sipWrapperType *wt, sipEnumMemberDef *enm)
{
	if (enm -> em_enum < 0)
		return PyInt_FromLong(enm -> em_val);

	return sip_api_convert_from_named_enum(enm -> em_val, wt -> type -> td_module -> em_enums[enm -> em_enum]);
}


/*
 * Create a Python object for a member of a named enum.
 */
PyObject *sip_api_convert_from_named_enum(int eval, PyTypeObject *et)
{
	PyObject *args, *mo;

	if ((args = Py_BuildValue("(i)", eval)) == NULL)
		return NULL;

	mo = PyObject_Call((PyObject *)et, args, NULL);

	Py_DECREF(args);

	return mo;
}


/*
 * Find definition for a lazy class attribute.
 */
static void findLazyAttr(sipWrapperType *wt,char *name,PyMethodDef **pmdp,
			 sipEnumMemberDef **enmp,PyMethodDef **vmdp,
			 sipWrapperType **in)
{
	sipTypeDef *td;
	sipSuperClassDef *sup;

	/* Assume it will be found in this type. */
	if (in != NULL)
		*in = wt;

	/* The base type doesn't have any type information. */
	if ((td = wt -> type) == NULL)
		return;

	/* Try the methods. */
	if (td -> td_nrmethods > 0 &&
	    (*pmdp = (PyMethodDef *)bsearch(name,td -> td_methods,td -> td_nrmethods,sizeof (PyMethodDef),compareMethodName)) != NULL)
		return;

	/* Try the enum members. */
	if (td -> td_nrenummembers > 0 &&
	    (*enmp = (sipEnumMemberDef *)bsearch(name,td -> td_enummembers,td -> td_nrenummembers,sizeof (sipEnumMemberDef),compareEnumMemberName)) != NULL)
		return;

	/* Try the variables.  Note, these aren't sorted. */
	if (td -> td_variables != NULL)
	{
		PyMethodDef *md;

		for (md = td -> td_variables; md -> ml_name != NULL; ++md)
			if (strcmp(name,md -> ml_name) == 0)
			{
				*vmdp = md;
				return;
			}
	}

	/* Check the base classes. */
	if ((sup = td -> td_supers) != NULL)
		do
		{
			sipExportedModuleDef *em = getClassModule(sup,td -> td_module);

			findLazyAttr(em -> em_types[sup -> sc_class],name,pmdp,enmp,vmdp,in);

			if (*pmdp != NULL || *enmp != NULL || *vmdp != NULL)
				break;
		}
		while (!sup++ -> sc_last);
}


/*
 * The bsearch() helper function for searching a sorted method table.
 */
static int compareMethodName(const void *key,const void *el)
{
	return strcmp((const char *)key,((const PyMethodDef *)el) -> ml_name);
}


/*
 * The bsearch() helper function for searching a sorted enum member table.
 */
static int compareEnumMemberName(const void *key,const void *el)
{
	return strcmp((const char *)key,((const sipEnumMemberDef *)el) -> em_name);
}


/*
 * Report a constructor with invalid argument types.
 */
static void sip_api_no_ctor(int argsParsed,char *classname)
{
	badArgs(argsParsed,NULL,classname);
}


/*
 * Report a function with invalid argument types.
 */
static void sip_api_no_function(int argsParsed,char *func)
{
	badArgs(argsParsed,NULL,func);
}


/*
 * Report a method/function/signal with invalid argument types.
 */
static void sip_api_no_method(int argsParsed,char *classname,char *method)
{
	badArgs(argsParsed,classname,method);
}


/*
 * Handle error reporting for bad arguments to various things.
 */
static void badArgs(int argsParsed,char *classname,char *method)
{
	char *sep;
	int nrparsed = argsParsed & ~PARSE_MASK;

	if (classname != NULL)
		sep = ".";
	else
	{
		classname = "";
		sep = "";
	}

	switch (argsParsed & PARSE_MASK)
	{
	case PARSE_FEW:
		PyErr_Format(PyExc_TypeError,"insufficient number of arguments to %s%s%s()",classname,sep,method);
		break;

	case PARSE_MANY:
		PyErr_Format(PyExc_TypeError,"too many arguments to %s%s%s(), %d at most expected",classname,sep,method,nrparsed);
		break;

	case PARSE_TYPE:
		PyErr_Format(PyExc_TypeError,"argument %d of %s%s%s() has an invalid type",nrparsed + 1,classname,sep,method);
		break;

	case PARSE_FORMAT:
		PyErr_Format(PyExc_TypeError,"invalid format to sipParseArgs() from %s%s%s()",classname,sep,method);
		break;

	case PARSE_UNBOUND:
		PyErr_Format(PyExc_TypeError,"first argument of unbound method %s%s%s() must be a %s instance",classname,sep,method,classname);
		break;

	case PARSE_RAISED:
		/* It has already been taken care of. */

		break;

	case PARSE_OK:
		PyErr_Format(PyExc_SystemError,"internal error: %s%s%s",classname,sep,method);
		break;
	}
}


/*
 * Report a sequence length that does not match the length of a slice.
 */
static void sip_api_bad_length_for_slice(int seqlen,int slicelen)
{
	PyErr_Format(PyExc_ValueError,"attempt to assign sequence of size %d to slice of size %d",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 an argument that can't be None.
 */
static void setBadNone(int a)
{
	PyErr_Format(PyExc_RuntimeError,"cannot pass None as argument %d in this call",a);
}


/*
 * Report a Python class variable with an unexpected type.
 */
static void sip_api_bad_set_type(const char *classname,const char *var)
{
	PyErr_Format(PyExc_TypeError,"invalid type for variable %s.%s",classname,var);
}


/*
 * Report a Python member function with an unexpected return type.
 */
static void sip_api_bad_catcher_result(PyObject *method)
{
	char *cname, *mname;

	/*
	 * This is part of the public API so we make no assumptions about the
	 * method object.
	 */
	if (!PyMethod_Check(method) ||
	    PyMethod_GET_FUNCTION(method) == NULL ||
	    !PyFunction_Check(PyMethod_GET_FUNCTION(method)) ||
	    PyMethod_GET_SELF(method) == NULL)
	{
		PyErr_Format(PyExc_TypeError,"invalid argument to sipBadCatcherResult()");
		return;
	}

	mname = PyString_AsString(((PyFunctionObject *)PyMethod_GET_FUNCTION(method)) -> func_name);

	if (mname == NULL)
		return;

	cname = PyMethod_GET_SELF(method)->ob_type->tp_name;

	PyErr_Format(PyExc_TypeError,"invalid result type from %s.%s()",cname,mname);
}


/*
 * Return the name of the class corresponding to a wrapper object.  This comes
 * with a reference.
 */
static PyObject *sip_api_class_name(PyObject *self)
{
	return PyString_FromString(self -> ob_type -> tp_name);
}


/*
 * Return non-zero if the object is a C++ instance wrapper.
 */
int sipWrapper_Check(PyObject *op)
{
	return PyObject_TypeCheck(op,(PyTypeObject *)&sipWrapper_Type);
}


/*
 * Return non-zero if the object is a C++ instance wrapper type.
 */
static int sipWrapperType_Check(PyObject *op)
{
	return PyObject_TypeCheck(op,(PyTypeObject *)&sipWrapperType_Type);
}


/*
 * Transfer ownersip of a class instance from Python to C/C++, or vice versa.
 */
static void sip_api_transfer(PyObject *self,int toCpp)
{
	/*
	 * 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 && sipWrapper_Check(self))
	{
		sipWrapper *w = (sipWrapper *)self;

		if (toCpp)
		{
			sipResetPyOwned(w);

			if (!sipIsExtraRef(w))
			{
				sipSetIsExtraRef(w);
				Py_INCREF(self);
			}
		}
		else
		{
			sipSetPyOwned(w);

			if (sipIsExtraRef(w))
			{
				sipResetIsExtraRef(w);
				Py_DECREF(self);
			}
		}
	}
}


/*
 * Add a license to a dictionary.
 */
static int addLicense(PyObject *dict,sipLicenseDef *lc)
{
	int rc;
	PyObject *ldict, *proxy, *o;

	/* Convert the strings we use to objects if not already done. */

	if (licenseName == NULL && (licenseName = PyString_FromString("__license__")) == NULL)
		return -1;

	if (licenseeName == NULL && (licenseeName = PyString_FromString("Licensee")) == NULL)
		return -1;

	if (typeName == NULL && (typeName = PyString_FromString("Type")) == NULL)
		return -1;

	if (timestampName == NULL && (timestampName = PyString_FromString("Timestamp")) == NULL)
		return -1;

	if (signatureName == NULL && (signatureName = PyString_FromString("Signature")) == NULL)
		return -1;

	/* We use a dictionary to hold the license information. */
	if ((ldict = PyDict_New()) == NULL)
		return -1;

	/* The license type is compulsory, the rest are optional. */
	if (lc -> lc_type == NULL || (o = PyString_FromString(lc -> lc_type)) == NULL)
		goto deldict;

	rc = PyDict_SetItem(ldict,typeName,o);
	Py_DECREF(o);

	if (rc < 0)
		goto deldict;

	if (lc -> lc_licensee != NULL)
	{
		if ((o = PyString_FromString(lc -> lc_licensee)) == NULL)
			goto deldict;

		rc = PyDict_SetItem(ldict,licenseeName,o);
		Py_DECREF(o);

		if (rc < 0)
			goto deldict;
	}

	if (lc -> lc_timestamp != NULL)
	{
		if ((o = PyString_FromString(lc -> lc_timestamp)) == NULL)
			goto deldict;

		rc = PyDict_SetItem(ldict,timestampName,o);
		Py_DECREF(o);

		if (rc < 0)
			goto deldict;
	}

	if (lc -> lc_signature != NULL)
	{
		if ((o = PyString_FromString(lc -> lc_signature)) == NULL)
			goto deldict;

		rc = PyDict_SetItem(ldict,signatureName,o);
		Py_DECREF(o);

		if (rc < 0)
			goto deldict;
	}

	/* Create a read-only proxy. */
	if ((proxy = PyDictProxy_New(ldict)) == NULL)
		goto deldict;

	Py_DECREF(ldict);

	rc = PyDict_SetItem(dict,licenseName,proxy);
	Py_DECREF(proxy);

	return rc;

deldict:
	Py_DECREF(ldict);

	return -1;
}


/*
 * Add the void pointer instances to a dictionary.
 */
static int addVoidPtrInstances(PyObject *dict,sipVoidPtrInstanceDef *vi)
{
	while (vi -> vi_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = sip_api_convert_from_void_ptr(vi -> vi_val)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict,vi -> vi_name,w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++vi;
	}

	return 0;
}


/*
 * Add the char instances to a dictionary.
 */
static int addCharInstances(PyObject *dict,sipCharInstanceDef *ci)
{
	while (ci -> ci_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = PyString_FromStringAndSize(&ci -> ci_val,1)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict,ci -> ci_name,w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++ci;
	}

	return 0;
}


/*
 * Add the string instances to a dictionary.
 */
static int addStringInstances(PyObject *dict,sipStringInstanceDef *si)
{
	while (si -> si_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = PyString_FromString(si -> si_val)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict,si -> si_name,w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++si;
	}

	return 0;
}


/*
 * Add the long instances to a dictionary.
 */
static int addLongInstances(PyObject *dict,sipLongInstanceDef *li)
{
	while (li -> li_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = PyInt_FromLong(li -> li_val)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict,li -> li_name,w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++li;
	}

	return 0;
}


/*
 * Add the double instances to a dictionary.
 */
static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di)
{
	while (di -> di_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = PyFloat_FromDouble(di -> di_val)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict,di -> di_name,w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++di;
	}

	return 0;
}


/*
 * Add the enum instances to a dictionary.
 */
static int addEnumInstances(PyObject *dict, sipEnumInstanceDef *ei)
{
	while (ei -> ei_name != NULL)
	{
		int rc;
		PyObject *w;

		if ((w = sip_api_convert_from_named_enum(ei -> ei_val, *ei -> ei_type)) == NULL)
			return -1;

		rc = PyDict_SetItemString(dict, ei -> ei_name, w);
		Py_DECREF(w);

		if (rc < 0)
			return -1;

		++ei;
	}

	return 0;
}


/*
 * Wrap a set of class instances and add them to a dictionary.
 */
static int addClassInstances(PyObject *dict,sipClassInstanceDef *ci)
{
	while (ci -> ci_name != NULL)
	{
		if (addSingleClassInstance(dict,ci -> ci_name,ci -> ci_ptr,*ci -> ci_type,ci -> ci_flags) < 0)
			return -1;

		++ci;
	}

	return 0;
}


/*
 * Wrap a single class instance and add it to a dictionary.
 */
static int addSingleClassInstance(PyObject *dict,char *name,void *cppPtr,
				  sipWrapperType *wt,int initflags)
{
	int rc;
	PyObject *w;

	if ((w = sip_api_new_cpp_to_self(cppPtr,wt,initflags)) == NULL)
		return -1;

	rc = PyDict_SetItemString(dict,name,w);
	Py_DECREF(w);

	return rc;
}


/*
 * Wrap a class instance and add it to a dictionary.
 */
static int sip_api_add_class_instance(PyObject *dict,char *name,void *cppPtr,
				      sipWrapperType *wt)
{
	/* If this is a wrapped type then get the type dictionary. */
	if (sipWrapperType_Check(dict))
		dict = ((sipWrapperType *)dict) -> super.type.tp_dict;

	return addSingleClassInstance(dict,name,cppPtr,wt,SIP_SIMPLE);
}


/*
 * Get the C/C++ pointer for a complex object.
 */
static void *sip_api_get_complex_cpp_ptr(sipWrapper *w)
{
	if (sipIsSimple(w))
	{
		PyErr_SetString(PyExc_RuntimeError,"no access to protected functions or signals for objects not created from Python");

		return NULL;
	}

	if (checkPointer(w -> u.cppPtr) < 0)
		return NULL;

	return w -> u.cppPtr;
}


/*
 * Return the Python member function corresponding to a C/C++ virtual function,
 * if any.  If one was found then the Python lock is acquired.
 */
static PyObject *sip_api_is_py_method(sip_gilstate_t *gil,sipMethodCache *pymc,
				      sipWrapper *sipSelf,char *cname,
				      char *mname)
{
	PyObject *meth;

	/* We might still have C++ going after the interpreter has gone. */
	if (sipInterpreter == NULL)
		return NULL;

	/*
	 * It's possible that the Python object has been deleted but the
	 * underlying (complex) C/C++ instance is still working and trying to
	 * handle virtual functions.  Or an instance has started handling
	 * virtual functions before its ctor has returned.  In either case say
	 * there is no Python method.
	 */
	if (sipSelf == NULL)
		return NULL;

#ifdef WITH_THREAD
	*gil = PyGILState_Ensure();
#endif

	/* See if we have already looked for the Python method. */
	if (!sipFoundMethod(pymc))
	{
		PyObject *methobj;

		/*
		 * Using PyMethod_Check() rather than PyCallable_Check() has
		 * the added benefits of ensuring the (common) case of there
		 * being no Python method is handled as a direct call to C/C++
		 * (rather than converted to Python and then back to C/C++) and
		 * makes sure that abstract virtuals are trapped.
		 */
		if ((methobj = PyObject_GetAttrString((PyObject *)sipSelf,mname)) != NULL)
		{
			if (PyMethod_Check(methobj))
			{
				sipSetIsMethod(pymc);
				sipSaveMethod(&pymc -> pyMethod,methobj);
			}

			Py_DECREF(methobj);
		}

		PyErr_Clear();

		sipSetFoundMethod(pymc);
	}
	else if (sipIsMethod(pymc))
		PyErr_Clear();

	if (sipIsMethod(pymc))
		return PyMethod_New(pymc -> pyMethod.mfunc,pymc -> pyMethod.mself,pymc -> pyMethod.mclass);

	if (cname != NULL)
		PyErr_Format(PyExc_NotImplementedError,"%s.%s() is abstract and must be overridden",cname,mname);

#ifdef WITH_THREAD
	PyGILState_Release(*gil);
#endif

	return NULL;
}


/*
 * Do the same as sip_api_new_cpp_to_self() but for classes that are influenced
 * by %ConvertToSubClassCode.
 */
static PyObject *sip_api_new_cpp_to_self_sub_class(void *cppPtr,
						   sipWrapperType *type,
						   int flags)
{
	return sip_api_new_cpp_to_self(cppPtr,convertSubClass(type,cppPtr),flags);
}


/*
 * Convert a C/C++ pointer to a Python instance.  If the C/C++ pointer is
 * recognised and it is an instance of a sub-class of the expected class then
 * the previously wrapped instance is returned.  Otherwise a new Python
 * instance is created with the expected class.  The instance comes with a
 * reference.
 */
static PyObject *sip_api_map_cpp_to_self(void *cppPtr,sipWrapperType *type)
{
	PyObject *sipSelf;

	if (cppPtr == NULL)
	{
		Py_INCREF(Py_None);
		return Py_None;
	}

	/* See if we have already wrapped it. */

	/* Don't indirect. */
	if ((sipSelf = sip_api_get_wrapper(cppPtr,type)) != NULL)
		Py_INCREF(sipSelf);
	else
		sipSelf = sip_api_new_cpp_to_self(cppPtr,type,SIP_SIMPLE|SIP_SHARE_MAP);

	return sipSelf;
}


/*
 * Do the same as sip_api_map_cpp_to_self() but for classes that are influenced
 * by %ConvertToSubClassCode.
 */
PyObject *sip_api_map_cpp_to_self_sub_class(void *cppPtr, sipWrapperType *type)
{
	return sip_api_map_cpp_to_self(cppPtr,convertSubClass(type,cppPtr));
}


/*
 * Convert a C/C++ pointer to the object that wraps it.
 */
static PyObject *sip_api_get_wrapper(void *cppPtr,sipWrapperType *type)
{
	return (PyObject *)sipOMFindObject(&cppPyMap,cppPtr,type);
}


/*
 * Get the C/C++ pointer from a wrapper and optionally cast it to the required
 * type.
 */
void *sip_api_get_cpp_ptr(sipWrapper *w,sipWrapperType *type)
{
	void *ptr;

	if (sipIsAccessFunc(w))
		ptr = (*w -> u.afPtr)();
	else if (sipIsIndirect(w))
		ptr = *((void **)w -> u.cppPtr);
	else
		ptr = w -> u.cppPtr;

	if (checkPointer(ptr) < 0)
		return NULL;

	if (type != NULL)
		ptr = (*((sipWrapperType *)w -> ob_type) -> type -> td_cast)(ptr,type);

	return ptr;
}


/*
 * Check that a pointer is non-NULL.
 */
static int checkPointer(void *ptr)
{
	if (ptr == NULL)
	{
		PyErr_SetString(PyExc_RuntimeError,"underlying C/C++ object has been deleted");
		return -1;
	}

	return 0;
}


/*
 * Convert a Python instance of a class to a C/C++ object pointer, checking
 * that the instance's class is derived from a given base type.
 */
static void *sip_api_convert_to_cpp(PyObject *sipSelf,sipWrapperType *type,
				    int *iserrp)
{
	void *ptr;

	if (sipSelf == Py_None)
		return NULL;

	if ((ptr = sip_api_get_cpp_ptr((sipWrapper *)sipSelf,type)) == NULL)
	{
		*iserrp = TRUE;
		return NULL;
	}

	return ptr;
}


/*
 * Save the components of a Python method.
 */
void sipSaveMethod(sipPyMethod *pm,PyObject *meth)
{
	pm -> mfunc = PyMethod_GET_FUNCTION(meth);
	pm -> mself = PyMethod_GET_SELF(meth);
	pm -> mclass = PyMethod_GET_CLASS(meth);
}


/*
 * Call a hook.
 */
static void sip_api_call_hook(char *hookname)
{
	PyObject *dictofmods, *mod, *dict, *hook, *res;
 
	/* Get the dictionary of modules. */
	if ((dictofmods = PyImport_GetModuleDict()) == NULL)
		return;
 
	/* Get the __builtin__ module. */
	if ((mod = PyDict_GetItemString(dictofmods,"__builtin__")) == NULL)
		return;
 
	/* Get it's dictionary. */
	if ((dict = PyModule_GetDict(mod)) == NULL)
		return;
 
	/* Get the function hook. */
	if ((hook = PyDict_GetItemString(dict,hookname)) == NULL)
		return;
 
	/* Call the hook and discard any result. */
	res = PyObject_CallObject(hook,NULL);
 
	Py_XDECREF(res);
}


/*
 * Call any sub-class convertors for a given type returning a pointer to the
 * sub-type object.
 */
static sipWrapperType *convertSubClass(sipWrapperType *type,void *cppPtr)
{
	sipExportedModuleDef *em;

	if (cppPtr == NULL)
		return NULL;

	for (em = clientList; em != NULL; em = em -> em_next)
	{
		sipSubClassConvertorDef *scc;

		if ((scc = em -> em_convertors) == NULL)
			continue;

		while (scc -> scc_convertor != NULL)
		{
			/*
			 * The base type is the "root" class that may have a
			 * number of convertors each handling a "branch" of the
			 * derived tree of classes.  The "root" normally
			 * implements the base function that provides the RTTI
			 * used by the convertors and is re-implemented by
			 * derived classes.  We therefore see if the target
			 * type is a sub-class of the root, ie. see if the
			 * convertor might be able to convert the target type
			 * to something more specific.
			 */
			if (PyType_IsSubtype(&type -> super.type,&scc -> scc_basetype -> super.type))
			{
				sipWrapperType *subtype;

				if ((subtype = (*scc -> scc_convertor)(cppPtr)) != NULL)
					return subtype;
			}

			++scc;
		}
	}

	/*
	 * We haven't found the exact type, so return the most specific type
	 * that it must be.  This can happen legitimately if the wrapped
	 * library is returning an internal class that is down-cast to a more
	 * generic class.  Also we want this function to be safe when a class
	 * doesn't have any convertors.
	 */
	return type;
}


/*
 * The bsearch() helper function for searching a sorted string map table.
 */
static int compareStringMapEntry(const void *key,const void *el)
{
	return strcmp((const char *)key,((const sipStringTypeClassMap *)el) -> typeString);
}


/*
 * A convenience function for %ConvertToSubClassCode for types represented as a
 * string.  Returns the Python class object or NULL if the type wasn't
 * recognised.
 */
static sipWrapperType *sip_api_map_string_to_class(const char *typeString,
						 const sipStringTypeClassMap *map,
						 int maplen)
{
	sipStringTypeClassMap *me;

	me = (sipStringTypeClassMap *)bsearch((const void *)typeString,
					      (const void *)map,maplen,
					      sizeof (sipStringTypeClassMap),
					      compareStringMapEntry);

        return ((me != NULL) ? *me -> pyType : NULL);
}


/*
 * The bsearch() helper function for searching a sorted integer map table.
 */
static int compareIntMapEntry(const void *keyp,const void *el)
{
	int key = *(int *)keyp;

	if (key > ((const sipIntTypeClassMap *)el) -> typeInt)
		return 1;

	if (key < ((const sipIntTypeClassMap *)el) -> typeInt)
		return -1;

	return 0;
}


/*
 * A convenience function for %ConvertToSubClassCode for types represented as
 * an integer.  Returns the Python class object or NULL if the type wasn't
 * recognised.
 */
static sipWrapperType *sip_api_map_int_to_class(int typeInt,
					      const sipIntTypeClassMap *map,
					      int maplen)
{
	sipIntTypeClassMap *me;

	me = (sipIntTypeClassMap *)bsearch((const void *)&typeInt,
					   (const void *)map,maplen,
					   sizeof (sipIntTypeClassMap),
					   compareIntMapEntry);

        return ((me != NULL) ? *me -> pyType : NULL);
}


/*
 * Raise an unknown exception.  Make no assumptions about the GIL.
 */
static void sip_api_raise_unknown_exception(void)
{
        static PyObject *mobj = NULL;

	SIP_BLOCK_THREADS

        if (mobj == NULL)
                mobj = PyString_FromString("unknown");

        PyErr_SetObject(PyExc_Exception,mobj);

	SIP_UNBLOCK_THREADS
}


/*
 * Raise an exception implemented as a class.  Make no assumptions about the
 * GIL.
 */
static void sip_api_raise_class_exception(sipWrapperType *type,void *ptr)
{
        PyObject *self;

	SIP_BLOCK_THREADS

        self = sip_api_new_cpp_to_self(ptr,type,SIP_SIMPLE | SIP_PY_OWNED);

        PyErr_SetObject((PyObject *)type,self);

        Py_XDECREF(self);

	SIP_UNBLOCK_THREADS
}


/*
 * Raise an exception implemented as a class or sub-class.  Make no assumptions
 * about the GIL.
 */
static void sip_api_raise_sub_class_exception(sipWrapperType *type,void *ptr)
{
        PyObject *self;

	SIP_BLOCK_THREADS

        self = sip_api_new_cpp_to_self_sub_class(ptr,type,SIP_SIMPLE | SIP_PY_OWNED);

        PyErr_SetObject((PyObject *)type,self);

        Py_XDECREF(self);

	SIP_UNBLOCK_THREADS
}


/*
 * Return the module in which a class is defined.
 */
static sipExportedModuleDef *getClassModule(sipSuperClassDef *sup,
					    sipExportedModuleDef *em)
{
	if (sup -> sc_module == 255)
		return em;

	return em -> em_imports[sup -> sc_module].im_module;
}


/*
 * Find a particular slot function for a wrapper.
 */
static void *findSlot(PyObject *self,sipPySlotType st)
{
	sipPySlotDef *psd;

	if ((psd = ((sipWrapperType *)(self -> ob_type)) -> type -> td_pyslots) != NULL)
		while (psd -> psd_func != NULL)
		{
			if (psd -> psd_type == st)
				return psd -> psd_func;

			++psd;
		}

	return NULL;
}


/*
 * Handle an objobjargproc slot.
 */
static int objobjargprocSlot(PyObject *self,PyObject *arg1,PyObject *arg2,
			     sipPySlotType st)
{
	int (*f)(PyObject *,PyObject *);
	PyObject *args;
	int res;

	/*
	 * Slot handlers require a single PyObject *.  The second argument is
	 * optional.
	 */
	if (arg2 == NULL)
		args = arg1;
	else if (PyTuple_Check(arg1))
	{
		int i;

		/*
		 * It's already a tuple so we need to copy it and append the
		 * value.
		 */
		if ((args = PyTuple_New(PyTuple_GET_SIZE(arg1) + 1)) == NULL)
			return -1;

		for (i = 0; i < PyTuple_GET_SIZE(arg1); ++i)
		{
			PyObject *o = PyTuple_GET_ITEM(arg1,i);

			PyTuple_SET_ITEM(args,i,o);
			Py_INCREF(o);
		}

		PyTuple_SET_ITEM(args,i,arg2);
		Py_INCREF(arg2);
	}
	else if ((args = Py_BuildValue("(OO)",arg1,arg2)) == NULL)
		return -1;

	f = (int (*)(PyObject *,PyObject *))findSlot(self,st);

	res = f(self,args);

	if (arg2 != NULL)
	{
		Py_DECREF(args);
	}

	return res;
}


/*
 * Handle an intobjargproc slot.
 */
static int intobjargprocSlot(PyObject *self,int arg1,PyObject *arg2,
			     sipPySlotType st)
{
	int (*f)(PyObject *,PyObject *);
	PyObject *args;
	int res;

	/*
	 * Slot handlers require a single PyObject *.  The second argument is
	 * optional.
	 */
	if (arg2 == NULL)
		args = PyInt_FromLong(arg1);
	else
		args = Py_BuildValue("(iO)",arg1,arg2);

	if (args == NULL)
		return -1;

	f = (int (*)(PyObject *,PyObject *))findSlot(self,st);

	res = f(self,args);

	Py_DECREF(args);

	return res;
}


/*****************************************************************************
 * The functions, data types and structures to support a Python type to hold a
 * void * that can be converted to an integer.
 *****************************************************************************/

/* The object data structure. */
typedef struct {
	PyObject_HEAD
	void *voidptr;
} sipVoidPtr;


/*
 * Implement int() for the type.
 */
static PyObject *sipVoidPtr_int(sipVoidPtr *v)
{
	return PyInt_FromLong((long)v -> voidptr);
}


/*
 * Implement asstring() for the type.
 */
static PyObject *sipVoidPtr_asstring(sipVoidPtr *v,PyObject *arg)
{
	long nbytes = PyInt_AsLong(arg);

	if (PyErr_Occurred())
		return NULL;

	return PyString_FromStringAndSize(v -> voidptr,nbytes);
}


/* The methods data structure. */
static PyMethodDef sipVoidPtr_Methods[] = {
	{"asstring", (PyCFunction)sipVoidPtr_asstring, METH_O, NULL},
	{NULL}
};


/* The number methods data structure. */
PyNumberMethods sipVoidPtr_NumberMethods = {
	0,						/* nb_add */
	0,						/* nb_subtract */
	0,						/* nb_multiply */
	0,						/* nb_divide */
	0,						/* nb_remainder */
	0,						/* nb_divmod */
	0,						/* nb_power */
	0,						/* nb_negative */
	0,						/* nb_positive */
	0,						/* nb_absolute */
	0,						/* nb_nonzero */
	0,						/* nb_invert */
	0,						/* nb_lshift */
	0,						/* nb_rshift */
	0,						/* nb_and */
	0,						/* nb_xor */
	0,						/* nb_or */
	0,						/* nb_coerce */
	(unaryfunc)sipVoidPtr_int,			/* nb_int */
};


/* The type data structure. */
static PyTypeObject sipVoidPtr_Type = {
	PyObject_HEAD_INIT(NULL)
	0,						/* ob_size */
	"sip.voidptr",					/* tp_name */
	sizeof (sipVoidPtr),				/* tp_basicsize */
	0,						/* tp_itemsize */
	0,						/* tp_dealloc */
	0,						/* tp_print */
	0,						/* tp_getattr */
	0,						/* tp_setattr */
	0,						/* tp_compare */
	0,						/* tp_repr */
	&sipVoidPtr_NumberMethods,			/* tp_as_number */
	0,						/* tp_as_sequence */
	0,						/* tp_as_mapping */
	0,						/* tp_hash */
	0,						/* tp_call */
	0,						/* tp_str */
	0,						/* tp_getattro */
	0,						/* tp_setattro */
	0,						/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* tp_flags */
	0,						/* tp_doc */
	0,						/* tp_traverse */
	0,						/* tp_clear */
	0,						/* tp_richcompare */
	0,						/* tp_weaklistoffset */
	0,						/* tp_iter */
	0,						/* tp_iternext */
	sipVoidPtr_Methods,				/* tp_methods */
};


/*
 * A convenience function to convert a C/C++ void pointer from a Python object.
 */
static void *sip_api_convert_to_void_ptr(PyObject *obj)
{
	if (obj == NULL)
	{
		PyErr_SetString(PyExc_TypeError,"sip.voidptr is NULL");
		return NULL;
	}

	if (obj == Py_None)
		return NULL;

	if (obj -> ob_type == &sipVoidPtr_Type)
		return ((sipVoidPtr *)obj) -> voidptr;

	return (void *)PyInt_AsLong(obj);
}


/*
 * A convenience function to convert a C/C++ void pointer to a Python object.
 */
PyObject *sip_api_convert_from_void_ptr(void *val)
{
	sipVoidPtr *self;

	if (val == NULL)
	{
		Py_INCREF(Py_None);
		return Py_None;
	}

	if ((self = PyObject_NEW(sipVoidPtr,&sipVoidPtr_Type)) == NULL)
		return NULL;

	self -> voidptr = val;

	return (PyObject *)self;
}


/*****************************************************************************
 * The Python metatype for a C++ wrapper type.
 *****************************************************************************/

/*
 * The type alloc slot.
 */
static PyObject *sipWrapperType_alloc(PyTypeObject *self, int nitems)
{
	PyObject *o;

	/* Call the standard super-metatype alloc. */
	if ((o = PyType_Type.tp_alloc(self, nitems)) == NULL)
		return NULL;

	/*
	 * Consume any extra type specific information and use it to initialise
	 * the slots.  This only happens for directly wrapped classes (and not
	 * programmer written sub-classes).  This must be done in the alloc
	 * function because it is the only place we can break out of the
	 * default new() function before PyType_Ready() is called.
	 */
	if (currentType != NULL)
	{
		((sipWrapperType *)o) -> type = currentType;
		addSlots((sipWrapperType *)o, currentType);
		currentType = NULL;
	}

	return o;
}


/*
 * The type init slot.
 */
static int sipWrapperType_init(sipWrapperType *self,PyObject *args,PyObject *kwds)
{
	/* Call the standard super-metatype init. */
	if (PyType_Type.tp_init((PyObject *)self,args,kwds) < 0)
		return -1;

	/*
	 * If we don't yet have any extra type specific information (because we
	 * are a programmer defined sub-class) then get it from the (first)
	 * super-type.
	 */
	if (self -> type == NULL)
		self -> type = ((sipWrapperType *)self -> super.type.tp_base) -> type;

	return 0;
}


/*
 * The type getattro slot.
 */
static PyObject *sipWrapperType_getattro(PyObject *obj,PyObject *name)
{
	char *nm;
	PyObject *attr;
	sipWrapperType *wt = (sipWrapperType *)obj;

	/*
	 * If we are getting the type dictionary then we don't want the
	 * super-metatype to handle it.
	 */
	if ((nm = PyString_AsString(name)) == NULL)
		return NULL;

	if (strcmp(nm,"__dict__") == 0)
	{
		int i;
		sipTypeDef *td;
		sipEnumMemberDef *enm;
		PyObject *dict, *tmpdict, *proxy;
		PyMethodDef *pmd;

		dict = wt -> super.type.tp_dict;

		/* The base type doesn't have any type information. */
		if ((td = wt -> type) == NULL)
			return PyDictProxy_New(dict);

		/*
		 * Add the type's lazy enums.  It doesn't matter if they are
		 * already there.
		 */
		enm = td -> td_enummembers;

		for (i = 0; i < td -> td_nrenummembers; ++i)
		{
			int rc;
			PyObject *val;

			if ((val = createEnumMember(wt, enm)) == NULL)
				return NULL;

			rc = PyDict_SetItemString(dict,enm -> em_name,val);

			Py_DECREF(val);

			if (rc < 0)
				return NULL;

			++enm;
		}

		/* If there are no lazy methods or variables then that's it. */
		if (td -> td_nrmethods == 0 && td -> td_variables == NULL)
			return PyDictProxy_New(dict);

		/*
		 * We can't cache the methods or variables so we need to make a
		 * temporary copy of the type dictionary and return that (so
		 * that it will get garbage collected immediately afterwards).
		 */
		if ((tmpdict = PyDict_Copy(dict)) == NULL)
			return NULL;

		/* Do the methods. */
		pmd = td -> td_methods;

		for (i = 0; i < td -> td_nrmethods; ++i)
		{
			int rc;
			PyObject *meth;

			if ((meth = PyCFunction_New(pmd,NULL)) == NULL)
			{
				Py_DECREF(tmpdict);
				return NULL;
			}

			rc = PyDict_SetItemString(tmpdict,pmd -> ml_name,meth);

			Py_DECREF(meth);

			if (rc < 0)
			{
				Py_DECREF(tmpdict);
				return NULL;
			}

			++pmd;
		}

		/* Do the static variables. */
		if ((pmd = td -> td_variables) != NULL)
			while (pmd -> ml_name != NULL)
			{
				if ((pmd -> ml_flags & METH_STATIC) != 0)
				{
					int rc;
					PyObject *val;

					if ((val = (*pmd -> ml_meth)(NULL,NULL)) == NULL)
					{
						Py_DECREF(tmpdict);
						return NULL;
					}

					rc = PyDict_SetItemString(tmpdict,pmd -> ml_name,val);

					Py_DECREF(val);

					if (rc < 0)
					{
						Py_DECREF(tmpdict);
						return NULL;
					}
				}

				++pmd;
			}

		proxy = PyDictProxy_New(tmpdict);
		Py_DECREF(tmpdict);

		return proxy;
	}

	/* Now try the super-metatype's method. */
	if ((attr = PyType_Type.tp_getattro(obj,name)) != NULL)
		return attr;

	return handleGetLazyAttr(name,wt,NULL);
}


/*
 * The type setattro slot.
 */
static int sipWrapperType_setattro(PyObject *obj,PyObject *name,PyObject *value)
{
	int rc;

	rc = handleSetLazyAttr(name,value,(sipWrapperType *)obj,NULL);

	if (rc <= 0)
		return rc;

	/* Try the super-type's method last. */
	return PyType_Type.tp_setattro(obj,name,value);
}


/*
 * The type data structure.  We inherit everything from the standard Python
 * metatype except the init and getattro methods and the size of the type
 * object created is increased to accomodate the extra information we associate
 * with a wrapped type.
 */
static PyTypeObject sipWrapperType_Type = {
	PyObject_HEAD_INIT(NULL)
	0,						/* ob_size */
	"sip.wrappertype",				/* tp_name */
	sizeof (sipWrapperType),			/* tp_basicsize */
	0,						/* tp_itemsize */
	0,						/* tp_dealloc */
	0,						/* tp_print */
	0,						/* tp_getattr */
	0,						/* tp_setattr */
	0,						/* tp_compare */
	0,						/* tp_repr */
	0,						/* tp_as_number */
	0,						/* tp_as_sequence */
	0,						/* tp_as_mapping */
	0,						/* tp_hash */
	0,						/* tp_call */
	0,						/* tp_str */
	sipWrapperType_getattro,			/* tp_getattro */
	sipWrapperType_setattro,			/* tp_setattro */
	0,						/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* tp_flags */
	0,						/* tp_doc */
	0,						/* tp_traverse */
	0,						/* tp_clear */
	0,						/* tp_richcompare */
	0,						/* tp_weaklistoffset */
	0,						/* tp_iter */
	0,						/* tp_iternext */
	0,						/* tp_methods */
	0,						/* tp_members */
	0,						/* tp_getset */
	0,						/* tp_base */
	0,						/* tp_dict */
	0,						/* tp_descr_get */
	0,						/* tp_descr_set */
	0,						/* tp_dictoffset */
	(initproc)sipWrapperType_init,			/* tp_init */
	sipWrapperType_alloc,				/* tp_alloc */
	0,						/* tp_new */
	0,						/* tp_free */
};


/*****************************************************************************
 * The Python type that is the super-type for all C++ wrapper types.
 *****************************************************************************/

/*
 * The instance new slot.
 */
static PyObject *sipWrapper_new(sipWrapperType *wt,PyObject *args,PyObject *kwds)
{
	/* See if it is a namespace. */
	if (wt -> type -> td_fcto == NULL)
	{
		PyErr_Format(PyExc_TypeError,"%s represents a C++ namespace and cannot be instantiated",wt -> type -> td_name);

		return NULL;
	}

	/* Call the standard super-type new. */
	return PyBaseObject_Type.tp_new(&wt -> super.type,args,kwds);
}


/*
 * The instance init slot.
 */
static int sipWrapper_init(sipWrapper *self,PyObject *args,PyObject *kwds)
{
	void *sipNew;
	int sipFlags;

	if (self -> ob_type == (PyTypeObject *)&sipWrapper_Type)
	{
		PyErr_SetString(PyExc_TypeError,"the sip.wrapper type cannot be instantiated");
		return -1;
	}

	if (kwds != NULL)
	{
		PyErr_SetString(PyExc_TypeError,"keyword arguments are not supported");
		return -1;
	}

	/*
	 * Create the instance dictionary if it hasn't already been done.  I
	 * think that it will have been created if an __init__ method of a
	 * sub-class creates instance attributes before calling it's
	 * super-class __init__ method (ie. this one).
	 */
	if (self -> dict == NULL && (self -> dict = PyDict_New()) == NULL)
		return -1;

	/* See if there is an existing C++ instance waiting to be wrapped. */
	if ((sipNew = sipGetPending(&sipFlags)) == NULL)
	{
		sipTypeDef *type = ((sipWrapperType *)self -> ob_type) -> type;

		if (type -> td_init == NULL)
		{
			PyErr_Format(PyExc_TypeError,"%s cannot be instantiated",type -> td_name);
			return -1;
		}

		sipFlags = SIP_PY_OWNED;

		/* Call the C++ ctor. */
		if ((sipNew = type -> td_init(self,args,&sipFlags)) == NULL)
			return -1;
	}

	/*
	 * If an extra reference has been requested then ownership is actually
	 * with C++.
	 */
	if (sipFlags & SIP_XTRA_REF)
	{
		sipFlags &= ~SIP_PY_OWNED;

		/* Give the extra reference. */
		Py_INCREF(self);
	}

	self -> u.cppPtr = sipNew;
	self -> flags = sipFlags;

	if (!sipNotInMap(self))
		sipOMAddObject(&cppPyMap,self);

	return 0;
}


/*
 * The instance dealloc slot.
 */
static void sipWrapper_dealloc(sipWrapper *self)
{
	/* Remove the instance dictionary. */
	Py_XDECREF(self -> dict);

	/* Ignore any errors.  Don't indirect. */
	if (!sipNotInMap(self) && self -> u.cppPtr != NULL)
	{
		sipTypeDef *type = ((sipWrapperType *)self -> ob_type) -> type;

		/* Call the C++ dtor if there is one. */
		if (type -> td_dealloc != NULL)
			type -> td_dealloc(self);

		sipOMRemoveObject(&cppPyMap,self);
	}

	while (self -> pySigList != NULL)
	{
		sipPySig *ps;
		sipPySigRx *psrx;

		/* Take this one out of the list. */
		ps = self -> pySigList;
		self -> pySigList = ps -> next;

		while ((psrx = ps -> rxlist) != NULL)
		{
			ps -> rxlist = psrx -> next;

			if (psrx -> rx.name != NULL)
				sip_api_free(psrx -> rx.name);

			sip_api_free(psrx);
		}

		sip_api_free(ps -> name);
		sip_api_free(ps);
	}

	/* Call the standard super-type dealloc. */
	PyBaseObject_Type.tp_dealloc((PyObject *)self);
}


/*
 * The instance call slot.  Note that keyword arguments aren't supported.
 */
static PyObject *sipWrapper_call(PyObject *self,PyObject *args,PyObject *kw)
{
	PyObject *(*f)(PyObject *,PyObject *);

	f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,call_slot);

	return f(self,args);
}


/*
 * The sequence instance item slot.
 */
static PyObject *sipWrapper_sq_item(PyObject *self,int n)
{
	PyObject *(*f)(PyObject *,PyObject *);
	PyObject *arg, *res;

	if ((arg = PyInt_FromLong(n)) == NULL)
		return NULL;

	f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,getitem_slot);

	res = f(self,arg);

	Py_DECREF(arg);

	return res;
}


/*
 * The mapping instance assign subscript slot.
 */
static int sipWrapper_mp_ass_subscript(PyObject *self,PyObject *key,
				       PyObject *value)
{
	return objobjargprocSlot(self,key,value,(value != NULL ? setitem_slot : delitem_slot));
}


/*
 * The sequence instance assign item slot.
 */
static int sipWrapper_sq_ass_item(PyObject *self,int i,PyObject *o)
{
	return intobjargprocSlot(self,i,o,(o != NULL ? setitem_slot : delitem_slot));
}


/*
 * The instance rich compare slot.
 */
static PyObject *sipWrapper_richcompare(PyObject *self,PyObject *arg,int op)
{
	PyObject *(*f)(PyObject *,PyObject *);
	sipPySlotType st;

	/* Convert the operation to a slot type. */
	switch (op)
	{
	case Py_LT:
		st = lt_slot;
		break;

	case Py_LE:
		st = le_slot;
		break;

	case Py_EQ:
		st = eq_slot;
		break;

	case Py_NE:
		st = ne_slot;
		break;

	case Py_GT:
		st = gt_slot;
		break;

	case Py_GE:
		st = ge_slot;
		break;
	}

	/* It might not exist if not all the above have been implemented. */
	if ((f = (PyObject *(*)(PyObject *,PyObject *))findSlot(self,st)) == NULL)
	{
		Py_INCREF(Py_NotImplemented);
		return Py_NotImplemented;
	}

	return f(self,arg);
}


/*
 * The instance getattro slot.
 */
static PyObject *sipWrapper_getattro(PyObject *obj,PyObject *name)
{
	char *nm;
	PyObject *attr;
	sipWrapperType *wt = (sipWrapperType *)obj -> ob_type;
	sipWrapper *w = (sipWrapper *)obj;

	/*
	 * If we are getting the instance dictionary then we don't want the
	 * metatype to handle it.
	 */
	if ((nm = PyString_AsString(name)) == NULL)
		return NULL;

	if (strcmp(nm,"__dict__") == 0)
	{
		PyObject *tmpdict;

		tmpdict = NULL;

		if (getNonStaticVariables(wt,w,&tmpdict) < 0)
		{
			Py_XDECREF(tmpdict);
			return NULL;
		}

		/*
		 * If a copy of the instance dictionary wasn't created then
		 * just return the original.  Note that Python doesn't want a
		 * proxy.
		 */
		if (tmpdict == NULL)
		{
			tmpdict = w -> dict;
			Py_INCREF(tmpdict);
		}

		return tmpdict;
	}

	/* Try the super-type's method first. */
	if ((attr = PyBaseObject_Type.tp_getattro(obj,name)) != NULL)
		return attr;

	return handleGetLazyAttr(name,wt,w);
}


/*
 * Add the values of all non-static variables to a dictionary (first making a
 * copy of the dictionary if needed).
 */
static int getNonStaticVariables(sipWrapperType *wt,sipWrapper *w,
				 PyObject **ndict)
{
	PyMethodDef *pmd;
	sipSuperClassDef *sup;

	if ((pmd = wt -> type -> td_variables) != NULL)
		while (pmd -> ml_name != NULL)
		{
			if ((pmd -> ml_flags & METH_STATIC) == 0)
			{
				int rc;
				PyObject *val, *dict;

				/*
				 * Create a copy of the original dictionary if
				 * it hasn't already been done.
				 */
				if ((dict = *ndict) == NULL)
				{
					if ((dict = PyDict_Copy(w -> dict)) == NULL)
						return -1;

					*ndict = dict;
				}

				if ((val = (*pmd -> ml_meth)((PyObject *)w,NULL)) == NULL)
					return -1;

				rc = PyDict_SetItemString(dict,pmd -> ml_name,val);

				Py_DECREF(val);

				if (rc < 0)
					return -1;
			}

			++pmd;
		}


	/* Check the base classes. */
	if ((sup = wt -> type -> td_supers) != NULL)
		do
		{
			sipExportedModuleDef *em = getClassModule(sup,wt -> type -> td_module);

			if (getNonStaticVariables(em -> em_types[sup -> sc_class],w,ndict) < 0)
				return -1;
		}
		while (!sup++ -> sc_last);

	return 0;
}


/*
 * The instance setattro slot.
 */
static int sipWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
{
	int rc;

	rc = handleSetLazyAttr(name,value,(sipWrapperType *)obj -> ob_type,(sipWrapper *)obj);

	if (rc <= 0)
		return rc;

	/* Try the super-type's method last. */
	return PyBaseObject_Type.tp_setattro(obj,name,value);
}


/*
 * The type data structure.  Note that we pretend to be a mapping object and a
 * sequence object at the same time.  Python will choose one over another,
 * depending on the context, but we implement as much as we can and don't make
 * assumptions about which Python will choose.
 */
static sipWrapperType sipWrapper_Type = {
	{
		{
			PyObject_HEAD_INIT(&sipWrapperType_Type)
			0,				/* ob_size */
			"sip.wrapper",			/* tp_name */
			sizeof (sipWrapper),		/* tp_basicsize */
			0,				/* tp_itemsize */
			(destructor)sipWrapper_dealloc,	/* tp_dealloc */
			0,				/* tp_print */
			0,				/* tp_getattr */
			0,				/* tp_setattr */
			0,				/* tp_compare */
			0,				/* tp_repr */
			0,				/* tp_as_number */
			0,				/* tp_as_sequence */
			0,				/* tp_as_mapping */
			0,				/* tp_hash */
			0,				/* tp_call */
			0,				/* tp_str */
			sipWrapper_getattro,		/* tp_getattro */
			sipWrapper_setattro,		/* tp_setattro */
			0,				/* tp_as_buffer */
			Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* 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 */
			offsetof(sipWrapper,dict),	/* tp_dictoffset */
			(initproc)sipWrapper_init,	/* tp_init */
			0,				/* tp_alloc */
			(newfunc)sipWrapper_new,	/* tp_new */
			0,				/* tp_free */
		},
	},
	0
};


/*
 * Add the slots for a type and all its super-types.
 */
static void addSlots(sipWrapperType *wt, sipTypeDef *td)
{
	sipSuperClassDef *sup;

	/* Add the slots for this type. */
	if (td -> td_pyslots != NULL)
		initSlots(wt, td -> td_pyslots);

	/* Recurse through any super-types. */
	if ((sup = td -> td_supers) != NULL)
		do
		{
			sipExportedModuleDef *em = getClassModule(sup, td -> td_module);

			addSlots(wt, em -> em_types[sup -> sc_class] -> type);
		}
		while (!sup++ -> sc_last);
}


/*
 * Add the slot handler for each slot present in the type that hasn't already
 * been defined.
 */
static void initSlots(sipWrapperType *wt, sipPySlotDef *slots)
{
	PyHeapTypeObject *sp = &wt -> super;
	void *f;

	while ((f = slots -> psd_func) != NULL)
		switch (slots++ -> psd_type)
		{
		case str_slot:
			if (sp -> type.tp_str == NULL)
				sp -> type.tp_str = (reprfunc)f;
			break;

		case int_slot:
			if (sp -> as_number.nb_int == NULL)
				sp -> as_number.nb_int = (unaryfunc)f;
			break;

		case len_slot:
			if (sp -> as_mapping.mp_length == NULL)
				sp -> as_mapping.mp_length = (inquiry)f;
			if (sp -> as_sequence.sq_length == NULL)
				sp -> as_sequence.sq_length = (inquiry)f;
			break;

		case contains_slot:
			if (sp -> as_sequence.sq_contains == NULL)
				sp -> as_sequence.sq_contains = (objobjproc)f;
			break;

		case add_slot:
			if (sp -> as_number.nb_add == NULL)
				sp -> as_number.nb_add = (binaryfunc)f;
			break;

		case concat_slot:
			if (sp -> as_sequence.sq_concat == NULL)
				sp -> as_sequence.sq_concat = (binaryfunc)f;
			break;

		case sub_slot:
			if (sp -> as_number.nb_subtract == NULL)
				sp -> as_number.nb_subtract = (binaryfunc)f;
			break;

		case mul_slot:
			if (sp -> as_number.nb_multiply == NULL)
				sp -> as_number.nb_multiply = (binaryfunc)f;
			break;

		case repeat_slot:
			if (sp -> as_sequence.sq_repeat == NULL)
				sp -> as_sequence.sq_repeat = (intargfunc)f;
			break;

		case div_slot:
			if (sp -> as_number.nb_divide == NULL)
				sp -> as_number.nb_divide = (binaryfunc)f;
			break;

		case mod_slot:
			if (sp -> as_number.nb_remainder == NULL)
				sp -> as_number.nb_remainder = (binaryfunc)f;
			break;

		case and_slot:
			if (sp -> as_number.nb_and == NULL)
				sp -> as_number.nb_and = (binaryfunc)f;
			break;

		case or_slot:
			if (sp -> as_number.nb_or == NULL)
				sp -> as_number.nb_or = (binaryfunc)f;
			break;

		case xor_slot:
			if (sp -> as_number.nb_xor == NULL)
				sp -> as_number.nb_xor = (binaryfunc)f;
			break;

		case lshift_slot:
			if (sp -> as_number.nb_lshift == NULL)
				sp -> as_number.nb_lshift = (binaryfunc)f;
			break;

		case rshift_slot:
			if (sp -> as_number.nb_rshift == NULL)
				sp -> as_number.nb_rshift = (binaryfunc)f;
			break;

		case iadd_slot:
			if (sp -> as_number.nb_inplace_add == NULL)
				sp -> as_number.nb_inplace_add = (binaryfunc)f;
			break;

		case iconcat_slot:
			if (sp -> as_sequence.sq_inplace_concat == NULL)
				sp -> as_sequence.sq_inplace_concat = (binaryfunc)f;
			break;

		case isub_slot:
			if (sp -> as_number.nb_inplace_subtract == NULL)
				sp -> as_number.nb_inplace_subtract = (binaryfunc)f;
			break;

		case imul_slot:
			if (sp -> as_number.nb_inplace_multiply == NULL)
				sp -> as_number.nb_inplace_multiply = (binaryfunc)f;
			break;

		case irepeat_slot:
			if (sp -> as_sequence.sq_inplace_repeat == NULL)
				sp -> as_sequence.sq_inplace_repeat = (intargfunc)f;
			break;

		case idiv_slot:
			if (sp -> as_number.nb_inplace_divide == NULL)
				sp -> as_number.nb_inplace_divide = (binaryfunc)f;
			break;

		case imod_slot:
			if (sp -> as_number.nb_inplace_remainder == NULL)
				sp -> as_number.nb_inplace_remainder = (binaryfunc)f;
			break;

		case iand_slot:
			if (sp -> as_number.nb_inplace_and == NULL)
				sp -> as_number.nb_inplace_and = (binaryfunc)f;
			break;

		case ior_slot:
			if (sp -> as_number.nb_inplace_or == NULL)
				sp -> as_number.nb_inplace_or = (binaryfunc)f;
			break;

		case ixor_slot:
			if (sp -> as_number.nb_inplace_xor == NULL)
				sp -> as_number.nb_inplace_xor = (binaryfunc)f;
			break;

		case ilshift_slot:
			if (sp -> as_number.nb_inplace_lshift == NULL)
				sp -> as_number.nb_inplace_lshift = (binaryfunc)f;
			break;

		case irshift_slot:
			if (sp -> as_number.nb_inplace_rshift == NULL)
				sp -> as_number.nb_inplace_rshift = (binaryfunc)f;
			break;

		case invert_slot:
			if (sp -> as_number.nb_invert == NULL)
				sp -> as_number.nb_invert = (unaryfunc)f;
			break;

		case call_slot:
			if (sp -> type.tp_call == NULL)
				sp -> type.tp_call = sipWrapper_call;
			break;

		case getitem_slot:
			if (sp -> as_mapping.mp_subscript == NULL)
				sp -> as_mapping.mp_subscript = (binaryfunc)f;
			if (sp -> as_sequence.sq_item == NULL)
				sp -> as_sequence.sq_item = sipWrapper_sq_item;
			break;

		case setitem_slot:
		case delitem_slot:
			if (sp -> as_mapping.mp_ass_subscript == NULL)
				sp -> as_mapping.mp_ass_subscript = sipWrapper_mp_ass_subscript;
			if (sp -> as_sequence.sq_ass_item == NULL)
				sp -> as_sequence.sq_ass_item = sipWrapper_sq_ass_item;
			break;

		case lt_slot:
		case le_slot:
		case eq_slot:
		case ne_slot:
		case gt_slot:
		case ge_slot:
			if (sp -> type.tp_richcompare == NULL)
				sp -> type.tp_richcompare = sipWrapper_richcompare;
			break;

		case cmp_slot:
			if (sp -> type.tp_compare == NULL)
				sp -> type.tp_compare = (cmpfunc)f;
			break;

		case nonzero_slot:
			if (sp -> as_number.nb_nonzero == NULL)
				sp -> as_number.nb_nonzero = (inquiry)f;
			break;

		case neg_slot:
			if (sp -> as_number.nb_negative == NULL)
				sp -> as_number.nb_negative = (unaryfunc)f;
			break;

		case repr_slot:
			if (sp -> type.tp_repr == NULL)
				sp -> type.tp_repr = (reprfunc)f;
			break;
		}
}


#ifdef SIP_QT_SUPPORT

/*
 * Search for a named class and return TRUE and the necessary information to
 * create an instance of it if it was found.
 */
static int findClassArg(sipWrapperType **wttab, const char *name, size_t len,
			sipSigArg *at)
{
	sipWrapperType *wt;

	while ((wt = *wttab++) != NULL)
	{
		if (wt -> type -> td_cname != NULL)
		{
			if (strncmp(wt -> type -> td_cname, name, len) != 0)
				continue;
		}
		else if (!sameScopedName(wt -> type -> td_name, name, len))
			continue;

		at -> atype = class_sat;
		at -> u.wt = wt;

		return TRUE;
	}

	return FALSE;
}


/*
 * Search for a mapped type and return TRUE and the necessary information to
 * create an instance of it if it was found.
 */
static int findMtypeArg(sipMappedTypeDef **mttab, const char *name, size_t len,
			sipSigArg *at)
{
	sipMappedTypeDef *mt;

	while ((mt = *mttab++) != NULL)
		if (strncmp(mt -> mt_name, name, len) == 0)
		{
			at -> atype = mtype_sat;
			at -> u.mt = mt;

			return TRUE;
		}

	return FALSE;
}


/*
 * Search for a named enum and return TRUE and the necessary information to
 * create an instance of it if it was found.
 */
static int findEnumArg(sipExportedModuleDef *emd, const char *name, size_t len,
		       sipSigArg *at)
{
	int i;
	sipEnumDef *ed;

	for (ed = emd -> em_enumdefs, i = 0; i < emd -> em_nrenums; ++i, ++ed)
	{
		if (ed -> e_cname != NULL)
		{
			if (strncmp(ed -> e_cname, name, len) != 0)
				continue;
		}
		else if (!sameScopedName(ed -> e_name, name, len))
			continue;

		at -> atype = enum_sat;
		at -> u.et = emd -> em_enums[i];

		return TRUE;
	}

	return FALSE;
}


/*
 * Search for a named type and the necessary information to create an instance
 * of it.
 */
void sipFindSigArgType(const char *name, size_t len, sipSigArg *at)
{
	sipExportedModuleDef *em;

	at -> atype = unknown_sat;

	for (em = clientList; em != NULL; em = em -> em_next)
	{
		sipTypedefDef *tdd;

		/* Search for a typedef. */
		if ((tdd = em -> em_typedefs) != NULL)
			while (tdd -> tdd_name != NULL)
			{
				if (strncmp(tdd -> tdd_name, name, len) == 0)
				{
					sipExportedModuleDef *tem;
					const char *tn;
					size_t tnlen;

					at -> atype = tdd -> tdd_type;

					/* Done with the simple cases. */
					if ((tn = tdd -> tdd_type_name) == NULL)
						return;

					/*
					 * Find the module that this class,
					 * mapped type or enum is defined in.
					 */
					if (tdd -> tdd_mod_name == NULL)
						tem = em;
					else
						for (tem = clientList; tem != NULL; tem = tem -> em_next)
							if (strcmp(tem -> em_name, tdd -> tdd_mod_name) == 0)
								break;

					tnlen = strlen(tn);

					switch (tdd -> tdd_type)
					{
					case class_sat:
						findClassArg(tem -> em_types, tn, tnlen, at);
						break;

					case mtype_sat:
						findMtypeArg(tem -> em_mappedtypes, tn, tnlen, at);
						break;

					case enum_sat:
						findEnumArg(tem, tn, tnlen, at);
						break;
					}

					/* We should have found it by now. */
					return;
				}

				++tdd;
			}

		/* Search for a class. */
		if (em -> em_types != NULL && findClassArg(em -> em_types, name, len, at))
			return;

		/* Search for a mapped type. */
		if (em -> em_mappedtypes != NULL && findMtypeArg(em -> em_mappedtypes, name, len, at))
			return;

		/* Search for an enum. */
		if (em -> em_enums != NULL && findEnumArg(em, name, len, at))
			return;
	}
}


/*
 * Return TRUE if a Python scoped name and a fixed length C++ scoped name
 * match.
 */
static int sameScopedName(const char *pyname, const char *name, size_t len)
{
	char ch;

	/* Skip the module name from the Python name. */
	pyname = strchr(pyname, '.') + 1;

	while ((ch = *pyname++) != '\0' && len)
		if (ch == '.')
		{
			if (len < 2 || name[0] != ':' || name[1] != ':')
				return FALSE;

			name += 2;
			len -= 2;
		}
		else if (ch == name[0])
		{
			++name;
			--len;
		}
		else
			return FALSE;

	return (ch == '\0' && len == 0);
}


/*
 * Wrap a QVariant instance and return the corresponding Python object.
 */
PyObject *sipWrapQVariant(void *cpp)
{
	static sipWrapperType *qvar_class = NULL;

	/* Find the type object if we haven't already got it. */
	if (qvar_class == NULL)
	{
		sipExportedModuleDef *em;

		for (em = clientList; em != NULL; em = em -> em_next)
		{
			sipWrapperType **wtp;

			for (wtp = em -> em_types; *wtp != NULL; ++wtp)
				if (strcmp((*wtp) -> type -> td_name, "qt.QVariant") == 0)
				{
					qvar_class = *wtp;
					break;
				}

			if (qvar_class != NULL)
				break;
		}

		if (qvar_class == NULL)
		{
			PyErr_SetString(PyExc_SystemError,"sipWrapQVariant(): unable to find qt.QVariant type");
			return NULL;
		}
	}

	return sip_api_map_cpp_to_self(cpp, qvar_class);
}

#endif
