### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###--------------------------------------------------------------------------
-### Base classes.
-
-cdef extern from 'mLib/codec.h':
-
- ctypedef struct codec
-
- ctypedef struct codec_class:
- char *name
- codec *(*encoder)(unsigned f, char *ind, unsigned max)
- codec *(*decoder)(unsigned f)
-
- ctypedef struct codec_ops:
- codec_class *c
- int (*code)(codec *c, void *p, size_t, dstr *d)
- void (*destroy)(codec *c)
- ctypedef struct codec:
- codec_ops *ops
-
- enum:
- CDCF_LOWERC
- CDCF_IGNCASE
- CDCF_NOEQPAD
- CDCF_IGNEQPAD
- CDCF_IGNEQMID
- CDCF_IGNZPAD
- CDCF_IGNNEWL
- CDCF_IGNSPC
- CDCF_IGNINVCH
- CDCF_IGNJUNK
-
- enum:
- CDCERR_OK
- CDCERR_INVCH
- CDCERR_INVEQPAD
- CDCERR_INVZPAD
-
- char *_codec_strerror "codec_strerror"(int err)
+### Constants.
+
+CDCF_LOWERC = _CDCF_LOWERC
+CDCF_IGNCASE = _CDCF_IGNCASE
+CDCF_NOEQPAD = _CDCF_NOEQPAD
+CDCF_IGNEQPAD = _CDCF_IGNEQPAD
+CDCF_IGNEQMID = _CDCF_IGNEQMID
+CDCF_IGNZPAD = _CDCF_IGNZPAD
+CDCF_IGNNEWL = _CDCF_IGNNEWL
+CDCF_IGNSPC = _CDCF_IGNSPC
+CDCF_IGNINVCH = _CDCF_IGNINVCH
+CDCF_IGNJUNK = _CDCF_IGNJUNK
class CDCF:
- LOWERC = CDCF_LOWERC
- IGNCASE = CDCF_IGNCASE
- NOEQPAD = CDCF_NOEQPAD
- IGNEQPAD = CDCF_IGNEQPAD
- IGNEQMID = CDCF_IGNEQMID
- IGNZPAD = CDCF_IGNZPAD
- IGNNEWL = CDCF_IGNNEWL
- IGNSPC = CDCF_IGNSPC
- IGNINVCH = CDCF_IGNINVCH
- IGNJUNK = CDCF_IGNJUNK
+ ## DEPRECATED. Use the original names at module level.
+ LOWERC = _CDCF_LOWERC
+ IGNCASE = _CDCF_IGNCASE
+ NOEQPAD = _CDCF_NOEQPAD
+ IGNEQPAD = _CDCF_IGNEQPAD
+ IGNEQMID = _CDCF_IGNEQMID
+ IGNZPAD = _CDCF_IGNZPAD
+ IGNNEWL = _CDCF_IGNNEWL
+ IGNSPC = _CDCF_IGNSPC
+ IGNINVCH = _CDCF_IGNINVCH
+ IGNJUNK = _CDCF_IGNJUNK
+
+CDCERR_OK = _CDCERR_OK
+CDCERR_INVCH = _CDCERR_INVCH
+CDCERR_INVEQPAD = _CDCERR_INVEQPAD
+CDCERR_INVZPAD = _CDCERR_INVZPAD
class CDCERR:
- OK = CDCERR_OK
- INVCH = CDCERR_INVCH
- INVEQPAD = CDCERR_INVEQPAD
- INVZPAD = CDCERR_INVZPAD
+ ## DEPRECATED. Use the original names at module level.
+ OK = _CDCERR_OK
+ INVCH = _CDCERR_INVCH
+ INVEQPAD = _CDCERR_INVEQPAD
+ INVZPAD = _CDCERR_INVZPAD
+
+###--------------------------------------------------------------------------
+### Base classes.
class CodecError (Exception):
"""
Exception from decoding operation.
- Attributes: err = CDCERR.* code, msg = message string
+ Attributes: `err' = `CDCERR_*' code, `msg' = message string
"""
def __init__(me, err):
me.err = err
- me.msg = _codec_strerror(err)
+ me.msg = <str>_codec_strerror(err)
def __str__(me):
return me.msg
def codec_strerror(err):
- """codec_strerror(ERR) -> STR: message for CDCERR.* code"""
- return _codec_strerror(err)
-
-cdef int code(codec *c, void *p, size_t len, dstr *d) except -1:
- cdef int err
- err = c.ops.code(c, p, len, d)
- if err:
- raise CodecError(err)
- return 0
+ """codec_strerror(ERR) -> STR: message for `CDCERR_*' code"""
+ return <str>_codec_strerror(err)
cdef class _BaseCodec:
"""Abstract superclass for codecs."""
cdef codec *c
def __cinit__(me, *hunoz, **hukairz):
me.c = NULL
- def __init__(me, *hunoz, **hukairz):
- raise TypeError, 'abstract class'
def __dealloc__(me):
if me.c is not NULL:
me.c.ops.destroy(me.c)
- cdef code(me, text, int finishp):
- cdef void *p
- cdef Py_ssize_t len
- cdef dstr d
+ def __init__(me, *hunoz, **hukairz):
+ raise TypeError('abstract class')
+ cdef int _code(me, const void *p, Py_ssize_t sz,
+ dstr *d, bint finishp) except -1:
cdef int err
if me.c is NULL:
- raise ValueError, 'Encoding finished'
- DCREATE(&d)
- try:
- PyObject_AsReadBuffer(text, <cvp *>&p, &len)
- code(me.c, p, len, &d)
- if finishp:
- code(me.c, NULL, 0, &d)
- me.c.ops.destroy(me.c)
- me.c = NULL
- return PyString_FromStringAndSize(d.buf, d.len)
- finally:
- dstr_destroy(&d)
+ raise ValueError('Encoding finished')
+ err = me.c.ops.code(me.c, p, sz, d)
+ if err:
+ raise CodecError(err)
+ if finishp:
+ err = me.c.ops.code(me.c, p, sz, d)
+ me.c.ops.destroy(me.c)
+ me.c = NULL
+ if err:
+ raise CodecError(err)
+ return 0
+
def done(me):
"""C.done() -> OUT: final output"""
me.code('', True)
cdef class _BaseEncoder (_BaseCodec):
- def encode(me, text, finishp = False):
+ def encode(me, input, finishp = False):
"""C.encode(IN, [finishp = False]) -> OUT: continue/finish encoding"""
- return me.code(text, finishp)
+ cdef const void *p
+ cdef Py_ssize_t sz
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ PyObject_AsReadBuffer(input, &p, &sz)
+ me._code(p, sz, &d, finishp)
+ return TEXT_FROMSTRLEN(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ def done(me):
+ """C.done() -> OUT: final output"""
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ me._code(NULL, 0, &d, True)
+ return TEXT_FROMSTRLEN(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
cdef class _BaseDecoder (_BaseCodec):
- def decode(me, text, finishp = False):
+ def decode(me, input, finishp = False):
"""C.decode(IN, [finishp = False]) -> OUT: continue/finish decoding"""
- return me.code(text, finishp)
+ cdef const char *p
+ cdef Py_ssize_t sz
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ TEXT_PTRLEN(input, &p, &sz)
+ me._code(p, sz, &d, finishp)
+ return BIN_FROMSTRLEN(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
+ def done(me):
+ """C.done() -> OUT: final output"""
+ cdef dstr d
+ DCREATE(&d)
+ try:
+ me._code(NULL, 0, &d, True)
+ return BIN_FROMSTRLEN(d.buf, d.len)
+ finally:
+ dstr_destroy(&d)
###--------------------------------------------------------------------------
### Base64.
cdef class Base64Encoder (_BaseEncoder):
"""
- Base64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
Base64 encoder.
"""
- def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
- me.c = base64_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = 0):
+ me.c = base64_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class Base64Decoder (_BaseDecoder):
"""
- Base64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
Base64 decoder.
"""
- def __init__(me, flags = CDCF_IGNJUNK):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
me.c = base64_class.decoder(flags)
cdef class File64Encoder (_BaseEncoder):
"""
- File64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ File64Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
Base64 encoder, using `%' instead of `/', so encoded strings are safe as
filenames.
"""
- def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
- me.c = file64_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = 0):
+ me.c = file64_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class File64Decoder (_BaseDecoder):
"""
- File64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ File64Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
Base64 encoder, using `%' instead of `/', so encoded strings are safe as
filenames.
"""
- def __init__(me, flags = CDCF_IGNJUNK):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
me.c = file64_class.decoder(flags)
cdef class Base64URLEncoder (_BaseEncoder):
"""
- Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = 0])
Base64 encoder, using `-' and `_' instead of `+' and `/', so encoded
strings are safe as URL components.
"""
- def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
- me.c = base64url_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = 0):
+ me.c = base64url_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class Base64URLDecoder (_BaseDecoder):
"""
- Base64URLDecoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base64URLDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL])
Base64 decoder, using `-' and `_' instead of `+' and `/', so encoded
strings are safe as URL components.
"""
- def __init__(me, flags = CDCF_IGNJUNK):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL):
me.c = base64url_class.decoder(flags)
###--------------------------------------------------------------------------
cdef class Base32Encoder (_BaseEncoder):
"""
- Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
Base32 encoder.
"""
- def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
- me.c = base32_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = 0):
+ me.c = base32_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class Base32Decoder (_BaseDecoder):
"""
- Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
Base32 decoder.
"""
- def __init__(me, flags = CDCF_IGNJUNK):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
me.c = base32_class.decoder(flags)
cdef class Base32HexEncoder (_BaseEncoder):
"""
- Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base32Encoder([indent = '\\n'], [maxline = 72], [flags = 0])
Base32 encoder, using digits and letters in ascending order, rather than
avoiding digits which visually resemble letters.
"""
- def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
- me.c = base32hex_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = 0):
+ me.c = base32hex_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class Base32HexDecoder (_BaseDecoder):
"""
- Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+ Base32Decoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
Base32 decoder, using digits and letters in ascending order, rather than
avoiding digits which visually resemble letters.
"""
- def __init__(me, flags = CDCF_IGNJUNK):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
me.c = base32hex_class.decoder(flags)
###--------------------------------------------------------------------------
cdef class HexEncoder (_BaseEncoder):
"""
- HexEncoder([indent = '\\n'], [maxline = 72],
- [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+ HexEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF_LOWERC])
Hexadecimal encoder.
"""
- def __init__(me, indent = '\n', maxline = 72,
- flags = CDCF_IGNJUNK | CDCF_LOWERC):
- me.c = hex_class.encoder(flags, indent, maxline)
+ def __init__(me, indent = '\n', maxline = 72, flags = _CDCF_LOWERC):
+ me.c = hex_class.encoder(flags, TEXT_PTR(indent), maxline)
cdef class HexDecoder (_BaseDecoder):
"""
- HexDecoder([indent = '\\n'], [maxline = 72],
- [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+ HexDecoder([flags = CDCF_IGNSPC | CDCF_IGNNEWL | CDCF_IGNCASE])
Hexadecimal decoder.
"""
- def __init__(me, flags = CDCF_IGNJUNK | CDCF_LOWERC):
+ def __init__(me, flags = _CDCF_IGNSPC | _CDCF_IGNNEWL | _CDCF_IGNCASE):
me.c = hex_class.decoder(flags)
###----- That's all, folks --------------------------------------------------
Obsolete %CLASS% encoder.
"""
cdef %PREFIX%_ctx ctx
- def __cinit__(me, *hunoz, **hukairz):
+ def __cinit__(me):
_%PREFIX%_init(&me.ctx)
me.ctx.indent = NULL
+ def __dealloc__(me):
+ if me.ctx.indent:
+ xfree(<void *>me.ctx.indent)
def __init__(me, indent = '\n', maxline = 72):
if me.ctx.indent:
xfree(<void *>me.ctx.indent)
- me.ctx.indent = xstrdup(indent)
+ me.ctx.indent = xstrdup(TEXT_PTR(indent))
me.ctx.maxline = maxline
- def __dealloc__(me):
+ @property
+ def indent(me):
+ """E.indent -> INT: indent level for new lines"""
+ return me.ctx.indent
+ @indent.setter
+ def indent(me, indent):
if me.ctx.indent:
xfree(<void *>me.ctx.indent)
- property indent:
- """E.indent -> INT: indent level for new lines"""
- def __get__(me):
- return me.ctx.indent
- def __set__(me, indent):
- if me.ctx.indent:
- xfree(<void *>me.ctx.indent)
- me.ctx.indent = xstrdup(indent)
- property maxline:
+ if indent is None:
+ me.ctx.indent = NULL
+ else:
+ me.ctx.indent = xstrdup(TEXT_PTR(indent))
+ @property
+ def maxline(me):
"""E.maxline -> INT: maximum length of line, or 0 to prevent splitting"""
- def __get__(me):
- return me.ctx.maxline
- def __set__(me, maxline):
+ return me.ctx.maxline
+ @maxline.setter
+ def maxline(me, maxline):
me.ctx.maxline = maxline
- def encode(me, text):
+ def encode(me, input):
"""E.encode(IN) -> OUT: continue encoding"""
- cdef void *p
- cdef Py_ssize_t len
+ cdef const void *p
+ cdef Py_ssize_t sz
cdef dstr d
DCREATE(&d)
try:
- PyObject_AsReadBuffer(text, <cvp *>&p, &len)
- _%PREFIX%_encode(&me.ctx, p, len, &d)
- rc = PyString_FromStringAndSize(d.buf, d.len)
+ PyObject_AsReadBuffer(input, &p, &sz)
+ _%PREFIX%_encode(&me.ctx, p, sz, &d)
+ return TEXT_FROMSTRLEN(d.buf, d.len)
finally:
dstr_destroy(&d)
- return rc
def done(me):
"""E.done() -> OUT: finish encoding, returning final output"""
cdef dstr d
DCREATE(&d)
try:
_%PREFIX%_encode(&me.ctx, NULL, 0, &d)
- rc = PyString_FromStringAndSize(d.buf, d.len)
+ return TEXT_FROMSTRLEN(d.buf, d.len)
finally:
dstr_destroy(&d)
- return rc
-def %PREFIX%_encode(text, *arg, **kw):
+def %PREFIX%_encode(input, *arg, **kw):
"""%PREFIX%_encode(IN, [ARGS...]) -> OUT: %CLASS%-encode the string IN"""
e = %CLASS%Encode(*arg, **kw)
- return e.encode(text) + e.done()
+ return e.encode(input) + e.done()
cdef class %CLASS%Decode:
"""
Obsolete %CLASS% decoder.
"""
cdef %PREFIX%_ctx ctx
- def __cinit__(me, *hunoz, **hukairz):
+ def __cinit__(me):
_%PREFIX%_init(&me.ctx)
me.ctx.indent = NULL
- def decode(me, text):
+ def decode(me, input):
"""D.encode(IN) -> OUT: continue decoding"""
- cdef void *p
- cdef Py_ssize_t len
+ cdef const char *p
+ cdef Py_ssize_t sz
cdef dstr d
DCREATE(&d)
try:
- PyObject_AsReadBuffer(text, <cvp *>&p, &len)
- _%PREFIX%_decode(&me.ctx, p, len, &d)
- rc = PyString_FromStringAndSize(d.buf, d.len)
+ TEXT_PTRLEN(input, &p, &sz)
+ _%PREFIX%_decode(&me.ctx, p, sz, &d)
+ return BIN_FROMSTRLEN(d.buf, d.len)
finally:
dstr_destroy(&d)
- return rc
def done(me):
"""D.done() -> OUT: finish decoding, returning final output"""
cdef dstr d
DCREATE(&d)
try:
_%PREFIX%_decode(&me.ctx, NULL, 0, &d)
- rc = PyString_FromStringAndSize(d.buf, d.len)
+ return BIN_FROMSTRLEN(d.buf, d.len)
finally:
dstr_destroy(&d)
- return rc
-def %PREFIX%_decode(text, *arg, **kw):
+def %PREFIX%_decode(input, *arg, **kw):
"""%PREFIX%_decode(IN) -> OUT: %CLASS%-decode the string IN"""
d = %CLASS%Decode(*arg, **kw)
- return d.decode(text) + d.done()
+ return d.decode(input) + d.done()
###----- That's all, folks --------------------------------------------------
STRF_PREFIX
char *str_qword(char **pp, unsigned f)
size_t str_qsplit(char *p, char **v, size_t c, char **rest, unsigned f)
- int str_matchx(char *p, char *s, unsigned f)
+ bint str_matchx(char *p, char *s, unsigned f)
void str_sanitize(char *d, char *p, size_t sz)
cdef extern from 'mLib/versioncmp.h':
int _versioncmp "versioncmp" (char *va, char *vb)
###--------------------------------------------------------------------------
+### Binary encoding functions.
+
+cdef extern from 'mLib/codec.h':
+ ctypedef struct codec
+ ctypedef struct codec_class:
+ char *name
+ codec *(*encoder)(unsigned f, char *ind, unsigned max)
+ codec *(*decoder)(unsigned f)
+ ctypedef struct codec_ops:
+ codec_class *c
+ int (*code)(codec *c, const void *p, size_t, dstr *d)
+ void (*destroy)(codec *c)
+ ctypedef struct codec:
+ codec_ops *ops
+ enum:
+ _CDCF_LOWERC "CDCF_LOWERC"
+ _CDCF_IGNCASE "CDCF_IGNCASE"
+ _CDCF_NOEQPAD "CDCF_NOEQPAD"
+ _CDCF_IGNEQPAD "CDCF_IGNEQPAD"
+ _CDCF_IGNEQMID "CDCF_IGNEQMID"
+ _CDCF_IGNZPAD "CDCF_IGNZPAD"
+ _CDCF_IGNNEWL "CDCF_IGNNEWL"
+ _CDCF_IGNSPC "CDCF_IGNSPC"
+ _CDCF_IGNINVCH "CDCF_IGNINVCH"
+ _CDCF_IGNJUNK "CDCF_IGNJUNK"
+ enum:
+ _CDCERR_OK "CDCERR_OK"
+ _CDCERR_INVCH "CDCERR_INVCH"
+ _CDCERR_INVEQPAD "CDCERR_INVEQPAD"
+ _CDCERR_INVZPAD "CDCERR_INVZPAD"
+ char *_codec_strerror "codec_strerror" (int err)
+
+###--------------------------------------------------------------------------
### Form-urlencoding functions.
cdef extern from 'mLib/url.h':
pass
void fwatch_init(fwatch *f, char *name)
void fwatch_initfd(fwatch *f, int fd)
- int fwatch_update(fwatch *f, char *name)
- int fwatch_updatefd(fwatch *f, int fd)
+ bint fwatch_update(fwatch *f, char *name)
+ bint fwatch_updatefd(fwatch *f, int fd)
###--------------------------------------------------------------------------
### File descriptor hacking.
cdef extern from 'grim.h':
int PSIZEOF(void *x)
+ object BIN_FROMSTRLEN(const void *p, Py_ssize_t sz)
+ void *BIN_PTR(object bin)
+ void BIN_SETLEN(object bin, Py_ssize_t sz)
+ int TEXT_CHECK(object p)
+ char *TEXT_PTR(str s)
void TEXT_PTRLEN(str s, const char **p, Py_ssize_t *sz)
- object TEXT_FROMSTRLEN(const char *p, Py_ssize_t sz)
- ctypedef void *cvp
+ str TEXT_FROMSTR(const char *p)
+ str TEXT_FROMSTRLEN(const char *p, Py_ssize_t sz)
###----- That's all, folks --------------------------------------------------
fdsend(SOCK, FILE, BUFFER) -> RC:
send FILE over Unix-domain socket SOCK, along with BUFFER
"""
- cdef void *p
+ cdef const void *p
cdef Py_ssize_t len
cdef int rc
- PyObject_AsReadBuffer(buffer, <cvp *>&p, &len)
+ PyObject_AsReadBuffer(buffer, &p, &len)
rc = fdpass_send(_getfd(sock), _getfd(file), p, len)
if rc < 0:
_oserror()
return rc
-def fdrecv(sock, unsigned size):
+def fdrecv(sock, size_t size):
"""
fdrecv(SOCK, SIZE) -> FD, BUFFER
receive file FD and BUFFER of length up to SIZE from Unix-domain SOCK
cdef Py_ssize_t len
cdef PyObject *obj
cdef int fd
- buf = PyString_FromStringAndSize(NULL, size)
- p = PyString_AS_STRING(buf)
- len = fdpass_recv(_getfd(sock), &fd, p, size)
+ buf = BIN_FROMSTRLEN(NULL, size)
+ len = fdpass_recv(_getfd(sock), &fd, BIN_PTR(buf), size)
if len < 0:
_oserror()
- obj = <PyObject *>buf
- _PyString_Resize(&obj, len)
- return fd, <object>obj
+ BIN_SETLEN(buf, len)
+ return fd, buf
###----- That's all, folks --------------------------------------------------
FILE may be a string, file descriptor, or an object with a `fileno' method.
"""
cdef fwatch fw
- cdef public file
- def __cinit__(me, file):
- me._init(file)
- def __init__(me, file):
- me._init(file)
- cdef _init(me, file):
- if isinstance(file, str):
- fwatch_init(&me.fw, file)
+ cdef fobj
+ cdef const char *fname
+ cdef int fd
+ def __cinit__(me):
+ me.fname = NULL
+ me.fd = -1
+ cdef _setfile(me, object file):
+ if TEXT_CHECK(file):
+ me.fname = TEXT_PTR(file)
+ me.fd = -1
else:
- fwatch_initfd(&me.fw, _getfd(file))
- me.file = file
+ me.fd = _getfd(file)
+ me.fname = NULL
+ me.fobj = file
+ def __init__(me, object file):
+ me._setfile(file)
+ if me.fname:
+ fwatch_init(&me.fw, me.fname)
+ else:
+ fwatch_initfd(&me.fw, me.fd)
+ @property
+ def file(me):
+ return me.fobj
+ @file.setter
+ def file(me, file):
+ me._setfile(file)
def update(me):
"""FW.update() -> RC: nonzero if the file has changed state"""
cdef int rc
- if isinstance(me.file, str):
- rc = fwatch_update(&me.fw, me.file)
+ if me.fname:
+ return fwatch_update(&me.fw, me.fname)
else:
- rc = fwatch_updatefd(&me.fw, _getfd(me.file))
- return rc
+ return fwatch_updatefd(&me.fw, me.fd)
###----- That's all, folks --------------------------------------------------
#define BIN_PTR(obj) PyBytes_AS_STRING(obj)
#define BIN_LEN(obj) PyBytes_GET_SIZE(obj)
#define BIN_FROMSTR(str) PyBytes_FromString(str)
+#define BIN_FROMSTRLEN(str, len) PyBytes_FromStringAndSize(str, len)
#define BIN_FORMAT PyBytes_FromFormat
#define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0)
#define BIN_PTR(obj) PyString_AS_STRING(obj)
#define BIN_LEN(obj) PyString_GET_SIZE(obj)
#define BIN_FROMSTR(str) PyString_FromString(str)
+#define BIN_FROMSTRLEN(str, len) PyString_FromStringAndSize(str, len)
#define BIN_FORMAT PyString_FromFormat
#define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0)
include 'assoc.pyx'
## String utilities.
-#include 'str.pyx'
+include 'str.pyx'
## Encodings.
-#include 'codec.pyx'
-#include 'base64.pyx'
-#include 'base32.pyx'
-#include 'hex.pyx'
-#include 'url.pyx'
+include 'codec.pyx'
+include 'base64.pyx'
+include 'base32.pyx'
+include 'hex.pyx'
+include 'url.pyx'
## Error reporting.
-#include 'report.pyx'
+include 'report.pyx'
## File utilities.
-#include 'fwatch.pyx'
-#include 'fdutils.pyx'
-#include 'mdup.pyx'
+include 'fwatch.pyx'
+include 'fdutils.pyx'
+include 'mdup.pyx'
## Other useful stuff.
#include 'stuff.pyx'
with CUR reflecting the new file descriptors even on error. Returns the
same LIST on success.
"""
- cdef mdup_fd *vv
+ cdef mdup_fd *vv = NULL
cdef size_t n
cdef int i
cdef int rc
n = len(v)
vv = <mdup_fd *>xmalloc(n * PSIZEOF(vv))
- for 0 <= i < n:
- vv[i].cur, vv[i].want = v[i]
- rc = _mdup(vv, n)
- for 0 <= i < n:
- v[i] = vv[i].cur, vv[i].want
- if rc < 0:
- _oserror()
+ try:
+ for 0 <= i < n:
+ vv[i].cur, vv[i].want = v[i]
+ rc = _mdup(vv, n)
+ for 0 <= i < n:
+ v[i] = vv[i].cur, vv[i].want
+ if rc < 0:
+ _oserror()
+ finally:
+ xfree(vv)
return v
###----- That's all, folks --------------------------------------------------
### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
quis = '<UNNAMED>'
-cdef char *_progstring
-_progstring = NULL
+cdef char *_progstring = NULL
-def ego(char *prog):
+def ego(object prog):
"""ego(PROG): set program name"""
global quis, _progstring
if _progstring:
xfree(_progstring)
- _progstring = xstrdup(prog)
+ _progstring = xstrdup(TEXT_PTR(prog))
_ego(_progstring)
- quis = _quis()
+ quis = TEXT_FROMSTR(_quis())
-def moan(char *msg):
+def moan(object msg):
"""moan(MSG): report a warning"""
- _moan('%s', msg)
-def die(char *msg, rc = 126):
+ _moan('%s', TEXT_PTR(msg))
+def die(object msg, rc = 126):
"""die(MSG, [rc = 126]): report a fatal error and exit"""
- _moan('%s', msg)
- raise SystemExit, rc
+ _moan('%s', TEXT_PTR(msg))
+ raise SystemExit(rc)
###----- That's all, folks --------------------------------------------------
## The `cythonize' function generates the C sources immediately, so we have
## to generate its inputs even earlier.
genfiles = [
-# MS.Derive('base64.pyx', 'codec.pyx.in',
-# {'CLASS': 'Base64', 'PREFIX': 'base64'}),
-# MS.Derive('base32.pyx', 'codec.pyx.in',
-# {'CLASS': 'Base32', 'PREFIX': 'base32'}),
-# MS.Derive('hex.pyx', 'codec.pyx.in',
-# {'CLASS': 'Hex', 'PREFIX': 'hex'})
+ MS.Derive('base64.pyx', 'codec.pyx.in',
+ {'CLASS': 'Base64', 'PREFIX': 'base64'}),
+ MS.Derive('base32.pyx', 'codec.pyx.in',
+ {'CLASS': 'Base32', 'PREFIX': 'base32'}),
+ MS.Derive('hex.pyx', 'codec.pyx.in',
+ {'CLASS': 'Hex', 'PREFIX': 'hex'})
]
for g in genfiles: g.gen()
## Generate the main C code.
if OS.path.exists(pyxc): OS.rename(pyxc, "mLib.c")
-CB.cythonize("mLib.pyx", compile_time_env = dict(PYVERSION = PYVERSION))
+CB.cythonize("mLib.pyx",
+ compile_time_env = dict(PYVERSION = PYVERSION),
+ compiler_directives = dict(c_string_encoding = 'utf8'))
OS.rename("mLib.c", pyxc)
MS.setup(name = 'mLib-python',
### along with mLib/Python; if not, write to the Free Software Foundation,
### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-def word(char *p, quotep = False):
+def word(object p, object quotep = False):
"""word(STR, [quotep = False]) -> WORD, REST"""
- cdef unsigned f
- cdef char *op
- cdef char *pp
+ cdef unsigned f = 0
+ cdef char *op = xstrdup(TEXT_PTR(p))
+ cdef char *pp = op
cdef char *q
cdef object w
cdef object r
- f = 0
if quotep:
- f = f | STRF_QUOTE
- pp = op = xstrdup(p)
+ f |= STRF_QUOTE
q = str_qword(&pp, f)
if q is NULL:
w = None
else:
- w = q
+ w = <str>q
if pp is NULL:
r = ''
else:
- r = pp
+ r = <str>pp
xfree(op)
return w, r
-def split(char *p, int n = -1, quotep = False):
+def split(object p, int n = -1, quotep = False):
"""split(STR, [n = -1], [quotep = False]) -> WORDS, REST"""
- cdef unsigned f
- cdef char *op
- cdef char *pp
+ cdef unsigned f = 0
+ cdef char *op = xstrdup(TEXT_PTR(p))
+ cdef char *pp = op
cdef char *q
- cdef object l
+ cdef object l = []
cdef object r
- f = 0
if quotep:
- f = f | STRF_QUOTE
- l = []
- op = pp = xstrdup(p)
+ f |= STRF_QUOTE
while n != 0:
q = str_qword(&pp, f)
if q is NULL:
break
- l.append(q)
+ l.append(<str>q)
if n > 0:
- n = n - 1
+ n -= 1
if pp is NULL:
r = ''
else:
- r = pp
+ r = <str>pp
xfree(op)
return l, r
-def match(char *p, char *s, prefixp = False):
+def match(object p, object s, prefixp = False):
"""match(PAT, STR, [prefixp = False]) -> BOOL"""
- cdef unsigned f
+ cdef unsigned f = 0
- f = 0
if prefixp:
- f = f | STRF_PREFIX
- return _tobool(str_matchx(p, s, f))
+ f |= STRF_PREFIX
+ return str_matchx(TEXT_PTR(p), TEXT_PTR(s), f)
-def sanitize(char *p, int n = -1):
+def sanitize(object s, int n = -1):
"""sanitize(STR, [n = -1]) -> STR"""
+ cdef Py_ssize_t nn
+ cdef const char *ss = _text_strlen(s, &nn)
cdef char *buf
cdef object d
if n < 0:
- n = strlen(p)
+ n = nn
buf = <char *>xmalloc(n + 1)
- str_sanitize(buf, p, n + 1)
- d = buf
+ str_sanitize(buf, ss, n + 1)
+ d = <str>buf
xfree(buf)
return d
-def versioncmp(char *va, char *vb):
+def versioncmp(object va, object vb):
"""versioncmp(V0, V1) -> -1 | 0 | +1"""
- return _versioncmp(va, vb)
+ return _versioncmp(TEXT_PTR(va), TEXT_PTR(vb))
###----- That's all, folks --------------------------------------------------
#! /usr/bin/python
### -*- coding: utf-8 -*-
+import contextlib as CTX
+import fcntl as FC
+import os as OS
+import socket as S
import sys as SYS
import mLib as M
print(";; test begins (Python %s)" % SYS.version)
## crc32
+print(";; test crc32...")
must_equal(M.crc32(_bin("abc")), 0x352441c2)
must_equal(M.CRC32().chunk(_bin("a")).chunk(_bin("bc")).done(), 0x352441c2)
## unihash
+print(";; test unihash...")
assert M.Unihash().key is None
must_equal(M.Unihash.hash(_bin("abc")), 0xbf71f6a2)
must_equal(M.Unihash().chunk(_bin("a")).chunk(_bin("bc")).done(), 0xbf71f6a2)
must_equal(M.Unihash.hash(_bin("abc")), 0xecd1e2a2)
## atom
+print(";; test atom...")
foo = M.Atom("foo")
bar = M.Atom("bär")
assert foo != bar
must_equal(list(tab.keys()), [keya])
must_equal(list(tab.values()), [42])
must_equal(list(tab.items()), [(keya, 42)])
+print(";; test assoc...")
test_mapping(M.AssocTable, foo, bar)
+print(";; test sym...")
test_mapping(M.SymTable, 'foo', 'bar')
+## str
+print(";; test str...")
+must_equal(M.word(" foo bar baz"), ("foo", "bar baz"))
+must_equal(M.word(" 'foo \\' bar' baz ", quotep = True),
+ ("foo ' bar", "baz "))
+must_equal(M.split(' one "two \\" three" four five six', 3, quotep = True),
+ (["one", 'two " three', "four"], "five six"))
+assert M.match("foo*bar", "food is served at the bar")
+must_equal(M.sanitize("some awful string!", 12), "some_awful_s")
+assert M.versioncmp("1.2.5~pre99", "1.2.5") < 0
+assert M.versioncmp("1.2.5pre99", "1.2.5") > 0
+
+## codec
+ref = _bin("just >some ?string to encode")
+def test_codecclass(enccls, deccls, encref):
+ enc = enccls("!", 8, M.CDCF_LOWERC)
+ e = enc.encode(ref[:10])
+ e += enc.encode(ref[10:])
+ e += enc.done()
+ must_equal(e, encref)
+ encref = encref.replace("!", "")
+ dec = deccls(M.CDCF_IGNCASE)
+ d = dec.decode(encref[:15])
+ d += dec.decode(encref[15:])
+ d += dec.done()
+ must_equal(d, ref)
+ try: deccls().decode("???")
+ except M.CodecError as e:
+ if e.err == M.CDCERR_INVCH: pass
+ else: raise
+ else: assert False
+def test_oldcodec(enccls, deccls, encref):
+ enc = enccls()
+ enc.indent = "!"
+ enc.maxline = 8
+ e = enc.encode(ref[:10])
+ e += enc.encode(ref[10:])
+ e += enc.done()
+ must_equal(e, encref)
+ encref = encref.replace("!", "")
+ dec = deccls()
+ d = dec.decode(encref[:15])
+ d += dec.decode(encref[15:])
+ d += dec.done()
+ must_equal(d, ref)
+
+print(";; test base64...")
+test_codecclass(M.Base64Encoder, M.Base64Decoder,
+ "anVzdCA+!c29tZSA/!c3RyaW5n!IHRvIGVu!Y29kZQ==")
+test_codecclass(M.File64Encoder, M.File64Decoder,
+ "anVzdCA+!c29tZSA%!c3RyaW5n!IHRvIGVu!Y29kZQ==")
+test_codecclass(M.Base64URLEncoder, M.Base64URLDecoder,
+ "anVzdCA-!c29tZSA_!c3RyaW5n!IHRvIGVu!Y29kZQ==")
+test_oldcodec(M.Base64Encode, M.Base64Decode,
+ "anVzdCA+!c29tZSA/!c3RyaW5n!IHRvIGVu!Y29kZQ==")
+
+print(";; test base32...")
+test_codecclass(M.Base32Encoder, M.Base32Decoder,
+ "nj2xg5ba!hzzw63lf!ea7xg5ds!nfxgoidu!n4qgk3td!n5sgk===")
+test_codecclass(M.Base32HexEncoder, M.Base32HexDecoder,
+ "d9qn6t10!7ppmurb5!40vn6t3i!d5n6e83k!dsg6arj3!dti6a===")
+test_oldcodec(M.Base32Encode, M.Base32Decode,
+ "NJ2XG5BA!HZZW63LF!EA7XG5DS!NFXGOIDU!N4QGK3TD!N5SGK===")
+
+print(";; test hex...")
+test_codecclass(M.HexEncoder, M.HexDecoder,
+ "6a757374!203e736f!6d65203f!73747269!6e672074!6f20656e!636f6465")
+test_oldcodec(M.HexEncode, M.HexDecode,
+ "6a757374!203e736f!6d65203f!73747269!6e672074!6f20656e!636f6465")
+
+## url
+print(";; test url...")
+uenc = M.URLEncode()
+uenc.encode("one", "some/string!")
+uenc.strictp = True
+uenc.encode("two", "some other/string!")
+uenc.laxp = True
+uenc.encode("three", "another!string")
+r = uenc.result
+must_equal(r, "one=some/string%21&two=some+other%2fstring%21&three=another!string")
+must_equal(list(M.URLDecode(r)),
+ [("one", "some/string!"),
+ ("two", "some other/string!"),
+ ("three", "another!string")])
+
+## report
+@CTX.contextmanager
+def stderr_test(want_out):
+ pin, pout = OS.pipe()
+ fin = OS.fdopen(pin, 'r')
+ olderr = OS.dup(2)
+ OS.dup2(pout, 2)
+ OS.close(pout)
+ try:
+ yield
+ OS.close(2)
+ out = fin.read()
+ finally:
+ fin.close()
+ OS.dup2(olderr, 2)
+ must_equal(out, want_out)
+print(";; test report...")
+M.ego("my/path/name")
+must_equal(M.quis, "name")
+with stderr_test("name: test moaning\n"):
+ M.moan("test moaning")
+with stderr_test("name: test death\n"):
+ try: M.die("test death")
+ except SystemExit as e: assert e.code == 126
+ else: assert False
+
+## fwatch
+print(";; test fwatch...")
+fd = OS.open(",test-stamp", OS.O_WRONLY | OS.O_CREAT, 0o666)
+fw = M.FWatch(fd)
+assert not fw.update()
+OS.write(fd, _bin("stuff\n"))
+assert fw.update()
+assert fw.file is fd
+fd2 = OS.open(",test-stamp.new", OS.O_WRONLY | OS.O_CREAT, 0o666)
+OS.rename(",test-stamp.new", ",test-stamp")
+assert not fw.update()
+fw.file = ",test-stamp"
+assert fw.update()
+OS.close(fd)
+OS.close(fd2)
+OS.unlink(",test-stamp")
+
+## fdflags
+print(";; test fdflags...")
+pin, pout = OS.pipe()
+ofl = FC.fcntl(pin, FC.F_GETFL)
+ofd = FC.fcntl(pout, FC.F_GETFD)
+fout = OS.fdopen(pout, 'wb')
+M.fdflags(pin, fbic = OS.O_NONBLOCK, fxor = OS.O_NONBLOCK)
+assert FC.fcntl(pin, FC.F_GETFL) == ofl | OS.O_NONBLOCK
+M.fdflags(pin, fbic = OS.O_NONBLOCK, fxor = 0)
+assert FC.fcntl(pin, FC.F_GETFL) == ofl&~OS.O_NONBLOCK
+M.fdflags(fout, fdbic = FC.FD_CLOEXEC, fdxor = FC.FD_CLOEXEC)
+assert FC.fcntl(pout, FC.F_GETFD) == ofd | FC.FD_CLOEXEC
+M.fdflags(fout, fdbic = FC.FD_CLOEXEC, fdxor = 0)
+assert FC.fcntl(pout, FC.F_GETFD) == ofd&~FC.FD_CLOEXEC
+OS.close(pin)
+fout.close()
+
+## fdpass
+print(";; test fdpass...")
+pin, pout = OS.pipe()
+fin = OS.fdopen(pin, 'r')
+OS.write(pout, _bin("Hello, world!"))
+OS.close(pout)
+sk0, sk1 = S.socketpair(S.AF_UNIX, S.SOCK_STREAM)
+M.fdsend(sk0, fin, _bin("Have a pipe!"))
+fin.close()
+sk0.close()
+fd, msg = M.fdrecv(sk1, 16)
+sk1.close()
+must_equal(msg, _bin("Have a pipe!"))
+data = OS.read(fd, 16)
+OS.close(fd)
+must_equal(data, _bin("Hello, world!"))
+
+## mdup
+## print(";; test mdup...")
+
+
## Done!
print(";; test completed OK")
def __cinit__(me, *hunoz, **hukairz):
url_initenc(&me.ctx)
DCREATE(&me.d)
+ def __dealloc__(me):
+ dstr_destroy(&me.d)
def __init__(me, strictp = False, laxp = False, semip = False):
cdef unsigned f
f = 0
if strictp:
- f = f | URLF_STRICT
+ f |= URLF_STRICT
if laxp:
- f = f | URLF_LAX
+ f |= URLF_LAX
if semip:
- f = f | URLF_SEMI
+ f |= URLF_SEMI
me.ctx.f = f
- def encode(me, char *name, char *value):
+ def encode(me, object name, object value):
"""UE.encode(NAME, VALUE): encode a key/value pair"""
- url_enc(&me.ctx, &me.d, name, value)
+ url_enc(&me.ctx, &me.d, TEXT_PTR(name), TEXT_PTR(value))
return me
- property result:
+ @property
+ def result(me):
"""UE.result -> STR: the encoded string"""
- def __get__(me):
- return PyString_FromStringAndSize(me.d.buf, me.d.len)
- property strictp:
+ return TEXT_FROMSTRLEN(me.d.buf, me.d.len)
+ @property
+ def strictp(me):
"""UE.strictp -> BOOL: strictly escape non-alphanumerics?"""
- def __get__(me):
- return _tobool(me.ctx.f & URLF_STRICT)
- def __set__(me, val):
- if val:
- me.ctx.f = me.ctx.f | URLF_STRICT
- else:
- me.ctx.f = me.ctx.f & ~URLF_STRICT
- property laxp:
+ return <bint>(me.ctx.f&URLF_STRICT)
+ @strictp.setter
+ def strictp(me, val):
+ if val:
+ me.ctx.f |= URLF_STRICT
+ else:
+ me.ctx.f &= ~URLF_STRICT
+ @property
+ def laxp(me):
"""UE.laxp -> BOOL: only escape obviously unsafe characters?"""
- def __get__(me):
- return _tobool(me.ctx.f & URLF_LAX)
- def __set__(me, val):
- if val:
- me.ctx.f = me.ctx.f | URLF_LAX
- else:
- me.ctx.f = me.ctx.f & ~URLF_LAX
- property semip:
+ return <bint>(me.ctx.f&URLF_LAX)
+ @laxp.setter
+ def laxp(me, val):
+ if val:
+ me.ctx.f |= URLF_LAX
+ else:
+ me.ctx.f &= ~URLF_LAX
+ @property
+ def semip(me):
"""UE.semip -> BOOL: separate key/value pairs with semicolons?"""
- def __get__(me):
- return _tobool(me.ctx.f & URLF_SEMI)
- def __set__(me, val):
- if val:
- me.ctx.f = me.ctx.f | URLF_SEMI
- else:
- me.ctx.f = me.ctx.f & ~URLF_SEMI
- def __del__(me):
- dstr_destroy(&me.d)
+ return <bint>(me.ctx.f&URLF_SEMI)
+ @semip.setter
+ def semip(me, val):
+ if val:
+ me.ctx.f |= URLF_SEMI
+ else:
+ me.ctx.f &= ~URLF_SEMI
cdef class URLDecode:
"""URLDecode(STR, [semip = False]): iterator over (KEY, VALUE) pairs"""
cdef char *p
def __cinit__(me, *hunoz, **hukairz):
- me.p = xstrdup('')
+ me.p = NULL
url_initdec(&me.ctx, me.p)
- def __init__(me, char *string, semip = False):
+ def __dealloc__(me):
+ xfree(me.p)
+ def __init__(me, object string, semip = False):
cdef unsigned f
f = 0
if semip:
- f = f | URLF_SEMI
+ f |= URLF_SEMI
xfree(me.p)
- me.p = xstrdup(string)
+ me.p = xstrdup(TEXT_PTR(string))
me.ctx.p = me.p
me.ctx.f = f
def __iter__(me):
DCREATE(&v)
anyp = url_dec(&me.ctx, &n, &v)
if anyp:
- nn = PyString_FromStringAndSize(n.buf, n.len)
- vv = PyString_FromStringAndSize(v.buf, v.len)
+ nn = TEXT_FROMSTRLEN(n.buf, n.len)
+ vv = TEXT_FROMSTRLEN(v.buf, v.len)
dstr_destroy(&n)
dstr_destroy(&v)
if not anyp:
raise StopIteration
return nn, vv
- property semip:
- """UD.semip -> BOOL: key/value pairs separated with semicolons?"""
- def __get__(me):
- return _tobool(me.ctx.f & URLF_SEMI)
- def __set__(me, val):
- if val:
- me.ctx.f = me.ctx.f | URLF_SEMI
- else:
- me.ctx.f = me.ctx.f & ~URLF_SEMI
- def __del__(me):
- xfree(me.p)
+ @property
+ def semip(me):
+ """UE.semip -> BOOL: separate key/value pairs with semicolons?"""
+ return <bint>(me.ctx.f&URLF_SEMI)
+ @semip.setter
+ def semip(me, val):
+ if val:
+ me.ctx.f |= URLF_SEMI
+ else:
+ me.ctx.f &= ~URLF_SEMI
###----- That's all, folks --------------------------------------------------
### 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 _oserror():
-# raise OSError, (errno, strerror(errno))
+cdef const char *_text_strlen(object s, Py_ssize_t *sz) except NULL:
+ cdef const char *p
+ TEXT_PTRLEN(s, &p, sz)
+ return p
-#cdef int _getfd(object fdobj):
-# try:
-# fd = int(fdobj)
-# except TypeError:
-# ##PyErr_Clear()
-# fd = fdobj.fileno()
-# return fd
+cdef object _oserror():
+ raise OSError(errno, strerror(errno))
+
+cdef int _getfd(object fdobj):
+ try:
+ fd = int(fdobj)
+ except TypeError:
+ fd = fdobj.fileno()
+ return fd
#cdef object _checkcallable(object f, object what):
# if f is not None and not callable(f):