Spaces:
Sleeping
Sleeping
| # | |
| # DEPRECATED: implementation for ffi.verify() | |
| # | |
| import sys | |
| from . import model | |
| from .error import VerificationError | |
| from . import _imp_emulation as imp | |
| class VCPythonEngine(object): | |
| _class_key = 'x' | |
| _gen_python_module = True | |
| def __init__(self, verifier): | |
| self.verifier = verifier | |
| self.ffi = verifier.ffi | |
| self._struct_pending_verification = {} | |
| self._types_of_builtin_functions = {} | |
| def patch_extension_kwds(self, kwds): | |
| pass | |
| def find_module(self, module_name, path, so_suffixes): | |
| try: | |
| f, filename, descr = imp.find_module(module_name, path) | |
| except ImportError: | |
| return None | |
| if f is not None: | |
| f.close() | |
| # Note that after a setuptools installation, there are both .py | |
| # and .so files with the same basename. The code here relies on | |
| # imp.find_module() locating the .so in priority. | |
| if descr[0] not in so_suffixes: | |
| return None | |
| return filename | |
| def collect_types(self): | |
| self._typesdict = {} | |
| self._generate("collecttype") | |
| def _prnt(self, what=''): | |
| self._f.write(what + '\n') | |
| def _gettypenum(self, type): | |
| # a KeyError here is a bug. please report it! :-) | |
| return self._typesdict[type] | |
| def _do_collect_type(self, tp): | |
| if ((not isinstance(tp, model.PrimitiveType) | |
| or tp.name == 'long double') | |
| and tp not in self._typesdict): | |
| num = len(self._typesdict) | |
| self._typesdict[tp] = num | |
| def write_source_to_f(self): | |
| self.collect_types() | |
| # | |
| # The new module will have a _cffi_setup() function that receives | |
| # objects from the ffi world, and that calls some setup code in | |
| # the module. This setup code is split in several independent | |
| # functions, e.g. one per constant. The functions are "chained" | |
| # by ending in a tail call to each other. | |
| # | |
| # This is further split in two chained lists, depending on if we | |
| # can do it at import-time or if we must wait for _cffi_setup() to | |
| # provide us with the <ctype> objects. This is needed because we | |
| # need the values of the enum constants in order to build the | |
| # <ctype 'enum'> that we may have to pass to _cffi_setup(). | |
| # | |
| # The following two 'chained_list_constants' items contains | |
| # the head of these two chained lists, as a string that gives the | |
| # call to do, if any. | |
| self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] | |
| # | |
| prnt = self._prnt | |
| # first paste some standard set of lines that are mostly '#define' | |
| prnt(cffimod_header) | |
| prnt() | |
| # then paste the C source given by the user, verbatim. | |
| prnt(self.verifier.preamble) | |
| prnt() | |
| # | |
| # call generate_cpy_xxx_decl(), for every xxx found from | |
| # ffi._parser._declarations. This generates all the functions. | |
| self._generate("decl") | |
| # | |
| # implement the function _cffi_setup_custom() as calling the | |
| # head of the chained list. | |
| self._generate_setup_custom() | |
| prnt() | |
| # | |
| # produce the method table, including the entries for the | |
| # generated Python->C function wrappers, which are done | |
| # by generate_cpy_function_method(). | |
| prnt('static PyMethodDef _cffi_methods[] = {') | |
| self._generate("method") | |
| prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') | |
| prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') | |
| prnt('};') | |
| prnt() | |
| # | |
| # standard init. | |
| modname = self.verifier.get_module_name() | |
| constants = self._chained_list_constants[False] | |
| prnt('#if PY_MAJOR_VERSION >= 3') | |
| prnt() | |
| prnt('static struct PyModuleDef _cffi_module_def = {') | |
| prnt(' PyModuleDef_HEAD_INIT,') | |
| prnt(' "%s",' % modname) | |
| prnt(' NULL,') | |
| prnt(' -1,') | |
| prnt(' _cffi_methods,') | |
| prnt(' NULL, NULL, NULL, NULL') | |
| prnt('};') | |
| prnt() | |
| prnt('PyMODINIT_FUNC') | |
| prnt('PyInit_%s(void)' % modname) | |
| prnt('{') | |
| prnt(' PyObject *lib;') | |
| prnt(' lib = PyModule_Create(&_cffi_module_def);') | |
| prnt(' if (lib == NULL)') | |
| prnt(' return NULL;') | |
| prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) | |
| prnt(' Py_DECREF(lib);') | |
| prnt(' return NULL;') | |
| prnt(' }') | |
| prnt('#if Py_GIL_DISABLED') | |
| prnt(' PyUnstable_Module_SetGIL(lib, Py_MOD_GIL_NOT_USED);') | |
| prnt('#endif') | |
| prnt(' return lib;') | |
| prnt('}') | |
| prnt() | |
| prnt('#else') | |
| prnt() | |
| prnt('PyMODINIT_FUNC') | |
| prnt('init%s(void)' % modname) | |
| prnt('{') | |
| prnt(' PyObject *lib;') | |
| prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) | |
| prnt(' if (lib == NULL)') | |
| prnt(' return;') | |
| prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) | |
| prnt(' return;') | |
| prnt(' return;') | |
| prnt('}') | |
| prnt() | |
| prnt('#endif') | |
| def load_library(self, flags=None): | |
| # XXX review all usages of 'self' here! | |
| # import it as a new extension module | |
| imp.acquire_lock() | |
| try: | |
| if hasattr(sys, "getdlopenflags"): | |
| previous_flags = sys.getdlopenflags() | |
| try: | |
| if hasattr(sys, "setdlopenflags") and flags is not None: | |
| sys.setdlopenflags(flags) | |
| module = imp.load_dynamic(self.verifier.get_module_name(), | |
| self.verifier.modulefilename) | |
| except ImportError as e: | |
| error = "importing %r: %s" % (self.verifier.modulefilename, e) | |
| raise VerificationError(error) | |
| finally: | |
| if hasattr(sys, "setdlopenflags"): | |
| sys.setdlopenflags(previous_flags) | |
| finally: | |
| imp.release_lock() | |
| # | |
| # call loading_cpy_struct() to get the struct layout inferred by | |
| # the C compiler | |
| self._load(module, 'loading') | |
| # | |
| # the C code will need the <ctype> objects. Collect them in | |
| # order in a list. | |
| revmapping = dict([(value, key) | |
| for (key, value) in self._typesdict.items()]) | |
| lst = [revmapping[i] for i in range(len(revmapping))] | |
| lst = list(map(self.ffi._get_cached_btype, lst)) | |
| # | |
| # build the FFILibrary class and instance and call _cffi_setup(). | |
| # this will set up some fields like '_cffi_types', and only then | |
| # it will invoke the chained list of functions that will really | |
| # build (notably) the constant objects, as <cdata> if they are | |
| # pointers, and store them as attributes on the 'library' object. | |
| class FFILibrary(object): | |
| _cffi_python_module = module | |
| _cffi_ffi = self.ffi | |
| _cffi_dir = [] | |
| def __dir__(self): | |
| return FFILibrary._cffi_dir + list(self.__dict__) | |
| library = FFILibrary() | |
| if module._cffi_setup(lst, VerificationError, library): | |
| import warnings | |
| warnings.warn("reimporting %r might overwrite older definitions" | |
| % (self.verifier.get_module_name())) | |
| # | |
| # finally, call the loaded_cpy_xxx() functions. This will perform | |
| # the final adjustments, like copying the Python->C wrapper | |
| # functions from the module to the 'library' object, and setting | |
| # up the FFILibrary class with properties for the global C variables. | |
| self._load(module, 'loaded', library=library) | |
| module._cffi_original_ffi = self.ffi | |
| module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions | |
| return library | |
| def _get_declarations(self): | |
| lst = [(key, tp) for (key, (tp, qual)) in | |
| self.ffi._parser._declarations.items()] | |
| lst.sort() | |
| return lst | |
| def _generate(self, step_name): | |
| for name, tp in self._get_declarations(): | |
| kind, realname = name.split(' ', 1) | |
| try: | |
| method = getattr(self, '_generate_cpy_%s_%s' % (kind, | |
| step_name)) | |
| except AttributeError: | |
| raise VerificationError( | |
| "not implemented in verify(): %r" % name) | |
| try: | |
| method(tp, realname) | |
| except Exception as e: | |
| model.attach_exception_info(e, name) | |
| raise | |
| def _load(self, module, step_name, **kwds): | |
| for name, tp in self._get_declarations(): | |
| kind, realname = name.split(' ', 1) | |
| method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) | |
| try: | |
| method(tp, realname, module, **kwds) | |
| except Exception as e: | |
| model.attach_exception_info(e, name) | |
| raise | |
| def _generate_nothing(self, tp, name): | |
| pass | |
| def _loaded_noop(self, tp, name, module, **kwds): | |
| pass | |
| # ---------- | |
| def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): | |
| extraarg = '' | |
| if isinstance(tp, model.PrimitiveType): | |
| if tp.is_integer_type() and tp.name != '_Bool': | |
| converter = '_cffi_to_c_int' | |
| extraarg = ', %s' % tp.name | |
| elif tp.is_complex_type(): | |
| raise VerificationError( | |
| "not implemented in verify(): complex types") | |
| else: | |
| converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), | |
| tp.name.replace(' ', '_')) | |
| errvalue = '-1' | |
| # | |
| elif isinstance(tp, model.PointerType): | |
| self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, | |
| tovar, errcode) | |
| return | |
| # | |
| elif isinstance(tp, (model.StructOrUnion, model.EnumType)): | |
| # a struct (not a struct pointer) as a function argument | |
| self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' | |
| % (tovar, self._gettypenum(tp), fromvar)) | |
| self._prnt(' %s;' % errcode) | |
| return | |
| # | |
| elif isinstance(tp, model.FunctionPtrType): | |
| converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') | |
| extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) | |
| errvalue = 'NULL' | |
| # | |
| else: | |
| raise NotImplementedError(tp) | |
| # | |
| self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) | |
| self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( | |
| tovar, tp.get_c_name(''), errvalue)) | |
| self._prnt(' %s;' % errcode) | |
| def _extra_local_variables(self, tp, localvars, freelines): | |
| if isinstance(tp, model.PointerType): | |
| localvars.add('Py_ssize_t datasize') | |
| localvars.add('struct _cffi_freeme_s *large_args_free = NULL') | |
| freelines.add('if (large_args_free != NULL)' | |
| ' _cffi_free_array_arguments(large_args_free);') | |
| def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): | |
| self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') | |
| self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( | |
| self._gettypenum(tp), fromvar, tovar)) | |
| self._prnt(' if (datasize != 0) {') | |
| self._prnt(' %s = ((size_t)datasize) <= 640 ? ' | |
| 'alloca((size_t)datasize) : NULL;' % (tovar,)) | |
| self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' | |
| '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) | |
| self._prnt(' datasize, &large_args_free) < 0)') | |
| self._prnt(' %s;' % errcode) | |
| self._prnt(' }') | |
| def _convert_expr_from_c(self, tp, var, context): | |
| if isinstance(tp, model.PrimitiveType): | |
| if tp.is_integer_type() and tp.name != '_Bool': | |
| return '_cffi_from_c_int(%s, %s)' % (var, tp.name) | |
| elif tp.name != 'long double': | |
| return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) | |
| else: | |
| return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( | |
| var, self._gettypenum(tp)) | |
| elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): | |
| return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( | |
| var, self._gettypenum(tp)) | |
| elif isinstance(tp, model.ArrayType): | |
| return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( | |
| var, self._gettypenum(model.PointerType(tp.item))) | |
| elif isinstance(tp, model.StructOrUnion): | |
| if tp.fldnames is None: | |
| raise TypeError("'%s' is used as %s, but is opaque" % ( | |
| tp._get_c_name(), context)) | |
| return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( | |
| var, self._gettypenum(tp)) | |
| elif isinstance(tp, model.EnumType): | |
| return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( | |
| var, self._gettypenum(tp)) | |
| else: | |
| raise NotImplementedError(tp) | |
| # ---------- | |
| # typedefs: generates no code so far | |
| _generate_cpy_typedef_collecttype = _generate_nothing | |
| _generate_cpy_typedef_decl = _generate_nothing | |
| _generate_cpy_typedef_method = _generate_nothing | |
| _loading_cpy_typedef = _loaded_noop | |
| _loaded_cpy_typedef = _loaded_noop | |
| # ---------- | |
| # function declarations | |
| def _generate_cpy_function_collecttype(self, tp, name): | |
| assert isinstance(tp, model.FunctionPtrType) | |
| if tp.ellipsis: | |
| self._do_collect_type(tp) | |
| else: | |
| # don't call _do_collect_type(tp) in this common case, | |
| # otherwise test_autofilled_struct_as_argument fails | |
| for type in tp.args: | |
| self._do_collect_type(type) | |
| self._do_collect_type(tp.result) | |
| def _generate_cpy_function_decl(self, tp, name): | |
| assert isinstance(tp, model.FunctionPtrType) | |
| if tp.ellipsis: | |
| # cannot support vararg functions better than this: check for its | |
| # exact type (including the fixed arguments), and build it as a | |
| # constant function pointer (no CPython wrapper) | |
| self._generate_cpy_const(False, name, tp) | |
| return | |
| prnt = self._prnt | |
| numargs = len(tp.args) | |
| if numargs == 0: | |
| argname = 'noarg' | |
| elif numargs == 1: | |
| argname = 'arg0' | |
| else: | |
| argname = 'args' | |
| prnt('static PyObject *') | |
| prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) | |
| prnt('{') | |
| # | |
| context = 'argument of %s' % name | |
| for i, type in enumerate(tp.args): | |
| prnt(' %s;' % type.get_c_name(' x%d' % i, context)) | |
| # | |
| localvars = set() | |
| freelines = set() | |
| for type in tp.args: | |
| self._extra_local_variables(type, localvars, freelines) | |
| for decl in sorted(localvars): | |
| prnt(' %s;' % (decl,)) | |
| # | |
| if not isinstance(tp.result, model.VoidType): | |
| result_code = 'result = ' | |
| context = 'result of %s' % name | |
| prnt(' %s;' % tp.result.get_c_name(' result', context)) | |
| prnt(' PyObject *pyresult;') | |
| else: | |
| result_code = '' | |
| # | |
| if len(tp.args) > 1: | |
| rng = range(len(tp.args)) | |
| for i in rng: | |
| prnt(' PyObject *arg%d;' % i) | |
| prnt() | |
| prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( | |
| 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) | |
| prnt(' return NULL;') | |
| prnt() | |
| # | |
| for i, type in enumerate(tp.args): | |
| self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, | |
| 'return NULL') | |
| prnt() | |
| # | |
| prnt(' Py_BEGIN_ALLOW_THREADS') | |
| prnt(' _cffi_restore_errno();') | |
| prnt(' { %s%s(%s); }' % ( | |
| result_code, name, | |
| ', '.join(['x%d' % i for i in range(len(tp.args))]))) | |
| prnt(' _cffi_save_errno();') | |
| prnt(' Py_END_ALLOW_THREADS') | |
| prnt() | |
| # | |
| prnt(' (void)self; /* unused */') | |
| if numargs == 0: | |
| prnt(' (void)noarg; /* unused */') | |
| if result_code: | |
| prnt(' pyresult = %s;' % | |
| self._convert_expr_from_c(tp.result, 'result', 'result type')) | |
| for freeline in freelines: | |
| prnt(' ' + freeline) | |
| prnt(' return pyresult;') | |
| else: | |
| for freeline in freelines: | |
| prnt(' ' + freeline) | |
| prnt(' Py_INCREF(Py_None);') | |
| prnt(' return Py_None;') | |
| prnt('}') | |
| prnt() | |
| def _generate_cpy_function_method(self, tp, name): | |
| if tp.ellipsis: | |
| return | |
| numargs = len(tp.args) | |
| if numargs == 0: | |
| meth = 'METH_NOARGS' | |
| elif numargs == 1: | |
| meth = 'METH_O' | |
| else: | |
| meth = 'METH_VARARGS' | |
| self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) | |
| _loading_cpy_function = _loaded_noop | |
| def _loaded_cpy_function(self, tp, name, module, library): | |
| if tp.ellipsis: | |
| return | |
| func = getattr(module, name) | |
| setattr(library, name, func) | |
| self._types_of_builtin_functions[func] = tp | |
| # ---------- | |
| # named structs | |
| _generate_cpy_struct_collecttype = _generate_nothing | |
| 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) | |
| _generate_cpy_union_collecttype = _generate_nothing | |
| def _generate_cpy_union_decl(self, tp, name): | |
| assert name == tp.name | |
| self._generate_struct_or_union_decl(tp, 'union', name) | |
| def _generate_cpy_union_method(self, tp, name): | |
| self._generate_struct_or_union_method(tp, 'union', name) | |
| def _loading_cpy_union(self, tp, name, module): | |
| self._loading_struct_or_union(tp, 'union', name, module) | |
| def _loaded_cpy_union(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 | |
| checkfuncname = '_cffi_check_%s_%s' % (prefix, name) | |
| layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) | |
| cname = ('%s %s' % (prefix, name)).strip() | |
| # | |
| prnt = self._prnt | |
| prnt('static void %s(%s *p)' % (checkfuncname, cname)) | |
| prnt('{') | |
| prnt(' /* only to generate compile-time warnings or errors */') | |
| prnt(' (void)p;') | |
| for fname, ftype, fbitsize, fqual in tp.enumfields(): | |
| if (isinstance(ftype, model.PrimitiveType) | |
| and ftype.is_integer_type()) or fbitsize >= 0: | |
| # accept all integers, but complain on float or double | |
| prnt(' (void)((p->%s) << 1);' % fname) | |
| else: | |
| # only accept exactly the type declared. | |
| try: | |
| prnt(' { %s = &p->%s; (void)tmp; }' % ( | |
| ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), | |
| fname)) | |
| except VerificationError as e: | |
| prnt(' /* %s */' % str(e)) # cannot verify it, ignore | |
| prnt('}') | |
| prnt('static PyObject *') | |
| prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) | |
| prnt('{') | |
| prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) | |
| prnt(' static Py_ssize_t nums[] = {') | |
| prnt(' sizeof(%s),' % cname) | |
| prnt(' offsetof(struct _cffi_aligncheck, y),') | |
| for fname, ftype, fbitsize, fqual in tp.enumfields(): | |
| if fbitsize >= 0: | |
| continue # xxx ignore fbitsize for now | |
| prnt(' offsetof(%s, %s),' % (cname, fname)) | |
| if isinstance(ftype, model.ArrayType) and ftype.length is None: | |
| prnt(' 0, /* %s */' % ftype._get_c_name()) | |
| else: | |
| prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) | |
| prnt(' -1') | |
| prnt(' };') | |
| prnt(' (void)self; /* unused */') | |
| prnt(' (void)noarg; /* unused */') | |
| prnt(' return _cffi_get_struct_layout(nums);') | |
| prnt(' /* the next line is not executed, but compiled */') | |
| prnt(' %s(0);' % (checkfuncname,)) | |
| prnt('}') | |
| prnt() | |
| def _generate_struct_or_union_method(self, tp, prefix, name): | |
| if tp.fldnames is None: | |
| return # nothing to do with opaque structs | |
| layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) | |
| self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, | |
| layoutfuncname)) | |
| def _loading_struct_or_union(self, tp, prefix, name, module): | |
| if tp.fldnames is None: | |
| return # nothing to do with opaque structs | |
| layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) | |
| # | |
| function = getattr(module, layoutfuncname) | |
| layout = function() | |
| if isinstance(tp, model.StructOrUnion) and tp.partial: | |
| # use the function()'s sizes and offsets to guide the | |
| # layout of the struct | |
| totalsize = layout[0] | |
| totalalignment = layout[1] | |
| fieldofs = layout[2::2] | |
| fieldsize = layout[3::2] | |
| tp.force_flatten() | |
| assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) | |
| tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment | |
| else: | |
| cname = ('%s %s' % (prefix, name)).strip() | |
| self._struct_pending_verification[tp] = layout, cname | |
| 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 | |
| if tp in self._struct_pending_verification: | |
| # check that the layout sizes and offsets match the real ones | |
| def check(realvalue, expectedvalue, msg): | |
| if realvalue != expectedvalue: | |
| raise VerificationError( | |
| "%s (we have %d, but C compiler says %d)" | |
| % (msg, expectedvalue, realvalue)) | |
| ffi = self.ffi | |
| BStruct = ffi._get_cached_btype(tp) | |
| layout, cname = self._struct_pending_verification.pop(tp) | |
| check(layout[0], ffi.sizeof(BStruct), "wrong total size") | |
| check(layout[1], ffi.alignof(BStruct), "wrong total alignment") | |
| i = 2 | |
| for fname, ftype, fbitsize, fqual in tp.enumfields(): | |
| if fbitsize >= 0: | |
| continue # xxx ignore fbitsize for now | |
| check(layout[i], ffi.offsetof(BStruct, fname), | |
| "wrong offset for field %r" % (fname,)) | |
| if layout[i+1] != 0: | |
| BField = ffi._get_cached_btype(ftype) | |
| check(layout[i+1], ffi.sizeof(BField), | |
| "wrong size for field %r" % (fname,)) | |
| i += 2 | |
| assert i == len(layout) | |
| # ---------- | |
| # 'anonymous' declarations. These are produced for anonymous structs | |
| # or unions; the 'name' is obtained by a typedef. | |
| _generate_cpy_anonymous_collecttype = _generate_nothing | |
| def _generate_cpy_anonymous_decl(self, tp, name): | |
| if isinstance(tp, model.EnumType): | |
| self._generate_cpy_enum_decl(tp, name, '') | |
| else: | |
| self._generate_struct_or_union_decl(tp, '', name) | |
| def _generate_cpy_anonymous_method(self, tp, name): | |
| if not isinstance(tp, model.EnumType): | |
| self._generate_struct_or_union_method(tp, '', name) | |
| def _loading_cpy_anonymous(self, tp, name, module): | |
| if isinstance(tp, model.EnumType): | |
| self._loading_cpy_enum(tp, name, module) | |
| else: | |
| self._loading_struct_or_union(tp, '', name, module) | |
| def _loaded_cpy_anonymous(self, tp, name, module, **kwds): | |
| if isinstance(tp, model.EnumType): | |
| self._loaded_cpy_enum(tp, name, module, **kwds) | |
| else: | |
| self._loaded_struct_or_union(tp) | |
| # ---------- | |
| # constants, likely declared with '#define' | |
| def _generate_cpy_const(self, is_int, name, tp=None, category='const', | |
| vartp=None, delayed=True, size_too=False, | |
| check_value=None): | |
| prnt = self._prnt | |
| funcname = '_cffi_%s_%s' % (category, name) | |
| prnt('static int %s(PyObject *lib)' % funcname) | |
| prnt('{') | |
| prnt(' PyObject *o;') | |
| prnt(' int res;') | |
| if not is_int: | |
| prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) | |
| else: | |
| assert category == 'const' | |
| # | |
| if check_value is not None: | |
| self._check_int_constant_value(name, check_value) | |
| # | |
| if not is_int: | |
| if category == 'var': | |
| realexpr = '&' + name | |
| else: | |
| realexpr = name | |
| prnt(' i = (%s);' % (realexpr,)) | |
| prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', | |
| 'variable type'),)) | |
| assert delayed | |
| else: | |
| prnt(' o = _cffi_from_c_int_const(%s);' % name) | |
| prnt(' if (o == NULL)') | |
| prnt(' return -1;') | |
| if size_too: | |
| prnt(' {') | |
| prnt(' PyObject *o1 = o;') | |
| prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' | |
| % (name,)) | |
| prnt(' Py_DECREF(o1);') | |
| prnt(' if (o == NULL)') | |
| prnt(' return -1;') | |
| prnt(' }') | |
| prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) | |
| prnt(' Py_DECREF(o);') | |
| prnt(' if (res < 0)') | |
| prnt(' return -1;') | |
| prnt(' return %s;' % self._chained_list_constants[delayed]) | |
| self._chained_list_constants[delayed] = funcname + '(lib)' | |
| prnt('}') | |
| prnt() | |
| def _generate_cpy_constant_collecttype(self, tp, name): | |
| is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() | |
| if not is_int: | |
| self._do_collect_type(tp) | |
| def _generate_cpy_constant_decl(self, tp, name): | |
| is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() | |
| self._generate_cpy_const(is_int, name, tp) | |
| _generate_cpy_constant_method = _generate_nothing | |
| _loading_cpy_constant = _loaded_noop | |
| _loaded_cpy_constant = _loaded_noop | |
| # ---------- | |
| # enums | |
| def _check_int_constant_value(self, name, value, err_prefix=''): | |
| prnt = self._prnt | |
| if value <= 0: | |
| prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( | |
| name, name, value)) | |
| else: | |
| prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( | |
| name, name, value)) | |
| prnt(' char buf[64];') | |
| prnt(' if ((%s) <= 0)' % name) | |
| prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) | |
| prnt(' else') | |
| prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % | |
| name) | |
| prnt(' PyErr_Format(_cffi_VerificationError,') | |
| prnt(' "%s%s has the real value %s, not %s",') | |
| prnt(' "%s", "%s", buf, "%d");' % ( | |
| err_prefix, name, value)) | |
| prnt(' return -1;') | |
| prnt(' }') | |
| def _enum_funcname(self, prefix, name): | |
| # "$enum_$1" => "___D_enum____D_1" | |
| name = name.replace('$', '___D_') | |
| return '_cffi_e_%s_%s' % (prefix, name) | |
| def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): | |
| if tp.partial: | |
| for enumerator in tp.enumerators: | |
| self._generate_cpy_const(True, enumerator, delayed=False) | |
| return | |
| # | |
| funcname = self._enum_funcname(prefix, name) | |
| prnt = self._prnt | |
| prnt('static int %s(PyObject *lib)' % funcname) | |
| prnt('{') | |
| for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): | |
| self._check_int_constant_value(enumerator, enumvalue, | |
| "enum %s: " % name) | |
| prnt(' return %s;' % self._chained_list_constants[True]) | |
| self._chained_list_constants[True] = funcname + '(lib)' | |
| prnt('}') | |
| prnt() | |
| _generate_cpy_enum_collecttype = _generate_nothing | |
| _generate_cpy_enum_method = _generate_nothing | |
| def _loading_cpy_enum(self, tp, name, module): | |
| if tp.partial: | |
| enumvalues = [getattr(module, enumerator) | |
| for enumerator in tp.enumerators] | |
| tp.enumvalues = tuple(enumvalues) | |
| tp.partial_resolved = True | |
| def _loaded_cpy_enum(self, tp, name, module, library): | |
| for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): | |
| setattr(library, enumerator, enumvalue) | |
| # ---------- | |
| # macros: for now only for integers | |
| def _generate_cpy_macro_decl(self, tp, name): | |
| if tp == '...': | |
| check_value = None | |
| else: | |
| check_value = tp # an integer | |
| self._generate_cpy_const(True, name, check_value=check_value) | |
| _generate_cpy_macro_collecttype = _generate_nothing | |
| _generate_cpy_macro_method = _generate_nothing | |
| _loading_cpy_macro = _loaded_noop | |
| _loaded_cpy_macro = _loaded_noop | |
| # ---------- | |
| # global variables | |
| def _generate_cpy_variable_collecttype(self, tp, name): | |
| if isinstance(tp, model.ArrayType): | |
| tp_ptr = model.PointerType(tp.item) | |
| else: | |
| tp_ptr = model.PointerType(tp) | |
| self._do_collect_type(tp_ptr) | |
| def _generate_cpy_variable_decl(self, tp, name): | |
| 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_is_unknown()) | |
| else: | |
| tp_ptr = model.PointerType(tp) | |
| self._generate_cpy_const(False, name, tp_ptr, category='var') | |
| _generate_cpy_variable_method = _generate_nothing | |
| _loading_cpy_variable = _loaded_noop | |
| def _loaded_cpy_variable(self, tp, name, module, library): | |
| value = getattr(library, name) | |
| if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the | |
| # sense that "a=..." is forbidden | |
| if tp.length_is_unknown(): | |
| assert isinstance(value, tuple) | |
| (value, size) = value | |
| BItemType = self.ffi._get_cached_btype(tp.item) | |
| length, rest = divmod(size, self.ffi.sizeof(BItemType)) | |
| if rest != 0: | |
| raise VerificationError( | |
| "bad size: %r does not seem to be an array of %s" % | |
| (name, tp.item)) | |
| tp = tp.resolve_length(length) | |
| # 'value' is a <cdata 'type *'> which we have to replace with | |
| # a <cdata 'type[N]'> if the N is actually known | |
| if tp.length is not None: | |
| BArray = self.ffi._get_cached_btype(tp) | |
| value = self.ffi.cast(BArray, value) | |
| setattr(library, name, value) | |
| return | |
| # remove ptr=<cdata 'int *'> from the library instance, and replace | |
| # it by a property on the class, which reads/writes into ptr[0]. | |
| ptr = value | |
| delattr(library, name) | |
| def getter(library): | |
| return ptr[0] | |
| def setter(library, value): | |
| ptr[0] = value | |
| setattr(type(library), name, property(getter, setter)) | |
| type(library)._cffi_dir.append(name) | |
| # ---------- | |
| def _generate_setup_custom(self): | |
| prnt = self._prnt | |
| prnt('static int _cffi_setup_custom(PyObject *lib)') | |
| prnt('{') | |
| prnt(' return %s;' % self._chained_list_constants[True]) | |
| prnt('}') | |
| cffimod_header = r''' | |
| #include <Python.h> | |
| #include <stddef.h> | |
| /* this block of #ifs should be kept exactly identical between | |
| c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py | |
| and cffi/_cffi_include.h */ | |
| #if defined(_MSC_VER) | |
| # include <malloc.h> /* for alloca() */ | |
| # if _MSC_VER < 1600 /* MSVC < 2010 */ | |
| typedef __int8 int8_t; | |
| typedef __int16 int16_t; | |
| typedef __int32 int32_t; | |
| typedef __int64 int64_t; | |
| typedef unsigned __int8 uint8_t; | |
| typedef unsigned __int16 uint16_t; | |
| typedef unsigned __int32 uint32_t; | |
| typedef unsigned __int64 uint64_t; | |
| typedef __int8 int_least8_t; | |
| typedef __int16 int_least16_t; | |
| typedef __int32 int_least32_t; | |
| typedef __int64 int_least64_t; | |
| typedef unsigned __int8 uint_least8_t; | |
| typedef unsigned __int16 uint_least16_t; | |
| typedef unsigned __int32 uint_least32_t; | |
| typedef unsigned __int64 uint_least64_t; | |
| typedef __int8 int_fast8_t; | |
| typedef __int16 int_fast16_t; | |
| typedef __int32 int_fast32_t; | |
| typedef __int64 int_fast64_t; | |
| typedef unsigned __int8 uint_fast8_t; | |
| typedef unsigned __int16 uint_fast16_t; | |
| typedef unsigned __int32 uint_fast32_t; | |
| typedef unsigned __int64 uint_fast64_t; | |
| typedef __int64 intmax_t; | |
| typedef unsigned __int64 uintmax_t; | |
| # else | |
| # include <stdint.h> | |
| # endif | |
| # if _MSC_VER < 1800 /* MSVC < 2013 */ | |
| # ifndef __cplusplus | |
| typedef unsigned char _Bool; | |
| # endif | |
| # endif | |
| # define _cffi_float_complex_t _Fcomplex /* include <complex.h> for it */ | |
| # define _cffi_double_complex_t _Dcomplex /* include <complex.h> for it */ | |
| #else | |
| # include <stdint.h> | |
| # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) | |
| # include <alloca.h> | |
| # endif | |
| # define _cffi_float_complex_t float _Complex | |
| # define _cffi_double_complex_t double _Complex | |
| #endif | |
| #if PY_MAJOR_VERSION < 3 | |
| # undef PyCapsule_CheckExact | |
| # undef PyCapsule_GetPointer | |
| # define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) | |
| # define PyCapsule_GetPointer(capsule, name) \ | |
| (PyCObject_AsVoidPtr(capsule)) | |
| #endif | |
| #if PY_MAJOR_VERSION >= 3 | |
| # define PyInt_FromLong PyLong_FromLong | |
| #endif | |
| #define _cffi_from_c_double PyFloat_FromDouble | |
| #define _cffi_from_c_float PyFloat_FromDouble | |
| #define _cffi_from_c_long PyInt_FromLong | |
| #define _cffi_from_c_ulong PyLong_FromUnsignedLong | |
| #define _cffi_from_c_longlong PyLong_FromLongLong | |
| #define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong | |
| #define _cffi_from_c__Bool PyBool_FromLong | |
| #define _cffi_to_c_double PyFloat_AsDouble | |
| #define _cffi_to_c_float PyFloat_AsDouble | |
| #define _cffi_from_c_int_const(x) \ | |
| (((x) > 0) ? \ | |
| ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ | |
| PyInt_FromLong((long)(x)) : \ | |
| PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ | |
| ((long long)(x) >= (long long)LONG_MIN) ? \ | |
| PyInt_FromLong((long)(x)) : \ | |
| PyLong_FromLongLong((long long)(x))) | |
| #define _cffi_from_c_int(x, type) \ | |
| (((type)-1) > 0 ? /* unsigned */ \ | |
| (sizeof(type) < sizeof(long) ? \ | |
| PyInt_FromLong((long)x) : \ | |
| sizeof(type) == sizeof(long) ? \ | |
| PyLong_FromUnsignedLong((unsigned long)x) : \ | |
| PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ | |
| (sizeof(type) <= sizeof(long) ? \ | |
| PyInt_FromLong((long)x) : \ | |
| PyLong_FromLongLong((long long)x))) | |
| #define _cffi_to_c_int(o, type) \ | |
| ((type)( \ | |
| sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ | |
| : (type)_cffi_to_c_i8(o)) : \ | |
| sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ | |
| : (type)_cffi_to_c_i16(o)) : \ | |
| sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ | |
| : (type)_cffi_to_c_i32(o)) : \ | |
| sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ | |
| : (type)_cffi_to_c_i64(o)) : \ | |
| (Py_FatalError("unsupported size for type " #type), (type)0))) | |
| #define _cffi_to_c_i8 \ | |
| ((int(*)(PyObject *))_cffi_exports[1]) | |
| #define _cffi_to_c_u8 \ | |
| ((int(*)(PyObject *))_cffi_exports[2]) | |
| #define _cffi_to_c_i16 \ | |
| ((int(*)(PyObject *))_cffi_exports[3]) | |
| #define _cffi_to_c_u16 \ | |
| ((int(*)(PyObject *))_cffi_exports[4]) | |
| #define _cffi_to_c_i32 \ | |
| ((int(*)(PyObject *))_cffi_exports[5]) | |
| #define _cffi_to_c_u32 \ | |
| ((unsigned int(*)(PyObject *))_cffi_exports[6]) | |
| #define _cffi_to_c_i64 \ | |
| ((long long(*)(PyObject *))_cffi_exports[7]) | |
| #define _cffi_to_c_u64 \ | |
| ((unsigned long long(*)(PyObject *))_cffi_exports[8]) | |
| #define _cffi_to_c_char \ | |
| ((int(*)(PyObject *))_cffi_exports[9]) | |
| #define _cffi_from_c_pointer \ | |
| ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) | |
| #define _cffi_to_c_pointer \ | |
| ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) | |
| #define _cffi_get_struct_layout \ | |
| ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) | |
| #define _cffi_restore_errno \ | |
| ((void(*)(void))_cffi_exports[13]) | |
| #define _cffi_save_errno \ | |
| ((void(*)(void))_cffi_exports[14]) | |
| #define _cffi_from_c_char \ | |
| ((PyObject *(*)(char))_cffi_exports[15]) | |
| #define _cffi_from_c_deref \ | |
| ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) | |
| #define _cffi_to_c \ | |
| ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) | |
| #define _cffi_from_c_struct \ | |
| ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) | |
| #define _cffi_to_c_wchar_t \ | |
| ((wchar_t(*)(PyObject *))_cffi_exports[19]) | |
| #define _cffi_from_c_wchar_t \ | |
| ((PyObject *(*)(wchar_t))_cffi_exports[20]) | |
| #define _cffi_to_c_long_double \ | |
| ((long double(*)(PyObject *))_cffi_exports[21]) | |
| #define _cffi_to_c__Bool \ | |
| ((_Bool(*)(PyObject *))_cffi_exports[22]) | |
| #define _cffi_prepare_pointer_call_argument \ | |
| ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) | |
| #define _cffi_convert_array_from_object \ | |
| ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) | |
| #define _CFFI_NUM_EXPORTS 25 | |
| typedef struct _ctypedescr CTypeDescrObject; | |
| static void *_cffi_exports[_CFFI_NUM_EXPORTS]; | |
| static PyObject *_cffi_types, *_cffi_VerificationError; | |
| static int _cffi_setup_custom(PyObject *lib); /* forward */ | |
| static PyObject *_cffi_setup(PyObject *self, PyObject *args) | |
| { | |
| PyObject *library; | |
| int was_alive = (_cffi_types != NULL); | |
| (void)self; /* unused */ | |
| if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, | |
| &library)) | |
| return NULL; | |
| Py_INCREF(_cffi_types); | |
| Py_INCREF(_cffi_VerificationError); | |
| if (_cffi_setup_custom(library) < 0) | |
| return NULL; | |
| return PyBool_FromLong(was_alive); | |
| } | |
| union _cffi_union_alignment_u { | |
| unsigned char m_char; | |
| unsigned short m_short; | |
| unsigned int m_int; | |
| unsigned long m_long; | |
| unsigned long long m_longlong; | |
| float m_float; | |
| double m_double; | |
| long double m_longdouble; | |
| }; | |
| struct _cffi_freeme_s { | |
| struct _cffi_freeme_s *next; | |
| union _cffi_union_alignment_u alignment; | |
| }; | |
| #ifdef __GNUC__ | |
| __attribute__((unused)) | |
| #endif | |
| static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, | |
| char **output_data, Py_ssize_t datasize, | |
| struct _cffi_freeme_s **freeme) | |
| { | |
| char *p; | |
| if (datasize < 0) | |
| return -1; | |
| p = *output_data; | |
| if (p == NULL) { | |
| struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( | |
| offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); | |
| if (fp == NULL) | |
| return -1; | |
| fp->next = *freeme; | |
| *freeme = fp; | |
| p = *output_data = (char *)&fp->alignment; | |
| } | |
| memset((void *)p, 0, (size_t)datasize); | |
| return _cffi_convert_array_from_object(p, ctptr, arg); | |
| } | |
| #ifdef __GNUC__ | |
| __attribute__((unused)) | |
| #endif | |
| static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) | |
| { | |
| do { | |
| void *p = (void *)freeme; | |
| freeme = freeme->next; | |
| PyObject_Free(p); | |
| } while (freeme != NULL); | |
| } | |
| static int _cffi_init(void) | |
| { | |
| PyObject *module, *c_api_object = NULL; | |
| module = PyImport_ImportModule("_cffi_backend"); | |
| if (module == NULL) | |
| goto failure; | |
| c_api_object = PyObject_GetAttrString(module, "_C_API"); | |
| if (c_api_object == NULL) | |
| goto failure; | |
| if (!PyCapsule_CheckExact(c_api_object)) { | |
| PyErr_SetNone(PyExc_ImportError); | |
| goto failure; | |
| } | |
| memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), | |
| _CFFI_NUM_EXPORTS * sizeof(void *)); | |
| Py_DECREF(module); | |
| Py_DECREF(c_api_object); | |
| return 0; | |
| failure: | |
| Py_XDECREF(module); | |
| Py_XDECREF(c_api_object); | |
| return -1; | |
| } | |
| #define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) | |
| /**********/ | |
| ''' | |