chiark / gitweb /
Split 'pyke/' into commit 'e5aa77d831ad8b42167f3205ee290f238003e20a'
[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 *, size_t),
39                       void (*drop)(void *))
40 {
41   size_t i = 0, o, n;
42   int flat;
43   PyObject *qq = 0, *x = 0, *y = 0, *z = 0, *it = 0;
44   char *v = 0;
45
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;
56   else {
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;
61   }
62
63   v = xmalloc(n*efsz);
64   o = 0;
65   for (;;) {
66     if (!flat) {
67       if (!PySequence_Check(qq) || PySequence_Size(qq) != 2)
68         TYERR("want a sequence of pairs");
69       x = PySequence_GetItem(qq, 0);
70       y = PySequence_GetItem(qq, 1);
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       }
78     }
79     if (!x || !y) goto end;
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;
95     }
96   }
97
98   z = exp(me, v, i);
99
100 end:
101   while (i--) { o -= efsz; drop(v + o); }
102   xfree(v);
103   Py_XDECREF(it); Py_XDECREF(qq); Py_XDECREF(x); Py_XDECREF(y);
104   return (z);
105 }
106
107 int 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);
116 end:
117   return (0);
118 }
119
120 static PyTypeObject *thingtab_pytype;
121
122 typedef struct thingentry {
123   sym_base _b;
124   PyObject *val;
125 } thingentry;
126 #define THING_VAL(x) (((thingentry *)(x))->val)
127
128 typedef struct thingtab_pyobj {
129   GMAP_PYOBJ_HEAD
130   sym_table t;
131 } thingtab_pyobj;
132 #define THINGTAB_T(x) (&((thingtab_pyobj *)(x))->t)
133
134 static void *thingtab_gmlookup(PyObject *me, PyObject *key, unsigned *f)
135 {
136   const char *p;
137
138   p = TEXT_STR(key); if (!p) return (0);
139   return (sym_find(THINGTAB_T(me), p, -1, 0, f));
140 }
141
142 static void thingtab_gmiterinit(PyObject *me, void *i)
143   { sym_mkiter(i, THINGTAB_T(me)); }
144
145 static void *thingtab_gmiternext(PyObject *me, void *i)
146   { sym_iter *it = i; void *e; SYM_NEXT(it, e); return (e); }
147
148 static PyObject *thingtab_gmentrykey(PyObject *me, void *e)
149   { return (TEXT_FROMSTR(SYM_NAME(e))); }
150
151 static PyObject *thingtab_gmentryvalue(PyObject *me, void *e)
152   { PyObject *rc = THING_VAL(e); RETURN_OBJ(rc); }
153
154 static 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
163 static Py_ssize_t thing_pysize(PyObject *me)
164   { return gmap_pysize_from_sym(THINGTAB_T(me)); }
165
166 static const PyMappingMethods thingtab_pymapping = {
167   thing_pysize,
168   gmap_pylookup,
169   0
170 };
171
172 static 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
181 PyObject *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
200 PyObject *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
240 static const PyTypeObject thingtab_pytype_skel = {
241   PyVarObject_HEAD_INIT(0, 0)           /* Header */
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
289 static PyObject *smallprimes(void)
290 {
291   PyObject *v = PyList_New(NPRIME);
292   int i;
293
294   for (i = 0; i < NPRIME; i++)
295     PyList_SET_ITEM(v, i, PyInt_FromLong(primetab[i]));
296   return (v);
297 }
298
299 static PyObject *meth__ego(PyObject *me, PyObject *arg)
300 {
301   char *argv0;
302   if (!PyArg_ParseTuple(arg, "s:_ego", &argv0))
303     return (0);
304   if (STRCMP(QUIS, ==, "<UNNAMED>"))
305     ego(argv0);
306   RETURN_NONE;
307 }
308
309 static const PyMethodDef methods[] = {
310 #define METHNAME(func) meth_##func
311   METH  (_ego,          "_ego(ARGV0)")
312 #undef METHNAME
313   { 0 }
314 };
315
316 static void init_random(void)
317 {
318 #if PY_VERSION_HEX >= 0x02060000
319   char *seed;
320   uint32 r;
321
322   if (!Py_HashRandomizationFlag) return;
323   seed = getenv("PYTHONHASHSEED");
324   if (!seed || STRCMP(seed, ==, "random")) r = GR_WORD(&rand_global);
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
331 #ifdef PY3
332 static 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
346 EXPORT PyMODINIT_FUNC PY23(init_base, PyInit__base)(void)
347 {
348   PyObject *mod;
349
350   modname = TEXT_FROMSTR("catacomb");
351   addmethods(methods);
352   INIT_MODULES;
353   INITTYPE(thingtab, root);
354   init_random();
355 #ifdef PY3
356   moddef.m_methods = donemethods();
357   mod = PyModule_Create(&moddef);
358 #else
359   mod = Py_InitModule("catacomb._base", donemethods());
360 #endif
361   INSERT_MODULES;
362   INSERT("_MiscTable", thingtab_pytype);
363   INSERT("smallprimes", smallprimes());
364 #ifdef PY3
365   return (mod);
366 #endif
367 }
368
369 /*----- That's all, folks -------------------------------------------------*/