Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 1 | /* Wrap void * pointers to be passed between C modules */ |
| 2 | |
| 3 | #include "Python.h" |
| 4 | |
| 5 | /* Internal structure of PyCapsule */ |
| 6 | typedef struct { |
| 7 | PyObject_HEAD |
| 8 | void *pointer; |
| 9 | const char *name; |
| 10 | void *context; |
| 11 | PyCapsule_Destructor destructor; |
| 12 | } PyCapsule; |
| 13 | |
| 14 | |
| 15 | |
| 16 | static int |
| 17 | _is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule) |
| 18 | { |
| 19 | if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) { |
| 20 | PyErr_SetString(PyExc_ValueError, invalid_capsule); |
| 21 | return 0; |
| 22 | } |
| 23 | return 1; |
| 24 | } |
| 25 | |
| 26 | #define is_legal_capsule(capsule, name) \ |
| 27 | (_is_legal_capsule(capsule, \ |
| 28 | name " called with invalid PyCapsule object")) |
| 29 | |
| 30 | |
| 31 | static int |
| 32 | name_matches(const char *name1, const char *name2) { |
| 33 | /* if either is NULL, */ |
| 34 | if (!name1 || !name2) { |
| 35 | /* they're only the same if they're both NULL. */ |
Benjamin Peterson | 3e79190 | 2009-06-28 16:23:55 +0000 | [diff] [blame] | 36 | return name1 == name2; |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 37 | } |
| 38 | return !strcmp(name1, name2); |
| 39 | } |
| 40 | |
| 41 | |
| 42 | |
| 43 | PyObject * |
| 44 | PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor) |
| 45 | { |
| 46 | PyCapsule *capsule; |
| 47 | |
| 48 | if (!pointer) { |
| 49 | PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer"); |
| 50 | return NULL; |
| 51 | } |
| 52 | |
Victor Stinner | 9205520 | 2020-04-08 00:38:15 +0200 | [diff] [blame] | 53 | capsule = PyObject_New(PyCapsule, &PyCapsule_Type); |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 54 | if (capsule == NULL) { |
| 55 | return NULL; |
| 56 | } |
| 57 | |
| 58 | capsule->pointer = pointer; |
| 59 | capsule->name = name; |
| 60 | capsule->context = NULL; |
| 61 | capsule->destructor = destructor; |
| 62 | |
| 63 | return (PyObject *)capsule; |
| 64 | } |
| 65 | |
| 66 | |
| 67 | int |
| 68 | PyCapsule_IsValid(PyObject *o, const char *name) |
| 69 | { |
| 70 | PyCapsule *capsule = (PyCapsule *)o; |
| 71 | |
| 72 | return (capsule != NULL && |
| 73 | PyCapsule_CheckExact(capsule) && |
| 74 | capsule->pointer != NULL && |
| 75 | name_matches(capsule->name, name)); |
| 76 | } |
| 77 | |
| 78 | |
| 79 | void * |
| 80 | PyCapsule_GetPointer(PyObject *o, const char *name) |
| 81 | { |
| 82 | PyCapsule *capsule = (PyCapsule *)o; |
| 83 | |
| 84 | if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) { |
| 85 | return NULL; |
| 86 | } |
| 87 | |
| 88 | if (!name_matches(name, capsule->name)) { |
| 89 | PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name"); |
| 90 | return NULL; |
| 91 | } |
| 92 | |
| 93 | return capsule->pointer; |
| 94 | } |
| 95 | |
| 96 | |
| 97 | const char * |
| 98 | PyCapsule_GetName(PyObject *o) |
| 99 | { |
| 100 | PyCapsule *capsule = (PyCapsule *)o; |
| 101 | |
| 102 | if (!is_legal_capsule(capsule, "PyCapsule_GetName")) { |
| 103 | return NULL; |
| 104 | } |
| 105 | return capsule->name; |
| 106 | } |
| 107 | |
| 108 | |
| 109 | PyCapsule_Destructor |
| 110 | PyCapsule_GetDestructor(PyObject *o) |
| 111 | { |
| 112 | PyCapsule *capsule = (PyCapsule *)o; |
| 113 | |
| 114 | if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) { |
| 115 | return NULL; |
| 116 | } |
| 117 | return capsule->destructor; |
| 118 | } |
| 119 | |
| 120 | |
| 121 | void * |
| 122 | PyCapsule_GetContext(PyObject *o) |
| 123 | { |
| 124 | PyCapsule *capsule = (PyCapsule *)o; |
| 125 | |
| 126 | if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) { |
| 127 | return NULL; |
| 128 | } |
| 129 | return capsule->context; |
| 130 | } |
| 131 | |
| 132 | |
| 133 | int |
| 134 | PyCapsule_SetPointer(PyObject *o, void *pointer) |
| 135 | { |
| 136 | PyCapsule *capsule = (PyCapsule *)o; |
| 137 | |
| 138 | if (!pointer) { |
| 139 | PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer"); |
| 140 | return -1; |
| 141 | } |
| 142 | |
| 143 | if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) { |
| 144 | return -1; |
| 145 | } |
| 146 | |
| 147 | capsule->pointer = pointer; |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | |
| 152 | int |
| 153 | PyCapsule_SetName(PyObject *o, const char *name) |
| 154 | { |
| 155 | PyCapsule *capsule = (PyCapsule *)o; |
| 156 | |
| 157 | if (!is_legal_capsule(capsule, "PyCapsule_SetName")) { |
| 158 | return -1; |
| 159 | } |
| 160 | |
| 161 | capsule->name = name; |
| 162 | return 0; |
| 163 | } |
| 164 | |
| 165 | |
| 166 | int |
| 167 | PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor) |
| 168 | { |
| 169 | PyCapsule *capsule = (PyCapsule *)o; |
| 170 | |
| 171 | if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) { |
| 172 | return -1; |
| 173 | } |
| 174 | |
| 175 | capsule->destructor = destructor; |
| 176 | return 0; |
| 177 | } |
| 178 | |
| 179 | |
| 180 | int |
| 181 | PyCapsule_SetContext(PyObject *o, void *context) |
| 182 | { |
| 183 | PyCapsule *capsule = (PyCapsule *)o; |
| 184 | |
| 185 | if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) { |
| 186 | return -1; |
| 187 | } |
| 188 | |
| 189 | capsule->context = context; |
| 190 | return 0; |
| 191 | } |
| 192 | |
| 193 | |
| 194 | void * |
| 195 | PyCapsule_Import(const char *name, int no_block) |
| 196 | { |
| 197 | PyObject *object = NULL; |
| 198 | void *return_value = NULL; |
| 199 | char *trace; |
Mark Dickinson | 8504d08 | 2009-10-03 20:13:37 +0000 | [diff] [blame] | 200 | size_t name_length = (strlen(name) + 1) * sizeof(char); |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 201 | char *name_dup = (char *)PyMem_MALLOC(name_length); |
| 202 | |
| 203 | if (!name_dup) { |
Zackery Spytz | 4c49da0 | 2018-12-07 03:11:30 -0700 | [diff] [blame] | 204 | return PyErr_NoMemory(); |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | memcpy(name_dup, name, name_length); |
| 208 | |
| 209 | trace = name_dup; |
| 210 | while (trace) { |
| 211 | char *dot = strchr(trace, '.'); |
| 212 | if (dot) { |
| 213 | *dot++ = '\0'; |
| 214 | } |
| 215 | |
| 216 | if (object == NULL) { |
| 217 | if (no_block) { |
| 218 | object = PyImport_ImportModuleNoBlock(trace); |
| 219 | } else { |
| 220 | object = PyImport_ImportModule(trace); |
| 221 | if (!object) { |
| 222 | PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace); |
| 223 | } |
| 224 | } |
| 225 | } else { |
| 226 | PyObject *object2 = PyObject_GetAttrString(object, trace); |
| 227 | Py_DECREF(object); |
| 228 | object = object2; |
| 229 | } |
| 230 | if (!object) { |
| 231 | goto EXIT; |
| 232 | } |
| 233 | |
| 234 | trace = dot; |
| 235 | } |
| 236 | |
| 237 | /* compare attribute name to module.name by hand */ |
| 238 | if (PyCapsule_IsValid(object, name)) { |
| 239 | PyCapsule *capsule = (PyCapsule *)object; |
| 240 | return_value = capsule->pointer; |
| 241 | } else { |
| 242 | PyErr_Format(PyExc_AttributeError, |
| 243 | "PyCapsule_Import \"%s\" is not valid", |
| 244 | name); |
| 245 | } |
| 246 | |
| 247 | EXIT: |
| 248 | Py_XDECREF(object); |
| 249 | if (name_dup) { |
| 250 | PyMem_FREE(name_dup); |
| 251 | } |
| 252 | return return_value; |
| 253 | } |
| 254 | |
| 255 | |
| 256 | static void |
| 257 | capsule_dealloc(PyObject *o) |
| 258 | { |
| 259 | PyCapsule *capsule = (PyCapsule *)o; |
| 260 | if (capsule->destructor) { |
| 261 | capsule->destructor(o); |
| 262 | } |
| 263 | PyObject_DEL(o); |
| 264 | } |
| 265 | |
| 266 | |
| 267 | static PyObject * |
| 268 | capsule_repr(PyObject *o) |
| 269 | { |
| 270 | PyCapsule *capsule = (PyCapsule *)o; |
| 271 | const char *name; |
| 272 | const char *quote; |
| 273 | |
| 274 | if (capsule->name) { |
| 275 | quote = "\""; |
| 276 | name = capsule->name; |
| 277 | } else { |
| 278 | quote = ""; |
| 279 | name = "NULL"; |
| 280 | } |
| 281 | |
| 282 | return PyUnicode_FromFormat("<capsule object %s%s%s at %p>", |
| 283 | quote, name, quote, capsule); |
| 284 | } |
| 285 | |
| 286 | |
| 287 | |
| 288 | PyDoc_STRVAR(PyCapsule_Type__doc__, |
| 289 | "Capsule objects let you wrap a C \"void *\" pointer in a Python\n\ |
| 290 | object. They're a way of passing data through the Python interpreter\n\ |
| 291 | without creating your own custom type.\n\ |
| 292 | \n\ |
| 293 | Capsules are used for communication between extension modules.\n\ |
| 294 | They provide a way for an extension module to export a C interface\n\ |
| 295 | to other extension modules, so that extension modules can use the\n\ |
| 296 | Python import mechanism to link to one another.\n\ |
| 297 | "); |
| 298 | |
| 299 | PyTypeObject PyCapsule_Type = { |
| 300 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
Alexander Belopolsky | f0f4514 | 2010-08-11 17:31:17 +0000 | [diff] [blame] | 301 | "PyCapsule", /*tp_name*/ |
| 302 | sizeof(PyCapsule), /*tp_basicsize*/ |
| 303 | 0, /*tp_itemsize*/ |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 304 | /* methods */ |
| 305 | capsule_dealloc, /*tp_dealloc*/ |
Jeroen Demeyer | 530f506 | 2019-05-31 04:13:39 +0200 | [diff] [blame] | 306 | 0, /*tp_vectorcall_offset*/ |
Alexander Belopolsky | f0f4514 | 2010-08-11 17:31:17 +0000 | [diff] [blame] | 307 | 0, /*tp_getattr*/ |
| 308 | 0, /*tp_setattr*/ |
Jeroen Demeyer | 530f506 | 2019-05-31 04:13:39 +0200 | [diff] [blame] | 309 | 0, /*tp_as_async*/ |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 310 | capsule_repr, /*tp_repr*/ |
Alexander Belopolsky | f0f4514 | 2010-08-11 17:31:17 +0000 | [diff] [blame] | 311 | 0, /*tp_as_number*/ |
| 312 | 0, /*tp_as_sequence*/ |
| 313 | 0, /*tp_as_mapping*/ |
| 314 | 0, /*tp_hash*/ |
| 315 | 0, /*tp_call*/ |
| 316 | 0, /*tp_str*/ |
| 317 | 0, /*tp_getattro*/ |
| 318 | 0, /*tp_setattro*/ |
| 319 | 0, /*tp_as_buffer*/ |
| 320 | 0, /*tp_flags*/ |
| 321 | PyCapsule_Type__doc__ /*tp_doc*/ |
Benjamin Peterson | b173f78 | 2009-05-05 22:31:58 +0000 | [diff] [blame] | 322 | }; |
| 323 | |
| 324 | |