summaryrefslogtreecommitdiffstats
path: root/Objects/capsule.c
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2009-05-05 22:31:58 (GMT)
committerBenjamin Peterson <benjamin@python.org>2009-05-05 22:31:58 (GMT)
commitb173f7853e4e3a4215a661d98174291e379cf6fb (patch)
tree02735987f20fc27277a82c14c5da5e043cc134aa /Objects/capsule.c
parentc679fd8efcae2b5d1117fc09380d74f0000086b0 (diff)
downloadcpython-b173f7853e4e3a4215a661d98174291e379cf6fb.zip
cpython-b173f7853e4e3a4215a661d98174291e379cf6fb.tar.gz
cpython-b173f7853e4e3a4215a661d98174291e379cf6fb.tar.bz2
add a replacement API for PyCObject, PyCapsule #5630
All stdlib modules with C-APIs now use this. Patch by Larry Hastings
Diffstat (limited to 'Objects/capsule.c')
-rw-r--r--Objects/capsule.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/Objects/capsule.c b/Objects/capsule.c
new file mode 100644
index 0000000..5304ce1
--- /dev/null
+++ b/Objects/capsule.c
@@ -0,0 +1,324 @@
+/* Wrap void * pointers to be passed between C modules */
+
+#include "Python.h"
+
+/* Internal structure of PyCapsule */
+typedef struct {
+ PyObject_HEAD
+ void *pointer;
+ const char *name;
+ void *context;
+ PyCapsule_Destructor destructor;
+} PyCapsule;
+
+
+
+static int
+_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
+{
+ if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
+ PyErr_SetString(PyExc_ValueError, invalid_capsule);
+ return 0;
+ }
+ return 1;
+}
+
+#define is_legal_capsule(capsule, name) \
+ (_is_legal_capsule(capsule, \
+ name " called with invalid PyCapsule object"))
+
+
+static int
+name_matches(const char *name1, const char *name2) {
+ /* if either is NULL, */
+ if (!name1 || !name2) {
+ /* they're only the same if they're both NULL. */
+ return name2 == name2;
+ }
+ return !strcmp(name1, name2);
+}
+
+
+
+PyObject *
+PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
+{
+ PyCapsule *capsule;
+
+ if (!pointer) {
+ PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
+ return NULL;
+ }
+
+ capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
+ if (capsule == NULL) {
+ return NULL;
+ }
+
+ capsule->pointer = pointer;
+ capsule->name = name;
+ capsule->context = NULL;
+ capsule->destructor = destructor;
+
+ return (PyObject *)capsule;
+}
+
+
+int
+PyCapsule_IsValid(PyObject *o, const char *name)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ return (capsule != NULL &&
+ PyCapsule_CheckExact(capsule) &&
+ capsule->pointer != NULL &&
+ name_matches(capsule->name, name));
+}
+
+
+void *
+PyCapsule_GetPointer(PyObject *o, const char *name)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
+ return NULL;
+ }
+
+ if (!name_matches(name, capsule->name)) {
+ PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
+ return NULL;
+ }
+
+ return capsule->pointer;
+}
+
+
+const char *
+PyCapsule_GetName(PyObject *o)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
+ return NULL;
+ }
+ return capsule->name;
+}
+
+
+PyCapsule_Destructor
+PyCapsule_GetDestructor(PyObject *o)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
+ return NULL;
+ }
+ return capsule->destructor;
+}
+
+
+void *
+PyCapsule_GetContext(PyObject *o)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
+ return NULL;
+ }
+ return capsule->context;
+}
+
+
+int
+PyCapsule_SetPointer(PyObject *o, void *pointer)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!pointer) {
+ PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
+ return -1;
+ }
+
+ if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
+ return -1;
+ }
+
+ capsule->pointer = pointer;
+ return 0;
+}
+
+
+int
+PyCapsule_SetName(PyObject *o, const char *name)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
+ return -1;
+ }
+
+ capsule->name = name;
+ return 0;
+}
+
+
+int
+PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
+ return -1;
+ }
+
+ capsule->destructor = destructor;
+ return 0;
+}
+
+
+int
+PyCapsule_SetContext(PyObject *o, void *context)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+
+ if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
+ return -1;
+ }
+
+ capsule->context = context;
+ return 0;
+}
+
+
+void *
+PyCapsule_Import(const char *name, int no_block)
+{
+ PyObject *object = NULL;
+ void *return_value = NULL;
+ char *trace;
+ int name_length = (strlen(name) + 1) * sizeof(char);
+ char *name_dup = (char *)PyMem_MALLOC(name_length);
+
+ if (!name_dup) {
+ return NULL;
+ }
+
+ memcpy(name_dup, name, name_length);
+
+ trace = name_dup;
+ while (trace) {
+ char *dot = strchr(trace, '.');
+ if (dot) {
+ *dot++ = '\0';
+ }
+
+ if (object == NULL) {
+ if (no_block) {
+ object = PyImport_ImportModuleNoBlock(trace);
+ } else {
+ object = PyImport_ImportModule(trace);
+ if (!object) {
+ PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
+ }
+ }
+ } else {
+ PyObject *object2 = PyObject_GetAttrString(object, trace);
+ Py_DECREF(object);
+ object = object2;
+ }
+ if (!object) {
+ goto EXIT;
+ }
+
+ trace = dot;
+ }
+
+ /* compare attribute name to module.name by hand */
+ if (PyCapsule_IsValid(object, name)) {
+ PyCapsule *capsule = (PyCapsule *)object;
+ return_value = capsule->pointer;
+ } else {
+ PyErr_Format(PyExc_AttributeError,
+ "PyCapsule_Import \"%s\" is not valid",
+ name);
+ }
+
+EXIT:
+ Py_XDECREF(object);
+ if (name_dup) {
+ PyMem_FREE(name_dup);
+ }
+ return return_value;
+}
+
+
+static void
+capsule_dealloc(PyObject *o)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+ if (capsule->destructor) {
+ capsule->destructor(o);
+ }
+ PyObject_DEL(o);
+}
+
+
+static PyObject *
+capsule_repr(PyObject *o)
+{
+ PyCapsule *capsule = (PyCapsule *)o;
+ const char *name;
+ const char *quote;
+
+ if (capsule->name) {
+ quote = "\"";
+ name = capsule->name;
+ } else {
+ quote = "";
+ name = "NULL";
+ }
+
+ return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
+ quote, name, quote, capsule);
+}
+
+
+
+PyDoc_STRVAR(PyCapsule_Type__doc__,
+"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
+object. They're a way of passing data through the Python interpreter\n\
+without creating your own custom type.\n\
+\n\
+Capsules are used for communication between extension modules.\n\
+They provide a way for an extension module to export a C interface\n\
+to other extension modules, so that extension modules can use the\n\
+Python import mechanism to link to one another.\n\
+");
+
+PyTypeObject PyCapsule_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "PyCapsule", /*tp_name*/
+ sizeof(PyCapsule), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ capsule_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_reserved*/
+ capsule_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ 0, /*tp_flags*/
+ PyCapsule_Type__doc__ /*tp_doc*/
+};
+
+