summaryrefslogtreecommitdiff
path: root/cffi
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2020-05-20 23:29:46 +0200
committerArmin Rigo <arigo@tunes.org>2020-05-20 23:29:46 +0200
commitbb48fdcc86c5bd2c211fba2ac4cffe8b6efb49e2 (patch)
treedd4e9101065c0a799cca5c03f31c3c310ef15d9a /cffi
parent680aa960da02dfa304c6b889489c05c38de89318 (diff)
downloadcffi-bb48fdcc86c5bd2c211fba2ac4cffe8b6efb49e2.tar.gz
#453
Special-case typedefs of arrays with '...' length, so that they can be used through recompiler.py as if they had a specified length in most cases.
Diffstat (limited to 'cffi')
-rw-r--r--cffi/cparser.py18
-rw-r--r--cffi/model.py7
-rw-r--r--cffi/vengine_cpy.py4
-rw-r--r--cffi/vengine_gen.py4
4 files changed, 24 insertions, 9 deletions
diff --git a/cffi/cparser.py b/cffi/cparser.py
index ea27c48..d7069a7 100644
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -395,7 +395,8 @@ class Parser(object):
realtype = self._get_unknown_ptr_type(decl)
else:
realtype, quals = self._get_type_and_quals(
- decl.type, name=decl.name, partial_length_ok=True)
+ decl.type, name=decl.name, partial_length_ok=True,
+ typedef_example="*(%s *)0" % (decl.name,))
self._declare('typedef ' + decl.name, realtype, quals=quals)
elif decl.__class__.__name__ == 'Pragma':
pass # skip pragma, only in pycparser 2.15
@@ -562,7 +563,8 @@ class Parser(object):
return model.NamedPointerType(type, declname, quals)
return model.PointerType(type, quals)
- def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False):
+ def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False,
+ typedef_example=None):
# first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
@@ -579,8 +581,18 @@ class Parser(object):
else:
length = self._parse_constant(
typenode.dim, partial_length_ok=partial_length_ok)
+ # a hack: in 'typedef int foo_t[...][...];', don't use '...' as
+ # the length but use directly the C expression that would be
+ # generated by recompiler.py. This lets the typedef be used in
+ # many more places within recompiler.py
+ if typedef_example is not None:
+ if length == '...':
+ length = '_cffi_array_len(%s)' % (typedef_example,)
+ typedef_example = "*" + typedef_example
+ #
tp, quals = self._get_type_and_quals(typenode.type,
- partial_length_ok=partial_length_ok)
+ partial_length_ok=partial_length_ok,
+ typedef_example=typedef_example)
return model.ArrayType(tp, length), quals
#
if isinstance(typenode, pycparser.c_ast.PtrDecl):
diff --git a/cffi/model.py b/cffi/model.py
index 5f1b0d2..ad1c176 100644
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -307,11 +307,14 @@ class ArrayType(BaseType):
self.c_name_with_marker = (
self.item.c_name_with_marker.replace('&', brackets))
+ def length_is_unknown(self):
+ return isinstance(self.length, str)
+
def resolve_length(self, newlength):
return ArrayType(self.item, newlength)
def build_backend_type(self, ffi, finishlist):
- if self.length == '...':
+ if self.length_is_unknown():
raise CDefError("cannot render the type %r: unknown length" %
(self,))
self.item.get_cached_btype(ffi, finishlist) # force the item BType
@@ -430,7 +433,7 @@ class StructOrUnion(StructOrUnionOrEnum):
fsize = fieldsize[i]
ftype = self.fldtypes[i]
#
- if isinstance(ftype, ArrayType) and ftype.length == '...':
+ if isinstance(ftype, ArrayType) and ftype.length_is_unknown():
# fix the length to match the total size
BItemType = ftype.item.get_cached_btype(ffi, finishlist)
nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
index cb344ce..6de0df0 100644
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -762,7 +762,7 @@ class VCPythonEngine(object):
if isinstance(tp, model.ArrayType):
tp_ptr = model.PointerType(tp.item)
self._generate_cpy_const(False, name, tp, vartp=tp_ptr,
- size_too = (tp.length == '...'))
+ size_too = tp.length_is_unknown())
else:
tp_ptr = model.PointerType(tp)
self._generate_cpy_const(False, name, tp_ptr, category='var')
@@ -774,7 +774,7 @@ class VCPythonEngine(object):
value = getattr(library, name)
if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
# sense that "a=..." is forbidden
- if tp.length == '...':
+ if tp.length_is_unknown():
assert isinstance(value, tuple)
(value, size) = value
BItemType = self.ffi._get_cached_btype(tp.item)
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
index a64ff64..2642152 100644
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -565,7 +565,7 @@ class VGenericEngine(object):
def _generate_gen_variable_decl(self, tp, name):
if isinstance(tp, model.ArrayType):
- if tp.length == '...':
+ if tp.length_is_unknown():
prnt = self._prnt
funcname = '_cffi_sizeof_%s' % (name,)
self.export_symbols.append(funcname)
@@ -584,7 +584,7 @@ class VGenericEngine(object):
def _loaded_gen_variable(self, tp, name, module, library):
if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
# sense that "a=..." is forbidden
- if tp.length == '...':
+ if tp.length_is_unknown():
funcname = '_cffi_sizeof_%s' % (name,)
BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0]
function = module.load_function(BFunc, funcname)