Author: Antonio Cuni <anto.c...@gmail.com> Branch: Changeset: r46021:d342648fe99a Date: 2011-07-27 18:33 +0200 http://bitbucket.org/pypy/pypy/changeset/d342648fe99a/
Log: special case the type "pointer to char", and allow automatic conversion of strings to it diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py --- a/pypy/module/_ffi/interp_ffi.py +++ b/pypy/module/_ffi/interp_ffi.py @@ -74,6 +74,9 @@ def is_struct(self): return libffi.types.is_struct(self.ffitype) + def is_char_p(self): + return self is app_types.char_p + W_FFIType.typedef = TypeDef( 'FFIType', __repr__ = interp2app(W_FFIType.repr), @@ -115,7 +118,10 @@ ## 'Z' : ffi_type_pointer, ] - return dict([(t.name, t) for t in types]) + d = dict([(t.name, t) for t in types]) + w_char = d['char'] + d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char) + return d class app_types: pass @@ -125,9 +131,12 @@ try: return descr_new_pointer.cache[w_pointer_to] except KeyError: - w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) - name = '(pointer to %s)' % w_pointer_to.name - w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) + if w_pointer_to is app_types.char: + w_result = app_types.char_p + else: + w_pointer_to = space.interp_w(W_FFIType, w_pointer_to) + name = '(pointer to %s)' % w_pointer_to.name + w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to) descr_new_pointer.cache[w_pointer_to] = w_result return w_result descr_new_pointer.cache = {} @@ -178,6 +187,8 @@ self.func.name, expected, arg, given) # argchain = libffi.ArgChain() + to_free = [] # list of automatically malloc()ed buffers that needs to + # be freed after the call for i in range(expected): w_argtype = self.argtypes_w[i] w_arg = args_w[i] @@ -188,6 +199,9 @@ self.arg_longlong(space, argchain, w_arg) elif w_argtype.is_signed(): argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg)) + elif self.add_char_p_maybe(space, argchain, to_free, w_arg, w_argtype): + # the argument is added to the argchain direcly by the method above + pass elif w_argtype.is_pointer(): w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype) argchain.arg(intmask(space.uint_w(w_arg))) @@ -210,7 +224,22 @@ argchain.arg_raw(ptrval) else: assert False, "Argument shape '%s' not supported" % w_argtype - return argchain + return argchain, to_free + + def add_char_p_maybe(self, space, argchain, to_free, w_arg, w_argtype): + """ + Automatic conversion from string to char_p. The allocated buffer will + be automatically freed after the call. + """ + w_type = jit.promote(space.type(w_arg)) + if w_argtype.is_char_p() and w_type is space.w_str: + strval = space.str_w(w_arg) + buf = rffi.str2charp(strval) + to_free.append(buf) + addr = rffi.cast(rffi.ULONG, buf) + argchain.arg(addr) + return True + return False def convert_pointer_arg_maybe(self, space, w_arg, w_argtype): """ @@ -234,7 +263,14 @@ def call(self, space, args_w): self = jit.promote(self) - argchain = self.build_argchain(space, args_w) + argchain, to_free = self.build_argchain(space, args_w) + try: + return self._do_call(space, argchain) + finally: + for buf in to_free: + lltype.free(buf, flavor='raw') + + def _do_call(self, space, argchain): w_restype = self.w_restype if w_restype.is_longlong(): # note that we must check for longlong first, because either diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py --- a/pypy/module/_ffi/test/test__ffi.py +++ b/pypy/module/_ffi/test/test__ffi.py @@ -188,6 +188,29 @@ assert get_dummy() == 123 set_val_to_ptr(ptr2, 0) + def test_convert_strings_to_char_str_p(self): + """ + long mystrlen(char* s) + { + long len = 0; + while(*s++) + len++; + return len; + } + """ + from _ffi import CDLL, types + import _rawffi + libfoo = CDLL(self.libfoo_name) + mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong) + # + # first, try automatic conversion from a string + assert mystrlen('foobar') == 6 + # then, try to pass an explicit pointer + CharArray = _rawffi.Array('c') + mystr = CharArray(7, 'foobar') + assert mystrlen(mystr.buffer) == 6 + mystr.free() + def test_typed_pointer(self): from _ffi import types intptr = types.Pointer(types.sint) # create a typed pointer to sint @@ -204,6 +227,11 @@ assert x is y assert x is not z + def test_char_p_cached(self): + from _ffi import types + x = types.Pointer(types.char) + assert x is types.char_p + def test_typed_pointer_args(self): """ extern int dummy; // defined in test_void_result _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit