mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 19:43:32 +00:00
9b29358511
Status lines for Emacs and Vim have been added to Python sources so they'll be easier to edit using Python's preferred coding style. Some DNS helper functions have been broken up into multiple files. It's nice to have one function per file whenever possible, since that way we don't need -ffunction-sections. Another reason it's good to have small source files, is because the build will be enforcing resource limits on compilation and testing soon.
336 lines
8.3 KiB
C
336 lines
8.3 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Python 3 │
|
|
│ https://docs.python.org/3/license.html │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "third_party/python/Include/import.h"
|
|
#include "third_party/python/Include/object.h"
|
|
#include "third_party/python/Include/objimpl.h"
|
|
#include "third_party/python/Include/pycapsule.h"
|
|
#include "third_party/python/Include/pyerrors.h"
|
|
#include "third_party/python/Include/pymacro.h"
|
|
/* clang-format off */
|
|
|
|
/* Wrap void * pointers to be passed between C modules */
|
|
|
|
/* 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 PyErr_NoMemory();
|
|
}
|
|
|
|
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*/
|
|
};
|
|
|
|
|