diff options
-rw-r--r-- | cffi/api.py | 53 | ||||
-rw-r--r-- | cffi/model.py | 2 | ||||
-rw-r--r-- | new/ffi_obj.c | 54 | ||||
-rw-r--r-- | new/parse_c_type.c | 4 | ||||
-rw-r--r-- | new/recompiler.py | 35 | ||||
-rw-r--r-- | new/test_dlopen.py | 28 |
6 files changed, 120 insertions, 56 deletions
diff --git a/cffi/api.py b/cffi/api.py index f74a92c..efd42bb 100644 --- a/cffi/api.py +++ b/cffi/api.py @@ -568,23 +568,48 @@ def _builtin_function_type(func): return ffi._get_cached_btype(tp) def _set_cdef_types(ffi): + from . import model + + all_structs = {} + all_typedefs = {} + for name, tp in ffi._parser._declarations.items(): + kind, basename = name.split(' ', 1) + if kind == 'struct' or kind == 'union' or kind == 'anonymous': + all_structs[tp.name] = tp + elif kind == 'typedef': + all_typedefs[basename] = tp + if getattr(tp, "origin", None) == "unknown_type": + all_structs[tp.name] = tp + elif isinstance(tp, model.NamedPointerType): + all_structs[tp.totype.name] = tp.totype + struct_unions = [] pending_completion = [] - lst = ffi._parser._declarations.items() - lst = sorted(lst, key=lambda x: x[0].split(' ', 1)[1]) - for name, tp in lst: - kind, basename = name.split(' ', 1) - if kind == 'struct' or kind == 'union': - if kind == 'struct': - BType = _cffi1_backend.new_struct_type(basename) - else: - BType = _cffi1_backend.new_union_type(basename) - struct_unions.append(basename) - struct_unions.append(BType) - if not tp.partial and tp.fldtypes is not None: - pending_completion.append((tp, BType)) + for name, tp in sorted(all_structs.items()): + if not isinstance(tp, model.UnionType): + BType = _cffi1_backend.new_struct_type(name) + else: + BType = _cffi1_backend.new_union_type(name) + struct_unions.append(name) + struct_unions.append(BType) + if not tp.partial and tp.fldtypes is not None: + pending_completion.append((tp, BType)) + # + typenames = [] + for name, tp in sorted(all_typedefs.items()): + cname = tp._get_c_name() + if cname == name: + assert isinstance(tp, model.StructOrUnionOrEnum) + cname = '%s %s' % (tp.kind, tp.name) + try: + BType = ffi.typeof(cname) + except ffi.error: + ffi.__set_types(struct_unions, typenames) + BType = ffi.typeof(cname) + typenames.append(name) + typenames.append(BType) # - ffi.__set_types(struct_unions) + ffi.__set_types(struct_unions, typenames) # for tp, BType in pending_completion: fldtypes = [ffi.typeof(ftp._get_c_name()) for ftp in tp.fldtypes] diff --git a/cffi/model.py b/cffi/model.py index 7152f24..955a045 100644 --- a/cffi/model.py +++ b/cffi/model.py @@ -459,7 +459,7 @@ def unknown_type(name, structname=None): def unknown_ptr_type(name, structname=None): if structname is None: - structname = '*$%s' % name + structname = '$$%s' % name tp = StructType(structname, None, None, None) return NamedPointerType(tp, name) diff --git a/new/ffi_obj.c b/new/ffi_obj.c index babcfb2..37f20eb 100644 --- a/new/ffi_obj.c +++ b/new/ffi_obj.c @@ -525,15 +525,18 @@ static int ffi_set_errno(PyObject *self, PyObject *newval, void *closure) static PyObject *ffi__set_types(FFIObject *self, PyObject *args) { - PyObject *lst1; + PyObject *lst1, *lst2; _cffi_opcode_t *types = NULL; struct _cffi_struct_union_s *struct_unions = NULL; + struct _cffi_typename_s *typenames = NULL; - if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &lst1)) + if (!PyArg_ParseTuple(args, "O!O!", + &PyList_Type, &lst1, &PyList_Type, &lst2)) return NULL; if (self->ctx_is_static) { bad_usage: + PyMem_Free(typenames); PyMem_Free(struct_unions); PyMem_Free(types); if (!PyErr_Occurred()) @@ -543,19 +546,24 @@ static PyObject *ffi__set_types(FFIObject *self, PyObject *args) cleanup_builder_c(self->types_builder); - int i, lst_length = PyList_GET_SIZE(lst1) / 2; - Py_ssize_t new_size_1 = sizeof(_cffi_opcode_t) * lst_length; - Py_ssize_t new_size_2 = sizeof(struct _cffi_struct_union_s) * lst_length; - types = PyMem_Malloc(new_size_1); - struct_unions = PyMem_Malloc(new_size_2); - if (!types || !struct_unions) { + int i; + int lst1_length = PyList_GET_SIZE(lst1) / 2; + int lst2_length = PyList_GET_SIZE(lst2) / 2; + Py_ssize_t newsize0 = sizeof(_cffi_opcode_t) * (lst1_length + lst2_length); + Py_ssize_t newsize1 = sizeof(struct _cffi_struct_union_s) * lst1_length; + Py_ssize_t newsize2 = sizeof(struct _cffi_typename_s) * lst2_length; + types = PyMem_Malloc(newsize0); + struct_unions = PyMem_Malloc(newsize1); + typenames = PyMem_Malloc(newsize2); + if (!types || !struct_unions || !typenames) { PyErr_NoMemory(); goto bad_usage; } - memset(types, 0, new_size_1); - memset(struct_unions, 0, new_size_2); + memset(types, 0, newsize0); + memset(struct_unions, 0, newsize1); + memset(typenames, 0, newsize2); - for (i = 0; i < lst_length; i++) { + for (i = 0; i < lst1_length; i++) { PyObject *x = PyList_GET_ITEM(lst1, i * 2); if (!PyString_Check(x)) goto bad_usage; @@ -570,18 +578,32 @@ static PyObject *ffi__set_types(FFIObject *self, PyObject *args) struct_unions[i].size = (size_t)-2; struct_unions[i].alignment = -2; } - for (i = 0; i < lst_length; i++) { + for (i = 0; i < lst2_length; i++) { + PyObject *x = PyList_GET_ITEM(lst2, i * 2); + if (!PyString_Check(x)) + goto bad_usage; + typenames[i].name = PyString_AS_STRING(x); + typenames[i].type_index = lst1_length + i; + + x = PyList_GET_ITEM(lst2, i * 2 + 1); + if (!CTypeDescr_Check(x)) + goto bad_usage; + types[lst1_length + i] = x; + } + for (i = 0; i < lst1_length + lst2_length; i++) { PyObject *x = (PyObject *)types[i]; Py_INCREF(x); } - Py_INCREF(lst1); /* to keep alive the strings in '.name' */ + Py_INCREF(args); /* to keep alive the strings in '.name' */ Py_XDECREF(self->dynamic_types); - self->dynamic_types = lst1; + self->dynamic_types = args; self->types_builder->ctx.types = types; - self->types_builder->num_types_imported = lst_length; + self->types_builder->num_types_imported = lst1_length + lst2_length; self->types_builder->ctx.struct_unions = struct_unions; - self->types_builder->ctx.num_struct_unions = lst_length; + self->types_builder->ctx.num_struct_unions = lst1_length; + self->types_builder->ctx.typenames = typenames; + self->types_builder->ctx.num_typenames = lst2_length; Py_INCREF(Py_None); return Py_None; diff --git a/new/parse_c_type.c b/new/parse_c_type.c index 426584b..05f38e8 100644 --- a/new/parse_c_type.c +++ b/new/parse_c_type.c @@ -56,7 +56,9 @@ static int is_space(char x) static int is_ident_first(char x) { - return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_'); + return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' || + x == '$'); /* '$' in names is supported here, for the struct + names invented by cparser */ } static int is_digit(char x) diff --git a/new/recompiler.py b/new/recompiler.py index 65e429f..4acc7d0 100644 --- a/new/recompiler.py +++ b/new/recompiler.py @@ -508,8 +508,17 @@ class Recompiler: _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype def _generate_cpy_struct_decl(self, tp, name): - cname = tp.get_c_name('') - self._struct_decl(tp, cname, cname.replace(' ', '_')) + cname = tp._get_c_name() + if ' ' in cname: + prefix, declname = cname.split(' ', 1) + else: + prefix, declname = '', cname + while declname.startswith('$'): + prefix += 'D' + declname = declname[1:] + approxname = prefix + '_' + declname + assert '$' not in approxname + self._struct_decl(tp, cname, approxname) _generate_cpy_union_decl = _generate_cpy_struct_decl def _generate_cpy_struct_ctx(self, tp, name, prefix='s'): @@ -518,28 +527,6 @@ class Recompiler: _generate_cpy_union_ctx = _generate_cpy_struct_ctx # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - def _generate_cpy_anonymous_collecttype(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_collecttype(tp, name) - else: - self._struct_collecttype(tp) - - def _generate_cpy_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_decl(tp, name, '') - else: - self._struct_decl(tp, name, 'typedef_' + name) - - def _generate_cpy_anonymous_ctx(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_ctx(tp, name, '') - else: - self._struct_ctx(tp, name, 'typedef_' + name) - - # ---------- # constants, declared with "static const ..." def _generate_cpy_const(self, is_int, name, tp=None, category='const', diff --git a/new/test_dlopen.py b/new/test_dlopen.py index b1348f9..633c731 100644 --- a/new/test_dlopen.py +++ b/new/test_dlopen.py @@ -19,6 +19,34 @@ def test_cdef_struct_union(): assert ffi.sizeof("union bar_s") == 4 assert ffi.sizeof("struct foo_s") == 4 +def test_cdef_struct_typename_1(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } t1; typedef struct { t1* m; } t2;") + assert ffi.sizeof("t2") == ffi.sizeof("void *") + assert ffi.sizeof("t1") == 4 + +def test_cdef_struct_typename_2(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } *p1; typedef struct { p1 m; } *p2;") + p2 = ffi.new("p2") + assert ffi.sizeof(p2[0]) == ffi.sizeof("void *") + assert ffi.sizeof(p2[0].m) == ffi.sizeof("void *") + +def test_cdef_struct_anon_1(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } t1; struct foo_s { t1* m; };") + assert ffi.sizeof("struct foo_s") == ffi.sizeof("void *") + +def test_cdef_struct_anon_2(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } *p1; struct foo_s { p1 m; };") + assert ffi.sizeof("struct foo_s") == ffi.sizeof("void *") + +def test_cdef_struct_anon_3(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } **pp; struct foo_s { pp m; };") + assert ffi.sizeof("struct foo_s") == ffi.sizeof("void *") + def test_math_sin(): py.test.skip("XXX redo!") ffi = FFI() |