[pypy-commit] cffi default: ffi.getcname().

arigo noreply at buildbot.pypy.org
Mon Jun 18 10:29:11 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r428:72b5198d9b44
Date: 2012-06-18 10:28 +0200
http://bitbucket.org/cffi/cffi/changeset/72b5198d9b44/

Log:	ffi.getcname().

diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -3201,6 +3201,34 @@
     return PyInt_FromSsize_t(cf->cf_offset);
 }
 
+static PyObject *b_getcname(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ct;
+    char *replace_with, *p;
+    PyObject *s;
+    Py_ssize_t namelen, replacelen;
+
+    if (!PyArg_ParseTuple(args, "O!s:getcname",
+                          &CTypeDescr_Type, &ct, &replace_with))
+        return NULL;
+
+    namelen = strlen(ct->ct_name);
+    replacelen = strlen(replace_with);
+    s = PyString_FromStringAndSize(NULL, namelen + replacelen);
+    if (s == NULL)
+        return NULL;
+
+    p = PyString_AS_STRING(s);
+    memcpy(p, ct->ct_name, ct->ct_name_position);
+    p += ct->ct_name_position;
+    memcpy(p, replace_with, replacelen);
+    p += replacelen;
+    memcpy(p, ct->ct_name + ct->ct_name_position,
+           namelen - ct->ct_name_position);
+
+    return s;
+}
+
 static PyObject *b_buffer(PyObject *self, PyObject *args)
 {
     CDataObject *cd;
@@ -3378,6 +3406,7 @@
     {"sizeof", b_sizeof, METH_O},
     {"typeof", b_typeof, METH_O},
     {"offsetof", b_offsetof, METH_VARARGS},
+    {"getcname", b_getcname, METH_VARARGS},
     {"buffer", b_buffer, METH_VARARGS},
     {"get_errno", b_get_errno, METH_NOARGS},
     {"set_errno", b_set_errno, METH_VARARGS},
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -169,11 +169,32 @@
         return self._backend.buffer(cdata, size)
 
     def callback(self, cdecl, python_callable):
+        """Return a callback object.  'cdecl' must name a C function pointer
+        type.  The callback invokes the specified 'python_callable'.
+        Important: the callback object must be manually kept alive for as
+        long as the callback may be invoked from the C level.
+        """
         if not callable(python_callable):
             raise TypeError("the 'python_callable' argument is not callable")
         BFunc = self.typeof(cdecl)
         return self._backend.callback(BFunc, python_callable)
 
+    def getctype(self, cdecl, replace_with=''):
+        """Return a string giving the C type 'cdecl', which may be itself
+        a string or a <ctype> object.  If 'replace_with' is given, it gives
+        extra text to append (or insert for more complicated C types), like
+        a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
+        """
+        if isinstance(cdecl, basestring):
+            cdecl = self.typeof(cdecl)
+        replace_with = replace_with.strip()
+        if (replace_with.startswith('*')
+                and '&[' in self._backend.getcname(cdecl, '&')):
+            replace_with = '(%s)' % replace_with
+        elif replace_with and not replace_with[0] in '[(':
+            replace_with = ' ' + replace_with
+        return self._backend.getcname(cdecl, replace_with)
+
     def _get_cached_btype(self, type):
         try:
             BType = self._cached_btypes[type]
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -816,6 +816,9 @@
 
     typeof = type
 
+    def getcname(self, BType, replace_with):
+        return BType._get_c_name(replace_with)
+
 
 class CTypesLibrary(object):
 
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -565,6 +565,13 @@
 ``ffi.offsetof("C struct type", "fieldname")``: return the offset within
 the struct of the given field.  Corresponds to ``offsetof()`` in C.
 
+``ffi.getcname("C type" or <ctype>, ["extra"])``: return the string
+representation of the given C type.  If non-empty, the "extra" string is
+appended (or inserted at the right place in more complicated cases); it
+can be the name of a variable to declare, or an extra part of the type
+like ``"*"`` or ``"[5]"``, so that for example
+``ffi.getcname(ffi.typeof(x), "*")`` returns the string representation
+of the C type "pointer to the same type than x".
 
 
 Comments and bugs
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -845,3 +845,20 @@
         assert p.len == 0
         assert p.data[9] == 0
         py.test.raises(IndexError, "p.data[10]")
+
+    def test_ffi_typeof_getcname(self):
+        ffi = FFI(backend=self.Backend())
+        assert ffi.getctype("int") == "int"
+        assert ffi.getctype("int", 'x') == "int x"
+        assert ffi.getctype("int*") == "int *"
+        assert ffi.getctype("int*", '') == "int *"
+        assert ffi.getctype("int", '*') == "int *"
+        assert ffi.getctype("int", ' * x ') == "int * x"
+        assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
+        assert ffi.getctype("int", '[5]') == "int[5]"
+        assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
+        assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
+        # special-case for convenience: automatically put '()' around '*'
+        assert ffi.getctype("int[5]", '*') == "int(*)[5]"
+        assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
+        assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"


More information about the pypy-commit mailing list