From 579d01693c86259110fe7a2c2a6f005f1bdbad5b Mon Sep 17 00:00:00 2001 Message-Id: <579d01693c86259110fe7a2c2a6f005f1bdbad5b.1713555516.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 18 Oct 2005 08:37:09 +0000 Subject: [PATCH] General reorganization. Organization: Straylight/Edgeware From: mdw --- MANIFEST.in | 8 +- Makefile | 6 +- array.c | 18 +- array.h | 45 ++++ assoc.pyx | 84 +++++++ atom-base.c | 12 +- atom.h | 4 +- atom.pyx | 252 ------------------- bres.pyx | 114 +++++++++ codec.pyx.in | 50 ++-- conn.pyx | 87 +++++++ crc32.pyx | 19 -- debian/changelog | 5 + debian/control | 69 ++++++ debian/copyright | 16 ++ debian/rules | 63 +++++ defs.pxi | 365 +++++++++++++++++++++++++++ grim.h | 4 +- ident.pyx | 171 +++++++++++++ lbuf.pyx | 131 ++++++++++ mLib.pyx | 92 +++++++ mLib/__init__.py | 1 - mapping.pyx | 201 +++++++++++++++ pkbuf.pyx | 127 ++++++++++ report.pyx | 26 +- sel-base.pyx | 36 +++ sel-file.pyx | 96 +++++++ sel-timer.pyx | 81 ++++++ selbuf.pyx | 106 ++++++++ select.pyx | 634 ----------------------------------------------- selpk.pyx | 105 ++++++++ setup.py | 51 ++-- sig.pyx | 86 +++++++ sym.pyx | 275 ++++---------------- unihash.pyx | 24 -- utils.pyx | 59 +++++ 36 files changed, 2253 insertions(+), 1270 deletions(-) create mode 100644 array.h create mode 100644 assoc.pyx create mode 100644 bres.pyx create mode 100644 conn.pyx create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules create mode 100644 defs.pxi create mode 100644 ident.pyx create mode 100644 lbuf.pyx create mode 100644 mLib.pyx delete mode 100644 mLib/__init__.py create mode 100644 mapping.pyx create mode 100644 pkbuf.pyx create mode 100644 sel-base.pyx create mode 100644 sel-file.pyx create mode 100644 sel-timer.pyx create mode 100644 selbuf.pyx delete mode 100644 select.pyx create mode 100644 selpk.pyx create mode 100644 sig.pyx create mode 100644 utils.pyx diff --git a/MANIFEST.in b/MANIFEST.in index b051d6b..38ad47f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,7 @@ -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 mLib.pyx defs.pxi utils.pyx +include codec.pyx.in grim.h atom.h array.h atom-base.c array.c Makefile +include lbuf.pyx pkbuf.pyx mapping.pyx +include atom.pyx crc32.pyx report.pyx sym.pyx assoc.pyx unihash.pyx +include sel-base.pyx sel-file.pyx sel-timer.pyx conn.pyx +include bres.pyx selbuf.pyx selpk.pyx sig.pyx ident.pyx include debian/rules debian/control debian/changelog debian/copyright diff --git a/Makefile b/Makefile index 53ea323..7963e52 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,6 @@ 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 @@ -15,7 +11,7 @@ all: setup.py clean: setup.py $(PYTHON) setup.py clean rm -rf build - rm -f $(AUTOC) $(GEN) MANIFEST + rm -f mLib.c $(GEN) MANIFEST dist: setup.py $(PYTHON) setup.py sdist diff --git a/array.c b/array.c index 37850d9..6f8048a 100644 --- a/array.c +++ b/array.c @@ -36,6 +36,7 @@ #include #include +#include "array.h" #include "grim.h" /*----- Data structures ---------------------------------------------------*/ @@ -58,8 +59,6 @@ typedef struct daiter_pyobj { #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; @@ -118,7 +117,7 @@ static PyObject *daiter_pynext(PyObject *me) static void daiter_pydealloc(PyObject *me) { Py_DECREF(DAITER_DA(me)); PyObject_DEL(me); } -static PyTypeObject daiter_pytype = { +PyTypeObject daiter_pytype = { PyObject_HEAD_INIT(0) 0, /* Header */ "array.ArrayIter", /* @tp_name@ */ sizeof(daiter_pyobj), /* @tp_basicsize@ */ @@ -600,7 +599,7 @@ static PyMappingMethods da_pymapping = { da_pyput /* @mp_ass_subscript@ */ }; -static PyTypeObject da_pytype = { +PyTypeObject da_pytype = { PyObject_HEAD_INIT(0) 0, /* Header */ "array.Array", /* @tp_name@ */ sizeof(da_pyobj), /* @tp_basicsize@ */ @@ -650,14 +649,7 @@ static PyTypeObject da_pytype = { /*----- 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); -} +void da_pysetup(void) + { PyType_Ready(&da_pytype); PyType_Ready(&daiter_pytype); } /*----- That's all, folks -------------------------------------------------*/ diff --git a/array.h b/array.h new file mode 100644 index 0000000..96d4f9a --- /dev/null +++ b/array.h @@ -0,0 +1,45 @@ +/* -*-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. + */ + +#ifndef ARRAY_H +#define ARRAY_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include + +extern void daysetup(void); +extern PyTypeObject da_pytype, daiter_pytype; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/assoc.pyx b/assoc.pyx new file mode 100644 index 0000000..26369de --- /dev/null +++ b/assoc.pyx @@ -0,0 +1,84 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Association 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 struct _assoc_entry: + sym_base _b + PyObject *v + +cdef class AssocTable (Mapping): + cdef assoc_table _t + cdef int _init(me) except -1: + assoc_create(&me._t) + return 0 + cdef void *_find(me, object key, unsigned *f) except NULL: + cdef void *p + cdef int n + cdef _assoc_entry *e + cdef atom *a + a = ATOM_A(atom_pyintern(key)) + PyObject_AsReadBuffer(key, &p, &n) + if f: + f[0] = 0 + e = <_assoc_entry *>assoc_find(&me._t, a, PSIZEOF(e), f) + if not f[0]: + e.v = NULL + else: + e = <_assoc_entry *>assoc_find(&me._t, a, 0, NULL) + return e + cdef object _key(me, void *e): + return atom_pywrap(ASSOC_ATOM(e)) + cdef object _value(me, void *e): + cdef _assoc_entry *ee + ee = <_assoc_entry *>e + Py_INCREF(ee.v) + return ee.v + cdef void _setval(me, void *e, object val): + cdef _assoc_entry *ee + ee = <_assoc_entry *>e + if ee.v: + Py_DECREF(ee.v) + ee.v = v + Py_INCREF(ee.v) + cdef void _del(me, void *e): + cdef _assoc_entry *ee + ee = <_assoc_entry *>e + if ee.v: + Py_DECREF(ee.v) + assoc_remove(&me._t, ee) + cdef _MapIterator _iter(me): + return _AssocIter(me) + +cdef class _AssocIter (_MapIterator): + cdef AssocTable t + cdef assoc_iter i + def __new__(me, AssocTable t): + me.t = t + assoc_mkiter(&me.i, &me.t._t) + cdef void *_next(me): + return assoc_next(&me.i) + +#----- That's all, folks ---------------------------------------------------- diff --git a/atom-base.c b/atom-base.c index 44b915b..e59fa2b 100644 --- a/atom-base.c +++ b/atom-base.c @@ -39,8 +39,6 @@ /*----- Data structures ---------------------------------------------------*/ -static PyTypeObject atom_pytype; - typedef struct entry { assoc_base _b; PyObject *a; @@ -156,7 +154,7 @@ done: static long atom_pyhash(PyObject *me) { long h = ATOM_HASH(ATOM_A(me)); if (h == -1) h = -2; return (h); } -static PyTypeObject atom_pytype = { +PyTypeObject atom_pytype = { PyObject_HEAD_INIT(0) 0, /* Header */ "atom.Atom", /* @tp_name@ */ sizeof(atom_pyobj), /* @tp_basicsize@ */ @@ -203,11 +201,7 @@ static PyTypeObject atom_pytype = { 0 /* @tp_is_gc@ */ }; -PyObject *atom_pystartup(void) -{ - assoc_create(&obarray); - PyType_Ready(&atom_pytype); - return ((PyObject *)&atom_pytype); -} +void atom_pysetup(void) + { assoc_create(&obarray); PyType_Ready(&atom_pytype); } /*----- That's all, folks -------------------------------------------------*/ diff --git a/atom.h b/atom.h index 8a2ff31..6bc5bd3 100644 --- a/atom.h +++ b/atom.h @@ -49,11 +49,13 @@ typedef struct atom_pyobj { #define ATOM_PYCHECK(obj) PyObject_TypeCheck(obj, &atom_pytype) #define ATOM_A(obj) (((atom_pyobj *)(obj))->a) +extern PyTypeObject atom_pytype; + /*----- Functions provided ------------------------------------------------*/ extern PyObject *atom_pywrap(atom *); extern PyObject *atom_pyintern(PyObject *); -extern PyObject *atom_pystartup(void); +extern void atom_pysetup(void); /*----- That's all, folks -------------------------------------------------*/ diff --git a/atom.pyx b/atom.pyx index 8fac74c..fc935f8 100644 --- a/atom.pyx +++ b/atom.pyx @@ -25,47 +25,6 @@ # 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): @@ -82,215 +41,4 @@ cdef class AtomIter: 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 = assoc_find(t, a, PSIZEOF(e), f) - if not f[0]: - e.v = NULL - else: - e = assoc_find(t, a, 0, NULL) - return e - -cdef _key(entry *e): - return atom_pywrap(ASSOC_ATOM(e)) - -cdef _eget(entry *e): - Py_INCREF(e.v) - return e.v - -cdef void _eset(entry *e, v): - if e.v: - Py_DECREF(e.v) - e.v = v - Py_INCREF(e.v) - -cdef void _edel(assoc_table *t, entry *e): - if e.v: - Py_DECREF(e.v) - assoc_remove(t, 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = assoc_next(&me._i) - if not e: - raise StopIteration - return _key(e), _eget(e) - -Atom = atom_pystartup() - #----- That's all, folks ---------------------------------------------------- diff --git a/bres.pyx b/bres.pyx new file mode 100644 index 0000000..162ff02 --- /dev/null +++ b/bres.pyx @@ -0,0 +1,114 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Background name resolution +# +# (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 class SelResolve: + cdef bres_client r + cdef int _activep + cdef _resolved + cdef _failed + 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' + me._dead() + bres_abort(&me.r) + return me + cdef _dead(me): + me._activep = 0 + me.dead() + def dead(me): + pass + property resolvedproc: + def __get__(me): + return me._resolved + def __set__(me, proc): + me._resolved = _checkcallable(proc, 'resolved proc') + def __del__(me): + me._resolved = None + property failedproc: + def __get__(me): + return me._failed + def __set__(me, proc): + me._failed = _checkcallable(proc, 'failed proc') + def __del__(me): + me._failed = None + def resolved(me, name, aliases, addrs): + return _maybecall(me._resolved, (name, aliases, addrs)) + def failed(me): + return _maybecall(me._failed, ()) + +cdef class SelResolveByName (SelResolve): + def __new__(me, char *name, resolvedproc = None, failedproc = None, + *hunoz, **hukairz): + bres_byname(&me.r, name, _resfunc, me) + me._resolved = _checkcallable(resolvedproc, 'resolved proc') + me._failed = _checkcallable(failedproc, 'failed proc') + me._activep = 1 + def __init__(me, name, resolvedproc = None, failedproc = None): + pass + +cdef class SelResolveByAddr (SelResolve): + def __new__(me, char *addr, resolvedproc = None, failedproc = None, + *hunoz, **hukairz): + cdef in_addr ia + if not inet_aton(addr, &ia): + raise TypeError, 'bad IP address' + bres_byaddr(&me.r, ia, _resfunc, me) + me._resolved = _checkcallable(resolvedproc, 'resolved proc') + me._failed = _checkcallable(failedproc, 'failed proc') + me._activep = 1 + def __init__(me, addr, resolvedproc = None, failedproc = None): + pass + +cdef void _resfunc(hostent *h, void *arg): + cdef SelResolve r + cdef int i + r = arg + r._dead() + 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((h.h_addr_list[i])[0])) + i = i + 1 + r.resolved(h.h_name, alias, addr) + +bres_exec(NULL) +bres_init(&_sel) + +#----- That's all, folks ---------------------------------------------------- diff --git a/codec.pyx.in b/codec.pyx.in index 60d9714..ebbb38e 100644 --- a/codec.pyx.in +++ b/codec.pyx.in @@ -27,36 +27,20 @@ #----- 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) + void _%PREFIX%_init "%PREFIX%_init"(%PREFIX%_ctx *b) + void _%PREFIX%_encode "%PREFIX%_encode"(%PREFIX%_ctx *b, + void *p, size_t sz, dstr *d) + void _%PREFIX%_decode"%PREFIX%_decode"(%PREFIX%_ctx *b, + void *p, size_t sz, dstr *d) -cdef class Encode: +cdef class %CLASS%Encode: cdef %PREFIX%_ctx ctx def __new__(me, *hunoz, **hukairz): - %PREFIX%_init(&me.ctx) + _%PREFIX%_init(&me.ctx) me.ctx.indent = NULL def __init__(me, indent = '\n', maxline = 72): if me.ctx.indent: @@ -85,7 +69,7 @@ cdef class Encode: DCREATE(&d) try: PyObject_AsReadBuffer(text, &p, &len) - %PREFIX%_encode(&me.ctx, p, len, &d) + _%PREFIX%_encode(&me.ctx, p, len, &d) rc = PyString_FromStringAndSize(d.buf, d.len) finally: dstr_destroy(&d) @@ -94,20 +78,20 @@ cdef class Encode: cdef dstr d DCREATE(&d) try: - %PREFIX%_encode(&me.ctx, NULL, 0, &d) + _%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) +def %PREFIX%_encode(text, *arg, **kw): + e = %CLASS%Encode(*arg, **kw) return e.encode(text) + e.done() -cdef class Decode: +cdef class %CLASS%Decode: cdef %PREFIX%_ctx ctx def __new__(me, *hunoz, **hukairz): - %PREFIX%_init(&me.ctx) + _%PREFIX%_init(&me.ctx) me.ctx.indent = NULL def decode(me, text): cdef void *p @@ -116,7 +100,7 @@ cdef class Decode: DCREATE(&d) try: PyObject_AsReadBuffer(text, &p, &len) - %PREFIX%_decode(&me.ctx, p, len, &d) + _%PREFIX%_decode(&me.ctx, p, len, &d) rc = PyString_FromStringAndSize(d.buf, d.len) finally: dstr_destroy(&d) @@ -125,14 +109,14 @@ cdef class Decode: cdef dstr d DCREATE(&d) try: - %PREFIX%_decode(&me.ctx, NULL, 0, &d) + _%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) +def %PREFIX%_decode(text, *arg, **kw): + d = %CLASS%Decode(*arg, **kw) return e.decode(text) + d.done() #----- That's all, folks ---------------------------------------------------- diff --git a/conn.pyx b/conn.pyx new file mode 100644 index 0000000..e485f5d --- /dev/null +++ b/conn.pyx @@ -0,0 +1,87 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Non-blocking connections +# +# (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 class SelConnect: + cdef conn c + cdef int _activep + cdef readonly object socket + cdef _connected + cdef _error + def __new__(me, sk, connectedproc = None, errorproc = None, + *hunoz, **hukairz): + conn_fd(&me.c, &_sel, sk.fileno(), _connfunc, me) + me._activep = 1 + me.socket = sk + me._connected = _checkcallable(connectedproc, 'connected proc') + me._error = _checkcallable(errorproc, 'error proc') + def __dealloc__(me): + if me._activep: + conn_kill(&me.c) + property activep: + def __get__(me): + return _tobool(me._activep) + property connectedproc: + def __get__(me): + return me._connected + def __set__(me, proc): + me._connected = _checkcallable(proc, 'connected proc') + def __del__(me): + me._connected = None + property errorproc: + def __get__(me): + return me._error + def __set__(me, proc): + me._error = _checkcallable(proc, 'error proc') + def __del__(me): + me._error = None + def kill(me): + if not me._activep: + raise ValueError, 'already dead' + conn_kill(&me.c); + me._dead() + return me + cdef _dead(me): + me._activep = 0 + me.dead() + def dead(me): + pass + def connected(me): + return _maybecall(me._connected, ()) + def error(me, errno, strerror): + return _maybecall(me._error, ()) + +cdef void _connfunc(int fd, void *arg): + cdef SelConnect c + c = arg + c._dead() + if fd == -1: + c.socket = None + c.error(errno, strerror(errno)) + else: + c.connected() + +#----- That's all, folks ---------------------------------------------------- diff --git a/crc32.pyx b/crc32.pyx index d5e0239..77bc863 100644 --- a/crc32.pyx +++ b/crc32.pyx @@ -25,25 +25,6 @@ # 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): diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..32301da --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +python-mlib (1.0.0) experimental; urgency=low + + * Debianization! + + -- Mark Wooding Thu, 13 Oct 2005 18:14:18 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..576aa11 --- /dev/null +++ b/debian/control @@ -0,0 +1,69 @@ +Source: python-mlib +Section: libs +Priority: extra +Build-Depends: + mlib-dev, + python, python2.3, python2.3-pyrex, python2.4, python2.4-pyrex +Maintainer: Mark Wooding +Standards-Version: 3.1.1 + +Package: python-mlib +Architecture: all +Depends: ${python:Depends} +Description: A library of miscellaneous stuff + The mLib library provides various handy utilities, including + * yet another options parser, like GNU getopt but more so; + * a simple but efficient universal hashing family; + * a suite for writing event-driven select-based servers; + * a simple exception-handling system, based on longjmp; + * dynamically resizing strings and arrays; + * a resizing hashtable; + * base64 and hex encoding and decoding; and + * a simple background DNS resolver. + . + This is a dummy package to pull in the right bindings for the default Debian + version of Python. + . + Not all of the features of mLib are available (or, indeed, very useful) in + Python. For example, Python has its own exception system, and different + ideas about how strings work. + +Package: python2.3-mlib +Architecture: any +Depends: ${shlibs:Depends}, ${python:Depends} +Description: A library of miscellaneous stuff + The mLib library provides various handy utilities, including + * yet another options parser, like GNU getopt but more so; + * a simple but efficient universal hashing family; + * a suite for writing event-driven select-based servers; + * a simple exception-handling system, based on longjmp; + * dynamically resizing strings and arrays; + * a resizing hashtable; + * base64 and hex encoding and decoding; and + * a simple background DNS resolver. + . + This package provides Python bindings for mLib, for Python version 2.3. + . + Not all of the features of mLib are available (or, indeed, very useful) in + Python. For example, Python has its own exception system, and different + ideas about how strings work. + +Package: python2.4-mlib +Architecture: any +Depends: ${shlibs:Depends}, ${python:Depends} +Description: A library of miscellaneous stuff + The mLib library provides various handy utilities, including + * yet another options parser, like GNU getopt but more so; + * a simple but efficient universal hashing family; + * a suite for writing event-driven select-based servers; + * a simple exception-handling system, based on longjmp; + * dynamically resizing strings and arrays; + * a resizing hashtable; + * base64 and hex encoding and decoding; and + * a simple background DNS resolver. + . + This package provides Python bindings for mLib, for Python version 2.4. + . + Not all of the features of mLib are available (or, indeed, very useful) in + Python. For example, Python has its own exception system, and different + ideas about how strings work. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..5c1a437 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,16 @@ +mLib-python is copyright (c) 2003 Straylight/Edgeware. + +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 a copy of the GNU General Public License in +/usr/share/common-licenses/GPL; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..71ecdda --- /dev/null +++ b/debian/rules @@ -0,0 +1,63 @@ +#! /usr/bin/make -f + +export DH_COMPAT = 4 + +DEFVERSION = 2.3 +VERSIONS = $(DEFVERSION) 2.4 + +build: build-stamp + +build-stamp: + for v in $(VERSIONS); do python$$v setup.py build; done + touch build-stamp + +clean: + dh_clean + make clean + rm -rf build build-stamp + +install: build + dh_clean + for v in $(VERSIONS); do \ + python$$v setup.py build; \ + python$$v setup.py install --root=debian/python$$v-mlib; \ + done + mkdir -p debian/python-mlib + +binary-indep: install + dh_testdir -i + dh_testroot -i + dh_compress -i + dh_installdocs -i + dh_python -i + dh_gencontrol -i + dh_fixperms -i + dh_installdeb -i + dh_md5sums -i + dh_builddeb -i + +binary-arch: install + dh_testdir -a + dh_testroot -a + dh_compress -a + dh_installdocs -a + dh_strip -a + dh_shlibdeps -a + dh_python -a + dh_gencontrol -a + dh_fixperms -a + dh_installdeb -a + dh_md5sums -a + dh_builddeb -a + +binary: binary-indep binary-arch + +source: + rm -rf dist/*.tar.gz dist/=deb= + python setup.py sdist + mkdir dist/=deb= + cd dist/=deb=; tar xvfz ../*.tar.gz + d=`pwd`; cd ..; dpkg-source -i -i'/\.svn/' -b $$d/dist/=deb=/* + rm -rf dist/=deb= + +.PHONY: binary binary-arch binary-indep clean install source build diff --git a/defs.pxi b/defs.pxi new file mode 100644 index 0000000..10502f7 --- /dev/null +++ b/defs.pxi @@ -0,0 +1,365 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Basic definitions, used all over +# +# (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. + +#----- C library ------------------------------------------------------------ + +cdef extern from 'errno.h': + int errno + enum: + EINTR + EAGAIN +cdef extern from 'limits.h': + enum: + LONG_MAX +cdef extern from 'math.h': + double modf(double x, double *i) +cdef extern from 'stddef.h': + ctypedef int size_t +cdef extern from 'string.h': + void memcpy(void *p, void *q, size_t n) + char *strerror(int err) + +#----- Unix interface ------------------------------------------------------- + +cdef extern from 'sys/types.h': + pass +cdef extern from 'sys/time.h': + struct timeval: + int tv_sec + int tv_usec + +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 + +#----- Python --------------------------------------------------------------- + +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) + object PyInt_FromLong(long i) + object PyLong_FromUnsignedLong(unsigned long i) + + ctypedef struct PyObject: + pass + ctypedef struct PyTypeObject: + pass + void Py_INCREF(PyObject *obj) + void Py_DECREF(PyObject *obj) + +#----- mLib basic stuff ----------------------------------------------------- + +cdef extern from 'mLib/alloc.h': + char *xstrdup(char *p) + void *xmalloc(size_t sz) + void xfree(void *p) + +cdef extern from 'mLib/bits.h': + ctypedef int uint32 + +cdef extern from 'mLib/dstr.h': + ctypedef struct dstr: + char *buf + int len + void DCREATE(dstr *d) + void dstr_destroy(dstr *d) + +#----- CRC32 ---------------------------------------------------------------- + +cdef extern from 'mLib/crc32.h': + uint32 c_crc32 "crc32" (uint32 a, void *p, int sz) + +#----- Universal hashing ---------------------------------------------------- + +cdef extern from 'mLib/unihash.h': + 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 + +#----- Symbol tables -------------------------------------------------------- + +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) + +#----- Atom stuff ----------------------------------------------------------- + +# --- Atoms --- +# +# Partly written in `real' C. + +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 *) + void atom_pysetup() + atom_pywrap(atom *a) + atom_pyintern(obj) + atom *ATOM_A(obj) + PyTypeObject atom_pytype + +# --- Association tables --- + +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) + +#----- Double-ended arrays -------------------------------------------------- + +cdef extern from 'array.h': + void da_pysetup() + PyTypeObject da_pytype + PyTypeObject daiter_pytype + +#----- Line buffer ---------------------------------------------------------- + +cdef extern from 'mLib/lbuf.h': + cdef struct lbuf: + int f + int delim + size_t sz + enum: + LBUF_ENABLE + _LBUF_CRLF "LBUF_CRLF" + _LBUF_STRICTCRLF "LBUF_STRICTCRLF" + void lbuf_flush(lbuf *b, char *p, size_t len) + void lbuf_close(lbuf *b) + size_t lbuf_free(lbuf *b, char **p) + void lbuf_setsize(lbuf *b, size_t sz) + void lbuf_enable(lbuf *b) + void lbuf_disable(lbuf *b) + void lbuf_init(lbuf *b, + void (*func)(char *s, size_t len, void *arg), void *arg) + void lbuf_destroy(lbuf *b) + +#----- Packet buffer -------------------------------------------------------- + +cdef extern from 'mLib/pkbuf.h': + ctypedef struct pkbuf: + int f + int want + enum: + PKBUF_ENABLE + void pkbuf_flush(pkbuf *pk, unsigned char *p, size_t len) + void pkbuf_close(pkbuf *pk) + size_t pkbuf_free(pkbuf *pk, unsigned char **p) + void pkbuf_want(pkbuf *pk, size_t sz) + void pkbuf_init(pkbuf *b, + void (*func)(unsigned char *s, size_t len, + pkbuf *pk, size_t *keep, void *arg), + void *arg) + void pkbuf_destroy(pkbuf *b) + +#----- Select stuff --------------------------------------------------------- + +# --- Basics --- + +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_READ" + _SEL_WRITE "SEL_WRITE" + _SEL_EXC "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 * + +# --- Non-blocking connection --- + +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) + +# --- Background name resolver --- + +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) + +# --- In-band signal handling --- + +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) + +# --- Line buffer --- + +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) + +# --- Packet buffer --- + +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) + +# --- Ident client --- + +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) + +#----- Error reporting ------------------------------------------------------ + +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) + +#----- Internal utilities --------------------------------------------------- + +cdef extern from 'grim.h': + int PSIZEOF(void *x) + +#----- That's all, folks ---------------------------------------------------- diff --git a/grim.h b/grim.h index d7ecbe2..80570a0 100644 --- a/grim.h +++ b/grim.h @@ -37,12 +37,10 @@ #include -/*----- Functions provided ------------------------------------------------*/ +/*----- Utilities ---------------------------------------------------------*/ #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) diff --git a/ident.pyx b/ident.pyx new file mode 100644 index 0000000..d19c3a4 --- /dev/null +++ b/ident.pyx @@ -0,0 +1,171 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Ident client +# +# (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. + +import socket + +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 SelIdentify: + cdef ident_request irq + cdef int _activep + cdef readonly localaddr + cdef readonly remoteaddr + cdef _user + cdef _bad + cdef _error + cdef _failed + cdef _bogus + def __new__(me, sk, + userproc = None, bogusproc = None, + badproc = None, errorproc = None, failedproc = None, + *hunoz, **hukairz): + 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, &s_in, &sz_in) or \ + getpeername(fd, &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, me) + me.localaddr = _inaddr_topy(&s_in) + me.remoteaddr = _inaddr_topy(&s_out) + me._activep = 1 + me._user = _checkcallable(userproc, 'user proc') + me._bad = _checkcallable(badproc, 'bad proc') + me._error = _checkcallable(errorproc, 'error proc') + me._failed = _checkcallable(failedproc, 'failed proc') + me._bogus = _checkcallable(bogusproc, 'bogus proc') + def __dealloc__(me): + if me._activep: + ident_abort(&me.irq) + property activep: + def __get__(me): + return _tobool(me._activep) + property userproc: + def __get__(me): + return me._user + def __set__(me, proc): + me._user = _checkcallable(proc, 'user proc') + def __del__(me): + me._user = None + property eofproc: + def __get__(me): + return me._eof + def __set__(me, proc): + me._eof = _checkcallable(proc, 'eof proc') + def __del__(me): + me._eof = None + property badproc: + def __get__(me): + return me._bad + def __set__(me, proc): + me._bad = _checkcallable(proc, 'bad proc') + def __del__(me): + me._bad = None + property errorproc: + def __get__(me): + return me._error + def __set__(me, proc): + me._error = _checkcallable(proc, 'error proc') + def __del__(me): + me._error = None + property failedproc: + def __get__(me): + return me._failed + def __set__(me, proc): + me._failed = _checkcallable(proc, 'failed proc') + def __del__(me): + me._failed = None + property bogusproc: + def __get__(me): + return me._bogus + def __set__(me, proc): + me._bogus = _checkcallable(proc, 'bogus proc') + def __del__(me): + me._bogus = None + def kill(me): + if not me._activep: + raise ValueError, 'already disabled' + ident_abort(&me.irq) + me._dead() + def _dead(me): + me._activep = 0 + me.dead() + def dead(me): + pass + def user(me, os, user): + return _maybecall(me._user, (os, user)) + def bad(me): + if me._bad is not None: + return me._bad() + return me.bogus() + def error(me, error): + if me._error is not None: + return me._error(error) + return me.bogus() + def failed(me, errno, strerror): + if me._failed is not None: + return me._failed(errno, strerror) + return me.bogus() + def bogus(me): + return _maybecall(me._bogus, ()) + +cdef void _identfunc(ident_reply *i, void *arg): + cdef SelIdentify id + id = arg + id._dead() + if i.type == IDENT_BAD: + id.bad() + elif i.type == IDENT_ERROR: + id.error(i.u.error) + elif i.type == IDENT_USERID: + id.user(i.u.userid.os, i.u.userid.user) + +#----- That's all, folks ---------------------------------------------------- diff --git a/lbuf.pyx b/lbuf.pyx new file mode 100644 index 0000000..820cba1 --- /dev/null +++ b/lbuf.pyx @@ -0,0 +1,131 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Line buffering +# +# (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. + +LBUF_CRLF = _LBUF_CRLF +LBUF_STRICTCRLF = _LBUF_STRICTCRLF + +cdef class LineBuffer: + cdef lbuf b + cdef _line + cdef _eof + def __new__(me, lineproc = None, eofproc = None, *hunoz, **hukairz): + lbuf_init(&me.b, _lbfunc, me) + me._line = _checkcallable(lineproc, 'line proc') + me._eof = _checkcallable(eofproc, 'eof proc') + def __dealloc__(me): + lbuf_destroy(&me.b) + property activep: + def __get__(me): + return _tobool(me.b.f & LBUF_ENABLE) + property delim: + def __get__(me): + if me.b.delim == _LBUF_CRLF or me.b.delim == _LBUF_STRICTCRLF: + return me.b.delim + else: + return chr(me.b.delim) + def __set__(me, d): + if d == _LBUF_CRLF or d == _LBUF_STRICTCRLF: + me.b.delim = d + else: + me.b.delim = ord(d) + property size: + def __get__(me): + return me.b.sz + def __set__(me, sz): + if sz <= 0: + raise TypeError, 'size must be positive' + lbuf_setsize(&me.b, sz) + property lineproc: + def __get__(me): + return me._line + def __set__(me, proc): + me._line = _checkcallable(proc, 'line proc') + def __del__(me): + me._line = None + property eofproc: + def __get__(me): + return me._eof + def __set__(me, proc): + me._eof = _checkcallable(proc, 'eof proc') + def __del__(me): + me._eof = None + def enable(me): + if me.b.f & LBUF_ENABLE: + raise ValueError, 'already enabled' + me.b.f = me.b.f | LBUF_ENABLE + me.enabled() + return me + def disable(me): + if not (me.b.f & LBUF_ENABLE): + raise ValueError, 'already disabled' + me.b.f = me.b.f & ~LBUF_ENABLE + me.disabled() + return me + def close(me): + if not (me.b.f & LBUF_ENABLE): + raise ValueError, 'buffer disabled' + lbuf_close(&me.b) + return me + property free: + def __get__(me): + cdef char *p + return lbuf_free(&me.b, &p) + def flush(me, str): + cdef int len + cdef char *p + cdef char *q + cdef size_t n + PyString_AsStringAndSize(str, &p, &len) + while len > 0: + n = lbuf_free(&me.b, &q) + if n > len: + n = len + memcpy(q, p, n) + p = p + n + len = len - n + if not (me.b.f & LBUF_ENABLE): + break + lbuf_flush(&me.b, q, n) + return PyString_FromStringAndSize(p, len) + def enabled(me): + pass + def disabled(me): + pass + def line(me, line): + return _maybecall(me._line, (line,)) + def eof(me): + return _maybecall(me._eof, ()) + +cdef void _lbfunc(char *s, size_t n, void *arg): + cdef LineBuffer sb + sb = arg + if s is NULL: + sb.eof() + else: + sb.line(PyString_FromStringAndSize(s, n)) + +#----- That's all, folks ---------------------------------------------------- diff --git a/mLib.pyx b/mLib.pyx new file mode 100644 index 0000000..098ca6b --- /dev/null +++ b/mLib.pyx @@ -0,0 +1,92 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Main driver for mLib module +# +# (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 stuff ------------------------------------------------------- + +include 'defs.pxi' + +#----- Various facilities --------------------------------------------------- + +# --- Internal utilities --- + +include 'utils.pyx' + +# --- Hashing --- + +include 'crc32.pyx' +include 'unihash.pyx' + +# --- Data structures --- + +include 'mapping.pyx' +include 'sym.pyx' +include 'atom.pyx' +include 'assoc.pyx' + +# --- Encodings --- + +include 'base64.pyx' +include 'base32.pyx' +include 'hex.pyx' + +# --- Error reporting --- + +include 'report.pyx' + +# --- Buffering --- + +include 'lbuf.pyx' +include 'pkbuf.pyx' + +# --- Select stuff --- + +include 'sel-base.pyx' +include 'sel-file.pyx' +include 'sel-timer.pyx' +include 'conn.pyx' +include 'bres.pyx' +include 'sig.pyx' +include 'selbuf.pyx' +include 'selpk.pyx' +include 'ident.pyx' + +#----- Set-up stuff --------------------------------------------------------- + +cdef object _tyobj(PyTypeObject *ty): + cdef PyObject *obj + obj = ty + Py_INCREF(obj) + return obj + +da_pysetup() +Array = _tyobj(&da_pytype) +ArrayIter = _tyobj(&daiter_pytype) + +atom_pysetup() +Atom = _tyobj(&atom_pytype) + +#----- That's all, folks ---------------------------------------------------- diff --git a/mLib/__init__.py b/mLib/__init__.py deleted file mode 100644 index 2ae2839..0000000 --- a/mLib/__init__.py +++ /dev/null @@ -1 +0,0 @@ -pass diff --git a/mapping.pyx b/mapping.pyx new file mode 100644 index 0000000..aa5de85 --- /dev/null +++ b/mapping.pyx @@ -0,0 +1,201 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Common mapping 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 class Mapping + +cdef class _MapIterator: + cdef void *_next(me): + return NULL + +cdef class Mapping: + + ## Subclasses must implement these + cdef int _init(me) except -1: + raise TypeError, 'abstract class' + cdef void *_find(me, object key, unsigned *f) except NULL: + raise SystemError, 'unimplemented _find' + cdef object _key(me, void *e): + return None + cdef object _value(me, void *e): + return None + cdef void _setval(me, void *e, object val): + pass + cdef void _del(me, void *e): + pass + cdef _MapIterator _iter(me): + raise SystemError, 'unimplemented _iter' + + ## Initialization + def __new__(me, *hunoz, **hukairz): + me._init() + def __init__(me, stuff = None, **kw): + me.update(stuff, kw) + + ## Bulk update + def update(me, stuff = None, **kw): + cdef unsigned f + if stuff is None: + pass + elif hasattr(stuff, 'itemiter'): + for k, v in stuff.itemiter: + me._setval(me._find(k, &f), v) + elif hasattr(stuff, 'keys'): + for k in stuff.keys(): + me._setval(me._find( k, &f), stuff[k]) + else: + for k, v in stuff: + me._setval(me._find(k, &f), v) + for k, v in kw.iteritems(): + me._setval(me._find(k, &f), v) + return me + + ## Item access + def __getitem__(me, key): + cdef void *e + e = me._find(key, NULL) + if not e: + raise KeyError, key + return me._value(e) + def __setitem__(me, key, value): + cdef unsigned f + me._setval(me._find(key, &f), value) + def __delitem__(me, key): + cdef void *e + cdef unsigned f + e = me._find(key, &f) + if not e: + raise KeyError, key + me._del(e) + def get(me, key, default = None): + cdef void *e + e = me._find(key, NULL) + if not e: + return default + return me._value(e) + def setdefault(me, key, default = None): + cdef void *e + cdef unsigned f + e = me._find(key, &f) + if f: + return me._value(e) + else: + me._setval(e, default) + return default + def pop(me, key, default = None): + cdef void *e + e = me._find(key, NULL) + if not e: + return default + rc = me._value(e) + me._del(e) + return rc + def popitem(me): + cdef _MapIterator i + cdef void *e + i = me._iter() + e = i._next() + if not e: + raise ValueError, 'popitem(): table is empty' + return me._key(e), me._value(e) + + ## Lists of items + cdef object _list(me, object (*func)(Mapping m, void *e)): + cdef _MapIterator i + cdef void *e + i = me._iter() + l = [] + while 1: + e = i._next() + if not e: + break + l.append(func(me, e)) + return l + + def keys(me): + return me._list(_map_key) + def values(me): + return me._list(_map_value) + def items(me): + return me._list(_map_item) + + def clear(me): + cdef _MapIterator i + cdef void *e + i = me._iter() + while 1: + e = i._next() + if not e: + break + me._del(e) + return me + + ## Iteration + def __iter__(me): + return MapKeyIter(me) + def iterkeys(me): + return MapKeyIter(me) + def itervalues(me): + return MapValueIter(me) + def iteritems(me): + return MapItemIter(me) + +cdef class MapIterBase: + cdef Mapping m + cdef object (*func)(Mapping m, void *e) + cdef _MapIterator i + cdef int _init(me) except -1: + raise TypeError, 'abstract class' + def __new__(me): + me.i = m._iter() + me._init() + def __next__(me): + cdef void *e + e = me.i._next() + if not e: + raise StopIteration + return me.func(me.m, e) +cdef class MapKeyIter (MapIterBase): + cdef int _init(me) except -1: + me.func = _map_key + return 0 +cdef class MapValueIter (MapIterBase): + cdef int _init(me) except -1: + me.func = _map_value + return 0 +cdef class MapItemIter (MapIterBase): + cdef int _init(me) except -1: + me.func = _map_item + return 0 + +cdef object _map_key(Mapping m, void *e): + return m._key(e) +cdef object _map_value(Mapping m, void *e): + return m._value(e) +cdef object _map_item(Mapping m, void *e): + return m._key(e), m._value(e) + +#----- That's all, folks ---------------------------------------------------- diff --git a/pkbuf.pyx b/pkbuf.pyx new file mode 100644 index 0000000..9626a98 --- /dev/null +++ b/pkbuf.pyx @@ -0,0 +1,127 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Packet buffering +# +# (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 class PacketBuffer: + cdef pkbuf pk + cdef _packet + cdef _eof + def __new__(me, packetproc = None, eofproc = None, *hunoz, **hukairz): + pkbuf_init(&me.pk, _pkfunc, me) + me._packet = _checkcallable(packetproc, 'packet proc') + me._eof = _checkcallable(eofproc, 'eof proc') + def __dealloc__(me): + pkbuf_destroy(&me.pk) + property activep: + def __get__(me): + return _tobool(me.pk.f & PKBUF_ENABLE) + property want: + def __get__(me): + return me.pk.want + def __set__(me, want): + if want <= 0: + raise TypeError, 'want must be positive' + pkbuf_want(&me.pk, pk) + property packetproc: + def __get__(me): + return me._packet + def __set__(me, proc): + me._line = _checkcallable(proc, 'packet proc') + def __del__(me): + me._line = None + property eofproc: + def __get__(me): + return me._eof + def __set__(me, proc): + me._eof = _checkcallable(proc, 'eof proc') + def __del__(me): + me._eof = None + def enable(me): + if me.pk.f & PKBUF_ENABLE: + raise ValueError, 'already enabled' + me.pk.f = me.pk.f | PKBUF_ENABLE + me.enabled() + return me + def disable(me): + if not (me.pk.f & PKBUF_ENABLE): + raise ValueError, 'already disabled' + me.pk.f = me.pk.f & ~PKBUF_ENABLE + me.disabled() + return me + def close(me): + if not (me.pk.f & PKBUF_ENABLE): + raise ValueError, 'buffer disabled' + pkbuf_close(&me.pk) + return me + property free: + def __get__(me): + cdef unsigned char *p + return pkbuf_free(&me.pk, &p) + def flush(me, str): + cdef int len + cdef unsigned char *p + cdef unsigned char *q + cdef size_t n + PyObject_AsReadBuffer(str, &p, &len) + while len > 0: + n = pkbuf_free(&me.pk, &q) + if n > len: + n = len + memcpy(q, p, n) + p = p + n + len = len - n + if not (me.pk.f & PKBUF_ENABLE): + break + pkbuf_flush(&me.pk, q, n) + return PyString_FromStringAndSize(p, len) + def enabled(me): + pass + def disabled(me): + pass + def packet(me, pk): + return _maybecall(me._packet, (pk,)) + def eof(me): + return _maybecall(me._eof, ()) + +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 = arg + if p is NULL: + pb.eof() + else: + r = pb.packet(PyString_FromStringAndSize(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 + +#----- That's all, folks ---------------------------------------------------- diff --git a/report.pyx b/report.pyx index e3749b4..cb368f6 100644 --- a/report.pyx +++ b/report.pyx @@ -25,24 +25,22 @@ # 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 = '' -def ego(prog): - _ego(prog) +cdef char *_progstring +_progstring = NULL + +def ego(char *prog): + global quis, _progstring + if _progstring: + xfree(_progstring) + _progstring = xstrdup(prog) + _ego(_progstring) quis = _quis() -def moan(msg): +def moan(char *msg): _moan('%s', msg) -def die(msg, rc = 1): +def die(char *msg, rc = 126): _moan('%s', msg) - sys.exit(rc) + raise SystemExit, rc #----- That's all, folks ---------------------------------------------------- diff --git a/sel-base.pyx b/sel-base.pyx new file mode 100644 index 0000000..e7b4fbe --- /dev/null +++ b/sel-base.pyx @@ -0,0 +1,36 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Select basic 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 sel_state _sel + +def select(): + if sel_select(&_sel) and errno != EINTR and errno != EAGAIN: + _oserror() + +sel_init(&_sel) + +#----- That's all, folks ---------------------------------------------------- diff --git a/sel-file.pyx b/sel-file.pyx new file mode 100644 index 0000000..72ff166 --- /dev/null +++ b/sel-file.pyx @@ -0,0 +1,96 @@ +# -*-pyrex-*- +# +# $Id$ +# +# File selectors +# +# (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. + +SEL_READ = _SEL_READ +SEL_WRITE = _SEL_WRITE +SEL_EXCEPT = _SEL_EXC + +cdef class SelFile: + cdef sel_file f + cdef int _activep + cdef readonly unsigned mode + cdef _readyfunc + def __new__(me, fd, int mode = SEL_READ, readyproc = None, + *hunoz, **hukairz): + 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, me) + me._activep = 0 + me.mode = mode + me._ready = _checkcallable(readyproc, 'ready proc') + 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) + property readyproc: + def __get__(me): + return me._ready + def __set__(me, proc): + me._ready = _checkcallable(proc, 'ready proc') + def __del__(me): + me._ready = None + def enable(me): + if me._activep: + raise ValueError, 'already enabled' + sel_addfile(&me.f) + me._enabled() + return me + def disable(me): + if not me._activep: + raise ValueError, 'already disabled' + sel_rmfile(&me.f) + me._disabled() + return me + def force(me): + sel_force(&me.f) + return me + cdef _enabled(me): + me._activep = 1 + me.enabled() + cdef _disabled(me): + me._activep = 0 + me.disabled() + def enabled(me): + pass + def disabled(me): + pass + def ready(me): + return _maybecall(me._ready, ()) + +cdef void _filefunc(int fd, unsigned mode, void *arg): + cdef SelFile sf + sf = arg + sf.ready() + +#----- That's all, folks ---------------------------------------------------- diff --git a/sel-timer.pyx b/sel-timer.pyx new file mode 100644 index 0000000..261ecde --- /dev/null +++ b/sel-timer.pyx @@ -0,0 +1,81 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Timer selectors +# +# (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 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 SelTimer: + cdef sel_timer t + cdef int _activep + cdef readonly double time + cdef _timer + def __new__(me, double when, timerproc = None, *hunoz, **hukairz): + cdef timeval tv + _floattotv(&tv, when) + sel_addtimer(&_sel, &me.t, &tv, _timerfunc, me) + me._activep = 1 + me.time = when + me._timer = _checkcallable(timerproc, 'timer proc') + def __dealloc__(me): + if me._activep: + sel_rmtimer(&me.t) + property activep: + def __get__(me): + return _tobool(me._activep) + property timerproc: + def __get__(me): + return me._timer + def __set__(me, proc): + me._timer = _checkcallable(proc, 'timer proc') + def __del__(me): + me._timer = None + def kill(me): + if not me._activep: + raise ValueError, 'already dead' + sel_rmtimer(&me.t) + me._dead() + return me + cdef _dead(me): + me._activep = 0 + me.dead() + def dead(me): + pass + def timer(me, now): + return _maybecall(me._timer, ()) + +cdef void _timerfunc(timeval *now, void *arg): + cdef SelTimer st + st = arg + st._dead() + st.timer(_tvtofloat(now)) + +#----- That's all, folks ---------------------------------------------------- diff --git a/selbuf.pyx b/selbuf.pyx new file mode 100644 index 0000000..4a5a288 --- /dev/null +++ b/selbuf.pyx @@ -0,0 +1,106 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Selecting line-buffers +# +# (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 class SelLineBuffer: + cdef selbuf b + cdef _line + cdef _eof + def __new__(me, fd, lineproc = None, eofproc = None, *hunoz, **hukairz): + selbuf_init(&me.b, &_sel, _getfd(fd), _selbfunc, me) + selbuf_disable(&me.b) + me._line = _checkcallable(lineproc, 'line proc') + me._eof = _checkcallable(eofproc, 'eof proc') + def __dealloc__(me): + selbuf_destroy(&me.b) + property activep: + def __get__(me): + return _tobool(me.b.b.f & LBUF_ENABLE) + property fd: + def __get__(me): + return me.b.reader.fd + 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): + if sz <= 0: + raise TypeError, 'size must be positive' + selbuf_setsize(&me.b, sz) + property lineproc: + def __get__(me): + return me._line + def __set__(me, proc): + me._line = _checkcallable(proc, 'line proc') + def __del__(me): + me._line = None + property eofproc: + def __get__(me): + return me._eof + def __set__(me, proc): + me._eof = _checkcallable(proc, 'eof proc') + def __del__(me): + me._eof = None + def enable(me): + if me.b.b.f & LBUF_ENABLE: + raise ValueError, 'already enabled' + selbuf_enable(&me.b) + me.enabled() + return me + def disable(me): + if not (me.b.b.f & LBUF_ENABLE): + raise ValueError, 'already disabled' + selbuf_disable(&me.b) + me.disabled() + return me + def enabled(me): + pass + def disabled(me): + pass + def line(me, line): + return _maybecall(me._line, (line,)) + def eof(me): + return _maybecall(me._eof, ()) + +cdef void _selbfunc(char *s, size_t n, void *arg): + cdef SelLineBuffer sb + sb = arg + if s is NULL: + sb.eof() + else: + sb.line(PyString_FromStringAndSize(s, n)) + +#----- That's all, folks ---------------------------------------------------- diff --git a/select.pyx b/select.pyx deleted file mode 100644 index 28fe05d..0000000 --- a/select.pyx +++ /dev/null @@ -1,634 +0,0 @@ -# -*-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, 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 = 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, 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 = 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, 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 = 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, 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, me) - me._activep = 1 - def __init__(me, addr): - pass - -cdef void _resfunc(hostent *h, void *arg): - cdef Resolve r - cdef int i - r = 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((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, 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 = 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, 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 = 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, 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 = arg - if p is NULL: - pb.eof() - else: - r = pb.packet(PyString_FromStringAndSize(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, &s_in, &sz_in) or \ - getpeername(fd, &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, 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 = 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 ---------------------------------------------------- diff --git a/selpk.pyx b/selpk.pyx new file mode 100644 index 0000000..fe85a9f --- /dev/null +++ b/selpk.pyx @@ -0,0 +1,105 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Selecting packet-buffer +# +# (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 class SelPacketBuffer: + cdef selpk p + cdef _packet + cdef _eof + def __new__(me, fd, packetproc = None, eofproc = None, *hunoz, **hukairz): + selpk_init(&me.p, &_sel, _getfd(fd), _selpkfunc, me) + selpk_disable(&me.p) + me._packet = _checkcallable(packetproc, 'packet proc') + me._eof = _checkcallable(eofproc, 'eof proc') + def __dealloc__(me): + selpk_destroy(&me.p) + property activep: + def __get__(me): + return _to_bool(me.p.pk.f & PKBUF_ENABLE) + property fd: + def __get__(me): + return me.p.reader.fd + property want: + def __get__(me): + return me.p.pk.want + def __set__(me, n): + if n <= 0: + raise TypeError, 'size must be positive' + selpk_want(&me.p, n) + property lineproc: + def __get__(me): + return me._line + def __set__(me, proc): + me._line = _checkcallable(proc, 'line proc') + def __del__(me): + me._line = None + property eofproc: + def __get__(me): + return me._eof + def __set__(me, proc): + me._eof = _checkcallable(proc, 'eof proc') + def __del__(me): + me._eof = None + def enable(me): + if me.p.pk.f & PKBUF_ENABLE: + raise ValueError, 'already enabled' + selpk_enable(&me.p) + me.enabled() + return me + def disable(me): + if not (me.p.pk.f & PKBUF_ENABLE): + raise ValueError, 'already disabled' + selpk_disable(&me.p) + me.disabled() + return me + def enabled(me): + pass + def disabled(me): + pass + def packet(me, pk): + return _maybecall(me._packet, (pk,)) + def eof(me): + return _maybecall(me._eof, ()) + +cdef void _selpkfunc(unsigned char *p, size_t n, pkbuf *pk, + size_t *keep, void *arg): + cdef SelPacketBuffer pb + cdef void *rp + cdef int rn + pb = arg + if p is NULL: + pb.eof() + else: + r = pb.packet(PyString_FromStringAndSize(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 + +#----- That's all, folks ---------------------------------------------------- diff --git a/setup.py b/setup.py index f8c091b..de8e515 100644 --- a/setup.py +++ b/setup.py @@ -51,24 +51,20 @@ def needs_update_p(target, sources): 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)) +def derive(target, src, subs): + if needs_update_p(target, [src]): + out = file(target + '.new', 'w') + for line in file(src): + out.write(rx_subst.sub((lambda m: subs[m.group(1)]), line)) out.close() - rename(src + '.new', src) - return src + rename(target + '.new', target) + +derive('base64.pyx', 'codec.pyx.in', + {'CLASS': 'Base64', 'PREFIX': 'base64'}) +derive('base32.pyx', 'codec.pyx.in', + {'CLASS': 'Base32', 'PREFIX': 'base32'}) +derive('hex.pyx', 'codec.pyx.in', + {'CLASS': 'Hex', 'PREFIX': 'hex'}) def mlibext(src): col = src.find('!') @@ -79,11 +75,13 @@ def mlibext(src): 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)) + +mlib = Extension('mLib', ['mLib.pyx', 'atom-base.c', 'array.c'], + + ##extra_compile_args = ['-O0'], + include_dirs = uniquify(incdirs), + library_dirs = uniquify(libdirs), + libraries = uniquify(libs)) setup(name = 'mLib-python', version = '1.0.0', @@ -91,12 +89,5 @@ setup(name = 'mLib-python', 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()], + ext_modules = [mlib], cmdclass = {'build_ext': build_ext}) diff --git a/sig.pyx b/sig.pyx new file mode 100644 index 0000000..17237f3 --- /dev/null +++ b/sig.pyx @@ -0,0 +1,86 @@ +# -*-pyrex-*- +# +# $Id$ +# +# In-band signals +# +# (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. + +import signal + +cdef class SelSignal: + cdef sig s + cdef int _activep + cdef readonly int signal + cdef _signalled + def __new__(me, int sig, signalledproc = None, *hunoz, **hukairz): + if sig < 0 or sig >= signal.NSIG: + raise ValueError, 'signal number out of range' + me.signal = sig + me._signalledproc = _checkcallable(signalledproc, 'signalled proc') + me._activep = 0 + def __dealloc__(me): + if me._activep: + sig_remove(&me.s) + property activep: + def __get__(me): + return _tobool(me._activep) + property signalledproc: + def __get__(me): + return me._signalled + def __set__(me, proc): + me._signalled = _checkcallable(proc, 'signalled proc') + def __del__(me): + me._signalled = None + def enable(me): + if me._activep: + raise ValueError, 'already enabled' + sig_add(&me.s, me.signal, _sigfunc, me) + me._enabled() + return me + def disable(me): + if not me._activep: + raise ValueError, 'already disabled' + sig_remove(&me.s) + me._disabled() + return me + cdef _enabled(me): + me._activep = 1 + me.enabled() + cdef _disabled(me): + me._activep = 0 + me.disabled() + def enabled(me): + pass + def disabled(me): + pass + def signalled(me): + return _maybecall(me._signalled, ()) + +cdef void _sigfunc(int sig, void *arg): + cdef SelSignal s + s = arg + s.signalled() + +sig_init(&_sel) + +#----- That's all, folks ---------------------------------------------------- diff --git a/sym.pyx b/sym.pyx index 4df3d9e..880d636 100644 --- a/sym.pyx +++ b/sym.pyx @@ -25,243 +25,58 @@ # 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: +cdef struct _sym_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 = sym_find(t, p, n, PSIZEOF(e), f) - if not f[0]: - e.v = NULL - else: - e = sym_find(t, p, n, 0, NULL) - return e - -cdef _eget(entry *e): - Py_INCREF(e.v) - return e.v - -cdef void _eset(entry *e, v): - if e.v: - Py_DECREF(e.v) - e.v = v - Py_INCREF(e.v) - -cdef void _edel(sym_table *t, entry *e): - if e.v: - Py_DECREF(e.v) - sym_remove(t, e) - -cdef _key(entry *e): - return PyString_FromStringAndSize(SYM_NAME(e), SYM_LEN(e)) - -cdef class Table: +cdef class SymTable (Mapping): cdef sym_table _t - def __new__(me, *hunoz, **hukairz): + cdef int _init(me) except -1: 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) + return 0 + cdef void *_find(me, object key, unsigned *f) except NULL: + cdef void *p + cdef int n + cdef _sym_entry *e + PyObject_AsReadBuffer(key, &p, &n) 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 = 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 = 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 = 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 = 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 = 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 = 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]) + f[0] = 0 + e = <_sym_entry *>sym_find(&me._t, p, n, PSIZEOF(e), f) + if not f[0]: + e.v = NULL 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 = 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 = sym_next(&me._i) - if not e: - raise StopIteration - return _eget(e) + e = <_sym_entry *>sym_find(&me._t, p, n, 0, NULL) + return e + cdef object _key(me, void *e): + return PyString_FromStringAndSize(SYM_NAME(e), SYM_LEN(e)) + cdef object _value(me, void *e): + cdef _sym_entry *ee + ee = <_sym_entry *>e + Py_INCREF(ee.v) + return ee.v + cdef void _setval(me, void *e, object val): + cdef _sym_entry *ee + ee = <_sym_entry *>e + if ee.v: + Py_DECREF(ee.v) + ee.v = v + Py_INCREF(ee.v) + cdef void _del(me, void *e): + cdef _sym_entry *ee + ee = <_sym_entry *>e + if ee.v: + Py_DECREF(ee.v) + sym_remove(&me._t, ee) + cdef _MapIterator _iter(me): + return _SymIter(me) -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 = sym_next(&me._i) - if not e: - raise StopIteration - return _key(e), _eget(e) +cdef class _SymIter (_MapIterator): + cdef SymTable t + cdef sym_iter i + def __new__(me, SymTable t): + me.t = t + sym_mkiter(&me.i, &me.t._t) + cdef void *_next(me): + return sym_next(&me.i) #----- That's all, folks ---------------------------------------------------- diff --git a/unihash.pyx b/unihash.pyx index f52e4af..b1cb979 100644 --- a/unihash.pyx +++ b/unihash.pyx @@ -25,30 +25,6 @@ # 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) diff --git a/utils.pyx b/utils.pyx new file mode 100644 index 0000000..6b62989 --- /dev/null +++ b/utils.pyx @@ -0,0 +1,59 @@ +# -*-pyrex-*- +# +# $Id$ +# +# Miscellaneous support gubbins +# +# (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 object _u32(uint32 x): + if x < LONG_MAX: + return PyInt_FromLong(x) + else: + return PyLong_FromUnsignedLong(x) + +cdef object _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() + +cdef object _checkcallable(f, what): + if f is not None and not callable(f): + raise TypeError, '%s must be callable' % what + return f + +cdef object _maybecall(f, args): + if f is None: + return None + return f(*args) + +#----- That's all, folks ---------------------------------------------------- -- [mdw]