/* 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 name1 == 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; | |
size_t 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 PyString_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*/ | |
}; | |