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