General reorganization.
authormdw <mdw>
Tue, 18 Oct 2005 08:37:09 +0000 (08:37 +0000)
committermdw <mdw>
Tue, 18 Oct 2005 08:37:09 +0000 (08:37 +0000)
36 files changed:
MANIFEST.in
Makefile
array.c
array.h [new file with mode: 0644]
assoc.pyx [new file with mode: 0644]
atom-base.c
atom.h
atom.pyx
bres.pyx [new file with mode: 0644]
codec.pyx.in
conn.pyx [new file with mode: 0644]
crc32.pyx
debian/changelog [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
defs.pxi [new file with mode: 0644]
grim.h
ident.pyx [new file with mode: 0644]
lbuf.pyx [new file with mode: 0644]
mLib.pyx [new file with mode: 0644]
mLib/__init__.py [deleted file]
mapping.pyx [new file with mode: 0644]
pkbuf.pyx [new file with mode: 0644]
report.pyx
sel-base.pyx [new file with mode: 0644]
sel-file.pyx [new file with mode: 0644]
sel-timer.pyx [new file with mode: 0644]
selbuf.pyx [new file with mode: 0644]
select.pyx [deleted file]
selpk.pyx [new file with mode: 0644]
setup.py
sig.pyx [new file with mode: 0644]
sym.pyx
unihash.pyx
utils.pyx [new file with mode: 0644]

index b051d6b..38ad47f 100644 (file)
@@ -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
index 53ea323..7963e52 100644 (file)
--- 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 (file)
--- a/array.c
+++ b/array.c
@@ -36,6 +36,7 @@
 #include <mLib/dstr.h>
 #include <mLib/exc.h>
 
+#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 (file)
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 <Python.h>
+
+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 (file)
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 <void *>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 <object>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 = <PyObject *>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, <void *>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 ----------------------------------------------------
index 44b915b..e59fa2b 100644 (file)
@@ -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 (file)
--- 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 -------------------------------------------------*/
 
index 8fac74c..fc935f8 100644 (file)
--- a/atom.pyx
+++ b/atom.pyx
 # 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 = <entry *>assoc_find(t, a, PSIZEOF(e), f)
-    if not f[0]:
-      e.v = NULL
-  else:
-    e = <entry *>assoc_find(t, a, 0, NULL)
-  return e
-
-cdef _key(entry *e):
-  return atom_pywrap(ASSOC_ATOM(<void *>e))
-
-cdef _eget(entry *e):
-  Py_INCREF(e.v)
-  return <object>e.v
-
-cdef void _eset(entry *e, v):
-  if e.v:
-    Py_DECREF(e.v)
-  e.v = <PyObject *>v
-  Py_INCREF(e.v)
-
-cdef void _edel(assoc_table *t, entry *e):
-  if e.v:
-    Py_DECREF(e.v)
-  assoc_remove(t, <void *>e)
-
-cdef class Table:
-  cdef assoc_table _t
-  def __new__(me, *hunoz, **hukairz):
-    assoc_create(&me._t)
-  def __init__(me, stuff = None, **kw):
-    me.update(stuff, **kw)
-  def __getitem__(me, key):
-    cdef entry *e
-    e = _find(&me._t, key, NULL)
-    if not e:
-      raise KeyError, key
-    return _eget(e)
-  def __setitem__(me, key, value):
-    cdef unsigned f
-    _eset(_find(&me._t, key, &f), value)
-  def __delitem__(me, key):
-    cdef entry *e
-    cdef unsigned f
-    e = _find(&me._t, key, &f)
-    if not e:
-      raise KeyError, key
-    _edel(&me._t, e)
-  def get(me, key, default = None):
-    cdef entry *e
-    e = _find(&me._t, key, NULL)
-    if not e:
-      return default
-    return _eget(e)
-  def setdefault(me, key, default = None):
-    cdef entry *e
-    cdef unsigned f
-    e = _find(&me._t, key, &f)
-    if f:
-      return _eget(e)
-    else:
-      _eset(e, default)
-      return default
-  def pop(me, key, default = None):
-    cdef entry *e
-    e = _find(&me._t, key, NULL)
-    if not e:
-      return default
-    rc = _eget(e)
-    _edel(&me._t, e)
-    return rc
-  def popitem(me):
-    cdef entry *e
-    cdef assoc_iter i
-    assoc_mkiter(&i, &me._t)
-    e = <entry *>assoc_next(&i)
-    if not e:
-      raise ValueError, 'popitem(): table is empty'
-    return _key(e), _eget(e)
-  def keys(me):
-    cdef assoc_iter i
-    cdef entry *e
-    l = []
-    assoc_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>assoc_next(&i)
-      if not e:
-        break
-      l.append(_key(e))
-    return l
-  def values(me):
-    cdef assoc_iter i
-    cdef entry *e
-    l = []
-    assoc_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>assoc_next(&i)
-      if not e:
-        break
-      l.append(_eget(e))
-    return l
-  def items(me):
-    cdef assoc_iter i
-    cdef entry *e
-    l = []
-    assoc_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>assoc_next(&i)
-      if not e:
-        break
-      l.append((_key(e), _eget(e)))
-    return l
-  def clear(me):
-    cdef assoc_iter i
-    cdef entry *e
-    assoc_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>assoc_next(&i)
-      if not e:
-        break
-      _edel(&me._t, e)
-    return me
-  def __dealloc__(me):
-    cdef assoc_iter i
-    cdef entry *e
-    assoc_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>assoc_next(&i)
-      if not e:
-        break
-      _edel(&me._t, e)
-    assoc_destroy(&me._t)
-  def iterkeys(me):
-    return KeyIter(me)
-  def __iter__(me):
-    return KeyIter(me)
-  def itervalues(me):
-    return ValueIter(me)
-  def iteritems(me):
-    return ItemIter(me)
-  def update(me, stuff = None, **kw):
-    if stuff is None:
-      pass
-    elif hasattr(stuff, 'keys'):
-      for k in stuff:
-        me[k] = stuff[k]
-    else:
-      for k, v in stuff:
-        me[k] = v
-    for k, v in kw.iteritems():
-      me[k] = kw[k]
-    return me
-
-cdef class KeyIter:
-  cdef Table _t
-  cdef assoc_iter _i
-  def __new__(me, Table t):
-    me._t = t
-    assoc_mkiter(&me._i, &t._t)
-  def __iter__(me):
-    return me
-  def __next__(me):
-    cdef entry *e
-    e = <entry *>assoc_next(&me._i)
-    if not e:
-      raise StopIteration
-    return _key(e)
-
-cdef class ValueIter:
-  cdef Table _t
-  cdef assoc_iter _i
-  def __new__(me, Table t):
-    me._t = t
-    assoc_mkiter(&me._i, &t._t)
-  def __iter__(me):
-    return me
-  def __next__(me):
-    cdef entry *e
-    e = <entry *>assoc_next(&me._i)
-    if not e:
-      raise StopIteration
-    return _eget(e)
-
-cdef class ItemIter:
-  cdef Table _t
-  cdef assoc_iter _i
-  def __new__(me, Table t):
-    me._t = t
-    assoc_mkiter(&me._i, &t._t)
-  def __iter__(me):
-    return me
-  def __next__(me):
-    cdef entry *e
-    e = <entry *>assoc_next(&me._i)
-    if not e:
-      raise StopIteration
-    return _key(e), _eget(e)
-
-Atom = atom_pystartup()
-
 #----- That's all, folks ----------------------------------------------------
diff --git a/bres.pyx b/bres.pyx
new file mode 100644 (file)
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, <void *>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, <void *>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 = <SelResolve>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((<in_addr *>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 ----------------------------------------------------
index 60d9714..ebbb38e 100644 (file)
 
 #----- 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 (file)
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, <void *>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 = <SelConnect>arg
+  c._dead()
+  if fd == -1:
+    c.socket = None
+    c.error(errno, strerror(errno))
+  else:
+    c.connected()
+
+#----- That's all, folks ----------------------------------------------------
index d5e0239..77bc863 100644 (file)
--- a/crc32.pyx
+++ b/crc32.pyx
 # 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 (file)
index 0000000..32301da
--- /dev/null
@@ -0,0 +1,5 @@
+python-mlib (1.0.0) experimental; urgency=low
+
+  * Debianization!
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Thu, 13 Oct 2005 18:14:18 +0100
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..576aa11
--- /dev/null
@@ -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 <mdw@distorted.org.uk>
+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 (file)
index 0000000..5c1a437
--- /dev/null
@@ -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 (executable)
index 0000000..71ecdda
--- /dev/null
@@ -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 (file)
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 (file)
--- a/grim.h
+++ b/grim.h
 
 #include <Python.h>
 
-/*----- 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 (file)
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, <sockaddr *>&s_in, &sz_in) or \
+         getpeername(fd, <sockaddr *>&s_out, &sz_out):
+        _oserror()
+      if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET:
+        raise TypeError, 'must be internet socket'
+    elif len(sk) != 2:
+      raise TypeError, 'want pair of addresses'
+    else:
+      _inaddr_frompy(&s_in, sk[0])
+      _inaddr_frompy(&s_out, sk[1])
+    ident(&me.irq, &_sel, &s_in, &s_out, _identfunc, <void *>me)
+    me.localaddr = _inaddr_topy(&s_in)
+    me.remoteaddr = _inaddr_topy(&s_out)
+    me._activep = 1
+    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 = <SelIdentify>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 (file)
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, <void *>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 = <LineBuffer>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 (file)
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 = <PyObject *>ty
+  Py_INCREF(obj)
+  return <object>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 (file)
index 2ae2839..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pass
diff --git a/mapping.pyx b/mapping.pyx
new file mode 100644 (file)
index 0000000..aa5de85
--- /dev/null
@@ -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 (file)
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, <void *>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, <void **>&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(<char *>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 = <PacketBuffer>arg
+  if p is NULL:
+    pb.eof()
+  else:
+    r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
+    if r is not None:
+      PyObject_AsReadBuffer(r, &rp, &rn)
+      if rn > n:
+        raise ValueError, 'remaining buffer too large'
+      if rn:
+        memcpy(p + n - rn, rp, rn)
+        keep[0] = rn
+
+#----- That's all, folks ----------------------------------------------------
index e3749b4..cb368f6 100644 (file)
 # along with mLib/Python; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-cdef extern from 'mLib/quis.h':
-  void _ego "ego"(char *prog)
-  char *_quis "quis"()
-
-cdef extern from 'mLib/report.h':
-  void _moan "moan"(char *f, char *msg)
-
-import sys
-
 quis = '<UNNAMED>'
-def ego(prog):
-  _ego(prog)
+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 (file)
index 0000000..e7b4fbe
--- /dev/null
@@ -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 (file)
index 0000000..72ff166
--- /dev/null
@@ -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, <void *>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 = <SelFile>arg
+  sf.ready()
+
+#----- That's all, folks ----------------------------------------------------
diff --git a/sel-timer.pyx b/sel-timer.pyx
new file mode 100644 (file)
index 0000000..261ecde
--- /dev/null
@@ -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, <void *>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 = <SelTimer>arg
+  st._dead()
+  st.timer(_tvtofloat(now))
+
+#----- That's all, folks ----------------------------------------------------
diff --git a/selbuf.pyx b/selbuf.pyx
new file mode 100644 (file)
index 0000000..4a5a288
--- /dev/null
@@ -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, <void *>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 = <SelLineBuffer>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 (file)
index 28fe05d..0000000
+++ /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, <void *>me)
-    me._activep = 0
-    me.mode = mode
-  def __dealloc__(me):
-    if me._activep:
-      sel_rmfile(&me.f)
-  property fd:
-    def __get__(me):
-      return me.f.fd
-  property activep:
-    def __get__(me):
-      return _tobool(me._activep)
-  def enable(me):
-    if me._activep:
-      raise ValueError, 'already enabled'
-    sel_addfile(&me.f)
-    me._activep = 1
-    return me
-  def disable(me):
-    if not me._activep:
-      raise ValueError, 'already disabled'
-    sel_rmfile(&me.f)
-    me._activep = 0
-    return me
-  def force(me):
-    sel_force(&me.f)
-    return me
-  def ready(me):
-    pass
-
-cdef void _filefunc(int fd, unsigned mode, void *arg):
-  cdef File sf
-  sf = <File>arg
-  sf.ready()
-
-#----- Timer selectors ------------------------------------------------------
-
-cdef double _tvtofloat(timeval *tv):
-  return tv.tv_sec + (tv.tv_usec / 1000000)
-cdef void _floattotv(timeval *tv, double t):
-  cdef double s, us
-  us = modf(t, &s)
-  tv.tv_sec = s
-  tv.tv_usec = us * 1000000
-
-cdef class Timer:
-  cdef sel_timer t
-  cdef int _activep
-  cdef readonly double time
-  def __new__(me, double when):
-    cdef timeval tv
-    _floattotv(&tv, when)
-    sel_addtimer(&sel, &me.t, &tv, _timerfunc, <void *>me)
-    me._activep = 1
-    me.time = when
-  def __dealloc__(me):
-    if me._activep:
-      sel_rmtimer(&me.t)
-  property activep:
-    def __get__(me):
-      return _tobool(me._activep)
-  def kill(me):
-    if not me._activep:
-      raise ValueError, 'already dead'
-    sel_rmtimer(&me.t)
-    me._activep = 0
-    return me
-  def timer(me, now):
-    pass
-
-cdef void _timerfunc(timeval *now, void *arg):
-  cdef Timer st
-  st = <Timer>arg
-  st._activep = 0
-  st.timer(_tvtofloat(now))
-
-#----- Connections ----------------------------------------------------------
-
-cdef class Connect:
-  cdef conn c
-  cdef int _activep
-  cdef readonly object socket
-  def __new__(me, sk):
-    conn_fd(&me.c, &sel, sk.fileno(), _connfunc, <void *>me)
-    me._activep = 1
-    me.socket = sk
-  def __dealloc__(me):
-    if me._activep:
-      conn_kill(&me.c)
-  property activep:
-    def __get__(me):
-      return _tobool(me._activep)
-  def kill(me):
-    if not me._activep:
-      raise ValueError, 'already dead'
-    conn_kill(&me.c);
-    me._activep = 0
-    return me
-  def connected(me):
-    pass
-  def error(me, errno, strerror):
-    pass
-
-cdef void _connfunc(int fd, void *arg):
-  cdef Connect c
-  c = <Connect>arg
-  c._activep = 0
-  if fd == -1:
-    c.socket = None
-    c.error(errno, strerror(errno))
-  else:
-    c.connected()
-
-#----- Background name resolution -------------------------------------------
-
-cdef class Resolve:
-  cdef bres_client r
-  cdef int _activep
-  def __init__(me, *hunoz, **hukairz):
-    raise TypeError, 'abstract class'
-  property activep:
-    def __get__(me):
-      return _tobool(me._activep)
-  def kill(me):
-    if not me._activep:
-      raise ValueError, 'already dead'
-    bres_abort(&me.r)
-    return me
-  def resolved(me, h):
-    pass
-  def failed(me):
-    pass
-
-cdef class ResolveByName (Resolve):
-  def __new__(me, char *name):
-    bres_byname(&me.r, name, _resfunc, <void *>me)
-    me._activep = 1
-  def __init__(me, name):
-    pass
-
-cdef class ResolveByAddr (Resolve):
-  def __new__(me, char *addr):
-    cdef in_addr ia
-    if not inet_aton(addr, &ia):
-      raise TypeError, 'bad IP address'
-    bres_byaddr(&me.r, ia, _resfunc, <void *>me)
-    me._activep = 1
-  def __init__(me, addr):
-    pass
-
-cdef void _resfunc(hostent *h, void *arg):
-  cdef Resolve r
-  cdef int i
-  r = <Resolve>arg
-  r._activep = 0
-  if h is NULL:
-    r.failed(r)
-  else:
-    alias = []
-    addr = []
-    i = 0
-    while h.h_aliases[i]:
-      alias.append(h.h_aliases[i])
-      i = i + 1
-    i = 0
-    while h.h_addr_list[i]:
-      addr.append(inet_ntoa((<in_addr *>h.h_addr_list[i])[0]))
-      i = i + 1
-    r.resolved(h.h_name, alias, addr)
-
-#----- Signal handling ------------------------------------------------------
-
-cdef class Signal:
-  cdef sig s
-  cdef int _activep
-  cdef readonly int signal
-  def __new__(me, int sig):
-    if sig < 0 or sig >= signal.NSIG:
-      raise ValueError, 'signal number out of range'
-    me.signal = sig
-    me._activep = 0
-  def __dealloc__(me):
-    if me._activep:
-      sig_remove(&me.s)
-  def enable(me):
-    if me._activep:
-      raise ValueError, 'already enabled'
-    sig_add(&me.s, me.signal, _sigfunc, <void *>me)
-    me._activep = 1
-    return me
-  def disable(me):
-    if not me._activep:
-      raise ValueError, 'already disabled'
-    sig_remove(&me.s)
-    me._activep = 0
-    return me
-  def signalled(me):
-    pass
-
-cdef void _sigfunc(int sig, void *arg):
-  cdef Signal s
-  s = <Signal>arg
-  s.signalled()
-
-#----- Line buffers ---------------------------------------------------------
-
-CRLF = LBUF_CRLF
-STRICTCRLF = LBUF_STRICTCRLF
-
-cdef class LineBuffer:
-  cdef selbuf b
-  def __new__(me, fd):
-    selbuf_init(&me.b, &sel, _getfd(fd), _lbfunc, <void *>me)
-    selbuf_disable(&me.b)
-  def __dealloc__(me):
-    selbuf_destroy(&me.b)
-  property activep:
-    def __get__(me):
-      return _tobool(me.b.b.f & LFBUF_ENABLE)
-  property delim:
-    def __get__(me):
-      if me.b.b.delim == LBUF_CRLF or me.b.b.delim == LBUF_STRICTCRLF:
-        return me.b.b.delim
-      else:
-        return chr(me.b.b.delim)
-    def __set__(me, d):
-      if d == LBUF_CRLF or d == LBUF_STRICTCRLF:
-        me.b.b.delim = d
-      else:
-        me.b.b.delim = ord(d)
-  property size:
-    def __get__(me):
-      return me.b.b.sz
-    def __set__(me, sz):
-      selbuf_setsize(&me.b, sz)
-  def enable(me):
-    if me.b.b.f & LBUF_ENABLE:
-      raise ValueError, 'already enabled'
-    selbuf_enable(&me.b)
-    return me
-  def disable(me):
-    if not (me.b.b.f & LBUF_ENABLE):
-      raise ValueError, 'already disabled'
-    selbuf_disable(&me.b)
-    return me
-  def line(me, line):
-    pass
-  def eof(me):
-    pass
-
-cdef void _lbfunc(char *s, size_t n, void *arg):
-  cdef LineBuffer sb
-  sb = <LineBuffer>arg
-  if s is NULL:
-    sb.eof()
-  else:
-    sb.line(PyString_FromStringAndSize(s, n))
-
-#----- Packet buffers -------------------------------------------------------
-
-cdef class PacketBuffer:
-  cdef selpk p
-  def __new__(me, fd):
-    selpk_init(&me.p, &sel, _getfd(fd), _pkfunc, <void *>me)
-    selpk_disable(&me.p)
-  def __dealloc__(me):
-    selpk_destroy(&me.p)
-  property activep:
-    def __get__(me):
-      return _to_bool(me.p.pk.f & PKBUF_ENABLE)
-  property want:
-    def __get__(me):
-      return me.p.pk.want
-    def __set__(me, n):
-      selpk_want(&me.p, n)
-  def enable(me):
-    if me.p.pk.f & PKBUF_ENABLE:
-      raise ValueError, 'already enabled'
-    selpk_enable(&me.p)
-    return me
-  def disable(me):
-    if not (me.p.pk.f & PKBUF_ENABLE):
-      raise ValueError, 'already disabled'
-    selpk_disable(&me.p)
-    return me
-  def packet(me, pk):
-    return None
-  def eof(me):
-    pass
-
-cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk,
-                  size_t *keep, void *arg):
-  cdef PacketBuffer pb
-  cdef void *rp
-  cdef int rn
-  pb = <PacketBuffer>arg
-  if p is NULL:
-    pb.eof()
-  else:
-    r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
-    if r is not None:
-      PyObject_AsReadBuffer(r, &rp, &rn)
-      if rn > n:
-        raise ValueError, 'remaining buffer too large'
-      if rn:
-        memcpy(p + n - rn, rp, rn)
-        keep[0] = rn
-
-#----- Ident client ---------------------------------------------------------
-
-cdef _inaddr_frompy(sockaddr_in *sin, addr):
-  cdef int port
-  if len(addr) != 2:
-    raise TypeError, 'want address/port pair'
-  a = addr[0]
-  if not inet_aton(a, &sin.sin_addr):
-    raise TypeError, 'bad IP address'
-  port = addr[1]
-  if not (0 <= port < 65536):
-    raise TypeError, 'port number out of range'
-  sin.sin_port = htons(port)
-
-cdef _inaddr_topy(sockaddr_in *sin):
-  return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)
-
-cdef class Identify:
-  cdef ident_request irq
-  cdef int _activep
-  cdef readonly localaddr
-  cdef readonly remoteaddr
-  def __new__(me, sk):
-    cdef sockaddr_in s_in, s_out
-    cdef size_t sz_in, sz_out
-    cdef int fd
-    if PyObject_TypeCheck(sk, socket.SocketType):
-      fd = sk.fileno()
-      sz_in = PSIZEOF(&s_in)
-      sz_out = PSIZEOF(&s_out)
-      if getsockname(fd, <sockaddr *>&s_in, &sz_in) or \
-         getpeername(fd, <sockaddr *>&s_out, &sz_out):
-        _oserror()
-      if s_in.sin_family != AF_INET or s_out.sin_family != AF_INET:
-        raise TypeError, 'must be internet socket'
-    elif len(sk) != 2:
-      raise TypeError, 'want pair of addresses'
-    else:
-      _inaddr_frompy(&s_in, sk[0])
-      _inaddr_frompy(&s_out, sk[1])
-    ident(&me.irq, &sel, &s_in, &s_out, _identfunc, <void *>me)
-    me.localaddr = _inaddr_topy(&s_in)
-    me.remoteaddr = _inaddr_topy(&s_out)
-    me._activep = 1
-  def __dealloc__(me):
-    if me._activep:
-      ident_abort(&me.irq)
-  property activep:
-    def __get__(me):
-      return _tobool(me._activep)
-  def kill(me):
-    if not me._activep:
-      raise ValueError, 'already disabled'
-    ident_abort(&me.irq)
-    me._activep = 0
-  def user(me, os, user):
-    pass
-  def bad(me):
-    pass
-  def error(me, error):
-    pass
-  def failed(me, errno, strerror):
-    pass
-
-cdef void _identfunc(ident_reply *i, void *arg):
-  cdef Identify id
-  id = <Identify>arg
-  id._activep = 0
-  if i.type == IDENT_BAD:
-    ii.bad()
-  elif i.type == IDENT_ERROR:
-    ii.error(i.u.error)
-  elif i.type == IDENT_USER:
-    ii.user(i.u.userid.os, i.u.userid.user)
-
-#----- That's all, folks ----------------------------------------------------
diff --git a/selpk.pyx b/selpk.pyx
new file mode 100644 (file)
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, <void *>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 = <SelPacketBuffer>arg
+  if p is NULL:
+    pb.eof()
+  else:
+    r = pb.packet(PyString_FromStringAndSize(<char *>p, n))
+    if r is not None:
+      PyObject_AsReadBuffer(r, &rp, &rn)
+      if rn > n:
+        raise ValueError, 'remaining buffer too large'
+      if rn:
+        memcpy(p + n - rn, rp, rn)
+        keep[0] = rn
+
+#----- That's all, folks ----------------------------------------------------
index f8c091b..de8e515 100644 (file)
--- 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 (file)
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, <void *>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 = <SelSignal>arg
+  s.signalled()
+
+sig_init(&_sel)
+
+#----- That's all, folks ----------------------------------------------------
diff --git a/sym.pyx b/sym.pyx
index 4df3d9e..880d636 100644 (file)
--- a/sym.pyx
+++ b/sym.pyx
 # 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 = <entry *>sym_find(t, <char *>p, n, PSIZEOF(e), f)
-    if not f[0]:
-      e.v = NULL
-  else:
-    e = <entry *>sym_find(t, <char *>p, n, 0, NULL)
-  return e
-
-cdef _eget(entry *e):
-  Py_INCREF(e.v)
-  return <object>e.v
-
-cdef void _eset(entry *e, v):
-  if e.v:
-    Py_DECREF(e.v)
-  e.v = <PyObject *>v
-  Py_INCREF(e.v)
-
-cdef void _edel(sym_table *t, entry *e):
-  if e.v:
-    Py_DECREF(e.v)
-  sym_remove(t, <void *>e)
-
-cdef _key(entry *e):
-  return PyString_FromStringAndSize(SYM_NAME(<void *>e), SYM_LEN(<void *>e))
-
-cdef class Table:
+cdef 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 = <entry *>sym_next(&i)
-    if not e:
-      raise ValueError, 'popitem(): table is empty'
-    return _key(e), _eget(e)
-  def keys(me):
-    cdef sym_iter i
-    cdef entry *e
-    l = []
-    sym_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>sym_next(&i)
-      if not e:
-        break
-      l.append(_key(e))
-    return l
-  def values(me):
-    cdef sym_iter i
-    cdef entry *e
-    l = []
-    sym_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>sym_next(&i)
-      if not e:
-        break
-      l.append(_eget(e))
-    return l
-  def items(me):
-    cdef sym_iter i
-    cdef entry *e
-    l = []
-    sym_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>sym_next(&i)
-      if not e:
-        break
-      l.append((_key(e), _eget(e)))
-    return l
-  def clear(me):
-    cdef sym_iter i
-    cdef entry *e
-    sym_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>sym_next(&i)
-      if not e:
-        break
-      _edel(&me._t, e)
-    return me
-  def __dealloc__(me):
-    cdef sym_iter i
-    cdef entry *e
-    sym_mkiter(&i, &me._t)
-    while 1:
-      e = <entry *>sym_next(&i)
-      if not e:
-        break
-      _edel(&me._t, e)
-    sym_destroy(&me._t)
-  def iterkeys(me):
-    return KeyIter(me)
-  def __iter__(me):
-    return KeyIter(me)
-  def itervalues(me):
-    return ValueIter(me)
-  def iteritems(me):
-    return ItemIter(me)
-  def update(me, stuff = None, **kw):
-    cdef unsigned f
-    if stuff is None:
-      pass
-    elif hasattr(stuff, 'itemiter'):
-      for k, v in stuff.itemiter:
-        _eset(_find(&me._t, k, &f), v)
-    elif hasattr(stuff, 'keys'):
-      for k in stuff.keys():
-        _eset(_find(&me._t, k, &f), stuff[k])
+      f[0] = 0
+      e = <_sym_entry *>sym_find(&me._t, <char *>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 = <entry *>sym_next(&me._i)
-    if not e:
-      raise StopIteration
-    return _key(e)
-
-cdef class ValueIter:
-  cdef Table _t
-  cdef sym_iter _i
-  def __new__(me, Table t):
-    me._t = t
-    sym_mkiter(&me._i, &t._t)
-  def __iter__(me):
-    return me
-  def __next__(me):
-    cdef entry *e
-    e = <entry *>sym_next(&me._i)
-    if not e:
-      raise StopIteration
-    return _eget(e)
+      e = <_sym_entry *>sym_find(&me._t, <char *>p, n, 0, NULL)
+    return <void *>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 <object>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 = <PyObject *>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, <void *>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 = <entry *>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 ----------------------------------------------------
index f52e4af..b1cb979 100644 (file)
 # 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 (file)
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 ----------------------------------------------------