2019-04-12 22:56:50 -03:00
|
|
|
#define PY_SSIZE_T_CLEAN
|
2018-04-07 13:27:05 -03:00
|
|
|
#include <Python.h>
|
|
|
|
#include "structmember.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
PyObject *first; /* first name */
|
|
|
|
PyObject *last; /* last name */
|
|
|
|
int number;
|
|
|
|
} CustomObject;
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_traverse(CustomObject *self, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
Py_VISIT(self->first);
|
|
|
|
Py_VISIT(self->last);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_clear(CustomObject *self)
|
|
|
|
{
|
|
|
|
Py_CLEAR(self->first);
|
|
|
|
Py_CLEAR(self->last);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Custom_dealloc(CustomObject *self)
|
|
|
|
{
|
|
|
|
PyObject_GC_UnTrack(self);
|
|
|
|
Custom_clear(self);
|
|
|
|
Py_TYPE(self)->tp_free((PyObject *) self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
|
|
|
CustomObject *self;
|
|
|
|
self = (CustomObject *) type->tp_alloc(type, 0);
|
|
|
|
if (self != NULL) {
|
|
|
|
self->first = PyUnicode_FromString("");
|
|
|
|
if (self->first == NULL) {
|
|
|
|
Py_DECREF(self);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
self->last = PyUnicode_FromString("");
|
|
|
|
if (self->last == NULL) {
|
|
|
|
Py_DECREF(self);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
self->number = 0;
|
|
|
|
}
|
|
|
|
return (PyObject *) self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
|
|
|
|
{
|
|
|
|
static char *kwlist[] = {"first", "last", "number", NULL};
|
|
|
|
PyObject *first = NULL, *last = NULL, *tmp;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
|
|
|
|
&first, &last,
|
|
|
|
&self->number))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
tmp = self->first;
|
|
|
|
Py_INCREF(first);
|
|
|
|
self->first = first;
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
}
|
|
|
|
if (last) {
|
|
|
|
tmp = self->last;
|
|
|
|
Py_INCREF(last);
|
|
|
|
self->last = last;
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyMemberDef Custom_members[] = {
|
|
|
|
{"number", T_INT, offsetof(CustomObject, number), 0,
|
|
|
|
"custom number"},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_getfirst(CustomObject *self, void *closure)
|
|
|
|
{
|
|
|
|
Py_INCREF(self->first);
|
|
|
|
return self->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
|
|
|
|
{
|
|
|
|
if (value == NULL) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!PyUnicode_Check(value)) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"The first attribute value must be a string");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Py_INCREF(value);
|
|
|
|
Py_CLEAR(self->first);
|
|
|
|
self->first = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_getlast(CustomObject *self, void *closure)
|
|
|
|
{
|
|
|
|
Py_INCREF(self->last);
|
|
|
|
return self->last;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Custom_setlast(CustomObject *self, PyObject *value, void *closure)
|
|
|
|
{
|
|
|
|
if (value == NULL) {
|
|
|
|
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!PyUnicode_Check(value)) {
|
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"The last attribute value must be a string");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Py_INCREF(value);
|
|
|
|
Py_CLEAR(self->last);
|
|
|
|
self->last = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyGetSetDef Custom_getsetters[] = {
|
|
|
|
{"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
|
|
|
|
"first name", NULL},
|
|
|
|
{"last", (getter) Custom_getlast, (setter) Custom_setlast,
|
|
|
|
"last name", NULL},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
|
|
|
|
{
|
|
|
|
return PyUnicode_FromFormat("%S %S", self->first, self->last);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyMethodDef Custom_methods[] = {
|
|
|
|
{"name", (PyCFunction) Custom_name, METH_NOARGS,
|
|
|
|
"Return the name, combining the first and last name"
|
|
|
|
},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyTypeObject CustomType = {
|
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
|
.tp_name = "custom4.Custom",
|
|
|
|
.tp_doc = "Custom objects",
|
|
|
|
.tp_basicsize = sizeof(CustomObject),
|
|
|
|
.tp_itemsize = 0,
|
|
|
|
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
|
|
|
.tp_new = Custom_new,
|
|
|
|
.tp_init = (initproc) Custom_init,
|
|
|
|
.tp_dealloc = (destructor) Custom_dealloc,
|
|
|
|
.tp_traverse = (traverseproc) Custom_traverse,
|
|
|
|
.tp_clear = (inquiry) Custom_clear,
|
|
|
|
.tp_members = Custom_members,
|
|
|
|
.tp_methods = Custom_methods,
|
|
|
|
.tp_getset = Custom_getsetters,
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyModuleDef custommodule = {
|
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
|
.m_name = "custom4",
|
|
|
|
.m_doc = "Example module that creates an extension type.",
|
|
|
|
.m_size = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
PyInit_custom4(void)
|
|
|
|
{
|
|
|
|
PyObject *m;
|
|
|
|
if (PyType_Ready(&CustomType) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
m = PyModule_Create(&custommodule);
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
Py_INCREF(&CustomType);
|
|
|
|
PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
|
|
|
|
return m;
|
|
|
|
}
|