chiark / gitweb /
Add 'pyke/' from commit '6c2569879c220eeac35957cdba9a043e8a5ea9ed'
authorMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 14:22:40 +0000 (15:22 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 11 Apr 2020 14:22:40 +0000 (15:22 +0100)
git-subtree-dir: pyke
git-subtree-mainline: c76685552d4bda3d354a8237749106e4460a4270
git-subtree-split: 6c2569879c220eeac35957cdba9a043e8a5ea9ed

1  2 
pyke/.skelrc
pyke/mapping-mLib.c
pyke/mapping.c
pyke/pyke-mLib.c
pyke/pyke-mLib.h
pyke/pyke.c
pyke/pyke.h

diff --combined pyke/.skelrc
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..21912db9242a9099b240a5dbc8f97eae3583815c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++;;; -*-emacs-lisp-*-
++
++(setq skel-alist
++      (append
++       '((author . "Straylight/Edgeware")
++       (licence-text . "[[gpl]]")
++       (full-title . "Pyke: the Python Kit for Extensions")
++       (program . "Pyke"))
++       skel-alist))
diff --combined pyke/mapping-mLib.c
index 0000000000000000000000000000000000000000,9b5c37e203ec6b04d7a8b3b615732820206206f2..9b5c37e203ec6b04d7a8b3b615732820206206f2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,36 +1,36 @@@
+ /* -*-c-*-
+  *
+  * Generic mapping support, with mLib integration
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ /*----- Header files ------------------------------------------------------*/
+ #include "pyke-mLib.h"
+ /*----- Main code ---------------------------------------------------------*/
+ Py_ssize_t gmap_pysize_from_sym(sym_table *tab)
+   { return (SYM_LIMIT(tab->t.mask + 1) - tab->load); }
+ /*----- That's all, folks -------------------------------------------------*/
diff --combined pyke/mapping.c
index 0000000000000000000000000000000000000000,ad02d253396f32d0b672bd3fd840952af000fa67..ad02d253396f32d0b672bd3fd840952af000fa67
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,965 +1,965 @@@
+ /* -*-c-*-
+  *
+  * Generic mapping support
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ /*----- Header files ------------------------------------------------------*/
+ #include "pyke.h"
+ /*----- Iteration ---------------------------------------------------------*/
+ static PyTypeObject *keyiter_pytype, *itemiter_pytype, *valiter_pytype;
+ union iterstate {
+   void *external;
+   void *internal[4];
+ };
+ typedef struct iter_pyobj {
+   PyObject_HEAD
+   PyObject *map;
+   union iterstate iter;
+ } iter_pyobj;
+ #define ITER_MAP(o) (((iter_pyobj *)(o))->map)
+ #define ITER_ITER(o) (&((iter_pyobj *)(o))->iter)
+ #define ITER_EXTERNALP(o)                                             \
+   (GMAP_OPS(ITER_MAP(o))->isz > sizeof(union iterstate))
+ #define ITER_I(o) (ITER_EXTERNALP(o) ? ITER_ITER(o)->external         \
+                                    : &ITER_ITER(o)->internal)
+ static void *iter_init(PyObject *me, union iterstate *iter)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   void *i;
+   if (gmops->isz <= sizeof(*iter)) i = &iter->internal;
+   else { i = iter->external = PyObject_Malloc(gmops->isz); assert(i); }
+   gmops->iter_init(me, i);
+   return (i);
+ }
+ static void iter_free(PyObject *me, union iterstate *iter)
+   { if (GMAP_OPS(me)->isz > sizeof(*iter)) PyObject_Free(iter->external); }
+ static void iter_pydealloc(PyObject *me)
+ {
+   PyObject *map = ITER_MAP(me);
+   iter_free(map, ITER_ITER(me));
+   Py_DECREF(map); FREEOBJ(me);
+ }
+ static PyObject *gmap_mkiter(PyObject *me, PyTypeObject *ty)
+ {
+   iter_pyobj *iter = PyObject_NEW(iter_pyobj, ty);
+   iter->map = me; Py_INCREF(me);
+   iter_init(me, &iter->iter);
+   return ((PyObject *)iter);
+ }
+ static PyObject *keyiter_pynext(PyObject *me)
+ {
+   PyObject *map = ITER_MAP(me);
+   const struct gmap_ops *gmops = GMAP_OPS(map);
+   void *e = gmops->iter_next(map, ITER_I(me));
+   if (!e) return (0);
+   else return (gmops->entry_key(map, e));
+ }
+ static const PyTypeObject keyiter_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_KeyIter",                         /* @tp_name@ */
+   sizeof(iter_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   iter_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "Iterates over the keys of a mapping.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   0,                                  /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   PyObject_SelfIter,                  /* @tp_iter@ */
+   keyiter_pynext,                     /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ static PyObject *valiter_pynext(PyObject *me)
+ {
+   PyObject *map = ITER_MAP(me);
+   const struct gmap_ops *gmops = GMAP_OPS(map);
+   void *e = gmops->iter_next(map, ITER_I(me));
+   if (!e) return (0);
+   else return (gmops->entry_value(map, e));
+ }
+ static const PyTypeObject valiter_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_ValueIter",                               /* @tp_name@ */
+   sizeof(iter_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   iter_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "Iterates over the values of a mapping.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   0,                                  /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   PyObject_SelfIter,                  /* @tp_iter@ */
+   valiter_pynext,                     /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ static PyObject *itemiter_pynext(PyObject *me)
+ {
+   PyObject *map = ITER_MAP(me);
+   const struct gmap_ops *gmops = GMAP_OPS(map);
+   void *e = gmops->iter_next(map, ITER_I(me));
+   PyObject *rc = 0;
+   if (e)
+     rc = Py_BuildValue("(NN)",
+                      gmops->entry_key(map, e),
+                      gmops->entry_value(map, e));
+   return (rc);
+ }
+ static const PyTypeObject itemiter_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_ItemIter",                                /* @tp_name@ */
+   sizeof(iter_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   iter_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "Iterates over the items of a mapping.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   0,                                  /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   PyObject_SelfIter,                  /* @tp_iter@ */
+   itemiter_pynext,                    /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ /*----- Mapping views -----------------------------------------------------*/
+ #ifdef PY3
+ static PyTypeObject *keyview_pytype, *itemview_pytype, *valview_pytype;
+ typedef struct view_pyobj {
+   PyObject_HEAD
+   PyObject *map;
+ } view_pyobj;
+ #define VIEW_MAP(o) (((view_pyobj *)(o))->map)
+ static PyObject *gmap_mkview(PyObject *me, PyTypeObject *ty)
+ {
+   view_pyobj *v = PyObject_NEW(view_pyobj, ty);
+   v->map = me; Py_INCREF(me);
+   return ((PyObject *)v);
+ }
+ static void view_pydealloc(PyObject *me)
+   { Py_DECREF(VIEW_MAP(me)); FREEOBJ(me); }
+ #define BINOP(op, update)                                             \
+   static PyObject *view_py##op(PyObject *me, PyObject *you)           \
+   {                                                                   \
+     PyObject *set = 0;                                                        \
+     PyObject *rc = 0;                                                 \
+                                                                       \
+     set = PySet_New(me); if (!set) goto end;                          \
+     if (!PyObject_CallMethod(set, #update, "(O)", you)) goto end;     \
+     rc = set; set = 0;                                                        \
+   end:                                                                        \
+     Py_XDECREF(set);                                                  \
+     return (rc);                                                      \
+   }
+ BINOP(and, intersection_update)
+ BINOP(or, update)
+ BINOP(xor, symmetric_difference_update)
+ #undef BINOP
+ static int all_contained_p(PyObject *x, PyObject *y)
+ {
+   PyObject *i = 0, *e;
+   int b, rc = -1;
+   i = PyObject_GetIter(x); if (!i) goto end;
+   for (;;) {
+     e = PyIter_Next(i); if (!e) break;
+     b = PySequence_Contains(y, e); Py_DECREF(e); if (b < 0) goto end;
+     if (!b) { rc = 0; goto end; }
+   }
+   if (PyErr_Occurred()) goto end;
+   rc = 1;
+ end:
+   Py_XDECREF(i);
+   return (rc);
+ }
+ static Py_ssize_t view_pysize(PyObject *me)
+   { return (PyMapping_Size(VIEW_MAP(me))); }
+ static PyObject *view_pyrichcompare(PyObject *me, PyObject *you, int op)
+ {
+   PyObject *map = ITER_MAP(me);
+   Py_ssize_t mysz, yoursz;
+   int b;
+   mysz = PyMapping_Size(map); if (mysz < 0) return (0);
+   yoursz = PyObject_Size(you);
+   if (yoursz < 0) { PyErr_Clear(); RETURN_NOTIMPL; }
+   switch (op) {
+     case Py_EQ:
+       if (mysz != yoursz) RETURN_FALSE;
+       b = all_contained_p(you, me);
+       break;
+     case Py_NE:
+       if (mysz != yoursz) RETURN_TRUE;
+       b = all_contained_p(you, me);
+       break;
+     case Py_LT:
+       if (mysz >= yoursz) RETURN_FALSE;
+       b = all_contained_p(me, you);
+       break;
+     case Py_LE:
+       if (mysz > yoursz) RETURN_FALSE;
+       b = all_contained_p(me, you);
+       break;
+     case Py_GE:
+       if (mysz < yoursz) RETURN_FALSE;
+       b = all_contained_p(you, me);
+       break;
+     case Py_GT:
+       if (mysz <= yoursz) RETURN_FALSE;
+       b = all_contained_p(you, me);
+       break;
+     default:
+       abort();
+   }
+   if (b < 0) return (0);
+   return (getbool(b));
+ }
+ static PyObject *keyview_pyiter(PyObject *me)
+   { return (gmap_mkiter(VIEW_MAP(me), keyiter_pytype)); }
+ static int keyview_pyhaskey(PyObject *me, PyObject *k)
+ {
+   PyObject *map = VIEW_MAP(me);
+   const struct gmap_ops *gmops = GMAP_OPS(map);
+   return (gmops->lookup(map, k, 0) ? 1 : PyErr_Occurred() ? -1 : 0);
+ }
+ static int itemview_pyhaskey(PyObject *me, PyObject *it)
+ {
+   PyObject *map = VIEW_MAP(me);
+   const struct gmap_ops *gmops = GMAP_OPS(map);
+   void *e;
+   int b;
+   PyObject *v;
+   if (!PyTuple_Check(it) || PyTuple_GET_SIZE(it) != 2) return (0);
+   e = gmops->lookup(map, PyTuple_GET_ITEM(it, 0), 0);
+   if (!e) return (PyErr_Occurred() ? -1 : 0);
+   v = gmops->entry_value(map, e); if (!v) return (-1);
+   b = PyObject_RichCompareBool(v, PyTuple_GET_ITEM(it, 1), Py_EQ);
+   Py_DECREF(v); return (b);
+ }
+ static PyObject *valview_pyiter(PyObject *me)
+   { return (gmap_mkiter(VIEW_MAP(me), valiter_pytype)); }
+ static PyObject *itemview_pyiter(PyObject *me)
+   { return (gmap_mkiter(VIEW_MAP(me), itemiter_pytype)); }
+ static const PyNumberMethods view_pynumber = {
+   0,                                  /* @nb_add@ */
+   0,                                  /* @nb_subtract@ */
+   0,                                  /* @nb_multiply@ */
+ #ifdef PY2
+   0,                                  /* @nb_divide@ */
+ #endif
+   0,                                  /* @nb_remainder@ */
+   0,                                  /* @nb_divmod@ */
+   0,                                  /* @nb_power@ */
+   0,                                  /* @nb_negative@ */
+   0,                                  /* @nb_positive@ */
+   0,                                  /* @nb_absolute@ */
+   0,                                  /* @nb_nonzero@ */
+   0,                                  /* @nb_invert@ */
+   0,                                  /* @nb_lshift@ */
+   0,                                  /* @nb_rshift@ */
+   view_pyand,                         /* @nb_and@ */
+   view_pyxor,                         /* @nb_xor@ */
+   view_pyor,                          /* @nb_or@ */
+   0,                                  /* @nb_coerce@ */
+   0,                                  /* @nb_int@ */
+   0,                                  /* @nb_long@ */
+   0,                                  /* @nb_float@ */
+   0,                                  /* @nb_oct@ */
+   0,                                  /* @nb_hex@ */
+ };
+ static const PySequenceMethods keyview_pysequence = {
+   view_pysize,                                /* @sq_length@ */
+   0,                                  /* @sq_concat@ */
+   0,                                  /* @sq_repeat@ */
+   0,                                  /* @sq_item@ */
+   0,                                  /* @sq_slice@ */
+   0,                                  /* @sq_ass_item@ */
+   0,                                  /* @sq_ass_slice@ */
+   keyview_pyhaskey,                   /* @sq_contains@ */
+   0,                                  /* @sq_inplace_concat@ */
+   0,                                  /* @sq_inplace_repeat@ */
+ };
+ static const PyTypeObject keyview_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_KeyView",                         /* @tp_name@ */
+   sizeof(view_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   view_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @tp_repr@ */
+   PYNUMBER(view),                     /* @tp_as_number@ */
+   PYSEQUENCE(keyview),                        /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "View of a mapping's keys.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   view_pyrichcompare,                 /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   keyview_pyiter,                     /* @tp_iter@ */
+   0,                                  /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ static const PySequenceMethods valview_pysequence = {
+   view_pysize,                                /* @sq_length@ */
+   0,                                  /* @sq_concat@ */
+   0,                                  /* @sq_repeat@ */
+   0,                                  /* @sq_item@ */
+   0,                                  /* @sq_slice@ */
+   0,                                  /* @sq_ass_item@ */
+   0,                                  /* @sq_ass_slice@ */
+   0,                                  /* @sq_contains@ */
+   0,                                  /* @sq_inplace_concat@ */
+   0,                                  /* @sq_inplace_repeat@ */
+ };
+ static const PyTypeObject valview_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_ValueView",                               /* @tp_name@ */
+   sizeof(view_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   view_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @tp_repr@ */
+   PYNUMBER(view),                     /* @tp_as_number@ */
+   PYSEQUENCE(valview),                        /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "View of a mapping's values.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   0,                                  /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   valview_pyiter,                     /* @tp_iter@ */
+   0,                                  /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ static const PySequenceMethods itemview_pysequence = {
+   view_pysize,                                /* @sq_length@ */
+   0,                                  /* @sq_concat@ */
+   0,                                  /* @sq_repeat@ */
+   0,                                  /* @sq_item@ */
+   0,                                  /* @sq_slice@ */
+   0,                                  /* @sq_ass_item@ */
+   0,                                  /* @sq_ass_slice@ */
+   itemview_pyhaskey,                  /* @sq_contains@ */
+   0,                                  /* @sq_inplace_concat@ */
+   0,                                  /* @sq_inplace_repeat@ */
+ };
+ static const PyTypeObject itemview_pytype_skel = {
+   PyVarObject_HEAD_INIT(0, 0)         /* Header */
+   "_ItemView",                                /* @tp_name@ */
+   sizeof(view_pyobj),                 /* @tp_basicsize@ */
+   0,                                  /* @tp_itemsize@ */
+   view_pydealloc,                     /* @tp_dealloc@ */
+   0,                                  /* @tp_print@ */
+   0,                                  /* @tp_getattr@ */
+   0,                                  /* @tp_setattr@ */
+   0,                                  /* @tp_compare@ */
+   0,                                  /* @tp_repr@ */
+   PYNUMBER(view),                     /* @tp_as_number@ */
+   PYSEQUENCE(itemview),                       /* @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@ */
+   Py_TPFLAGS_DEFAULT |                        /* @tp_flags@ */
+     Py_TPFLAGS_BASETYPE,
+   /* @tp_doc@ */
+   "View of a mapping's key/value items.",
+   0,                                  /* @tp_traverse@ */
+   0,                                  /* @tp_clear@ */
+   view_pyrichcompare,                 /* @tp_richcompare@ */
+   0,                                  /* @tp_weaklistoffset@ */
+   itemview_pyiter,                    /* @tp_iter@ */
+   0,                                  /* @tp_iternext@ */
+   0,                                  /* @tp_methods@ */
+   0,                                  /* @tp_members@ */
+   0,                                  /* @tp_getset@ */
+   0,                                  /* @tp_base@ */
+   0,                                  /* @tp_dict@ */
+   0,                                  /* @tp_descr_get@ */
+   0,                                  /* @tp_descr_set@ */
+   0,                                  /* @tp_dictoffset@ */
+   0,                                  /* @tp_init@ */
+   PyType_GenericAlloc,                        /* @tp_alloc@ */
+   abstract_pynew,                     /* @tp_new@ */
+   0,                                  /* @tp_free@ */
+   0                                   /* @tp_is_gc@ */
+ };
+ #endif
+ /*----- Other mapping protocol support ------------------------------------*/
+ Py_ssize_t gmap_pysize(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter;
+   void *i;
+   Py_ssize_t n = 0;
+   i = iter_init(me, &iter);
+   while (gmops->iter_next(me, i)) n++;
+   iter_free(me, &iter);
+   return (n);
+ }
+ PyObject *gmap_pylookup(PyObject *me, PyObject *key)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   void *e = gmops->lookup(me, key, 0);
+   PyObject *rc = 0;
+   if (!e) { if (!PyErr_Occurred()) MAPERR(key); else goto end; }
+   rc = gmops->entry_value(me, e);
+ end:
+   return (rc);
+ }
+ int gmap_pystore(PyObject *me, PyObject *key, PyObject *value)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   unsigned f;
+   void *e = gmops->lookup(me, key, &f);
+   int rc = -1;
+   if (!e) goto end;
+   if (!value)
+     rc = gmops->del_entry(me, e);
+   else {
+     rc = gmops->set_entry(me, e, value);
+     if (rc && !f) gmops->del_entry(me, e);
+   }
+   rc = 0;
+ end:
+   return (rc);
+ }
+ int gmap_pyhaskey(PyObject *me, PyObject *key)
+   { return (GMAP_OPS(me)->lookup(me, key, 0) ? 1 : PyErr_Occurred() ? -1 : 0); }
+ const PySequenceMethods gmap_pysequence = {
+   0,                                  /* @sq_length@ */
+   0,                                  /* @sq_concat@ */
+   0,                                  /* @sq_repeat@ */
+   0,                                  /* @sq_item@ */
+   0,                                  /* @sq_slice@ */
+   0,                                  /* @sq_ass_item@ */
+   0,                                  /* @sq_ass_slice@ */
+   gmap_pyhaskey,                      /* @sq_contains@ */
+   0,                                  /* @sq_inplace_concat@ */
+   0                                   /* @sq_inplace_repeat@ */
+ };
+ #ifdef PY3
+ PyObject *gmapmeth_keys(PyObject *me)
+   { return (gmap_mkview(me, keyview_pytype)); }
+ PyObject *gmapmeth_values(PyObject *me)
+   { return (gmap_mkview(me, valview_pytype)); }
+ PyObject *gmapmeth_items(PyObject *me)
+   { return (gmap_mkview(me, itemview_pytype)); }
+ #else
+ PyObject *gmapmeth_has_key(PyObject *me, PyObject *arg)
+ {
+   PyObject *k;
+   void *e;
+   if (!PyArg_ParseTuple(arg, "O:has_key", &k)) return (0);
+   e = GMAP_OPS(me)->lookup(me, k, 0);
+   if (e) RETURN_TRUE;
+   else if (!PyErr_Occurred()) RETURN_FALSE;
+   else return (0);
+ }
+ PyObject *gmapmeth_keys(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter; void *i = 0, *e;
+   PyObject *l = 0, *k, *rc = 0;
+   int err;
+   if ((l = PyList_New(0)) == 0) goto done;
+   i = iter_init(me, &iter);
+   while ((e = gmops->iter_next(me, i)) != 0) {
+     k = gmops->entry_key(me, e);
+     err = PyList_Append(l, k);
+     Py_DECREF(k);
+     if (err) goto done;
+   }
+   rc = l; l = 0;
+ done:
+   Py_XDECREF(l);
+   if (i) iter_free(me, &iter);
+   return (rc);
+ }
+ PyObject *gmapmeth_values(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter; void *i = 0, *e;
+   PyObject *l = 0, *v, *rc = 0;
+   int err;
+   if ((l = PyList_New(0)) == 0) goto done;
+   i = iter_init(me, &iter);
+   while ((e = gmops->iter_next(me, i)) != 0) {
+     v = gmops->entry_value(me, e);
+     err = PyList_Append(l, v);
+     Py_DECREF(v);
+     if (err) goto done;
+   }
+   rc = l; l = 0;
+ done:
+   Py_XDECREF(l);
+   if (i) iter_free(me, &iter);
+   return (rc);
+ }
+ PyObject *gmapmeth_items(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter; void *i = 0, *e;
+   PyObject *l = 0, *z, *rc = 0;
+   int err;
+   if ((l = PyList_New(0)) == 0) goto done;
+   i = iter_init(me, &iter);
+   while ((e = gmops->iter_next(me, i)) != 0) {
+     if ((z = Py_BuildValue("(NN)",
+                          gmops->entry_key(me, e),
+                          gmops->entry_value(me, e))) == 0)
+       goto done;
+     err = PyList_Append(l, z);
+     Py_XDECREF(z);
+     if (err) goto done;
+   }
+   rc = l; l = 0;
+ done:
+   Py_XDECREF(l);
+   if (i) iter_free(me, &iter);
+   return (rc);
+ }
+ PyObject *gmapmeth_iterkeys(PyObject *me)
+   { return (gmap_mkiter(me, keyiter_pytype)); }
+ PyObject *gmapmeth_itervalues(PyObject *me)
+   { return (gmap_mkiter(me, valiter_pytype)); }
+ PyObject *gmapmeth_iteritems(PyObject *me)
+   { return (gmap_mkiter(me, itemiter_pytype)); }
+ #endif
+ PyObject *gmap_pyiter(PyObject *me)
+   { return gmap_mkiter(me, keyiter_pytype); }
+ PyObject *gmapmeth_clear(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter;
+   void *i, *e;
+   PyObject *rc = 0;
+   i = iter_init(me, &iter);
+   for (;;) {
+     e = gmops->iter_next(me, i); if (!e) break;
+     if (gmops->del_entry(me, e)) goto end;
+   }
+   iter_free(me, &iter);
+   rc = me; Py_INCREF(me);
+ end:
+   return (rc);
+ }
+ static const char *const def_kwlist[] = { "key", "default", 0 };
+ #define DEF_KWLIST ((/*unconst*/ char **)def_kwlist)
+ PyObject *gmapmeth_get(PyObject *me, PyObject *arg, PyObject *kw)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   PyObject *k, *def = Py_None;
+   void *e;
+   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", DEF_KWLIST, &k, &def))
+     return (0);
+   e = gmops->lookup(me, k, 0);
+   if (e) return (gmops->entry_value(me, e));
+   else if (!PyErr_Occurred()) RETURN_OBJ(def);
+   else return (0);
+ }
+ PyObject *gmapmeth_setdefault(PyObject *me, PyObject *arg, PyObject *kw)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   PyObject *k, *def = Py_None;
+   void *e;
+   unsigned f;
+   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault", DEF_KWLIST,
+                                  &k, &def))
+     return (0);
+   e = gmops->lookup(me, k, &f);
+   if (!e) return (0);
+   else if (f) return (gmops->entry_value(me, e));
+   else if (gmops->set_entry(me, e, def)) return (0);
+   else RETURN_OBJ(def);
+ }
+ PyObject *gmapmeth_pop(PyObject *me, PyObject *arg, PyObject *kw)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   PyObject *k, *def = 0;
+   PyObject *rc = 0;
+   void *e;
+   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop", DEF_KWLIST, &k, &def))
+     goto end;
+   e = gmops->lookup(me, k, 0);
+   if (!e) {
+     if (PyErr_Occurred()) goto end;
+     else if (def) { rc = def; Py_INCREF(rc); }
+     else MAPERR(k);
+   } else {
+     rc = gmops->entry_value(me, e);
+     if (gmops->del_entry(me, e)) { Py_DECREF(rc); rc = 0; }
+   }
+ end:
+   return (rc);
+ }
+ static int update_core(PyObject *me, PyObject *map)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   PyObject *i = 0, *item = 0, *k = 0, *v = 0;
+   void *e;
+   unsigned foundp;
+   int rc = -1;
+   v = PyObject_CallMethod(map, PY23("iteritems", "items"), 0);
+ #ifdef PY3
+   if (v) { i = PyObject_GetIter(v); Py_DECREF(v); v = 0; }
+ #else
+   i = v; v = 0;
+ #endif
+   if (i) {
+     for (;;) {
+       item = PyIter_Next(i); if (!item) break;
+       if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2)
+       TYERR("wanted a pair");
+       k = PyTuple_GET_ITEM(item, 0); Py_INCREF(k);
+       v = PyTuple_GET_ITEM(item, 1); Py_INCREF(v);
+       e = gmops->lookup(me, k, &foundp); if (!e) goto end;
+       if (gmops->set_entry(me, e, v)) goto end;
+       Py_DECREF(item); Py_DECREF(k); Py_DECREF(v); item = k = v = 0;
+     }
+     if (PyErr_Occurred()) goto end;
+   } else {
+     PyErr_Clear();
+     i = PyObject_GetIter(map); if (!i) goto end;
+     for (;;) {
+       k = PyIter_Next(i); if (!k) goto end;
+       v = PyObject_GetItem(map, k); if (!v) goto end;
+       e = gmops->lookup(me, k, &foundp); if (!e) goto end;
+       if (gmops->set_entry(me, e, v)) goto end;
+       Py_DECREF(k); Py_DECREF(v); k = v = 0;
+     }
+     if (PyErr_Occurred()) goto end;
+   }
+   rc = 0;
+ end:
+   Py_XDECREF(i); Py_XDECREF(item);
+   Py_XDECREF(k); Py_XDECREF(v);
+   return (rc);
+ }
+ PyObject *gmapmeth_update(PyObject *me, PyObject *arg, PyObject *kw)
+ {
+   PyObject *map = 0;
+   if (!PyArg_ParseTuple(arg, "|O:update", &map)) return (0);
+   if (map && update_core(me, map)) return (0);
+   if (kw && update_core(me, kw)) return (0);
+   RETURN_ME;
+ }
+ PyObject *gmapmeth_popitem(PyObject *me)
+ {
+   const gmap_ops *gmops = GMAP_OPS(me);
+   union iterstate iter;
+   void *i;
+   PyObject *rc = 0;
+   void *e;
+   i = iter_init(me, &iter);
+   e = gmops->iter_next(me, i);
+   iter_free(me, &iter);
+   if (!e)
+     MAPERR(Py_None);
+   else {
+     rc = Py_BuildValue("(NN)",
+                      gmops->entry_key(me, e), gmops->entry_value(me, e));
+     if (gmops->del_entry(me, e)) { Py_DECREF(rc); rc = 0; }
+   }
+ end:
+   return (rc);
+ }
+ const PyMethodDef gmapro_pymethods[] = {
+   GMAP_ROMETHODS
+   { 0 }
+ };
+ const PyMethodDef gmap_pymethods[] = {
+   GMAP_METHODS
+   { 0 }
+ };
+ /*----- Submodule initialization ------------------------------------------*/
+ void pyke_gmap_pyinit(void)
+ {
+   INITTYPE(keyiter, root);
+   INITTYPE(itemiter, root);
+   INITTYPE(valiter, root);
+ #ifdef PY3
+   INITTYPE(keyview, root);
+   INITTYPE(valview, root);
+   INITTYPE(itemview, root);
+ #endif
+ }
+ void pyke_gmap_pyinsert(PyObject *mod)
+ {
+   INSERT("_KeyIter", keyiter_pytype);
+   INSERT("_ValueIter", valiter_pytype);
+   INSERT("_ItemIter", itemiter_pytype);
+ #ifdef PY3
+   INSERT("_KeyView", keyview_pytype);
+   INSERT("_ValueView", valview_pytype);
+   INSERT("_ItemView", itemview_pytype);
+ #endif
+ }
+ /*----- That's all, folks -------------------------------------------------*/
diff --combined pyke/pyke-mLib.c
index 0000000000000000000000000000000000000000,900dc41524a5fe884b41466db32f8228b0c6c597..900dc41524a5fe884b41466db32f8228b0c6c597
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,134 +1,134 @@@
+ /* -*-c-*-
+  *
+  * Pyke: the Python Kit for Extensions, mLib integration
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ /*----- Header files ------------------------------------------------------*/
+ #include "pyke-mLib.h"
+ /* #undef HAVE_LONG_LONG */
+ /*----- Conversions -------------------------------------------------------*/
+ #ifndef HAVE_LONG_LONG
+ static PyObject *i32 = 0;
+ static int init_i32(void)
+   { if (!i32 && (i32 = PyInt_FromLong(32)) == 0) return (-1); return (0); }
+ #endif
+ PyObject *getk64(kludge64 u)
+ {
+ #ifdef HAVE_LONG_LONG
+   return (PyLong_FromUnsignedLongLong(GET64(unsigned PY_LONG_LONG, u)));
+ #else
+   PyObject *i = 0, *j = 0, *t;
+   PyObject *rc = 0;
+   if (init_i32()) goto end;
+   if ((i = PyLong_FromUnsignedLong(HI64(u))) == 0) goto end;
+   if ((t = PyNumber_InPlaceLshift(i, i32)) == 0) goto end;
+   Py_DECREF(i); i = t;
+   if ((j = PyLong_FromUnsignedLong(LO64(u))) == 0) goto end;
+   if ((t = PyNumber_InPlaceOr(i, j)) == 0) goto end;
+ #  ifdef PY2
+   Py_DECREF(i); i = t;
+   if ((t = PyNumber_Int(i)) == 0) goto end;
+ #  endif
+   rc = t;
+ end:
+   Py_XDECREF(i);
+   Py_XDECREF(j);
+   return (rc);
+ #endif
+ }
+ #ifdef HAVE_UINT64
+ #  define CONVu64(n) do {                                             \
+      kludge64 k;                                                      \
+      uint64 t;                                                                \
+      if (!convk64(o, &k)) goto end;                                   \
+      t = GET64(uint64, k);                                            \
+      if (t > MASK##n) OVFERR("out of range");                         \
+      *p = t;                                                          \
+    } while (0)
+ #else
+ #  define CONVu64(n) assert(!"shouldn't be possible")
+ #endif
+ #define CONVU_(n)                                                     \
+   int convu##n(PyObject *o, void *pp)                                 \
+   {                                                                   \
+     unsigned long u;                                                  \
+     uint##n *p = pp;                                                  \
+                                                                       \
+     if (MASK##n > ULONG_MAX)                                          \
+       CONVu64(n);                                                     \
+     else {                                                            \
+       if (!convulong(o, &u)) goto end;                                        \
+       if (u > MASK##n) OVFERR("out of range");                                \
+       *p = u;                                                         \
+     }                                                                 \
+     return (1);                                                               \
+   end:                                                                        \
+     return (0);                                                               \
+   }
+ DOUINTSZ(CONVU_)
+ int convk64(PyObject *o, void *pp)
+ {
+   PyObject *i = 0;
+   int rc = 0;
+ #if HAVE_LONG_LONG
+   unsigned PY_LONG_LONG t;
+ #else
+   PyObject *t;
+   uint32 lo, hi;
+ #endif
+ #if HAVE_LONG_LONG
+   if ((i = PyNumber_Long(o)) == 0) goto end;
+   t = PyLong_AsUnsignedLongLong(i);
+   if (t == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) goto end;
+   ASSIGN64(*(kludge64 *)pp, t);
+ #else
+   if (init_i32()) goto end;
+   if ((i = PyNumber_Int(o)) == 0) goto end;
+   lo = PyInt_AsUnsignedLongMask(i);
+   if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end;
+   Py_DECREF(i); i = t;
+   hi = PyInt_AsUnsignedLongMask(i);
+   if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end;
+   Py_DECREF(i); i = t;
+   if (PyObject_IsTrue(i)) OVFERR("out of range");
+   SET64(*(kludge64 *)pp, hi, lo);
+ #endif
+   rc = 1;
+ end:
+   Py_XDECREF(i);
+   return (rc);
+ }
+ /*----- That's all, folks -------------------------------------------------*/
diff --combined pyke/pyke-mLib.h
index 0000000000000000000000000000000000000000,aa50bd8886ab6b1375f0b1969452904584d6ac9b..aa50bd8886ab6b1375f0b1969452904584d6ac9b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,68 +1,68 @@@
+ /* -*-c-*-
+  *
+  * Pyke: the Python Kit for Extensions, mLib integration
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ #ifndef PYKE_MLIB_H
+ #define PYKE_MLIB_H
+ #ifdef __cplusplus
+   extern "C" {
+ #endif
+ /*----- Header files ------------------------------------------------------*/
+ #ifndef PYKE_H
+ #  include "pyke.h"
+ #endif
+ PUBLIC_SYMBOLS;
+ #include <mLib/bits.h>
+ #include <mLib/sym.h>
+ PRIVATE_SYMBOLS;
+ /*----- Conversions -------------------------------------------------------*/
+ #define DECL_CONVU_(n) extern int convu##n(PyObject *, void *);
+ DOUINTSZ(DECL_CONVU_)
+   /* Define an `O&' input conversion `convuN' for each mLib type `uintN'. */
+ extern int convk64(PyObject *, void *);
+   /* Input conversion for `kludge64'. */
+ extern PyObject *getk64(kludge64);
+   /* Output conversion for `kludge64'. */
+ /*----- Mapping support ---------------------------------------------------*/
+ extern Py_ssize_t gmap_pysize_from_sym(sym_table *);
+   /* Determine the size of a mapping based on a `sym_table'. */
+ /*----- That's all, folks -------------------------------------------------*/
+ #ifdef __cplusplus
+   }
+ #endif
+ #endif
diff --combined pyke/pyke.c
index 0000000000000000000000000000000000000000,330f15cab6e95d2f88221d647993ad84be54d3dc..330f15cab6e95d2f88221d647993ad84be54d3dc
mode 000000,100644..100644
--- /dev/null
--- 2/pyke.c
@@@ -1,0 -1,419 +1,419 @@@
+ /* -*-c-*-
+  *
+  * Pyke: the Python Kit for Extensions
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ /*----- Header files ------------------------------------------------------*/
+ #include "pyke.h"
+ /*----- External variables ------------------------------------------------*/
+ PyObject *modname;
+ PyObject *home_module;
+ /*----- Conversions -------------------------------------------------------*/
+ PyObject *getulong(unsigned long w)
+ {
+   if (w <= LONG_MAX) return (PyInt_FromLong(w));
+   else return (PyLong_FromUnsignedLong(w));
+ }
+ PyObject *getbool(int b)
+   { if (b) RETURN_TRUE; else RETURN_FALSE; }
+ int convulong(PyObject *o, void *pp)
+ {
+   unsigned long *p = pp;
+   PyObject *t;
+   if (!o) VALERR("can't delete");
+ #ifdef PY2
+   if (PyInt_Check(o)) {
+     long i = PyInt_AS_LONG(o);
+     if (i < 0) VALERR("must be nonnegative");
+     *p = i;
+   } else
+ #endif
+   {
+     if ((t = PyNumber_Long(o)) == 0) goto end;
+     *p = PyLong_AsUnsignedLong(t);
+     Py_DECREF(t);
+     if (PyErr_Occurred()) goto end;
+   }
+   return (1);
+ end:
+   return (0);
+ }
+ int convuint(PyObject *o, void *pp)
+ {
+   unsigned long u;
+   unsigned *p = pp;
+   if (!convulong(o, &u)) goto end;
+   if (u > UINT_MAX) VALERR("out of range");
+   *p = u;
+   return (1);
+ end:
+   return (0);
+ }
+ int convszt(PyObject *o, void *pp)
+ {
+   unsigned long u;
+   size_t *p = pp;
+   if (!convulong(o, &u)) goto end;
+   if (u > ~(size_t)0) VALERR("out of range");
+   *p = u;
+   return (1);
+ end:
+   return (0);
+ }
+ int convbool(PyObject *o, void *pp)
+ {
+   if (!o) VALERR("can't delete");
+   *(int *)pp = PyObject_IsTrue(o);
+   return (1);
+ end:
+   return (0);
+ }
+ int convbin(PyObject *o, void *pp)
+ {
+   struct bin *r = pp;
+   if (BIN_CHECK(o)) {
+     r->p = BIN_PTR(o);
+     r->sz = BIN_LEN(o);
+     return (1);
+   }
+ #ifdef PY2
+   if (PyUnicode_Check(o)) {
+     o = _PyUnicode_AsDefaultEncodedString(o, 0);
+     if (!o) return (0);
+     r->p = PyString_AS_STRING(o);
+     r->sz = PyString_GET_SIZE(o);
+     return (1);
+   }
+ #endif
+   return (PyObject_AsReadBuffer(o, &r->p, &r->sz) ? 0 : 1);
+ }
+ /*----- Miscellaneous utilities -------------------------------------------*/
+ PyObject *abstract_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+ {
+   PyErr_SetString(PyExc_TypeError, "can't instantiate this class");
+   return (0);
+ }
+ PyObject *enrich_compare(int op, int cmp)
+ {
+   int r = -1;
+   switch (op) {
+     case Py_LT: r = cmp <  0; break;
+     case Py_LE: r = cmp <= 0; break;
+     case Py_EQ: r = cmp == 0; break;
+     case Py_NE: r = cmp != 0; break;
+     case Py_GE: r = cmp >= 0; break;
+     case Py_GT: r = cmp >  0; break;
+     default: assert(0);
+   }
+   return (getbool(r));
+ }
+ /*----- Saving and restoring exceptions ----------------------------------*/
+ void report_lost_exception_v(struct excinfo *exc,
+                            const char *why, va_list ap)
+ {
+   PyObject *hookfn = 0;
+   PyObject *whyobj = 0;
+   PyObject *obj = 0;
+   /* Make sure we start out without a pending exception, or this will get
+    * really confusing.
+    */
+   assert(!PyErr_Occurred());
+   /* Format the explanation. */
+   if (why) whyobj = TEXT_VFORMAT(why, ap);
+   else { whyobj = Py_None; Py_INCREF(whyobj); }
+   /* Find our home module's `lostexchook' function.  This won't work if
+    * there's no module, or the function isn't defined, or it's `None'.
+    */
+   if (!home_module) goto sys;
+   hookfn = PyObject_GetAttrString(home_module, "lostexchook");
+   if (hookfn == Py_None) goto sys;
+   else if (hookfn) ;
+   else if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto ouch;
+   else { PyErr_Clear(); goto sys; }
+   /* Call the hook function. */
+   obj = PyObject_CallFunction(hookfn, "(OOOO)",
+                             whyobj, exc->ty, exc->val, exc->tb);
+   if (!obj) goto ouch;
+   goto end;
+   /* Something went wrong reporting the problem. */
+ ouch:
+   PySys_WriteStderr("\n!!! FAILURE REPORTING LOST EXCEPTION\n");
+   PyErr_Print();
+   /* drop through... */
+   /* There was no hook, so try to do something sensible using
+    * `sys.excepthook'.
+    */
+ sys:
+   PySys_WriteStderr("\n!!! LOST EXCEPTION: %s\n", TEXT_PTR(whyobj));
+   RESTORE_EXCINFO(exc);
+   PyErr_Print();
+   /* drop through... */
+   /* Clean up afterwards. */
+ end:
+   Py_XDECREF(hookfn);
+   Py_XDECREF(whyobj);
+   Py_XDECREF(obj);
+ }
+ void report_lost_exception(struct excinfo *exc, const char *why, ...)
+ {
+   va_list ap;
+   va_start(ap, why);
+   report_lost_exception_v(exc, why, ap);
+   va_end(ap);
+ }
+ void stash_exception(struct excinfo *exc, const char *why, ...)
+ {
+   va_list ap;
+   struct excinfo stash;
+   if (!exc->ty)
+     STASH_EXCINFO(exc);
+   else {
+     va_start(ap, why);
+     STASH_EXCINFO(&stash);
+     report_lost_exception_v(&stash, why, ap);
+     va_end(ap);
+   }
+ }
+ void restore_exception(struct excinfo *exc, const char *why, ...)
+ {
+   va_list ap;
+   struct excinfo stash;
+   if (!PyErr_Occurred())
+     RESTORE_EXCINFO(exc);
+   else {
+     va_start(ap, why);
+     STASH_EXCINFO(&stash);
+     report_lost_exception_v(exc, why, ap);
+     RESTORE_EXCINFO(&stash);
+     va_end(ap);
+   }
+ }
+ /*----- Type definitions --------------------------------------------------*/
+ static const PyTypeObject emptytype = { 0 };
+ void *newtype(PyTypeObject *metaty,
+             const PyTypeObject *skel,
+             const char *name)
+ {
+   PyHeapTypeObject *ty =
+     (PyHeapTypeObject *)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty, 0));
+   if (!skel) skel = &emptytype;
+   memcpy(ty, skel, sizeof(*skel));
+ #define COPY(blah) do {                                                       \
+     if (ty->ht_type.tp_as_##blah) {                                   \
+       memcpy(&ty->as_##blah,                                          \
+            ty->ht_type.tp_as_##blah,                                  \
+            sizeof(ty->as_##blah));                                    \
+       ty->ht_type.tp_as_##blah = &ty->as_##blah;                      \
+     }                                                                 \
+   } while (0)
+   COPY(number);
+   COPY(sequence);
+   COPY(mapping);
+   COPY(buffer);
+ #undef COPY
+   if (name)
+     ty->ht_name = TEXT_FROMSTR(name);
+   else if (ty->ht_type.tp_name)
+     ty->ht_name = TEXT_FROMSTR(ty->ht_type.tp_name);
+   else
+     ty->ht_name = 0;
+   if (ty->ht_name)
+     ty->ht_type.tp_name = TEXT_STR(ty->ht_name);
+   ty->ht_slots = 0;
+ #ifdef PY3
+   ty->ht_qualname = 0;
+ #endif
+   (void)PyObject_INIT(&ty->ht_type, metaty);
+   Py_INCREF(metaty);
+   return (ty);
+ }
+ void typeready(PyTypeObject *ty)
+ {
+ #ifdef PY3
+   PyHeapTypeObject *hty = (PyHeapTypeObject *)ty;
+   hty->ht_qualname = hty->ht_name;
+ #endif
+   PyType_Ready(ty);
+   PyDict_SetItemString(ty->tp_dict, "__module__", modname);
+ }
+ PyTypeObject *inittype(const PyTypeObject *tyskel,
+                      PyTypeObject *base, PyTypeObject *meta)
+ {
+   PyTypeObject *ty = newtype(meta, tyskel, 0);
+   if (base) { ty->tp_base = base; Py_INCREF(base); }
+   ty->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+   typeready(ty);
+   return (ty);
+ }
+ /*----- Populating modules ------------------------------------------------*/
+ PyObject *mkexc(PyObject *mod, PyObject *base,
+               const char *name, const PyMethodDef *mm)
+ {
+   PyObject *nameobj = 0;
+   PyObject *dict = 0;
+   PyObject *exc = 0;
+   PyObject *func = 0;
+   PyObject *meth = 0;
+   if ((dict = PyDict_New()) == 0) goto fail;
+   if (mm) {
+     while (mm->ml_name) {
+       if ((func = PyCFunction_NewEx((/*unconst*/ PyMethodDef *)mm,
+                                   0, mod)) == 0 ||
+         (meth = PY23(PyMethod_New(func, 0, exc),
+                      PyInstanceMethod_New(func))) == 0 ||
+         PyDict_SetItemString(dict, mm->ml_name, meth))
+       goto fail;
+       Py_DECREF(func); func = 0;
+       Py_DECREF(meth); meth = 0;
+       mm++;
+     }
+   }
+   if ((nameobj = TEXT_FORMAT("%s.%s", PyModule_GetName(mod), name)) == 0 ||
+       (exc = PyErr_NewException(TEXT_STR(nameobj), base, dict)) == 0)
+     goto fail;
+ done:
+   Py_XDECREF(nameobj);
+   Py_XDECREF(dict);
+   return (exc);
+ fail:
+   Py_XDECREF(exc);
+   Py_XDECREF(func);
+   Py_XDECREF(meth);
+   exc = 0;
+   goto done;
+ }
+ void setconstants(PyObject *mod, const struct nameval *c)
+ {
+   PyObject *x;
+   unsigned long u;
+   while (c->name) {
+     u = c->value;
+     if (u <= LONG_MAX) x = PyInt_FromLong(u);
+     else if (c->f&CF_SIGNED) x = PyInt_FromLong(-1 - (long)(ULONG_MAX - u));
+     else x = PyLong_FromUnsignedLong(u);
+     PyModule_AddObject(mod, (/*unconst*/ char *)c->name, x);
+     c++;
+   }
+ }
+ /*----- Submodules --------------------------------------------------------*/
+ static PyMethodDef *global_methods;
+ static size_t nmethods, methodsz;
+ void addmethods(const PyMethodDef *m)
+ {
+   size_t n, want, newsz;
+   for (n = 0; m[n].ml_name; n++);
+   want = nmethods + n + 1;
+   if (want > methodsz) {
+     newsz = methodsz ? 2*methodsz : 16;
+     while (want > newsz) newsz *= 2;
+     if (!global_methods)
+       global_methods = PyObject_Malloc(newsz*sizeof(PyMethodDef));
+     else
+       global_methods = PyObject_Realloc(global_methods,
+                                       newsz*sizeof(PyMethodDef));
+     assert(global_methods);
+     methodsz = newsz;
+   }
+   memcpy(global_methods + nmethods, m, n*sizeof(PyMethodDef));
+   nmethods += n;
+   global_methods[nmethods].ml_name = 0;
+ }
+ PyMethodDef *donemethods(void) { return (global_methods); }
+ /*----- Low-level Python interface ----------------------------------------*/
+ static PyObject *meth__set_home_module(PyObject *me, PyObject *arg)
+ {
+   PyObject *mod;
+   if (!PyArg_ParseTuple(arg, "O!:_set_home_module", &PyModule_Type, &mod))
+     return (0);
+   Py_XDECREF(home_module); home_module = mod; Py_INCREF(home_module);
+   RETURN_NONE;
+ }
+ static const PyMethodDef methods[] = {
+ #define METHNAME(func) meth_##func
+   METH        (_set_home_module, "_set_home_module(MOD)")
+ #undef METHNAME
+   { 0 }
+ };
+ void pyke_core_pyinit(void) { addmethods(methods); }
+ void pyke_core_pyinsert(PyObject *mod) { ; }
+ /*----- That's all, folks -------------------------------------------------*/
diff --combined pyke/pyke.h
index 0000000000000000000000000000000000000000,a60fd76a93f8e45682150920862787e8e0b75e4d..a60fd76a93f8e45682150920862787e8e0b75e4d
mode 000000,100644..100644
--- /dev/null
--- 2/pyke.h
@@@ -1,0 -1,700 +1,700 @@@
+ /* -*-c-*-
+  *
+  * Pyke: the Python Kit for Extensions
+  *
+  * (c) 2019 Straylight/Edgeware
+  */
+ /*----- Licensing notice --------------------------------------------------*
+  *
+  * This file is part of Pyke: the Python Kit for Extensions.
+  *
+  * Pyke is free software: you can redistribute it and/or modify it under
+  * the terms of the GNU General Public License as published by the Free
+  * Software Foundation; either version 2 of the License, or (at your
+  * option) any later version.
+  *
+  * Pyke is distributed in the hope that it will be useful, but WITHOUT
+  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  * for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with Pyke.  If not, write to the Free Software Foundation, Inc.,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+ #ifndef PYKE_H
+ #define PYKE_H
+ #ifdef __cplusplus
+   extern "C" {
+ #endif
+ /*----- Header files ------------------------------------------------------*/
+ #define PY_SSIZE_T_CLEAN
+ #include <Python.h>
+ #include <structmember.h>
+ /*----- Other preliminaries -----------------------------------------------*/
+ #define NOTHING
+ #define COMMA ,
+ /*----- Symbol visibility -------------------------------------------------*
+  *
+  * This library is very messy regarding symbol namespace.  Keep this mess
+  * within our shared-object.
+  */
+ #define GOBBLE_SEMI extern int notexist
+ #if defined(__GNUC__) && defined(__ELF__)
+ #  define PRIVATE_SYMBOLS _Pragma("GCC visibility push(hidden)") GOBBLE_SEMI
+ #  define PUBLIC_SYMBOLS _Pragma("GCC visibility pop") GOBBLE_SEMI
+ #  define EXPORT __attribute__((__visibility__("default")))
+ #else
+ #  define PRIVATE_SYMBOLS GOBBLE_SEMI
+ #  define PUBLIC_SYMBOLS GOBBLE_SEMI
+ #  define EXPORT
+ #endif
+ PRIVATE_SYMBOLS;
+ /*----- Python version compatibility hacks --------------------------------*/
+ /* Explicit version switching. */
+ #if PY_VERSION_HEX >= 0x03000000
+ #  define PY3 1
+ #  define PY23(two, three) three
+ #else
+ #  define PY2 1
+ #  define PY23(two, three) two
+ #endif
+ /* The handy `Py_TYPE' and `Py_SIZE' macros turned up in 2.6.  Define them if
+  * they're not already here.
+  */
+ #ifndef Py_TYPE
+ #  define Py_TYPE(obj) (((PyObject *)(obj))->ob_type)
+ #endif
+ #ifndef Py_SIZE
+ #  define Py_SIZE(obj) (((PyVarObject *)(obj))->ob_size)
+ #endif
+ /* Python 3 added internal structure to the various object headers, and
+  * defined a new macro `PyVarObject_HEAD_INIT' to initialize variable-length
+  * static instances correctly.  Define it if it's not already here.
+  */
+ #ifndef PyVarObject_HEAD_INIT
+ #  define PyVarObject_HEAD_INIT(super, sz) PyObject_HEAD_INIT(super) sz,
+ #endif
+ /* Python 3 doesn't have `int', only `long', even though it's called `int' at
+  * the Python level.  Provide some obvious macros to fill in the gaps.
+  */
+ #ifdef PY3
+ #  define PyInt_Check PyLong_Check
+ #  define PyInt_FromLong PyLong_FromLong
+ #  define PyInt_AS_LONG PyLong_AS_LONG
+ #  define PyInt_AsLong PyLong_AsLong
+ #  define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
+ #  define PyNumber_Int PyNumber_Long
+ #endif
+ /* Python 3.2 changed the type of hash values, so paper over this annoying
+  * difference.
+  */
+ #if PY_VERSION_HEX < 0x03020000
+   typedef long Py_hash_t;
+ #endif
+ /* Python 3 always has the `CHECKTYPES' behaviour, and doesn't define the
+  * flag.
+  */
+ #ifdef PY3
+ #  define Py_TPFLAGS_CHECKTYPES 0
+ #endif
+ /* Plain octet strings.  Python 2 calls these `str', while Python 3 calls
+  * them `bytes'.  We call them `bin' here, and define the following.
+  *
+  *   * `BINOBJ' is the C type of a `bin' object.
+  *   * `BIN_TYPE' is the Python `type' object for `bin'.
+  *   * `BIN_CHECK(OBJ)' is true if OBJ is a `bin' object.
+  *   * `BIN_PTR(OBJ)' points to the first octet of OBJ, without checking!
+  *   * `BIN_LEN(OBJ)' yields the length of OBJ in octets, without checking!
+  *   * `BIN_FROMSTR(STR)' makes a `bin' object from a null-terminated string.
+  *   * `BIN_FORMAT(FMT, ARGS...)' and `BIN_VFORMAT(FMT, AP)' make a `bin'
+  *     object from a `printf'-like format string and arguments.
+  *   * `BIN_PREPAREWRITE(OBJ, PTR, LEN)' prepares to make a `bin' object: it
+  *     sets PTR to point to a buffer of LEN bytes; call `BIN_DONEWRITE' when
+  *     finished.  The variable OBJ will eventually be the resulting object,
+  *     but until `BIN_DONEWRITE' is called, it may in fact be some different
+  *     object.
+  *   * `BIN_DONEWRITE(OBJ, LEN)' completes making a `bin' object: it adjusts
+  *     its length to be LEN, which must not be larger than the LEN given to
+  *     `BIN_PREPAREWRITE', and sets OBJ to point to the finished object.
+  *   * `BIN_SETLEN(OBJ, LEN)' adjusts the length of OBJ downwards to LEN,
+  *     without checking!
+  #   * `Y' is a format character for `PyArg_ParseTuple...' for retrieving a
+  *     null-terminated octet string from a `bin' object.
+  #   * `YN' is a format character for `PyArg_ParseTuple...' for retrieving an
+  *     octet string and length from any sort-of vaguely binary-ish object.
+  */
+ #ifdef PY3
+ #  define BINOBJ PyBytesObject
+ #  define BIN_TYPE PyBytes_Type
+ #  define BIN_CHECK(obj) PyBytes_Check(obj)
+ #  define BIN_PTR(obj) PyBytes_AS_STRING(obj)
+ #  define BIN_LEN(obj) PyBytes_GET_SIZE(obj)
+ #  define BIN_FROMSTR(str) PyBytes_FromString(str)
+ #  define BIN_FROMSTRLEN(str, len) PyBytes_FromStringAndSize(str, len)
+ #  define BIN_FORMAT PyBytes_FromFormat
+ #  define BIN_VFORMAT PyBytes_FromFormatV
+ #  define BIN_PREPAREWRITE(obj, ptr, sz) do {                         \
+      (obj) = PyBytes_FromStringAndSize(0, (sz));                      \
+      (ptr) = PyBytes_AS_STRING(obj);                                  \
+    } while (0)
+ #  define BIN_DONEWRITE(obj, sz) do Py_SIZE(obj) = (sz); while (0)
+ #  define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0)
+ #  define Y "y"
+ #  define YN "y#"
+ #else
+ #  define BINOBJ PyStringObject
+ #  define BIN_TYPE PyString_Type
+ #  define BIN_CHECK(obj) PyString_Check(obj)
+ #  define BIN_PTR(obj) PyString_AS_STRING(obj)
+ #  define BIN_LEN(obj) PyString_GET_SIZE(obj)
+ #  define BIN_FROMSTR(str) PyString_FromString(str)
+ #  define BIN_FROMSTRLEN(str, len) PyString_FromStringAndSize(str, len)
+ #  define BIN_FORMAT PyString_FromFormat
+ #  define BIN_VFORMAT PyString_FromFormatV
+ #  define BIN_PREPAREWRITE(obj, ptr, sz) do {                         \
+      (obj) = PyString_FromStringAndSize(0, (sz));                     \
+      (ptr) = PyString_AS_STRING(obj);                                 \
+    } while (0)
+ #  define BIN_DONEWRITE(obj, sz) do Py_SIZE(obj) = (sz); while (0)
+ #  define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0)
+ #  define Y "s"
+ #  define YN "s#"
+ #endif
+ /* Text strings.  Both Python 2 and Python 3 call these `str', but they're
+  * very different because a Python 3 `str' is Unicode inside.  When dealing
+  * with Python 3 text, the data is UTF-8 encoded.  We call them `text' here,
+  * and define the following.
+  *
+  *   * `TEXTOBJ' is the C type of a `text' object.
+  *   * `TEXT_TYPE' is the Python `type' object for `text'.
+  *   * `TEXT_CHECK(OBJ)' is true if OBJ is a `text' object.
+  *   * `TEXT_STR(OBJ)' points to the first byte of a null-terminated string
+  *     OBJ, or is null.
+  *   * `TEXT_PTR(OBJ)' points to the first byte of OBJ, without checking!
+  *   * `TEXT_LEN(OBJ)' yields the length of OBJ in octets, without checking!
+  *   * `TEXT_FROMSTR(STR)' makes a `text' object from a null-terminated
+  *     string.
+  *   * `TEXT_FORMAT(FMT, ARGS...)' and `TEST_VFORMAT(FMT, AP)' make a `text'
+  *     object from a `printf'-like format string and arguments.
+  *   * `TEXT_PREPAREWRITE(OBJ, PTR, LEN)' prepares to make a `text' object:
+  *     it sets PTR to point to a buffer of LEN bytes; call `TEXT_DONEWRITE'
+  *     when finished.  The variable OBJ will eventually be the resulting
+  *     object, but until `TEXT_DONEWRITE' is called, it may in fact be some
+  *     different object.
+  *   * `TEXT_DONEWRITE(OBJ, LEN)' completes making a `text' object: it
+  *     adjusts its length to be LEN, which must not be larger than the LEN
+  *     given to `TEXT_PREPAREWRITE', and sets OBJ to point to the finished
+  *     object.
+  *
+  * (Use `s' and `s#' in `PyArg_ParseTuple...'.)
+  */
+ #ifdef PY3
+ #  define TEXTOBJ PyUnicodeObject
+ #  define TEXT_TYPE PyUnicode_Type
+ #  define TEXT_CHECK(obj) PyUnicode_Check(obj)
+ #  if PY_VERSION_HEX >= 0x03030000
+ #    define TEXT_PTR(obj) PyUnicode_AsUTF8(obj)
+ #    define TEXT_STR(obj) PyUnicode_AsUTF8(obj)
+ #    define TEXT_PTRLEN(obj, ptr, len) do {                           \
+        Py_ssize_t len_;                                                       \
+        (ptr) = PyUnicode_AsUTF8AndSize((obj), &len_);                 \
+        (len) = len_;                                                  \
+      } while (0)
+ #    define TEXT_PREPAREWRITE(obj, ptr, sz) do {                      \
+        (obj) = PyUnicode_New((sz), 127);                              \
+        (ptr) = PyUnicode_DATA(obj);                                   \
+      } while (0)
+ #    define TEXT_DONEWRITE(obj, len) do {                             \
+        size_t len_ = (len);                                           \
+        assert(PyUnicode_IS_COMPACT_ASCII(obj));                               \
+        ((char *)PyUnicode_DATA(obj))[len_] = 0;                               \
+        ((PyASCIIObject *)(obj))->length = len_;                               \
+      } while (0)
+ #  else
+ #    define TEXT_PTR(obj) _PyUnicode_AsString(obj)
+ #    define TEXT_STR(obj) _PyUnicode_AsString(obj)
+ #    define TEXT_PTRLEN(obj, ptr, len) do {                           \
+        Py_ssize_t len_;                                                       \
+        (ptr) = _PyUnicode_AsStringAndSize((obj), &len_);              \
+        (len) = len_;                                                  \
+      } while (0)
+ #    define TEXT_PREPAREWRITE(obj, ptr, sz) do {                      \
+        (obj) = PyBytes_FromStringAndSize(0, (sz));                    \
+        (ptr) = PyBytes_AS_STRING(obj);                                        \
+      } while (0)
+ #    define TEXT_DONEWRITE(obj, len) do {                             \
+        PyObject *new_;                                                        \
+        Py_SIZE(obj) = (len);                                          \
+        new_ = PyUnicode_FromEncodedObject(obj, 0, 0);                 \
+        assert(new_); Py_DECREF(obj); (obj) = new_;                    \
+      } while (0)
+ #  endif
+ #  define TEXT_FORMAT PyUnicode_FromFormat
+ #  define TEXT_VFORMAT PyUnicode_FromFormatV
+ #  define TEXT_FROMSTR(str) PyUnicode_FromString(str)
+ #  define TEXT_FROMSTRLEN(str, len) PyUnicode_FromStringAndSize(str, len)
+ #else
+ #  define TEXTOBJ PyStringObject
+ #  define TEXT_TYPE PyString_Type
+ #  define TEXT_CHECK(obj) PyString_Check(obj)
+ #  define TEXT_PTR(obj) PyString_AS_STRING(obj)
+ #  define TEXT_STR(obj) PyString_AsString(obj)
+ #  define TEXT_PTRLEN(obj, ptr, len) do {                             \
+      (ptr) = PyString_AS_STRING(obj);                                 \
+      (len) = PyString_GET_SIZE(obj);                                  \
+    } while (0)
+ #  define TEXT_FORMAT PyString_FromFormat
+ #  define TEXT_VFORMAT PyString_FromFormatV
+ #  define TEXT_PREPAREWRITE(obj, ptr, sz) do {                                \
+      (obj) = PyString_FromStringAndSize(0, (sz));                     \
+      (ptr) = PyString_AS_STRING(obj);                                 \
+    } while (0)
+ #  define TEXT_DONEWRITE(obj, sz) do { Py_SIZE(obj) = (sz); } while (0)
+ #  define TEXT_FROMSTR(str) PyString_FromString(str)
+ #  define TEXT_FROMSTRLEN(str, len) PyString_FromStringAndSize(str, len)
+ #endif
+ /*----- Utilities for returning values and exceptions ---------------------*/
+ /* Returning values. */
+ #define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0)
+ #define RETURN_NONE RETURN_OBJ(Py_None)
+ #define RETURN_NOTIMPL RETURN_OBJ(Py_NotImplemented)
+ #define RETURN_TRUE RETURN_OBJ(Py_True)
+ #define RETURN_FALSE RETURN_OBJ(Py_False)
+ #define RETURN_ME RETURN_OBJ(me)
+ /* Returning exceptions.  (Note that `KeyError' is `MAPERR' here, because
+  * Catacomb has its own kind of `KeyError'.)
+  */
+ #define EXCERR(exc, str) do {                                         \
+   PyErr_SetString(exc, str);                                          \
+   goto end;                                                           \
+ } while (0)
+ #define VALERR(str) EXCERR(PyExc_ValueError, str)
+ #define OVFERR(str) EXCERR(PyExc_OverflowError, str)
+ #define TYERR(str) EXCERR(PyExc_TypeError, str)
+ #define IXERR(str) EXCERR(PyExc_IndexError, str)
+ #define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str)
+ #define SYSERR(str) EXCERR(PyExc_SystemError, str)
+ #define NIERR(str) EXCERR(PyExc_NotImplementedError, str)
+ #define MAPERR(idx) do {                                              \
+   PyErr_SetObject(PyExc_KeyError, idx);                                       \
+   goto end;                                                           \
+ } while (0)
+ #define OSERR(name) do {                                              \
+   PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);                        \
+   goto end;                                                           \
+ } while (0)
+ /* Saving and restoring exceptions. */
+ struct excinfo { PyObject *ty, *val, *tb; };
+ #define EXCINFO_INIT { 0, 0, 0 }
+ #define INIT_EXCINFO(exc) do {                                                \
+   struct excinfo *_exc = (exc); _exc->ty = _exc->val = _exc->tb = 0;  \
+ } while (0)
+ #define RELEASE_EXCINFO(exc) do {                                     \
+   struct excinfo *_exc = (exc);                                               \
+   Py_XDECREF(_exc->ty);        _exc->ty  = 0;                                 \
+   Py_XDECREF(_exc->val); _exc->val = 0;                                       \
+   Py_XDECREF(_exc->tb);        _exc->tb  = 0;                                 \
+ } while (0)
+ #define STASH_EXCINFO(exc) do {                                               \
+   struct excinfo *_exc = (exc);                                               \
+   PyErr_Fetch(&_exc->ty, &_exc->val, &_exc->tb);                      \
+   PyErr_NormalizeException(&_exc->ty, &_exc->val, &_exc->tb);         \
+ } while (0)
+ #define RESTORE_EXCINFO(exc) do {                                     \
+   struct excinfo *_exc = (exc);                                               \
+   PyErr_Restore(_exc->ty, _exc->val, _exc->tb);                               \
+   _exc->ty = _exc->val = _exc->tb = 0;                                        \
+ } while (0)
+ extern void report_lost_exception(struct excinfo *, const char *, ...);
+ extern void report_lost_exception_v(struct excinfo *, const char *, va_list);
+ extern void stash_exception(struct excinfo *, const char *, ...);
+ extern void restore_exception(struct excinfo *, const char *, ...);
+ /*----- Conversions -------------------------------------------------------*/
+ /* Define an input conversion (`O&') function: check that the object has
+  * Python type TY, and extract a C pointer to CTY by calling EXT on the
+  * object (which may well be a macro).
+  */
+ #define CONVFUNC(ty, cty, ext)                                                \
+   int conv##ty(PyObject *o, void *p)                                  \
+   {                                                                   \
+     if (!PyObject_TypeCheck(o, ty##_pytype))                          \
+       TYERR("wanted a " #ty);                                         \
+     *(cty *)p = ext(o);                                                       \
+     return (1);                                                               \
+   end:                                                                        \
+     return (0);                                                               \
+   }
+ /* Input conversion functions for standard kinds of objects, with overflow
+  * checking where applicable.
+  */
+ struct bin { const void *p; Py_ssize_t sz; };
+ extern int convulong(PyObject *, void *); /* unsigned long */
+ extern int convuint(PyObject *, void *); /* unsigned int */
+ extern int convszt(PyObject *, void *);       /* size_t */
+ extern int convbool(PyObject *, void *); /* bool */
+ extern int convbin(PyObject *, void *); /* read buffer holding bytes */
+ /* Output conversions. */
+ extern PyObject *getbool(int);                /* bool */
+ extern PyObject *getulong(unsigned long); /* any kind of unsigned integer */
+ /*----- Miscellaneous utilities -------------------------------------------*/
+ #define FREEOBJ(obj) (Py_TYPE(obj)->tp_free((PyObject *)(obj)))
+   /* Actually free OBJ, e.g., in a deallocation function. */
+ extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *);
+   /* A `tp_new' function which refuses to make the object. */
+ extern PyObject *enrich_compare(int /*op*/, int /*cmp*/);
+   /* Use a traditional compare-against-zero comparison result CMP to answer a
+    * modern Python `tp_richcompare' operation OP.
+    */
+ #ifndef CONVERT_CAREFULLY
+ #  define CONVERT_CAREFULLY(newty, expty, obj)                                \
+      (!sizeof(*(expty *)0 = (obj)) + (/*unconst*/ newty)(obj))
+   /* Convert OBJ to the type NEWTY, having previously checked that it is
+    * convertible to the expected type EXPTY.
+    *
+    * Because of the way we set up types, we can make many kinds of tables be
+    * `const' which can't usually be so (because Python will want to fiddle
+    * with their reference counts); and, besides, Python's internals are
+    * generally quite bad at being `const'-correct about tables.  One frequent
+    * application of this macro, then, is in removing `const' from a type
+    * without sacrificing all type safety.  The other common use is in
+    * checking that method function types match up with the signatures
+    * expected in their method definitions.
+    */
+ #endif
+ #define KWLIST CONVERT_CAREFULLY(char **, const char *const *, kwlist)
+   /* Strip `const' qualifiers from the keyword list `kwlist'.  Useful when
+    * calling `PyArg_ParseTupleAndKeywords', which isn't `const'-correct.
+    */
+ /*----- Type definitions --------------------------------------------------*
+  *
+  * Pyke types are defined in a rather unusual way.
+  *
+  * The main code defines a `type skeleton' of type `PyTypeObject',
+  * conventionally named `TY_pytype_skel'.  Unlike typical Python type
+  * definitions in extensions, this can (and should) be read-only.  Also,
+  * there's no point in setting the `tp_base' pointer here, because the actual
+  * runtime base type object won't, in general, be known at compile time.
+  * Instead, the type skeletons are converted into Python `heap types' by the
+  * `INITTYPE' macro.  The main difference is that Python code can add
+  * attributes to heap types, and we make extensive use of this ability.
+  */
+ extern void *newtype(PyTypeObject */*meta*/,
+                    const PyTypeObject */*skel*/, const char */*name*/);
+   /* Make and return a new Python type object, of type META (typically
+    * `PyType_Type', but may be a subclass), filled in from the skeleton SKEL
+    * (null to inherit everything), and named NAME.  The caller can mess with
+    * the type object further at this time: call `typeready' when it's set up
+    * properly.
+    */
+ extern void typeready(PyTypeObject *);
+   /* The type object is now ready to be used. */
+ extern PyTypeObject *inittype(const PyTypeObject */*skel*/,
+                             PyTypeObject */*base*/,
+                             PyTypeObject */*meta*/);
+   /* All-in-one function to construct a working type from a type skeleton
+    * SKEL, with known base type BASE (null for `object') and metaclass.
+    */
+ /* Alias for built-in types, to fit in with Pyke naming conventions. */
+ #define root_pytype 0
+ #define type_pytype &PyType_Type
+ #define INITTYPE_META(ty, base, meta) do {                            \
+   ty##_pytype = inittype(&ty##_pytype_skel, base##_pytype, meta##_pytype); \
+ } while (0)
+ #define INITTYPE(ty, base) INITTYPE_META(ty, base, type)
+   /* Macros to initialize a type from its skeleton. */
+ /* Macros for filling in `PyMethodDef' tables, ensuring that functions have
+  * the expected signatures.
+  */
+ #define STD_METHOD(decor, func, flags, doc)                           \
+   { #func, decor(func), METH_VARARGS | flags, doc },
+ #define KEYWORD_METHOD(decor, func, flags, doc)                               \
+   { #func,                                                            \
+     CONVERT_CAREFULLY(PyCFunction, PyCFunctionWithKeywords, decor(func)), \
+     METH_VARARGS | METH_KEYWORDS | flags,                             \
+     doc },
+ #define NOARG_METHOD(decor, func, flags, doc)                         \
+   { #func,                                                            \
+     CONVERT_CAREFULLY(PyCFunction, PyNoArgsFunction, decor(func)),    \
+     METH_NOARGS | flags,                                              \
+     doc },
+ /* Convenience wrappers for filling in `PyMethodDef' tables, following
+  * Pyke naming convention.  Define `METHNAME' locally as
+  *
+  *    #define METHNAME(name) foometh_##func
+  *
+  * around the method table.
+  */
+ #define METH(func, doc) STD_METHOD(METHNAME, func, 0, doc)
+ #define KWMETH(func, doc) KEYWORD_METHOD(METHNAME, func, 0, doc)
+ #define NAMETH(func, doc) NOARG_METHOD(METHNAME, func, 0, doc)
+ #define CMTH(func, doc) STD_METHOD(METHNAME, func, METH_CLASS, doc)
+ #define KWCMTH(func, doc) KEYWORD_METHOD(METHNAME, func, METH_CLASS, doc)
+ #define NACMTH(func, doc) NOARG_METHOD(METHNAME, func, METH_CLASS, doc)
+ #define SMTH(func, doc) STD_METHOD(METHNAME, func, METH_STATIC, doc)
+ #define KWSMTH(func, doc) KEYWORD_METHOD(METHNAME, func, METH_STATIC, doc)
+ #define NASMTH(func, doc) NOARG_METHOD(METHNAME, func, METH_STATIC, doc)
+ /* Convenience wrappers for filling in `PyGetSetDef' tables, following Pyke
+  * naming convention.  Define `GETSETNAME' locally as
+  *
+  *    #define GETSETNAME(op, name) foo##op##_##func
+  *
+  * around the get/set table.
+  */
+ #define GET(func, doc)                                                        \
+   { #func, GETSETNAME(get, func), 0, doc },
+ #define GETSET(func, doc)                                             \
+   { #func, GETSETNAME(get, func), GETSETNAME(set, func), doc },
+ /* Convenience wrappers for filling in `PyMemberDef' tables.  Define
+  * `MEMBERSTRUCT' locally as
+  *
+  *    #define MEMBERSTRUCT foo_pyobj
+  *
+  * around the member table.
+  */
+ #define MEMRNM(name, ty, mem, f, doc)                                 \
+   { #name, ty, offsetof(MEMBERSTRUCT, mem), f, doc },
+ #define MEMBER(name, ty, f, doc) MEMRNM(name, ty, 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;
+   /* The overall module name.  Set this with `TEXT_FROMSTR'. */
+ extern PyObject *home_module;
+   /* The overall module object. */
+ extern PyObject *mkexc(PyObject */*mod*/, PyObject */*base*/,
+                      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.
+    */
+ #define INSERT(name, ob) do {                                         \
+   PyObject *_o = (PyObject *)(ob);                                    \
+   Py_INCREF(_o);                                                      \
+   PyModule_AddObject(mod, name, _o);                                  \
+ } while (0)
+   /* Insert a Python object OB into the module `mod' under the given NAME. */
+ /* Numeric constants. */
+ struct nameval { const char *name; unsigned f; unsigned long value; };
+ #define CF_SIGNED 1u
+ extern void setconstants(PyObject *, const struct nameval *);
+ #define CONST(x) { #x, (x) >= 0 ? 0 : CF_SIGNED, x }
+ #define CONSTFLAG(f, x) { #x, f, x }
+ #define INSEXC(name, var, base, meth)                                 \
+   INSERT(name, var = mkexc(mod, base, name, meth))
+   /* Insert an exception class into the module `mod'; other arguments are as
+    * for `mkexc'.
+    */
+ /*----- Submodules --------------------------------------------------------*
+  *
+  * It's useful to split the Python module up into multiple source files, and
+  * have each one contribute its definitions into the main module.
+  *
+  * Define a list-macro `MODULES' in the master header file naming the
+  * submodules to be processed, and run
+  *
+  *    MODULES(DECLARE_MODINIT)
+  *
+  * to declare the interface functions.
+  *
+  * Each submodule FOO defines two functions: `FOO_pyinit' initializes types
+  * (see `INITTYPE' above) and accumulates methods (`addmethods' below), while
+  * `FOO_pyinsert' populates the module with additional definitions
+  * (especially types, though also constants).
+  *
+  * The top-level module initialization should call `INIT_MODULES' before
+  * creating the Python module, and `INSERT_MODULES' afterwards to make
+  * everything work.
+  */
+ extern void addmethods(const PyMethodDef *);
+ extern PyMethodDef *donemethods(void);
+   /* Accumulate method-table fragments, and return the combined table of all
+    * of the fragments.
+    */
+ #define DECLARE_MODINIT(m)                                            \
+   extern void m##_pyinit(void);                                               \
+   extern void m##_pyinsert(PyObject *);
+   /* Declare submodule interface functions. */
+ #define DOMODINIT(m) m##_pyinit();
+ #define DOMODINSERT(m) m##_pyinsert(mod);
+ #define INIT_MODULES do { MODULES(DOMODINIT) } while (0)
+ #define INSERT_MODULES do { MODULES(DOMODINSERT) } while (0)
+   /* Top-level dispatch to the various submodules. */
+ /*----- Generic mapping support -------------------------------------------*/
+ /* Operations table.  ME is the mapping object throughout. */
+ typedef struct gmap_ops {
+   size_t isz;                         /* iterator size */
+   void *(*lookup)(PyObject *me, PyObject *key, unsigned *f);
+     /* Lookup the KEY.  If it is found, return an entry pointer for it; if F
+      * is not null, set *F nonzero.  Otherwise, if F is null, return a null
+      * pointer (without setting a pending exception); if F is not null, then
+      * set *F zero and return a fresh entry pointer.  Return null on a Python
+      * exception (the caller will notice the difference.)
+      */
+   void (*iter_init)(PyObject *me, void *i);
+     /* Initialize an iterator at I. */
+   void *(*iter_next)(PyObject *me, void *i);
+     /* Return an entry pointer for a different item, or null if all have been
+      * visited.
+      */
+   PyObject *(*entry_key)(PyObject *me, void *e);
+     /* Return the key object for a mapping entry. */
+   PyObject *(*entry_value)(PyObject *me, void *e);
+     /* Return the value object for a mapping entry. */
+   int (*set_entry)(PyObject *me, void *e, PyObject *val);
+     /* Modify the entry by storing VAL in its place.  Return 0 on success,
+      * or -1 on a Python error.
+      */
+   int (*del_entry)(PyObject *me, void *e);
+     /* Delete the entry.  (It may be necessary to delete a freshly allocated
+      * entry, e.g., if `set_entry' failed.)  Return 0 on success, or -1 on a
+      * Python error.
+      */
+ } gmap_ops;
+ /* The intrusion at the head of a mapping object. */
+ #define GMAP_PYOBJ_HEAD                                                       \
+   PyObject_HEAD                                                               \
+   const gmap_ops *gmops;
+ typedef struct gmap_pyobj {
+   GMAP_PYOBJ_HEAD
+ } gmap_pyobj;
+ #define GMAP_OPS(obj) (((gmap_pyobj *)(obj))->gmops)
+   /* Discover the operations from a mapping object. */
+ /* Mapping methods. */
+ #define GMAP_METMNAME(func) gmapmeth_##func
+ #define GMAP_METH(func, doc) STD_METHOD(GMAP_METMNAME, func, 0, doc)
+ #define GMAP_KWMETH(func, doc) KEYWORD_METHOD(GMAP_METMNAME, func, 0, doc)
+ #define GMAP_NAMETH(func, doc) NOARG_METHOD(GMAP_METMNAME, func, 0, doc)
+ #define GMAP_METHDECL(func, doc)                                      \
+   extern PyObject *gmapmeth_##func(PyObject *, PyObject *);
+ #define GMAP_KWMETHDECL(func, doc)                                    \
+   extern PyObject *gmapmeth_##func(PyObject *, PyObject *, PyObject *);
+ #define GMAP_NAMETHDECL(func, doc)                                    \
+   extern PyObject *gmapmeth_##func(PyObject *);
+ #ifdef PY3
+ #  define GMAP_DOROMETHODS(METH, KWMETH, NAMETH)                      \
+     NAMETH(keys,      "D.keys() -> LIST")                             \
+     NAMETH(values,    "D.values() -> LIST")                           \
+     NAMETH(items,     "D.items() -> LIST")                            \
+     KWMETH(get,               "D.get(KEY, [default = None]) -> VALUE")
+ #else
+ #  define GMAP_DOROMETHODS(METH, KWMETH, NAMETH)                      \
+     METH  (has_key,   "D.has_key(KEY) -> BOOL")                       \
+     NAMETH(keys,      "D.keys() -> LIST")                             \
+     NAMETH(values,    "D.values() -> LIST")                           \
+     NAMETH(items,     "D.items() -> LIST")                            \
+     NAMETH(iterkeys,  "D.iterkeys() -> ITER")                         \
+     NAMETH(itervalues,        "D.itervalues() -> ITER")                       \
+     NAMETH(iteritems, "D.iteritems() -> ITER")                        \
+     KWMETH(get,               "D.get(KEY, [default = None]) -> VALUE")
+ #endif
+ #define GMAP_DOMETHODS(METH, KWMETH, NAMETH)                          \
+   GMAP_DOROMETHODS(METH, KWMETH, NAMETH)                              \
+   NAMETH(clear,               "D.clear()")                                    \
+   KWMETH(setdefault,  "D.setdefault(K, [default = None]) -> VALUE")   \
+   KWMETH(pop,         "D.pop(KEY, [default = <error>]) -> VALUE")     \
+   NAMETH(popitem,     "D.popitem() -> (KEY, VALUE)")                  \
+   KWMETH(update,      "D.update(MAP)")
+ GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL, GMAP_NAMETHDECL)
+ #define GMAP_ROMETHODS GMAP_DOROMETHODS(GMAP_METH, GMAP_KWMETH, GMAP_NAMETH)
+ #define GMAP_METHODS GMAP_DOMETHODS(GMAP_METH, GMAP_KWMETH, GMAP_NAMETH)
+ /* Mapping protocol implementation. */
+ extern Py_ssize_t gmap_pysize(PyObject *); /* for `mp_length' */
+ extern PyObject *gmap_pyiter(PyObject *); /* for `tp_iter' */
+ extern PyObject *gmap_pylookup(PyObject *, PyObject *); /* for `mp_subscript' */
+ extern int gmap_pystore(PyObject *, PyObject *, PyObject *); /* for `mp_ass_subscript' */
+ extern int gmap_pyhaskey(PyObject *, PyObject *); /* for `sq_contains' */
+ extern const PySequenceMethods gmap_pysequence; /* for `tp_as_sequence' */
+ extern const PyMethodDef gmapro_pymethods[]; /* read-only methods */
+ extern const PyMethodDef gmap_pymethods[]; /* all the standard methods */
+ /*----- That's all, folks -------------------------------------------------*/
+ #ifdef __cplusplus
+   }
+ #endif
+ #endif