[pypy-commit] cffi default: Issue #228: do the same for "FILE". Only remaining case now is the

arigo noreply at buildbot.pypy.org
Tue Nov 3 02:47:14 EST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2368:8b042b8ebb63
Date: 2015-11-03 08:47 +0100
http://bitbucket.org/cffi/cffi/changeset/8b042b8ebb63/

Log:	Issue #228: do the same for "FILE". Only remaining case now is the
	very obscure Windows type UNICODE_STRING. I think it is unlikely
	that someone hits the case of their cdef not mentioning
	UNICODE_STRING but their runtime code still wants to use it, so I'll
	close this issue.

diff --git a/c/commontypes.c b/c/commontypes.c
--- a/c/commontypes.c
+++ b/c/commontypes.c
@@ -23,6 +23,11 @@
     EQ("DWORD64", "unsigned long long"),
     EQ("DWORDLONG", "ULONGLONG"),
     EQ("DWORD_PTR", "ULONG_PTR"),
+#endif
+
+    EQ("FILE", "struct _IO_FILE"),
+
+#ifdef MS_WIN32   /* more Windows types */
     EQ("FLOAT", "float"),
     EQ("HACCEL", "HANDLE"),
     EQ("HALF_PTR", W32_64("short","int")),
diff --git a/c/parse_c_type.c b/c/parse_c_type.c
--- a/c/parse_c_type.c
+++ b/c/parse_c_type.c
@@ -755,10 +755,15 @@
                 return parse_error(tok, "struct or union name expected");
 
             n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size);
-            if (n < 0)
-                return parse_error(tok, "undefined struct/union name");
-            if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) != 0)
-                ^ (kind == TOK_UNION))
+            if (n < 0) {
+                if (kind == TOK_STRUCT && tok->size == 8 &&
+                        !memcmp(tok->p, "_IO_FILE", 8))
+                    n = _CFFI__IO_FILE_STRUCT;
+                else
+                    return parse_error(tok, "undefined struct/union name");
+            }
+            else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION)
+                      != 0) ^ (kind == TOK_UNION))
                 return parse_error(tok, "wrong kind of tag: struct vs union");
 
             t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n);
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
--- a/c/realize_c_type.c
+++ b/c/realize_c_type.c
@@ -314,6 +314,16 @@
     _cffi_opcode_t op2;
     const struct _cffi_struct_union_s *s;
 
+    if (sindex == _CFFI__IO_FILE_STRUCT) {
+        /* returns a single global cached opaque type */
+        static PyObject *file_struct = NULL;
+        if (file_struct == NULL)
+            file_struct = new_struct_or_union_type("struct _IO_FILE",
+                                                   CT_STRUCT | CT_IS_FILE);
+        Py_XINCREF(file_struct);
+        return file_struct;
+    }
+
     s = &builder->ctx.struct_unions[sindex];
     op2 = builder->ctx.types[s->type_index];
     if ((((uintptr_t)op2) & 1) == 0) {
@@ -330,9 +340,9 @@
                           (s->flags & _CFFI_F_UNION) ? "union " : "struct ",
                           s->name);
             if (strcmp(name, "struct _IO_FILE") == 0)
-                flags |= CT_IS_FILE;
-
-            x = new_struct_or_union_type(name, flags);
+                x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT);
+            else
+                x = new_struct_or_union_type(name, flags);
             if (x == NULL)
                 return NULL;
 
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -110,6 +110,8 @@
 _UNKNOWN_FLOAT_PRIM    = -2
 _UNKNOWN_LONG_DOUBLE   = -3
 
+_IO_FILE_STRUCT        = -1
+
 PRIMITIVE_TO_INDEX = {
     'char':               PRIM_CHAR,
     'short':              PRIM_SHORT,
diff --git a/cffi/commontypes.py b/cffi/commontypes.py
--- a/cffi/commontypes.py
+++ b/cffi/commontypes.py
@@ -2,10 +2,7 @@
 from . import api, model
 
 
-COMMON_TYPES = {
-    'FILE': model.unknown_type('FILE', '_IO_FILE'),
-    'bool': '_Bool',
-    }
+COMMON_TYPES = {}
 
 try:
     # fetch "bool" and all simple Windows types
@@ -14,6 +11,9 @@
 except ImportError:
     pass
 
+COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE')
+COMMON_TYPES['bool'] = '_Bool'    # in case we got ImportError above
+
 for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
     if _type.endswith('_t'):
         COMMON_TYPES[_type] = _type
diff --git a/cffi/parse_c_type.h b/cffi/parse_c_type.h
--- a/cffi/parse_c_type.h
+++ b/cffi/parse_c_type.h
@@ -83,6 +83,8 @@
 #define _CFFI__UNKNOWN_FLOAT_PRIM     (-2)
 #define _CFFI__UNKNOWN_LONG_DOUBLE    (-3)
 
+#define _CFFI__IO_FILE_STRUCT         (-1)
+
 
 struct _cffi_global_s {
     const char *name;
diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py
--- a/testing/cffi1/test_ffi_obj.py
+++ b/testing/cffi1/test_ffi_obj.py
@@ -401,6 +401,12 @@
     fntype = ffi.typeof("int(*callback)(bool is_valid)")
     assert repr(fntype.args[0]) == "<ctype '_Bool'>"
 
+def test_FILE_issue228():
+    fntype1 = _cffi1_backend.FFI().typeof("FILE *")
+    fntype2 = _cffi1_backend.FFI().typeof("FILE *")
+    assert repr(fntype1) == "<ctype 'struct _IO_FILE *'>"
+    assert fntype1 is fntype2
+
 def test_cast_from_int_type_to_bool():
     ffi = _cffi1_backend.FFI()
     for basetype in ['char', 'short', 'int', 'long', 'long long']:
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -2246,3 +2246,26 @@
     ffi = FFI()
     ffi.cdef("struct s { char *const *a; };")
     ffi.verify("struct s { char *const *a; };")
+
+def test_share_FILE():
+    ffi1 = FFI()
+    ffi1.cdef("void do_stuff(FILE *);")
+    lib1 = ffi1.verify("void do_stuff(FILE *f) { (void)f; }")
+    ffi2 = FFI()
+    ffi2.cdef("FILE *barize(void);")
+    lib2 = ffi2.verify("FILE *barize(void) { return NULL; }")
+    lib1.do_stuff(lib2.barize())
+
+def test_win_common_types():
+    if sys.platform != 'win32':
+        py.test.skip("Windows only")
+    ffi = FFI()
+    ffi.set_unicode(True)
+    ffi.verify("")
+    assert ffi.typeof("PBYTE") is ffi.typeof("unsigned char *")
+    if sys.maxsize > 2**32:
+        expected = "unsigned long long"
+    else:
+        expected = "unsigned int"
+    assert ffi.typeof("UINT_PTR") is ffi.typeof(expected)
+    assert ffi.typeof("PTSTR") is ffi.typeof("wchar_t *")


More information about the pypy-commit mailing list