[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