Commits

Armin Rigo  committed ee984a0

Basic 'void*' support.

  • Participants
  • Parent commits 590c7c8

Comments (0)

Files changed (4)

         #
         if isinstance(typenode, pycparser.c_ast.PtrDecl):
             BItem = self._get_btype(typenode.type)
-            is_const_charp = (list(typenode.type.quals) == ['const'] and
+            is_const_charp = ('const' in typenode.type.quals and
                               BItem is self._backend.get_cached_btype(
                                   "new_primitive_type", "char"))
             return self._backend.get_cached_btype("new_pointer_type", BItem,
                         and names != ['unsigned', 'int']):
                     names.pop()
                 ident = ' '.join(names)
+                if ident == 'void':
+                    return self._backend.get_cached_btype("new_void_type")
                 return self._backend.get_cached_btype(
                     'new_primitive_type', ident)
             #

File ffi/backend_ctypes.py

             name = 'c'    # on Posix only
         path = ctypes.util.find_library(name)
         cdll = ctypes.CDLL(path)
-        return CTypesLibrary(cdll)
+        return CTypesLibrary(self, cdll)
+
+    def new_void_type(self):
+        class CTypesVoid(CTypesData):
+            _reftypename = 'void &'
+            def __init__(self, value=None):
+                raise TypeError("%s cannot be instantiated" % (CTypesVoid,))
+        CTypesVoid._fix_class()
+        return CTypesVoid
 
     def new_primitive_type(self, name):
         ctype = self.PRIMITIVE_TYPES[name]
             kind = 'generic'
         #
         class CTypesPtr(CTypesData):
-            _ctype = ctypes.POINTER(BItem._ctype)
+            if hasattr(BItem, '_ctype'):
+                _ctype = ctypes.POINTER(BItem._ctype)
+            else:
+                _ctype = ctypes.c_void_p
             _reftypename = BItem._get_c_name(' * &')
 
             def __init__(self, init):
                     return ''.join(self._blob)
 
             def _convert_to_address_of(self, BClass):
-                if BItem is BClass:
+                if BItem is BClass or BClass is CTypesVoid:
                     return ctypes.addressof(self._blob)
                 else:
                     return CTypesData._convert_to_address_of(self, BClass)
                 self._blob = ctypes_array
                 return self
         #
+        CTypesVoid = self.get_cached_btype('new_void_type')
         CTypesArray._fix_class()
         return CTypesArray
 
 
 class CTypesLibrary(object):
 
-    def __init__(self, cdll):
+    def __init__(self, backend, cdll):
+        self.backend = backend
         self.cdll = cdll
+        self.void_type = self.backend.get_cached_btype('new_void_type')
 
     def load_function(self, name, bargs, bresult):
         func = getattr(self.cdll, name)
         func.argtypes = [barg._ctype for barg in bargs]
-        func.restype = bresult._ctype
+        if bresult is self.void_type:
+            func.restype = None
+        else:
+            func.restype = bresult._ctype
         return func
 
 

File testing/backend_tests.py

         assert p[3] == '4'
         assert p[8] == '\x00'
         py.test.raises(IndexError, "p[9]")
+        py.test.raises(IndexError, "p[-1]")
         py.test.raises(TypeError, "p[3] = '?'")
         py.test.raises(TypeError, ffi.new, "char *", "some string")
+        py.test.raises(ValueError, ffi.new, "const char *", "a\x00b")
+
+    def test_voidp(self):
+        ffi = FFI(backend=self.Backend())
+        py.test.raises(TypeError, ffi.new, "void")
+        p = ffi.new("void *")
+        assert not p
+        a = ffi.new("int[]", [10, 11, 12])
+        p = ffi.new("void *", a)
+        py.test.raises(TypeError, "p[0]")

File testing/test_math.py

 from ffi import FFI
-import math
+import math, os, cStringIO
+
+
+class FdWriteCapture(object):
+    """xxx limited to capture at most 512 bytes of output, according
+    to the Posix manual."""
+
+    def __init__(self, capture_fd=1):   # stdout, by default
+        self.capture_fd = capture_fd
+
+    def __enter__(self):
+        self.read_fd, self.write_fd = os.pipe()
+        self.copy_fd = os.dup(self.capture_fd)
+        os.dup2(self.write_fd, self.capture_fd)
+        return self
+
+    def __exit__(self, *args):
+        os.dup2(self.copy_fd, self.capture_fd)
+        os.close(self.copy_fd)
+        os.close(self.write_fd)
+        self._value = os.read(self.read_fd, 512)
+        os.close(self.read_fd)
+
+    def getvalue(self):
+        return self._value
 
 
 def test_sin():
     assert type(x) is float
     assert x != math.sin(1.23)    # rounding effects
     assert abs(x - math.sin(1.23)) < 1E-6
+
+def test_puts():
+    ffi = FFI()
+    ffi.cdef("""
+       void puts(const char *);
+       int fflush(void *);
+    """)
+    with FdWriteCapture() as fd:
+        ffi.C.puts("hello")
+        ffi.C.puts("  world")
+        ffi.C.fflush(None)
+    res = fd.getvalue()
+    assert res == 'hello\n  world\n'