--- /dev/null
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+ (append
+ '((author . "Straylight/Edgeware")
+ (licence-text . "[[gpl]]")
+ (full-title . "the Python interface to mLib")
+ (program . "mLib/Python"))
+ skel-alist))
--- /dev/null
+include atom.pyx crc32.pyx report.pyx select.pyx sym.pyx unihash.pyx
+include codec.pyx.in grim.h atom.h atom-base.c array.c Makefile
+include debian/rules debian/control debian/changelog debian/copyright
--- /dev/null
+## Makefile
+
+PYTHON = python
+prefix = /usr/local
+
+AUTOC = \
+ select.c crc32.c atom.c report.c sym.c unihash.c \
+ base64.c base32.c hex.c
+
+GEN = base64.pyx base32.pyx hex.pyx
+
+all: setup.py
+ $(PYTHON) setup.py build
+
+clean: setup.py
+ $(PYTHON) setup.py clean
+ rm -rf build
+ rm -f $(AUTOC) $(GEN) MANIFEST
+
+dist: setup.py
+ $(PYTHON) setup.py sdist
+
+install: setup.py
+ $(PYTHON) setup.py install --prefix $(prefix)
+
+.PHONY: all clean dist install
--- /dev/null
+Nothing much to say
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Double-ended arrays
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to mLib.
+ *
+ * mLib/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mLib/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mLib/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <Python.h>
+
+#include <string.h>
+
+#include <mLib/darray.h>
+#include <mLib/dstr.h>
+#include <mLib/exc.h>
+
+#include "grim.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+DA_DECL(obj_v, PyObject *);
+
+typedef struct da_pyobj {
+ PyObject_HEAD
+ obj_v v;
+} da_pyobj;
+#define DA_PYCHECK(o) PyObject_TypeCheck((o), &da_pytype)
+#define DA_V(o) (&((da_pyobj *)(o))->v)
+
+typedef struct daiter_pyobj {
+ PyObject_HEAD
+ PyObject *da;
+ size_t i;
+} daiter_pyobj;
+#define DAITER_DA(obj) (((daiter_pyobj *)(obj))->da)
+#define DAITER_V(obj) DA_V(DAITER_DA(obj))
+#define DAITER_I(obj) (((daiter_pyobj *)(obj))->i)
+
+static PyTypeObject da_pytype, daiter_pytype;
+
+static int getseq(PyObject **pseq, PyObject ***v, size_t *n)
+{
+ PyObject *seq = *pseq;
+
+ if (!seq || seq == Py_None) {
+ *v = 0;
+ *n = 0;
+ *pseq = 0;
+ } else if (DA_PYCHECK(seq)) {
+ *v = DA(DA_V(seq));
+ *n = DA_LEN(DA_V(seq));
+ Py_INCREF(seq);
+ } else if ((seq = PySequence_Fast(seq, "expected iterable")) == 0)
+ return (-1);
+ else {
+ *pseq = seq;
+ *v = PySequence_Fast_ITEMS(seq);
+ *n = PySequence_Fast_GET_SIZE(seq);
+ }
+ return (0);
+}
+
+static void range_inc(PyObject **v, PyObject **vl)
+ { while (v < vl) { Py_INCREF(*v); v++; } }
+static void range_dec(PyObject **v, PyObject **vl)
+ { if (v) { while (v < vl) { Py_DECREF(*v); v++; } } }
+static void range_copy(PyObject ***gv, PyObject ***gvl)
+{
+ size_t n = *gvl - *gv;
+ size_t sz = sizeof(PyObject *) * n;
+ PyObject **v;
+ if (!n) { *gv = *gvl = 0; return; }
+ v = xmalloc(sz);
+ memcpy(v, *gv, sz);
+ *gv = v;
+ *gvl = v + n;
+}
+
+static PyObject *abstract_pynew(PyTypeObject *ty,
+ PyObject *hunoz, PyObject *hukairz)
+{
+ PyErr_SetString(PyExc_TypeError, "can't instantiate this type");
+ return (0);
+}
+
+/*----- Iterator ----------------------------------------------------------*/
+
+static PyObject *daiter_pynext(PyObject *me)
+{
+ PyObject *x;
+
+ if (DAITER_I(me) >= DA_LEN(DAITER_V(me))) return (0);
+ x = DA(DAITER_V(me))[DAITER_I(me)]; DAITER_I(me)++; RETURN_OBJ(x);
+}
+
+static void daiter_pydealloc(PyObject *me)
+ { Py_DECREF(DAITER_DA(me)); PyObject_DEL(me); }
+
+static PyTypeObject daiter_pytype = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "array.ArrayIter", /* @tp_name@ */
+ sizeof(daiter_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ daiter_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @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@ */
+"Array iterator.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ PyObject_SelfIter, /* @tp_iter@ */
+ daiter_pynext, /* @tp_iternexr@ */
+ 0, /* @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@ */
+};
+
+/*----- Main array code ---------------------------------------------------*/
+
+static void da_doinsert(PyObject *me, PyObject **items, size_t n,
+ size_t start, size_t end)
+{
+ PyObject **v, **gv, **gvl;
+ obj_v *da = DA_V(me);
+ size_t off, ne;
+
+ ne = end - start;
+ v = DA(da);
+ gv = v + start; gvl = v + end; range_copy(&gv, &gvl);
+ if (start < DA_LEN(da) - end) {
+ if (n > ne) {
+ off = n - ne;
+ DA_SHUNT(da, off);
+ DA_UNSAFE_SLIDE(da, off);
+ memmove(v, v + off, sizeof(PyObject *) * start);
+ } else {
+ off = ne - n;
+ memmove(v + off, v, sizeof(PyObject *) * start);
+ DA_UNSAFE_UNSLIDE(da, off);
+ }
+ } else {
+ if (n > ne) {
+ off = n - ne;
+ DA_ENSURE(da, off);
+ memmove(v + end + off, v + end,
+ sizeof(PyObject *) * (DA_LEN(da) - end));
+ } else {
+ off = ne - n;
+ memmove(v + end - off, v + end,
+ sizeof(PyObject *) * (DA_LEN(da) - end));
+ DA_UNSAFE_SHRINK(da, off);
+ }
+ DA_UNSAFE_EXTEND(da, off);
+ }
+
+ if (n) {
+ v = DA(da) + start;
+ memcpy(v, items, sizeof(PyObject *) * n);
+ range_inc(v, v + n);
+ }
+ if (gv) {
+ range_dec(gv, gvl);
+ xfree(gv);
+ }
+}
+
+static int da_insert(PyObject *me, PyObject *seq, int start, int end)
+{
+ PyObject **items;
+ size_t n;
+
+ if (0 > start || start > end || end > DA_LEN(DA_V(me))) {
+ PyErr_SetString(PyExc_IndexError, "bad slice");
+ return (-1);
+ }
+ if (getseq(&seq, &items, &n)) return (-1);
+ da_doinsert(me, items, n, start, end);
+ Py_XDECREF(seq);
+ return (0);
+}
+
+static PyObject *da_new(PyTypeObject *ty)
+{
+ da_pyobj *me = (da_pyobj *)ty->tp_alloc(ty, 0);
+ DA_CREATE(&me->v);
+ return ((PyObject *)me);
+}
+
+static PyObject *da_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+ { return (da_new(ty)); }
+static int da_pyinit(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ PyObject *init = 0;
+ static char *kwlist[] = { "sequence", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &init) ||
+ (init && da_insert((PyObject *)me, init, 0, 0)))
+ return (-1);
+ return (0);
+}
+
+static void da_pydealloc(PyObject *me)
+{
+ size_t i;
+ PyObject **v = DA(DA_V(me));
+ size_t n = DA_LEN(DA_V(me));
+
+ for (i = 0; i < n; i++) Py_DECREF(v[i]);
+ DA_DESTROY(DA_V(me));
+}
+
+static int da_pylength(PyObject *me)
+ { return (DA_LEN(DA_V(me))); }
+
+static int da_pytraverse(PyObject *me, visitproc proc, void *arg)
+{
+ size_t i;
+ PyObject **v = DA(DA_V(me));
+ size_t n = DA_LEN(DA_V(me));
+ int err;
+
+ for (i = 0; i < n; i++) {
+ if ((err = proc(v[i], arg)) != 0)
+ return (err);
+ }
+ return (0);
+}
+
+static int da_pyclear(PyObject *me)
+{
+ range_dec(DA(DA_V(me)), DA(DA_V(me)) + DA_LEN(DA_V(me)));
+ DA_RESET(DA_V(me));
+ return (0);
+}
+
+static PyObject *da_pyconcat(PyObject *me, PyObject *other)
+{
+ PyObject *x = da_new(&da_pytype);
+ PyObject **items = DA(DA_V(me));
+ size_t n = DA_LEN(DA_V(me));
+
+ da_doinsert(x, items, n, 0, 0);
+ if (da_insert(x, other, n, n)) {
+ Py_DECREF(x);
+ return (0);
+ }
+ return (x);
+}
+
+static PyObject *da_pyrepeat(PyObject *me, int times)
+{
+ PyObject *x = da_new(&da_pytype);
+ PyObject **items = DA(DA_V(me)), **dest;
+ size_t n = DA_LEN(DA_V(me));
+ int i;
+
+ DA_ENSURE(DA_V(x), n * times);
+ DA_UNSAFE_EXTEND(DA_V(x), n * times);
+ for (i = 0, dest = DA(DA_V(x)); i < times; i++, dest += n)
+ memcpy(dest, items, n * sizeof(PyObject *));
+ range_inc(DA(DA_V(x)), DA(DA_V(x)) + n * times);
+ return (x);
+}
+
+static PyObject *da_pygetitem(PyObject *me, int i)
+{
+ PyObject *o;
+
+ if (i < 0 || i >= DA_LEN(DA_V(me))) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return (0);
+ }
+ o = DA(DA_V(me))[i];
+ Py_INCREF(o);
+ return (o);
+}
+
+static PyObject *da_pygetslice(PyObject *me, int i, int j)
+{
+ PyObject *x;
+
+ if (i < 0 || j < i || DA_LEN(DA_V(me)) < j) {
+ PyErr_SetString(PyExc_IndexError, "bad slice");
+ return (0);
+ }
+ x = da_new(&da_pytype);
+ da_doinsert(x, DA(DA_V(me)) + i, j - i, 0, 0);
+ return (x);
+}
+
+static int da_pyputitem(PyObject *me, int i, PyObject *x)
+{
+ PyObject **p;
+
+ if (i < 0 || i >= DA_LEN(DA_V(me))) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return (-1);
+ }
+ p = DA(DA_V(me)) + i;
+ Py_DECREF(*p);
+ *p = x;
+ Py_INCREF(*p);
+ return (0);
+}
+
+static int da_pyputslice(PyObject *me, int i, int j, PyObject *x)
+ { return (da_insert(me, x, i, j)); }
+
+static int da_pycontainsp(PyObject *me, PyObject *x)
+{
+ PyObject **items = DA(DA_V(me));
+ size_t n = DA_LEN(DA_V(me));
+ size_t i;
+ int rc;
+
+ for (i = 0; i < n; i++) {
+ if (PyObject_Cmp(items[i], x, &rc))
+ return (-1);
+ if (rc)
+ return (1);
+ }
+ return (0);
+}
+
+static PyObject *da_pyrepr(PyObject *me)
+{
+ dstr d = DSTR_INIT;
+ PyObject *s, *rc = 0;
+ char *p;
+ int n;
+ size_t i;
+
+ dstr_puts(&d, "Array([");
+ for (i = 0; i < DA_LEN(DA_V(me)); i++) {
+ if ((s = PyObject_Repr(DA(DA_V(me))[i])) == 0 ||
+ PyString_AsStringAndSize(s, &p, &n)) {
+ Py_XDECREF(s);
+ goto done;
+ }
+ if (i) dstr_puts(&d, ", ");
+ dstr_putm(&d, p, n);
+ Py_DECREF(s);
+ }
+ dstr_puts(&d, "])");
+ rc = PyString_FromStringAndSize(d.buf, d.len);
+done:
+ dstr_destroy(&d);
+ return (rc);
+}
+
+static PyObject *da_pyappend(PyObject *me, PyObject *seq)
+{
+ size_t n = DA_LEN(DA_V(me));
+ if (da_insert(me, seq, n, n)) return (0);
+ RETURN_ME;
+}
+
+static PyObject *da_pyiprepeat(PyObject *me, int times)
+{
+ PyObject **items, **dest;
+ size_t n = DA_LEN(DA_V(me));
+ int i;
+
+ if (times < 0) {
+ PyErr_SetString(PyExc_ValueError, "multiplier must be nonnegative");
+ return (0);
+ }
+ if (!times) {
+ items = DA(DA_V(me));
+ range_dec(items, items + n);
+ DA_RESET(DA_V(me));
+ RETURN_ME;
+ }
+ times--;
+ DA_ENSURE(DA_V(me), n * times);
+ items = DA(DA_V(me));
+ for (i = 0, dest = items + n; i < times; i++, dest += n)
+ memcpy(dest, items, n * sizeof(PyObject *));
+ range_inc(items + n, dest);
+ DA_UNSAFE_EXTEND(DA_V(me), n * times);
+ RETURN_ME;
+}
+
+static PyObject *da_pyget(PyObject *me, PyObject *index)
+{
+ if (PySlice_Check(index)) {
+ int start, stop, step, len;
+ PyObject *v;
+ PyObject **ww;
+ PyObject **vv;
+
+ if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
+ &start, &stop, &step, &len))
+ return (0);
+ if (step == 1) return (da_pygetslice(me, start, stop));
+ v = da_new(&da_pytype);
+ DA_ENSURE(DA_V(v), len);
+ vv = DA(DA_V(v));
+ ww = DA(DA_V(me)) + start;
+ DA_UNSAFE_EXTEND(DA_V(v), len);
+ while (len) {
+ *vv = *ww;
+ Py_INCREF(*vv);
+ vv++; ww += step; len--;
+ }
+ return ((PyObject *)v);
+ } else {
+ int i;
+
+ if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (0);
+ return (da_pygetitem(me, i));
+ }
+}
+
+static int da_pyput(PyObject *me, PyObject *index, PyObject *x)
+{
+ if (PySlice_Check(index)) {
+ int start, stop, step, len;
+ size_t n;
+ PyObject **ww;
+ PyObject **vv;
+ PyObject **g, **gg;
+
+ if (PySlice_GetIndicesEx((PySliceObject *)index, DA_LEN(DA_V(me)),
+ &start, &stop, &step, &len))
+ return (-1);
+ if (step == 1) return (da_insert(me, x, start, stop));
+ if (getseq(&x, &vv, &n)) return (-1);
+ if (n != len) {
+ PyErr_SetString(PyExc_ValueError, "wrong number of items");
+ Py_XDECREF(x);
+ return (-1);
+ }
+ g = gg = xmalloc(len * sizeof(PyObject *));
+ ww = DA(DA_V(me)) + start;
+ while (len) {
+ *gg++ = *ww; *ww = *vv++;
+ Py_INCREF(*ww);
+ ww += step; len--;
+ }
+ range_dec(g, gg);
+ xfree(g);
+ Py_XDECREF(x);
+ return (0);
+ } else {
+ int i;
+
+ if ((i = PyInt_AsLong(index)) == -1 && PyErr_Occurred()) return (-1);
+ return (da_pyputitem(me, i, x));
+ }
+}
+
+static PyObject *da_pyiter(PyObject *me)
+{
+ daiter_pyobj *i = PyObject_NEW(daiter_pyobj, &daiter_pytype);
+ i->da = me; Py_INCREF(me);
+ i->i = 0;
+ return ((PyObject *)i);
+}
+
+static PyObject *dameth_push(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+
+ if (!PyArg_ParseTuple(arg, "O:push", &x)) return (0);
+ Py_INCREF(x);
+ DA_PUSH(DA_V(me), x);
+ RETURN_ME;
+}
+
+static PyObject *dameth_pop(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+
+ if (!PyArg_ParseTuple(arg, ":pop")) return (0);
+ TRY
+ x = DA_POP(DA_V(me));
+ CATCH switch (exc_type) {
+ case DAEXC_UFLOW:
+ PyErr_SetString(PyExc_ValueError, "stack underflow");
+ return (0);
+ default:
+ RETHROW;
+ } END_TRY;
+ RETURN_OBJ(x);
+}
+
+static PyObject *dameth_unshift(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+
+ if (!PyArg_ParseTuple(arg, "O:unshift", &x)) return (0);
+ Py_INCREF(x);
+ DA_UNSHIFT(DA_V(me), x);
+ RETURN_ME;
+}
+
+static PyObject *dameth_shift(PyObject *me, PyObject *arg)
+{
+ PyObject *x;
+
+ if (!PyArg_ParseTuple(arg, ":shift")) return (0);
+ TRY
+ x = DA_SHIFT(DA_V(me));
+ CATCH switch (exc_type) {
+ case DAEXC_UFLOW:
+ PyErr_SetString(PyExc_ValueError, "stack underflow");
+ return (0);
+ default:
+ RETHROW;
+ } END_TRY;
+ RETURN_OBJ(x);
+}
+
+static PyObject *dameth_tidy(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":tidy")) return (0);
+ DA_TIDY(DA_V(me));
+ RETURN_ME;
+}
+
+static PyMethodDef da_pymethods[] = {
+#define METHNAME(func) dameth_##func
+ METH (push, "A.push(X): [A, B, ..., W], X -> [A, B, ..., W, X]")
+ METH (pop, "A.pop() -> X: [A, B, ..., W, X] -> [A, B, ..., W]")
+ METH (unshift, "A.unshift(X): [A, B, ..., W], X -> [X, A, ..., W]")
+ METH (shift, "A.shift() -> X: [X, A, ..., W] -> [A, ..., W], X")
+ METH (tidy, "A.tidy()")
+#undef METHNAME
+ { 0 }
+};
+
+static PySequenceMethods da_pysequence = {
+ da_pylength, /* @sq_length@ */
+ da_pyconcat, /* @sq_concat@ */
+ da_pyrepeat, /* @sq_repeat@ */
+ da_pygetitem, /* @sq_item@ */
+ da_pygetslice, /* @sq_slice@ */
+ da_pyputitem, /* @sq_ass_item@ */
+ da_pyputslice, /* @sq_ass_slice@ */
+ da_pycontainsp, /* @sq_contains@ */
+ da_pyappend, /* @sq_inplace_concat@ */
+ da_pyiprepeat /* @sq_inplace_repeat@ */
+};
+
+static PyMappingMethods da_pymapping = {
+ da_pylength, /* @mp_length@ */
+ da_pyget, /* @mp_subscript@ */
+ da_pyput /* @mp_ass_subscript@ */
+};
+
+static PyTypeObject da_pytype = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "array.Array", /* @tp_name@ */
+ sizeof(da_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ da_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ da_pyrepr, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ &da_pysequence, /* @tp_as_sequence@ */
+ &da_pymapping, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ &da_pyrepr, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_HAVE_GC,
+
+ /* @tp_doc@ */
+"Double-ended array type.",
+
+ da_pytraverse, /* @tp_traverse@ */
+ da_pyclear, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ da_pyiter, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ da_pymethods, /* @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@ */
+ da_pyinit, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ da_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+/*----- Initialization ----------------------------------------------------*/
+
+static PyMethodDef emptymethods[] = { { 0 } };
+
+void initarray(void)
+{
+ PyObject *mod = Py_InitModule("array", emptymethods);
+ PyType_Ready(&da_pytype); PyType_Ready(&daiter_pytype);
+ PyModule_AddObject(mod, "Array", (PyObject *)&da_pytype);
+ PyModule_AddObject(mod, "ArrayIter", (PyObject *)&daiter_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Atom stuff
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to mLib.
+ *
+ * mLib/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mLib/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mLib/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <Python.h>
+
+#include <mLib/atom.h>
+#include <mLib/assoc.h>
+#include <mLib/dstr.h>
+
+#include "atom.h"
+#include "grim.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+static PyTypeObject atom_pytype;
+
+typedef struct entry {
+ assoc_base _b;
+ PyObject *a;
+} entry;
+
+/*----- Static variables --------------------------------------------------*/
+
+static assoc_table obarray;
+
+/*----- Main code ---------------------------------------------------------*/
+
+PyObject *atom_pywrap(atom *a)
+{
+ entry *e;
+ unsigned f = 0;
+
+ e = assoc_find(&obarray, a, sizeof(entry), &f);
+ if (!f) {
+ atom_pyobj *ao = PyObject_NEW(atom_pyobj, &atom_pytype);
+ ao->a = a;
+ e->a = (PyObject *)ao;
+ }
+ RETURN_OBJ(e->a);
+}
+
+PyObject *atom_pyintern(PyObject *x)
+{
+ atom *a;
+ const void *p;
+ int n;
+
+ if (ATOM_PYCHECK(x))
+ RETURN_OBJ(x);
+ if (x == Py_None)
+ a = atom_gensym(ATOM_GLOBAL);
+ else {
+ if (PyObject_AsReadBuffer(x, &p, &n)) return (0);
+ a = atom_nintern(ATOM_GLOBAL, p, n);
+ }
+ return (atom_pywrap(a));
+}
+
+static void atom_pydealloc(PyObject *me)
+ { fprintf(stderr, "ouch! freeing atom\n"); abort(); }
+
+static PyObject *atom_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ PyObject *name;
+ static char *kwlist[] = { "name", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &name))
+ return (0);
+ return (atom_pyintern(name));
+}
+
+static PyObject *aget_name(PyObject *me, void *hunoz)
+{
+ return (PyString_FromStringAndSize(ATOM_NAME(ATOM_A(me)),
+ ATOM_LEN(ATOM_A(me))));
+}
+
+static PyObject *aget_internedp(PyObject *me, void *hunoz)
+{
+ PyObject *rc = (ATOM_A(me)->f & ATOMF_GENSYM) ? Py_False : Py_True;
+ RETURN_OBJ(rc);
+}
+
+static PyGetSetDef atom_pygetset[] = {
+#define GETSETNAME(op, name) a##op##_##name
+ GET (name, "A.name -> NAME")
+ GET (internedp, "A.internedp -> BOOL")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *atom_pyrichcompare(PyObject *x, PyObject *y, int op)
+{
+ PyObject *rc = 0;
+
+ switch (op) {
+ case Py_EQ: rc = (x == y) ? Py_True : Py_False; break;
+ case Py_NE: rc = (x != y) ? Py_True : Py_False; break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "atoms are unordered");
+ return (0);
+ }
+ RETURN_OBJ(rc);
+}
+
+static PyObject *atom_pyrepr(PyObject *me)
+{
+ PyObject *s, *sr = 0;
+ PyObject *rc = 0;
+ char *p;
+ int n;
+ dstr d = DSTR_INIT;
+
+ if ((s = aget_name(me, 0)) == 0 ||
+ (sr = PyObject_Repr(s)) == 0 ||
+ PyString_AsStringAndSize(sr, &p, &n))
+ goto done;
+ dstr_puts(&d, "Atom(");
+ dstr_putm(&d, p, n);
+ dstr_puts(&d, ")");
+ rc = PyString_FromStringAndSize(d.buf, d.len);
+done:
+ Py_XDECREF(s);
+ Py_XDECREF(sr);
+ dstr_destroy(&d);
+ return (rc);
+}
+
+static long atom_pyhash(PyObject *me)
+ { long h = ATOM_HASH(ATOM_A(me)); if (h == -1) h = -2; return (h); }
+
+static PyTypeObject atom_pytype = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "atom.Atom", /* @tp_name@ */
+ sizeof(atom_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ atom_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ atom_pyrepr, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ atom_pyhash, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ atom_pyrepr, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT, /* @tp_flags@ */
+
+ /* @tp_doc@ */
+"Atom.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ atom_pyrichcompare, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternexr@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ atom_pygetset, /* @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@ */
+ atom_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+PyObject *atom_pystartup(void)
+{
+ assoc_create(&obarray);
+ PyType_Ready(&atom_pytype);
+ return ((PyObject *)&atom_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Atom stuff
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to mLib.
+ *
+ * mLib/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mLib/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mLib/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ATOM_H
+#define ATOM_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <Python.h>
+
+#include <mLib/atom.h>
+#include <mLib/assoc.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct atom_pyobj {
+ PyObject_HEAD
+ atom *a;
+} atom_pyobj;
+#define ATOM_PYCHECK(obj) PyObject_TypeCheck(obj, &atom_pytype)
+#define ATOM_A(obj) (((atom_pyobj *)(obj))->a)
+
+/*----- Functions provided ------------------------------------------------*/
+
+extern PyObject *atom_pywrap(atom *);
+extern PyObject *atom_pyintern(PyObject *);
+extern PyObject *atom_pystartup(void);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Atom tables
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+cdef extern from 'atom.h':
+ ctypedef struct atom:
+ pass
+ ctypedef struct atom_iter:
+ pass
+ ctypedef struct atom_table:
+ pass
+ atom_table *ATOM_GLOBAL
+ void atom_mkiter(atom_iter *i, atom_table *t)
+ atom *atom_next(atom_iter *)
+ atom_pystartup()
+ atom_pywrap(atom *a)
+ atom_pyintern(obj)
+ atom *ATOM_A(obj)
+
+cdef extern from 'mLib/assoc.h':
+ ctypedef struct assoc_table:
+ pass
+ ctypedef struct assoc_base:
+ pass
+ ctypedef struct assoc_iter:
+ pass
+ void assoc_create(assoc_table *t)
+ void assoc_destroy(assoc_table *t)
+ void *assoc_find(assoc_table *t, atom *a, int sz, unsigned *f)
+ void assoc_remove(assoc_table *t, void *b)
+ atom *ASSOC_ATOM(void *b)
+ void assoc_mkiter(assoc_iter *i, assoc_table *t)
+ void *assoc_next(assoc_iter *i)
+
+cdef extern from 'grim.h':
+ int PSIZEOF(void *p)
+
+cdef extern from 'Python.h':
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ PyString_FromStringAndSize(char *p, int n)
+ ctypedef struct PyObject:
+ pass
+ void Py_INCREF(PyObject *obj)
+ void Py_DECREF(PyObject *obj)
+
+cdef class AtomIter:
+ cdef atom_iter _i
+ def __new__(me):
+ atom_mkiter(&me._i, ATOM_GLOBAL)
+ def __next__(me):
+ cdef atom *a
+ a = atom_next(&me._i)
+ if not a:
+ raise StopIteration
+ return atom_pywrap(a)
+ def __iter__(me):
+ return me
+
+def atoms():
+ return AtomIter()
+
+cdef struct entry:
+ assoc_base _b
+ PyObject *v
+
+cdef entry *_find(assoc_table *t, object key, unsigned *f) except ?NULL:
+ cdef void *p
+ cdef int n
+ cdef entry *e
+ cdef atom *a
+ a = ATOM_A(atom_pyintern(key))
+ if f:
+ f[0] = 0
+ e = <entry *>assoc_find(t, a, PSIZEOF(e), f)
+ if not f[0]:
+ e.v = NULL
+ else:
+ e = <entry *>assoc_find(t, a, 0, NULL)
+ return e
+
+cdef _key(entry *e):
+ return atom_pywrap(ASSOC_ATOM(<void *>e))
+
+cdef _eget(entry *e):
+ Py_INCREF(e.v)
+ return <object>e.v
+
+cdef void _eset(entry *e, v):
+ if e.v:
+ Py_DECREF(e.v)
+ e.v = <PyObject *>v
+ Py_INCREF(e.v)
+
+cdef void _edel(assoc_table *t, entry *e):
+ if e.v:
+ Py_DECREF(e.v)
+ assoc_remove(t, <void *>e)
+
+cdef class Table:
+ cdef assoc_table _t
+ def __new__(me, *hunoz, **hukairz):
+ assoc_create(&me._t)
+ def __init__(me, stuff = None, **kw):
+ me.update(stuff, **kw)
+ def __getitem__(me, key):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ raise KeyError, key
+ return _eget(e)
+ def __setitem__(me, key, value):
+ cdef unsigned f
+ _eset(_find(&me._t, key, &f), value)
+ def __delitem__(me, key):
+ cdef entry *e
+ cdef unsigned f
+ e = _find(&me._t, key, &f)
+ if not e:
+ raise KeyError, key
+ _edel(&me._t, e)
+ def get(me, key, default = None):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ return default
+ return _eget(e)
+ def setdefault(me, key, default = None):
+ cdef entry *e
+ cdef unsigned f
+ e = _find(&me._t, key, &f)
+ if f:
+ return _eget(e)
+ else:
+ _eset(e, default)
+ return default
+ def pop(me, key, default = None):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ return default
+ rc = _eget(e)
+ _edel(&me._t, e)
+ return rc
+ def popitem(me):
+ cdef entry *e
+ cdef assoc_iter i
+ assoc_mkiter(&i, &me._t)
+ e = <entry *>assoc_next(&i)
+ if not e:
+ raise ValueError, 'popitem(): table is empty'
+ return _key(e), _eget(e)
+ def keys(me):
+ cdef assoc_iter i
+ cdef entry *e
+ l = []
+ assoc_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>assoc_next(&i)
+ if not e:
+ break
+ l.append(_key(e))
+ return l
+ def values(me):
+ cdef assoc_iter i
+ cdef entry *e
+ l = []
+ assoc_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>assoc_next(&i)
+ if not e:
+ break
+ l.append(_eget(e))
+ return l
+ def items(me):
+ cdef assoc_iter i
+ cdef entry *e
+ l = []
+ assoc_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>assoc_next(&i)
+ if not e:
+ break
+ l.append((_key(e), _eget(e)))
+ return l
+ def clear(me):
+ cdef assoc_iter i
+ cdef entry *e
+ assoc_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>assoc_next(&i)
+ if not e:
+ break
+ _edel(&me._t, e)
+ return me
+ def __dealloc__(me):
+ cdef assoc_iter i
+ cdef entry *e
+ assoc_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>assoc_next(&i)
+ if not e:
+ break
+ _edel(&me._t, e)
+ assoc_destroy(&me._t)
+ def iterkeys(me):
+ return KeyIter(me)
+ def __iter__(me):
+ return KeyIter(me)
+ def itervalues(me):
+ return ValueIter(me)
+ def iteritems(me):
+ return ItemIter(me)
+ def update(me, stuff = None, **kw):
+ if stuff is None:
+ pass
+ elif hasattr(stuff, 'keys'):
+ for k in stuff:
+ me[k] = stuff[k]
+ else:
+ for k, v in stuff:
+ me[k] = v
+ for k, v in kw.iteritems():
+ me[k] = kw[k]
+ return me
+
+cdef class KeyIter:
+ cdef Table _t
+ cdef assoc_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ assoc_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>assoc_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _key(e)
+
+cdef class ValueIter:
+ cdef Table _t
+ cdef assoc_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ assoc_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>assoc_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _eget(e)
+
+cdef class ItemIter:
+ cdef Table _t
+ cdef assoc_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ assoc_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>assoc_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _key(e), _eget(e)
+
+Atom = atom_pystartup()
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Generic encoder/decoder
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- External dependencies ------------------------------------------------
+
+cdef extern from 'stddef.h':
+ ctypedef int size_t
+
+cdef extern from 'mLib/dstr.h':
+ ctypedef struct dstr:
+ char *buf
+ int len
+ void DCREATE(dstr *d)
+ void dstr_destroy(dstr *d)
+
+cdef extern from 'mLib/alloc.h':
+ char *xstrdup(char *p)
+ void xfree(void *p)
+
+cdef extern from 'mLib/%PREFIX%.h':
+ ctypedef struct %PREFIX%_ctx:
+ char *indent
+ int maxline
+ void %PREFIX%_init(%PREFIX%_ctx *b)
+ void %PREFIX%_encode(%PREFIX%_ctx *b, void *p, size_t sz, dstr *d)
+ void %PREFIX%_decode(%PREFIX%_ctx *b, void *p, size_t sz, dstr *d)
+
+cdef extern from 'Python.h':
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ object PyString_FromStringAndSize(char *p, int len)
+
+cdef class Encode:
+ cdef %PREFIX%_ctx ctx
+ def __new__(me, *hunoz, **hukairz):
+ %PREFIX%_init(&me.ctx)
+ me.ctx.indent = NULL
+ def __init__(me, indent = '\n', maxline = 72):
+ if me.ctx.indent:
+ xfree(me.ctx.indent)
+ me.ctx.indent = xstrdup(indent)
+ me.ctx.maxline = maxline
+ def __dealloc__(me):
+ if me.ctx.indent:
+ xfree(me.ctx.indent)
+ property indent:
+ def __get__(me):
+ return me.ctx.indent
+ def __set__(me, indent):
+ if me.ctx.indent:
+ xfree(me.ctx.indent)
+ me.ctx.indent = xstrdup(indent)
+ property maxline:
+ def __get__(me):
+ return me.ctx.maxline
+ def __set__(me, maxline):
+ me.ctx.maxline = maxline
+ def encode(me, text):
+ cdef void *p
+ cdef int len
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ PyObject_AsReadBuffer(text, &p, &len)
+ %PREFIX%_encode(&me.ctx, p, len, &d)
+ rc = PyString_FromStringAndSize(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ return rc
+ def done(me):
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ %PREFIX%_encode(&me.ctx, NULL, 0, &d)
+ rc = PyString_FromStringAndSize(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ return rc
+
+def encode(text, *arg, **kw):
+ e = Encode(*arg, **kw)
+ return e.encode(text) + e.done()
+
+cdef class Decode:
+ cdef %PREFIX%_ctx ctx
+ def __new__(me, *hunoz, **hukairz):
+ %PREFIX%_init(&me.ctx)
+ me.ctx.indent = NULL
+ def decode(me, text):
+ cdef void *p
+ cdef int len
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ PyObject_AsReadBuffer(text, &p, &len)
+ %PREFIX%_decode(&me.ctx, p, len, &d)
+ rc = PyString_FromStringAndSize(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ return rc
+ def done(me):
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ %PREFIX%_decode(&me.ctx, NULL, 0, &d)
+ rc = PyString_FromStringAndSize(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ return rc
+
+def decode(text, *arg, **kw):
+ d = Decode(*arg, **kw)
+ return e.decode(text) + d.done()
+
+#----- That's all, folks ----------------------------------------------------
+
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Cyclic redundancy checker
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+cdef extern from 'mLib/crc32.h':
+ ctypedef int uint32
+ uint32 c_crc32 "crc32" (uint32 a, void *p, int sz)
+
+cdef extern from 'limits.h':
+ enum:
+ LONG_MAX
+
+cdef extern from 'Python.h':
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ PyInt_FromLong(long i)
+ PyLong_FromUnsignedLong(unsigned long i)
+
+cdef _u32(uint32 x):
+ if x < LONG_MAX:
+ return PyInt_FromLong(x)
+ else:
+ return PyLong_FromUnsignedLong(x)
+
+cdef class CRC32:
+ cdef uint32 _a
+ def __new__(me, *hunoz, **hukairz):
+ me._a = 0
+ def __init__(me):
+ pass
+ def chunk(me, data):
+ cdef void *p
+ cdef int n
+ PyObject_AsReadBuffer(data, &p, &n)
+ me._a = c_crc32(me._a, p, n)
+ return me
+ def done(me):
+ return _u32(me._a)
+
+def crc32(data):
+ cdef void *p
+ cdef int n
+ cdef uint32 c
+ PyObject_AsReadBuffer(data, &p, &n)
+ c = c_crc32(0, p, n)
+ return _u32(c)
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Grim hacks to support the Pyrex code
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Python interface to mLib.
+ *
+ * mLib/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mLib/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mLib/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GRIM_H
+#define GRIM_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <Python.h>
+
+/*----- Functions provided ------------------------------------------------*/
+
+#define PSIZEOF(x) sizeof(*x)
+
+/*----- Utilities ---------------------------------------------------------*/
+
+#define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0)
+#define RETURN_ME RETURN_OBJ(me)
+#define RETURN_NONE RETURN_OBJ(Py_None)
+#define RETURN_NOTIMPL RETURN_OBJ(Py_NotImplemented)
+
+#define METH(func, doc) \
+ { #func, METHNAME(func), METH_VARARGS, doc },
+#define KWMETH(func, doc) \
+ { #func, (PyCFunction)METHNAME(func), \
+ METH_VARARGS | METH_KEYWORDS, doc },
+
+#define GET(func, doc) \
+ { #func, GETSETNAME(get, func), 0, doc },
+#define GETSET(func, doc) \
+ { #func, GETSETNAME(get, func), GETSETNAME(set, func), doc },
+
+#ifndef PySequence_Fast_ITEMS
+# define PySequence_Fast_ITEMS(o) \
+ (PyList_Check(o) ? &PyList_GET_ITEM(o, 0) : &PyTuple_GET_ITEM(o, 0))
+#endif
+
+#define FREEOBJ(obj) \
+ (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj)))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Error reporting and stuff
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+cdef extern from 'mLib/quis.h':
+ void _ego "ego"(char *prog)
+ char *_quis "quis"()
+
+cdef extern from 'mLib/report.h':
+ void _moan "moan"(char *f, char *msg)
+
+import sys
+
+quis = '<UNNAMED>'
+def ego(prog):
+ _ego(prog)
+ quis = _quis()
+
+def moan(msg):
+ _moan('%s', msg)
+def die(msg, rc = 1):
+ _moan('%s', msg)
+ sys.exit(rc)
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Selectery
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- External dependencies ------------------------------------------------
+
+cdef extern from 'stddef.h':
+ ctypedef int size_t
+cdef extern from 'string.h':
+ void memcpy(void *p, void *q, size_t n)
+cdef extern from 'errno.h':
+ int errno
+ enum:
+ EINTR
+ EAGAIN
+cdef extern from 'math.h':
+ double modf(double x, double *i)
+cdef extern from 'string.h':
+ char *strerror(int err)
+cdef extern from 'sys/time.h':
+ struct timeval:
+ int tv_sec
+ int tv_usec
+cdef extern from 'sys/types.h':
+ pass
+cdef extern from 'sys/socket.h':
+ struct sockaddr:
+ int sa_family
+ enum:
+ AF_INET
+ int getsockname(int fd, sockaddr *pa, size_t *psz)
+ int getpeername(int fd, sockaddr *pa, size_t *psz)
+cdef extern from 'arpa/inet.h':
+ struct in_addr:
+ int s_addr
+ int inet_aton(char *rp, in_addr *ia)
+ char *inet_ntoa(in_addr ia)
+cdef extern from 'netinet/in.h':
+ struct sockaddr_in:
+ int sin_family
+ in_addr sin_addr
+ int sin_port
+ int htons(int x)
+ int htonl(int x)
+ int ntohs(int x)
+ int ntohl(int x)
+cdef extern from 'netdb.h':
+ struct hostent:
+ char *h_name
+ char **h_aliases
+ int h_addrtype
+ int h_length
+ char **h_addr_list
+ char *h_addr
+ int h_errno
+
+cdef extern from 'mLib/sel.h':
+ ctypedef struct sel_state:
+ pass
+ ctypedef struct sel_file:
+ int fd
+ ctypedef struct sel_timer:
+ pass
+ enum:
+ SEL_READ
+ SEL_WRITE
+ SEL_EXC
+ void sel_init(sel_state *s)
+ void sel_initfile(sel_state *s, sel_file *f, int fd, unsigned mode,
+ void (*func)(int fd, unsigned mode, void *arg),
+ void *arg)
+ void sel_force(sel_file *f)
+ void sel_addfile(sel_file *f)
+ void sel_rmfile(sel_file *f)
+ void sel_addtimer(sel_state *s, sel_timer *t, timeval *tv,
+ void (*func)(timeval *tv, void *arg),
+ void *arg)
+ void sel_rmtimer(sel_timer *t)
+ int sel_select(sel_state *s) except *
+
+cdef extern from 'mLib/conn.h':
+ ctypedef struct conn:
+ pass
+ int conn_fd(conn *c, sel_state *s, int fd,
+ void (*func)(int fd, void *arg), void *arg)
+ void conn_kill(conn *c)
+
+cdef extern from 'mLib/bres.h':
+ ctypedef struct bres_client:
+ pass
+ void bres_byname(bres_client *r, char *name,
+ void (*func)(hostent *h, void *arg), void *arg)
+ void bres_byaddr(bres_client *r, in_addr addr,
+ void (*func)(hostent *h, void *arg), void *arg)
+ void bres_abort(bres_client *r)
+ void bres_exec(char *null)
+ void bres_init(sel_state *s)
+
+cdef extern from 'mLib/sig.h':
+ ctypedef struct sig:
+ pass
+ void sig_add(sig *s, int n, void (*func)(int n, void *arg), void *arg)
+ void sig_remove(sig *s)
+ void sig_init(sel_state *s)
+
+cdef extern from 'mLib/lbuf.h':
+ cdef struct lbuf:
+ int f
+ int delim
+ size_t sz
+ enum:
+ LBUF_ENABLE
+ LBUF_CRLF
+ LBUF_STRICTCRLF
+
+cdef extern from 'mLib/selbuf.h':
+ ctypedef struct selbuf:
+ sel_file reader
+ lbuf b
+ void selbuf_enable(selbuf *b)
+ void selbuf_disable(selbuf *b)
+ void selbuf_setsize(selbuf *b, size_t sz)
+ void selbuf_init(selbuf *b, sel_state *s, int fd,
+ void (*func)(char *s, size_t len, void *arg), void *arg)
+ void selbuf_destroy(selbuf *b)
+
+cdef extern from 'mLib/pkbuf.h':
+ ctypedef struct pkbuf:
+ int f
+ int want
+ enum:
+ PKBUF_ENABLE
+
+cdef extern from 'mLib/selpk.h':
+ ctypedef struct selpk:
+ sel_file reader
+ pkbuf pk
+ void selpk_enable(selpk *b)
+ void selpk_disable(selpk *b)
+ void selpk_want(selpk *b, size_t sz)
+ void selpk_init(selpk *b, sel_state *s, int fd,
+ void (*func)(unsigned char *p, size_t n,
+ pkbuf *pk, size_t *keep, void *arg),
+ void *arg)
+ void selpk_destroy(selpk *b)
+
+cdef extern from 'mLib/ident.h':
+ ctypedef struct ident_request:
+ pass
+ enum:
+ IDENT_USERID
+ IDENT_ERROR
+ IDENT_BAD
+ struct ident_userid:
+ char *os
+ char *user
+ union ident_u:
+ ident_userid userid
+ char *error
+ ctypedef struct ident_reply:
+ int sport
+ int dport
+ int type
+ ident_u u
+ void ident(ident_request *rq, sel_state *s,
+ sockaddr_in *local, sockaddr_in *remote,
+ void (*func)(ident_reply *r, void *arg),
+ void *arg)
+ void ident_abort(ident_request *rq)
+
+cdef extern from 'Python.h':
+ object PyString_FromStringAndSize(char *p, int len)
+ int PyString_AsStringAndSize(obj, char **p, int *len) except -1
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ int PyObject_TypeCheck(obj, ty)
+
+cdef extern from 'grim.h':
+ int PSIZEOF(void *x)
+
+import socket
+import signal
+
+#----- Utility functions ----------------------------------------------------
+
+cdef _oserror():
+ raise OSError, (errno, strerror(errno))
+
+cdef object _tobool(int i):
+ if i:
+ return True
+ else:
+ return False
+
+cdef int _getfd(object fdobj):
+ try:
+ return fdobj
+ except TypeError:
+ return fdobj.fileno()
+
+#----- The global select state ----------------------------------------------
+
+cdef sel_state sel
+
+sel_init(&sel)
+bres_init(&sel)
+bres_exec(NULL)
+sig_init(&sel)
+
+def select():
+ if sel_select(&sel) and errno != EINTR and errno != EAGAIN:
+ _oserror()
+
+#----- File selectors -------------------------------------------------------
+
+READ = SEL_READ
+WRITE = SEL_WRITE
+EXCEPT = SEL_EXC
+
+cdef class File:
+ cdef sel_file f
+ cdef int _activep
+ cdef readonly unsigned mode
+ def __new__(me, fd, int mode = SEL_READ):
+ if (mode != SEL_READ and
+ mode != SEL_WRITE and
+ mode != SEL_EXC):
+ raise ValueError, 'bad select mode'
+ sel_initfile(&sel, &me.f, _getfd(fd), mode, _filefunc, <void *>me)
+ me._activep = 0
+ me.mode = mode
+ def __dealloc__(me):
+ if me._activep:
+ sel_rmfile(&me.f)
+ property fd:
+ def __get__(me):
+ return me.f.fd
+ property activep:
+ def __get__(me):
+ return _tobool(me._activep)
+ def enable(me):
+ if me._activep:
+ raise ValueError, 'already enabled'
+ sel_addfile(&me.f)
+ me._activep = 1
+ return me
+ def disable(me):
+ if not me._activep:
+ raise ValueError, 'already disabled'
+ sel_rmfile(&me.f)
+ me._activep = 0
+ return me
+ def force(me):
+ sel_force(&me.f)
+ return me
+ def ready(me):
+ pass
+
+cdef void _filefunc(int fd, unsigned mode, void *arg):
+ cdef File sf
+ sf = <File>arg
+ sf.ready()
+
+#----- Timer selectors ------------------------------------------------------
+
+cdef double _tvtofloat(timeval *tv):
+ return tv.tv_sec + (tv.tv_usec / 1000000)
+cdef void _floattotv(timeval *tv, double t):
+ cdef double s, us
+ us = modf(t, &s)
+ tv.tv_sec = s
+ tv.tv_usec = us * 1000000
+
+cdef class Timer:
+ cdef sel_timer t
+ cdef int _activep
+ cdef readonly double time
+ def __new__(me, double when):
+ cdef timeval tv
+ _floattotv(&tv, when)
+ sel_addtimer(&sel, &me.t, &tv, _timerfunc, <void *>me)
+ me._activep = 1
+ me.time = when
+ def __dealloc__(me):
+ if me._activep:
+ sel_rmtimer(&me.t)
+ property activep:
+ def __get__(me):
+ return _tobool(me._activep)
+ def kill(me):
+ if not me._activep:
+ raise ValueError, 'already dead'
+ sel_rmtimer(&me.t)
+ me._activep = 0
+ return me
+ def timer(me, now):
+ pass
+
+cdef void _timerfunc(timeval *now, void *arg):
+ cdef Timer st
+ st = <Timer>arg
+ st._activep = 0
+ st.timer(_tvtofloat(now))
+
+#----- Connections ----------------------------------------------------------
+
+cdef class Connect:
+ cdef conn c
+ cdef int _activep
+ cdef readonly object socket
+ def __new__(me, sk):
+ conn_fd(&me.c, &sel, sk.fileno(), _connfunc, <void *>me)
+ me._activep = 1
+ me.socket = sk
+ def __dealloc__(me):
+ if me._activep:
+ conn_kill(&me.c)
+ property activep:
+ def __get__(me):
+ return _tobool(me._activep)
+ def kill(me):
+ if not me._activep:
+ raise ValueError, 'already dead'
+ conn_kill(&me.c);
+ me._activep = 0
+ return me
+ def connected(me):
+ pass
+ def error(me, errno, strerror):
+ pass
+
+cdef void _connfunc(int fd, void *arg):
+ cdef Connect c
+ c = <Connect>arg
+ c._activep = 0
+ if fd == -1:
+ c.socket = None
+ c.error(errno, strerror(errno))
+ else:
+ c.connected()
+
+#----- Background name resolution -------------------------------------------
+
+cdef class Resolve:
+ cdef bres_client r
+ cdef int _activep
+ def __init__(me, *hunoz, **hukairz):
+ raise TypeError, 'abstract class'
+ property activep:
+ def __get__(me):
+ return _tobool(me._activep)
+ def kill(me):
+ if not me._activep:
+ raise ValueError, 'already dead'
+ bres_abort(&me.r)
+ return me
+ def resolved(me, h):
+ pass
+ def failed(me):
+ pass
+
+cdef class ResolveByName (Resolve):
+ def __new__(me, char *name):
+ bres_byname(&me.r, name, _resfunc, <void *>me)
+ me._activep = 1
+ def __init__(me, name):
+ pass
+
+cdef class ResolveByAddr (Resolve):
+ def __new__(me, char *addr):
+ cdef in_addr ia
+ if not inet_aton(addr, &ia):
+ raise TypeError, 'bad IP address'
+ bres_byaddr(&me.r, ia, _resfunc, <void *>me)
+ me._activep = 1
+ def __init__(me, addr):
+ pass
+
+cdef void _resfunc(hostent *h, void *arg):
+ cdef Resolve r
+ cdef int i
+ r = <Resolve>arg
+ r._activep = 0
+ if h is NULL:
+ r.failed(r)
+ else:
+ alias = []
+ addr = []
+ i = 0
+ while h.h_aliases[i]:
+ alias.append(h.h_aliases[i])
+ i = i + 1
+ i = 0
+ while h.h_addr_list[i]:
+ addr.append(inet_ntoa((<in_addr *>h.h_addr_list[i])[0]))
+ i = i + 1
+ r.resolved(h.h_name, alias, addr)
+
+#----- Signal handling ------------------------------------------------------
+
+cdef class Signal:
+ cdef sig s
+ cdef int _activep
+ cdef readonly int signal
+ def __new__(me, int sig):
+ if sig < 0 or sig >= signal.NSIG:
+ raise ValueError, 'signal number out of range'
+ me.signal = sig
+ me._activep = 0
+ def __dealloc__(me):
+ if me._activep:
+ sig_remove(&me.s)
+ def enable(me):
+ if me._activep:
+ raise ValueError, 'already enabled'
+ sig_add(&me.s, me.signal, _sigfunc, <void *>me)
+ me._activep = 1
+ return me
+ def disable(me):
+ if not me._activep:
+ raise ValueError, 'already disabled'
+ sig_remove(&me.s)
+ me._activep = 0
+ return me
+ def signalled(me):
+ pass
+
+cdef void _sigfunc(int sig, void *arg):
+ cdef Signal s
+ s = <Signal>arg
+ s.signalled()
+
+#----- Line buffers ---------------------------------------------------------
+
+CRLF = LBUF_CRLF
+STRICTCRLF = LBUF_STRICTCRLF
+
+cdef class LineBuffer:
+ cdef selbuf b
+ def __new__(me, fd):
+ selbuf_init(&me.b, &sel, _getfd(fd), _lbfunc, <void *>me)
+ selbuf_disable(&me.b)
+ def __dealloc__(me):
+ selbuf_destroy(&me.b)
+ property activep:
+ def __get__(me):
+ return _tobool(me.b.b.f & LFBUF_ENABLE)
+ property delim:
+ def __get__(me):
+ if me.b.b.delim == LBUF_CRLF or me.b.b.delim == LBUF_STRICTCRLF:
+ return me.b.b.delim
+ else:
+ return chr(me.b.b.delim)
+ def __set__(me, d):
+ if d == LBUF_CRLF or d == LBUF_STRICTCRLF:
+ me.b.b.delim = d
+ else:
+ me.b.b.delim = ord(d)
+ property size:
+ def __get__(me):
+ return me.b.b.sz
+ def __set__(me, sz):
+ selbuf_setsize(&me.b, sz)
+ def enable(me):
+ if me.b.b.f & LBUF_ENABLE:
+ raise ValueError, 'already enabled'
+ selbuf_enable(&me.b)
+ return me
+ def disable(me):
+ if not (me.b.b.f & LBUF_ENABLE):
+ raise ValueError, 'already disabled'
+ selbuf_disable(&me.b)
+ return me
+ def line(me, line):
+ pass
+ def eof(me):
+ pass
+
+cdef void _lbfunc(char *s, size_t n, void *arg):
+ cdef LineBuffer sb
+ sb = <LineBuffer>arg
+ if s is NULL:
+ sb.eof()
+ else:
+ sb.line(PyString_FromStringAndSize(s, n))
+
+#----- Packet buffers -------------------------------------------------------
+
+cdef class PacketBuffer:
+ cdef selpk p
+ def __new__(me, fd):
+ selpk_init(&me.p, &sel, _getfd(fd), _pkfunc, <void *>me)
+ selpk_disable(&me.p)
+ def __dealloc__(me):
+ selpk_destroy(&me.p)
+ property activep:
+ def __get__(me):
+ return _to_bool(me.p.pk.f & PKBUF_ENABLE)
+ property want:
+ def __get__(me):
+ return me.p.pk.want
+ def __set__(me, n):
+ selpk_want(&me.p, n)
+ def enable(me):
+ if me.p.pk.f & PKBUF_ENABLE:
+ raise ValueError, 'already enabled'
+ selpk_enable(&me.p)
+ return me
+ def disable(me):
+ if not (me.p.pk.f & PKBUF_ENABLE):
+ raise ValueError, 'already disabled'
+ selpk_disable(&me.p)
+ return me
+ def packet(me, pk):
+ return None
+ def eof(me):
+ pass
+
+cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk,
+ size_t *keep, void *arg):
+ cdef PacketBuffer pb
+ cdef void *rp
+ cdef int rn
+ pb = <PacketBuffer>arg
+ if p is NULL:
+ pb.eof()
+ else:
+ r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
+ if r is not None:
+ PyObject_AsReadBuffer(r, &rp, &rn)
+ if rn > n:
+ raise ValueError, 'remaining buffer too large'
+ if rn:
+ memcpy(p + n - rn, rp, rn)
+ keep[0] = rn
+
+#----- Ident client ---------------------------------------------------------
+
+cdef _inaddr_frompy(sockaddr_in *sin, addr):
+ cdef int port
+ if len(addr) != 2:
+ raise TypeError, 'want address/port pair'
+ a = addr[0]
+ if not inet_aton(a, &sin.sin_addr):
+ raise TypeError, 'bad IP address'
+ port = addr[1]
+ if not (0 <= port < 65536):
+ raise TypeError, 'port number out of range'
+ sin.sin_port = htons(port)
+
+cdef _inaddr_topy(sockaddr_in *sin):
+ return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)
+
+cdef class Identify:
+ cdef ident_request irq
+ cdef int _activep
+ cdef readonly localaddr
+ cdef readonly remoteaddr
+ def __new__(me, sk):
+ cdef sockaddr_in s_in, s_out
+ cdef size_t sz_in, sz_out
+ cdef int fd
+ if PyObject_TypeCheck(sk, socket.SocketType):
+ fd = sk.fileno()
+ sz_in = PSIZEOF(&s_in)
+ sz_out = PSIZEOF(&s_out)
+ if getsockname(fd, <sockaddr *>&s_in, &sz_in) or \
+ getpeername(fd, <sockaddr *>&s_out, &sz_out):
+ _oserror()
+ if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET:
+ raise TypeError, 'must be internet socket'
+ elif len(sk) != 2:
+ raise TypeError, 'want pair of addresses'
+ else:
+ _inaddr_frompy(&s_in, sk[0])
+ _inaddr_frompy(&s_out, sk[1])
+ ident(&me.irq, &sel, &s_in, &s_out, _identfunc, <void *>me)
+ me.localaddr = _inaddr_topy(&s_in)
+ me.remoteaddr = _inaddr_topy(&s_out)
+ me._activep = 1
+ def __dealloc__(me):
+ if me._activep:
+ ident_abort(&me.irq)
+ property activep:
+ def __get__(me):
+ return _tobool(me._activep)
+ def kill(me):
+ if not me._activep:
+ raise ValueError, 'already disabled'
+ ident_abort(&me.irq)
+ me._activep = 0
+ def user(me, os, user):
+ pass
+ def bad(me):
+ pass
+ def error(me, error):
+ pass
+ def failed(me, errno, strerror):
+ pass
+
+cdef void _identfunc(ident_reply *i, void *arg):
+ cdef Identify id
+ id = <Identify>arg
+ id._activep = 0
+ if i.type == IDENT_BAD:
+ ii.bad()
+ elif i.type == IDENT_ERROR:
+ ii.error(i.u.error)
+ elif i.type == IDENT_USER:
+ ii.user(i.u.userid.os, i.u.userid.user)
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+from distutils.core import setup, Extension
+from Pyrex.Distutils import build_ext
+from os import *
+from errno import *
+import sre
+import sys
+from sys import stdin, stdout, stderr
+
+incdirs = []
+libdirs = []
+libs = []
+
+def progoutput(cmd):
+ p = popen(cmd)
+ out = p.readline()
+ if p.read() != '': raise 'extra junk from %s' % cmd
+ p.close()
+ return out.rstrip('\n')
+
+def libconfig(lib, ver):
+ config = lib + '-config'
+ if system('%s --check %s' % (config, ver)):
+ raise '%s version %s not found' % (lib, ver)
+ version = progoutput('%s --version' % config)
+ for i in progoutput('%s --cflags' % config).split():
+ if i[:2] == '-I': incdirs.append(i[2:])
+ else: raise 'strange cflags item %s' % i
+ for i in progoutput('%s --libs' % config).split():
+ if i[:2] == '-L': libdirs.append(i[2:])
+ elif i[:2] == '-l': libs.append(i[2:])
+ else: raise 'strange libs item %s' % i
+
+def uniquify(l):
+ u = {}
+ o = []
+ for i in l:
+ if i not in u:
+ o.append(i)
+ u[i] = 1
+ return o
+
+libconfig('catacomb', '2.1.0')
+libconfig('mLib', '2.0.3')
+
+def needs_update_p(target, sources):
+ if not path.exists(target): return True
+ t_target = stat(target).st_mtime
+ for s in sources:
+ if stat(s).st_mtime > t_target: return True
+ return False
+
+rx_subst = sre.compile(r'\%(\w+)\%')
+
+def getsource(src):
+ br = src.find('[')
+ if br >= 0:
+ if src[-1] != ']':
+ raise SyntaxError, 'bad auto file'
+ subst = src[br + 1:-1]
+ src = src[:br]
+ x = subst.split(':')
+ infile = x[0]
+ if needs_update_p(src, [infile]):
+ print 'creating %s from %s...' % (src, infile)
+ d = dict([i.split('/', 1) for i in x[1:]])
+ out = file(src + '.new', 'w')
+ for line in file(infile):
+ out.write(rx_subst.sub((lambda m: d[m.group(1)]), line))
+ out.close()
+ rename(src + '.new', src)
+ return src
+
+def mlibext(src):
+ col = src.find('!')
+ if col >= 0:
+ mod = src[:col]
+ srcs = [getsource(s) for s in src[col + 1:].split(',')]
+ else:
+ src = getsource(src)
+ mod, hunoz = src.split('.', 1)
+ srcs = [src]
+ return Extension('mLib.' + mod, srcs,
+ ##extra_compile_args = ['-O0'],
+ include_dirs = uniquify(incdirs),
+ library_dirs = uniquify(libdirs),
+ libraries = uniquify(libs))
+
+setup(name = 'mLib-python',
+ version = '1.0.0',
+ description = 'Python interface to mLib utilities library',
+ author = 'Straylight/Edgeware',
+ author_email = 'mdw@distorted.org.uk',
+ license = 'GNU General Public License',
+ packages = ['mLib'],
+ ext_modules = [mlibext(x) for x in '''
+ select.pyx crc32.pyx unihash.pyx report.pyx
+ base64.pyx[codec.pyx.in:PREFIX/base64]
+ base32.pyx[codec.pyx.in:PREFIX/base32]
+ hex.pyx[codec.pyx.in:PREFIX/hex]
+ array.c sym.pyx atom!atom-base.c,atom.pyx
+ '''.split()],
+ cmdclass = {'build_ext': build_ext})
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Symbol table, using universal hashing
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+cdef extern from 'mLib/sym.h':
+ ctypedef struct sym_table:
+ pass
+ ctypedef struct sym_base:
+ pass
+ ctypedef struct sym_iter:
+ pass
+ void sym_create(sym_table *t)
+ void sym_destroy(sym_table *t)
+ void *sym_find(sym_table *t, char *n, long l, int sz, unsigned *f)
+ void sym_remove(sym_table *t, void *b)
+ char *SYM_NAME(void *b)
+ int SYM_LEN(void *b)
+ void sym_mkiter(sym_iter *i, sym_table *t)
+ void *sym_next(sym_iter *i)
+
+cdef extern from 'grim.h':
+ int PSIZEOF(void *p)
+
+cdef extern from 'Python.h':
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ PyString_FromStringAndSize(char *p, int n)
+ ctypedef struct PyObject:
+ pass
+ void Py_INCREF(PyObject *obj)
+ void Py_DECREF(PyObject *obj)
+
+cdef struct entry:
+ sym_base _b
+ PyObject *v
+
+cdef entry *_find(sym_table *t, object k, unsigned *f) except ?NULL:
+ cdef void *p
+ cdef int n
+ cdef entry *e
+ PyObject_AsReadBuffer(key, &p, &n)
+ if f:
+ f[0] = 0
+ e = <entry *>sym_find(t, <char *>p, n, PSIZEOF(e), f)
+ if not f[0]:
+ e.v = NULL
+ else:
+ e = <entry *>sym_find(t, <char *>p, n, 0, NULL)
+ return e
+
+cdef _eget(entry *e):
+ Py_INCREF(e.v)
+ return <object>e.v
+
+cdef void _eset(entry *e, v):
+ if e.v:
+ Py_DECREF(e.v)
+ e.v = <PyObject *>v
+ Py_INCREF(e.v)
+
+cdef void _edel(sym_table *t, entry *e):
+ if e.v:
+ Py_DECREF(e.v)
+ sym_remove(t, <void *>e)
+
+cdef _key(entry *e):
+ return PyString_FromStringAndSize(SYM_NAME(<void *>e), SYM_LEN(<void *>e))
+
+cdef class Table:
+ cdef sym_table _t
+ def __new__(me, *hunoz, **hukairz):
+ sym_create(&me._t)
+ def __init__(me, stuff = None, **kw):
+ me.update(stuff, kw)
+ def __getitem__(me, key):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ raise KeyError, key
+ return _eget(e)
+ def __setitem__(me, key, value):
+ cdef unsigned f
+ _eset(_find(&me._t, key, &f), value)
+ def __delitem__(me, key):
+ cdef entry *e
+ cdef unsigned f
+ e = _find(&me._t, key, &f)
+ if not e:
+ raise KeyError, key
+ _edel(&me._t, e)
+ def get(me, key, default = None):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ return default
+ return _eget(e)
+ def setdefault(me, key, default = None):
+ cdef entry *e
+ cdef unsigned f
+ e = _find(&me._t, key, &f)
+ if f:
+ return _eget(e)
+ else:
+ _eset(e, default)
+ return default
+ def pop(me, key, default = None):
+ cdef entry *e
+ e = _find(&me._t, key, NULL)
+ if not e:
+ return default
+ rc = _eget(e)
+ _edel(&me._t, e)
+ return rc
+ def popitem(me):
+ cdef entry *e
+ cdef sym_iter i
+ sym_mkiter(&i, &me._t)
+ e = <entry *>sym_next(&i)
+ if not e:
+ raise ValueError, 'popitem(): table is empty'
+ return _key(e), _eget(e)
+ def keys(me):
+ cdef sym_iter i
+ cdef entry *e
+ l = []
+ sym_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>sym_next(&i)
+ if not e:
+ break
+ l.append(_key(e))
+ return l
+ def values(me):
+ cdef sym_iter i
+ cdef entry *e
+ l = []
+ sym_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>sym_next(&i)
+ if not e:
+ break
+ l.append(_eget(e))
+ return l
+ def items(me):
+ cdef sym_iter i
+ cdef entry *e
+ l = []
+ sym_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>sym_next(&i)
+ if not e:
+ break
+ l.append((_key(e), _eget(e)))
+ return l
+ def clear(me):
+ cdef sym_iter i
+ cdef entry *e
+ sym_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>sym_next(&i)
+ if not e:
+ break
+ _edel(&me._t, e)
+ return me
+ def __dealloc__(me):
+ cdef sym_iter i
+ cdef entry *e
+ sym_mkiter(&i, &me._t)
+ while 1:
+ e = <entry *>sym_next(&i)
+ if not e:
+ break
+ _edel(&me._t, e)
+ sym_destroy(&me._t)
+ def iterkeys(me):
+ return KeyIter(me)
+ def __iter__(me):
+ return KeyIter(me)
+ def itervalues(me):
+ return ValueIter(me)
+ def iteritems(me):
+ return ItemIter(me)
+ def update(me, stuff = None, **kw):
+ cdef unsigned f
+ if stuff is None:
+ pass
+ elif hasattr(stuff, 'itemiter'):
+ for k, v in stuff.itemiter:
+ _eset(_find(&me._t, k, &f), v)
+ elif hasattr(stuff, 'keys'):
+ for k in stuff.keys():
+ _eset(_find(&me._t, k, &f), stuff[k])
+ else:
+ for k, v in stuff:
+ _eset(_find(&me._t, k, &f), v)
+ for k, v in kw.iteritems():
+ _eset(_find(&me._t, k, &f), v)
+ return me
+
+cdef class KeyIter:
+ cdef Table _t
+ cdef sym_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ sym_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>sym_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _key(e)
+
+cdef class ValueIter:
+ cdef Table _t
+ cdef sym_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ sym_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>sym_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _eget(e)
+
+cdef class ItemIter:
+ cdef Table _t
+ cdef sym_iter _i
+ def __new__(me, Table t):
+ me._t = t
+ sym_mkiter(&me._i, &t._t)
+ def __iter__(me):
+ return me
+ def __next__(me):
+ cdef entry *e
+ e = <entry *>sym_next(&me._i)
+ if not e:
+ raise StopIteration
+ return _key(e), _eget(e)
+
+#----- That's all, folks ----------------------------------------------------
--- /dev/null
+# -*-pyrex-*-
+#
+# $Id$
+#
+# Universal hashing interface
+#
+# (c) 2005 Straylight/Edgeware
+#
+
+#----- Licensing notice -----------------------------------------------------
+#
+# This file is part of the Python interface to mLib.
+#
+# mLib/Python is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# mLib/Python is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mLib/Python; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+cdef extern from 'mLib/unihash.h':
+ ctypedef int uint32
+ ctypedef struct unihash_info:
+ pass
+ void unihash_setkey(unihash_info *i, uint32 k)
+ uint32 UNIHASH_INIT(unihash_info *i)
+ uint32 unihash_hash(unihash_info *i, uint32 a, void *p, int sz)
+ unihash_info unihash_global
+
+cdef extern from 'limits.h':
+ enum:
+ LONG_MAX
+
+cdef extern from 'Python.h':
+ int PyObject_AsReadBuffer(obj, void **buf, int *len) except -1
+ PyInt_FromLong(long i)
+ PyLong_FromUnsignedLong(unsigned long i)
+
+cdef _u32(uint32 x):
+ if x < LONG_MAX:
+ return PyInt_FromLong(x)
+ else:
+ return PyLong_FromUnsignedLong(x)
+
+def setglobalkey(uint32 k):
+ unihash_setkey(&unihash_global, k)
+
+cdef class Key:
+ cdef unihash_info _i
+ cdef uint32 _k
+ def __new__(me, uint32 k):
+ unihash_setkey(&me._i, k)
+ me._k = k
+ property k:
+ def __get__(me):
+ return _u32(me._k)
+
+cdef class Unihash:
+ cdef uint32 _a
+ cdef readonly Key key
+ cdef unihash_info *_i
+ def __new__(me, key = None):
+ cdef Key k
+ me.key = key
+ if key is None:
+ me._i = &unihash_global
+ else:
+ k = key
+ me._i = &k._i
+ me._a = UNIHASH_INIT(me._i)
+ def chunk(me, data):
+ cdef void *p
+ cdef int n
+ PyObject_AsReadBuffer(data, &p, &n)
+ me._a = unihash_hash(me._i, me._a, p, n)
+ def done(me):
+ return _u32(me._a)
+
+#----- That's all, folks ----------------------------------------------------