summaryrefslogtreecommitdiffstats
path: root/python/sip/siplib
diff options
context:
space:
mode:
Diffstat (limited to 'python/sip/siplib')
-rw-r--r--python/sip/siplib/bool.cpp19
-rw-r--r--python/sip/siplib/objmap.c264
-rw-r--r--python/sip/siplib/qtlib.c1254
-rw-r--r--python/sip/siplib/sip.h1302
-rw-r--r--python/sip/siplib/sipint.h121
-rw-r--r--python/sip/siplib/siplib.c7902
-rw-r--r--python/sip/siplib/siplib.sbf16
-rw-r--r--python/sip/siplib/threads.c223
8 files changed, 11101 insertions, 0 deletions
diff --git a/python/sip/siplib/bool.cpp b/python/sip/siplib/bool.cpp
new file mode 100644
index 00000000..c21a0c79
--- /dev/null
+++ b/python/sip/siplib/bool.cpp
@@ -0,0 +1,19 @@
+// This contains all the C++ code that is needed by the sip module.
+//
+// Copyright (c) 2007
+// Riverbank Computing Limited <[email protected]>
+//
+// 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.
+
+
+// Set a C++ bool for the main C implementation of the module.
+extern "C" void sipSetBool(void *ptr, int val)
+{
+ *reinterpret_cast<bool *>(ptr) = val;
+}
diff --git a/python/sip/siplib/objmap.c b/python/sip/siplib/objmap.c
new file mode 100644
index 00000000..efc7bc2a
--- /dev/null
+++ b/python/sip/siplib/objmap.c
@@ -0,0 +1,264 @@
+/*
+ * This module implements a hash table class for mapping C/C++ addresses to the
+ * corresponding wrapped Python object.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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 <string.h>
+
+#include "sip.h"
+#include "sipint.h"
+
+
+#define hash_1(k,s) (((unsigned long)(k)) % (s))
+#define hash_2(k,s) ((s) - 2 - (hash_1((k),(s)) % ((s) - 2)))
+
+
+/* Prime numbers to use as hash table sizes. */
+static unsigned long hash_primes[] = {
+ 521, 1031, 2053, 4099,
+ 8209, 16411, 32771, 65537, 131101, 262147,
+ 524309, 1048583, 2097169, 4194319, 8388617, 16777259,
+ 33554467, 67108879, 134217757, 268435459, 536870923, 1073741827,
+ 2147483659U,0
+};
+
+
+static sipHashEntry *newHashTable(unsigned long);
+static sipHashEntry *findHashEntry(sipObjectMap *,void *);
+static void reorganiseMap(sipObjectMap *om);
+
+
+/*
+ * Initialise an object map.
+ */
+void sipOMInit(sipObjectMap *om)
+{
+ om -> primeIdx = 0;
+ om -> unused = om -> size = hash_primes[om -> primeIdx];
+ om -> stale = 0;
+ om -> hash_array = newHashTable(om -> size);
+}
+
+
+/*
+ * Finalise an object map.
+ */
+void sipOMFinalise(sipObjectMap *om)
+{
+ sip_api_free(om -> hash_array);
+}
+
+
+/*
+ * Allocate and initialise a new hash table.
+ */
+static sipHashEntry *newHashTable(unsigned long size)
+{
+ size_t nbytes;
+ sipHashEntry *hashtab;
+
+ nbytes = sizeof (sipHashEntry) * size;
+
+ if ((hashtab = (sipHashEntry *)sip_api_malloc(nbytes)) != NULL)
+ memset(hashtab,0,nbytes);
+
+ return hashtab;
+}
+
+
+/*
+ * Return a pointer to the hash entry that is used, or should be used, for the
+ * given C/C++ address.
+ */
+static sipHashEntry *findHashEntry(sipObjectMap *om,void *key)
+{
+ unsigned long hash, inc;
+ void *hek;
+
+ hash = hash_1(key,om -> size);
+ inc = hash_2(key,om -> size);
+
+ while ((hek = om -> hash_array[hash].key) != NULL && hek != key)
+ hash = (hash + inc) % om -> size;
+
+ return &om -> hash_array[hash];
+}
+
+
+/*
+ * Return the wrapped Python object of a specific type for a C/C++ address or
+ * NULL if it wasn't found.
+ */
+sipWrapper *sipOMFindObject(sipObjectMap *om,void *key, sipWrapperType *type)
+{
+ sipHashEntry *he = findHashEntry(om, key);
+ sipWrapper *w;
+
+ /* Go through each wrapped object at this address. */
+ for (w = he->first; w != NULL; w = w->next)
+ {
+ /*
+ * If this wrapped object is of the given type, or a sub-type
+ * of it, or vice versa, then we assume it is the same C++
+ * object.
+ */
+ if (PyObject_TypeCheck(w, (PyTypeObject *)type) ||
+ PyType_IsSubtype((PyTypeObject *)type, w->ob_type))
+ return w;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Add a C/C++ address and the corresponding wrapped Python object to the map.
+ */
+void sipOMAddObject(sipObjectMap *om,sipWrapper *val)
+{
+ sipHashEntry *he = findHashEntry(om,val -> u.cppPtr);
+
+ /*
+ * If the bucket is in use then we appear to have several objects at
+ * the same address.
+ */
+ if (he -> first != NULL)
+ {
+ /*
+ * This can happen for three reasons. A variable of one class
+ * can be declared at the start of another class. Therefore
+ * there are two objects, of different classes, with the same
+ * address. The second reason is that the old C/C++ object has
+ * been deleted by C/C++ but we didn't get to find out for some
+ * reason, and a new C/C++ instance has been created at the
+ * same address. The third reason is if we are in the process
+ * of deleting a Python object but the C++ object gets wrapped
+ * again because the C++ dtor called a method that has been
+ * re-implemented in Python. The absence of the SIP_SHARE_MAP
+ * flag tells us that a new C++ instance has just been created
+ * and so we know the second reason is the correct one so we
+ * mark the old pointers as invalid and reuse the entry.
+ * Otherwise we just add this one to the existing list of
+ * objects at this address.
+ */
+ if (!(val -> flags & SIP_SHARE_MAP))
+ {
+ sipWrapper *w;
+
+ for (w = he -> first; w != NULL; w = w -> next)
+ w -> u.cppPtr = NULL;
+
+ he -> first = NULL;
+ }
+
+ val -> next = he -> first;
+ he -> first = val;
+
+ return;
+ }
+
+ /* See if the bucket was unused or stale. */
+ if (he -> key == NULL)
+ {
+ he -> key = val -> u.cppPtr;
+ om -> unused--;
+ }
+ else
+ om -> stale--;
+
+ /* Add the rest of the new value. */
+ he -> first = val;
+ val -> next = NULL;
+
+ reorganiseMap(om);
+}
+
+
+/*
+ * Reorganise a map if it is running short of space.
+ */
+static void reorganiseMap(sipObjectMap *om)
+{
+ unsigned long old_size, i;
+ sipHashEntry *ohe, *old_tab;
+
+ /* Don't bother if it still has more than 12% available. */
+ if (om -> unused > om -> size >> 3)
+ return;
+
+ /*
+ * If reorganising (ie. making the stale buckets unused) using the same
+ * sized table would make 25% available then do that. Otherwise use a
+ * bigger table (if possible).
+ */
+ if (om -> unused + om -> stale < om -> size >> 2 && hash_primes[om -> primeIdx + 1] != 0)
+ om -> primeIdx++;
+
+ old_size = om -> size;
+ old_tab = om -> hash_array;
+
+ om -> unused = om -> size = hash_primes[om -> primeIdx];
+ om -> stale = 0;
+ om -> hash_array = newHashTable(om -> size);
+
+ /* Transfer the entries from the old table to the new one. */
+ ohe = old_tab;
+
+ for (i = 0; i < old_size; ++i)
+ {
+ if (ohe -> key != NULL && ohe -> first != NULL)
+ {
+ *findHashEntry(om,ohe -> key) = *ohe;
+ om -> unused--;
+ }
+
+ ++ohe;
+ }
+
+ sip_api_free(old_tab);
+}
+
+
+/*
+ * Remove a C/C++ object from the table. Return 0 if it was removed
+ * successfully.
+ */
+int sipOMRemoveObject(sipObjectMap *om,sipWrapper *val)
+{
+ sipHashEntry *he = findHashEntry(om,val -> u.cppPtr);
+ sipWrapper **wp;
+
+ for (wp = &he -> first; *wp != NULL; wp = &(*wp) -> next)
+ if (*wp == val)
+ {
+ *wp = val -> next;
+
+ /*
+ * If the bucket is now empty then count it as stale.
+ * Note that we do not NULL the key and count it as
+ * unused because that might throw out the search for
+ * another entry that wanted to go here, found it
+ * already occupied, and was put somewhere else. In
+ * other words, searches must be repeatable until we
+ * reorganise the table.
+ */
+ if (he -> first == NULL)
+ om -> stale++;
+
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/python/sip/siplib/qtlib.c b/python/sip/siplib/qtlib.c
new file mode 100644
index 00000000..da7637f1
--- /dev/null
+++ b/python/sip/siplib/qtlib.c
@@ -0,0 +1,1254 @@
+/*
+ * The SIP library code that implements the interface to the optional module
+ * supplied Qt support.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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 <string.h>
+
+#include "sip.h"
+#include "sipint.h"
+
+
+/* This is how Qt "types" signals and slots. */
+#define isQtSlot(s) (*(s) == '1')
+#define isQtSignal(s) (*(s) == '2')
+
+
+static PyObject *py_sender = NULL; /* The last Python signal sender. */
+
+
+static int isSameSlot(sipSlot *,PyObject *,const char *);
+static int emitQtSig(sipWrapper *,const char *,PyObject *);
+static int emitToSlotList(sipSlotList *rxlist, PyObject *sigargs);
+static int addSlotToPySigList(sipWrapper *,const char *,PyObject *,const char *);
+static void removeSlotFromPySigList(sipWrapper *,const char *,PyObject *,const char *);
+static PyObject *getWeakRef(PyObject *obj);
+static sipPySig *findPySignal(sipWrapper *,const char *);
+static char *sipStrdup(const char *);
+static int saveSlot(sipSlot *sp, PyObject *rxObj, const char *slot);
+static void *createUniversalSlot(sipWrapper *txSelf, const char *sig, PyObject *rxObj, const char *slot, const char **member);
+static void *findSignal(void *txrx, const char **sig);
+static void *newSignal(void *txrx, const char **sig);
+static void freeSlot(sipSlot *slot);
+
+
+/*
+ * Return the most recent signal sender.
+ */
+PyObject *sip_api_get_sender()
+{
+ PyObject *sender;
+ const void *qt_sender;
+
+ /*
+ * If there is a Qt sender then it is more recent than the last Python
+ * sender, so use it instead.
+ */
+ if ((qt_sender = sipQtSupport->qt_get_sender()) != NULL)
+ sender = sip_api_convert_from_instance((void *)qt_sender, sipQObjectClass, NULL);
+ else
+ {
+ if ((sender = py_sender) == NULL)
+ sender = Py_None;
+
+ Py_INCREF(sender);
+ }
+
+ return sender;
+}
+
+
+/*
+ * Release the resources held by a connection.
+ */
+void sip_api_free_connection(sipSlotConnection *conn)
+{
+ freeSlot(&conn->sc_slot);
+}
+
+
+/*
+ * Compare two connections and return TRUE if they are the same.
+ */
+int sip_api_same_connection(sipSlotConnection *conn, void *tx, const char *sig,
+ PyObject *rxObj, const char *slot)
+{
+ return (conn->sc_transmitter == tx &&
+ sipQtSupport->qt_same_name(conn->sc_signature->sg_signature, sig) &&
+ isSameSlot(&conn->sc_slot, rxObj, slot));
+}
+
+
+/*
+ * Parse the signal arguments for a connection.
+ */
+sipSignature *sip_api_parse_signature(const char *sig)
+{
+ static sipSignature *psig_list = NULL;
+ sipSignature *psig;
+ const char *sp, *ep;
+
+ /*
+ * First see if it has already been parsed. Note that both sides of a
+ * connection will probably be parsed twice because the function names will
+ * be different even though the signatures will probably be the same. We
+ * could be more clever, the most saving is when repeatedly emitting a
+ * signal for which this is sufficient.
+ */
+ for (psig = psig_list; psig != NULL; psig = psig->sg_next)
+ if (sipQtSupport->qt_same_name(psig->sg_signature, sig))
+ return psig;
+
+ /* Create a new one including space for the copy of the signature. */
+ if ((psig = (sipSignature *)sip_api_malloc(sizeof (sipSignature) + strlen(sig) + 1)) == NULL)
+ return NULL;
+
+ psig->sg_signature = (char *)&psig[1];
+ psig->sg_nrargs = 0;
+ psig->sg_args = 0;
+
+ /* Find the start and end of the arguments. */
+ sp = strchr(sig, '(');
+ ep = strrchr(sig, ')');
+
+ /* If the signal isn't well formed we assume Qt will pick it up. */
+ if (sp && ep && sp < ep)
+ {
+ /*
+ * Copy the signature arguments while counting them and
+ * removing non-significant spaces. Each argument is left as a
+ * '\0' terminated string.
+ */
+ char *dp = psig->sg_signature;
+ int depth = 0, nrcommas = 0, argstart = TRUE;
+
+ for (;;)
+ {
+ char ch = *++sp;
+
+ if (strchr(",*&)<>", ch))
+ {
+ /* Backup over any previous trailing space. */
+ if (dp > psig->sg_signature && dp[-1] == ' ')
+ --dp;
+
+ if (sp == ep)
+ {
+ *dp = '\0';
+ break;
+ }
+
+ if (ch == ',' && depth == 0)
+ {
+ *dp++ = '\0';
+ ++nrcommas;
+ argstart = TRUE;
+ }
+ else
+ {
+ *dp++ = ch;
+
+ /*
+ * Make sure commas in template
+ * arguments are ignored.
+ */
+ if (ch == '<')
+ ++depth;
+ else if (ch == '>')
+ --depth;
+ }
+ }
+ else if (ch == ' ')
+ {
+ /* Ignore leading and multiple spaces. */
+ if (!argstart && dp[-1] != ' ')
+ *dp++ = ch;
+ }
+ else
+ {
+ *dp++ = ch;
+ argstart = FALSE;
+ }
+ }
+
+ /* Handle the arguments now they are in a normal form. */
+ if (*psig->sg_signature)
+ {
+ char *arg = psig->sg_signature;
+ int a;
+
+ /* Allocate the space. */
+ psig->sg_nrargs = nrcommas + 1;
+
+ if ((psig->sg_args = (sipSigArg *)sip_api_malloc(sizeof (sipSigArg) * psig->sg_nrargs)) == NULL)
+ {
+ sip_api_free(psig);
+ return NULL;
+ }
+
+ for (a = 0; a < psig->sg_nrargs; ++a)
+ {
+ size_t btlen = 0;
+ int unsup, isref = FALSE, indir = 0;
+ sipSigArgType sat = unknown_sat;
+
+ /* Find the start of the significant part of the type. */
+ dp = arg;
+
+ if (strncmp(dp, "const ", 6) == 0)
+ dp += 6;
+
+ /*
+ * Find the length of the base type, the number of indirections
+ * and if it is a reference.
+ */
+ for (ep = dp; *ep; ++ep)
+ if (*ep == '&')
+ isref = TRUE;
+ else if (*ep == '*')
+ ++indir;
+ else
+ ++btlen;
+
+ /*
+ * Assume that anything other than a base type is unsupported.
+ */
+ unsup = (isref || indir);
+
+ /* Parse the base type. */
+ switch (btlen)
+ {
+ case 3:
+ if (strncmp(dp, "int", 3) == 0)
+ sat = int_sat;
+ break;
+
+ case 4:
+ if (strncmp(dp, "bool", 4) == 0)
+ sat = bool_sat;
+ else if (strncmp(dp, "long", 4) == 0)
+ sat = long_sat;
+ else if (strncmp(dp, "char", 4) == 0)
+ {
+ sat = (indir ? string_sat : char_sat);
+ unsup = (isref || indir > 1);
+ }
+ else if (strncmp(dp, "void", 4) == 0)
+ {
+ sat = void_sat;
+ unsup = (isref || indir != 1);
+ }
+ break;
+
+ case 5:
+ if (strncmp(dp, "float", 5) == 0)
+ sat = float_sat;
+ else if (strncmp(dp, "short", 5) == 0)
+ sat = short_sat;
+ break;
+
+ case 6:
+ if (strncmp(dp, "double", 6) == 0)
+ sat = double_sat;
+ break;
+
+ case 7:
+ if (strncmp(dp, "__int64", 7) == 0)
+ sat = longlong_sat;
+ else if (strncmp(dp, "wchar_t", 7) == 0)
+ {
+ sat = (indir ? wstring_sat : wchar_sat);
+ unsup = (isref || indir > 1);
+ }
+ break;
+
+ case 8:
+ if (strncmp(dp, "unsigned", 8) == 0)
+ sat = uint_sat;
+ else if (strncmp(dp, "QVariant", 8) == 0)
+ {
+ if (indir == 0)
+ {
+ sat = qvariant_sat;
+ unsup = FALSE;
+ }
+ else if (indir == 1)
+ {
+ sat = qvariantp_sat;
+ unsup = FALSE;
+ }
+ }
+ break;
+
+ case 9:
+ if (strncmp(dp, "long long", 9) == 0)
+ sat = longlong_sat;
+ break;
+
+ case 11:
+ if (strncmp(dp, "signed char", 11) == 0)
+ {
+ sat = (indir ? sstring_sat : schar_sat);
+ unsup = (isref || indir > 1);
+ }
+ break;
+
+ case 12:
+ if (strncmp(dp, "unsigned int", 12) == 0)
+ sat = uint_sat;
+ break;
+
+ case 13:
+ if (strncmp(dp, "unsigned long", 13) == 0)
+ sat = ulong_sat;
+ else if (strncmp(dp, "unsigned char", 13) == 0)
+ {
+ sat = (indir ? ustring_sat : uchar_sat);
+ unsup = (isref || indir > 1);
+ }
+ else if (strncmp(dp, "PyQt_PyObject", 13) == 0 && indir == 0)
+ {
+ sat = pyobject_sat;
+ unsup = FALSE;
+ }
+ break;
+
+ case 14:
+ if (strncmp(dp, "unsigned short", 14) == 0)
+ sat = ushort_sat;
+ break;
+
+ case 16:
+ if (strncmp(dp, "unsigned __int64", 16) == 0)
+ sat = ulonglong_sat;
+ break;
+
+ case 18:
+ if (strncmp(dp, "unsigned long long", 18) == 0)
+ sat = ulonglong_sat;
+ break;
+ }
+
+ if (sat == unknown_sat)
+ sipFindSigArgType(dp, btlen, &psig->sg_args[a], indir);
+ else
+ {
+ if (unsup)
+ sat = unknown_sat;
+
+ psig->sg_args[a].atype = sat;
+ }
+
+ /* Move to the start of the next argument. */
+ arg += strlen(arg) + 1;
+ }
+ }
+ }
+
+ /* Make a deep copy of the signal. */
+ strcpy(psig->sg_signature, sig);
+
+ /* Add it to the list so it can be re-used. */
+ psig->sg_next = psig_list;
+ psig_list = psig;
+
+ return psig;
+}
+
+
+/*
+ * Find an existing signal.
+ */
+static void *findSignal(void *txrx, const char **sig)
+{
+ sipSignature *psig;
+
+ /*
+ * Handle the trivial case where the Qt implementation doesn't support
+ * universal signals.
+ */
+ if (sipQtSupport->qt_is_qt_signal == NULL)
+ return txrx;
+
+ /* See if this a shortcircuited Python signal. */
+ if (strchr(*sig, '(') == NULL)
+ return sipQtSupport->qt_find_universal_signal_shortcut(txrx, *sig, sig);
+
+ /* See if the existing object can be used itself. */
+ if (sipQtSupport->qt_is_qt_signal(txrx, *sig))
+ return txrx;
+
+ if ((psig = sip_api_parse_signature(*sig)) == NULL)
+ return NULL;
+
+ /* Find an ordinary universal signal. */
+ return sipQtSupport->qt_find_universal_signal(txrx, psig);
+}
+
+
+/*
+ * Return a usable signal, creating a new universal signal if needed.
+ */
+static void *newSignal(void *txrx, const char **sig)
+{
+ sipSignature *psig;
+
+ /*
+ * Handle the trivial case where the Qt implementation doesn't support
+ * universal signals.
+ */
+ if (sipQtSupport->qt_is_qt_signal == NULL)
+ return txrx;
+
+ /* See if this a shortcircuited Python signal. */
+ if (strchr(*sig, '(') == NULL)
+ return sipQtSupport->qt_create_universal_signal_shortcut(txrx, *sig, sig);
+
+ /* See if the existing object can be used itself. */
+ if (sipQtSupport->qt_is_qt_signal(txrx, *sig))
+ return txrx;
+
+ if ((psig = sip_api_parse_signature(*sig)) == NULL)
+ return NULL;
+
+ /* Create an ordinary universal signal. */
+ return sipQtSupport->qt_create_universal_signal(txrx, psig);
+}
+
+
+/*
+ * Create a universal slot. Returns a pointer to it or 0 if there was an
+ * error.
+ */
+static void *createUniversalSlot(sipWrapper *txSelf, const char *sig,
+ PyObject *rxObj, const char *slot,
+ const char **member)
+{
+ sipSlotConnection conn;
+ void *us;
+
+ /* Initialise the connection. */
+ conn.sc_transmitter = (txSelf ? sipGetAddress(txSelf) : 0);
+
+ /* Save the real slot. */
+ if (saveSlot(&conn.sc_slot, rxObj, slot) < 0)
+ return 0;
+
+ /* Parse the signature and create the universal slot. */
+ if ((conn.sc_signature = sip_api_parse_signature(sig)) == NULL || (us = sipQtSupport->qt_create_universal_slot(txSelf, &conn, member)) == NULL)
+ {
+ sip_api_free_connection(&conn);
+ return 0;
+ }
+
+ return us;
+}
+
+
+/*
+ * Emit a Python or Qt signal.
+ */
+int sip_api_emit_signal(PyObject *self,const char *sig,PyObject *sigargs)
+{
+ sipPySig *ps;
+ void *tx;
+ sipWrapper *w = (sipWrapper *)self;
+
+ /*
+ * Don't do anything if signals are blocked. Qt signals would be blocked
+ * anyway, but this blocks Python signals as well.
+ */
+ if ((tx = sip_api_get_cpp_ptr(w, sipQObjectClass)) == NULL || sipQtSupport->qt_signals_blocked(tx))
+ return 0;
+
+ if (isQtSignal(sig))
+ {
+ sipSignature *psig;
+
+ /* Handle Qt implementations that emit using generated code. */
+ if (!sipQtSupport->qt_emit_signal)
+ return emitQtSig(w, sig, sigargs);
+
+ /* See if the signal is a shortcut. */
+ if (strchr(sig, '(') == NULL)
+ return sipQtSupport->qt_emit_signal_shortcut(tx, sig, sigargs);
+
+ if ((psig = sip_api_parse_signature(sig)) == NULL)
+ return -1;
+
+ if (psig->sg_nrargs != PyTuple_GET_SIZE(sigargs))
+ PyErr_Format(PyExc_TypeError, "Signal has %d arguments, but %d given", psig->sg_nrargs, PyTuple_GET_SIZE(sigargs));
+
+ return sipQtSupport->qt_emit_signal(tx, psig, sigargs);
+ }
+
+ if ((ps = findPySignal(w,sig)) != NULL)
+ {
+ int rc;
+
+ /* Forget the last Qt sender and remember this one. */
+ sipQtSupport->qt_forget_sender();
+ py_sender = self;
+
+ rc = emitToSlotList(ps -> rxlist,sigargs);
+
+ /* Forget this as a sender. */
+ py_sender = NULL;
+
+ return rc;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Search the Python signal list for a signal.
+ */
+static sipPySig *findPySignal(sipWrapper *w,const char *sig)
+{
+ sipPySig *ps;
+
+ for (ps = w -> pySigList; ps != NULL; ps = ps -> next)
+ if (sipQtSupport->qt_same_name(ps -> name,sig))
+ return ps;
+
+ return NULL;
+}
+
+
+/*
+ * Search a signal table for a signal. If found, call the emitter function
+ * with the signal arguments. Return 0 if the signal was emitted or <0 if
+ * there was an error.
+ */
+static int emitQtSig(sipWrapper *w,const char *sig,PyObject *sigargs)
+{
+ sipQtSignal *tab;
+
+ /* Search the table. */
+ for (tab = ((sipWrapperType *)(w -> ob_type)) -> type -> td_emit; tab -> st_name != NULL; ++tab)
+ {
+ const char *sp, *tp;
+ int found;
+
+ /* Compare only the base name. */
+ sp = &sig[1];
+ tp = tab -> st_name;
+
+ found = TRUE;
+
+ while (*sp != '\0' && *sp != '(' && *tp != '\0')
+ if (*sp++ != *tp++)
+ {
+ found = FALSE;
+ break;
+ }
+
+ if (found)
+ return (*tab -> st_emitfunc)(w,sigargs);
+ }
+
+ /* It wasn't found if we got this far. */
+ PyErr_Format(PyExc_NameError,"Invalid signal %s",&sig[1]);
+
+ return -1;
+}
+
+
+/*
+ * Send a signal to a single slot (Qt or Python).
+ */
+int sip_api_emit_to_slot(sipSlot *slot, PyObject *sigargs)
+{
+ PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *newmeth, *sref;
+
+ /* Keep some compilers quiet. */
+ oxtype = oxvalue = oxtb = NULL;
+
+ /* Fan out Qt signals. */
+ if (slot -> name != NULL && slot -> name[0] != '\0')
+ return sip_api_emit_signal(slot -> pyobj,slot -> name,sigargs);
+
+ /* Get the object to call, resolving any weak references. */
+ if (slot -> weakSlot == NULL)
+ sref = NULL;
+ else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL)
+ return -1;
+ else
+ Py_INCREF(sref);
+
+ if (sref == Py_None)
+ {
+ /*
+ * If the real object has gone then we pretend everything is Ok. This
+ * mimics the Qt behaviour of not caring if a receiving object has been
+ * deleted.
+ */
+ Py_DECREF(sref);
+ return 0;
+ }
+
+ if (slot -> pyobj == NULL)
+ {
+ PyObject *self = (sref != NULL ? sref : slot->meth.mself);
+
+ /* See if any underlying C++ instance has gone. */
+ if (self != NULL && sip_api_wrapper_check(self) && ((sipWrapper *)self)->u.cppPtr == NULL)
+ {
+ Py_XDECREF(sref);
+ return 0;
+ }
+
+ if ((sfunc = PyMethod_New(slot->meth.mfunc, self, slot->meth.mclass)) == NULL)
+ {
+ Py_XDECREF(sref);
+ return -1;
+ }
+
+ /* Make sure we garbage collect the new method. */
+ newmeth = sfunc;
+ }
+ else if (slot -> name != NULL)
+ {
+ char *mname = slot -> name + 1;
+ PyObject *self = (sref != NULL ? sref : slot->pyobj);
+
+ /* See if any underlying C++ instance has gone. */
+ if (self != NULL && sip_api_wrapper_check(self) && ((sipWrapper *)self)->u.cppPtr == NULL)
+ {
+ Py_XDECREF(sref);
+ return 0;
+ }
+
+ if ((sfunc = PyObject_GetAttrString(self, mname)) == NULL || !PyCFunction_Check(sfunc))
+ {
+ /*
+ * Note that in earlier versions of SIP this error would be
+ * detected when the slot was connected.
+ */
+ PyErr_Format(PyExc_NameError,"Invalid slot %s",mname);
+
+ Py_XDECREF(sref);
+ return -1;
+ }
+
+ /* Make sure we garbage collect the new method. */
+ newmeth = sfunc;
+ }
+ else if (slot->pyobj == Py_None)
+ {
+ /*
+ * This was a lambda function that has been freed by the cyclic garbage
+ * collector so ignore it.
+ */
+ Py_XDECREF(sref);
+ return 0;
+ }
+ else
+ {
+ sfunc = slot -> pyobj;
+ newmeth = NULL;
+ }
+
+ /*
+ * We make repeated attempts to call a slot. If we work out that it failed
+ * because of an immediate type error we try again with one less argument.
+ * We keep going until we run out of arguments to drop. This emulates the
+ * Qt ability of the slot to accept fewer arguments than a signal provides.
+ */
+ sa = sigargs;
+ Py_INCREF(sa);
+
+ for (;;)
+ {
+ PyObject *nsa, *xtype, *xvalue, *xtb, *resobj;
+
+ if ((resobj = PyEval_CallObject(sfunc,sa)) != NULL)
+ {
+ Py_DECREF(resobj);
+
+ Py_XDECREF(newmeth);
+ Py_XDECREF(sref);
+
+ /* Remove any previous exception. */
+
+ if (sa != sigargs)
+ {
+ Py_XDECREF(oxtype);
+ Py_XDECREF(oxvalue);
+ Py_XDECREF(oxtb);
+ PyErr_Clear();
+ }
+
+ Py_DECREF(sa);
+
+ return 0;
+ }
+
+ /* Get the exception. */
+ PyErr_Fetch(&xtype,&xvalue,&xtb);
+
+ /*
+ * See if it is unacceptable. An acceptable failure is a type error
+ * with no traceback - so long as we can still reduce the number of
+ * arguments and try again.
+ */
+ if (!PyErr_GivenExceptionMatches(xtype,PyExc_TypeError) ||
+ xtb != NULL ||
+ PyTuple_GET_SIZE(sa) == 0)
+ {
+ /*
+ * If there is a traceback then we must have called the slot and
+ * the exception was later on - so report the exception as is.
+ */
+ if (xtb != NULL)
+ {
+ if (sa != sigargs)
+ {
+ Py_XDECREF(oxtype);
+ Py_XDECREF(oxvalue);
+ Py_XDECREF(oxtb);
+ }
+
+ PyErr_Restore(xtype,xvalue,xtb);
+ }
+ else if (sa == sigargs)
+ PyErr_Restore(xtype,xvalue,xtb);
+ else
+ {
+ /*
+ * Discard the latest exception and restore the original one.
+ */
+ Py_XDECREF(xtype);
+ Py_XDECREF(xvalue);
+ Py_XDECREF(xtb);
+
+ PyErr_Restore(oxtype,oxvalue,oxtb);
+ }
+
+ break;
+ }
+
+ /* If this is the first attempt, save the exception. */
+ if (sa == sigargs)
+ {
+ oxtype = xtype;
+ oxvalue = xvalue;
+ oxtb = xtb;
+ }
+ else
+ {
+ Py_XDECREF(xtype);
+ Py_XDECREF(xvalue);
+ Py_XDECREF(xtb);
+ }
+
+ /* Create the new argument tuple. */
+ if ((nsa = PyTuple_GetSlice(sa,0,PyTuple_GET_SIZE(sa) - 1)) == NULL)
+ {
+ /* Tidy up. */
+ Py_XDECREF(oxtype);
+ Py_XDECREF(oxvalue);
+ Py_XDECREF(oxtb);
+
+ break;
+ }
+
+ Py_DECREF(sa);
+ sa = nsa;
+ }
+
+ Py_XDECREF(newmeth);
+ Py_XDECREF(sref);
+
+ Py_DECREF(sa);
+
+ return -1;
+}
+
+
+/*
+ * Send a signal to the slots (Qt or Python) in a Python list.
+ */
+static int emitToSlotList(sipSlotList *rxlist,PyObject *sigargs)
+{
+ int rc;
+
+ /* Apply the arguments to each slot method. */
+ rc = 0;
+
+ while (rxlist != NULL && rc >= 0)
+ {
+ sipSlotList *next;
+
+ /*
+ * We get the next in the list before calling the slot in case the list
+ * gets changed by the slot - usually because the slot disconnects
+ * itself.
+ */
+ next = rxlist -> next;
+ rc = sip_api_emit_to_slot(&rxlist -> rx, sigargs);
+ rxlist = next;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Add a slot to a transmitter's Python signal list. The signal is a Python
+ * signal, the slot may be either a Qt signal, a Qt slot, a Python signal or a
+ * Python slot.
+ */
+static int addSlotToPySigList(sipWrapper *txSelf,const char *sig,
+ PyObject *rxObj,const char *slot)
+{
+ sipPySig *ps;
+ sipSlotList *psrx;
+
+ /* Create a new one if necessary. */
+ if ((ps = findPySignal(txSelf,sig)) == NULL)
+ {
+ if ((ps = (sipPySig *)sip_api_malloc(sizeof (sipPySig))) == NULL)
+ return -1;
+
+ if ((ps -> name = sipStrdup(sig)) == NULL)
+ {
+ sip_api_free(ps);
+ return -1;
+ }
+
+ ps -> rxlist = NULL;
+ ps -> next = txSelf -> pySigList;
+
+ txSelf -> pySigList = ps;
+ }
+
+ /* Create the new receiver. */
+ if ((psrx = (sipSlotList *)sip_api_malloc(sizeof (sipSlotList))) == NULL)
+ return -1;
+
+ if (saveSlot(&psrx->rx, rxObj, slot) < 0)
+ {
+ sip_api_free(psrx);
+ return -1;
+ }
+
+ psrx -> next = ps -> rxlist;
+ ps -> rxlist = psrx;
+
+ return 0;
+}
+
+
+/*
+ * Compare two slots to see if they are the same.
+ */
+static int isSameSlot(sipSlot *slot1,PyObject *rxobj2,const char *slot2)
+{
+ /* See if they are signals or Qt slots, ie. they have a name. */
+ if (slot1 -> name != NULL)
+ return (slot2 != NULL &&
+ sipQtSupport->qt_same_name(slot1 -> name,slot2) &&
+ slot1 -> pyobj == rxobj2);
+
+ /* Both must be Python slots. */
+ if (slot2 != NULL)
+ return 0;
+
+ /* See if they are Python methods. */
+ if (slot1 -> pyobj == NULL)
+ return (PyMethod_Check(rxobj2) &&
+ slot1 -> meth.mfunc == PyMethod_GET_FUNCTION(rxobj2) &&
+ slot1 -> meth.mself == PyMethod_GET_SELF(rxobj2) &&
+ slot1 -> meth.mclass == PyMethod_GET_CLASS(rxobj2));
+
+ if (PyMethod_Check(rxobj2))
+ return 0;
+
+ /* The objects must be the same. */
+ return (slot1 -> pyobj == rxobj2);
+}
+
+
+/*
+ * Convert a valid Python signal or slot to an existing universal slot.
+ */
+void *sipGetRx(sipWrapper *txSelf,const char *sigargs,PyObject *rxObj,
+ const char *slot,const char **memberp)
+{
+ if (slot != NULL)
+ if (isQtSlot(slot) || isQtSignal(slot))
+ {
+ void *rx;
+
+ *memberp = slot;
+
+ if ((rx = sip_api_get_cpp_ptr((sipWrapper *)rxObj, sipQObjectClass)) == NULL)
+ return NULL;
+
+ if (isQtSignal(slot))
+ rx = findSignal(rx, memberp);
+
+ return rx;
+ }
+
+ /*
+ * The slot was either a Python callable or PyQt3 Python signal so there
+ * should be a universal slot.
+ */
+ return sipQtSupport->qt_find_slot(sipGetAddress(txSelf), sigargs, rxObj, slot, memberp);
+}
+
+
+/*
+ * Convert a Python receiver (either a Python signal or slot or a Qt signal or
+ * slot) to a Qt receiver. It is only ever called when the signal is a Qt
+ * signal. Return NULL is there was an error.
+ */
+void *sip_api_convert_rx(sipWrapper *txSelf,const char *sig,PyObject *rxObj,
+ const char *slot,const char **memberp)
+{
+ if (slot == NULL)
+ return createUniversalSlot(txSelf, sig, rxObj, NULL, memberp);
+
+ if (isQtSlot(slot) || isQtSignal(slot))
+ {
+ void *rx;
+
+ *memberp = slot;
+
+ if ((rx = sip_api_get_cpp_ptr((sipWrapper *)rxObj, sipQObjectClass)) == NULL)
+ return NULL;
+
+ if (isQtSignal(slot))
+ rx = newSignal(rx, memberp);
+
+ return rx;
+ }
+
+ /* The slot is a Python signal so we need a universal slot to catch it. */
+ return createUniversalSlot(txSelf, sig, rxObj, slot, memberp);
+}
+
+
+/*
+ * Connect a Qt signal or a Python signal to a Qt slot, a Qt signal, a Python
+ * slot or a Python signal. This is all possible combinations.
+ */
+PyObject *sip_api_connect_rx(PyObject *txObj,const char *sig,PyObject *rxObj,
+ const char *slot, int type)
+{
+ sipWrapper *txSelf = (sipWrapper *)txObj;
+
+ /* Handle Qt signals. */
+ if (isQtSignal(sig))
+ {
+ void *tx, *rx;
+ const char *member, *real_sig;
+ int res;
+
+ if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectClass)) == NULL)
+ return NULL;
+
+ real_sig = sig;
+
+ if ((tx = newSignal(tx, &real_sig)) == NULL)
+ return NULL;
+
+ if ((rx = sip_api_convert_rx(txSelf, sig, rxObj, slot, &member)) == NULL)
+ return NULL;
+
+ res = sipQtSupport->qt_connect(tx, real_sig, rx, member, type);
+
+ return PyBool_FromLong(res);
+ }
+
+ /* Handle Python signals. */
+ if (addSlotToPySigList(txSelf, sig, rxObj, slot) < 0)
+ return NULL;
+
+ Py_INCREF(Py_True);
+ return Py_True;
+}
+
+
+/*
+ * Disconnect a signal to a signal or a Qt slot.
+ */
+PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig,
+ PyObject *rxObj,const char *slot)
+{
+ sipWrapper *txSelf = (sipWrapper *)txObj;
+
+ /* Handle Qt signals. */
+ if (isQtSignal(sig))
+ {
+ void *tx, *rx;
+ const char *member;
+ int res;
+
+ if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectClass)) == NULL)
+ return NULL;
+
+ if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL)
+ {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+
+ /* Handle Python signals. */
+ tx = findSignal(tx, &sig);
+
+ res = sipQtSupport->qt_disconnect(tx, sig, rx, member);
+
+ /*
+ * Delete it if it is a universal slot as this will be it's only
+ * connection. If the slot is actually a universal signal then it
+ * should leave it in place.
+ */
+ sipQtSupport->qt_destroy_universal_slot(rx);
+
+ return PyBool_FromLong(res);
+ }
+
+ /* Handle Python signals. */
+ removeSlotFromPySigList(txSelf,sig,rxObj,slot);
+
+ Py_INCREF(Py_True);
+ return Py_True;
+}
+
+
+/*
+ * Remove a slot from a transmitter's Python signal list.
+ */
+static void removeSlotFromPySigList(sipWrapper *txSelf,const char *sig,
+ PyObject *rxObj,const char *slot)
+{
+ sipPySig *ps;
+
+ if ((ps = findPySignal(txSelf,sig)) != NULL)
+ {
+ sipSlotList **psrxp;
+
+ for (psrxp = &ps -> rxlist; *psrxp != NULL; psrxp = &(*psrxp) -> next)
+ {
+ sipSlotList *psrx = *psrxp;
+
+ if (isSameSlot(&psrx -> rx,rxObj,slot))
+ {
+ *psrxp = psrx -> next;
+ sipFreeSlotList(psrx);
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * Free a sipSlot structure.
+ */
+static void freeSlot(sipSlot *slot)
+{
+ if (slot->name != NULL)
+ sip_api_free(slot->name);
+ else
+ {
+ PyObject *lam = slot->pyobj;
+
+ if (lam != NULL && (lam == Py_None || sipLambdaSlot(lam)))
+ Py_DECREF(lam);
+ }
+
+ /* Remove any weak reference. */
+ Py_XDECREF(slot->weakSlot);
+}
+
+
+/*
+ * Free a sipSlotList structure on the heap.
+ */
+void sipFreeSlotList(sipSlotList *rx)
+{
+ freeSlot(&rx->rx);
+ sip_api_free(rx);
+}
+
+
+/*
+ * Implement strdup() using sip_api_malloc().
+ */
+static char *sipStrdup(const char *s)
+{
+ char *d;
+
+ if ((d = (char *)sip_api_malloc(strlen(s) + 1)) != NULL)
+ strcpy(d,s);
+
+ return d;
+}
+
+
+/*
+ * Initialise a slot, returning 0 if there was no error. If the signal was a
+ * Qt signal, then the slot may be a Python signal or a Python slot. If the
+ * signal was a Python signal, then the slot may be anything.
+ */
+static int saveSlot(sipSlot *sp, PyObject *rxObj, const char *slot)
+{
+ sp -> weakSlot = NULL;
+
+ if (slot == NULL)
+ {
+ sp -> name = NULL;
+
+ if (PyMethod_Check(rxObj))
+ {
+ /*
+ * Python creates methods on the fly. We could increment the
+ * reference count to keep it alive, but that would keep "self"
+ * alive as well and would probably be a circular reference.
+ * Instead we remember the component parts and hope they are still
+ * valid when we re-create the method when we need it.
+ */
+ sipSaveMethod(&sp -> meth,rxObj);
+
+ /* Notice if the class instance disappears. */
+ sp -> weakSlot = getWeakRef(sp -> meth.mself);
+
+ /* This acts a flag to say that the slot is a method. */
+ sp -> pyobj = NULL;
+ }
+ else
+ {
+ PyObject *self;
+
+ /*
+ * We know that it is another type of callable, ie. a
+ * function/builtin.
+ */
+
+ if (PyCFunction_Check(rxObj) &&
+ (self = PyCFunction_GET_SELF(rxObj)) != NULL &&
+ sip_api_wrapper_check(self))
+ {
+ /*
+ * It is a wrapped C++ class method. We can't keep a copy
+ * because they are generated on the fly and we can't take a
+ * reference as that may keep the instance (ie. self) alive.
+ * We therefore treat it as if the user had specified the slot
+ * at "obj, SLOT('meth()')" rather than "obj.meth" (see below).
+ */
+
+ const char *meth;
+
+ /* Get the method name. */
+ meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name;
+
+ if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL)
+ return -1;
+
+ /*
+ * Copy the name and set the marker that it needs converting to
+ * a built-in method.
+ */
+ sp -> name[0] = '\0';
+ strcpy(&sp -> name[1],meth);
+
+ sp -> pyobj = self;
+ sp -> weakSlot = getWeakRef(self);
+ }
+ else
+ {
+ /*
+ * A bit of a hack to allow lamba functions to be used as
+ * slots.
+ */
+ if (sipLambdaSlot(rxObj))
+ Py_INCREF(rxObj);
+
+ /*
+ * It's unlikely that we will succeed in getting a weak
+ * reference to the slot, but there is no harm in trying (and
+ * future versions of Python may support references to more
+ * object types).
+ */
+ sp -> pyobj = rxObj;
+ sp -> weakSlot = getWeakRef(rxObj);
+ }
+ }
+ }
+ else if ((sp -> name = sipStrdup(slot)) == NULL)
+ return -1;
+ else if (isQtSlot(slot))
+ {
+ /*
+ * The user has decided to connect a Python signal to a Qt slot and
+ * specified the slot as "obj, SLOT('meth()')" rather than "obj.meth".
+ */
+
+ char *tail;
+
+ /* Remove any arguments. */
+ if ((tail = strchr(sp -> name,'(')) != NULL)
+ *tail = '\0';
+
+ /*
+ * A bit of a hack to indicate that this needs converting to a built-in
+ * method.
+ */
+ sp -> name[0] = '\0';
+
+ /* Notice if the class instance disappears. */
+ sp -> weakSlot = getWeakRef(rxObj);
+
+ sp -> pyobj = rxObj;
+ }
+ else
+ /* It's a Qt signal. */
+ sp -> pyobj = rxObj;
+
+ return 0;
+}
+
+
+/*
+ * Return a weak reference to the given object.
+ */
+static PyObject *getWeakRef(PyObject *obj)
+{
+ PyObject *wr;
+
+ if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL)
+ PyErr_Clear();
+
+ return wr;
+}
+
+
+/*
+ * See if an object is a lambda function.
+ */
+int sipLambdaSlot(PyObject *slotObj)
+{
+ if (!PyFunction_Check(slotObj))
+ return FALSE;
+
+ return (strcmp(PyString_AsString(((PyFunctionObject *)slotObj)->func_name), "<lambda>") == 0);
+}
diff --git a/python/sip/siplib/sip.h b/python/sip/siplib/sip.h
new file mode 100644
index 00000000..d08a913d
--- /dev/null
+++ b/python/sip/siplib/sip.h
@@ -0,0 +1,1302 @@
+/*
+ * The SIP module interface.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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.
+ */
+
+
+#ifndef _SIP_H
+#define _SIP_H
+
+
+/*
+ * This gets round a problem with Qt's moc and Python v2.3. Strictly speaking
+ * it's a Qt problem but later versions of Python include a fix for it so we
+ * might as well too.
+ */
+#undef slots
+
+
+#include <Python.h>
+
+/*
+ * There is a mis-feature somewhere with the Borland compiler. This works
+ * around it.
+ */
+#if defined(__BORLANDC__)
+#include <rpc.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Sanity check on the Python version. */
+#if PY_VERSION_HEX < 0x02030000
+#error "This version of SIP requires Python v2.3 or later"
+#endif
+
+
+/*
+ * Define the SIP version number.
+ */
+#define SIP_VERSION 0x040600
+#define SIP_VERSION_STR "4.6"
+
+
+/*
+ * Define the current API version number. SIP must handle modules with the
+ * same major number and with the same or earlier minor number. Whenever data
+ * structure elements are added they must be appended and the minor number
+ * incremented. Whenever data structure elements are removed or the order
+ * changed then the major number must be incremented and the minor number set
+ * to 0.
+ *
+ * History:
+ *
+ * 3.4 Added qt_find_connection() to the Qt support API.
+ * Added sip_api_string_as_char(), sip_api_unicode_as_wchar(),
+ * sip_api_unicode_as_wstring(), sip_api_find_class(),
+ * sip_api_find_named_enum() and sip_api_parse_signature().
+ * Added the 'A', 'w' and 'x' format characters to sip_api_parse_args(),
+ * sip_api_parse_result(), sip_api_build_result() and
+ * sip_api_call_method().
+ *
+ * 3.3 Added sip_api_register_int_types().
+ *
+ * 3.2 Added sip_api_export_symbol() and sip_api_import_symbol().
+ *
+ * 3.1 Added sip_api_add_mapped_type_instance().
+ *
+ * 3.0 Moved the Qt support out of the sip module and into PyQt. This is
+ * such a dramatic change that there is no point in attempting to maintain
+ * backwards compatibility.
+ *
+ * 2.0 Added the td_flags field to the sipTypeDef structure.
+ * Added the first_child, sibling_next, sibling_prev and parent fields to
+ * the sipWrapper structure.
+ * Added the td_traverse and td_clear fields to the sipTypeDef structure.
+ * Added the em_api_minor field to the sipExportedModuleDef structure.
+ * Added sip_api_bad_operator_arg().
+ * Added sip_api_wrapper_check().
+ *
+ * 1.1 Added support for __pos__ and __abs__.
+ *
+ * 1.0 Removed all deprecated parts of the API.
+ * Removed the td_proxy field from the sipTypeDef structure.
+ * Removed the create proxy function from the 'q' and 'y' format
+ * characters to sip_api_parse_args().
+ * Removed sip_api_emit_to_slot().
+ * Reworked the enum related structures.
+ *
+ * 0.2 Added the 'H' format character to sip_api_parse_args().
+ *
+ * 0.1 Added sip_api_add_class_instance().
+ * Added the 't' format character to sip_api_parse_args().
+ * Deprecated the 'J' and 'K' format characters to sip_api_parse_result().
+ *
+ * 0.0 Original version.
+ */
+#define SIP_API_MAJOR_NR 3
+#define SIP_API_MINOR_NR 4
+
+
+/* Some compatibility stuff to help with handwritten code for SIP v3. */
+#if !defined(ANY)
+#define ANY void
+#endif
+
+
+/* Some Python compatibility stuff. */
+#if PY_VERSION_HEX >= 0x02050000
+#define SIP_SSIZE_T Py_ssize_t
+#else
+#define SIP_SSIZE_T int
+#endif
+
+
+/*
+ * The mask that can be passed to sipTrace().
+ */
+#define SIP_TRACE_CATCHERS 0x0001
+#define SIP_TRACE_CTORS 0x0002
+#define SIP_TRACE_DTORS 0x0004
+#define SIP_TRACE_INITS 0x0008
+#define SIP_TRACE_DEALLOCS 0x0010
+#define SIP_TRACE_METHODS 0x0020
+
+
+/*
+ * Hide some thread dependent stuff.
+ */
+#ifdef WITH_THREAD
+typedef PyGILState_STATE sip_gilstate_t;
+#define SIP_RELEASE_GIL(gs) PyGILState_Release(gs);
+#define SIP_BLOCK_THREADS {PyGILState_STATE sipGIL = PyGILState_Ensure();
+#define SIP_UNBLOCK_THREADS PyGILState_Release(sipGIL);}
+#else
+typedef int sip_gilstate_t;
+#define SIP_RELEASE_GIL(gs)
+#define SIP_BLOCK_THREADS
+#define SIP_UNBLOCK_THREADS
+#endif
+
+
+/*
+ * The metatype of a wrapper type.
+ */
+typedef struct _sipWrapperType {
+ /*
+ * The super-metatype. This must be first in the structure so that it can
+ * be cast to a PyTypeObject *.
+ */
+ PyHeapTypeObject super;
+
+ /* The additional type information. */
+ struct _sipTypeDef *type;
+
+ /* The list of init extenders. */
+ struct _sipInitExtenderDef *iextend;
+
+ /* The optional PyQt defined Q_OBJECT information. */
+ void *qt_qobject;
+} sipWrapperType;
+
+
+/*
+ * The type of a C/C++ wrapper object.
+ */
+typedef struct _sipWrapper {
+ PyObject_HEAD
+
+ /* For the user to use. */
+ PyObject *user;
+
+ union {
+ /* C/C++ object pointer. */
+ void *cppPtr;
+
+ /* Access function. */
+ void *(*afPtr)();
+ } u;
+
+ /* Object flags. */
+ int flags;
+
+ /* The instance dictionary. */
+ PyObject *dict;
+
+ /* Python signal list (complex). */
+ struct _sipPySig *pySigList;
+
+ /* Next object at this address. */
+ struct _sipWrapper *next;
+
+ /* First child object. */
+ struct _sipWrapper *first_child;
+
+ /* Next sibling. */
+ struct _sipWrapper *sibling_next;
+
+ /* Previous sibling. */
+ struct _sipWrapper *sibling_prev;
+
+ /* Owning object. */
+ struct _sipWrapper *parent;
+} sipWrapper;
+
+
+/*
+ * Some convenient function pointers.
+ */
+typedef void *(*sipInitFunc)(sipWrapper *, PyObject *, sipWrapper **, int *);
+typedef int (*sipTraverseFunc)(void *, visitproc, void *);
+typedef int (*sipClearFunc)(void *);
+typedef SIP_SSIZE_T (*sipBufferFunc)(PyObject *, void *, SIP_SSIZE_T, void **);
+typedef SIP_SSIZE_T (*sipSegCountFunc)(PyObject *, void *, SIP_SSIZE_T *);
+typedef void (*sipDeallocFunc)(sipWrapper *);
+typedef void *(*sipCastFunc)(void *, sipWrapperType *);
+typedef sipWrapperType *(*sipSubClassConvertFunc)(void **);
+typedef void *(*sipForceConvertToFunc)(PyObject *, int *);
+typedef int (*sipConvertToFunc)(PyObject *, void **, int *, PyObject *);
+typedef PyObject *(*sipConvertFromFunc)(void *, PyObject *);
+typedef int (*sipVirtHandlerFunc)(void *, PyObject *, ...);
+typedef int (*sipEmitFunc)(sipWrapper *, PyObject *);
+typedef void (*sipReleaseFunc)(void *, int);
+
+
+/*
+ * The information describing an encoded class ID.
+ */
+typedef struct _sipEncodedClassDef {
+ /* The class number. */
+ unsigned sc_class:16;
+
+ /* The module number (255 for this one). */
+ unsigned sc_module:8;
+
+ /* A context specific flag. */
+ unsigned sc_flag:1;
+} sipEncodedClassDef;
+
+
+/*
+ * The information describing an enum member.
+ */
+typedef struct _sipEnumMemberDef {
+ /* The member name. */
+ const char *em_name;
+
+ /* The member value. */
+ int em_val;
+
+ /* The member enum, -ve if anonymous. */
+ int em_enum;
+} sipEnumMemberDef;
+
+
+/*
+ * The information describing a named enum.
+ */
+typedef struct _sipEnumDef {
+ /* The Python name of the enum. */
+ const char *e_name;
+
+ /* The C/C++ name of the enum, NULL if the same as the Python name. */
+ const char *e_cname;
+
+ /* The scoping type. */
+ int e_scope;
+
+ /* The Python slots. */
+ struct _sipPySlotDef *e_pyslots;
+} sipEnumDef;
+
+
+/*
+ * The information describing static instances.
+ */
+typedef struct _sipInstancesDef {
+ /* The classes. */
+ struct _sipClassInstanceDef *id_class;
+
+ /* The void *. */
+ struct _sipVoidPtrInstanceDef *id_voidp;
+
+ /* The chars. */
+ struct _sipCharInstanceDef *id_char;
+
+ /* The strings. */
+ struct _sipStringInstanceDef *id_string;
+
+ /* The ints. */
+ struct _sipIntInstanceDef *id_int;
+
+ /* The longs. */
+ struct _sipLongInstanceDef *id_long;
+
+ /* The unsigned longs. */
+ struct _sipUnsignedLongInstanceDef *id_ulong;
+
+ /* The long longs. */
+ struct _sipLongLongInstanceDef *id_llong;
+
+ /* The unsigned long longs. */
+ struct _sipUnsignedLongLongInstanceDef *id_ullong;
+
+ /* The doubles. */
+ struct _sipDoubleInstanceDef *id_double;
+
+ /* The enums. */
+ struct _sipEnumInstanceDef *id_enum;
+} sipInstancesDef;
+
+
+/*
+ * The information describing a type initialiser extender.
+ */
+typedef struct _sipInitExtenderDef {
+ /* The extender function. */
+ sipInitFunc ie_extender;
+
+ /* The class being extended. */
+ sipEncodedClassDef ie_class;
+
+ /* The next extender for this class. */
+ struct _sipInitExtenderDef *ie_next;
+} sipInitExtenderDef;
+
+
+/*
+ * The information describing a sub-class convertor.
+ */
+typedef struct _sipSubClassConvertorDef {
+ /* The convertor. */
+ sipSubClassConvertFunc scc_convertor;
+
+ /* The encoded base type. */
+ sipEncodedClassDef scc_base;
+
+ /* The base type. */
+ sipWrapperType *scc_basetype;
+} sipSubClassConvertorDef;
+
+
+/*
+ * The different Python slot types.
+ */
+typedef enum {
+ str_slot, /* __str__ */
+ int_slot, /* __int__ */
+ long_slot, /* __long__ */
+ float_slot, /* __float__ */
+ len_slot, /* __len__ */
+ contains_slot, /* __contains__ */
+ add_slot, /* __add__ for number */
+ concat_slot, /* __add__ for sequence types */
+ sub_slot, /* __sub__ */
+ mul_slot, /* __mul__ for number types */
+ repeat_slot, /* __mul__ for sequence types */
+ div_slot, /* __div__ */
+ mod_slot, /* __mod__ */
+ and_slot, /* __and__ */
+ or_slot, /* __or__ */
+ xor_slot, /* __xor__ */
+ lshift_slot, /* __lshift__ */
+ rshift_slot, /* __rshift__ */
+ iadd_slot, /* __iadd__ for number types */
+ iconcat_slot, /* __iadd__ for sequence types */
+ isub_slot, /* __isub__ */
+ imul_slot, /* __imul__ for number types */
+ irepeat_slot, /* __imul__ for sequence types */
+ idiv_slot, /* __idiv__ */
+ imod_slot, /* __imod__ */
+ iand_slot, /* __iand__ */
+ ior_slot, /* __ior__ */
+ ixor_slot, /* __ixor__ */
+ ilshift_slot, /* __ilshift__ */
+ irshift_slot, /* __irshift__ */
+ invert_slot, /* __invert__ */
+ call_slot, /* __call__ */
+ getitem_slot, /* __getitem__ */
+ setitem_slot, /* __setitem__ */
+ delitem_slot, /* __delitem__ */
+ lt_slot, /* __lt__ */
+ le_slot, /* __le__ */
+ eq_slot, /* __eq__ */
+ ne_slot, /* __ne__ */
+ gt_slot, /* __gt__ */
+ ge_slot, /* __ge__ */
+ cmp_slot, /* __cmp__ */
+ nonzero_slot, /* __nonzero__ */
+ neg_slot, /* __neg__ */
+ repr_slot, /* __repr__ */
+ hash_slot, /* __hash__ */
+ pos_slot, /* __pos__ */
+ abs_slot /* __abs__ */
+} sipPySlotType;
+
+
+/*
+ * The information describing a Python slot function.
+ */
+typedef struct _sipPySlotDef {
+ /* The function. */
+ void *psd_func;
+
+ /* The type. */
+ sipPySlotType psd_type;
+} sipPySlotDef;
+
+
+/*
+ * The information describing a Python slot extender.
+ */
+typedef struct _sipPySlotExtenderDef {
+ /* The function. */
+ void *pse_func;
+
+ /* The type. */
+ sipPySlotType pse_type;
+
+ /* The encoded class. */
+ sipEncodedClassDef pse_class;
+} sipPySlotExtenderDef;
+
+
+/*
+ * This enumerates the different dynamic signal argument types.
+ */
+typedef enum {
+ unknown_sat,
+ char_sat,
+ uchar_sat,
+ string_sat,
+ ustring_sat,
+ short_sat,
+ ushort_sat,
+ int_sat,
+ uint_sat,
+ long_sat,
+ ulong_sat,
+ longlong_sat,
+ ulonglong_sat,
+ float_sat,
+ double_sat,
+ enum_sat,
+ bool_sat,
+ void_sat,
+ class_sat,
+ classp_sat,
+ mtype_sat,
+ mtypep_sat,
+ qvariant_sat,
+ qvariantp_sat,
+ pyobject_sat,
+ schar_sat,
+ sstring_sat,
+ wchar_sat,
+ wstring_sat
+} sipSigArgType;
+
+
+/*
+ * The information describing a typedef.
+ */
+typedef struct _sipTypedefDef {
+ /* The typedef name. */
+ const char *tdd_name;
+
+ /* The typedef type. */
+ sipSigArgType tdd_type;
+
+ /* The type name for enum_sat, class_sat and mtype_sat. */
+ const char *tdd_type_name;
+
+ /* The defining module, NULL if the current one. */
+ const char *tdd_mod_name;
+} sipTypedefDef;
+
+
+/*
+ * The information describing a type.
+ */
+typedef struct _sipTypeDef {
+ /* The module. */
+ struct _sipExportedModuleDef *td_module;
+
+ /* Type flags, see the sipType*() macros. */
+ int td_flags;
+
+ /* The Python name of the type. */
+ const char *td_name;
+
+ /* The C/C++ name of the type, NULL if the same as the Python name. */
+ const char *td_cname;
+
+ /* The scoping type. */
+ sipEncodedClassDef td_scope;
+
+ /* The super-types. */
+ sipEncodedClassDef *td_supers;
+
+ /* The table of Python slots. */
+ sipPySlotDef *td_pyslots;
+
+ /* The number of lazy methods. */
+ int td_nrmethods;
+
+ /* The table of lazy methods. */
+ PyMethodDef *td_methods;
+
+ /* The number of lazy enum members. */
+ int td_nrenummembers;
+
+ /* The table of lazy enum members. */
+ sipEnumMemberDef *td_enummembers;
+
+ /* The variable table. */
+ PyMethodDef *td_variables;
+
+ /* The initialisation function. */
+ sipInitFunc td_init;
+
+ /* The traverse function. */
+ sipTraverseFunc td_traverse;
+
+ /* The clear function. */
+ sipClearFunc td_clear;
+
+ /* The read buffer function. */
+ sipBufferFunc td_readbuffer;
+
+ /* The write buffer function. */
+ sipBufferFunc td_writebuffer;
+
+ /* The segment count function. */
+ sipSegCountFunc td_segcount;
+
+ /* The char buffer function. */
+ sipBufferFunc td_charbuffer;
+
+ /* The deallocation function. */
+ sipDeallocFunc td_dealloc;
+
+ /* The cast function, 0 if a C struct. */
+ sipCastFunc td_cast;
+
+ /* The release function. */
+ sipReleaseFunc td_release;
+
+ /* The force convert to function, 0 if a C++ namespace. */
+ sipForceConvertToFunc td_fcto;
+
+ /* The convert to function. */
+ sipConvertToFunc td_cto;
+
+ /* Emit table for Qt signals. */
+ struct _sipQtSignal *td_emit;
+
+ /* The static instances. */
+ sipInstancesDef td_instances;
+
+ /* The next namespace extender. */
+ struct _sipTypeDef *td_nsextender;
+} sipTypeDef;
+
+
+/*
+ * The information describing an external type.
+ */
+typedef struct _sipExternalTypeDef {
+ /* The index into the type table. */
+ int et_nr;
+
+ /* The name of the type. */
+ const char *et_name;
+} sipExternalTypeDef;
+
+
+/*
+ * The information describing a mapped class.
+ */
+typedef struct _sipMappedType {
+ /* The corresponding C++ definition. */
+ const char *mt_name;
+
+ /* The release function. */
+ sipReleaseFunc mt_release;
+
+ /* The force convert to function. */
+ sipForceConvertToFunc mt_fcto;
+
+ /* The convert to function. */
+ sipConvertToFunc mt_cto;
+
+ /* The convert from function. */
+ sipConvertFromFunc mt_cfrom;
+} sipMappedType;
+
+
+/*
+ * Defines an entry in the module specific list of delayed dtor calls.
+ */
+typedef struct _sipDelayedDtor {
+ /* The C/C++ instance. */
+ void *dd_ptr;
+
+ /* The class name. */
+ const char *dd_name;
+
+ /* Non-zero if dd_ptr is a derived class instance. */
+ int dd_isderived;
+
+ /* Next in the list. */
+ struct _sipDelayedDtor *dd_next;
+} sipDelayedDtor;
+
+
+/*
+ * The information describing an imported module.
+ */
+typedef struct _sipImportedModuleDef {
+ /* The module name. */
+ const char *im_name;
+
+ /* The required version. */
+ int im_version;
+
+ /* The imported module. */
+ struct _sipExportedModuleDef *im_module;
+} sipImportedModuleDef;
+
+
+/*
+ * The main client module structure.
+ */
+typedef struct _sipExportedModuleDef {
+ /* The next in the list. */
+ struct _sipExportedModuleDef *em_next;
+
+ /* The SIP API minor version number. */
+ unsigned em_api_minor;
+
+ /* The module name. */
+ const char *em_name;
+
+ /* The module name as an object. */
+ PyObject *em_nameobj;
+
+ /* The module version. */
+ int em_version;
+
+ /* The imported modules. */
+ sipImportedModuleDef *em_imports;
+
+ /* The optional Qt support API. */
+ struct _sipQtAPI *em_qt_api;
+
+ /* The number of types. */
+ int em_nrtypes;
+
+ /* The table of type types. */
+ struct _sipWrapperType **em_types;
+
+ /* The table of external types. */
+ sipExternalTypeDef *em_external;
+
+ /* The table of mapped types. */
+ sipMappedType **em_mappedtypes;
+
+ /* The number of enums. */
+ int em_nrenums;
+
+ /* The table of enum types. */
+ PyTypeObject **em_enums;
+
+ /* The table of enum type data. */
+ sipEnumDef *em_enumdefs;
+
+ /* The number of members in global enums. */
+ int em_nrenummembers;
+
+ /* The table of members in global enums. */
+ sipEnumMemberDef *em_enummembers;
+
+ /* The table of typedefs. */
+ sipTypedefDef *em_typedefs;
+
+ /* The table of virtual handlers. */
+ sipVirtHandlerFunc *em_virthandlers;
+
+ /* The sub-class convertors. */
+ sipSubClassConvertorDef *em_convertors;
+
+ /* The static instances. */
+ sipInstancesDef em_instances;
+
+ /* The license. */
+ struct _sipLicenseDef *em_license;
+
+ /* The table of exception types. */
+ PyObject **em_exceptions;
+
+ /* The table of Python slot extenders. */
+ sipPySlotExtenderDef *em_slotextend;
+
+ /* The table of initialiser extenders. */
+ sipInitExtenderDef *em_initextend;
+
+ /* The delayed dtor handler. */
+ void (*em_delayeddtors)(const sipDelayedDtor *);
+
+ /* The list of delayed dtors. */
+ sipDelayedDtor *em_ddlist;
+} sipExportedModuleDef;
+
+
+/*
+ * The information describing a license to be added to a dictionary.
+ */
+typedef struct _sipLicenseDef {
+ /* The type of license. */
+ const char *lc_type;
+
+ /* The licensee. */
+ const char *lc_licensee;
+
+ /* The timestamp. */
+ const char *lc_timestamp;
+
+ /* The signature. */
+ const char *lc_signature;
+} sipLicenseDef;
+
+
+/*
+ * The information describing a void pointer instance to be added to a
+ * dictionary.
+ */
+typedef struct _sipVoidPtrInstanceDef {
+ /* The void pointer name. */
+ const char *vi_name;
+
+ /* The void pointer value. */
+ void *vi_val;
+} sipVoidPtrInstanceDef;
+
+
+/*
+ * The information describing a char instance to be added to a dictionary.
+ */
+typedef struct _sipCharInstanceDef {
+ /* The char name. */
+ const char *ci_name;
+
+ /* The char value. */
+ char ci_val;
+} sipCharInstanceDef;
+
+
+/*
+ * The information describing a string instance to be added to a dictionary.
+ */
+typedef struct _sipStringInstanceDef {
+ /* The string name. */
+ const char *si_name;
+
+ /* The string value. */
+ const char *si_val;
+} sipStringInstanceDef;
+
+
+/*
+ * The information describing an int instance to be added to a dictionary.
+ */
+typedef struct _sipIntInstanceDef {
+ /* The int name. */
+ const char *ii_name;
+
+ /* The int value. */
+ int ii_val;
+} sipIntInstanceDef;
+
+
+/*
+ * The information describing a long instance to be added to a dictionary.
+ */
+typedef struct _sipLongInstanceDef {
+ /* The long name. */
+ const char *li_name;
+
+ /* The long value. */
+ long li_val;
+} sipLongInstanceDef;
+
+
+/*
+ * The information describing an unsigned long instance to be added to a
+ * dictionary.
+ */
+typedef struct _sipUnsignedLongInstanceDef {
+ /* The unsigned long name. */
+ const char *uli_name;
+
+ /* The unsigned long value. */
+ unsigned long uli_val;
+} sipUnsignedLongInstanceDef;
+
+
+/*
+ * The information describing a long long instance to be added to a dictionary.
+ */
+typedef struct _sipLongLongInstanceDef {
+ /* The long long name. */
+ const char *lli_name;
+
+ /* The long long value. */
+#if defined(HAVE_LONG_LONG)
+ PY_LONG_LONG lli_val;
+#else
+ long lli_val;
+#endif
+} sipLongLongInstanceDef;
+
+
+/*
+ * The information describing an unsigned long long instance to be added to a
+ * dictionary.
+ */
+typedef struct _sipUnsignedLongLongInstanceDef {
+ /* The unsigned long long name. */
+ const char *ulli_name;
+
+ /* The unsigned long long value. */
+#if defined(HAVE_LONG_LONG)
+ unsigned PY_LONG_LONG ulli_val;
+#else
+ unsigned long ulli_val;
+#endif
+} sipUnsignedLongLongInstanceDef;
+
+
+/*
+ * The information describing a double instance to be added to a dictionary.
+ */
+typedef struct _sipDoubleInstanceDef {
+ /* The double name. */
+ const char *di_name;
+
+ /* The double value. */
+ double di_val;
+} sipDoubleInstanceDef;
+
+
+/*
+ * The information describing a class instance to be added to a dictionary.
+ */
+typedef struct _sipClassInstanceDef {
+ /* The class instance name. */
+ const char *ci_name;
+
+ /* The actual instance. */
+ void *ci_ptr;
+
+ /* A pointer to the Python type. */
+ struct _sipWrapperType **ci_type;
+
+ /* The wrapping flags. */
+ int ci_flags;
+} sipClassInstanceDef;
+
+
+/*
+ * The information describing an enum instance to be added to a dictionary.
+ */
+typedef struct _sipEnumInstanceDef {
+ /* The enum instance name. */
+ const char *ei_name;
+
+ /* The enum value. */
+ int ei_val;
+
+ /* A pointer to the Python type. */
+ PyTypeObject **ei_type;
+} sipEnumInstanceDef;
+
+
+/*
+ * Define a mapping between a wrapped type identified by a string and the
+ * corresponding Python type.
+ */
+typedef struct _sipStringTypeClassMap {
+ /* The type as a string. */
+ const char *typeString;
+
+ /* A pointer to the Python type. */
+ struct _sipWrapperType **pyType;
+} sipStringTypeClassMap;
+
+
+/*
+ * Define a mapping between a wrapped type identified by an integer and the
+ * corresponding Python type.
+ */
+typedef struct _sipIntTypeClassMap {
+ /* The type as an integer. */
+ int typeInt;
+
+ /* A pointer to the Python type. */
+ struct _sipWrapperType **pyType;
+} sipIntTypeClassMap;
+
+
+/*
+ * A Python method's component parts. This allows us to re-create the method
+ * without changing the reference counts of the components.
+ */
+typedef struct _sipPyMethod {
+ /* The function. */
+ PyObject *mfunc;
+
+ /* Self if it is a bound method. */
+ PyObject *mself;
+
+ /* The class. */
+ PyObject *mclass;
+} sipPyMethod;
+
+
+/*
+ * Cache a reference to a Python member function.
+ */
+typedef struct _sipMethodCache {
+ /* Method cache flags. */
+ int mcflags;
+
+ /* The method. */
+ sipPyMethod pyMethod;
+} sipMethodCache;
+
+
+/*
+ * A slot (in the Qt, rather than Python, sense).
+ */
+typedef struct _sipSlot {
+ /* Name if a Qt or Python signal. */
+ char *name;
+
+ /* Signal or Qt slot object. */
+ PyObject *pyobj;
+
+ /* Python slot method, pyobj is NULL. */
+ sipPyMethod meth;
+
+ /* A weak reference to the slot. */
+ PyObject *weakSlot;
+} sipSlot;
+
+
+/*
+ * An entry in a linked list of slots.
+ */
+typedef struct _sipSlotList {
+ /* The receiver. */
+ sipSlot rx;
+
+ /* Next in the list. */
+ struct _sipSlotList *next;
+} sipSlotList;
+
+
+/*
+ * A Python signal.
+ */
+typedef struct _sipPySig {
+ /* The name of the signal. */
+ char *name;
+
+ /* The list of receivers. */
+ sipSlotList *rxlist;
+
+ /* Next in the list. */
+ struct _sipPySig *next;
+} sipPySig;
+
+
+/*
+ * This defines a single dynamic signal argument type.
+ */
+typedef struct _sipSigArg {
+ /* The type. */
+ sipSigArgType atype;
+
+ union {
+ /* The Python type for classes. */
+ sipWrapperType *wt;
+
+ /* The data for mapped types. */
+ sipMappedType *mt;
+
+ /* The Python type for named enums. */
+ PyTypeObject *et;
+ } u;
+} sipSigArg;
+
+
+/*
+ * A parsed signal signature.
+ */
+typedef struct _sipSignature {
+ /* The number of arguments. */
+ int sg_nrargs;
+
+ /* The parsed arguments (heap). */
+ sipSigArg *sg_args;
+
+ /* The unparsed signature (heap). */
+ char *sg_signature;
+
+ /* The next in the list. */
+ struct _sipSignature *sg_next;
+} sipSignature;
+
+
+/*
+ * A connection to a universal slot.
+ */
+typedef struct _sipSlotConnection {
+ /* The transmitter QObject. */
+ void *sc_transmitter;
+
+ /* The parsed signature. */
+ const sipSignature *sc_signature;
+
+ /* The slot. */
+ sipSlot sc_slot;
+} sipSlotConnection;
+
+
+/*
+ * Maps the name of a Qt signal to a wrapper function to emit it.
+ */
+typedef struct _sipQtSignal {
+ /* The signal name. */
+ char *st_name;
+
+ /* The emitter function. */
+ sipEmitFunc st_emitfunc;
+} sipQtSignal;
+
+
+/*
+ * The API exported by the SIP module, ie. pointers to all the data and
+ * functions that can be used by generated code.
+ */
+typedef struct _sipAPIDef {
+ /*
+ * This must be the first entry and it's signature must not change so that
+ * version number mismatches can be detected and reported.
+ */
+ int (*api_export_module)(sipExportedModuleDef *client, unsigned api_major,
+ unsigned api_minor, PyObject *mod_dict);
+
+ /*
+ * The following are part of the public API.
+ */
+ void (*api_bad_catcher_result)(PyObject *method);
+ void (*api_bad_length_for_slice)(SIP_SSIZE_T seqlen, SIP_SSIZE_T slicelen);
+ PyObject *(*api_build_result)(int *isErr, const char *fmt, ...);
+ PyObject *(*api_call_method)(int *isErr, PyObject *method, const char *fmt,
+ ...);
+ PyObject *(*api_class_name)(PyObject *self);
+ PyObject *(*api_connect_rx)(PyObject *txObj, const char *sig,
+ PyObject *rxObj, const char *slot, int type);
+ SIP_SSIZE_T (*api_convert_from_sequence_index)(SIP_SSIZE_T idx,
+ SIP_SSIZE_T len);
+ int (*api_can_convert_to_instance)(PyObject *pyObj, sipWrapperType *type,
+ int flags);
+ int (*api_can_convert_to_mapped_type)(PyObject *pyObj,
+ const sipMappedType *mt, int flags);
+ void *(*api_convert_to_instance)(PyObject *pyObj, sipWrapperType *type,
+ PyObject *transferObj, int flags, int *statep, int *iserrp);
+ void *(*api_convert_to_mapped_type)(PyObject *pyObj,
+ const sipMappedType *mt, PyObject *transferObj, int flags,
+ int *statep, int *iserrp);
+ void *(*api_force_convert_to_instance)(PyObject *pyObj,
+ sipWrapperType *type, PyObject *transferObj, int flags,
+ int *statep, int *iserrp);
+ void *(*api_force_convert_to_mapped_type)(PyObject *pyObj,
+ const sipMappedType *mt, PyObject *transferObj, int flags,
+ int *statep, int *iserrp);
+ void (*api_release_instance)(void *cpp, sipWrapperType *type, int state);
+ void (*api_release_mapped_type)(void *cpp, const sipMappedType *mt,
+ int state);
+ PyObject *(*api_convert_from_instance)(void *cpp, sipWrapperType *type,
+ PyObject *transferObj);
+ PyObject *(*api_convert_from_new_instance)(void *cpp, sipWrapperType *type,
+ PyObject *transferObj);
+ PyObject *(*api_convert_from_mapped_type)(void *cpp,
+ const sipMappedType *mt, PyObject *transferObj);
+ void *(*api_convert_to_cpp)(PyObject *sipSelf, sipWrapperType *type,
+ int *iserrp);
+ int (*api_get_state)(PyObject *transferObj);
+ const sipMappedType *(*api_find_mapped_type)(const char *type);
+ PyObject *(*api_disconnect_rx)(PyObject *txObj, const char *sig,
+ PyObject *rxObj, const char *slot);
+ int (*api_emit_signal)(PyObject *self, const char *sig, PyObject *sigargs);
+ void (*api_free)(void *mem);
+ PyObject *(*api_get_sender)();
+ PyObject *(*api_get_wrapper)(void *cppPtr, sipWrapperType *type);
+ void *(*api_malloc)(size_t nbytes);
+ sipWrapperType *(*api_map_int_to_class)(int typeInt,
+ const sipIntTypeClassMap *map, int maplen);
+ sipWrapperType *(*api_map_string_to_class)(const char *typeString,
+ const sipStringTypeClassMap *map, int maplen);
+ int (*api_parse_result)(int *isErr, PyObject *method, PyObject *res,
+ const char *fmt, ...);
+ void (*api_trace)(unsigned mask, const char *fmt, ...);
+ void (*api_transfer)(PyObject *self, int toCpp);
+ void (*api_transfer_back)(PyObject *self);
+ void (*api_transfer_to)(PyObject *self, PyObject *owner);
+ int (*api_wrapper_check)(PyObject *o);
+ unsigned long (*api_long_as_unsigned_long)(PyObject *o);
+ PyObject *(*api_convert_from_named_enum)(int eval, PyTypeObject *et);
+
+ /*
+ * The following may be used by Qt support code but no other handwritten
+ * code.
+ */
+ PyObject *(*api_convert_from_void_ptr)(void *val);
+ void (*api_free_connection)(sipSlotConnection *conn);
+ int (*api_emit_to_slot)(sipSlot *slot, PyObject *sigargs);
+ int (*api_same_connection)(sipSlotConnection *conn, void *tx,
+ const char *sig, PyObject *rxObj, const char *slot);
+ void *(*api_convert_rx)(sipWrapper *txSelf, const char *sigargs,
+ PyObject *rxObj, const char *slot, const char **memberp);
+
+ /*
+ * The following are not part of the public API.
+ */
+ int (*api_parse_args)(int *argsParsedp, PyObject *sipArgs,
+ const char *fmt, ...);
+ int (*api_parse_pair)(int *argsParsedp, PyObject *arg0, PyObject *arg1,
+ const char *fmt, ...);
+ void (*api_common_ctor)(sipMethodCache *cache, int nrmeths);
+ void (*api_common_dtor)(sipWrapper *sipSelf);
+ void *(*api_convert_to_void_ptr)(PyObject *obj);
+ void (*api_no_function)(int argsParsed, const char *func);
+ void (*api_no_method)(int argsParsed, const char *classname,
+ const char *method);
+ void (*api_abstract_method)(const char *classname, const char *method);
+ void (*api_bad_class)(const char *classname);
+ void (*api_bad_set_type)(const char *classname, const char *var);
+ void *(*api_get_cpp_ptr)(sipWrapper *w, sipWrapperType *type);
+ void *(*api_get_complex_cpp_ptr)(sipWrapper *w);
+ PyObject *(*api_is_py_method)(sip_gilstate_t *gil, sipMethodCache *pymc,
+ sipWrapper *sipSelf, char *cname, char *mname);
+ void (*api_call_hook)(const char *hookname);
+ void (*api_start_thread)(void);
+ void (*api_end_thread)(void);
+ void (*api_raise_unknown_exception)(void);
+ void (*api_raise_class_exception)(sipWrapperType *type, void *ptr);
+ void (*api_raise_sub_class_exception)(sipWrapperType *type, void *ptr);
+ int (*api_add_class_instance)(PyObject *dict, const char *name,
+ void *cppPtr, sipWrapperType *wt);
+ int (*api_add_enum_instance)(PyObject *dict, const char *name, int value,
+ PyTypeObject *type);
+ void (*api_bad_operator_arg)(PyObject *self, PyObject *arg,
+ sipPySlotType st);
+ PyObject *(*api_pyslot_extend)(sipExportedModuleDef *mod, sipPySlotType st,
+ sipWrapperType *type, PyObject *arg0, PyObject *arg1);
+ void (*api_add_delayed_dtor)(sipWrapper *w);
+ int (*api_add_mapped_type_instance)(PyObject *dict, const char *name,
+ void *cppPtr, const sipMappedType *mt);
+
+ /*
+ * The following are part of the public API.
+ */
+ int (*api_export_symbol)(const char *name, void *sym);
+ void *(*api_import_symbol)(const char *name);
+
+ /*
+ * The following may be used by Qt support code but no other handwritten
+ * code.
+ */
+ int (*api_register_int_types)(PyObject *args);
+ sipSignature *(*api_parse_signature)(const char *sig);
+
+ /*
+ * The following are part of the public API.
+ */
+ sipWrapperType *(*api_find_class)(const char *type);
+ PyTypeObject *(*api_find_named_enum)(const char *type);
+
+ /*
+ * The following are not part of the public API.
+ */
+ char (*api_string_as_char)(PyObject *obj);
+#if defined(HAVE_WCHAR_H)
+ wchar_t (*api_unicode_as_wchar)(PyObject *obj);
+ wchar_t *(*api_unicode_as_wstring)(PyObject *obj);
+#else
+ int (*api_unicode_as_wchar)(PyObject *obj);
+ int *(*api_unicode_as_wstring)(PyObject *obj);
+#endif
+} sipAPIDef;
+
+
+/*
+ * The API implementing the optional Qt support.
+ */
+typedef struct _sipQtAPI {
+ struct _sipWrapperType **qt_qobject;
+ int (*qt_is_qt_signal)(void *, const char *);
+ void *(*qt_create_universal_signal_shortcut)(void *, const char *,
+ const char **);
+ void *(*qt_create_universal_signal)(void *, const struct _sipSignature *);
+ void *(*qt_find_universal_signal_shortcut)(void *, const char *,
+ const char **);
+ void *(*qt_find_universal_signal)(void *, const struct _sipSignature *);
+ int (*qt_emit_signal_shortcut)(void *, const char *, PyObject *);
+ int (*qt_emit_signal)(void *, const struct _sipSignature *, PyObject *);
+ void *(*qt_create_universal_slot)(struct _sipWrapper *,
+ struct _sipSlotConnection *, const char **);
+ void (*qt_destroy_universal_slot)(void *);
+ void *(*qt_find_slot)(void *, const char *, PyObject *, const char *,
+ const char **);
+ int (*qt_connect)(void *, const char *, void *, const char *, int);
+ int (*qt_disconnect)(void *, const char *, void *, const char *);
+ int (*qt_signals_blocked)(void *);
+ const void *(*qt_get_sender)();
+ void (*qt_forget_sender)();
+ int (*qt_same_name)(const char *, const char *);
+ sipSlotConnection *(*qt_find_connection)(void *, void **);
+} sipQtAPI;
+
+
+/*
+ * These are flags that can be passed to sipCanConvertToInstance(),
+ * sipConvertToInstance() and sipForceConvertToInstance().
+ */
+#define SIP_NOT_NONE 0x01 /* Disallow None. */
+#define SIP_NO_CONVERTORS 0x02 /* Disable any type convertors. */
+
+
+/*
+ * These are the state flags returned by %ConvertToTypeCode. Note that these
+ * share the same "namespace" as the flags below.
+ */
+#define SIP_TEMPORARY 0x0001 /* A temporary instance. */
+#define SIP_DERIVED_CLASS 0x0002 /* The instance is derived. */
+
+
+/*
+ * Useful macros, not part of the public API.
+ */
+#define SIP_PY_OWNED 0x0004 /* Owned by Python. */
+#define SIP_INDIRECT 0x0008 /* If there is a level of indirection. */
+#define SIP_ACCFUNC 0x0010 /* If there is an access function. */
+#define SIP_NOT_IN_MAP 0x0020 /* If Python object not in the map. */
+#define SIP_SHARE_MAP 0x0040 /* If the map slot might be occupied. */
+#define SIP_CPP_HAS_REF 0x0080 /* If C/C++ has a reference. */
+
+#define sipIsPyOwned(w) ((w)->flags & SIP_PY_OWNED)
+#define sipSetPyOwned(w) ((w)->flags |= SIP_PY_OWNED)
+#define sipResetPyOwned(w) ((w)->flags &= ~SIP_PY_OWNED)
+#define sipIsDerived(w) ((w)->flags & SIP_DERIVED_CLASS)
+#define sipIsIndirect(w) ((w)->flags & SIP_INDIRECT)
+#define sipIsAccessFunc(w) ((w)->flags & SIP_ACCFUNC)
+#define sipNotInMap(w) ((w)->flags & SIP_NOT_IN_MAP)
+#define sipCppHasRef(w) ((w)->flags & SIP_CPP_HAS_REF)
+#define sipSetCppHasRef(w) ((w)->flags |= SIP_CPP_HAS_REF)
+#define sipResetCppHasRef(w) ((w)->flags &= ~SIP_CPP_HAS_REF)
+
+
+#define SIP_TYPE_ABSTRACT 0x0001 /* If the type is abstract. */
+#define SIP_TYPE_SCC 0x0002 /* If the type is subject to sub-class convertors. */
+#define SIP_TYPE_FLAGS_SHIFT 8 /* The user type flags shift. */
+#define SIP_TYPE_FLAGS_MASK 0x0f00 /* The user type flags mask. */
+
+#define sipTypeIsAbstract(wt) ((wt)->type->td_flags & SIP_TYPE_ABSTRACT)
+#define sipTypeHasSCC(wt) ((wt)->type->td_flags & SIP_TYPE_SCC)
+#define sipTypeFlags(wt) (((wt)->type->td_flags & SIP_TYPE_FLAGS_MASK) >> SIP_TYPE_FLAGS_SHIFT)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/python/sip/siplib/sipint.h b/python/sip/siplib/sipint.h
new file mode 100644
index 00000000..97c35631
--- /dev/null
+++ b/python/sip/siplib/sipint.h
@@ -0,0 +1,121 @@
+/*
+ * This file defines the SIP library internal interfaces.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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.
+ */
+
+
+#ifndef _SIPINT_H
+#define _SIPINT_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef TRUE
+#define TRUE 1
+
+#undef FALSE
+#define FALSE 0
+
+
+/*
+ * This defines a single entry in an object map's hash table.
+ */
+typedef struct
+{
+ void *key; /* The C/C++ address. */
+ sipWrapper *first; /* The first object at this address. */
+} sipHashEntry;
+
+
+/*
+ * This defines the interface to a hash table class for mapping C/C++ addresses
+ * to the corresponding wrapped Python object.
+ */
+typedef struct
+{
+ int primeIdx; /* Index into table sizes. */
+ unsigned long size; /* Size of hash table. */
+ unsigned long unused; /* Nr. unused in hash table. */
+ unsigned long stale; /* Nr. stale in hash table. */
+ sipHashEntry *hash_array; /* Current hash table. */
+} sipObjectMap;
+
+
+extern PyInterpreterState *sipInterpreter; /* The interpreter. */
+
+
+extern sipQtAPI *sipQtSupport; /* The Qt support API. */
+extern sipWrapperType *sipQObjectClass; /* The Python QObject class. */
+
+void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs,
+ PyObject *rxObj, const char *slot,
+ const char **memberp);
+void *sipGetRx(sipWrapper *txSelf,const char *sigargs,PyObject *rxObj,
+ const char *slot,const char **memberp);
+int sip_api_emit_signal(PyObject *self,const char *sig,PyObject *sigargs);
+PyObject *sip_api_get_sender();
+PyObject *sip_api_connect_rx(PyObject *txObj,const char *sig,
+ PyObject *rxObj,const char *slot, int type);
+PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig,
+ PyObject *rxObj,const char *slot);
+sipSignature *sip_api_parse_signature(const char *sig);
+
+
+/*
+ * These are part of the SIP API but are also used within the SIP module.
+ */
+void *sip_api_malloc(size_t nbytes);
+void sip_api_free(void *mem);
+void *sip_api_get_cpp_ptr(sipWrapper *w,sipWrapperType *type);
+PyObject *sip_api_convert_from_instance(void *cppPtr, sipWrapperType *type,
+ PyObject *transferObj);
+void sip_api_start_thread(void);
+void sip_api_end_thread(void);
+PyObject *sip_api_convert_from_void_ptr(void *val);
+PyObject *sip_api_convert_from_named_enum(int eval, PyTypeObject *et);
+int sip_api_wrapper_check(PyObject *o);
+void sip_api_free_connection(sipSlotConnection *conn);
+int sip_api_emit_to_slot(sipSlot *slot, PyObject *sigargs);
+int sip_api_same_connection(sipSlotConnection *conn, void *tx, const char *sig,
+ PyObject *rxObj, const char *slot);
+
+
+/*
+ * These are not part of the SIP API but are used within the SIP module.
+ */
+void sipFreeSlotList(sipSlotList *rx);
+void sipSaveMethod(sipPyMethod *pm,PyObject *meth);
+void *sipGetPending(sipWrapper **op, int *fp);
+PyObject *sipWrapSimpleInstance(void *cppPtr, sipWrapperType *type,
+ sipWrapper *owner, int initflags);
+int sipLambdaSlot(PyObject *slotObj);
+
+void sipOMInit(sipObjectMap *om);
+void sipOMFinalise(sipObjectMap *om);
+sipWrapper *sipOMFindObject(sipObjectMap *om,void *key,sipWrapperType *type);
+void sipOMAddObject(sipObjectMap *om,sipWrapper *val);
+int sipOMRemoveObject(sipObjectMap *om,sipWrapper *val);
+
+void sipSetBool(void *ptr,int val);
+
+void *sipGetAddress(sipWrapper *w);
+void sipFindSigArgType(const char *name, size_t len, sipSigArg *at, int indir);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/python/sip/siplib/siplib.c b/python/sip/siplib/siplib.c
new file mode 100644
index 00000000..d546522c
--- /dev/null
+++ b/python/sip/siplib/siplib.c
@@ -0,0 +1,7902 @@
+/*
+ * SIP library code.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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(SIP_SSIZE_T seqlen,
+ SIP_SSIZE_T slicelen);
+static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...);
+static PyObject *sip_api_call_method(int *isErr, PyObject *method,
+ const char *fmt, ...);
+static PyObject *sip_api_class_name(PyObject *self);
+static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx,
+ SIP_SSIZE_T len);
+static int sip_api_can_convert_to_instance(PyObject *pyObj,
+ sipWrapperType *type, int flags);
+static int sip_api_can_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt, int flags);
+static void *sip_api_convert_to_instance(PyObject *pyObj, sipWrapperType *type,
+ PyObject *transferObj, int flags, int *statep, int *iserrp);
+static void *sip_api_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt, PyObject *transferObj, int flags, int *statep,
+ int *iserrp);
+static void *sip_api_force_convert_to_instance(PyObject *pyObj,
+ sipWrapperType *type, PyObject *transferObj, int flags, int *statep,
+ int *iserrp);
+static void *sip_api_force_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt, PyObject *transferObj, int flags, int *statep,
+ int *iserrp);
+static void sip_api_release_instance(void *cpp, sipWrapperType *type,
+ int state);
+static void sip_api_release_mapped_type(void *cpp, const sipMappedType *mt,
+ int state);
+static PyObject *sip_api_convert_from_new_instance(void *cpp,
+ sipWrapperType *type, PyObject *transferObj);
+static PyObject *sip_api_convert_from_mapped_type(void *cpp,
+ const sipMappedType *mt, PyObject *transferObj);
+static void *sip_api_convert_to_cpp(PyObject *sipSelf, sipWrapperType *type,
+ int *iserrp);
+static int sip_api_get_state(PyObject *transferObj);
+static const sipMappedType *sip_api_find_mapped_type(const char *type);
+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,
+ const char *fmt, ...);
+static void sip_api_trace(unsigned mask,const char *fmt,...);
+static void sip_api_transfer(PyObject *self, int toCpp);
+static void sip_api_transfer_back(PyObject *self);
+static void sip_api_transfer_to(PyObject *self, PyObject *owner);
+static int sip_api_export_module(sipExportedModuleDef *client,
+ unsigned api_major, unsigned api_minor, PyObject *mod_dict);
+static int sip_api_parse_args(int *argsParsedp, PyObject *sipArgs,
+ const char *fmt, ...);
+static int sip_api_parse_pair(int *argsParsedp, PyObject *sipArg0,
+ PyObject *sipArg1, const 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_function(int argsParsed, const char *func);
+static void sip_api_no_method(int argsParsed, const char *classname,
+ const char *method);
+static void sip_api_abstract_method(const char *classname, const char *method);
+static void sip_api_bad_class(const char *classname);
+static void sip_api_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 void sip_api_call_hook(const 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, const char *name,
+ void *cppPtr, sipWrapperType *wt);
+static int sip_api_add_mapped_type_instance(PyObject *dict, const char *name,
+ void *cppPtr, const sipMappedType *mt);
+static int sip_api_add_enum_instance(PyObject *dict, const char *name,
+ int value, PyTypeObject *type);
+static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg,
+ sipPySlotType st);
+static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod,
+ sipPySlotType st, sipWrapperType *type, PyObject *arg0,
+ PyObject *arg1);
+static void sip_api_add_delayed_dtor(sipWrapper *w);
+static unsigned long sip_api_long_as_unsigned_long(PyObject *o);
+static int sip_api_export_symbol(const char *name, void *sym);
+static void *sip_api_import_symbol(const char *name);
+static int sip_api_register_int_types(PyObject *args);
+static sipWrapperType *sip_api_find_class(const char *type);
+static PyTypeObject *sip_api_find_named_enum(const char *type);
+static char sip_api_string_as_char(PyObject *obj);
+#if defined(HAVE_WCHAR_H)
+static wchar_t sip_api_unicode_as_wchar(PyObject *obj);
+static wchar_t *sip_api_unicode_as_wstring(PyObject *obj);
+#else
+static int sip_api_unicode_as_wchar(PyObject *obj);
+static int *sip_api_unicode_as_wstring(PyObject *obj);
+#endif
+
+
+/*
+ * The data structure that represents the SIP API.
+ */
+static const sipAPIDef sip_api = {
+ /* This must be first. */
+ sip_api_export_module,
+ /*
+ * The following are part of the public API.
+ */
+ sip_api_bad_catcher_result,
+ sip_api_bad_length_for_slice,
+ sip_api_build_result,
+ sip_api_call_method,
+ sip_api_class_name,
+ sip_api_connect_rx,
+ sip_api_convert_from_sequence_index,
+ sip_api_can_convert_to_instance,
+ sip_api_can_convert_to_mapped_type,
+ sip_api_convert_to_instance,
+ sip_api_convert_to_mapped_type,
+ sip_api_force_convert_to_instance,
+ sip_api_force_convert_to_mapped_type,
+ sip_api_release_instance,
+ sip_api_release_mapped_type,
+ sip_api_convert_from_instance,
+ sip_api_convert_from_new_instance,
+ sip_api_convert_from_mapped_type,
+ sip_api_convert_to_cpp,
+ sip_api_get_state,
+ sip_api_find_mapped_type,
+ sip_api_disconnect_rx,
+ sip_api_emit_signal,
+ sip_api_free,
+ sip_api_get_sender,
+ 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,
+ sip_api_transfer_back,
+ sip_api_transfer_to,
+ sip_api_wrapper_check,
+ sip_api_long_as_unsigned_long,
+ /*
+ * The following may be used by Qt support code but by no other handwritten
+ * code.
+ */
+ sip_api_convert_from_named_enum,
+ sip_api_convert_from_void_ptr,
+ sip_api_free_connection,
+ sip_api_emit_to_slot,
+ sip_api_same_connection,
+ sip_api_convert_rx,
+ /*
+ * The following are not part of the public API.
+ */
+ sip_api_parse_args,
+ sip_api_parse_pair,
+ sip_api_common_ctor,
+ sip_api_common_dtor,
+ sip_api_convert_to_void_ptr,
+ sip_api_no_function,
+ sip_api_no_method,
+ sip_api_abstract_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_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_add_enum_instance,
+ sip_api_bad_operator_arg,
+ sip_api_pyslot_extend,
+ sip_api_add_delayed_dtor,
+ sip_api_add_mapped_type_instance,
+ /*
+ * The following are part of the public API.
+ */
+ sip_api_export_symbol,
+ sip_api_import_symbol,
+ /*
+ * The following may be used by Qt support code but by no other handwritten
+ * code.
+ */
+ sip_api_register_int_types,
+ sip_api_parse_signature,
+ /*
+ * The following are part of the public API.
+ */
+ sip_api_find_class,
+ sip_api_find_named_enum,
+ /*
+ * The following are not part of the public API.
+ */
+ sip_api_string_as_char,
+ sip_api_unicode_as_wchar,
+ sip_api_unicode_as_wstring,
+};
+
+
+#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
+
+/*
+ * Note that some of the following flags safely share values because they
+ * cannot be used at the same time.
+ */
+#define FORMAT_DEREF 0x01 /* The pointer will be dereferenced. */
+#define FORMAT_FACTORY 0x02 /* Implement /Factory/ in a VH. */
+#define FORMAT_TRANSFER 0x02 /* Implement /Transfer/. */
+#define FORMAT_NO_STATE 0x04 /* Don't return the C/C++ state. */
+#define FORMAT_TRANSFER_BACK 0x04 /* Implement /TransferBack/. */
+#define FORMAT_GET_WRAPPER 0x08 /* Implement /GetWrapper/. */
+#define FORMAT_NO_CONVERTORS 0x10 /* Suppress any convertors. */
+#define FORMAT_TRANSFER_THIS 0x20 /* Support for /TransferThis/. */
+
+#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)
+
+
+/*
+ * An entry in a linked list of name/symbol pairs.
+ */
+typedef struct _sipSymbol {
+ const char *name; /* The name. */
+ void *symbol; /* The symbol. */
+ struct _sipSymbol *next; /* The next in the list. */
+} sipSymbol;
+
+
+/*
+ * An entry in a linked list of Python objects.
+ */
+typedef struct _sipPyObject {
+ PyObject *object; /* The Python object. */
+ struct _sipPyObject *next; /* The next in the list. */
+} sipPyObject;
+
+
+static PyTypeObject sipWrapperType_Type;
+static sipWrapperType sipWrapper_Type;
+static PyTypeObject sipVoidPtr_Type;
+
+PyInterpreterState *sipInterpreter = NULL;
+sipQtAPI *sipQtSupport = NULL;
+sipWrapperType *sipQObjectClass;
+sipPyObject *sipRegisteredIntTypes = NULL;
+sipSymbol *sipSymbolList = NULL;
+
+
+/*
+ * 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(PyTypeObject *to, PyNumberMethods *nb,
+ PySequenceMethods *sq, PyMappingMethods *mp, sipPySlotDef *slots,
+ int force);
+static void *findSlot(PyObject *self, sipPySlotType st);
+static void *findSlotInType(sipTypeDef *td, sipPySlotType st);
+static int objobjargprocSlot(PyObject *self, PyObject *arg1, PyObject *arg2,
+ sipPySlotType st);
+static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T arg1,
+ PyObject *arg2, sipPySlotType st);
+static PyObject *buildObject(PyObject *tup, const char *fmt, va_list va);
+static int parsePass1(sipWrapper **selfp, int *selfargp, int *argsParsedp,
+ PyObject *sipArgs, const char *fmt, va_list va);
+static int parsePass2(sipWrapper *self, int selfarg, int nrargs,
+ PyObject *sipArgs, const char *fmt, va_list va);
+static int getSelfFromArgs(sipWrapperType *type, PyObject *args, int argnr,
+ sipWrapper **selfp);
+static PyObject *createEnumMember(sipTypeDef *td, 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, sipTypeDef **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 *cast_cpp_ptr(void *ptr, sipWrapperType *src_type,
+ sipWrapperType *dst_type);
+static void badArgs(int argsParsed, const char *classname, const char *method);
+static void finalise(void);
+static sipWrapperType *createType(sipExportedModuleDef *client,
+ sipTypeDef *type, PyObject *mod_dict);
+static PyTypeObject *createEnum(sipExportedModuleDef *client, sipEnumDef *ed,
+ PyObject *mod_dict);
+static const char *getBaseName(const char *name);
+static PyObject *getBaseNameObject(const char *name);
+static PyObject *createTypeDict(PyObject *mname);
+static sipExportedModuleDef *getClassModule(sipEncodedClassDef *enc,
+ sipExportedModuleDef *em);
+static sipWrapperType *getClassType(sipEncodedClassDef *enc,
+ sipExportedModuleDef *em);
+static sipWrapperType *convertSubClass(sipWrapperType *type, void **cppPtr);
+static void *getPtrTypeDef(sipWrapper *self, sipTypeDef **td);
+static int addInstances(PyObject *dict, sipInstancesDef *id);
+static int addVoidPtrInstances(PyObject *dict, sipVoidPtrInstanceDef *vi);
+static int addCharInstances(PyObject *dict, sipCharInstanceDef *ci);
+static int addStringInstances(PyObject *dict, sipStringInstanceDef *si);
+static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii);
+static int addLongInstances(PyObject *dict, sipLongInstanceDef *li);
+static int addUnsignedLongInstances(PyObject *dict,
+ sipUnsignedLongInstanceDef *uli);
+static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli);
+static int addUnsignedLongLongInstances(PyObject *dict,
+ sipUnsignedLongLongInstanceDef *ulli);
+static int addDoubleInstances(PyObject *dict, sipDoubleInstanceDef *di);
+static int addEnumInstances(PyObject *dict, sipEnumInstanceDef *ei);
+static int addSingleEnumInstance(PyObject *dict, const char *name, int value,
+ PyTypeObject *type);
+static int addClassInstances(PyObject *dict, sipClassInstanceDef *ci);
+static int addSingleClassInstance(PyObject *dict, const char *name,
+ void *cppPtr, sipWrapperType *wt, int initflags);
+static int addLicense(PyObject *dict, sipLicenseDef *lc);
+static PyObject *cast(PyObject *self, PyObject *args);
+static PyObject *callDtor(PyObject *self, PyObject *args);
+static PyObject *isDeleted(PyObject *self, PyObject *args);
+static PyObject *setDeleted(PyObject *self, PyObject *args);
+static PyObject *setTraceMask(PyObject *self, PyObject *args);
+static PyObject *wrapInstance(PyObject *self, PyObject *args);
+static PyObject *unwrapInstance(PyObject *self, PyObject *args);
+static PyObject *transfer(PyObject *self, PyObject *args);
+static PyObject *transferBack(PyObject *self, PyObject *args);
+static PyObject *transferTo(PyObject *self, PyObject *args);
+static int sipWrapperType_Check(PyObject *op);
+static void addToParent(sipWrapper *self, sipWrapper *owner);
+static void removeFromParent(sipWrapper *self);
+static sipWrapperType *findClass(sipExportedModuleDef *emd, const char *name,
+ size_t len);
+static int findClassArg(sipExportedModuleDef *emd, const char *name,
+ size_t len, sipSigArg *at, int indir);
+static int findMtypeArg(sipMappedType **mttab, const char *name, size_t len,
+ sipSigArg *at, int indir);
+static PyTypeObject *findEnum(sipExportedModuleDef *emd, const char *name,
+ size_t len);
+static int findEnumArg(sipExportedModuleDef *emd, const char *name, size_t len,
+ sipSigArg *at, int indir);
+static int sameScopedName(const char *pyname, const char *name, size_t len);
+static int nameEq(const char *with, const char *name, size_t len);
+static int isExactWrappedType(sipWrapperType *wt);
+static void release(void *addr, sipTypeDef *td, int state);
+static void callPyDtor(sipWrapper *self);
+static int qt_and_sip_api_3_4(void);
+static int visitSlot(sipSlot *slot, visitproc visit, void *arg);
+static void clearAnyLambda(sipSlot *slot);
+static int parseCharArray(PyObject *obj, char **ap, int *aszp);
+static int parseChar(PyObject *obj, char *ap);
+static int parseCharString(PyObject *obj, char **ap);
+#if defined(HAVE_WCHAR_H)
+static int parseWCharArray(PyObject *obj, wchar_t **ap, int *aszp);
+static int parseWChar(PyObject *obj, wchar_t *ap);
+static int parseWCharString(PyObject *obj, wchar_t **ap);
+#else
+static void raiseNoWChar();
+#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},
+ {"delete", callDtor, METH_VARARGS, NULL},
+ {"isdeleted", isDeleted, METH_VARARGS, NULL},
+ {"setdeleted", setDeleted, METH_VARARGS, NULL},
+ {"settracemask", setTraceMask, METH_VARARGS, NULL},
+ {"transfer", transfer, METH_VARARGS, NULL},
+ {"transferback", transferBack, METH_VARARGS, NULL},
+ {"transferto", transferTo, METH_VARARGS, NULL},
+ {"wrapinstance", wrapInstance, METH_VARARGS, NULL},
+ {"unwrapinstance", unwrapInstance, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
+ };
+
+ 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((PyTypeObject *)&sipWrapper_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);
+ }
+
+ if ((obj = PyString_FromString(SIP_VERSION_STR)) != NULL)
+ {
+ PyDict_SetItemString(mod_dict, "SIP_VERSION_STR", obj);
+ Py_DECREF(obj);
+ }
+
+ /* Add the type objects, but don't worry about errors. */
+ PyDict_SetItemString(mod_dict, "wrappertype", (PyObject *)&sipWrapperType_Type);
+ PyDict_SetItemString(mod_dict, "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);
+
+ sipQtSupport = NULL;
+
+ /*
+ * 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 to C/C++.
+ */
+static PyObject *transferTo(PyObject *self, PyObject *args)
+{
+ PyObject *w, *owner;
+
+ if (PyArg_ParseTuple(args, "O!O:transferto", &sipWrapper_Type, &w, &owner))
+ {
+ if (owner == Py_None)
+ owner = NULL;
+ else if (!sip_api_wrapper_check(owner))
+ {
+ PyErr_Format(PyExc_TypeError, "transferto() argument 2 must be sip.wrapper, not %s", owner->ob_type->tp_name);
+ return NULL;
+ }
+
+ sip_api_transfer_to(w, owner);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Transfer the ownership of an instance to Python.
+ */
+static PyObject *transferBack(PyObject *self, PyObject *args)
+{
+ PyObject *w;
+
+ if (PyArg_ParseTuple(args, "O!:transferback", &sipWrapper_Type, &w))
+ {
+ sip_api_transfer_back(w);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Transfer the ownership of an instance. This is deprecated.
+ */
+static PyObject *transfer(PyObject *self, PyObject *args)
+{
+ PyObject *w;
+ int toCpp;
+
+ if (PyArg_ParseTuple(args, "O!i:transfer", &sipWrapper_Type, &w, &toCpp))
+ {
+ if (toCpp)
+ sip_api_transfer_to(w, NULL);
+ else
+ sip_api_transfer_back(w);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Cast an instance to one of it's sub or super-classes by returning a new
+ * Python object with the superclass type wrapping the same C++ instance.
+ */
+static PyObject *cast(PyObject *self, PyObject *args)
+{
+ sipWrapper *w;
+ sipWrapperType *wt, *type;
+ 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 (ft == tt || PyType_IsSubtype(tt, ft))
+ type = NULL;
+ else if (PyType_IsSubtype(ft, tt))
+ type = wt;
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "argument 1 of sip.cast() must be an instance of a sub or super-type of argument 2");
+ return NULL;
+ }
+
+ if ((addr = sip_api_get_cpp_ptr(w, type)) == NULL)
+ return NULL;
+
+ /*
+ * We don't put this new object into the map so that the original object is
+ * always found. It would also totally confuse the map logic.
+ */
+ return sipWrapSimpleInstance(addr, wt, NULL, (w->flags | SIP_NOT_IN_MAP) & ~SIP_PY_OWNED);
+}
+
+
+/*
+ * Call an instance's dtor.
+ */
+static PyObject *callDtor(PyObject *self, PyObject *args)
+{
+ sipWrapper *w;
+ void *addr;
+ sipTypeDef *td;
+
+ if (!PyArg_ParseTuple(args, "O!:delete", &sipWrapper_Type, &w))
+ return NULL;
+
+ addr = getPtrTypeDef(w, &td);
+
+ if (checkPointer(addr) < 0)
+ return NULL;
+
+ /*
+ * Transfer ownership to C++ so we don't try to release it again when the
+ * Python object is garbage collected.
+ */
+ removeFromParent(w);
+ sipResetPyOwned(w);
+
+ release(addr, td, w->flags);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/*
+ * Check if an instance still exists without raising an exception.
+ */
+static PyObject *isDeleted(PyObject *self, PyObject *args)
+{
+ sipWrapper *w;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "O!:isdeleted", &sipWrapper_Type, &w))
+ return NULL;
+
+ res = (sipGetAddress(w) == NULL ? Py_True : Py_False);
+
+ Py_INCREF(res);
+ return res;
+}
+
+
+/*
+ * Mark an instance as having been deleted.
+ */
+static PyObject *setDeleted(PyObject *self, PyObject *args)
+{
+ sipWrapper *w;
+
+ if (!PyArg_ParseTuple(args, "O!:setdeleted", &sipWrapper_Type, &w))
+ return NULL;
+
+ /*
+ * Transfer ownership to C++ so we don't try to release it when the Python
+ * object is garbage collected.
+ */
+ removeFromParent(w);
+ sipResetPyOwned(w);
+
+ w->u.cppPtr = NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/*
+ * 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_convert_from_instance((void *)addr, wt, NULL);
+
+ 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;
+ sipInitExtenderDef *ie;
+ int i;
+
+ /* Check that we can support it. */
+
+ if (api_major != SIP_API_MAJOR_NR || api_minor > SIP_API_MINOR_NR)
+ {
+#if SIP_API_MINOR_NR > 0
+ PyErr_Format(PyExc_RuntimeError, "the sip module 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);
+#else
+ PyErr_Format(PyExc_RuntimeError, "the sip module supports API v%d.0 but the %s module requires API v%d.%d", SIP_API_MAJOR_NR, client->em_name, api_major,api_minor);
+#endif
+
+ return -1;
+ }
+
+ /* Convert the module name to an object. */
+ if ((client->em_nameobj = PyString_FromString(client->em_name)) == NULL)
+ return -1;
+
+ 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;
+ }
+
+ /* Only one module can claim to wrap QObject. */
+ if (em->em_qt_api != NULL && client->em_qt_api != NULL)
+ {
+ PyErr_Format(PyExc_RuntimeError, "the %s and %s modules both wrap the QObject class", client->em_name, em->em_name);
+
+ return -1;
+ }
+ }
+
+ /* 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;
+ }
+ }
+
+ /* Create the module's classes. */
+ if ((mw = client->em_types) != NULL)
+ for (i = 0; i < client->em_nrtypes; ++i, ++mw)
+ {
+ sipTypeDef *td = (sipTypeDef *)*mw;
+
+ /* Skip external classes. */
+ if (td == NULL)
+ continue;
+
+ /* See if this is a namespace extender. */
+ if (td->td_name == NULL)
+ {
+ sipTypeDef **last;
+ sipWrapperType *wt = getClassType(&td->td_scope, client);
+
+ /* Append this type to the real one. */
+ last = &wt->type->td_nsextender;
+
+ while (*last != NULL)
+ last = &(*last)->td_nsextender;
+
+ *last = td;
+
+ /*
+ * Set this so that the extender's original
+ * module can be found.
+ */
+ td->td_module = client;
+
+ /*
+ * Save the real namespace type so that it is
+ * the correct scope for any enums or classes
+ * defined in this module.
+ */
+ *mw = wt;
+ }
+ else if ((*mw = createType(client, td, mod_dict)) == NULL)
+ return -1;
+ }
+
+ /* Set any Qt support API. */
+ if (client->em_qt_api != NULL)
+ {
+ sipQtSupport = client->em_qt_api;
+ sipQObjectClass = *sipQtSupport->qt_qobject;
+ }
+
+ /* Append any initialiser extenders to the relevant classes. */
+ if ((ie = client->em_initextend) != NULL)
+ while (ie->ie_extender != NULL)
+ {
+ sipWrapperType *wt = getClassType(&ie->ie_class, client);
+
+ ie->ie_next = wt->iextend;
+ wt->iextend = ie;
+
+ ++ie;
+ }
+
+ /* Set the base class object for any sub-class convertors. */
+ if ((scc = client->em_convertors) != NULL)
+ while (scc->scc_convertor != NULL)
+ {
+ scc->scc_basetype = getClassType(&scc->scc_base, client);
+
+ ++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, &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)
+ for (i = 0; i < client->em_nrtypes; ++i)
+ {
+ sipWrapperType *wt;
+
+ if ((wt = *mw++) != NULL && addInstances(((PyTypeObject *)wt)->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;
+
+ /* See if the new module satisfies any outstanding external types. */
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ sipExternalTypeDef *etd;
+
+ if (em->em_external == NULL)
+ continue;
+
+ for (etd = em->em_external; etd->et_nr >= 0; ++etd)
+ {
+ if (etd->et_name == NULL)
+ continue;
+
+ mw = client->em_types;
+
+ for (i = 0; i < client->em_nrtypes; ++i)
+ {
+ sipWrapperType *wt;
+ const char *tname;
+
+ if ((wt = *mw++) == NULL)
+ continue;
+
+ tname = strchr(wt->type->td_name, '.') + 1;
+
+ if (strcmp(etd->et_name, tname) == 0)
+ {
+ em->em_types[etd->et_nr] = wt;
+ etd->et_name = NULL;
+
+ break;
+ }
+ }
+ }
+ }
+
+ /* Add to the list of client modules. */
+ client->em_next = clientList;
+ clientList = client;
+
+ return 0;
+}
+
+
+/*
+ * Called by the interpreter to do any final clearing up, just in case the
+ * interpreter will re-start.
+ */
+static void finalise(void)
+{
+ sipExportedModuleDef *em;
+
+ /* Mark the Python API as unavailable. */
+ sipInterpreter = NULL;
+
+ /* Handle any delayed dtors. */
+ for (em = clientList; em != NULL; em = em->em_next)
+ if (em->em_ddlist != NULL)
+ {
+ em->em_delayeddtors(em->em_ddlist);
+
+ /* Free the list. */
+ do
+ {
+ sipDelayedDtor *dd = em->em_ddlist;
+
+ em->em_ddlist = dd->dd_next;
+ sip_api_free(dd);
+ }
+ while (em->em_ddlist != NULL);
+ }
+
+ licenseName = NULL;
+ licenseeName = NULL;
+ typeName = NULL;
+ timestampName = NULL;
+ signatureName = NULL;
+
+ /* Release all memory we've allocated directly. */
+ sipOMFinalise(&cppPyMap);
+
+ /* Re-initialise those globals that (might) need it. */
+ clientList = NULL;
+}
+
+
+/*
+ * Add a wrapped C/C++ pointer to the list of delayed dtors.
+ */
+static void sip_api_add_delayed_dtor(sipWrapper *w)
+{
+ void *ptr;
+ sipTypeDef *td;
+ sipExportedModuleDef *em;
+
+ if ((ptr = getPtrTypeDef(w, &td)) == NULL)
+ return;
+
+ /* Find the defining module. */
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ int i;
+
+ for (i = 0; i < em->em_nrtypes; ++i)
+ if (em->em_types[i] != NULL && em->em_types[i]->type == td)
+ {
+ sipDelayedDtor *dd;
+
+ if ((dd = sip_api_malloc(sizeof (sipDelayedDtor))) == NULL)
+ return;
+
+ /* Add to the list. */
+ dd->dd_ptr = ptr;
+ dd->dd_name = getBaseName(td->td_name);
+ dd->dd_isderived = sipIsDerived(w);
+ dd->dd_next = em->em_ddlist;
+
+ em->em_ddlist = dd;
+
+ return;
+ }
+ }
+}
+
+
+/*
+ * A wrapper around the Python memory allocater that will raise an exception if
+ * if the allocation fails.
+ */
+void *sip_api_malloc(size_t nbytes)
+{
+ void *mem;
+
+ if ((mem = PyMem_Malloc(nbytes)) == NULL)
+ PyErr_NoMemory();
+
+ return mem;
+}
+
+
+/*
+ * A wrapper around the Python memory de-allocater.
+ */
+void sip_api_free(void *mem)
+{
+ PyMem_Free(mem);
+}
+
+
+/*
+ * Extend a Python slot by looking in other modules to see if there is an
+ * extender function that can handle the arguments.
+ */
+static PyObject *sip_api_pyslot_extend(sipExportedModuleDef *mod,
+ sipPySlotType st, sipWrapperType *type,
+ PyObject *arg0, PyObject *arg1)
+{
+ sipExportedModuleDef *em;
+
+ /* Go through each module. */
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ sipPySlotExtenderDef *ex;
+
+ /* Skip the module that couldn't handle the arguments. */
+ if (em == mod)
+ continue;
+
+ /* Skip if the module doesn't have any extenders. */
+ if (em->em_slotextend == NULL)
+ continue;
+
+ /* Go through each extender. */
+ for (ex = em->em_slotextend; ex->pse_func != NULL; ++ex)
+ {
+ PyObject *res;
+
+ /* Skip if not the right slot type. */
+ if (ex->pse_type != st)
+ continue;
+
+ /* Check against the type if one was given. */
+ if (type != NULL && type != getClassType(&ex->pse_class, NULL))
+ continue;
+
+ PyErr_Clear();
+
+ res = ((binaryfunc)ex->pse_func)(arg0, arg1);
+
+ if (res != Py_NotImplemented)
+ return res;
+ }
+ }
+
+ /* The arguments couldn't handled anywhere. */
+ PyErr_Clear();
+
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+
+/*
+ * Call the Python re-implementation of a C++ virtual.
+ */
+static PyObject *sip_api_call_method(int *isErr, PyObject *method,
+ const char *fmt, ...)
+{
+ PyObject *args, *res;
+ va_list va;
+
+ va_start(va,fmt);
+
+ if ((args = PyTuple_New(strlen(fmt))) != NULL && buildObject(args,fmt,va) != NULL)
+ res = PyEval_CallObject(method,args);
+ else
+ {
+ res = NULL;
+
+ if (isErr != NULL)
+ *isErr = TRUE;
+ }
+
+ Py_XDECREF(args);
+
+ va_end(va);
+
+ return res;
+}
+
+
+/*
+ * Build a result object based on a format string.
+ */
+static PyObject *sip_api_build_result(int *isErr, const char *fmt, ...)
+{
+ PyObject *res = NULL;
+ int badfmt, tupsz;
+ va_list va;
+
+ va_start(va,fmt);
+
+ /* Basic validation of the format string. */
+
+ badfmt = FALSE;
+
+ if (*fmt == '(')
+ {
+ char *ep;
+
+ if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0')
+ badfmt = TRUE;
+ else
+ tupsz = ep - fmt - 1;
+ }
+ else if (strlen(fmt) == 1)
+ tupsz = -1;
+ else
+ badfmt = TRUE;
+
+ if (badfmt)
+ PyErr_Format(PyExc_SystemError,"sipBuildResult(): invalid format string \"%s\"",fmt);
+ else if (tupsz < 0 || (res = PyTuple_New(tupsz)) != NULL)
+ res = buildObject(res,fmt,va);
+
+ va_end(va);
+
+ if (res == NULL && isErr != NULL)
+ *isErr = TRUE;
+
+ return res;
+}
+
+
+/*
+ * Get the values off the stack and put them into an object.
+ */
+static PyObject *buildObject(PyObject *obj, const char *fmt, va_list va)
+{
+ char ch, termch;
+ int i;
+
+ /*
+ * The format string has already been checked that it is properly
+ * formed if it is enclosed in parenthesis.
+ */
+ if (*fmt == '(')
+ {
+ termch = ')';
+ ++fmt;
+ }
+ else
+ termch = '\0';
+
+ i = 0;
+
+ while ((ch = *fmt++) != termch)
+ {
+ PyObject *el;
+
+ switch (ch)
+ {
+ case 'a':
+ {
+ char *s;
+ int l;
+
+ s = va_arg(va, char *);
+ l = va_arg(va, int);
+
+ if (s != NULL)
+ el = PyString_FromStringAndSize(s, (SIP_SSIZE_T)l);
+ else
+ {
+ Py_INCREF(Py_None);
+ el = Py_None;
+ }
+ }
+
+ break;
+
+ case 'A':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t *s;
+ int l;
+
+ s = va_arg(va, wchar_t *);
+ l = va_arg(va, int);
+
+ if (s != NULL)
+ el = PyUnicode_FromWideChar(s, (SIP_SSIZE_T)l);
+ else
+ {
+ Py_INCREF(Py_None);
+ el = Py_None;
+ }
+ }
+#else
+ raiseNoWChar();
+ el = NULL;
+#endif
+
+ break;
+
+ case 'b':
+ el = PyBool_FromLong(va_arg(va,int));
+ break;
+
+ case 'c':
+ {
+ char c = va_arg(va, int);
+
+ el = PyString_FromStringAndSize(&c,1);
+ }
+
+ break;
+
+ case 'w':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t c = va_arg(va, int);
+
+ el = PyUnicode_FromWideChar(&c, 1);
+ }
+#else
+ raiseNoWChar();
+ el = NULL;
+#endif
+
+ break;
+
+ case 'e':
+ 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 = PyLong_FromLong(va_arg(va,long));
+ break;
+
+ case 'm':
+ el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
+ break;
+
+ case 'n':
+#if defined(HAVE_LONG_LONG)
+ el = PyLong_FromLongLong(va_arg(va, PY_LONG_LONG));
+#else
+ el = PyLong_FromLong(va_arg(va, long));
+#endif
+ break;
+
+ case 'o':
+#if defined(HAVE_LONG_LONG)
+ el = PyLong_FromUnsignedLongLong(va_arg(va, unsigned PY_LONG_LONG));
+#else
+ el = PyLong_FromUnsignedLong(va_arg(va, unsigned long));
+#endif
+ break;
+
+ case 's':
+ {
+ char *s = va_arg(va, char *);
+
+ if (s != NULL)
+ el = PyString_FromString(s);
+ else
+ {
+ Py_INCREF(Py_None);
+ el = Py_None;
+ }
+ }
+
+ break;
+
+ case 'x':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t *s = va_arg(va, wchar_t *);
+
+ if (s != NULL)
+ el = PyUnicode_FromWideChar(s, (SIP_SSIZE_T)wcslen(s));
+ else
+ {
+ Py_INCREF(Py_None);
+ el = Py_None;
+ }
+ }
+#else
+ raiseNoWChar();
+ el = NULL;
+#endif
+
+ break;
+
+ case 't':
+ case 'u':
+ el = PyLong_FromUnsignedLong(va_arg(va, unsigned));
+ break;
+
+ case 'B':
+ {
+ void *p = va_arg(va,void *);
+ sipWrapperType *wt = va_arg(va, sipWrapperType *);
+ PyObject *xfer = va_arg(va, PyObject *);
+
+ el = sip_api_convert_from_new_instance(p, wt, xfer);
+ }
+
+ break;
+
+ case 'C':
+ {
+ void *p = va_arg(va,void *);
+ sipWrapperType *wt = va_arg(va, sipWrapperType *);
+ PyObject *xfer = va_arg(va, PyObject *);
+
+ el = sip_api_convert_from_instance(p, wt, xfer);
+ }
+
+ break;
+
+ case 'D':
+ {
+ void *p = va_arg(va, void *);
+ const sipMappedType *mt = va_arg(va, const sipMappedType *);
+ PyObject *xfer = va_arg(va, PyObject *);
+
+ el = sip_api_convert_from_mapped_type(p, mt, xfer);
+ }
+
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ void *sipCpp = va_arg(va,void *);
+ sipWrapperType *wt = va_arg(va,sipWrapperType *);
+
+ el = sip_api_convert_from_instance(sipCpp,wt,NULL);
+ }
+
+ break;
+
+ case 'N':
+ case 'P':
+ {
+ void *sipCpp = va_arg(va,void *);
+ sipWrapperType *wt = va_arg(va,sipWrapperType *);
+
+ el = sip_api_convert_from_new_instance(sipCpp,wt,NULL);
+ }
+
+ 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 *);
+ sipConvertFromFunc func = va_arg(va,sipConvertFromFunc);
+
+ el = func(sipCpp, NULL);
+ }
+
+ break;
+
+ case 'V':
+ el = sip_api_convert_from_void_ptr(va_arg(va,void *));
+ break;
+
+ default:
+ PyErr_Format(PyExc_SystemError,"buildObject(): invalid format character '%c'",ch);
+ el = NULL;
+ }
+
+ if (el == NULL)
+ {
+ Py_XDECREF(obj);
+ return NULL;
+ }
+
+ if (obj == NULL)
+ return el;
+
+ PyTuple_SET_ITEM(obj,i,el);
+ ++i;
+ }
+
+ return obj;
+}
+
+
+/*
+ * Parse a result object based on a format string.
+ */
+static int sip_api_parse_result(int *isErr, PyObject *method, PyObject *res,
+ const char *fmt, ...)
+{
+ int tupsz, rc = 0;
+ va_list va;
+
+ va_start(va,fmt);
+
+ /* Basic validation of the format string. */
+
+ if (*fmt == '(')
+ {
+ char *ep;
+
+ if ((ep = strchr(fmt,')')) == NULL || ep[1] != '\0')
+ {
+ PyErr_Format(PyExc_SystemError, "sipParseResult(): invalid format string \"%s\"", fmt);
+ rc = -1;
+ }
+ else
+ {
+ tupsz = ep - ++fmt;
+
+ if (tupsz >= 0 && (!PyTuple_Check(res) || PyTuple_GET_SIZE(res) != tupsz))
+ {
+ sip_api_bad_catcher_result(method);
+ rc = -1;
+ }
+ }
+ }
+ else
+ tupsz = -1;
+
+ if (rc == 0)
+ {
+ char ch;
+ int i = 0;
+
+ while ((ch = *fmt++) != '\0' && ch != ')' && rc == 0)
+ {
+ PyObject *arg;
+ int invalid = FALSE;
+
+ if (tupsz > 0)
+ {
+ arg = PyTuple_GET_ITEM(res,i);
+ ++i;
+ }
+ else
+ arg = res;
+
+ switch (ch)
+ {
+ case 'a':
+ {
+ char **p = va_arg(va, char **);
+ int *szp = va_arg(va, int *);
+
+ if (parseCharArray(arg, p, szp) < 0)
+ invalid = TRUE;
+ }
+
+ break;
+
+ case 'A':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t **p = va_arg(va, wchar_t **);
+ int *szp = va_arg(va, int *);
+
+ if (parseWCharArray(arg, p, szp) < 0)
+ invalid = TRUE;
+ }
+#else
+ raiseNoWChar();
+ invalid = TRUE;
+#endif
+
+ break;
+
+ case 'b':
+ {
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ sipSetBool(va_arg(va,void *),v);
+ }
+
+ break;
+
+ case 'c':
+ {
+ char *p = va_arg(va, char *);
+
+ if (parseChar(arg, p) < 0)
+ invalid = TRUE;
+ }
+
+ break;
+
+ case 'w':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t *p = va_arg(va, wchar_t *);
+
+ if (parseWChar(arg, p) < 0)
+ invalid = TRUE;
+ }
+#else
+ raiseNoWChar();
+ invalid = TRUE;
+#endif
+
+ break;
+
+ case 'd':
+ {
+ double v = PyFloat_AsDouble(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,double *) = v;
+ }
+
+ break;
+
+ case 'e':
+ {
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,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':
+ {
+ float v = PyFloat_AsDouble(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,float *) = v;
+ }
+
+ break;
+
+ case 'h':
+ {
+ short v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,short *) = v;
+ }
+
+ break;
+
+ case 't':
+ {
+ unsigned short v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,unsigned short *) = v;
+ }
+
+ break;
+
+ case 'i':
+ {
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,int *) = v;
+ }
+
+ break;
+
+ case 'u':
+ {
+ unsigned v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,unsigned *) = v;
+ }
+
+ break;
+
+ case 'l':
+ {
+ long v = PyLong_AsLong(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va,long *) = v;
+ }
+
+ break;
+
+ case 'm':
+ {
+ unsigned long v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+ *va_arg(va, unsigned long *) = v;
+ }
+
+ break;
+
+ case 'n':
+ {
+#if defined(HAVE_LONG_LONG)
+ PY_LONG_LONG v = PyLong_AsLongLong(arg);
+#else
+ long v = PyLong_AsLong(arg);
+#endif
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+#if defined(HAVE_LONG_LONG)
+ *va_arg(va, PY_LONG_LONG *) = v;
+#else
+ *va_arg(va, long *) = v;
+#endif
+ }
+
+ break;
+
+ case 'o':
+ {
+#if defined(HAVE_LONG_LONG)
+ unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg);
+#else
+ unsigned long v = PyLong_AsUnsignedLong(arg);
+#endif
+
+ if (PyErr_Occurred())
+ invalid = TRUE;
+ else
+#if defined(HAVE_LONG_LONG)
+ *va_arg(va, unsigned PY_LONG_LONG *) = v;
+#else
+ *va_arg(va, unsigned long *) = v;
+#endif
+ }
+
+ break;
+
+ case 's':
+ {
+ char **p = va_arg(va, char **);
+
+ if (parseCharString(arg, p) < 0)
+ invalid = TRUE;
+ }
+
+ break;
+
+ case 'x':
+#if defined(HAVE_WCHAR_H)
+ {
+ wchar_t **p = va_arg(va, wchar_t **);
+
+ if (parseWCharString(arg, p) < 0)
+ invalid = TRUE;
+ }
+#else
+ raiseNoWChar();
+ invalid = TRUE;
+#endif
+
+ break;
+
+ case 'C':
+ {
+ if (*fmt == '\0')
+ invalid = TRUE;
+ else
+ {
+ int flags = *fmt++ - '0';
+ int iserr = FALSE;
+ sipWrapperType *type;
+ void **cpp;
+ int *state;
+
+ type = va_arg(va, sipWrapperType *);
+
+ if (flags & FORMAT_NO_STATE)
+ state = NULL;
+ else
+ state = va_arg(va, int *);
+
+ cpp = va_arg(va, void **);
+
+ *cpp = sip_api_force_convert_to_instance(arg, type, (flags & FORMAT_FACTORY ? arg : NULL), (flags & FORMAT_DEREF ? SIP_NOT_NONE : 0), state, &iserr);
+
+ if (iserr)
+ invalid = TRUE;
+ }
+ }
+
+ break;
+
+ case 'D':
+ {
+ if (*fmt == '\0')
+ invalid = TRUE;
+ else
+ {
+ int flags = *fmt++ - '0';
+ int iserr = FALSE;
+ const sipMappedType *mt;
+ void **cpp;
+ int *state;
+
+ mt = va_arg(va, const sipMappedType *);
+
+ if (flags & FORMAT_NO_STATE)
+ state = NULL;
+ else
+ state = va_arg(va, int *);
+
+ cpp = va_arg(va, void **);
+
+ *cpp = sip_api_force_convert_to_mapped_type(arg, mt, (flags & FORMAT_FACTORY ? arg : NULL), (flags & FORMAT_DEREF ? SIP_NOT_NONE : 0), state, &iserr);
+
+ if (iserr)
+ invalid = TRUE;
+ }
+ }
+
+ break;
+
+ case 'L':
+ {
+ sipForceConvertToFunc func = va_arg(va,sipForceConvertToFunc);
+ void **sipCpp = va_arg(va,void **);
+ int iserr = FALSE;
+
+ *sipCpp = func(arg,&iserr);
+
+ if (iserr)
+ invalid = TRUE;
+ }
+
+ break;
+
+ case 'M':
+ {
+ sipForceConvertToFunc func = va_arg(va,sipForceConvertToFunc);
+ 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;
+}
+
+
+/*
+ * A thin wrapper around PyLong_AsUnsignedLong() that works around a bug in
+ * Python versions prior to v2.4 where an integer (or a named enum) causes an
+ * error.
+ */
+static unsigned long sip_api_long_as_unsigned_long(PyObject *o)
+{
+#if PY_VERSION_HEX < 0x02040000
+ if (o != NULL && !PyLong_Check(o) && PyInt_Check(o))
+ {
+ long v = PyInt_AsLong(o);
+
+ if (v < 0)
+ {
+ PyErr_SetString(PyExc_OverflowError,
+ "can't convert negative value to unsigned long");
+
+ return (unsigned long)-1;
+ }
+
+ return v;
+ }
+#endif
+
+ return PyLong_AsUnsignedLong(o);
+}
+
+
+/*
+ * Parse the arguments to a C/C++ function without any side effects.
+ */
+static int sip_api_parse_args(int *argsParsedp, PyObject *sipArgs,
+ const 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;
+}
+
+
+/*
+ * Parse a pair of arguments to a C/C++ function without any side effects.
+ */
+static int sip_api_parse_pair(int *argsParsedp, PyObject *sipArg0,
+ PyObject *sipArg1, const char *fmt, ...)
+{
+ int valid, nrargs, selfarg;
+ sipWrapper *self;
+ PyObject *args;
+ va_list va;
+
+ /* Previous sticky errors stop subsequent parses. */
+ if (*argsParsedp & PARSE_STICKY)
+ return 0;
+
+ if ((args = PyTuple_New(2)) == NULL)
+ return 0;
+
+ Py_INCREF(sipArg0);
+ PyTuple_SET_ITEM(args, 0, sipArg0);
+
+ Py_INCREF(sipArg1);
+ PyTuple_SET_ITEM(args, 1, sipArg1);
+
+ nrargs = 2;
+
+ /*
+ * 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,args,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(args);
+
+ 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,args,fmt,va);
+ va_end(va);
+
+ if (valid != PARSE_OK)
+ {
+ *argsParsedp = valid | PARSE_STICKY;
+
+ Py_DECREF(args);
+
+ return 0;
+ }
+
+ *argsParsedp = nrargs;
+
+ Py_DECREF(args);
+
+ 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, const 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 'B':
+ 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;
+ }
+
+ /* 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)
+ {
+ /*
+ * It is an error if we are still expecting compulsory
+ * arguments unless the current argume is an ellipsis.
+ */
+ if (ch != 'W' && ch != '\0' && compulsory)
+ valid = PARSE_FEW;
+
+ break;
+ }
+
+ /* Get the next argument. */
+ arg = PyTuple_GET_ITEM(sipArgs,argnr);
+ ++argnr;
+
+ switch (ch)
+ {
+ case 'W':
+ /* Ellipsis. */
+ break;
+
+ case 's':
+ {
+ /* String or None. */
+
+ char **p = va_arg(va, char **);
+
+ if (parseCharString(arg, p) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'x':
+#if defined(HAVE_WCHAR_H)
+ {
+ /* Wide string or None. */
+
+ wchar_t **p = va_arg(va, wchar_t **);
+
+ if (parseWCharString(arg, p) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+#else
+ raiseNoWChar();
+ valid = PARSE_RAISED;
+ break;
+#endif
+
+ case 'U':
+ {
+ /*
+ * Slot name or callable, return the name or
+ * callable.
+ */
+
+ char **sname = va_arg(va, char **);
+ PyObject **scall = va_arg(va, PyObject **);
+
+ *sname = NULL;
+ *scall = NULL;
+
+ if (PyString_Check(arg))
+ {
+ char *s = PyString_AS_STRING(arg);
+
+ if (*s == '1' || *s == '2' || *s == '9')
+ *sname = s;
+ else
+ valid = PARSE_TYPE;
+ }
+ else if (PyCallable_Check(arg))
+ *scall = arg;
+ else if (arg != Py_None)
+ 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. */
+
+ if (*fmt == '\0')
+ valid = PARSE_FORMAT;
+ else
+ {
+ int flags = *fmt++ - '0';
+ sipWrapperType *type;
+ int iflgs = 0;
+
+ type = va_arg(va,sipWrapperType *);
+ va_arg(va,void **);
+
+ if (flags & FORMAT_DEREF)
+ iflgs |= SIP_NOT_NONE;
+
+ if (flags & (FORMAT_GET_WRAPPER|FORMAT_TRANSFER_THIS))
+ va_arg(va,PyObject **);
+
+ if (flags & FORMAT_NO_CONVERTORS)
+ iflgs |= SIP_NO_CONVERTORS;
+ else
+ va_arg(va, int *);
+
+ if (!sip_api_can_convert_to_instance(arg, type, iflgs))
+ valid = PARSE_TYPE;
+ }
+
+ break;
+ }
+
+ case 'M':
+ {
+ /* Mapped type instance. */
+
+ if (*fmt == '\0')
+ valid = PARSE_FORMAT;
+ else
+ {
+ int flags = *fmt++ - '0';
+ sipMappedType *mt;
+ int iflgs = 0;
+
+ mt = va_arg(va, sipMappedType *);
+ va_arg(va, void **);
+ va_arg(va, int *);
+
+ if (flags & FORMAT_DEREF)
+ iflgs |= SIP_NOT_NONE;
+
+ if (!sip_api_can_convert_to_mapped_type(arg, mt, iflgs))
+ valid = PARSE_TYPE;
+ }
+
+ 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':
+ {
+ /* Sub-class of QObject. */
+
+ if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass))
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va,PyObject **) = arg;
+
+ 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':
+ {
+ /* Qt receiver to connect. */
+
+ va_arg(va,char *);
+ va_arg(va,void **);
+ va_arg(va,const char **);
+
+ if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass))
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'Q':
+ {
+ /* Qt receiver to disconnect. */
+
+ va_arg(va,char *);
+ va_arg(va,void **);
+ va_arg(va,const char **);
+
+ if (sipQtSupport == NULL || !PyObject_TypeCheck(arg, (PyTypeObject *)sipQObjectClass))
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'y':
+ {
+ /* Python slot to connect. */
+
+ va_arg(va,char *);
+ va_arg(va,void **);
+ va_arg(va,const char **);
+
+ if (sipQtSupport == NULL || !PyCallable_Check(arg))
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'Y':
+ {
+ /* Python slot to disconnect. */
+
+ va_arg(va,char *);
+ va_arg(va,void **);
+ va_arg(va,const char **);
+
+ if (sipQtSupport == NULL || !PyCallable_Check(arg))
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'a':
+ {
+ /* Char array or None. */
+
+ char **p = va_arg(va, char **);
+ int *szp = va_arg(va, int *);
+
+ if (parseCharArray(arg, p, szp) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'A':
+#if defined(HAVE_WCHAR_H)
+ {
+ /* Wide char array or None. */
+
+ wchar_t **p = va_arg(va, wchar_t **);
+ int *szp = va_arg(va, int *);
+
+ if (parseWCharArray(arg, p, szp) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+#else
+ raiseNoWChar();
+ valid = PARSE_RAISED;
+ break
+#endif
+
+ case 'c':
+ {
+ /* Character. */
+
+ char *p = va_arg(va, char *);
+
+ if (parseChar(arg, p) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ case 'w':
+#if defined(HAVE_WCHAR_H)
+ {
+ /* Wide character. */
+
+ wchar_t *p = va_arg(va, wchar_t *);
+
+ if (parseWChar(arg, p) < 0)
+ valid = PARSE_TYPE;
+
+ break;
+ }
+#else
+ raiseNoWChar();
+ valid = PARSE_RAISED;
+ break
+#endif
+
+ case 'b':
+ {
+ /* Bool. */
+
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ sipSetBool(va_arg(va,void *),v);
+
+ break;
+ }
+
+ case 'e':
+ {
+ /* Anonymous enum. */
+
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va,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. */
+
+ int v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va,int *) = v;
+
+ break;
+ }
+
+ case 'u':
+ {
+ /* Unsigned integer. */
+
+ unsigned v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va, unsigned *) = v;
+
+ break;
+ }
+
+ case 'h':
+ {
+ /* Short integer. */
+
+ short v = PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va,short *) = v;
+
+ break;
+ }
+
+ case 't':
+ {
+ /* Unsigned short integer. */
+
+ unsigned short v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va, unsigned short *) = v;
+
+ break;
+ }
+
+ case 'l':
+ {
+ /* Long integer. */
+
+ long v = PyLong_AsLong(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va,long *) = v;
+
+ break;
+ }
+
+ case 'm':
+ {
+ /* Unsigned long integer. */
+
+ unsigned long v = sip_api_long_as_unsigned_long(arg);
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+ *va_arg(va, unsigned long *) = v;
+
+ break;
+ }
+
+ case 'n':
+ {
+ /* Long long integer. */
+
+#if defined(HAVE_LONG_LONG)
+ PY_LONG_LONG v = PyLong_AsLongLong(arg);
+#else
+ long v = PyLong_AsLong(arg);
+#endif
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+#if defined(HAVE_LONG_LONG)
+ *va_arg(va, PY_LONG_LONG *) = v;
+#else
+ *va_arg(va, long *) = v;
+#endif
+
+ break;
+ }
+
+ case 'o':
+ {
+ /* Unsigned long long integer. */
+
+#if defined(HAVE_LONG_LONG)
+ unsigned PY_LONG_LONG v = PyLong_AsUnsignedLongLong(arg);
+#else
+ unsigned long v = PyLong_AsUnsignedLong(arg);
+#endif
+
+ if (PyErr_Occurred())
+ valid = PARSE_TYPE;
+ else
+#if defined(HAVE_LONG_LONG)
+ *va_arg(va, unsigned PY_LONG_LONG *) = v;
+#else
+ *va_arg(va, unsigned long *) = v;
+#endif
+
+ 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 'b':
+ {
+ /* Boolean. */
+
+ if (PyBool_Check(arg))
+ sipSetBool(va_arg(va,void *),(arg == Py_True));
+ else
+ valid = PARSE_TYPE;
+
+ break;
+ }
+
+ 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 *) = 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)
+ {
+ if (ch == 'W')
+ {
+ /*
+ * An ellipsis matches everything and ends the
+ * parse.
+ */
+ nrparsed = nrargs;
+ break;
+ }
+
+ ++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, const char *fmt, va_list va)
+{
+ int a, valid;
+
+ valid = PARSE_OK;
+
+ /* Handle the converions of "self" first. */
+ switch (*fmt++)
+ {
+ case 'B':
+ {
+ /*
+ * The address of a C++ instance when calling one of
+ * its public methods.
+ */
+
+ sipWrapperType *type;
+ void **p;
+
+ *va_arg(va,PyObject **) = (PyObject *)self;
+ 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 **) = (PyObject *)self;
+ 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;
+ }
+
+ for (a = (selfarg ? 1 : 0); a < nrargs && *fmt != 'W' && 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':
+ {
+ /* 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 = sip_api_convert_rx(self,sig,arg,*slot,slot)) == NULL)
+ valid = PARSE_RAISED;
+
+ break;
+ }
+
+ case 'Q':
+ {
+ /* Qt receiver to disconnect. */
+
+ char *sig = va_arg(va,char *);
+ void **rx = va_arg(va,void **);
+ const char **slot = va_arg(va,const char **);
+
+ *rx = sipGetRx(self,sig,arg,*slot,slot);
+ break;
+ }
+
+ case 'y':
+ {
+ /* Python slot to connect. */
+
+ char *sig = va_arg(va,char *);
+ void **rx = va_arg(va,void **);
+ const char **slot = va_arg(va,const char **);
+
+ if ((*rx = sip_api_convert_rx(self,sig,arg,NULL,slot)) == NULL)
+ valid = PARSE_RAISED;
+
+ break;
+ }
+
+ case 'Y':
+ {
+ /* Python slot to disconnect. */
+
+ char *sig = va_arg(va,char *);
+ void **rx = va_arg(va,void **);
+ const char **slot = va_arg(va,const char **);
+
+ *rx = sipGetRx(self,sig,arg,NULL,slot);
+ break;
+ }
+
+ case 'J':
+ {
+ /* Class instance. */
+
+ int flags = *fmt++ - '0';
+ sipWrapperType *type;
+ void **p;
+ int iflgs = 0;
+ int iserr = FALSE;
+ int *state;
+ PyObject *xfer, **wrapper;
+
+ type = va_arg(va,sipWrapperType *);
+ p = va_arg(va,void **);
+
+ if (flags & FORMAT_TRANSFER)
+ xfer = (self ? (PyObject *)self : arg);
+ else if (flags & FORMAT_TRANSFER_BACK)
+ xfer = Py_None;
+ else
+ xfer = NULL;
+
+ if (flags & FORMAT_DEREF)
+ iflgs |= SIP_NOT_NONE;
+
+ if (flags & (FORMAT_GET_WRAPPER|FORMAT_TRANSFER_THIS))
+ wrapper = va_arg(va, PyObject **);
+
+ if (flags & FORMAT_NO_CONVERTORS)
+ {
+ iflgs |= SIP_NO_CONVERTORS;
+ state = NULL;
+ }
+ else
+ state = va_arg(va, int *);
+
+ *p = sip_api_convert_to_instance(arg, type, xfer, iflgs, state, &iserr);
+
+ if (iserr)
+ valid = PARSE_RAISED;
+
+ if (flags & FORMAT_GET_WRAPPER)
+ *wrapper = (*p != NULL ? arg : NULL);
+ else if (flags & FORMAT_TRANSFER_THIS && *p != NULL)
+ *wrapper = arg;
+
+ break;
+ }
+
+ case 'M':
+ {
+ /* Mapped type instance. */
+
+ int flags = *fmt++ - '0';
+ sipMappedType *mt;
+ void **p;
+ int iflgs = 0;
+ int iserr = FALSE;
+ int *state;
+ PyObject *xfer;
+
+ mt = va_arg(va, sipMappedType *);
+ p = va_arg(va, void **);
+ state = va_arg(va, int *);
+
+ if (flags & FORMAT_TRANSFER)
+ xfer = (self ? (PyObject *)self : arg);
+ else if (flags & FORMAT_TRANSFER_BACK)
+ xfer = Py_None;
+ else
+ xfer = NULL;
+
+ if (flags & FORMAT_DEREF)
+ iflgs |= SIP_NOT_NONE;
+
+ *p = sip_api_convert_to_mapped_type(arg, mt, xfer, iflgs, state, &iserr);
+
+ if (iserr)
+ valid = PARSE_RAISED;
+
+ 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':
+ case 'A':
+ va_arg(va,void *);
+
+ /* Drop through. */
+
+ default:
+ va_arg(va,void *);
+ }
+ }
+
+ /* Handle any ellipsis argument. */
+ if (*fmt == 'W' && valid == PARSE_OK)
+ {
+ PyObject *al;
+
+ /* Create a tuple for any remaining arguments. */
+ if ((al = PyTuple_New(nrargs - a)) != NULL)
+ {
+ int da = 0;
+
+ while (a < nrargs)
+ {
+ PyObject *arg = PyTuple_GET_ITEM(sipArgs,a);
+
+ /* Add the remaining argument to the tuple. */
+ Py_INCREF(arg);
+ PyTuple_SET_ITEM(al, da, arg);
+
+ ++a;
+ ++da;
+ }
+
+ /* Return the tuple. */
+ *va_arg(va, PyObject **) = al;
+ }
+ else
+ valid = PARSE_RAISED;
+ }
+
+ 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
+
+ callPyDtor(sipSelf);
+
+ if (!sipNotInMap(sipSelf))
+ sipOMRemoveObject(&cppPyMap,sipSelf);
+
+ /* This no longer points to anything useful. */
+ sipSelf->u.cppPtr = NULL;
+
+ /*
+ * If C/C++ has a reference (and therefore no parent) then remove it.
+ * Otherwise remove the object from any parent.
+ */
+ if (sipCppHasRef(sipSelf))
+ {
+ sipResetCppHasRef(sipSelf);
+ Py_DECREF(sipSelf);
+ }
+ else
+ removeFromParent(sipSelf);
+
+ SIP_UNBLOCK_THREADS
+ }
+}
+
+
+/*
+ * Call self.__dtor__() if it is implemented.
+ */
+static void callPyDtor(sipWrapper *self)
+{
+ sip_gilstate_t sipGILState;
+ sipMethodCache pymc;
+ PyObject *meth;
+
+ /* No need to cache the method, it will only be called once. */
+ pymc.mcflags = 0;
+ meth = sip_api_is_py_method(&sipGILState, &pymc, self, NULL, "__dtor__");
+
+ if (meth != NULL)
+ {
+ PyObject *res = sip_api_call_method(0, meth, "", NULL);
+
+ Py_DECREF(meth);
+
+ /* Discard any result. */
+ Py_XDECREF(res);
+
+ SIP_RELEASE_GIL(sipGILState);
+ }
+}
+
+
+/*
+ * Add a wrapper to it's parent owner if it has one. The wrapper must not
+ * currently have a parent and, therefore, no siblings.
+ */
+static void addToParent(sipWrapper *self, sipWrapper *owner)
+{
+ if (owner != NULL)
+ {
+ if (owner->first_child != NULL)
+ {
+ self->sibling_next = owner->first_child;
+ owner->first_child->sibling_prev = self;
+ }
+
+ owner->first_child = self;
+ self->parent = owner;
+
+ /*
+ * The owner holds a real reference so that the cyclic garbage
+ * collector works properly.
+ */
+ Py_INCREF(self);
+ }
+}
+
+
+/*
+ * Remove a wrapper from it's parent if it has one.
+ */
+static void removeFromParent(sipWrapper *self)
+{
+ if (self->parent != NULL)
+ {
+ if (self->parent->first_child == self)
+ self->parent->first_child = self->sibling_next;
+
+ if (self->sibling_next != NULL)
+ self->sibling_next->sibling_prev = self->sibling_prev;
+
+ if (self->sibling_prev != NULL)
+ self->sibling_prev->sibling_next = self->sibling_next;
+
+ self->parent = NULL;
+ self->sibling_next = NULL;
+ self->sibling_prev = NULL;
+
+ /*
+ * We must do this last, after all the pointers are correct,
+ * because this is used by the clear slot.
+ */
+ Py_DECREF(self);
+ }
+}
+
+
+/*
+ * Convert a sequence index. Return the index or a negative value if there was
+ * an error.
+ */
+static SIP_SSIZE_T sip_api_convert_from_sequence_index(SIP_SSIZE_T idx,
+ SIP_SSIZE_T len)
+{
+ /* Negative indices start from the other end. */
+ if (idx < 0)
+ idx = len + idx;
+
+ if (idx < 0 || idx >= len)
+ {
+ PyErr_Format(PyExc_IndexError, "sequence index out of range");
+ return -1;
+ }
+
+ return idx;
+}
+
+
+/*
+ * Create and return a single type object.
+ */
+static sipWrapperType *createType(sipExportedModuleDef *client,
+ sipTypeDef *type, PyObject *mod_dict)
+{
+ PyObject *name, *bases, *typedict, *args, *dict;
+ sipEncodedClassDef *sup;
+ sipWrapperType *wt;
+
+ /* Create an object corresponding to the type name. */
+ if ((name = getBaseNameObject(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_flag);
+
+ if ((bases = PyTuple_New(nrsupers)) == NULL)
+ goto relname;
+
+ for (sup = type->td_supers, i = 0; i < nrsupers; ++i, ++sup)
+ {
+ PyObject *st = (PyObject *)getClassType(sup, client);
+
+ Py_INCREF(st);
+ PyTuple_SET_ITEM(bases,i,st);
+ }
+ }
+
+ /* Create the type dictionary. */
+ if ((typedict = createTypeDict(client->em_nameobj)) == 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.sc_flag)
+ dict = mod_dict;
+ else
+ dict = ((PyTypeObject *)getClassType(&type->td_scope, client))->tp_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, sipEnumDef *ed,
+ PyObject *mod_dict)
+{
+ static PyObject *bases = NULL;
+ PyObject *name, *typedict, *args, *dict;
+ PyTypeObject *et;
+
+ /* Get the module and dictionary into which the type will be placed. */
+ if (ed->e_scope < 0)
+ dict = mod_dict;
+ else
+ dict = ((PyTypeObject *)client->em_types[ed->e_scope])->tp_dict;
+
+ /* 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 = getBaseNameObject(ed->e_name)) == NULL)
+ goto reterr;
+
+ /* Create the type dictionary. */
+ if ((typedict = createTypeDict(client->em_nameobj)) == NULL)
+ goto relname;
+
+ /* Create the type by calling the metatype. */
+ if ((args = Py_BuildValue("OOO",name,bases,typedict)) == NULL)
+ goto reldict;
+
+ if ((et = (PyTypeObject *)PyObject_Call((PyObject *)&PyType_Type,args,NULL)) == NULL)
+ goto relargs;
+
+ /* Initialise any slots. */
+ if (ed->e_pyslots != NULL)
+ initSlots(et, et->tp_as_number, et->tp_as_sequence, et->tp_as_mapping, ed->e_pyslots, TRUE);
+
+ /* 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;
+}
+
+
+/*
+ * Return a pointer to the basename of a Python "pathname".
+ */
+static const char *getBaseName(const char *name)
+{
+ const char *bn;
+
+ if ((bn = strrchr(name, '.')) != NULL)
+ ++bn;
+ else
+ bn = name;
+
+ return bn;
+}
+
+
+/*
+ * Create a Python object corresponding to the basename of a Python "pathname".
+ */
+static PyObject *getBaseNameObject(const char *name)
+{
+ return PyString_FromString(getBaseName(name));
+}
+
+
+/*
+ * Create a type dictionary for dynamic type being created in the module with
+ * the specified name.
+ */
+static PyObject *createTypeDict(PyObject *mname)
+{
+ static PyObject *proto = NULL;
+ static PyObject *mstr = NULL;
+ PyObject *dict;
+
+ /* Create a prototype dictionary. */
+ if (proto == NULL)
+ {
+ if ((proto = PyDict_New()) == NULL)
+ return NULL;
+
+ /*
+ * These tell pickle that SIP generated classes can't be
+ * pickled.
+ */
+ if (PyDict_SetItemString(proto, "__reduce_ex__", Py_None) < 0 ||
+ PyDict_SetItemString(proto, "__reduce__", Py_None) < 0)
+ {
+ Py_DECREF(proto);
+ proto = NULL;
+
+ return NULL;
+ }
+ }
+
+ /* Create an object for "__module__". */
+ if (mstr == NULL && (mstr = PyString_FromString("__module__")) == NULL)
+ return NULL;
+
+ if ((dict = PyDict_Copy(proto)) == 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_int != NULL && addIntInstances(dict, id->id_int) < 0)
+ return -1;
+
+ if (id->id_long != NULL && addLongInstances(dict,id->id_long) < 0)
+ return -1;
+
+ if (id->id_ulong != NULL && addUnsignedLongInstances(dict, id->id_ulong) < 0)
+ return -1;
+
+ if (id->id_llong != NULL && addLongLongInstances(dict, id->id_llong) < 0)
+ return -1;
+
+ if (id->id_ullong != NULL && addUnsignedLongLongInstances(dict, id->id_ullong) < 0)
+ return -1;
+
+ if (id->id_double != NULL && addDoubleInstances(dict,id->id_double) < 0)
+ return -1;
+
+ 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, (PyTypeObject *)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;
+
+ /* 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;
+ sipTypeDef *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. Note that we cannot cache
+ * it in the type dictionary because a sub-type might have a
+ * lazy attribute of the same name. In this case (because we
+ * call the standard getattro code first) this one would be
+ * wrongly found in preference to the one in the sub-class.
+ * The example in PyQt is QScrollView::ResizePolicy and
+ * QListView::WidthMode both having a member called Manual.
+ * One way around this might be to cache them in a separate
+ * dictionary and search that before doing the binary search
+ * through the lazy enum table.
+ */
+ if ((attr = createEnumMember(in, enm)) == NULL)
+ 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(sipTypeDef *td, sipEnumMemberDef *enm)
+{
+ if (enm->em_enum < 0)
+ return PyInt_FromLong(enm->em_val);
+
+ return sip_api_convert_from_named_enum(enm->em_val, td->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,
+ sipTypeDef **in)
+{
+ sipTypeDef *td, *nsx;
+ sipEncodedClassDef *sup;
+
+ /* The base type doesn't have any type information. */
+ if ((td = wt->type) == NULL)
+ return;
+
+ /* Search the possible linked list of namespace extenders. */
+ nsx = td;
+
+ do
+ {
+ /* Try the methods. */
+ if (nsx->td_nrmethods > 0 &&
+ (*pmdp = (PyMethodDef *)bsearch(name, nsx->td_methods, nsx->td_nrmethods, sizeof (PyMethodDef), compareMethodName)) != NULL)
+ return;
+
+ /* Try the enum members. */
+ if (nsx->td_nrenummembers > 0 &&
+ (*enmp = (sipEnumMemberDef *)bsearch(name, nsx->td_enummembers, nsx->td_nrenummembers, sizeof (sipEnumMemberDef), compareEnumMemberName)) != NULL)
+ {
+ if (in != NULL)
+ *in = nsx;
+
+ return;
+ }
+
+ /* Try the variables. Note, these aren't sorted. */
+ if (nsx->td_variables != NULL)
+ {
+ PyMethodDef *md;
+
+ for (md = nsx->td_variables; md->ml_name != NULL; ++md)
+ if (strcmp(name, md->ml_name) == 0)
+ {
+ *vmdp = md;
+ return;
+ }
+ }
+
+ nsx = nsx->td_nsextender;
+ }
+ while (nsx != NULL);
+
+ /* Check the base classes. */
+ if ((sup = td->td_supers) != NULL)
+ do
+ {
+ findLazyAttr(getClassType(sup, td->td_module), name, pmdp, enmp, vmdp, in);
+
+ if (*pmdp != NULL || *enmp != NULL || *vmdp != NULL)
+ break;
+ }
+ while (!sup++->sc_flag);
+}
+
+
+/*
+ * 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 function with invalid argument types.
+ */
+static void sip_api_no_function(int argsParsed, const char *func)
+{
+ badArgs(argsParsed,NULL,func);
+}
+
+
+/*
+ * Report a method/function/signal with invalid argument types.
+ */
+static void sip_api_no_method(int argsParsed, const char *classname, const char *method)
+{
+ badArgs(argsParsed,classname,method);
+}
+
+
+/*
+ * Report an abstract method called with an unbound self.
+ */
+static void sip_api_abstract_method(const char *classname, const char *method)
+{
+ PyErr_Format(PyExc_TypeError,"%s.%s() is abstract and cannot be called as an unbound method", classname, method);
+}
+
+
+/*
+ * Handle error reporting for bad arguments to various things.
+ */
+static void badArgs(int argsParsed, const char *classname, const 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:
+ /* This is raised by a private re-implementation. */
+ PyErr_Format(PyExc_AttributeError,"%s%s%s is a private method",classname,sep,method);
+ break;
+ }
+}
+
+
+/*
+ * Report a bad operator argument. Only a small subset of operators need to
+ * be handled (those that don't return Py_NotImplemented).
+ */
+static void sip_api_bad_operator_arg(PyObject *self, PyObject *arg,
+ sipPySlotType st)
+{
+ const char *sn = NULL;
+
+ /* Try and get the text to match a Python exception. */
+
+ switch (st)
+ {
+ case concat_slot:
+ case iconcat_slot:
+ PyErr_Format(PyExc_TypeError, "cannot concatenate '%s' and '%s' objects", self->ob_type->tp_name, arg->ob_type->tp_name);
+ break;
+
+ case repeat_slot:
+ sn = "*";
+ break;
+
+ case irepeat_slot:
+ sn = "*=";
+ break;
+
+ default:
+ sn = "unknown";
+ }
+
+ if (sn != NULL)
+ PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %s: '%s' and '%s'", sn, self->ob_type->tp_name, arg->ob_type->tp_name);
+}
+
+
+/*
+ * Report a sequence length that does not match the length of a slice.
+ */
+static void sip_api_bad_length_for_slice(SIP_SSIZE_T seqlen,
+ SIP_SSIZE_T slicelen)
+{
+ PyErr_Format(PyExc_ValueError,
+#if PY_VERSION_HEX >= 0x02050000
+ "attempt to assign sequence of size %zd to slice of size %zd",
+#else
+ "attempt to assign sequence of size %d to slice of size %d",
+#endif
+ seqlen, slicelen);
+}
+
+
+/*
+ * Report a Python object that cannot be converted to a particular class.
+ */
+static void sip_api_bad_class(const char *classname)
+{
+ PyErr_Format(PyExc_TypeError,"cannot convert Python object to an instance of %s",classname);
+}
+
+
+/*
+ * Report a Python 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)
+{
+ const char *cname;
+ char *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 sip_api_wrapper_check(PyObject *o)
+{
+ return PyObject_TypeCheck(o,(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 ownership of a class instance to Python from C/C++.
+ */
+static void sip_api_transfer_back(PyObject *self)
+{
+ if (self != NULL && sip_api_wrapper_check(self))
+ {
+ sipWrapper *w = (sipWrapper *)self;
+
+ if (sipCppHasRef(w))
+ {
+ sipResetCppHasRef(w);
+ Py_DECREF(w);
+ }
+ else
+ removeFromParent(w);
+
+ sipSetPyOwned(w);
+ }
+}
+
+
+/*
+ * Transfer ownership of a class instance to C/C++ from Python.
+ */
+static void sip_api_transfer_to(PyObject *self, PyObject *owner)
+{
+ /*
+ * There is a legitimate case where we try to transfer a PyObject that
+ * may not be a SIP generated class. The virtual handler code calls
+ * this function to keep the C/C++ instance alive when it gets rid of
+ * the Python object returned by the Python method. A class may have
+ * handwritten code that converts a regular Python type - so we can't
+ * assume that we can simply cast to sipWrapper.
+ */
+ if (self != NULL && sip_api_wrapper_check(self) && (owner == NULL || sip_api_wrapper_check(owner)))
+ {
+ sipWrapper *w = (sipWrapper *)self;
+
+ /*
+ * Keep the object alive while we do the transfer. If C++ has a
+ * reference then there is no need to increment it, just reset the flag
+ * and the following decrement will bring everything back to the way it
+ * should be.
+ */
+ if (sipCppHasRef(w))
+ sipResetCppHasRef(w);
+ else
+ {
+ Py_INCREF(self);
+ removeFromParent(w);
+ }
+
+ addToParent(w, (sipWrapper *)owner);
+
+ Py_DECREF(self);
+
+ sipResetPyOwned(w);
+ }
+}
+
+
+/*
+ * Transfer ownership of a class instance from Python to C/C++, or vice versa.
+ * This is deprecated.
+ */
+static void sip_api_transfer(PyObject *self, int toCpp)
+{
+ if (toCpp)
+ sip_api_transfer_to(self, self);
+ else
+ sip_api_transfer_back(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 int instances to a dictionary.
+ */
+static int addIntInstances(PyObject *dict, sipIntInstanceDef *ii)
+{
+ while (ii->ii_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+ if ((w = PyInt_FromLong(ii->ii_val)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict, ii->ii_name, w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++ii;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add the long instances to a dictionary.
+ */
+static int addLongInstances(PyObject *dict,sipLongInstanceDef *li)
+{
+ while (li->li_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+ if ((w = PyLong_FromLong(li->li_val)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict,li->li_name,w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++li;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add the unsigned long instances to a dictionary.
+ */
+static int addUnsignedLongInstances(PyObject *dict, sipUnsignedLongInstanceDef *uli)
+{
+ while (uli->uli_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+ if ((w = PyLong_FromUnsignedLong(uli->uli_val)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict, uli->uli_name, w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++uli;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add the long long instances to a dictionary.
+ */
+static int addLongLongInstances(PyObject *dict, sipLongLongInstanceDef *lli)
+{
+ while (lli->lli_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+#if defined(HAVE_LONG_LONG)
+ if ((w = PyLong_FromLongLong(lli->lli_val)) == NULL)
+#else
+ if ((w = PyLong_FromLong(lli->lli_val)) == NULL)
+#endif
+ return -1;
+
+ rc = PyDict_SetItemString(dict, lli->lli_name, w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++lli;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add the unsigned long long instances to a dictionary.
+ */
+static int addUnsignedLongLongInstances(PyObject *dict, sipUnsignedLongLongInstanceDef *ulli)
+{
+ while (ulli->ulli_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+#if defined(HAVE_LONG_LONG)
+ if ((w = PyLong_FromUnsignedLongLong(ulli->ulli_val)) == NULL)
+#else
+ if ((w = PyLong_FromUnsignedLong(ulli->ulli_val)) == NULL)
+#endif
+ return -1;
+
+ rc = PyDict_SetItemString(dict, ulli->ulli_name, w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++ulli;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add the double instances to a dictionary.
+ */
+static int addDoubleInstances(PyObject *dict,sipDoubleInstanceDef *di)
+{
+ while (di->di_name != NULL)
+ {
+ int rc;
+ PyObject *w;
+
+ if ((w = PyFloat_FromDouble(di->di_val)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict,di->di_name,w);
+ Py_DECREF(w);
+
+ if (rc < 0)
+ return -1;
+
+ ++di;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Wrap a set of enum instances and add them to a dictionary.
+ */
+static int addEnumInstances(PyObject *dict, sipEnumInstanceDef *ei)
+{
+ while (ei->ei_name != NULL)
+ {
+ if (addSingleEnumInstance(dict, ei->ei_name, ei->ei_val, *ei->ei_type) < 0)
+ return -1;
+
+ ++ei;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Wrap a single enum instance and add it to a dictionary.
+ */
+static int addSingleEnumInstance(PyObject *dict, const char *name, int value,
+ PyTypeObject *type)
+{
+ int rc;
+ PyObject *w;
+
+ if ((w = sip_api_convert_from_named_enum(value, type)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict, name, w);
+ Py_DECREF(w);
+
+ return rc;
+}
+
+
+/*
+ * Wrap an enum instance and add it to a dictionary.
+ */
+static int sip_api_add_enum_instance(PyObject *dict, const char *name,
+ int value, PyTypeObject *type)
+{
+ /* If this is a wrapped type then get the type dictionary. */
+ if (sipWrapperType_Check(dict))
+ dict = ((PyTypeObject *)dict)->tp_dict;
+
+ return addSingleEnumInstance(dict, name, value, type);
+}
+
+
+/*
+ * 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, const char *name,
+ void *cppPtr, sipWrapperType *wt, int initflags)
+{
+ int rc;
+ PyObject *w;
+
+ if ((w = sipWrapSimpleInstance(cppPtr,wt,NULL,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, const char *name,
+ void *cppPtr, sipWrapperType *wt)
+{
+ /* If this is a wrapped type then get the type dictionary. */
+ if (sipWrapperType_Check(dict))
+ dict = ((PyTypeObject *)dict)->tp_dict;
+
+ return addSingleClassInstance(dict, name, cppPtr, wt, 0);
+}
+
+
+/*
+ * Wrap a mapped type instance and add it to a dictionary.
+ */
+static int sip_api_add_mapped_type_instance(PyObject *dict, const char *name,
+ void *cppPtr, const sipMappedType *mt)
+{
+ int rc;
+ PyObject *w;
+
+ /* If this is a wrapped type then get the type dictionary. */
+ if (sipWrapperType_Check(dict))
+ dict = ((PyTypeObject *)dict)->tp_dict;
+
+ if ((w = mt->mt_cfrom(cppPtr, NULL)) == NULL)
+ return -1;
+
+ rc = PyDict_SetItemString(dict, name, w);
+ Py_DECREF(w);
+
+ return rc;
+}
+
+
+/*
+ * Get the C/C++ pointer for a complex object.
+ */
+static void *sip_api_get_complex_cpp_ptr(sipWrapper *w)
+{
+ if (!sipIsDerived(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)
+{
+ /* 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;
+}
+
+
+/*
+ * 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);
+}
+
+
+/*
+ * Return the C/C++ pointer from a wrapper without any checks.
+ */
+void *sipGetAddress(sipWrapper *w)
+{
+ if (sipIsAccessFunc(w))
+ return (*w->u.afPtr)();
+
+ if (sipIsIndirect(w))
+ return *((void **)w->u.cppPtr);
+
+ return w->u.cppPtr;
+}
+
+
+/*
+ * 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 = sipGetAddress(w);
+
+ if (checkPointer(ptr) < 0)
+ return NULL;
+
+ if (type != NULL)
+ ptr = cast_cpp_ptr(ptr, (sipWrapperType *)w->ob_type, type);
+
+ return ptr;
+}
+
+
+/*
+ * Cast a C/C++ pointer from a source type to a destination type.
+ */
+static void *cast_cpp_ptr(void *ptr, sipWrapperType *src_type,
+ sipWrapperType *dst_type)
+{
+ sipCastFunc cast = src_type->type->td_cast;
+
+ /* C structures don't have cast functions. */
+ if (cast != NULL)
+ ptr = (*cast)(ptr, dst_type);
+
+ return ptr;
+}
+
+
+/*
+ * Check that a pointer is non-NULL.
+ */
+static int checkPointer(void *ptr)
+{
+ if (ptr == NULL)
+ {
+ PyErr_SetString(PyExc_RuntimeError,"underlying C/C++ object has been deleted");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Check to see if a Python object can be converted to a wrapped type.
+ */
+static int sip_api_can_convert_to_instance(PyObject *pyObj,
+ sipWrapperType *type, int flags)
+{
+ int ok;
+ sipConvertToFunc cto = type->type->td_cto;
+
+ /* None is handled outside the type checkers. */
+ if (pyObj == Py_None)
+ ok = ((flags & SIP_NOT_NONE) == 0);
+ else if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0)
+ ok = PyObject_TypeCheck(pyObj, (PyTypeObject *)type);
+ else
+ ok = cto(pyObj, NULL, NULL, NULL);
+
+ return ok;
+}
+
+
+/*
+ * Check to see if a Python object can be converted to a mapped type.
+ */
+static int sip_api_can_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt,
+ int flags)
+{
+ int ok;
+
+ /* None is handled outside the type checkers. */
+ if (pyObj == Py_None)
+ ok = ((flags & SIP_NOT_NONE) == 0);
+ else
+ ok = mt->mt_cto(pyObj, NULL, NULL, NULL);
+
+ return ok;
+}
+
+
+/*
+ * Convert a Python object to a C/C++ pointer, assuming a previous call to
+ * sip_api_can_convert_to_instance() has been successful. Allow ownership to
+ * be transferred and any type convertors to be disabled.
+ */
+static void *sip_api_convert_to_instance(PyObject *pyObj, sipWrapperType *type,
+ PyObject *transferObj, int flags,
+ int *statep, int *iserrp)
+{
+ void *cpp = NULL;
+ int state = 0;
+ sipConvertToFunc cto = type->type->td_cto;
+
+ /* Don't convert if there has already been an error. */
+ if (!*iserrp)
+ {
+ /* Do the conversion. */
+ if (pyObj == Py_None)
+ cpp = NULL;
+ else if (cto == NULL || (flags & SIP_NO_CONVERTORS) != 0)
+ {
+ if ((cpp = sip_api_get_cpp_ptr((sipWrapper *)pyObj, type)) == NULL)
+ *iserrp = TRUE;
+ else if (transferObj != NULL)
+ if (transferObj == Py_None)
+ sip_api_transfer_back(pyObj);
+ else
+ sip_api_transfer_to(pyObj, transferObj);
+ }
+ else
+ state = cto(pyObj, &cpp, iserrp, transferObj);
+ }
+
+ if (statep != NULL)
+ *statep = state;
+
+ return cpp;
+}
+
+
+/*
+ * Convert a Python object to a C/C++ pointer, assuming a previous call to
+ * sip_api_can_convert_to_mapped_type() has been successful. Allow ownership
+ * to be transferred.
+ */
+static void *sip_api_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt,
+ PyObject *transferObj, int flags,
+ int *statep, int *iserrp)
+{
+ void *cpp = NULL;
+ int state = 0;
+
+ /* Don't convert if there has already been an error. */
+ if (!*iserrp)
+ if (pyObj == Py_None)
+ cpp = NULL;
+ else
+ state = mt->mt_cto(pyObj, &cpp, iserrp, transferObj);
+
+ if (statep != NULL)
+ *statep = state;
+
+ return cpp;
+}
+
+
+/*
+ * Convert a Python object to a C/C++ pointer and raise an exception if it
+ * can't be done.
+ */
+static void *sip_api_force_convert_to_instance(PyObject *pyObj,
+ sipWrapperType *type,
+ PyObject *transferObj,
+ int flags, int *statep,
+ int *iserrp)
+{
+ /* Don't even try if there has already been an error. */
+ if (*iserrp)
+ return NULL;
+
+ /* See if the object's type can be converted. */
+ if (!sip_api_can_convert_to_instance(pyObj, type, flags))
+ {
+ PyErr_Format(PyExc_TypeError, "%s cannot be converted to %s in this context", pyObj->ob_type->tp_name, type->type->td_name);
+
+ if (statep != NULL)
+ *statep = 0;
+
+ *iserrp = TRUE;
+ return NULL;
+ }
+
+ /* Do the conversion. */
+ return sip_api_convert_to_instance(pyObj, type, transferObj, flags, statep, iserrp);
+}
+
+
+/*
+ * Convert a Python object to a C/C++ pointer and raise an exception if it
+ * can't be done.
+ */
+static void *sip_api_force_convert_to_mapped_type(PyObject *pyObj,
+ const sipMappedType *mt,
+ PyObject *transferObj,
+ int flags, int *statep,
+ int *iserrp)
+{
+ /* Don't even try if there has already been an error. */
+ if (*iserrp)
+ return NULL;
+
+ /* See if the object's type can be converted. */
+ if (!sip_api_can_convert_to_mapped_type(pyObj, mt, flags))
+ {
+ PyErr_Format(PyExc_TypeError, "%s cannot be converted to %s in this context", pyObj->ob_type->tp_name, mt->mt_name);
+
+ if (statep != NULL)
+ *statep = 0;
+
+ *iserrp = TRUE;
+ return NULL;
+ }
+
+ /* Do the conversion. */
+ return sip_api_convert_to_mapped_type(pyObj, mt, transferObj, flags, statep, iserrp);
+}
+
+
+/*
+ * Release a possibly temporary instance created by a type convertor.
+ */
+static void sip_api_release_instance(void *cpp, sipWrapperType *type, int state)
+{
+ /* See if there is something to release. */
+ if (state & SIP_TEMPORARY)
+ release(cpp, type->type, state);
+}
+
+
+/*
+ * Release an instance.
+ */
+static void release(void *addr, sipTypeDef *td, int state)
+{
+ sipReleaseFunc rel = td->td_release;
+
+ /*
+ * If there is no release function then it must be a C structure and we can
+ * just free it.
+ */
+ if (rel == NULL)
+ sip_api_free(addr);
+ else
+ rel(addr, state);
+}
+
+
+/*
+ * Release a possibly temporary mapped type created by a type convertor.
+ */
+static void sip_api_release_mapped_type(void *cpp, const sipMappedType *mt,
+ int state)
+{
+ /* See if there is something to release. */
+ if (state & SIP_TEMPORARY)
+ {
+ sipReleaseFunc rel = mt->mt_release;
+
+ /*
+ * If there is no release function then it must be a C
+ * structure and we can just free it.
+ */
+ if (rel == NULL)
+ sip_api_free(cpp);
+ else
+ rel(cpp, state);
+ }
+}
+
+
+/*
+ * Convert a C/C++ instance to a Python instance.
+ */
+PyObject *sip_api_convert_from_instance(void *cpp, sipWrapperType *type,
+ PyObject *transferObj)
+{
+ PyObject *py;
+
+ /* Handle None. */
+ if (cpp == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ /* Apply any sub-class convertor. */
+ if (sipTypeHasSCC(type))
+ type = convertSubClass(type, &cpp);
+
+ /* See if we have already wrapped it. */
+ if ((py = sip_api_get_wrapper(cpp, type)) != NULL)
+ Py_INCREF(py);
+ else if ((py = sipWrapSimpleInstance(cpp, type, NULL, SIP_SHARE_MAP)) == NULL)
+ return NULL;
+
+ /* Handle any ownership transfer. */
+ if (transferObj != NULL)
+ if (transferObj == Py_None)
+ sip_api_transfer_back(py);
+ else
+ sip_api_transfer_to(py, transferObj);
+
+ return py;
+}
+
+
+/*
+ * Convert a new C/C++ instance to a Python instance.
+ */
+static PyObject *sip_api_convert_from_new_instance(void *cpp,
+ sipWrapperType *type,
+ PyObject *transferObj)
+{
+ sipWrapper *owner;
+
+ /* Handle None. */
+ if (cpp == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ /* Apply any sub-class convertor. */
+ if (sipTypeHasSCC(type))
+ type = convertSubClass(type, &cpp);
+
+ /* Handle any ownership transfer. */
+ if (transferObj != NULL && transferObj != Py_None)
+ owner = (sipWrapper *)transferObj;
+ else
+ owner = NULL;
+
+ return sipWrapSimpleInstance(cpp, type, owner, (owner == NULL ? SIP_PY_OWNED : 0));
+}
+
+
+/*
+ * Convert a C/C++ instance implemented as a mapped type to a Python object.
+ */
+static PyObject *sip_api_convert_from_mapped_type(void *cpp,
+ const sipMappedType *mt,
+ PyObject *transferObj)
+{
+ /* Handle None. */
+ if (cpp == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return mt->mt_cfrom(cpp, transferObj);
+}
+
+
+/*
+ * 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)
+{
+ return sip_api_convert_to_instance(sipSelf, type, NULL, SIP_NO_CONVERTORS, NULL, iserrp);
+}
+
+
+/*
+ * Implement the normal transfer policy for the result of %ConvertToTypeCode,
+ * ie. it is temporary unless it is being transferred from Python.
+ */
+int sip_api_get_state(PyObject *transferObj)
+{
+ return (transferObj == NULL || transferObj == Py_None) ? SIP_TEMPORARY : 0;
+}
+
+
+/*
+ * Return the mapped type structure for a particular mapped type.
+ */
+static const sipMappedType *sip_api_find_mapped_type(const char *type)
+{
+ sipExportedModuleDef *em;
+
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ sipMappedType **mtypes, *mt;
+
+ if ((mtypes = em->em_mappedtypes) == NULL)
+ continue;
+
+ while ((mt = *mtypes++) != NULL)
+ {
+ const char *s1 = mt->mt_name, *s2 = type;
+
+ /*
+ * Compare while ignoring spaces so that we don't impose a rigorous
+ * naming standard.
+ */
+ do
+ {
+ while (*s1 == ' ')
+ ++s1;
+
+ while (*s2 == ' ')
+ ++s2;
+
+ if (*s1 == '\0' && *s2 == '\0')
+ return mt;
+ }
+ while (*s1++ == *s2++);
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Return the type structure for a particular class.
+ */
+static sipWrapperType *sip_api_find_class(const char *type)
+{
+ sipExportedModuleDef *em;
+ size_t type_len = strlen(type);
+
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ sipWrapperType *wt = findClass(em, type, type_len);
+
+ if (wt != NULL)
+ return wt;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Return the type structure for a particular named enum.
+ */
+static PyTypeObject *sip_api_find_named_enum(const char *type)
+{
+ sipExportedModuleDef *em;
+ size_t type_len = strlen(type);
+
+ for (em = clientList; em != NULL; em = em->em_next)
+ {
+ PyTypeObject *py = findEnum(em, type, type_len);
+
+ if (py != NULL)
+ return py;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Save the components of a Python method.
+ */
+void sipSaveMethod(sipPyMethod *pm,PyObject *meth)
+{
+ pm->mfunc = PyMethod_GET_FUNCTION(meth);
+ pm->mself = PyMethod_GET_SELF(meth);
+ pm->mclass = PyMethod_GET_CLASS(meth);
+}
+
+
+/*
+ * Call a hook.
+ */
+static void sip_api_call_hook(const char *hookname)
+{
+ PyObject *dictofmods, *mod, *dict, *hook, *res;
+
+ /* Get the dictionary of modules. */
+ if ((dictofmods = PyImport_GetModuleDict()) == NULL)
+ return;
+
+ /* Get the __builtin__ module. */
+ if ((mod = PyDict_GetItemString(dictofmods,"__builtin__")) == NULL)
+ return;
+
+ /* Get it's dictionary. */
+ if ((dict = PyModule_GetDict(mod)) == NULL)
+ return;
+
+ /* Get the function hook. */
+ if ((hook = PyDict_GetItemString(dict,hookname)) == NULL)
+ return;
+
+ /* Call the hook and discard any result. */
+ res = PyObject_CallObject(hook,NULL);
+
+ Py_XDECREF(res);
+}
+
+
+/*
+ * Call any sub-class convertors for a given type returning a pointer to the
+ * sub-type object, and possibly modifying the C++ address (in the case of
+ * multiple inheritence).
+ */
+static sipWrapperType *convertSubClass(sipWrapperType *type, void **cppPtr)
+{
+ sipExportedModuleDef *em;
+
+ if (*cppPtr == NULL)
+ return NULL;
+
+ /*
+ * Note that this code depends on the fact that a module appears in the
+ * list of modules before any module it imports, ie. sub-class convertors
+ * will be invoked for more specific types first.
+ */
+ for (em = 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((PyTypeObject *)type, (PyTypeObject *)scc->scc_basetype))
+ {
+ void *ptr;
+ sipWrapperType *subtype;
+
+ ptr = cast_cpp_ptr(*cppPtr, type, scc->scc_basetype);
+ subtype = (*scc->scc_convertor)(&ptr);
+
+ /*
+ * We are only interested in types that are not super-classes
+ * of the target. This happens either because it is in an
+ * earlier convertor than the one that handles the type or it
+ * is in a later convertor that handles a different branch of
+ * the hierarchy. Either way, the ordering of the modules
+ * ensures that there will be no more than one and that it will
+ * be the right one.
+ */
+ if (subtype != NULL && !PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)subtype))
+ {
+ *cppPtr = ptr;
+ return subtype;
+ }
+ }
+
+ ++scc;
+ }
+ }
+
+ /*
+ * We haven't found the exact type, so return the most specific type that
+ * it must be. This can happen legitimately if the wrapped library is
+ * returning an internal class that is down-cast to a more generic class.
+ * Also we want this function to be safe when a class doesn't have any
+ * convertors.
+ */
+ return 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 = sipWrapSimpleInstance(ptr,type,NULL,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 = sipWrapSimpleInstance(ptr,type,NULL,SIP_PY_OWNED);
+
+ PyErr_SetObject((PyObject *)type,self);
+
+ Py_XDECREF(self);
+
+ SIP_UNBLOCK_THREADS
+}
+
+
+/*
+ * Return the module of an encoded class.
+ */
+static sipExportedModuleDef *getClassModule(sipEncodedClassDef *enc,
+ sipExportedModuleDef *em)
+{
+ if (enc->sc_module != 255)
+ em = em->em_imports[enc->sc_module].im_module;
+
+ return em;
+}
+
+
+/*
+ * Return the type of an encoded class.
+ */
+static sipWrapperType *getClassType(sipEncodedClassDef *enc,
+ sipExportedModuleDef *em)
+{
+ return getClassModule(enc, em)->em_types[enc->sc_class];
+}
+
+
+/*
+ * Find a particular slot function for a wrapper.
+ */
+static void *findSlot(PyObject *self,sipPySlotType st)
+{
+ sipTypeDef *td = ((sipWrapperType *)(self->ob_type))->type;
+ sipEncodedClassDef *sup;
+ void *slot;
+
+ /* Check the immediate type. */
+ if ((slot = findSlotInType(td, st)) != NULL)
+ return slot;
+
+ /* Check the super-types, if there are any. */
+ if ((sup = td->td_supers) != NULL)
+ do
+ if ((slot = findSlotInType(getClassType(sup, td->td_module)->type, st)) != NULL)
+ return slot;
+ while (!sup++->sc_flag);
+
+ /* This should never happen. */
+ return NULL;
+}
+
+
+/*
+ * Find a particular slot function in a type.
+ */
+static void *findSlotInType(sipTypeDef *td, sipPySlotType st)
+{
+ sipPySlotDef *psd;
+
+ if ((psd = td->td_pyslots) != NULL)
+ while (psd->psd_func != NULL)
+ {
+ if (psd->psd_type == st)
+ return psd->psd_func;
+
+ ++psd;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Return the C/C++ address and the basic type information for a wrapper.
+ */
+static void *getPtrTypeDef(sipWrapper *self, sipTypeDef **td)
+{
+ *td = ((sipWrapperType *)self->ob_type)->type;
+
+ return (sipNotInMap(self) ? NULL : self->u.cppPtr);
+}
+
+
+/*
+ * Handle an objobjargproc slot.
+ */
+static int objobjargprocSlot(PyObject *self,PyObject *arg1,PyObject *arg2,
+ sipPySlotType st)
+{
+ int (*f)(PyObject *,PyObject *);
+ 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 ssizeobjargproc slot.
+ */
+static int ssizeobjargprocSlot(PyObject *self, SIP_SSIZE_T 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)
+#if PY_VERSION_HEX >= 0x02050000
+ args = PyInt_FromSsize_t(arg1);
+#else
+ args = PyInt_FromLong(arg1);
+#endif
+ else
+#if PY_VERSION_HEX >= 0x02050000
+ args = Py_BuildValue("(nO)", arg1, arg2);
+#else
+ args = Py_BuildValue("(iO)", arg1, arg2);
+#endif
+
+ if (args == NULL)
+ return -1;
+
+ 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 __new__ for the type.
+ */
+static PyObject *sipVoidPtr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+ void *ptr;
+ int nargs, bad;
+
+ /* We don't support keyword arguments. */
+ if (kwds != NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported");
+ return NULL;
+ }
+
+ /* Get the single argument. */
+ if ((nargs = PyTuple_Size(args)) < 0)
+ return NULL;
+
+ bad = FALSE;
+
+ if (nargs == 1)
+ {
+ PyObject *arg = PyTuple_GET_ITEM(args, 0);
+
+ if (arg == Py_None)
+ ptr = NULL;
+ else if (PyCObject_Check(arg))
+ ptr = PyCObject_AsVoidPtr(arg);
+ else if (arg->ob_type == &sipVoidPtr_Type)
+ {
+ /*
+ * The type is immutable so just return the argument.
+ */
+ Py_INCREF(arg);
+ return arg;
+ }
+ else
+ {
+ ptr = (void *)PyInt_AsLong(arg);
+
+ if (PyErr_Occurred())
+ bad = TRUE;
+ }
+ }
+ else
+ bad = TRUE;
+
+ if (bad)
+ {
+ PyErr_SetString(PyExc_TypeError, "a single integer, CObject, None or another voidptr is required");
+ return NULL;
+ }
+
+ /* Create the instance. */
+ if ((obj = subtype->tp_alloc(subtype, 0)) == NULL)
+ return NULL;
+
+ /* Save the pointer. */
+ ((sipVoidPtr *)obj)->voidptr = ptr;
+
+ return obj;
+}
+
+
+/*
+ * Implement int() for the type.
+ */
+static PyObject *sipVoidPtr_int(sipVoidPtr *v)
+{
+ return PyInt_FromLong((long)v->voidptr);
+}
+
+
+/*
+ * Implement hex() for the type.
+ */
+static PyObject *sipVoidPtr_hex(sipVoidPtr *v)
+{
+ char buf[2 + 16 + 1];
+
+ PyOS_snprintf(buf, sizeof (buf), "0x%.*lx", (int)(sizeof (void *) * 2), (unsigned long)v->voidptr);
+
+ return PyString_FromString(buf);
+}
+
+
+/*
+ * Implement ascobject() for the type.
+ */
+static PyObject *sipVoidPtr_ascobject(sipVoidPtr *v, PyObject *arg)
+{
+ return PyCObject_FromVoidPtr(v->voidptr, NULL);
+}
+
+
+/*
+ * 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[] = {
+ {"ascobject", (PyCFunction)sipVoidPtr_ascobject, METH_NOARGS, NULL},
+ {"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 */
+ 0, /* nb_long */
+ 0, /* nb_float */
+ 0, /* nb_oct */
+ (unaryfunc)sipVoidPtr_hex, /* nb_hex */
+};
+
+
+/* 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 */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ sipVoidPtr_new, /* tp_new */
+};
+
+
+/*
+ * 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;
+
+ /* Save a conversion if it's not a sub-type. */
+ 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;
+}
+
+
+/*
+ * Return TRUE if a type is a wrapped type, rather than a sub-type implemented
+ * in Python or the super-type.
+ */
+static int isExactWrappedType(sipWrapperType *wt)
+{
+ char *name;
+
+ /*
+ * We check by comparing the actual type name with the name used to create
+ * the original wrapped type.
+ */
+#if PY_VERSION_HEX >= 0x02050000
+ if ((name = PyString_AsString(wt->super.ht_name)) == NULL)
+#else
+ if ((name = PyString_AsString(wt->super.name)) == NULL)
+#endif
+ return FALSE;
+
+ return (strcmp(name, getBaseName(wt->type->td_name)) == 0);
+}
+
+
+/*****************************************************************************
+ * The Python metatype for a C++ wrapper type.
+ *****************************************************************************/
+
+/*
+ * The type alloc slot.
+ */
+static PyObject *sipWrapperType_alloc(PyTypeObject *self, SIP_SSIZE_T nitems)
+{
+ PyObject *o;
+
+ /* Call the standard super-metatype alloc. */
+ if ((o = PyType_Type.tp_alloc(self, nitems)) == NULL)
+ return NULL;
+
+ /*
+ * Consume any extra type specific information and use it to initialise
+ * the slots. This only happens for directly wrapped classes (and not
+ * programmer written sub-classes). This must be done in the alloc
+ * function because it is the only place we can break out of the
+ * default new() function before PyType_Ready() is called.
+ */
+ if (currentType != NULL)
+ {
+ ((sipWrapperType *)o)->type = currentType;
+ 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)
+ {
+ PyTypeObject *sc = ((PyTypeObject *)self)->tp_base;
+
+ /*
+ * Make sure that the type is derived from sip.wrapper. It might not
+ * if the type specifies sip.wrappertype as the __metaclass__.
+ */
+ if (sc == NULL || !sipWrapperType_Check((PyObject *)sc))
+ {
+ PyErr_Format(PyExc_TypeError,
+ "type %s must be derived from sip.wrapper",
+ ((PyTypeObject *)self)->tp_name);
+
+ return -1;
+ }
+
+ self->type = ((sipWrapperType *)sc)->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 for a base wrapped type 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;
+ PyMethodDef *pmd;
+
+ dict = ((PyTypeObject *)wt)->tp_dict;
+
+ /* The base type doesn't have any type information. */
+ if ((td = wt->type) == NULL || !isExactWrappedType(wt))
+ {
+ Py_INCREF(dict);
+ return 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 ((dict = PyDict_Copy(dict)) == NULL)
+ return NULL;
+
+ /* Search the possible linked list of namespace extenders. */
+ do
+ {
+ /*
+ * 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(td, enm)) == NULL)
+ return NULL;
+
+ rc = PyDict_SetItemString(dict, enm->em_name, val);
+
+ Py_DECREF(val);
+
+ if (rc < 0)
+ return NULL;
+
+ ++enm;
+ }
+
+ /* 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(dict);
+ return NULL;
+ }
+
+ rc = PyDict_SetItemString(dict, pmd->ml_name, meth);
+
+ Py_DECREF(meth);
+
+ if (rc < 0)
+ {
+ Py_DECREF(dict);
+ 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(dict);
+ return NULL;
+ }
+
+ rc = PyDict_SetItemString(dict, pmd->ml_name, val);
+
+ Py_DECREF(val);
+
+ if (rc < 0)
+ {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ }
+
+ ++pmd;
+ }
+
+ td = td->td_nsextender;
+ }
+ while (td != NULL);
+
+ return dict;
+ }
+
+ /* 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 that cannot be instantiated", wt->type->td_name);
+
+ return NULL;
+ }
+
+ /*
+ * See if the object is being created explicitly rather than being wrapped.
+ */
+ if (sipGetPending(NULL, NULL) == NULL)
+ {
+ /*
+ * See if it cannot be instantiated or sub-classed from Python, eg.
+ * it's an opaque class. Some restrictions might be overcome with
+ * better SIP support.
+ */
+ if (wt->type->td_init == NULL)
+ {
+ PyErr_Format(PyExc_TypeError,"%s cannot be instantiated or sub-classed", wt->type->td_name);
+
+ return NULL;
+ }
+
+ /* See if it is an abstract type. */
+ if (sipTypeIsAbstract(wt) && strcmp(strchr(wt->type->td_name, '.') + 1, ((PyTypeObject *)wt)->tp_name) == 0)
+ {
+ PyErr_Format(PyExc_TypeError, "%s represents a C++ abstract class and cannot be instantiated", wt->type->td_name);
+
+ return NULL;
+ }
+ }
+
+ /* Call the standard super-type new. */
+ return PyBaseObject_Type.tp_new((PyTypeObject *)wt, args, kwds);
+}
+
+
+/*
+ * The instance init slot.
+ */
+static int sipWrapper_init(sipWrapper *self,PyObject *args,PyObject *kwds)
+{
+ void *sipNew;
+ int sipFlags;
+ sipWrapper *owner;
+
+ 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;
+ }
+
+ /* Check there is no existing C++ instance waiting to be wrapped. */
+ if ((sipNew = sipGetPending(&owner, &sipFlags)) == NULL)
+ {
+ int argsparsed = 0;
+ sipWrapperType *wt = (sipWrapperType *)self->ob_type;
+
+ /* Call the C++ ctor. */
+ owner = NULL;
+
+ if ((sipNew = wt->type->td_init(self, args, &owner, &argsparsed)) != NULL)
+ sipFlags = SIP_DERIVED_CLASS;
+ else
+ {
+ int pstate = argsparsed & PARSE_MASK;
+ sipInitExtenderDef *ie = wt->iextend;
+
+ /*
+ * While we just have signature errors, try any initialiser
+ * extenders.
+ */
+ while (ie != NULL && (pstate == PARSE_MANY || pstate == PARSE_FEW || pstate == PARSE_TYPE))
+ {
+ argsparsed = 0;
+
+ if ((sipNew = ie->ie_extender(self, args, &owner, &argsparsed)) != NULL)
+ break;
+
+ pstate = argsparsed & PARSE_MASK;
+ ie = ie->ie_next;
+ }
+
+ if (sipNew == NULL)
+ {
+ /*
+ * If the arguments were parsed without error then assume an
+ * exception has already been raised for why the instance
+ * wasn't created.
+ */
+ if (pstate == PARSE_OK)
+ argsparsed = PARSE_RAISED;
+
+ badArgs(argsparsed, NULL, getBaseName(wt->type->td_name));
+ return -1;
+ }
+
+ sipFlags = 0;
+ }
+
+ if (owner == NULL)
+ sipFlags |= SIP_PY_OWNED;
+ }
+
+ addToParent(self, owner);
+
+ self->u.cppPtr = sipNew;
+ self->flags = sipFlags;
+
+ if (!sipNotInMap(self))
+ sipOMAddObject(&cppPyMap,self);
+
+ return 0;
+}
+
+
+/*
+ * The instance traverse slot.
+ */
+static int sipWrapper_traverse(sipWrapper *self, visitproc visit, void *arg)
+{
+ int vret;
+ void *ptr;
+ sipTypeDef *td;
+ sipWrapper *w;
+ sipPySig *ps;
+
+ /* Call the nearest handwritten traverse code in the class hierachy. */
+ if ((ptr = getPtrTypeDef(self, &td)) != NULL)
+ {
+ sipTypeDef *ctd = td;
+
+ if (td->td_traverse == NULL)
+ {
+ sipEncodedClassDef *sup;
+
+ if ((sup = td->td_supers) != NULL)
+ do
+ ctd = getClassType(sup, td->td_module)->type;
+ while (ctd->td_traverse == NULL && !sup++->sc_flag);
+ }
+
+ if (ctd->td_traverse != NULL)
+ if ((vret = ctd->td_traverse(ptr, visit, arg)) != 0)
+ return vret;
+ }
+
+ if (qt_and_sip_api_3_4())
+ {
+ void *tx = sipGetAddress(self);
+
+ if (tx != NULL)
+ {
+ sipSlotConnection *conn;
+ void *context = NULL;
+
+ while ((conn = sipQtSupport->qt_find_connection(tx, &context)) != NULL)
+ {
+ if ((vret = visitSlot(&conn->sc_slot, visit, arg)) != 0)
+ return vret;
+
+ if (context == NULL)
+ break;
+ }
+ }
+ }
+
+ for (ps = self->pySigList; ps != NULL; ps = ps->next)
+ {
+ sipSlotList *psrx;
+
+ for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next)
+ if ((vret = visitSlot(&psrx->rx, visit, arg)) != 0)
+ return vret;
+ }
+
+ if (self->user != NULL)
+ if ((vret = visit(self->user, arg)) != 0)
+ return vret;
+
+ if (self->dict != NULL)
+ if ((vret = visit(self->dict, arg)) != 0)
+ return vret;
+
+ for (w = self->first_child; w != NULL; w = w->sibling_next)
+ {
+ /*
+ * We don't traverse if the wrapper is a child of itself. We
+ * do this so that wrapped objects returned by virtual methods
+ * with the /Factory/ don't have those objects collected. This
+ * then means that plugins implemented in Python have a chance
+ * of working.
+ */
+ if (w != self)
+ if ((vret = visit((PyObject *)w, arg)) != 0)
+ return vret;
+ }
+
+ return 0;
+}
+
+
+/*
+ * The instance clear slot.
+ */
+static int sipWrapper_clear(sipWrapper *self)
+{
+ int vret = 0;
+ void *ptr;
+ sipTypeDef *td;
+ PyObject *tmp;
+ sipPySig *ps;
+
+ /* Call the nearest handwritten clear code in the class hierachy. */
+ if ((ptr = getPtrTypeDef(self, &td)) != NULL)
+ {
+ sipTypeDef *ctd = td;
+
+ if (td->td_clear == NULL)
+ {
+ sipEncodedClassDef *sup;
+
+ if ((sup = td->td_supers) != NULL)
+ do
+ ctd = getClassType(sup, td->td_module)->type;
+ while (ctd->td_clear == NULL && !sup++->sc_flag);
+ }
+
+ if (ctd->td_clear != NULL)
+ vret = ctd->td_clear(ptr);
+ }
+
+ /* Remove any lambda slots connected via a proxy. */
+ if (qt_and_sip_api_3_4())
+ {
+ void *tx = sipGetAddress(self);
+
+ if (tx != NULL)
+ {
+ sipSlotConnection *conn;
+ void *context = NULL;
+
+ while ((conn = sipQtSupport->qt_find_connection(tx, &context)) != NULL)
+ {
+ clearAnyLambda(&conn->sc_slot);
+
+ if (context == NULL)
+ break;
+ }
+ }
+ }
+
+ /* Remove any lambda slots connected to PyQt v3 Python signals. */
+ for (ps = self->pySigList; ps != NULL; ps = ps->next)
+ {
+ sipSlotList *psrx;
+
+ for (psrx = ps->rxlist; psrx != NULL; psrx = psrx->next)
+ clearAnyLambda(&psrx->rx);
+ }
+
+ /* Remove any user object. */
+ tmp = self->user;
+ self->user = NULL;
+ Py_XDECREF(tmp);
+
+ /* Remove the instance dictionary. */
+ tmp = self->dict;
+ self->dict = NULL;
+ Py_XDECREF(tmp);
+
+ /* Detach children (which will be owned by C/C++. */
+ while (self->first_child != NULL)
+ {
+ /*
+ * Although this object is being garbage collected it doesn't follow
+ * that it's children should be. So we make sure that the child stays
+ * alive and remember we have done so.
+ */
+ Py_INCREF(self->first_child);
+ sipSetCppHasRef(self->first_child);
+
+ removeFromParent(self->first_child);
+ }
+
+ return vret;
+}
+
+
+/*
+ * The instance read buffer slot.
+ */
+static SIP_SSIZE_T sipWrapper_getreadbuffer(sipWrapper *self,
+ SIP_SSIZE_T segment, void **ptrptr)
+{
+ void *ptr;
+ sipTypeDef *td;
+
+ if ((ptr = getPtrTypeDef(self, &td)) == NULL)
+ return -1;
+
+ return td->td_readbuffer((PyObject *)self, ptr, segment, ptrptr);
+}
+
+
+/*
+ * The instance write buffer slot.
+ */
+static SIP_SSIZE_T sipWrapper_getwritebuffer(sipWrapper *self,
+ SIP_SSIZE_T segment, void **ptrptr)
+{
+ void *ptr;
+ sipTypeDef *td;
+
+ if ((ptr = getPtrTypeDef(self, &td)) == NULL)
+ return -1;
+
+ return td->td_writebuffer((PyObject *)self, ptr, segment, ptrptr);
+}
+
+
+/*
+ * The instance segment count slot.
+ */
+static SIP_SSIZE_T sipWrapper_getsegcount(sipWrapper *self, SIP_SSIZE_T *lenp)
+{
+ void *ptr;
+ sipTypeDef *td;
+
+ if ((ptr = getPtrTypeDef(self, &td)) == NULL)
+ return 0;
+
+ return td->td_segcount((PyObject *)self, ptr, lenp);
+}
+
+
+/*
+ * The instance char buffer slot.
+ */
+static SIP_SSIZE_T sipWrapper_getcharbuffer(sipWrapper *self,
+ SIP_SSIZE_T segment, void **ptrptr)
+{
+ void *ptr;
+ sipTypeDef *td;
+
+ if ((ptr = getPtrTypeDef(self, &td)) == NULL)
+ return -1;
+
+ return td->td_charbuffer((PyObject *)self, ptr, segment, ptrptr);
+}
+
+
+/*
+ * The instance dealloc slot.
+ */
+static void sipWrapper_dealloc(sipWrapper *self)
+{
+ sipTypeDef *td;
+
+ if (getPtrTypeDef(self, &td) != NULL)
+ {
+ /*
+ * Remove the object from the map before calling the class specific
+ * dealloc code. This code calls the C++ dtor and may result in
+ * further calls that pass the instance as an argument. If this is
+ * still in the map then it's reference count would be increased (to
+ * one) and bad things happen when it drops back to zero again. (An
+ * example is PyQt events generated during the dtor call being passed
+ * to an event filter implemented in Python.) By removing it from the
+ * map first we ensure that a new Python object is created.
+ */
+ sipOMRemoveObject(&cppPyMap, self);
+
+ /* Call the C++ dtor if there is one. */
+ if (td->td_dealloc != NULL)
+ td->td_dealloc(self);
+ }
+
+ /*
+ * Now that the C++ object no longer exists we can tidy up the Python
+ * object. We used to do this first but that meant lambda slots were
+ * removed too soon (if they were connected to QObject.destroyed()).
+ */
+ sipWrapper_clear(self);
+
+ while (self->pySigList != NULL)
+ {
+ sipPySig *ps;
+ sipSlotList *psrx;
+
+ /* Take this one out of the list. */
+ ps = self->pySigList;
+ self->pySigList = ps->next;
+
+ while ((psrx = ps->rxlist) != NULL)
+ {
+ ps->rxlist = psrx->next;
+ sipFreeSlotList(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, SIP_SSIZE_T n)
+{
+ PyObject *(*f)(PyObject *,PyObject *);
+ PyObject *arg, *res;
+
+#if PY_VERSION_HEX >= 0x02050000
+ if ((arg = PyInt_FromSsize_t(n)) == NULL)
+#else
+ if ((arg = PyInt_FromLong(n)) == NULL)
+#endif
+ 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, SIP_SSIZE_T i, PyObject *o)
+{
+ return ssizeobjargprocSlot(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 of a base wrapper type
+ * 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 = NULL;
+
+ if (isExactWrappedType(wt) && 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)
+ if ((tmpdict = w->dict) == NULL)
+ tmpdict = PyDict_New();
+ else
+ 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;
+
+ 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;
+ }
+
+ 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 | Py_TPFLAGS_HAVE_GC, /* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)sipWrapper_traverse, /* tp_traverse */
+ (inquiry)sipWrapper_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(sipWrapper,dict), /* tp_dictoffset */
+ (initproc)sipWrapper_init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)sipWrapper_new, /* tp_new */
+ 0, /* tp_free */
+ },
+ },
+ 0,
+ 0
+};
+
+
+/*
+ * Add the slots for a type and all its super-types.
+ */
+static void addSlots(sipWrapperType *wt, sipTypeDef *td)
+{
+ sipEncodedClassDef *sup;
+
+ /* Add the buffer interface. */
+ if (td->td_readbuffer != NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ wt->super.as_buffer.bf_getreadbuffer = (readbufferproc)sipWrapper_getreadbuffer;
+#else
+ wt->super.as_buffer.bf_getreadbuffer = (getreadbufferproc)sipWrapper_getreadbuffer;
+#endif
+
+ if (td->td_writebuffer != NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ wt->super.as_buffer.bf_getwritebuffer = (writebufferproc)sipWrapper_getwritebuffer;
+#else
+ wt->super.as_buffer.bf_getwritebuffer = (getwritebufferproc)sipWrapper_getwritebuffer;
+#endif
+
+ if (td->td_segcount != NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ wt->super.as_buffer.bf_getsegcount = (segcountproc)sipWrapper_getsegcount;
+#else
+ wt->super.as_buffer.bf_getsegcount = (getsegcountproc)sipWrapper_getsegcount;
+#endif
+
+ if (td->td_charbuffer != NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ wt->super.as_buffer.bf_getcharbuffer = (charbufferproc)sipWrapper_getcharbuffer;
+#else
+ wt->super.as_buffer.bf_getcharbuffer = (getcharbufferproc)sipWrapper_getcharbuffer;
+#endif
+
+ /* Add the slots for this type. */
+ if (td->td_pyslots != NULL)
+ initSlots((PyTypeObject *)wt, &wt->super.as_number, &wt->super.as_sequence, &wt->super.as_mapping, td->td_pyslots, FALSE);
+
+ /* Recurse through any super-types. */
+ if ((sup = td->td_supers) != NULL)
+ do
+ addSlots(wt, getClassType(sup, td->td_module)->type);
+ while (!sup++->sc_flag);
+}
+
+
+/*
+ * Add the slot handler for each slot present in the type, optionally replacing
+ * any that have already been defined.
+ */
+static void initSlots(PyTypeObject *to, PyNumberMethods *nb, PySequenceMethods *sq, PyMappingMethods *mp, sipPySlotDef *slots, int force)
+{
+ void *f;
+
+ while ((f = slots->psd_func) != NULL)
+ switch (slots++->psd_type)
+ {
+ case str_slot:
+ if (force || to->tp_str == NULL)
+ to->tp_str = (reprfunc)f;
+ break;
+
+ case int_slot:
+ if (nb != NULL)
+ if (force || nb->nb_int == NULL)
+ nb->nb_int = (unaryfunc)f;
+ break;
+
+ case long_slot:
+ if (nb != NULL)
+ if (force || nb->nb_long == NULL)
+ nb->nb_long = (unaryfunc)f;
+ break;
+
+ case float_slot:
+ if (nb != NULL)
+ if (force || nb->nb_float == NULL)
+ nb->nb_float = (unaryfunc)f;
+ break;
+
+ case len_slot:
+ if (mp != NULL)
+ if (force || mp->mp_length == NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ mp->mp_length = (lenfunc)f;
+#else
+ mp->mp_length = (inquiry)f;
+#endif
+ if (sq != NULL)
+ if (force || sq->sq_length == NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ sq->sq_length = (lenfunc)f;
+#else
+ sq->sq_length = (inquiry)f;
+#endif
+ break;
+
+ case contains_slot:
+ if (sq != NULL)
+ if (force || sq->sq_contains == NULL)
+ sq->sq_contains = (objobjproc)f;
+ break;
+
+ case add_slot:
+ if (nb != NULL)
+ if (force || nb->nb_add == NULL)
+ nb->nb_add = (binaryfunc)f;
+ break;
+
+ case concat_slot:
+ if (sq != NULL)
+ if (force || sq->sq_concat == NULL)
+ sq->sq_concat = (binaryfunc)f;
+ break;
+
+ case sub_slot:
+ if (nb != NULL)
+ if (force || nb->nb_subtract == NULL)
+ nb->nb_subtract = (binaryfunc)f;
+ break;
+
+ case mul_slot:
+ if (nb != NULL)
+ if (force || nb->nb_multiply == NULL)
+ nb->nb_multiply = (binaryfunc)f;
+ break;
+
+ case repeat_slot:
+ if (sq != NULL)
+ if (force || sq->sq_repeat == NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ sq->sq_repeat = (ssizeargfunc)f;
+#else
+ sq->sq_repeat = (intargfunc)f;
+#endif
+ break;
+
+ case div_slot:
+ if (nb != NULL)
+ {
+ if (force || nb->nb_divide == NULL)
+ nb->nb_divide = (binaryfunc)f;
+
+ if (force || nb->nb_true_divide == NULL)
+ nb->nb_true_divide = (binaryfunc)f;
+ }
+ break;
+
+ case mod_slot:
+ if (nb != NULL)
+ if (force || nb->nb_remainder == NULL)
+ nb->nb_remainder = (binaryfunc)f;
+ break;
+
+ case and_slot:
+ if (nb != NULL)
+ if (force || nb->nb_and == NULL)
+ nb->nb_and = (binaryfunc)f;
+ break;
+
+ case or_slot:
+ if (nb != NULL)
+ if (force || nb->nb_or == NULL)
+ nb->nb_or = (binaryfunc)f;
+ break;
+
+ case xor_slot:
+ if (nb != NULL)
+ if (force || nb->nb_xor == NULL)
+ nb->nb_xor = (binaryfunc)f;
+ break;
+
+ case lshift_slot:
+ if (nb != NULL)
+ if (force || nb->nb_lshift == NULL)
+ nb->nb_lshift = (binaryfunc)f;
+ break;
+
+ case rshift_slot:
+ if (nb != NULL)
+ if (force || nb->nb_rshift == NULL)
+ nb->nb_rshift = (binaryfunc)f;
+ break;
+
+ case iadd_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_add == NULL)
+ nb->nb_inplace_add = (binaryfunc)f;
+ break;
+
+ case iconcat_slot:
+ if (sq != NULL)
+ if (force || sq->sq_inplace_concat == NULL)
+ sq->sq_inplace_concat = (binaryfunc)f;
+ break;
+
+ case isub_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_subtract == NULL)
+ nb->nb_inplace_subtract = (binaryfunc)f;
+ break;
+
+ case imul_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_multiply == NULL)
+ nb->nb_inplace_multiply = (binaryfunc)f;
+ break;
+
+ case irepeat_slot:
+ if (sq != NULL)
+ if (force || sq->sq_inplace_repeat == NULL)
+#if PY_VERSION_HEX >= 0x02050000
+ sq->sq_inplace_repeat = (ssizeargfunc)f;
+#else
+ sq->sq_inplace_repeat = (intargfunc)f;
+#endif
+ break;
+
+ case idiv_slot:
+ if (nb != NULL)
+ {
+ if (force || nb->nb_inplace_divide == NULL)
+ nb->nb_inplace_divide = (binaryfunc)f;
+
+ if (force || nb->nb_inplace_true_divide == NULL)
+ nb->nb_inplace_true_divide = (binaryfunc)f;
+ }
+ break;
+
+ case imod_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_remainder == NULL)
+ nb->nb_inplace_remainder = (binaryfunc)f;
+ break;
+
+ case iand_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_and == NULL)
+ nb->nb_inplace_and = (binaryfunc)f;
+ break;
+
+ case ior_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_or == NULL)
+ nb->nb_inplace_or = (binaryfunc)f;
+ break;
+
+ case ixor_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_xor == NULL)
+ nb->nb_inplace_xor = (binaryfunc)f;
+ break;
+
+ case ilshift_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_lshift == NULL)
+ nb->nb_inplace_lshift = (binaryfunc)f;
+ break;
+
+ case irshift_slot:
+ if (nb != NULL)
+ if (force || nb->nb_inplace_rshift == NULL)
+ nb->nb_inplace_rshift = (binaryfunc)f;
+ break;
+
+ case invert_slot:
+ if (nb != NULL)
+ if (force || nb->nb_invert == NULL)
+ nb->nb_invert = (unaryfunc)f;
+ break;
+
+ case call_slot:
+ if (force || to->tp_call == NULL)
+ to->tp_call = sipWrapper_call;
+ break;
+
+ case getitem_slot:
+ if (mp != NULL)
+ if (force || mp->mp_subscript == NULL)
+ mp->mp_subscript = (binaryfunc)f;
+ if (sq != NULL)
+ if (force || sq->sq_item == NULL)
+ sq->sq_item = sipWrapper_sq_item;
+ break;
+
+ case setitem_slot:
+ case delitem_slot:
+ if (mp != NULL)
+ if (force || mp->mp_ass_subscript == NULL)
+ mp->mp_ass_subscript = sipWrapper_mp_ass_subscript;
+ if (sq != NULL)
+ if (force || sq->sq_ass_item == NULL)
+ sq->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 (force || to->tp_richcompare == NULL)
+ to->tp_richcompare = sipWrapper_richcompare;
+ break;
+
+ case cmp_slot:
+ if (force || to->tp_compare == NULL)
+ to->tp_compare = (cmpfunc)f;
+ break;
+
+ case nonzero_slot:
+ if (nb != NULL)
+ if (force || nb->nb_nonzero == NULL)
+ nb->nb_nonzero = (inquiry)f;
+ break;
+
+ case neg_slot:
+ if (nb != NULL)
+ if (force || nb->nb_negative == NULL)
+ nb->nb_negative = (unaryfunc)f;
+ break;
+
+ case repr_slot:
+ if (force || to->tp_repr == NULL)
+ to->tp_repr = (reprfunc)f;
+ break;
+
+ case hash_slot:
+ if (force || to->tp_hash == NULL)
+ to->tp_hash = (hashfunc)f;
+ break;
+
+ case pos_slot:
+ if (nb != NULL)
+ if (force || nb->nb_positive == NULL)
+ nb->nb_positive = (unaryfunc)f;
+ break;
+
+ case abs_slot:
+ if (nb != NULL)
+ if (force || nb->nb_absolute == NULL)
+ nb->nb_absolute = (unaryfunc)f;
+ break;
+ }
+}
+
+
+/*
+ * Search for a named class and return the wrapper type.
+ */
+static sipWrapperType *findClass(sipExportedModuleDef *emd, const char *name,
+ size_t len)
+{
+ int i;
+ sipWrapperType **wtp = emd->em_types;
+
+ for (i = 0; i < emd->em_nrtypes; ++i)
+ {
+ sipWrapperType *wt;
+
+ if ((wt = *wtp++) == NULL)
+ continue;
+
+ if (wt->type->td_cname != NULL)
+ {
+ if (!nameEq(wt->type->td_cname, name, len))
+ continue;
+ }
+ else if (!sameScopedName(wt->type->td_name, name, len))
+ continue;
+
+ return wt;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * 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(sipExportedModuleDef *emd, const char *name,
+ size_t len, sipSigArg *at, int indir)
+{
+ sipWrapperType *wt = findClass(emd, name, len);
+
+ if (wt == NULL)
+ return FALSE;
+
+ if (indir == 0)
+ at->atype = class_sat;
+ else if (indir == 1)
+ at->atype = classp_sat;
+ else
+ at->atype = unknown_sat;
+
+ at->u.wt = wt;
+
+ return TRUE;
+}
+
+
+/*
+ * 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(sipMappedType **mttab, const char *name, size_t len,
+ sipSigArg *at, int indir)
+{
+ sipMappedType *mt;
+
+ while ((mt = *mttab++) != NULL)
+ if (nameEq(mt->mt_name, name, len))
+ {
+ if (indir == 0)
+ at->atype = mtype_sat;
+ else if (indir == 1)
+ at->atype = mtypep_sat;
+ else
+ at->atype = unknown_sat;
+
+ at->u.mt = mt;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * Search for a named enum in a particular module and return the corresponding
+ * type object.
+ */
+static PyTypeObject *findEnum(sipExportedModuleDef *emd, const char *name,
+ size_t len)
+{
+ int i;
+ sipEnumDef *ed;
+
+ for (ed = emd->em_enumdefs, i = 0; i < emd->em_nrenums; ++i, ++ed)
+ {
+ if (ed->e_cname != NULL)
+ {
+ if (!nameEq(ed->e_cname, name, len))
+ continue;
+ }
+ else if (!sameScopedName(ed->e_name, name, len))
+ continue;
+
+ return emd->em_enums[i];
+ }
+
+ return NULL;
+}
+
+
+/*
+ * 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 indir)
+{
+ PyTypeObject *py = findEnum(emd, name, len);
+
+ if (py == NULL)
+ return FALSE;
+
+ if (indir == 0)
+ at->atype = enum_sat;
+ else
+ at->atype = unknown_sat;
+
+ at->u.et = py;
+
+ return TRUE;
+}
+
+
+/*
+ * 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, int indir)
+{
+ sipExportedModuleDef *em;
+ sipPyObject *po;
+
+ 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 (nameEq(tdd->tdd_name, name, len))
+ {
+ 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, tn, tnlen, at, indir);
+ break;
+
+ case mtype_sat:
+ findMtypeArg(tem->em_mappedtypes, tn, tnlen, at, indir);
+ break;
+
+ case enum_sat:
+ findEnumArg(tem, tn, tnlen, at, indir);
+ break;
+ }
+
+ /* We should have found it by now. */
+ return;
+ }
+
+ ++tdd;
+ }
+
+ /* Search for a class. */
+ if (em->em_types != NULL && findClassArg(em, name, len, at, indir))
+ return;
+
+ /* Search for a mapped type. */
+ if (em->em_mappedtypes != NULL && findMtypeArg(em->em_mappedtypes, name, len, at, indir))
+ return;
+
+ /* Search for an enum. */
+ if (em->em_enums != NULL && findEnumArg(em, name, len, at, indir))
+ return;
+ }
+
+ /* Search for a dynamically registered int type. */
+ for (po = sipRegisteredIntTypes; po != NULL; po = po->next)
+ {
+ int i;
+
+ for (i = 0; i < PyTuple_GET_SIZE(po->object); ++i)
+ {
+ char *int_nm = PyString_AsString(PyTuple_GET_ITEM(po->object, i));
+
+ if (int_nm == NULL)
+ continue;
+
+ if (nameEq(int_nm, name, len))
+ {
+ at->atype = int_sat;
+ return;
+ }
+ }
+ }
+}
+
+
+/*
+ * Compare a '\0' terminated string with the first len characters of a second
+ * and return a non-zero value if they are equal.
+ */
+static int nameEq(const char *with, const char *name, size_t len)
+{
+ return (strlen(with) == len && strncmp(with, name, len) == 0);
+}
+
+
+/*
+ * 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);
+}
+
+
+/*
+ * Register a Python tuple of type names that will be interpreted as ints if
+ * they are seen as signal arguments.
+ */
+static int sip_api_register_int_types(PyObject *args)
+{
+ sipPyObject *po;
+ int bad_args = FALSE;
+
+ /* Raise an exception if the arguments are bad. */
+ if (PyTuple_Check(args))
+ {
+ int i;
+
+ for (i = 0; i < PyTuple_GET_SIZE(args); ++i)
+ if (!PyString_Check(PyTuple_GET_ITEM(args, i)))
+ {
+ bad_args = TRUE;
+ break;
+ }
+ }
+ else
+ bad_args = TRUE;
+
+ if (bad_args)
+ {
+ PyErr_SetString(PyExc_TypeError, "all arguments must be strings");
+ return -1;
+ }
+
+ if ((po = sip_api_malloc(sizeof (sipPyObject))) == NULL)
+ return -1;
+
+ Py_INCREF(args);
+
+ po->object = args;
+ po->next = sipRegisteredIntTypes;
+
+ sipRegisteredIntTypes = po;
+
+ return 0;
+}
+
+
+/*
+ * Register a symbol with a name. A negative value is returned if the name was
+ * already registered.
+ */
+static int sip_api_export_symbol(const char *name, void *sym)
+{
+ sipSymbol *ss;
+
+ if (sip_api_import_symbol(name) != NULL)
+ return -1;
+
+ if ((ss = sip_api_malloc(sizeof (sipSymbol))) == NULL)
+ return -1;
+
+ ss->name = name;
+ ss->symbol = sym;
+ ss->next = sipSymbolList;
+
+ sipSymbolList = ss;
+
+ return 0;
+}
+
+
+/*
+ * Return the symbol registered with the given name. NULL is returned if the
+ * name was not registered.
+ */
+static void *sip_api_import_symbol(const char *name)
+{
+ sipSymbol *ss;
+
+ for (ss = sipSymbolList; ss != NULL; ss = ss->next)
+ if (strcmp(ss->name, name) == 0)
+ return ss->symbol;
+
+ return NULL;
+}
+
+
+/*
+ * Returns TRUE if the Qt support is present and conforms to the v3.4 or later
+ * of the SIP API.
+ */
+static int qt_and_sip_api_3_4(void)
+{
+ return (sipQtSupport != NULL && sipQObjectClass->type->td_module->em_api_minor >= 4);
+}
+
+
+/*
+ * Visit a slot connected to an object for the cyclic garbage collector.
+ */
+static int visitSlot(sipSlot *slot, visitproc visit, void *arg)
+{
+ if (slot->pyobj != NULL && sipLambdaSlot(slot->pyobj))
+ return visit(slot->pyobj, arg);
+
+ return 0;
+}
+
+
+/*
+ * Clear a slot if it is a lambda function.
+ */
+static void clearAnyLambda(sipSlot *slot)
+{
+ PyObject *lam = slot->pyobj;
+
+ if (lam != NULL && sipLambdaSlot(lam))
+ {
+ /*
+ * Replace the lambda function with None. We don't use NULL as this
+ * has another meaning.
+ */
+ Py_INCREF(Py_None);
+ slot->pyobj = Py_None;
+
+ Py_DECREF(lam);
+ }
+}
+
+
+/*
+ * Convert a Python object to a character.
+ */
+static char sip_api_string_as_char(PyObject *obj)
+{
+ char ch;
+
+ if (parseChar(obj, &ch) < 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "string of length 1 expected");
+
+ return '\0';
+ }
+
+ return ch;
+}
+
+
+/*
+ * Parse a character array and return it's address and length.
+ */
+static int parseCharArray(PyObject *obj, char **ap, int *aszp)
+{
+ if (obj == Py_None)
+ {
+ *ap = NULL;
+ *aszp = 0;
+ }
+ else if (PyString_Check(obj))
+ {
+ *ap = PyString_AS_STRING(obj);
+ *aszp = (int)PyString_GET_SIZE(obj);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Parse a character and return it.
+ */
+static int parseChar(PyObject *obj, char *ap)
+{
+ if (!PyString_Check(obj) || PyString_GET_SIZE(obj) != 1)
+ return -1;
+
+ *ap = *PyString_AS_STRING(obj);
+
+ return 0;
+}
+
+
+/*
+ * Parse a character string and return it.
+ */
+static int parseCharString(PyObject *obj, char **ap)
+{
+ if (obj == Py_None)
+ *ap = NULL;
+ else if (PyString_Check(obj))
+ *ap = PyString_AS_STRING(obj);
+ else
+ return -1;
+
+ return 0;
+}
+
+
+#if defined(HAVE_WCHAR_H)
+/*
+ * Convert a Python object to a wide character.
+ */
+static wchar_t sip_api_unicode_as_wchar(PyObject *obj)
+{
+ wchar_t ch;
+
+ if (parseWChar(obj, &ch) < 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "unicode string of length 1 expected");
+
+ return L'\0';
+ }
+
+ return ch;
+}
+
+
+/*
+ * Convert a Python object to a wide character string on the heap.
+ */
+static wchar_t *sip_api_unicode_as_wstring(PyObject *obj)
+{
+ wchar_t *p;
+
+ if (parseWCharString(obj, &p) < 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "unicode string expected");
+
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/*
+ * Parse a wide character array and return it's address and length.
+ */
+static int parseWCharArray(PyObject *obj, wchar_t **ap, int *aszp)
+{
+ if (obj == Py_None)
+ {
+ *ap = NULL;
+ *aszp = 0;
+ }
+ else if (PyUnicode_Check(obj))
+ {
+ SIP_SSIZE_T ulen;
+ wchar_t *wc;
+
+ ulen = PyUnicode_GET_SIZE(obj);
+
+ if ((wc = sip_api_malloc(ulen * sizeof (wchar_t))) == NULL)
+ return -1;
+
+ ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen);
+
+ if (ulen < 0)
+ {
+ sip_api_free(wc);
+ return -1;
+ }
+
+ *ap = wc;
+ *aszp = (int)ulen;
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Parse a wide character and return it.
+ */
+static int parseWChar(PyObject *obj, wchar_t *ap)
+{
+ if (!PyUnicode_Check(obj) || PyUnicode_GET_SIZE(obj) != 1)
+ return -1;
+
+ if (PyUnicode_AsWideChar((PyUnicodeObject *)obj, ap, 1) != 1)
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Parse a wide character string and return it.
+ */
+static int parseWCharString(PyObject *obj, wchar_t **ap)
+{
+ if (obj == Py_None)
+ *ap = NULL;
+ else if (PyUnicode_Check(obj))
+ {
+ SIP_SSIZE_T ulen;
+ wchar_t *wc;
+
+ ulen = PyUnicode_GET_SIZE(obj);
+
+ if ((wc = sip_api_malloc((ulen + 1) * sizeof (wchar_t))) == NULL)
+ return -1;
+
+ ulen = PyUnicode_AsWideChar((PyUnicodeObject *)obj, wc, ulen);
+
+ if (ulen < 0)
+ {
+ sip_api_free(wc);
+ return -1;
+ }
+
+ wc[ulen] = L'\0';
+
+ *ap = wc;
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+#else
+
+/*
+ * Convert a Python object to a wide character.
+ */
+static int sip_api_unicode_as_wchar(PyObject *obj)
+{
+ raiseNoWChar();
+
+ return 0;
+}
+
+
+/*
+ * Convert a Python object to a wide character.
+ */
+static int *sip_api_unicode_as_wstring(PyObject *obj)
+{
+ raiseNoWChar();
+
+ return NULL;
+}
+
+
+/*
+ * Report the need for absent wide character support.
+ */
+static void raiseNoWChar()
+{
+ PyErr_SetString(PyExc_SystemError, "sip built without wchar_t support");
+}
+
+#endif
diff --git a/python/sip/siplib/siplib.sbf b/python/sip/siplib/siplib.sbf
new file mode 100644
index 00000000..2499d1b8
--- /dev/null
+++ b/python/sip/siplib/siplib.sbf
@@ -0,0 +1,16 @@
+# This is the build file for the extension module.
+#
+# Copyright (c) 2007
+# Riverbank Computing Limited <[email protected]>
+#
+# 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.
+
+target = sip
+sources = siplib.c qtlib.c threads.c objmap.c bool.cpp
+headers = sip.h sipint.h
diff --git a/python/sip/siplib/threads.c b/python/sip/siplib/threads.c
new file mode 100644
index 00000000..c4ee75ff
--- /dev/null
+++ b/python/sip/siplib/threads.c
@@ -0,0 +1,223 @@
+/*
+ * Thread support for the SIP library. This module provides the hooks for
+ * C++ classes that provide a thread interface to interact properly with the
+ * Python threading infrastructure.
+ *
+ * Copyright (c) 2007
+ * Riverbank Computing Limited <[email protected]>
+ *
+ * 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 "sip.h"
+#include "sipint.h"
+
+
+/*
+ * The data associated with pending request to wrap an object.
+ */
+typedef struct _pendingDef {
+ void *cpp; /* The C/C++ object ot be wrapped. */
+ sipWrapper *owner; /* The owner of the object. */
+ int flags; /* The flags. */
+} pendingDef;
+
+
+#ifdef WITH_THREAD
+
+#include <pythread.h>
+
+
+/*
+ * The per thread data we need to maintain.
+ */
+typedef struct _threadDef {
+ long thr_ident; /* The thread identifier. */
+ pendingDef pending; /* An object waiting to be wrapped. */
+ struct _threadDef *next; /* Next in the list. */
+} threadDef;
+
+
+static threadDef *threads = NULL; /* Linked list of threads. */
+
+
+static threadDef *currentThreadDef(void);
+
+#endif
+
+
+static pendingDef pending; /* An object waiting to be wrapped. */
+
+
+/*
+ * Get the address of any C/C++ object waiting to be wrapped.
+ */
+void *sipGetPending(sipWrapper **op, int *fp)
+{
+ pendingDef *pp;
+
+#ifdef WITH_THREAD
+ threadDef *td;
+
+ if ((td = currentThreadDef()) != NULL)
+ pp = &td->pending;
+ else
+ pp = &pending;
+#else
+ pp = &pending;
+#endif
+
+ if (pp->cpp != NULL)
+ {
+ if (op != NULL)
+ *op = pp->owner;
+
+ if (fp != NULL)
+ *fp = pp->flags;
+ }
+
+ return pp->cpp;
+}
+
+
+/*
+ * Convert a new C/C++ pointer to a Python instance.
+ */
+PyObject *sipWrapSimpleInstance(void *cppPtr, sipWrapperType *type,
+ sipWrapper *owner, int flags)
+{
+ static PyObject *nullargs = NULL;
+
+ pendingDef old_pending;
+ PyObject *self;
+#ifdef WITH_THREAD
+ threadDef *td;
+#endif
+
+ if (nullargs == NULL && (nullargs = PyTuple_New(0)) == NULL)
+ return NULL;
+
+ if (cppPtr == NULL)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ /*
+ * Object creation can trigger the Python garbage collector which in turn
+ * can execute arbitrary Python code which can then call this function
+ * recursively. Therefore we save any existing pending object before
+ * setting the new one.
+ */
+#ifdef WITH_THREAD
+ if ((td = currentThreadDef()) != NULL)
+ {
+ old_pending = td->pending;
+
+ td->pending.cpp = cppPtr;
+ td->pending.owner = owner;
+ td->pending.flags = flags;
+ }
+ else
+ {
+ old_pending = pending;
+
+ pending.cpp = cppPtr;
+ pending.owner = owner;
+ pending.flags = flags;
+ }
+#else
+ old_pending = pending;
+
+ pending.cpp = cppPtr;
+ pending.owner = owner;
+ pending.flags = flags;
+#endif
+
+ self = PyObject_Call((PyObject *)type, nullargs, NULL);
+
+#ifdef WITH_THREAD
+ if (td != NULL)
+ td->pending = old_pending;
+ else
+ pending = old_pending;
+#else
+ pending = old_pending;
+#endif
+
+ return self;
+}
+
+
+/*
+ * This is called from a newly created thread to initialise some thread local
+ * storage.
+ */
+void sip_api_start_thread(void)
+{
+#ifdef WITH_THREAD
+ threadDef *td;
+
+ /* Save the thread ID. First, find an empty slot in the list. */
+ for (td = threads; td != NULL; td = td->next)
+ if (td->thr_ident == 0)
+ break;
+
+ if (td == NULL)
+ {
+ td = sip_api_malloc(sizeof (threadDef));
+ td->next = threads;
+ threads = td;
+ }
+
+ if (td != NULL)
+ {
+ td->thr_ident = PyThread_get_thread_ident();
+ td->pending.cpp = NULL;
+ }
+#endif
+}
+
+
+/*
+ * Handle the termination of a thread. The thread state should already have
+ * been handled by the last call to PyGILState_Release().
+ */
+void sip_api_end_thread(void)
+{
+#ifdef WITH_THREAD
+ threadDef *td;
+
+ /* We have the GIL at this point. */
+ if ((td = currentThreadDef()) != NULL)
+ td->thr_ident = 0;
+#endif
+}
+
+
+#ifdef WITH_THREAD
+
+/*
+ * Return the thread data for the current thread or NULL if it wasn't
+ * recognised.
+ */
+static threadDef *currentThreadDef(void)
+{
+ threadDef *td;
+ long ident = PyThread_get_thread_ident();
+
+ for (td = threads; td != NULL; td = td->next)
+ if (td->thr_ident == ident)
+ break;
+
+ return td;
+}
+
+#endif