+int convmpw(PyObject *o, void *pp)
+{
+ unsigned long u;
+ unsigned *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > MPW_MAX) VALERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+static PyTypeObject *thingtab_pytype;
+
+typedef struct thingentry {
+ sym_base _b;
+ PyObject *val;
+} thingentry;
+#define THING_VAL(x) (((thingentry *)(x))->val)
+
+typedef struct thingtab_pyobj {
+ GMAP_PYOBJ_HEAD
+ sym_table t;
+} thingtab_pyobj;
+#define THINGTAB_T(x) (&((thingtab_pyobj *)(x))->t)
+
+static void *thingtab_gmlookup(PyObject *me, PyObject *key, unsigned *f)
+{
+ const char *p;
+
+ p = PyString_AsString(key); if (!p) return (0);
+ return (sym_find(THINGTAB_T(me), p, -1, 0, f));
+}
+
+static void thingtab_gmiterinit(PyObject *me, void *i)
+ { sym_mkiter(i, THINGTAB_T(me)); }
+
+static void *thingtab_gmiternext(PyObject *me, void *i)
+ { sym_iter *it = i; void *e; SYM_NEXT(it, e); return (e); }
+
+static PyObject *thingtab_gmentrykey(PyObject *me, void *e)
+ { return (PyString_FromString(SYM_NAME(e))); }
+
+static PyObject *thingtab_gmentryvalue(PyObject *me, void *e)
+ { PyObject *rc = THING_VAL(e); RETURN_OBJ(rc); }
+
+static const gmap_ops thingtab_gmops = {
+ sizeof(sym_iter),
+ thingtab_gmlookup,
+ thingtab_gmiterinit,
+ thingtab_gmiternext,
+ thingtab_gmentrykey,
+ thingtab_gmentryvalue
+};
+
+static Py_ssize_t thing_pysize(PyObject *me)
+ { return gmap_pysize_from_sym(THINGTAB_T(me)); }
+
+static const PyMappingMethods thingtab_pymapping = {
+ thing_pysize,
+ gmap_pylookup,
+ 0
+};
+
+static thingtab_pyobj *make_thingtab(void)
+{
+ thingtab_pyobj *map = PyObject_NEW(thingtab_pyobj, thingtab_pytype);
+
+ map->gmops = &thingtab_gmops;
+ sym_create(&map->t);
+ return (map);
+}
+
+PyObject *make_algtab(const void *tab, size_t esz,
+ const char *(*namefn)(const void *),
+ PyObject *(*valfn)(const void *))
+{
+ thingtab_pyobj *map = make_thingtab();
+ const char *p = tab;
+ const char *name;
+ thingentry *e;
+ unsigned f;
+
+ for (;;) {
+ name = namefn(p); if (!name) break;
+ e = sym_find(&map->t, name, -1, sizeof(*e), &f); assert(!f);
+ e->val = valfn(p);
+ p += esz;
+ }
+ return ((PyObject *)map);
+}
+
+PyObject *make_grouptab(const void *tab, size_t esz,
+ const char *(*namefn)(const void *),
+ int (*ixfn)(const void *), PyObject *(*valfn)(int))
+{
+ thingtab_pyobj *map = make_thingtab();
+ struct { const char *name; int ix; } *ixtab = 0;
+ PyObject **valtab, **vv;
+ size_t i = 0, n = 0;
+ const char *p = tab;
+ const char *name;
+ thingentry *e;
+ unsigned f;
+
+ for (;;) {
+ name = namefn(p); if (!name) break;
+ if (i >= n) {
+ if (!n) n = 16;
+ else n *= 2;
+ ixtab = xrealloc(ixtab, n*sizeof(*ixtab), i*sizeof(*ixtab));
+ }
+ ixtab[i].name = name; ixtab[i].ix = ixfn(p); assert(ixtab[i].ix >= 0);
+ p += esz; i++;
+ }
+ n = i;
+
+ valtab = xmalloc(n*sizeof(*valtab));
+ for (i = 0; i < n; i++) valtab[i] = 0;
+
+ for (i = 0; i < n; i++) {
+ e = sym_find(&map->t, ixtab[i].name, -1, sizeof(*e), &f); assert(!f);
+ vv = &valtab[ixtab[i].ix];
+ if (*vv) Py_INCREF(*vv);
+ else *vv = valfn(ixtab[i].ix);
+ e->val = *vv;
+ }
+
+ xfree(ixtab); xfree(valtab);
+ return ((PyObject *)map);
+}
+
+static const PyTypeObject thingtab_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "_MiscTable", /* @tp_name@ */
+ sizeof(thingtab_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ PYSEQUENCE(gmap), /* @tp_as_sequence@ */
+ PYMAPPING(thingtab), /* @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@ */
+ "Class for tables of algorithms and abstract-group data.\n"
+ " Not instantiable by users.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ gmap_pyiter, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ PYMETHODS(gmapro), /* @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@ */
+};
+