1. Python CFFI
  2. Untitled project
  3. cffi

Commits

Armin Rigo  committed b33e90b

Fix the issue. Tests pass but would need some review because it's
slightly fragile... But it's enough to have the simple xclient.py
demo work.

  • Participants
  • Parent commits 874950e
  • Branches default

Comments (0)

Files changed (5)

File cffi/cparser.py

View file
 
     def _declare(self, name, obj):
         if name in self._declarations:
+            if self._declarations[name] is obj:
+                return
             raise api.FFIError("multiple declarations of %s" % (name,))
         assert name != '__dotdotdot__'
         self._declarations[name] = obj
             if name is not None:
                 self._declare(key, tp)
         tp.forcename = tp.forcename or force_name
+        if tp.forcename and '$' in tp.name:
+            self._declare('anonymous %s' % tp.forcename, tp)
         #
         self._structnode2type[type] = tp
         #
                 # of strings, but is sometimes just one string.  Use
                 # str.join() as a way to cope with both.
                 tp.partial = True
+                if not tp.has_c_name():
+                    raise api.CDefError("%s is partial but has no C name"
+                                        % (tp,))
                 continue
             if decl.bitsize is None:
                 bitsize = -1

File cffi/model.py

View file
                 % (result,))
         return result
 
+    def has_c_name(self):
+        return '$' not in self._get_c_name('')
+
     def __repr__(self):
         return '<%s>' % (self._get_c_name(''),)
 

File cffi/verifier.py

View file
     def generate(self, step_name):
         for name, tp in self.ffi._parser._declarations.iteritems():
             kind, realname = name.split(' ', 1)
-            method = getattr(self, 'generate_cpy_%s_%s' % (kind, step_name))
+            try:
+                method = getattr(self, 'generate_cpy_%s_%s' % (kind,
+                                                               step_name))
+            except AttributeError:
+                raise ffiplatform.VerificationError(
+                    "not implemented in verify(): %r" % name)
             method(tp, realname)
 
     def load(self, module, step_name, **kwds):
         setattr(library, name, getattr(module, name))
 
     # ----------
-    # struct declarations
+    # named structs
 
     def generate_cpy_struct_decl(self, tp, name):
+        assert name == tp.name
+        self._generate_struct_or_union_decl(tp, 'struct', name)
+
+    def generate_cpy_struct_method(self, tp, name):
+        self._generate_struct_or_union_method(tp, 'struct', name)
+
+    def loading_cpy_struct(self, tp, name, module):
+        self._loading_struct_or_union(tp, 'struct', name, module)
+
+    def loaded_cpy_struct(self, tp, name, module, **kwds):
+        self._loaded_struct_or_union(tp)
+
+    def _generate_struct_or_union_decl(self, tp, prefix, name):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        assert name == tp.name
+        checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        cname = ('%s %s' % (prefix, name)).strip()
+        #
         prnt = self.prnt
-        checkfuncname = '_cffi_check_%s' % (name,)
-        prnt('static void %s(struct %s *p)' % (checkfuncname, name))
+        prnt('static void %s(%s *p)' % (checkfuncname, cname))
         prnt('{')
         prnt('  /* only to generate compile-time warnings or errors */')
         for i in range(len(tp.fldnames)):
                     ftype.get_c_name('(*tmp)'), fname))
         prnt('}')
         prnt('static PyObject *')
-        prnt('_cffi_struct_%s(PyObject *self, PyObject *noarg)' % name)
+        prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
         prnt('{')
-        prnt('  struct _cffi_aligncheck { char x; struct %s y; };' % name)
+        prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
         if tp.partial:
             prnt('  static Py_ssize_t nums[] = {')
-            prnt('    sizeof(struct %s),' % name)
+            prnt('    sizeof(%s),' % cname)
             prnt('    offsetof(struct _cffi_aligncheck, y),')
             for fname in tp.fldnames:
-                prnt('    offsetof(struct %s, %s),' % (name, fname))
-                prnt('    sizeof(((struct %s *)0)->%s),' % (name, fname))
+                prnt('    offsetof(%s, %s),' % (cname, fname))
+                prnt('    sizeof(((%s *)0)->%s),' % (cname, fname))
             prnt('    -1')
             prnt('  };')
             prnt('  return _cffi_get_struct_layout(nums);')
             ffi = self.ffi
             BStruct = ffi._get_cached_btype(tp)
             conditions = [
-                'sizeof(struct %s) != %d' % (name, ffi.sizeof(BStruct)),
+                'sizeof(%s) != %d' % (cname, ffi.sizeof(BStruct)),
                 'offsetof(struct _cffi_aligncheck, y) != %d' % (
                     ffi.alignof(BStruct),)]
             for fname, ftype in zip(tp.fldnames, tp.fldtypes):
                 BField = ffi._get_cached_btype(ftype)
                 conditions += [
-                    'offsetof(struct %s, %s) != %d' % (
-                        name, fname, ffi.offsetof(BStruct, fname)),
-                    'sizeof(((struct %s *)0)->%s) != %d' % (
-                        name, fname, ffi.sizeof(BField))]
+                    'offsetof(%s, %s) != %d' % (
+                        cname, fname, ffi.offsetof(BStruct, fname)),
+                    'sizeof(((%s *)0)->%s) != %d' % (
+                        cname, fname, ffi.sizeof(BField))]
             prnt('  if (%s ||' % conditions[0])
             for i in range(1, len(conditions)-1):
                 prnt('      %s ||' % conditions[i])
         prnt('}')
         prnt()
 
-    def generate_cpy_struct_method(self, tp, name):
+    def _generate_struct_or_union_method(self, tp, prefix, name):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        self.prnt('  {"_cffi_struct_%s", _cffi_struct_%s, METH_NOARGS},' % (
-            name, name))
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        self.prnt('  {"%s", %s, METH_NOARGS},' % (layoutfuncname,
+                                                  layoutfuncname))
 
-    def loading_cpy_struct(self, tp, name, module):
+    def _loading_struct_or_union(self, tp, prefix, name, module):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        assert name == tp.name
-        function = getattr(module, '_cffi_struct_%s' % name)
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        cname = ('%s %s' % (prefix, name)).strip()
+        #
+        function = getattr(module, layoutfuncname)
         layout = function()
         if layout is False:
             raise ffiplatform.VerificationError(
-                "incompatible layout for struct %s" % name)
+                "incompatible layout for %s" % cname)
         elif layout is True:
             assert not tp.partial
         else:
             assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
             tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
 
-    def loaded_cpy_struct(self, tp, name, module, **kwds):
+    def _loaded_struct_or_union(self, tp):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
         self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered
 
     # ----------
+    # 'anonymous' declarations.  These are produced for anonymous structs
+    # or unions; the 'name' is obtained by a typedef.
+
+    def generate_cpy_anonymous_decl(self, tp, name):
+        self._generate_struct_or_union_decl(tp, '', name)
+
+    def generate_cpy_anonymous_method(self, tp, name):
+        self._generate_struct_or_union_method(tp, '', name)
+
+    def loading_cpy_anonymous(self, tp, name, module):
+        self._loading_struct_or_union(tp, '', name, module)
+
+    def loaded_cpy_anonymous(self, tp, name, module, **kwds):
+        self._loaded_struct_or_union(tp)
+
+    # ----------
     # constants, likely declared with '#define'
 
     def _generate_cpy_const(self, is_int, name, tp=None, category='const',

File demo/xclient.py

View file
+from cffi import FFI
+
+ffi = FFI()
+ffi.cdef("""
+
+typedef ... Display;
+typedef unsigned int Window;   /* 32-bit integer */
+
+typedef struct { int type; ...; } XEvent;
+
+Display *XOpenDisplay(char *display_name);
+Window DefaultRootWindow(Display *display);
+int XMapRaised(Display *display, Window w);
+Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
+                           unsigned int width, unsigned int height,
+                           unsigned int border_width, unsigned long border,
+                           unsigned long background);
+int XNextEvent(Display *display, XEvent *event_return);
+""")
+lib = ffi.verify("""
+#include <X11/Xlib.h>
+""", libraries=['X11'])
+
+globals().update(lib.__dict__)
+
+class XError(Exception):
+    pass
+
+def main():
+    display = XOpenDisplay(None)
+    if display is None:
+        raise XError("cannot open display")
+    w = XCreateSimpleWindow(display, DefaultRootWindow(display),
+                            10, 10, 500, 350, 0, 0, 0)
+    XMapRaised(display, w)
+    event = ffi.new("XEvent")
+    XNextEvent(display, event)
+
+if __name__ == '__main__':
+    main()

File testing/test_parsing.py

View file
              "typedef struct { int y; } *bar_p;\n")
     assert 'typedef foo_t' in ffi._parser._declarations
     assert 'typedef bar_p' in ffi._parser._declarations
-    #assert 'structdef foo_t' in ffi._parser._declarations ...
-    #assert 'structdef bar_p' in ffi._parser._declarations
+    assert 'anonymous foo_t' in ffi._parser._declarations
     type_foo = ffi._parser.parse_type("foo_t")
     type_bar = ffi._parser.parse_type("bar_p").totype
     assert repr(type_foo) == "<foo_t>"