chiark / gitweb /
*.c: Introduce a new input conversion for binary strings.
[catacomb-python] / buffer.c
index bd5e3349094865cd756ad0de81ed7e7d05f28cf1..59eaec614cb0a57de91db11381e053c692c7de5e 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -46,24 +46,24 @@ static PyTypeObject *rbuf_pytype, *wbuf_pytype;
 
 static PyObject *buferr;
 
-#define BUFERR() do { PyErr_SetNone(buferr); goto end; } while (0)
+#define BUFERR(str) do { PyErr_SetString(buferr, str); goto end; } while (0)
 
 /*----- Read buffers ------------------------------------------------------*/
 
 static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
 {
-  char *p, *q;
-  Py_ssize_t n;
+  struct bin in;
+  void *q;
   buf_pyobj *me = 0;
-  static char *kwlist[] = { "data", 0 };
+  static const char *const kwlist[] = { "data", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convbin, &in))
     goto end;
-  q = xmalloc(n);
-  memcpy(q, p, n);
+  q = xmalloc(in.sz);
+  memcpy(q, in.p, in.sz);
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
   me->sub = 0;
-  buf_init(&me->b, q, n);
+  buf_init(&me->b, q, in.sz);
 end:
   return ((PyObject *)me);
 }
@@ -88,7 +88,7 @@ static PyObject *rbmeth_skip(PyObject *me, PyObject *arg)
   size_t n;
 
   if (!PyArg_ParseTuple(arg, "O&:skip", convszt, &n)) goto end;
-  if (!buf_get(BUF_B(me), n)) BUFERR();
+  if (!buf_get(BUF_B(me), n)) BUFERR("buffer exhausted");
   RETURN_ME;
 end:
   return (0);
@@ -100,18 +100,17 @@ static PyObject *rbmeth_get(PyObject *me, PyObject *arg)
   size_t n;
 
   if (!PyArg_ParseTuple(arg, "O&:get", convszt, &n)) goto end;
-  if ((p = buf_get(BUF_B(me), n)) == 0) BUFERR();
+  if ((p = buf_get(BUF_B(me), n)) == 0) BUFERR("buffer exhausted");
   return (bytestring_pywrap(p, n));
 end:
   return (0);
 }
 
 #define RBMETH_GETU_(n, W, w)                                          \
-  static PyObject *rbmeth_getu##w(PyObject *me, PyObject *arg)         \
+  static PyObject *rbmeth_getu##w(PyObject *me)                                \
   {                                                                    \
     uint##n x;                                                         \
-    if (!PyArg_ParseTuple(arg, ":getu" #w)) goto end;                  \
-    if (buf_getu##w(BUF_B(me), &x)) BUFERR();                          \
+    if (buf_getu##w(BUF_B(me), &x)) BUFERR("buffer exhausted");                \
     if (MASK##W <= ULONG_MAX) return (getulong(x));                    \
     else { kludge64 y; ASSIGN64(y, x); return (getk64(y)); }           \
   end:                                                                 \
@@ -120,12 +119,12 @@ end:
 DOUINTCONV(RBMETH_GETU_)
 
 #define RBMETH_GETBLK_(n, W, w)                                                \
-  static PyObject *rbmeth_getblk##w(PyObject *me, PyObject *arg)       \
+  static PyObject *rbmeth_getblk##w(PyObject *me)                      \
   {                                                                    \
     size_t sz;                                                         \
     char *q;                                                           \
-    if (!PyArg_ParseTuple(arg, ":getblk" #w)) goto end;                        \
-    if ((q = buf_getmem##w(BUF_B(me), &sz)) == 0) BUFERR();            \
+    if ((q = buf_getmem##w(BUF_B(me), &sz)) == 0)                      \
+      BUFERR("buffer exhausted");                                      \
     return (bytestring_pywrap(q, sz));                                 \
   end:                                                                 \
     return (0);                                                                \
@@ -133,12 +132,11 @@ DOUINTCONV(RBMETH_GETU_)
 BUF_DOSUFFIXES(RBMETH_GETBLK_)
 
 #define RBMETH_GETBUF_(n, W, w)                                                \
-  static PyObject *rbmeth_getbuf##w(PyObject *me, PyObject *arg)       \
+  static PyObject *rbmeth_getbuf##w(PyObject *me)                      \
   {                                                                    \
     buf_pyobj *b;                                                      \
     buf bb;                                                            \
-    if (!PyArg_ParseTuple(arg, ":getbuf" #w)) goto end;                        \
-    if (buf_getbuf##w(BUF_B(me), &bb)) BUFERR();                       \
+    if (buf_getbuf##w(BUF_B(me), &bb)) BUFERR("buffer exhausted");     \
     b = PyObject_NEW(buf_pyobj, rbuf_pytype);                          \
     b->b = bb;                                                         \
     b->sub = me;                                                       \
@@ -149,21 +147,19 @@ BUF_DOSUFFIXES(RBMETH_GETBLK_)
   }
 BUF_DOSUFFIXES(RBMETH_GETBUF_)
 
-static PyObject *rbmeth_getmp(PyObject *me, PyObject *arg)
+static PyObject *rbmeth_getmp(PyObject *me)
 {
   mp *x;
-  if (!PyArg_ParseTuple(arg, ":getmp")) goto end;
-  if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR();
+  if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR("buffer exhausted");
   return (mp_pywrap(x));
 end:
   return (0);
 }
 
-static PyObject *rbmeth_getgf(PyObject *me, PyObject *arg)
+static PyObject *rbmeth_getgf(PyObject *me)
 {
   mp *x;
-  if (!PyArg_ParseTuple(arg, ":getgf")) goto end;
-  if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR();
+  if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR("buffer exhausted");
   return (gf_pywrap(x));
 end:
   return (0);
@@ -172,15 +168,15 @@ end:
 static PyObject *rbmeth_getecpt(PyObject *me, PyObject *arg, PyObject *kw)
 {
   PyObject *cobj = Py_None;
-  static char *kwlist[] = { "curve", 0 };
+  static const char *const kwlist[] = { "curve", 0 };
   ec pt = EC_INIT;
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:getecpt", kwlist, &cobj))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:getecpt", KWLIST, &cobj))
     goto end;
   if (cobj == Py_None) cobj = (PyObject *)ecpt_pytype;
   if (!PyType_Check(cobj) ||
       !PyType_IsSubtype((PyTypeObject *)cobj, ecpt_pytype))
     TYERR("expected elliptic curve type");
-  if (buf_getec(BUF_B(me), &pt)) BUFERR();
+  if (buf_getec(BUF_B(me), &pt)) BUFERR("buffer exhausted");
   return (ecpt_pywrapout(cobj, &pt));
 end:
   return (0);
@@ -192,7 +188,7 @@ static PyObject *rbmeth_getecptraw(PyObject *me, PyObject *arg)
   ec pt = EC_INIT;
   if (!PyArg_ParseTuple(arg, "O!:getecptraw", eccurve_pytype, &cobj))
     goto end;
-  if (ec_getraw(ECCURVE_C(cobj), BUF_B(me), &pt)) BUFERR();
+  if (ec_getraw(ECCURVE_C(cobj), BUF_B(me), &pt)) BUFERR("buffer exhausted");
   return (ecpt_pywrapout(cobj, &pt));
 end:
   return (0);
@@ -204,7 +200,7 @@ static PyObject *rbmeth_getge(PyObject *me, PyObject *arg)
   ge *x = 0;
   if (!PyArg_ParseTuple(arg, "O!:getge", group_pytype, &gobj)) goto end;
   x = G_CREATE(GROUP_G(gobj));
-  if (G_FROMBUF(GROUP_G(gobj), BUF_B(me), x)) BUFERR();
+  if (G_FROMBUF(GROUP_G(gobj), BUF_B(me), x)) BUFERR("buffer exhausted");
   return (ge_pywrap(gobj, x));
 end:
   if (x) G_DESTROY(GROUP_G(gobj), x);
@@ -217,7 +213,7 @@ static PyObject *rbmeth_getgeraw(PyObject *me, PyObject *arg)
   ge *x = 0;
   if (!PyArg_ParseTuple(arg, "O!:getgeraw", group_pytype, &gobj)) goto end;
   x = G_CREATE(GROUP_G(gobj));
-  if (G_FROMRAW(GROUP_G(gobj), BUF_B(me), x)) BUFERR();
+  if (G_FROMRAW(GROUP_G(gobj), BUF_B(me), x)) BUFERR("buffer exhausted");
   return (ge_pywrap(gobj, x));
 end:
   if (x) G_DESTROY(GROUP_G(gobj), x);
@@ -244,48 +240,48 @@ end:
   return (-1);
 }
 
-static PyGetSetDef rbuf_pygetset[] = {
+static const PyGetSetDef rbuf_pygetset[] = {
 #define GETSETNAME(op, name) rb##op##_##name
-  GET  (size,                  "RBUF.size -> SIZE")
-  GET  (left,                  "RBUF.left -> REMAINDER")
-  GET  (endp,                  "RBUF.endp -> BOOL")
-  GETSET(offset,               "RBUF.offset -> OFFSET")
+  GET  (size,          "RBUF.size -> SIZE")
+  GET  (left,          "RBUF.left -> REMAINDER")
+  GET  (endp,          "RBUF.endp -> BOOL")
+  GETSET(offset,       "RBUF.offset -> OFFSET")
 #undef GETSETNAME
   { 0 }
 };
 
-static PyMethodDef rbuf_pymethods[] = {
+static const PyMethodDef rbuf_pymethods[] = {
 #define METHNAME(func) rbmeth_##func
-  METH (skip,                  "RBUF.skip(N)")
-  METH (get,                   "RBUF.get(N) -> BYTES")
+  METH (skip,          "RBUF.skip(N)")
+  METH (get,           "RBUF.get(N) -> BYTES")
 #define RBMETH_DECL_GETU_(n, W, w)                                     \
-    METH(getu##w, "RBUF.getu" #w "() -> INT")
+    NAMETH(getu##w,    "RBUF.getu" #w "() -> INT")
   DOUINTCONV(RBMETH_DECL_GETU_)
 #define RBMETH_DECL_GETBLK_(n, W, w)                                   \
-    METH(getblk##w, "RBUF.getblk" #w "() -> INT")
+    NAMETH(getblk##w,  "RBUF.getblk" #w "() -> BYTES")
   BUF_DOSUFFIXES(RBMETH_DECL_GETBLK_)
 #define RBMETH_DECL_GETBUF_(n, W, w)                                   \
-    METH(getbuf##w, "RBUF.getbuf" #w "() -> INT")
+    NAMETH(getbuf##w,  "RBUF.getbuf" #w "() -> RBUF'")
   BUF_DOSUFFIXES(RBMETH_DECL_GETBUF_)
-  METH (getmp,                 "RBUF.getmp() -> X")
-  METH (getgf,                 "RBUF.getgf() -> X")
-  KWMETH(getecpt,              "RBUF.getecpt(curve = None) -> P")
-  METH (getecptraw,            "RBUF.getecptraw(CURVE) -> P")
-  METH (getge,                 "RBUF.getge(GROUP) -> X")
-  METH (getgeraw,              "RBUF.getgeraw(GROUP) -> X")
+  NAMETH(getmp,                "RBUF.getmp() -> X")
+  NAMETH(getgf,                "RBUF.getgf() -> X")
+  KWMETH(getecpt,      "RBUF.getecpt([curve = None]) -> P")
+  METH (getecptraw,    "RBUF.getecptraw(CURVE) -> P")
+  METH (getge,         "RBUF.getge(GROUP) -> X")
+  METH (getgeraw,      "RBUF.getgeraw(GROUP) -> X")
 #undef METHNAME
   { 0 }
 };
 
-static PyBufferProcs rbuf_pybuffer = {
+static const PyBufferProcs rbuf_pybuffer = {
   rbuf_pyreadbuf,                      /* @bf_getreadbuffer@ */
   0,                                   /* @bf_getwritebuffer@ */
   rbuf_pysegcount,                     /* @bf_getsegcount@ */
   0                                    /* @bf_getcharbuffer@ */
 };
 
-static PyTypeObject rbuf_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+static const PyTypeObject rbuf_pytype_skel = {
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "ReadBuffer",                                /* @tp_name@ */
   sizeof(buf_pyobj),                   /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -304,12 +300,12 @@ static PyTypeObject rbuf_pytype_skel = {
   0,                                   /* @tp_str@ */
   0,                                   /* @tp_getattro@ */
   0,                                   /* @tp_setattro@ */
-  &rbuf_pybuffer,                      /* @tp_as_buffer@ */
+  PYBUFFER(rbuf),                      /* @tp_as_buffer@ */
   Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "A read buffer.",
+  "ReadBuffer(STR): a read buffer.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -317,9 +313,9 @@ static PyTypeObject rbuf_pytype_skel = {
   0,                                   /* @tp_weaklistoffset@ */
   0,                                   /* @tp_iter@ */
   0,                                   /* @tp_iternext@ */
-  rbuf_pymethods,                      /* @tp_methods@ */
+  PYMETHODS(rbuf),                     /* @tp_methods@ */
   0,                                   /* @tp_members@ */
-  rbuf_pygetset,                       /* @tp_getset@ */
+  PYGETSET(rbuf),                      /* @tp_getset@ */
   0,                                   /* @tp_base@ */
   0,                                   /* @tp_dict@ */
   0,                                   /* @tp_descr_get@ */
@@ -355,9 +351,9 @@ static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   char *p;
   size_t n = 64;
   buf_pyobj *me = 0;
-  static char *kwlist[] = { "size", 0 };
+  static const char *const kwlist[] = { "size", 0 };
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist,
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST,
                                   convszt, &n))
     goto end;
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
@@ -387,11 +383,10 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg)
 
 static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
 {
-  void *p;
-  Py_ssize_t n;
-  if (!PyArg_ParseTuple(arg, "s#:put", &p, &n)) return (0);
-  ensure(me, n);
-  buf_put(BUF_B(me), p, n); assert(BOK(BUF_B(me)));
+  struct bin in;
+  if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
+  ensure(me, in.sz);
+  buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
 
@@ -411,12 +406,11 @@ DOUINTCONV(WBMETH_PUTU_)
 #define WBMETH_PUTBLK_(n, W, w)                                                \
   static PyObject *wbmeth_putblk##w(PyObject *me, PyObject *arg)       \
   {                                                                    \
-    char *p;                                                           \
-    Py_ssize_t sz;                                                     \
-    if (!PyArg_ParseTuple(arg, "s#:putblk" #w, &p, &sz)) goto end;     \
-    if (MASK##W && sz > MASK##W) VALERR("too large");                  \
-    ensure(me, sz + SZ_##n);                                           \
-    buf_putmem##w(BUF_B(me), p, sz); assert(BOK(BUF_B(me)));           \
+    struct bin in;                                                     \
+    if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end;        \
+    if (MASK##W && in.sz > MASK##W) VALERR("too large");               \
+    ensure(me, in.sz + SZ_##n);                                                \
+    buf_putmem##w(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));     \
     RETURN_ME;                                                         \
   end:                                                                 \
     return (0);                                                                \
@@ -446,8 +440,7 @@ static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg)
 {
   ec pt = EC_INIT;
   if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0);
-  if (EC_ATINF(&pt)) ensure(me, 2);
-  else ensure(me, 4 + mp_octets(pt.x) + mp_octets(pt.y));
+  ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y));
   buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
@@ -487,42 +480,46 @@ static PyObject *wbmeth_putgeraw(PyObject *me, PyObject *arg)
 static PyObject *wbget_size(PyObject *me, void *hunoz)
   { return (PyInt_FromLong(BLEN(BUF_B(me)))); }
 
-static PyGetSetDef wbuf_pygetset[] = {
+static PyObject *wbget_contents(PyObject *me, void *hunoz)
+  { return (bytestring_pywrap(BBASE(BUF_B(me)), BLEN(BUF_B(me)))); }
+
+static const PyGetSetDef wbuf_pygetset[] = {
 #define GETSETNAME(op, name) wb##op##_##name
-  GET  (size,                  "WBUF.size -> SIZE")
+  GET  (size,          "WBUF.size -> SIZE")
+  GET  (contents,      "WBUF.contents -> STR")
 #undef GETSETNAME
   { 0 }
 };
 
-static PyMethodDef wbuf_pymethods[] = {
+static const PyMethodDef wbuf_pymethods[] = {
 #define METHNAME(func) wbmeth_##func
-  METH (zero,                  "WBUF.zero(N)")
-  METH (put,                   "WBUF.put(BYTES)")
+  METH (zero,          "WBUF.zero(N)")
+  METH (put,           "WBUF.put(BYTES)")
 #define WBMETH_DECL_PUTU_(n, W, w)                                     \
-    METH(putu##w, "WBUF.putu" #w "(INT)")
+    METH(putu##w,      "WBUF.putu" #w "(INT)")
   DOUINTCONV(WBMETH_DECL_PUTU_)
 #define WBMETH_DECL_PUTBLK_(n, W, w)                                   \
-    METH(putblk##w, "WBUF.putblk" #w "(BYTES)")
+    METH(putblk##w,    "WBUF.putblk" #w "(BYTES)")
   BUF_DOSUFFIXES(WBMETH_DECL_PUTBLK_)
-  METH (putmp,                 "WBUF.putmp(X)")
-  METH (putgf,                 "WBUF.putgf(X)")
-  METH (putecpt,               "WBUF.putecpt(P)")
-  METH (putecptraw,            "WBUF.putecptraw(P)")
-  METH (putge,                 "WBUF.putge(X)")
-  METH (putgeraw,              "WBUF.putgeraw(X)")
+  METH (putmp,         "WBUF.putmp(X)")
+  METH (putgf,         "WBUF.putgf(X)")
+  METH (putecpt,       "WBUF.putecpt(P)")
+  METH (putecptraw,    "WBUF.putecptraw(P)")
+  METH (putge,         "WBUF.putge(X)")
+  METH (putgeraw,      "WBUF.putgeraw(X)")
 #undef METHNAME
   { 0 }
 };
 
-static PyBufferProcs wbuf_pybuffer = {
+static const PyBufferProcs wbuf_pybuffer = {
   wbuf_pyreadbuf,                      /* @bf_getreadbuffer@ */
   0,                                   /* @bf_getwritebuffer@ */
   wbuf_pysegcount,                     /* @bf_getsegcount@ */
   0                                    /* @bf_getcharbuffer@ */
 };
 
-static PyTypeObject wbuf_pytype_skel = {
-  PyObject_HEAD_INIT(0) 0,             /* Header */
+static const PyTypeObject wbuf_pytype_skel = {
+  PyVarObject_HEAD_INIT(0, 0)          /* Header */
   "WriteBuffer",                       /* @tp_name@ */
   sizeof(buf_pyobj),                   /* @tp_basicsize@ */
   0,                                   /* @tp_itemsize@ */
@@ -541,12 +538,12 @@ static PyTypeObject wbuf_pytype_skel = {
   0,                                   /* @tp_str@ */
   0,                                   /* @tp_getattro@ */
   0,                                   /* @tp_setattro@ */
-  &wbuf_pybuffer,                      /* @tp_as_buffer@ */
+  PYBUFFER(wbuf),                      /* @tp_as_buffer@ */
   Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "A write buffer.",
+  "WriteBuffer([size = ?]): a write buffer.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */
@@ -554,9 +551,9 @@ static PyTypeObject wbuf_pytype_skel = {
   0,                                   /* @tp_weaklistoffset@ */
   0,                                   /* @tp_iter@ */
   0,                                   /* @tp_iternext@ */
-  wbuf_pymethods,                      /* @tp_methods@ */
+  PYMETHODS(wbuf),                     /* @tp_methods@ */
   0,                                   /* @tp_members@ */
-  wbuf_pygetset,                       /* @tp_getset@ */
+  PYGETSET(wbuf),                      /* @tp_getset@ */
   0,                                   /* @tp_base@ */
   0,                                   /* @tp_dict@ */
   0,                                   /* @tp_descr_get@ */