/* * 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; }
/* * Add a new API to the global list returning a negative value on error. */ static int add_api(const char *api, int version_nr) { apiVersionDef *avd; if ((avd = sip_api_malloc(sizeof (apiVersionDef))) == NULL) return -1; avd->api_name = api; avd->version_nr = version_nr; avd->next = api_versions; api_versions = avd; return 0; }
/* * Set the version number for an API. */ PyObject *sipSetAPI(PyObject *self, PyObject *args) { const char *api; int version_nr; const apiVersionDef *avd; if (!PyArg_ParseTuple(args, "si:setapi", &api, &version_nr)) return NULL; if (version_nr < 1) { PyErr_Format(PyExc_ValueError, "API version numbers must be greater or equal to 1, not %d", version_nr); return NULL; } if ((avd = find_api(api)) == NULL) { char *api_copy; /* Make a deep copy of the name. */ if ((api_copy = sip_api_malloc(strlen(api) + 1)) == NULL) return NULL; strcpy(api_copy, api); if (add_api(api_copy, version_nr) < 0) return NULL; } else if (avd->version_nr != version_nr) { PyErr_Format(PyExc_ValueError, "API '%s' has already been set to version %d", api, avd->version_nr); return NULL; } Py_INCREF(Py_None); return Py_None; }
/* * Return the thread data for the current thread, allocating it if necessary, * or NULL if there was an error. */ static threadDef *currentThreadDef(int auto_alloc) { threadDef *thread, *empty = NULL; long ident = PyThread_get_thread_ident(); /* See if we already know about the thread. */ for (thread = threads; thread != NULL; thread = thread->next) { if (thread->thr_ident == ident) return thread; if (thread->thr_ident == 0) empty = thread; } if (!auto_alloc) { /* This is not an error. */ return NULL; } if (empty != NULL) { /* Use an empty entry in the list. */ thread = empty; } else if ((thread = sip_api_malloc(sizeof (threadDef))) == NULL) { return NULL; } else { thread->next = threads; threads = thread; } thread->thr_ident = ident; thread->pending.cpp = NULL; return thread; }
/* * This is called from a newly created thread to initialise some thread local * storage. */ void sip_api_start_thread(void) { #ifdef WITH_THREAD threadDef *thread; /* Save the thread ID. First, find an empty slot in the list. */ for (thread = threads; thread != NULL; thread = thread->next) if (thread->thr_ident == 0) break; if (thread == NULL) { thread = sip_api_malloc(sizeof (threadDef)); thread->next = threads; threads = thread; } if (thread != NULL) { thread->thr_ident = PyThread_get_thread_ident(); thread->pending.cpp = NULL; } #endif }
/* * 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. */ int sip_api_save_slot(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 && PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type)) { /* * 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 { /* * Give the slot an extra reference to keep it alive and * remember we have done so by treating weakSlot specially. */ Py_INCREF(rxObj); sp->pyobj = rxObj; Py_INCREF(Py_True); sp->weakSlot = Py_True; } } } 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; }
/* * Initialise the the API for a module and return a negative value on error. */ int sipInitAPI(sipExportedModuleDef *em, PyObject *mod_dict) { int *apis, i; sipVersionedFunctionDef *vf; sipTypeDef **tdp; /* See if the module defines any APIs. */ if ((apis = em->em_versions) != NULL) { while (apis[0] >= 0) { /* * See if it is an API definition rather than a range * definition. */ if (apis[2] < 0) { const char *api_name; const apiVersionDef *avd; api_name = sipNameFromPool(em, apis[0]); /* Use the default version if not already set explicitly. */ if ((avd = find_api(api_name)) == NULL) if (add_api(api_name, apis[1]) < 0) return -1; } apis += 3; } } /* Add any versioned global functions to the module dictionary. */ if ((vf = em->em_versioned_functions) != NULL) { while (vf->vf_name >= 0) { if (sipIsRangeEnabled(em, vf->vf_api_range)) { const char *func_name = sipNameFromPool(em, vf->vf_name); PyMethodDef *pmd; PyObject *py_func; if ((pmd = sip_api_malloc(sizeof (PyMethodDef))) == NULL) return -1; pmd->ml_name = SIP_MLNAME_CAST(func_name); pmd->ml_meth = vf->vf_function; pmd->ml_flags = vf->vf_flags; pmd->ml_doc = vf->vf_docstring; if ((py_func = PyCFunction_New(pmd, NULL)) == NULL) return -1; if (PyDict_SetItemString(mod_dict, func_name, py_func) < 0) { Py_DECREF(py_func); return -1; } Py_DECREF(py_func); } ++vf; } } /* Update the types table according to any version information. */ for (tdp = em->em_types, i = 0; i < em->em_nrtypes; ++i, ++tdp) { sipTypeDef *td; if ((td = *tdp) != NULL && td->td_version >= 0) { do { if (sipIsRangeEnabled(em, td->td_version)) { /* Update the type with the enabled version. */ *tdp = td; break; } } while ((td = td->td_next_version) != NULL); /* * If there is no enabled version then stub the disabled version * so that we don't lose the name from the (sorted) types table. */ if (td == NULL) sipTypeSetStub(*tdp); } } return 0; }