Commits

Armin Rigo committed 04fd964

Fix the new test.

Comments (0)

Files changed (4)

pypy/module/_cffi_backend/ctypearray.py

 from pypy.rlib.objectmodel import keepalive_until_here
 from pypy.rlib.rarithmetic import ovfcheck
 
-from pypy.module._cffi_backend.ctypeobj import W_CType
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveChar
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUniChar
 from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray
 
 
 class W_CTypeArray(W_CTypePtrOrArray):
-    _attrs_            = ['length', 'ctptr']
-    _immutable_fields_ = ['length', 'ctptr']
+    _attrs_            = ['ctptr']
+    _immutable_fields_ = ['ctptr']
 
     def __init__(self, space, ctptr, length, arraysize, extra):
         W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
         return self
 
     def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        if (space.isinstance_w(w_ob, space.w_list) or
-            space.isinstance_w(w_ob, space.w_tuple)):
-            lst_w = space.listview(w_ob)
-            if self.length >= 0 and len(lst_w) > self.length:
-                raise operationerrfmt(space.w_IndexError,
-                    "too many initializers for '%s' (got %d)",
-                                      self.name, len(lst_w))
-            ctitem = self.ctitem
-            for i in range(len(lst_w)):
-                ctitem.convert_from_object(cdata, lst_w[i])
-                cdata = rffi.ptradd(cdata, ctitem.size)
-        elif isinstance(self.ctitem, W_CTypePrimitiveChar):
-            try:
-                s = space.str_w(w_ob)
-            except OperationError, e:
-                if not e.match(space, space.w_TypeError):
-                    raise
-                raise self._convert_error("str or list or tuple", w_ob)
-            n = len(s)
-            if self.length >= 0 and n > self.length:
-                raise operationerrfmt(space.w_IndexError,
-                                      "initializer string is too long for '%s'"
-                                      " (got %d characters)",
-                                      self.name, n)
-            for i in range(n):
-                cdata[i] = s[i]
-            if n != self.length:
-                cdata[n] = '\x00'
-        elif isinstance(self.ctitem, W_CTypePrimitiveUniChar):
-            try:
-                s = space.unicode_w(w_ob)
-            except OperationError, e:
-                if not e.match(space, space.w_TypeError):
-                    raise
-                raise self._convert_error("unicode or list or tuple", w_ob)
-            n = len(s)
-            if self.length >= 0 and n > self.length:
-                raise operationerrfmt(space.w_IndexError,
-                              "initializer unicode string is too long for '%s'"
-                                      " (got %d characters)",
-                                      self.name, n)
-            unichardata = rffi.cast(rffi.CWCHARP, cdata)
-            for i in range(n):
-                unichardata[i] = s[i]
-            if n != self.length:
-                unichardata[n] = u'\x00'
-        else:
-            raise self._convert_error("list or tuple", w_ob)
+        self.convert_array_from_object(cdata, w_ob)
 
     def convert_to_object(self, cdata):
         return cdataobj.W_CData(self.space, cdata, self)

pypy/module/_cffi_backend/ctypefunc.py

 from pypy.rlib.objectmodel import keepalive_until_here
 
 from pypy.module._cffi_backend.ctypeobj import W_CType
-from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase
+from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase, W_CTypePointer
 from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
 from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct
 from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
                 buffer_array[i] = data
                 w_obj = args_w[i]
                 argtype = self.fargs[i]
-                #
-                # special-case for strings.  xxx should avoid copying
-                if argtype.is_char_ptr_or_array():
-                    try:
-                        s = space.str_w(w_obj)
-                    except OperationError, e:
-                        if not e.match(space, space.w_TypeError):
-                            raise
-                    else:
-                        raw_string = rffi.str2charp(s)
-                        rffi.cast(rffi.CCHARPP, data)[0] = raw_string
-                        # set the "must free" flag to 1
-                        set_mustfree_flag(data, 1)
-                        mustfree_max_plus_1 = i + 1
-                        continue   # skip the convert_from_object()
-
-                    # set the "must free" flag to 0
-                    set_mustfree_flag(data, 0)
-                #
-                if argtype.is_unichar_ptr_or_array():
-                    try:
-                        space.unicode_w(w_obj)
-                    except OperationError, e:
-                        if not e.match(space, space.w_TypeError):
-                            raise
-                    else:
-                        # passing a unicode raises NotImplementedError for now
-                        raise OperationError(space.w_NotImplementedError,
-                                    space.wrap("automatic unicode-to-"
-                                               "'wchar_t *' conversion"))
-                #
-                argtype.convert_from_object(data, w_obj)
+                if argtype.convert_argument_from_object(data, w_obj):
+                    # argtype is a pointer type, and w_obj a list/tuple/str
+                    mustfree_max_plus_1 = i + 1
             resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
 
             ec = cerrno.get_errno_container(space)
         finally:
             for i in range(mustfree_max_plus_1):
                 argtype = self.fargs[i]
-                if argtype.is_char_ptr_or_array():
+                if isinstance(argtype, W_CTypePointer):
                     data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
                     if get_mustfree_flag(data):
                         raw_string = rffi.cast(rffi.CCHARPP, data)[0]
 
         # loop over args
         for i, farg in enumerate(self.fargs):
-            if farg.is_char_ptr_or_array():
+            if isinstance(farg, W_CTypePointer):
                 exchange_offset += 1   # for the "must free" flag
             exchange_offset = self.align_arg(exchange_offset)
             cif_descr.exchange_args[i] = exchange_offset

pypy/module/_cffi_backend/ctypeobj.py

         raise operationerrfmt(space.w_TypeError,
                               "cannot initialize cdata '%s'", self.name)
 
+    def convert_argument_from_object(self, cdata, w_ob):
+        self.convert_from_object(cdata, w_ob)
+        return False
+
     def _convert_error(self, expected, w_got):
         space = self.space
         ob = space.interpclass_w(w_got)

pypy/module/_cffi_backend/ctypeptr.py

 Pointers.
 """
 
-from pypy.interpreter.error import operationerrfmt
-from pypy.rpython.lltypesystem import rffi
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import ovfcheck
 
 from pypy.module._cffi_backend.ctypeobj import W_CType
-from pypy.module._cffi_backend import cdataobj, misc
+from pypy.module._cffi_backend import cdataobj, misc, ctypeprim
 
 
 class W_CTypePtrOrArray(W_CType):
-    _attrs_            = ['ctitem', 'can_cast_anything', 'is_struct_ptr']
-    _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr']
+    _attrs_            = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
+                          'length']
+    _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
+                          'length']
+    length = -1
 
     def __init__(self, space, size, extra, extra_position, ctitem,
                  could_cast_anything=True):
         self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
 
     def is_char_ptr_or_array(self):
-        from pypy.module._cffi_backend import ctypeprim
         return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
 
     def is_unichar_ptr_or_array(self):
-        from pypy.module._cffi_backend import ctypeprim
         return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
 
     def is_char_or_unichar_ptr_or_array(self):
-        from pypy.module._cffi_backend import ctypeprim
         return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveCharOrUniChar)
 
     def cast(self, w_ob):
             value = rffi.cast(rffi.CCHARP, value)
         return cdataobj.W_CData(space, value, self)
 
+    def convert_array_from_object(self, cdata, w_ob):
+        space = self.space
+        if (space.isinstance_w(w_ob, space.w_list) or
+            space.isinstance_w(w_ob, space.w_tuple)):
+            lst_w = space.listview(w_ob)
+            if self.length >= 0 and len(lst_w) > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                    "too many initializers for '%s' (got %d)",
+                                      self.name, len(lst_w))
+            ctitem = self.ctitem
+            for i in range(len(lst_w)):
+                ctitem.convert_from_object(cdata, lst_w[i])
+                cdata = rffi.ptradd(cdata, ctitem.size)
+        elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar):
+            try:
+                s = space.str_w(w_ob)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
+                raise self._convert_error("str or list or tuple", w_ob)
+            n = len(s)
+            if self.length >= 0 and n > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                                      "initializer string is too long for '%s'"
+                                      " (got %d characters)",
+                                      self.name, n)
+            for i in range(n):
+                cdata[i] = s[i]
+            if n != self.length:
+                cdata[n] = '\x00'
+        elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar):
+            try:
+                s = space.unicode_w(w_ob)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
+                raise self._convert_error("unicode or list or tuple", w_ob)
+            n = len(s)
+            if self.length >= 0 and n > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                              "initializer unicode string is too long for '%s'"
+                                      " (got %d characters)",
+                                      self.name, n)
+            unichardata = rffi.cast(rffi.CWCHARP, cdata)
+            for i in range(n):
+                unichardata[i] = s[i]
+            if n != self.length:
+                unichardata[n] = u'\x00'
+        else:
+            raise self._convert_error("list or tuple", w_ob)
+
 
 class W_CTypePtrBase(W_CTypePtrOrArray):
     # base class for both pointers and pointers-to-functions
         return W_CTypePtrOrArray.unicode(self, cdataobj)
 
     def newp(self, w_init):
-        from pypy.module._cffi_backend import ctypeprim
         space = self.space
         ctitem = self.ctitem
         datasize = ctitem.size
                                   self.name)
         p = rffi.ptradd(cdata, i * self.ctitem.size)
         return cdataobj.W_CData(space, p, self)
+
+    def _prepare_pointer_call_argument(self, w_init):
+        space = self.space
+        if (space.isinstance_w(w_init, space.w_list) or
+            space.isinstance_w(w_init, space.w_tuple)):
+            length = space.int_w(space.len(w_init))
+        elif space.isinstance_w(w_init, space.w_basestring):
+            # from a string, we add the null terminator
+            length = space.int_w(space.len(w_init)) + 1
+        else:
+            return lltype.nullptr(rffi.CCHARP.TO)
+        if self.ctitem.size <= 0:
+            return lltype.nullptr(rffi.CCHARP.TO)
+        try:
+            datasize = ovfcheck(length * self.ctitem.size)
+        except OverflowError:
+            raise OperationError(space.w_OverflowError,
+                space.wrap("array size would overflow a ssize_t"))
+        result = lltype.malloc(rffi.CCHARP.TO, datasize,
+                               flavor='raw', zero=True)
+        try:
+            self.convert_array_from_object(result, w_init)
+        except Exception:
+            lltype.free(result, flavor='raw')
+            raise
+        return result
+
+    def convert_argument_from_object(self, cdata, w_ob):
+        from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            buffer = lltype.nullptr(rffi.CCHARP.TO)
+        else:
+            buffer = self._prepare_pointer_call_argument(w_ob)
+        #
+        if buffer:
+            rffi.cast(rffi.CCHARPP, cdata)[0] = buffer
+            set_mustfree_flag(cdata, True)
+            return True
+        else:
+            set_mustfree_flag(cdata, False)
+            self.convert_from_object(cdata, w_ob)
+            return False