Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r2658:21bef1a21d1b Date: 2016-04-15 18:23 +0200 http://bitbucket.org/cffi/cffi/changeset/21bef1a21d1b/
Log: ffi.rawstring(), with a minimal interface diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -5582,6 +5582,36 @@ return NULL; } +static PyObject *b_rawstring(PyObject *self, PyObject *arg) +{ + CDataObject *cd; + Py_ssize_t length; + + if (!CData_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); + return NULL; + } + cd = (CDataObject *)arg; + if (!(cd->c_type->ct_flags & CT_ARRAY) || + !(cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR)) { + PyErr_Format(PyExc_TypeError, + "expected an array of 'char' or 'wchar_t', got '%s'", + cd->c_type->ct_name); + return NULL; + } + + length = get_array_length(cd); + if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) + return PyBytes_FromStringAndSize(cd->c_data, length); +#ifdef HAVE_WCHAR_H + else if (cd->c_type->ct_itemdescr->ct_size == sizeof(wchar_t)) + return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, length); +#endif + + PyErr_SetString(PyExc_SystemError, "bad size for char-like"); + return NULL; +} + static PyObject *b_buffer(PyObject *self, PyObject *args, PyObject *kwds) { CDataObject *cd; @@ -6225,6 +6255,7 @@ {"rawaddressof", b_rawaddressof, METH_VARARGS}, {"getcname", b_getcname, METH_VARARGS}, {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, + {"rawstring", b_rawstring, METH_O}, {"buffer", (PyCFunction)b_buffer, METH_VARARGS | METH_KEYWORDS}, {"get_errno", b_get_errno, METH_NOARGS}, {"set_errno", b_set_errno, METH_O}, diff --git a/c/ffi_obj.c b/c/ffi_obj.c --- a/c/ffi_obj.c +++ b/c/ffi_obj.c @@ -459,6 +459,19 @@ #define ffi_string b_string /* ffi_string() => b_string() from _cffi_backend.c */ +PyDoc_STRVAR(ffi_rawstring_doc, +"Convert a cdata that is an array of 'char' or 'wchar_t' to\n" +"a byte or unicode string. Unlike ffi.string(), it does not stop\n" +"at the first null.\n" +"\n" +"Note that if you have a pointer and an explicit length, you\n" +"can use 'p[0:length]' to make an array view. This is similar to\n" +"the construct 'list(p[0:length])', which returns a list of chars/\n" +"unichars/ints/floats."); + +#define ffi_rawstring b_rawstring /* ffi_rawstring() => b_rawstring() + from _cffi_backend.c */ + PyDoc_STRVAR(ffi_buffer_doc, "Return a read-write buffer object that references the raw C data\n" "pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n" @@ -1090,6 +1103,7 @@ {"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc}, {"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc}, {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc}, + {"rawstring", (PyCFunction)ffi_rawstring, METH_O, ffi_rawstring_doc}, {"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc}, {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc}, {"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc}, diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -299,6 +299,18 @@ """ return self._backend.string(cdata, maxlen) + def rawstring(self, cdata): + """Convert a cdata that is an array of 'char' or 'wchar_t' to + a byte or unicode string. Unlike ffi.string(), it does not stop + at the first null. + + Note that if you have a pointer and an explicit length, you + can use 'p[0:length]' to make an array view. This is similar to + the construct 'list(p[0:length])', which returns a list of chars/ + unichars/ints/floats. + """ + return self._backend.rawstring(cdata) + def buffer(self, cdata, size=-1): """Return a read-write buffer object that references the raw C data pointed to by the given 'cdata'. The 'cdata' must be a pointer or diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py --- a/testing/cffi0/test_ffi_backend.py +++ b/testing/cffi0/test_ffi_backend.py @@ -472,3 +472,12 @@ assert ffi.list_types() == (['b', 'bb', 'bbb'], ['a', 'cc', 'ccc'], ['aa', 'aaa', 'g']) + + def test_rawstring(self): + ffi = FFI() + p = ffi.new("char[]", "abc\x00def") + assert ffi.rawstring(p) == "abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == "bc\x00de" + p = ffi.new("wchar_t[]", u"abc\x00def") + assert ffi.rawstring(p) == u"abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == u"bc\x00de" diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py --- a/testing/cffi1/test_ffi_obj.py +++ b/testing/cffi1/test_ffi_obj.py @@ -495,3 +495,15 @@ assert i < 20 time.sleep(0.51) assert seen == ['init!', 'oops'] * 3 + +def test_rawstring(): + ffi = _cffi1_backend.FFI() + p = ffi.new("char[]", "abc\x00def") + assert ffi.rawstring(p) == "abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == "bc\x00de" + p = ffi.new("wchar_t[]", u"abc\x00def") + assert ffi.rawstring(p) == u"abc\x00def\x00" + assert ffi.rawstring(p[1:6]) == u"bc\x00de" + # + py.test.raises(TypeError, ffi.rawstring, "foobar") + py.test.raises(TypeError, ffi.rawstring, p + 1) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit