Commits

Alex Gaynor committed 9b49e5f

finish(?) +/- segfaults

Comments (0)

Files changed (1)

c/_cffi_backend.c

     int res = PyDict_Contains(self->l_defines, name);
     if (res == -1)
         return NULL;
-    if (res == 1)
+    if (res == 1) {
         PyErr_Format(PyExc_ValueError, "%s was already defined",
             PyString_AS_STRING(name)
         );
         return NULL;
+    }
     res = PyDict_Contains(self->l_property_defines, name);
     if (res == -1)
         return NULL;
-    if (res == 1)
+    if (res == 1) {
         PyErr_Format(PyExc_ValueError, "%s was already defined as a property",
             PyString_AS_STRING(name)
         );
         return NULL;
+    }
     res = PyDict_SetItem(self->l_defines, name, value);
     if (res == -1)
         return NULL;
     Py_RETURN_NONE;
 }
 
+static PyObject *
+ffilibrary_defineproperty(FFILibrary *self, PyObject *args)
+{
+    PyObject *name = NULL;
+    PyObject *getter = NULL;
+    PyObject *setter = NULL;
+    if (!PyArg_ParseTuple(args, "SOO:define_property", &name, &getter, &setter))
+        return NULL;
+    int res = PyDict_Contains(self->l_property_defines, name);
+    if (res == -1)
+        return NULL;
+    if (res == 1) {
+        PyErr_Format(PyExc_ValueError, "%s was already defined as a property",
+            PyString_AS_STRING(name)
+        );
+        return NULL;
+    }
+    res = PyDict_Contains(self->l_defines, name);
+    if (res == -1)
+        return NULL;
+    if (res == 1) {
+        PyErr_Format(PyExc_ValueError, "%s was already defined",
+            PyString_AS_STRING(name)
+        );
+        return NULL;
+    }
+    PyObject *value = Py_BuildValue("OO", getter, setter);
+    res = PyDict_SetItem(self->l_property_defines, name, value);
+    if (res == -1)
+        return NULL;
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+ffilibrary_getattro(FFILibrary *self, PyObject *attr)
+{
+    PyObject *res = PyDict_GetItem(self->l_defines, attr);
+    if (res != NULL) {
+        Py_INCREF(res);
+        return res;
+    }
+    res = PyDict_GetItem(self->l_property_defines, attr);
+    if (res != NULL) {
+        PyObject *getter = PyTuple_GetItem(res, 0);
+        Py_INCREF(getter);
+        res = PyObject_CallFunctionObjArgs(getter, self);
+        Py_INCREF(res);
+        return res;
+    }
+    return PyObject_GenericGetAttr(self, attr);
+}
+
+static int
+ffilibrary_setattro(FFILibrary *self, PyObject *attr, PyObject *value)
+{
+    PyObject *res = PyDict_GetItem(self->l_property_defines, attr);
+    if (res != NULL) {
+        PyObject *setter = PyTuple_GetItem(res, 1);
+        Py_INCREF(setter);
+        res = PyObject_CallFunctionObjArgs(setter, self, value);
+        if (res == NULL)
+            return -1;
+        return 0;
+    }
+    return PyObject_GenericSetAttr(self, attr, value);
+}
+
 static int
 ffilibrary_traverse(FFILibrary *self, visitproc visit, void *arg)
 {
     Py_VISIT(self->l_generic_module);
     Py_VISIT(self->l_ffi);
+    Py_VISIT(self->l_defines);
+    Py_VISIT(self->l_property_defines);
     return 0;
 }
 
 
 static PyMethodDef ffilibrary_methods[] = {
     {"define", ffilibrary_define, METH_VARARGS, NULL},
+    {"define_property", ffilibrary_defineproperty, METH_VARARGS, NULL},
     {NULL},
 };
 
     0,                                          /* tp_hash */
     0,                                          /* tp_call */
     0,                                          /* tp_str */
-    0,                                          /* tp_getattro */
-    0,                                          /* tp_setattro */
+    ffilibrary_getattro,                        /* tp_getattro */
+    ffilibrary_setattro,                        /* tp_setattro */
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT,                         /* tp_flags */
     0,                                          /* tp_doc */