chiark / gitweb /
*.c: Make all of the type-definition tables read-only.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 20 Oct 2019 21:46:05 +0000 (22:46 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 11:44:14 +0000 (12:44 +0100)
The hard part is a new collection of macros which strip the `const'
qualifier from the actual table definitions, after checking that they
actually have the correct type.

And then there's the slog of actually changing all of the definitions
and using the new macros.

mapping.c
pyke.c
pyke.h

index 229dfa99b32eafb136c9c9cb3d01b74a7f54cad7..615c5edcbdefe8e1211d04e45609994d33dddc6d 100644 (file)
--- a/mapping.c
+++ b/mapping.c
@@ -160,7 +160,7 @@ static PyTypeObject valiter_pytype_skel = {
   0                                    /* @tp_is_gc@ */
 };
 
-PySequenceMethods gmap_pysequence = {
+const PySequenceMethods gmap_pysequence = {
   0,                                   /* @sq_length@ */
   0,                                   /* @sq_concat@ */
   0,                                   /* @sq_repeat@ */
@@ -403,7 +403,7 @@ end:
   return (rc);
 }
 
-PyMethodDef gmap_pymethods[] = {
+const PyMethodDef gmap_pymethods[] = {
   GMAP_METHODS
   { 0 }
 };
diff --git a/pyke.c b/pyke.c
index 883223a925f69b4b667d2fd1109240ee281ff156..b462a1f8196454005769025753c0a89192e5359a 100644 (file)
--- a/pyke.c
+++ b/pyke.c
@@ -260,7 +260,7 @@ PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta)
 /*----- Populating modules ------------------------------------------------*/
 
 PyObject *mkexc(PyObject *mod, PyObject *base,
-               const char *name, PyMethodDef *mm)
+               const char *name, const PyMethodDef *mm)
 {
   PyObject *nameobj = 0;
   PyObject *dict = 0;
@@ -272,7 +272,8 @@ PyObject *mkexc(PyObject *mod, PyObject *base,
 
   if (mm) {
     while (mm->ml_name) {
-      if ((func = PyCFunction_NewEx(mm, 0, mod)) == 0 ||
+      if ((func = PyCFunction_NewEx((/*unconst*/ PyMethodDef *)mm,
+                                   0, mod)) == 0 ||
          (meth = PyMethod_New(func, 0, exc)) == 0 ||
          PyDict_SetItemString(dict, mm->ml_name, meth))
        goto fail;
diff --git a/pyke.h b/pyke.h
index b91b48df073f470f8d6cac555287a2186f40919b..e200c097af927c67021a7855ce49abc3e61d330c 100644 (file)
--- a/pyke.h
+++ b/pyke.h
@@ -269,6 +269,20 @@ extern PyTypeObject *inittype(PyTypeObject */*skel*/,
 #define MEMBER(name, ty, f, doc)                                       \
   { #name, ty, offsetof(MEMBERSTRUCT, name), f, doc },
 
+/* Wrappers for filling in pointers in a `PyTypeObject' structure, (a)
+ * following Pyke naming convention, and (b) stripping `const' from the types
+ * without losing type safety.
+ */
+#define UNCONST_TYPE_SLOT(type, suffix, op, ty)                                \
+  CONVERT_CAREFULLY(type *, const type *, op ty##_py##suffix)
+#define PYGETSET(ty) UNCONST_TYPE_SLOT(PyGetSetDef, getset, NOTHING, ty)
+#define PYMETHODS(ty) UNCONST_TYPE_SLOT(PyMethodDef, methods, NOTHING, ty)
+#define PYMEMBERS(ty) UNCONST_TYPE_SLOT(PyMemberDef, members, NOTHING, ty)
+#define PYNUMBER(ty) UNCONST_TYPE_SLOT(PyNumberMethods, number, &, ty)
+#define PYSEQUENCE(ty) UNCONST_TYPE_SLOT(PySequenceMethods, sequence, &, ty)
+#define PYMAPPING(ty) UNCONST_TYPE_SLOT(PyMappingMethods, mapping, &, ty)
+#define PYBUFFER(ty) UNCONST_TYPE_SLOT(PyBufferProcs, buffer, &, ty)
+
 /*----- Populating modules ------------------------------------------------*/
 
 extern PyObject *modname;
@@ -278,7 +292,7 @@ extern PyObject *home_module;
   /* The overall module object. */
 
 extern PyObject *mkexc(PyObject */*mod*/, PyObject */*base*/,
-                      const char */*name*/, PyMethodDef */*methods*/);
+                      const char */*name*/, const PyMethodDef */*methods*/);
   /* Make and return an exception class called NAME, which will end up in
    * module MOD (though it is not added at this time).  The new class is a
    * subclass of BASE.  Attach the METHODS to it.
@@ -376,8 +390,8 @@ GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL)
 
 /* Mapping protocol implementation. */
 extern Py_ssize_t gmap_pysize(PyObject *); /* for `mp_length' */
-extern PySequenceMethods gmap_pysequence; /* for `tp_as_sequence' */
-extern PyMethodDef gmap_pymethods[]; /* all the standard methods */
+extern const PySequenceMethods gmap_pysequence; /* for `tp_as_sequence' */
+extern const PyMethodDef gmap_pymethods[]; /* all the standard methods */
 
 /*----- That's all, folks -------------------------------------------------*/