[pypy-commit] creflect default: ffi.string

arigo noreply at buildbot.pypy.org
Fri Dec 5 16:56:01 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r166:030aea977e7e
Date: 2014-12-05 16:52 +0100
http://bitbucket.org/cffi/creflect/changeset/030aea977e7e/

Log:	ffi.string

diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c
--- a/zeffir/ffi_obj.c
+++ b/zeffir/ffi_obj.c
@@ -255,12 +255,75 @@
     return (PyObject *)cd;
 }
 
+static PyObject *ffi_string(PyObject *self, PyObject *args)
+{
+    CDataObject *cd;
+    Py_ssize_t maxlen = -1;
+    if (!PyArg_ParseTuple(args, "O!|n:string",
+                          &CData_Type, &cd, &maxlen))
+        return NULL;
+
+    if (cd->c_type->ct_itemdescr != NULL &&
+        cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR |
+                                              CT_PRIMITIVE_SIGNED |
+                                              CT_PRIMITIVE_UNSIGNED)) {
+        Py_ssize_t length = maxlen;
+        if (cd->c_data == NULL) {
+            PyObject *s = cdata_repr(cd);
+            if (s != NULL) {
+                PyErr_Format(PyExc_RuntimeError,
+                             "cannot use string() on %s",
+                             PyText_AS_UTF8(s));
+                Py_DECREF(s);
+            }
+            return NULL;
+        }
+        if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) {
+            length = get_array_length(cd);
+        }
+        if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) {
+            const char *start = cd->c_data;
+            if (length < 0) {
+                /*READ(start, 1)*/
+                length = strlen(start);
+                /*READ(start, length)*/
+            }
+            else {
+                const char *end;
+                /*READ(start, length)*/
+                end = (const char *)memchr(start, 0, length);
+                if (end != NULL)
+                    length = end - start;
+            }
+            return PyBytes_FromStringAndSize(start, length);
+        }
+    }
+    else if (cd->c_type->ct_flags & CT_IS_ENUM) {
+        abort();
+        //return convert_cdata_to_enum_string(cd, 0);
+    }
+    else if (cd->c_type->ct_flags & CT_IS_BOOL) {
+        /* fall through to TypeError */
+    }
+    else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR |
+                                     CT_PRIMITIVE_SIGNED |
+                                     CT_PRIMITIVE_UNSIGNED)) {
+        /*READ(cd->c_data, cd->c_type->ct_size)*/
+        if (cd->c_type->ct_size == sizeof(char))
+            return PyBytes_FromStringAndSize(cd->c_data, 1);
+    }
+    PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument",
+                 cd->c_type->ct_name);
+    return NULL;
+}
+
 static PyMethodDef ffi_methods[] = {
     {"close_library", ffi_close_library,         METH_VARARGS | METH_STATIC},
     {"load_library",  (PyCFunction)ffi_load_library,
                                                  METH_VARARGS | METH_KEYWORDS},
     {"new",           (PyCFunction)ffi_new,      METH_VARARGS},
     {"sizeof",        (PyCFunction)ffi_sizeof,   METH_O},
+    {"string",        (PyCFunction)ffi_string,   METH_VARARGS},
     {"typeof",        (PyCFunction)ffi_typeof,   METH_O},
     {NULL}
 };
diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py
--- a/zeffir/test/test_basic.py
+++ b/zeffir/test/test_basic.py
@@ -36,3 +36,11 @@
     ffi = support.new_ffi()
     assert repr(ffi.NULL) == "<cdata 'void *' NULL>"
     assert repr(type(ffi).NULL) == "<cdata 'void *' NULL>"
+
+def test_string():
+    ffi = support.new_ffi()
+    p = ffi.new("char[]", "hello\x00world")
+    assert ffi.string(p) == "hello"
+    for i in range(50):
+        p = ffi.new("char[]", "12345678" * i)
+        assert ffi.string(p) == "12345678" * i


More information about the pypy-commit mailing list