algorithms.c: Add bindings for STROBE.
[catacomb-python] / catacomb.c
CommitLineData
d7ab1bab 1/* -*-c-*-
2 *
d7ab1bab 3 * Where the fun begins
4 *
5 * (c) 2004 Straylight/Edgeware
6 */
7
b2687a0a 8/*----- Licensing notice --------------------------------------------------*
d7ab1bab 9 *
10 * This file is part of the Python interface to Catacomb.
11 *
12 * Catacomb/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
b2687a0a 16 *
d7ab1bab 17 * Catacomb/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
b2687a0a 21 *
d7ab1bab 22 * You should have received a copy of the GNU General Public License
23 * along with Catacomb/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27/*----- Header files ------------------------------------------------------*/
28
29#include "catacomb-python.h"
30
31/*----- Main code ---------------------------------------------------------*/
32
d7ab1bab 33PyObject *mexp_common(PyObject *me, PyObject *arg,
34 size_t efsz,
35 PyObject *(*id)(PyObject *),
36 int (*fill)(void *, PyObject *,
37 PyObject *, PyObject *),
af974107 38 PyObject *(*exp)(PyObject *, void *, size_t),
d7ab1bab 39 void (*drop)(void *))
40{
74836df7 41 size_t i = 0, o, n;
af974107 42 int flat;
74836df7
MW
43 PyObject *qq = 0, *x = 0, *y = 0, *z = 0, *it = 0;
44 char *v = 0;
d7ab1bab 45
74836df7
MW
46 if (PyTuple_Size(arg) == 1) arg = PyTuple_GET_ITEM(arg, 0);
47 it = PyObject_GetIter(arg); if (!it) goto end;
48 qq = PyIter_Next(it);
49 if (!qq) {
50 if (!PyErr_Occurred()) z = id(me);
51 else goto end;
52 }
53 flat = !PySequence_Check(qq);
54 if (!PySequence_Check(arg))
55 n = 16;
d7ab1bab 56 else {
74836df7
MW
57 n = PySequence_Size(arg);
58 if (n == (size_t)-1 && PyErr_Occurred()) goto end;
59 if (flat) n /= 2;
60 if (!n) n = 16;
d7ab1bab 61 }
d7ab1bab 62
74836df7
MW
63 v = xmalloc(n*efsz);
64 o = 0;
65 for (;;) {
66 if (!flat) {
67 if (!PySequence_Check(qq) || PySequence_Size(qq) != 2)
d7ab1bab 68 TYERR("want a sequence of pairs");
d7ab1bab 69 x = PySequence_GetItem(qq, 0);
70 y = PySequence_GetItem(qq, 1);
74836df7
MW
71 } else {
72 x = qq; qq = 0;
73 y = PyIter_Next(it);
74 if (!y) {
75 if (PyErr_Occurred()) goto end;
76 VALERR("must have even number of operands");
77 }
d7ab1bab 78 }
79 if (!x || !y) goto end;
74836df7
MW
80
81 if (i >= n) { n *= 2; v = xrealloc(v, n*efsz, i*efsz); }
82 if (fill(v + o, me, x, y)) {
83 if (PyErr_Occurred()) goto end;
84 TYERR("type mismatch");
85 }
86 i++; o += efsz;
87 Py_DECREF(x); x = 0;
88 Py_DECREF(y); y = 0;
89 Py_XDECREF(qq);
90
91 qq = PyIter_Next(it);
92 if (!qq) {
93 if (PyErr_Occurred()) goto end;
94 else break;
d7ab1bab 95 }
d7ab1bab 96 }
74836df7
MW
97
98 z = exp(me, v, i);
d7ab1bab 99
100end:
74836df7
MW
101 while (i--) { o -= efsz; drop(v + o); }
102 xfree(v);
103 Py_XDECREF(it); Py_XDECREF(qq); Py_XDECREF(x); Py_XDECREF(y);
d7ab1bab 104 return (z);
105}
106
361fd0e6
MW
107int convmpw(PyObject *o, void *pp)
108{
109 unsigned long u;
110 unsigned *p = pp;
111
112 if (!convulong(o, &u)) goto end;
113 if (u > MPW_MAX) VALERR("out of range");
114 *p = u;
115 return (1);
116end:
117 return (0);
118}
119
b115b0c0
MW
120static PyTypeObject *thingtab_pytype;
121
122typedef struct thingentry {
123 sym_base _b;
124 PyObject *val;
125} thingentry;
126#define THING_VAL(x) (((thingentry *)(x))->val)
127
128typedef struct thingtab_pyobj {
129 GMAP_PYOBJ_HEAD
130 sym_table t;
131} thingtab_pyobj;
132#define THINGTAB_T(x) (&((thingtab_pyobj *)(x))->t)
133
134static void *thingtab_gmlookup(PyObject *me, PyObject *key, unsigned *f)
135{
136 const char *p;
137
cfb291f0 138 p = TEXT_STR(key); if (!p) return (0);
b115b0c0
MW
139 return (sym_find(THINGTAB_T(me), p, -1, 0, f));
140}
141
142static void thingtab_gmiterinit(PyObject *me, void *i)
143 { sym_mkiter(i, THINGTAB_T(me)); }
144
145static void *thingtab_gmiternext(PyObject *me, void *i)
146 { sym_iter *it = i; void *e; SYM_NEXT(it, e); return (e); }
147
148static PyObject *thingtab_gmentrykey(PyObject *me, void *e)
cfb291f0 149 { return (TEXT_FROMSTR(SYM_NAME(e))); }
b115b0c0
MW
150
151static PyObject *thingtab_gmentryvalue(PyObject *me, void *e)
152 { PyObject *rc = THING_VAL(e); RETURN_OBJ(rc); }
153
154static const gmap_ops thingtab_gmops = {
155 sizeof(sym_iter),
156 thingtab_gmlookup,
157 thingtab_gmiterinit,
158 thingtab_gmiternext,
159 thingtab_gmentrykey,
160 thingtab_gmentryvalue
161};
162
163static Py_ssize_t thing_pysize(PyObject *me)
164 { return gmap_pysize_from_sym(THINGTAB_T(me)); }
165
166static const PyMappingMethods thingtab_pymapping = {
167 thing_pysize,
168 gmap_pylookup,
169 0
170};
171
172static thingtab_pyobj *make_thingtab(void)
173{
174 thingtab_pyobj *map = PyObject_NEW(thingtab_pyobj, thingtab_pytype);
175
176 map->gmops = &thingtab_gmops;
177 sym_create(&map->t);
178 return (map);
179}
180
181PyObject *make_algtab(const void *tab, size_t esz,
182 const char *(*namefn)(const void *),
183 PyObject *(*valfn)(const void *))
184{
185 thingtab_pyobj *map = make_thingtab();
186 const char *p = tab;
187 const char *name;
188 thingentry *e;
189 unsigned f;
190
191 for (;;) {
192 name = namefn(p); if (!name) break;
193 e = sym_find(&map->t, name, -1, sizeof(*e), &f); assert(!f);
194 e->val = valfn(p);
195 p += esz;
196 }
197 return ((PyObject *)map);
198}
199
200PyObject *make_grouptab(const void *tab, size_t esz,
201 const char *(*namefn)(const void *),
202 int (*ixfn)(const void *), PyObject *(*valfn)(int))
203{
204 thingtab_pyobj *map = make_thingtab();
205 struct { const char *name; int ix; } *ixtab = 0;
206 PyObject **valtab, **vv;
207 size_t i = 0, n = 0;
208 const char *p = tab;
209 const char *name;
210 thingentry *e;
211 unsigned f;
212
213 for (;;) {
214 name = namefn(p); if (!name) break;
215 if (i >= n) {
216 if (!n) n = 16;
217 else n *= 2;
218 ixtab = xrealloc(ixtab, n*sizeof(*ixtab), i*sizeof(*ixtab));
219 }
220 ixtab[i].name = name; ixtab[i].ix = ixfn(p); assert(ixtab[i].ix >= 0);
221 p += esz; i++;
222 }
223 n = i;
224
225 valtab = xmalloc(n*sizeof(*valtab));
226 for (i = 0; i < n; i++) valtab[i] = 0;
227
228 for (i = 0; i < n; i++) {
229 e = sym_find(&map->t, ixtab[i].name, -1, sizeof(*e), &f); assert(!f);
230 vv = &valtab[ixtab[i].ix];
231 if (*vv) Py_INCREF(*vv);
232 else *vv = valfn(ixtab[i].ix);
233 e->val = *vv;
234 }
235
236 xfree(ixtab); xfree(valtab);
237 return ((PyObject *)map);
238}
239
240static const PyTypeObject thingtab_pytype_skel = {
4648f560 241 PyVarObject_HEAD_INIT(0, 0) /* Header */
b115b0c0
MW
242 "_MiscTable", /* @tp_name@ */
243 sizeof(thingtab_pyobj), /* @tp_basicsize@ */
244 0, /* @tp_itemsize@ */
245
246 0, /* @tp_dealloc@ */
247 0, /* @tp_print@ */
248 0, /* @tp_getattr@ */
249 0, /* @tp_setattr@ */
250 0, /* @tp_compare@ */
251 0, /* @tp_repr@ */
252 0, /* @tp_as_number@ */
253 PYSEQUENCE(gmap), /* @tp_as_sequence@ */
254 PYMAPPING(thingtab), /* @tp_as_mapping@ */
255 0, /* @tp_hash@ */
256 0, /* @tp_call@ */
257 0, /* @tp_str@ */
258 0, /* @tp_getattro@ */
259 0, /* @tp_setattro@ */
260 0, /* @tp_as_buffer@ */
261 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
262 Py_TPFLAGS_BASETYPE,
263
264 /* @tp_doc@ */
265 "Class for tables of algorithms and abstract-group data.\n"
266 " Not instantiable by users.",
267
268 0, /* @tp_traverse@ */
269 0, /* @tp_clear@ */
270 0, /* @tp_richcompare@ */
271 0, /* @tp_weaklistoffset@ */
272 gmap_pyiter, /* @tp_iter@ */
273 0, /* @tp_iternext@ */
274 PYMETHODS(gmapro), /* @tp_methods@ */
275 0, /* @tp_members@ */
276 0, /* @tp_getset@ */
277 0, /* @tp_base@ */
278 0, /* @tp_dict@ */
279 0, /* @tp_descr_get@ */
280 0, /* @tp_descr_set@ */
281 0, /* @tp_dictoffset@ */
282 0, /* @tp_init@ */
283 PyType_GenericAlloc, /* @tp_alloc@ */
284 abstract_pynew, /* @tp_new@ */
285 0, /* @tp_free@ */
286 0 /* @tp_is_gc@ */
287};
288
d7ab1bab 289static PyObject *smallprimes(void)
290{
291 PyObject *v = PyList_New(NPRIME);
292 int i;
293
294 for (i = 0; i < NPRIME; i++)
8dd6ebb3 295 PyList_SET_ITEM(v, i, PyInt_FromLong(primetab[i]));
d7ab1bab 296 return (v);
297}
298
46e6ad89 299static PyObject *meth__ego(PyObject *me, PyObject *arg)
300{
301 char *argv0;
302 if (!PyArg_ParseTuple(arg, "s:_ego", &argv0))
303 return (0);
20441612 304 if (STRCMP(QUIS, ==, "<UNNAMED>"))
46e6ad89 305 ego(argv0);
306 RETURN_NONE;
307}
308
ddd4720b 309static const PyMethodDef methods[] = {
46e6ad89 310#define METHNAME(func) meth_##func
ef783f91 311 METH (_ego, "_ego(ARGV0)")
46e6ad89 312#undef METHNAME
313 { 0 }
314};
315
bb87b97a
MW
316static void init_random(void)
317{
57aaeb41 318#if PY_VERSION_HEX >= 0x02060000
bb87b97a
MW
319 char *seed;
320 uint32 r;
321
322 if (!Py_HashRandomizationFlag) return;
323 seed = getenv("PYTHONHASHSEED");
20441612 324 if (!seed || STRCMP(seed, ==, "random")) r = GR_WORD(&rand_global);
bb87b97a
MW
325 else r = strtoul(seed, 0, 0);
326 if (!r) r = 0xe011f220; /* zero doesn't work well */
327 unihash_setkey(&unihash_global, r);
328#endif
329}
330
d472b9a1
MW
331#ifdef PY3
332static PyModuleDef moddef = {
333 PyModuleDef_HEAD_INIT,
334 "catacomb._base", /* @m_name@ */
335 "Low-level module for Catacomb bindings. Use `catacomb' instead.",
336 /* @m_doc@ */
337 0, /* @m_size@ */
338 0, /* @m_methods@ */
339 0, /* @m_slots@ */
340 0, /* @m_traverse@ */
341 0, /* @m_clear@ */
342 0 /* @m_free@ */
343};
344#endif
345
346EXPORT PyMODINIT_FUNC PY23(init_base, PyInit__base)(void)
11cb3d97 347{
d7ab1bab 348 PyObject *mod;
47061e38 349
cfb291f0 350 modname = TEXT_FROMSTR("catacomb");
46e6ad89 351 addmethods(methods);
d7ab1bab 352 INIT_MODULES;
b115b0c0 353 INITTYPE(thingtab, root);
bb87b97a 354 init_random();
d472b9a1
MW
355#ifdef PY3
356 moddef.m_methods = donemethods();
357 mod = PyModule_Create(&moddef);
358#else
11cb3d97 359 mod = Py_InitModule("catacomb._base", donemethods());
d472b9a1 360#endif
d7ab1bab 361 INSERT_MODULES;
b115b0c0 362 INSERT("_MiscTable", thingtab_pytype);
d7ab1bab 363 INSERT("smallprimes", smallprimes());
d472b9a1
MW
364#ifdef PY3
365 return (mod);
366#endif
d7ab1bab 367}
368
369/*----- That's all, folks -------------------------------------------------*/