|
|
|
|
|
|
|
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() |
|
|
|
|
|
|
|
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): |
|
|
|
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() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] |
|
|
|
prnt = self._prnt |
|
|
|
prnt(cffimod_header) |
|
prnt() |
|
|
|
prnt(self.verifier.preamble) |
|
prnt() |
|
|
|
|
|
|
|
self._generate("decl") |
|
|
|
|
|
|
|
self._generate_setup_custom() |
|
prnt() |
|
|
|
|
|
|
|
|
|
prnt('static PyMethodDef _cffi_methods[] = {') |
|
self._generate("method") |
|
prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') |
|
prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') |
|
prnt('};') |
|
prnt() |
|
|
|
|
|
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(' 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): |
|
|
|
|
|
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() |
|
|
|
|
|
|
|
self._load(module, 'loading') |
|
|
|
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
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())) |
|
|
|
|
|
|
|
|
|
|
|
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)): |
|
|
|
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) |
|
|
|
|
|
|
|
|
|
_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 |
|
|
|
|
|
|
|
|
|
def _generate_cpy_function_collecttype(self, tp, name): |
|
assert isinstance(tp, model.FunctionPtrType) |
|
if tp.ellipsis: |
|
self._do_collect_type(tp) |
|
else: |
|
|
|
|
|
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: |
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
_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 |
|
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: |
|
|
|
prnt(' (void)((p->%s) << 1);' % fname) |
|
else: |
|
|
|
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)) |
|
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 |
|
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 |
|
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 |
|
layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) |
|
|
|
function = getattr(module, layoutfuncname) |
|
layout = function() |
|
if isinstance(tp, model.StructOrUnion) and tp.partial: |
|
|
|
|
|
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 |
|
self.ffi._get_cached_btype(tp) |
|
|
|
if tp in self._struct_pending_verification: |
|
|
|
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 |
|
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) |
|
|
|
|
|
|
|
|
|
|
|
_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) |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
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): |
|
|
|
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) |
|
|
|
|
|
|
|
|
|
def _generate_cpy_macro_decl(self, tp, name): |
|
if tp == '...': |
|
check_value = None |
|
else: |
|
check_value = tp |
|
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 |
|
|
|
|
|
|
|
|
|
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): |
|
|
|
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) |
|
|
|
|
|
if tp.length is not None: |
|
BArray = self.ffi._get_cached_btype(tp) |
|
value = self.ffi.cast(BArray, value) |
|
setattr(library, name, value) |
|
return |
|
|
|
|
|
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)) |
|
|
|
/**********/ |
|
''' |
|
|