Armin Rigo avatar Armin Rigo committed ee2c2a7

Implementation

Comments (0)

Files changed (6)

c/_cffi_backend.c

         return NULL;
 
     flag = CT_STRUCT;
-    if (strcmp(name, "_IO_FILE") == 0)
+    if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
         flag |= CT_IS_FILE;
     return _b_struct_or_union_type("struct", name, flag);
 }
     if sys.platform == "win32":
         py.test.skip("testing FILE not implemented")
     #
-    BFILE = new_struct_type("_IO_FILE")
+    BFILE = new_struct_type("$FILE")
     BFILEP = new_pointer_type(BFILE)
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
             if name.startswith('RTLD_'):
                 setattr(self, name, getattr(backend, name))
         #
-        self._parser._declarations['typedef FILE'] = model.file_type
         BVoidP = self._get_cached_btype(model.voidp_type)
         if isinstance(backend, types.ModuleType):
             # _cffi_backend: attach these constants to the class
 
 from . import api, model
+from .commontypes import COMMON_TYPES
 import pycparser.c_parser, weakref, re, sys
 
 try:
 _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
 _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
 _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
+_r_words = re.compile(r"\w+|\S")
 _parser_cache = None
 
 def _get_parser():
     # which is declared with a typedef for the purpose of C parsing.
     return csource.replace('...', ' __dotdotdot__ '), macros
 
+def _common_type_names(csource):
+    # Look in the source for what looks like usages of types from the
+    # list of common types.  A "usage" is approximated here as the
+    # appearance of the word, minus a "definition" of the type, which
+    # is the last word in a "typedef" statement.  Approximative only
+    # but should be fine for all the common types.
+    look_for_words = set(COMMON_TYPES)
+    look_for_words.add(';')
+    look_for_words.add('typedef')
+    words_used = set()
+    is_typedef = False
+    previous_word = ''
+    for word in _r_words.findall(csource):
+        if word in look_for_words:
+            if word == ';':
+                if is_typedef:
+                    words_used.discard(previous_word)
+                    look_for_words.discard(previous_word)
+                    is_typedef = False
+            elif word == 'typedef':
+                is_typedef = True
+            else:   # word in COMMON_TYPES
+                words_used.add(word)
+        previous_word = word
+    return words_used
+
+
 class Parser(object):
-    TYPEDEFS = sorted(
-        [_name for _name in model.PrimitiveType.ALL_PRIMITIVE_TYPES
-               if _name.endswith('_t')])
 
     def __init__(self):
         self._declarations = {}
         self._override = False
 
     def _parse(self, csource):
+        csource, macros = _preprocess(csource)
         # XXX: for more efficiency we would need to poke into the
         # internals of CParser...  the following registers the
         # typedefs, because their presence or absence influences the
         # parsing itself (but what they are typedef'ed to plays no role)
-        typenames = self.TYPEDEFS[:]
+        ctn = _common_type_names(csource)
+        print `csource`, ctn
+        typenames = []
         for name in sorted(self._declarations):
             if name.startswith('typedef '):
-                typenames.append(name[8:])
+                name = name[8:]
+                typenames.append(name)
+                ctn.discard(name)
+        typenames += sorted(ctn)
+        #
         csourcelines = ['typedef int %s;' % typename for typename in typenames]
         csourcelines.append('typedef int __dotdotdot__;')
-        csource, macros = _preprocess(csource)
         csourcelines.append(csource)
         csource = '\n'.join(csourcelines)
         if lock is not None:
                     return model.void_type
                 if ident == '__dotdotdot__':
                     raise api.FFIError('bad usage of "..."')
+                if ident in COMMON_TYPES:
+                    return COMMON_TYPES[ident]
                 return model.PrimitiveType(ident)
             #
             if isinstance(type, pycparser.c_ast.Struct):
         'float':              'f',
         'double':             'f',
         'long double':        'f',
-        'wchar_t':            'c',
         '_Bool':              'u',
         # the following types are not primitive in the C sense
+        'wchar_t':            'c',
         'int8_t':             'i',
         'uint8_t':            'u',
         'int16_t':            'i',

testing/test_parsing.py

     assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
     e = py.test.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
     assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')
+
+def test_redefine_common_type():
+    ffi = FFI()
+    ffi.cdef("typedef char FILE;")
+    assert repr(ffi.cast("FILE", 123)) == "<cdata 'char' '{'>"
+    ffi.cdef("typedef char int32_t;")
+    assert repr(ffi.cast("int32_t", 123)) == "<cdata 'char' '{'>"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.