chiark / gitweb /
Checkin, Debianized and more or less complete.
[pyke] / catacomb.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Where the fun begins
6  *
7  * (c) 2004 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the Python interface to Catacomb.
13  *
14  * Catacomb/Python is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * Catacomb/Python is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with Catacomb/Python; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "catacomb-python.h"
32
33 /*----- Main code ---------------------------------------------------------*/
34
35 static void setconstants(PyObject *mod)
36 {
37   static const struct { const char *name; unsigned long value; } consts[] = {
38 #define C(x) { #x, x }
39     C(FTY_PRIME), C(FTY_BINARY),
40     C(PGEN_PASS), C(PGEN_FAIL), C(PGEN_BEGIN), C(PGEN_TRY), C(PGEN_DONE),
41       C(PGEN_ABORT),
42     C(MPW_MAX),
43     C(PMODE_READ), C(PMODE_VERIFY),
44     C(KOPEN_READ), C(KOPEN_WRITE), C(KOPEN_NOFILE),
45     C(KEXP_FOREVER), C(KEXP_EXPIRE),
46     C(KF_ENCMASK), C(KENC_BINARY), C(KENC_MP), C(KENC_STRUCT),
47       C(KENC_ENCRYPT), C(KENC_STRING), C(KENC_EC),
48     C(KF_CATMASK), C(KCAT_SYMM), C(KCAT_PRIV), C(KCAT_PUB), C(KCAT_SHARE),
49     C(KF_NONSECRET),
50     C(KF_BURN), C(KF_OPT),
51 #define ENTRY(tag, val, str) C(KERR_##tag),
52     KEY_ERRORS(ENTRY)
53 #undef ENTRY
54 #undef C
55     { 0 }
56   };
57   int i;
58   PyObject *x;
59
60   for (i = 0; consts[i].name; i++) {
61     if (consts[i].value > LONG_MAX)
62       x = PyLong_FromUnsignedLong(consts[i].value);
63     else
64       x = PyInt_FromLong(consts[i].value);
65     PyModule_AddObject(mod, (/*unconst*/ char *)consts[i].name, x);
66   }
67 }
68
69 #define GETU_(n)                                                        \
70   PyObject *getu##n(uint##n w)                                          \
71   {                                                                     \
72     if (w <= MASK##n)                                                   \
73       return (PyInt_FromLong(w));                                       \
74     else                                                                \
75       return (PyLong_FromUnsignedLong(w));                              \
76   }
77 DOUINTSZ(GETU_)
78
79 PyObject *getbool(int b)
80 {
81   if (b) RETURN_TRUE;
82   else RETURN_FALSE;
83 }
84
85 PyObject *abstract_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
86 {
87   PyErr_SetString(PyExc_TypeError, "can't instantiate this class");
88   return (0);
89 }
90
91 int convulong(PyObject *o, void *pp)
92 {
93   long i;
94   unsigned long *p = pp;
95   PyObject *t;
96
97   if (PyInt_Check(o)) {
98     i = PyInt_AS_LONG(o);
99     if (i < 0) TYERR("must be nonnegative");
100     *p = i;
101   } else {
102     if ((t = PyNumber_Long(o)) == 0) goto end;
103     *p = PyLong_AsUnsignedLong(t);
104     Py_DECREF(t);
105     if (PyErr_Occurred()) goto end;
106   }
107   return (1);
108 end:
109   return (0);
110 }
111
112 #define CONVU_(n)                                                       \
113   int convu##n(PyObject *o, void *pp)                                   \
114   {                                                                     \
115     unsigned long u;                                                    \
116     uint##n *p = pp;                                                    \
117                                                                         \
118     if (!convulong(o, &u)) goto end;                                    \
119     if (u > MASK##n) TYERR("out of range");                             \
120     *p = u;                                                             \
121     return (1);                                                         \
122   end:                                                                  \
123     return (0);                                                         \
124   }
125 DOUINTSZ(CONVU_)
126
127 int convuint(PyObject *o, void *pp)
128 {
129   unsigned long u;
130   unsigned *p = pp;
131
132   if (!convulong(o, &u)) goto end;
133   if (u > UINT_MAX) TYERR("out of range");
134   *p = u;
135   return (1);
136 end:
137   return (0);
138 }
139
140 int convmpw(PyObject *o, void *pp)
141 {
142   unsigned long u;
143   unsigned *p = pp;
144
145   if (!convulong(o, &u)) goto end;
146   if (u > MPW_MAX) TYERR("out of range");
147   *p = u;
148   return (1);
149 end:
150   return (0);
151 }
152
153 int convszt(PyObject *o, void *pp)
154 {
155   unsigned long u;
156   size_t *p = pp;
157
158   if (!convulong(o, &u)) goto end;
159   if (u > ~(size_t)0) TYERR("out of range");
160   *p = u;
161   return (1);
162 end:
163   return (0);
164 }
165
166 int convbool(PyObject *o, void *pp)
167 {
168   *(int *)pp = PyObject_IsTrue(o);
169   return (1);
170 }
171
172 PyObject *mexp_common(PyObject *me, PyObject *arg,
173                       size_t efsz,
174                       PyObject *(*id)(PyObject *),
175                       int (*fill)(void *, PyObject *,
176                                   PyObject *, PyObject *),
177                       PyObject *(*exp)(PyObject *, void *, int),
178                       void (*drop)(void *))
179 {
180   int i = 0, j, n, flat;
181   PyObject *qq, *x, *y, *z = 0;
182   char *v = 0, *vv;
183
184   if (PyTuple_Size(arg) == 1)
185     arg = PyTuple_GetItem(arg, 0);
186   Py_INCREF(arg);
187   if (!PySequence_Check(arg)) TYERR("not a sequence");
188   n = PySequence_Size(arg); if (!n) { z = id(me); goto end; }
189   x = PySequence_GetItem(arg, 0);
190   if (PySequence_Check(x))
191     flat = 0;
192   else {
193     if (n % 2) VALERR("must have even number of arguments");
194     n /= 2;
195     flat = 1;
196   }
197   Py_DECREF(x);
198
199   v = xmalloc(n * efsz);
200   for (i = j = 0, vv = v; i < n; i++, vv += efsz) {
201     if (flat) {
202       x = PySequence_GetItem(arg, j++);
203       y = PySequence_GetItem(arg, j++);
204     } else {
205       qq = PySequence_GetItem(arg, j++);
206       if (!qq) goto end;
207       if (!PySequence_Check(qq) || PySequence_Size(qq) != 2) {
208         Py_DECREF(qq);
209         TYERR("want a sequence of pairs");
210       }
211       x = PySequence_GetItem(qq, 0);
212       y = PySequence_GetItem(qq, 1);
213       Py_DECREF(qq);
214     }
215     if (!x || !y) goto end;
216     if (fill(vv, me, x, y)) {
217       Py_DECREF(x);
218       Py_DECREF(y);
219       if (!PyErr_Occurred())
220         PyErr_SetString(PyExc_TypeError, "type mismatch");
221       goto end;
222     }
223     Py_DECREF(x);
224     Py_DECREF(y);
225   }
226   z = exp(me, v, n);
227
228 end:
229   if (v) {
230     for (j = 0, vv = v; j < i; j++, vv += efsz)
231       drop(vv);
232     xfree(v);
233   }
234   Py_DECREF(arg);
235   return (z);
236 }
237
238 PyObject * mkexc(PyObject *mod, PyObject *base,
239                  const char *name, PyMethodDef *mm)
240 {
241   PyObject *nameobj = 0;
242   PyObject *dict = 0;
243   PyObject *exc = 0;
244   PyObject *func = 0;
245   PyObject *meth = 0;
246
247   if ((nameobj = PyString_FromFormat("%s.%s",
248                                      PyModule_GetName(mod),
249                                      name)) == 0 ||
250       (dict = PyDict_New()) == 0 ||
251       (exc = PyErr_NewException(PyString_AS_STRING(nameobj),
252                                 base, dict)) == 0)
253     goto fail;
254
255   if (mm) {
256     while (mm->ml_name) {
257       if ((func = PyCFunction_NewEx(mm, 0, mod)) == 0 ||
258           (meth = PyMethod_New(func, 0, exc)) == 0 ||
259           PyDict_SetItemString(dict, mm->ml_name, meth))
260         goto fail;
261       Py_DECREF(func); func = 0;
262       Py_DECREF(meth); meth = 0;
263       mm++;
264     }
265   }
266
267 done:
268   Py_XDECREF(nameobj);
269   Py_XDECREF(dict);
270   return (exc);
271
272 fail:
273   Py_XDECREF(exc);
274   Py_XDECREF(func);
275   Py_XDECREF(meth);
276   exc = 0;
277   goto done;
278 }
279
280 DA_DECL(method_v, PyMethodDef);
281 static method_v global_pymethods = DA_INIT;
282 void addmethods(const PyMethodDef *m)
283 {
284   size_t n;
285
286   for (n = 0; m[n].ml_name; n++);
287   DA_ENSURE(&global_pymethods, n);
288   memcpy(DA(&global_pymethods) + DA_LEN(&global_pymethods),
289          m, n * sizeof(*m));
290   DA_EXTEND(&global_pymethods, n);
291 }
292
293 static const PyTypeObject emptytype = { 0 };
294
295 void *newtype(PyTypeObject *metaty,
296               const PyTypeObject *skel,
297               const char *name)
298 {
299   PyHeapTypeObject *ty =
300     (PyHeapTypeObject *)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty, 0));
301   if (!skel) skel = &emptytype;
302   memcpy(ty, skel, sizeof(*skel));
303   if (ty->type.tp_base) Py_INCREF(ty->type.tp_base);
304 #define COPY(blah) do {                                                 \
305     if (ty->type.tp_as_##blah) {                                        \
306       memcpy(&ty->as_##blah,                                            \
307              ty->type.tp_as_##blah,                                     \
308              sizeof(ty->as_##blah));                                    \
309       ty->type.tp_as_##blah = &ty->as_##blah;                           \
310     }                                                                   \
311   } while (0)
312   COPY(number);
313   COPY(sequence);
314   COPY(mapping);
315   COPY(buffer);
316 #undef COPY
317   if (name)
318     ty->name = PyString_FromString(name);
319   else if (ty->type.tp_name)
320     ty->name = PyString_FromString(ty->type.tp_name);
321   if (ty->name)
322     ty->type.tp_name = PyString_AS_STRING(ty->name);
323   PyObject_INIT(&ty->type, metaty);
324   Py_INCREF(metaty);
325   return (ty);
326 }
327
328 static PyObject *smallprimes(void)
329 {
330   PyObject *v = PyList_New(NPRIME);
331   int i;
332
333   for (i = 0; i < NPRIME; i++)
334     PyList_SetItem(v, i, PyInt_FromLong(primetab[i]));
335   return (v);
336 }
337
338 PyTypeObject *inittype(PyTypeObject *tyskel)
339 {
340   PyTypeObject *ty = newtype(&PyType_Type, tyskel, 0);
341   ty->tp_flags |= Py_TPFLAGS_HEAPTYPE;
342   PyType_Ready(ty);
343   return (ty);
344 }
345
346 static PyObject *meth__ego(PyObject *me, PyObject *arg)
347 {
348   char *argv0;
349   if (!PyArg_ParseTuple(arg, "s:_ego", &argv0))
350     return (0);
351   if (strcmp(QUIS, "<UNNAMED>") == 0)
352     ego(argv0);
353   RETURN_NONE;
354 }
355
356 static PyMethodDef methods[] = {
357 #define METHNAME(func) meth_##func
358   METH  (_ego,                  "_ego(ARGV0)")
359 #undef METHNAME
360   { 0 }
361 };
362
363 void init_base(void) {
364   static const PyMethodDef mzero = { 0 };
365   PyObject *mod;
366   addmethods(methods);
367   INIT_MODULES;
368   DA_PUSH(&global_pymethods, mzero);
369   mod = Py_InitModule("catacomb._base", DA(&global_pymethods));
370   INSERT_MODULES;
371   INSERT("smallprimes", smallprimes());
372   setconstants(mod);
373 }
374
375 /*----- That's all, folks -------------------------------------------------*/