[pypy-commit] cffi cpy-extension: Function call with pointer arguments

arigo noreply at buildbot.pypy.org
Tue Jun 12 22:34:26 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: cpy-extension
Changeset: r301:416b0e8ba3b5
Date: 2012-06-12 22:33 +0200
http://bitbucket.org/cffi/cffi/changeset/416b0e8ba3b5/

Log:	Function call with pointer arguments

diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -608,6 +608,23 @@
     return -1;
 }
 
+static int _convert_error(PyObject *init, const char *ct_name,
+                          const char *expected)
+{
+    if (CData_Check(init))
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not cdata '%s'",
+                     ct_name, expected,
+                     ((CDataObject *)init)->c_type->ct_name);
+    else
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not %.200s",
+                     ct_name, expected, Py_TYPE(init)->tp_name);
+    return -1;
+}
+
 static int
 convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init)
 {
@@ -798,18 +815,7 @@
     return _convert_overflow(init, ct->ct_name);
 
  cannot_convert:
-    if (CData_Check(init))
-        PyErr_Format(PyExc_TypeError,
-                     "initializer for ctype '%s' must be a %s, "
-                     "not cdata '%s'",
-                     ct->ct_name, expected,
-                     ((CDataObject *)init)->c_type->ct_name);
-    else
-        PyErr_Format(PyExc_TypeError,
-                     "initializer for ctype '%s' must be a %s, "
-                     "not %.200s",
-                     ct->ct_name, expected, Py_TYPE(init)->tp_name);
-    return -1;
+    return _convert_error(init, ct->ct_name, expected);
 }
 
 static int
@@ -3266,9 +3272,7 @@
     if (CData_Check(obj)) {
         return ((CDataObject *)obj)->c_data;
     }
-    PyErr_Format(PyExc_TypeError,
-                "initializer for ctype 'char *' must be a compatible pointer, "
-                 "not %.200s", Py_TYPE(obj)->tp_name);
+    _convert_error(obj, "char *", "compatible pointer");
     return NULL;
 }
 
@@ -3311,6 +3315,19 @@
     return (char)_convert_to_char(obj);
 }
 
+static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct)
+{
+    return convert_to_object((char *)&ptr, ct);
+}
+
+static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct)
+{
+    char *result;
+    if (convert_from_object((char *)&result, ct, obj) < 0)
+        return NULL;
+    return result;
+}
+
 static void *cffi_exports[] = {
     _cffi_to_c_char_p,
     _cffi_to_c_signed_char,
@@ -3327,6 +3344,8 @@
     _cffi_to_c_unsigned_long,
     _cffi_to_c_unsigned_long_long,
     _cffi_to_c_char,
+    _cffi_from_c_pointer,
+    _cffi_to_c_pointer,
 };
 
 /************************************************************/
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -5,16 +5,19 @@
 
     def __init__(self, ffi):
         self.ffi = ffi
+        self.typesdict = {}
 
     def prnt(self, what=''):
         print >> self.f, what
 
-##    def write_printf(self, what, *args):
-##        if not args:
-##            print >> self.f, '  printf("%s\\n");' % (what,)
-##        else:
-##            print >> self.f, '  printf("%s\\n", %s);' % (
-##                what, ', '.join(args))
+    def gettypenum(self, type):
+        BType = self.ffi._get_cached_btype(type)
+        try:
+            return self.typesdict[BType]
+        except KeyError:
+            num = len(self.typesdict)
+            self.typesdict[BType] = num
+            return num
 
     def verify(self, preamble, **kwargs):
         modname = ffiplatform.undercffi_module_name()
@@ -31,6 +34,7 @@
             #
             self.prnt('static PyMethodDef _cffi_methods[] = {')
             self.generate("method")
+            self.prnt('  {"_cffi_setup", _cffi_setup, METH_O},')
             self.prnt('  {NULL, NULL}    /* Sentinel */')
             self.prnt('};')
             self.prnt()
@@ -55,9 +59,16 @@
         #
         import imp
         try:
-            return imp.load_dynamic(modname, '%s.so' % filebase)
+            module = imp.load_dynamic(modname, '%s.so' % filebase)
         except ImportError, e:
             raise ffiplatform.VerificationError(str(e))
+        #
+        revmapping = dict([(value, key)
+                           for (key, value) in self.typesdict.items()])
+        lst = [revmapping[i] for i in range(len(revmapping))]
+        module._cffi_setup(lst)
+        del module._cffi_setup
+        return module
 
     def generate(self, step_name):
         for name, tp in self.ffi._parser._declarations.iteritems():
@@ -71,6 +82,7 @@
     # ----------
 
     def convert_to_c(self, tp, fromvar, tovar, errcode, is_funcarg=False):
+        extraarg = ''
         if isinstance(tp, model.PrimitiveType):
             converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),)
             errvalue = '-1'
@@ -81,20 +93,24 @@
                     tp.totype.name == 'char'):
                 converter = '_cffi_to_c_char_p'
             else:
-                converter = '_cffi_to_c_pointer'
+                converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
+                extraarg = ', _cffi_type(%d)' % self.gettypenum(tp)
             errvalue = 'NULL'
         #
         else:
             raise NotImplementedError(tp)
         #
-        self.prnt('  %s = %s(%s);' % (tovar, converter, fromvar))
+        self.prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
         self.prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
             tovar, tp.get_c_name(''), errvalue))
         self.prnt('    %s;' % errcode)
 
-    def get_converter_from_c(self, tp):
+    def convert_expr_from_c(self, tp, var):
         if isinstance(tp, model.PrimitiveType):
-            return '_cffi_from_c_%s' % (tp.name.replace(' ', '_'),)
+            return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
+        elif isinstance(tp, model.PointerType):
+            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
+                var, self.gettypenum(tp))
         else:
             raise NotImplementedError(tp)
 
@@ -151,7 +167,8 @@
         prnt()
         #
         if result_code:
-            prnt('  return %s(result);' % self.get_converter_from_c(tp.result))
+            prnt('  return %s;' %
+                 self.convert_expr_from_c(tp.result, 'result'))
         else:
             prnt('  Py_INCREF(Py_None);')
             prnt('  return Py_None;')
@@ -232,6 +249,10 @@
                  ((unsigned long long(*)(PyObject *))_cffi_exports[8])
 #define _cffi_to_c_char                                                  \
                  ((char(*)(PyObject *))_cffi_exports[9])
+#define _cffi_from_c_pointer                                             \
+    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
+#define _cffi_to_c_pointer                                               \
+    ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
 
 #if SIZEOF_LONG < SIZEOF_LONG_LONG
 #  define _cffi_to_c_long_long PyLong_AsLongLong
@@ -239,7 +260,10 @@
 #  define _cffi_to_c_long_long _cffi_to_c_long
 #endif
 
+typedef struct _ctypedescr CTypeDescrObject;
+
 static void **_cffi_exports;
+static PyObject *_cffi_types;
 
 static int _cffi_init(void)
 {
@@ -260,5 +284,15 @@
     return 0;
 }
 
+static PyObject *_cffi_setup(PyObject *self, PyObject *arg)
+{
+    Py_INCREF(arg);
+    _cffi_types = arg;
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
+
 /**********/
 '''
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -95,6 +95,16 @@
     lib = ffi.verify("#define foo(a, b) ((a) * (b))")
     assert lib.foo(-6, -7) == 42
 
+def test_ptr():
+    ffi = FFI()
+    ffi.cdef("int *foo(int *);")
+    lib = ffi.verify("int *foo(int *a) { return a; }")
+    assert lib.foo(None) is None
+    p = ffi.new("int", 42)
+    q = ffi.new("int", 42)
+    assert lib.foo(p) == p
+    assert lib.foo(q) != p
+
 
 def test_verify_typedefs():
     py.test.skip("XXX?")


More information about the pypy-commit mailing list