���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home/ukubnwwtacc0unt/chapelbellstudios.com/uploads/cover/cffi.zip
���ѧ٧ѧ�
PK %�\2��t� � ffiplatform.pynu �[��� import sys, os from .error import VerificationError LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', 'extra_objects', 'depends'] def get_extension(srcfilename, modname, sources=(), **kwds): _hack_at_distutils() from distutils.core import Extension allsources = [srcfilename] for src in sources: allsources.append(os.path.normpath(src)) return Extension(name=modname, sources=allsources, **kwds) def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" _hack_at_distutils() saved_environ = os.environ.copy() try: outputfilename = _build(tmpdir, ext, compiler_verbose, debug) outputfilename = os.path.abspath(outputfilename) finally: # workaround for a distutils bugs where some env vars can # become longer and longer every time it is used for key, value in saved_environ.items(): if os.environ.get(key) != value: os.environ[key] = value return outputfilename def _build(tmpdir, ext, compiler_verbose=0, debug=None): # XXX compact but horrible :-( from distutils.core import Distribution import distutils.errors, distutils.log # dist = Distribution({'ext_modules': [ext]}) dist.parse_config_files() options = dist.get_option_dict('build_ext') if debug is None: debug = sys.flags.debug options['debug'] = ('ffiplatform', debug) options['force'] = ('ffiplatform', True) options['build_lib'] = ('ffiplatform', tmpdir) options['build_temp'] = ('ffiplatform', tmpdir) # try: old_level = distutils.log.set_threshold(0) or 0 try: distutils.log.set_verbosity(compiler_verbose) dist.run_command('build_ext') cmd_obj = dist.get_command_obj('build_ext') [soname] = cmd_obj.get_outputs() finally: distutils.log.set_threshold(old_level) except (distutils.errors.CompileError, distutils.errors.LinkError) as e: raise VerificationError('%s: %s' % (e.__class__.__name__, e)) # return soname try: from os.path import samefile except ImportError: def samefile(f1, f2): return os.path.abspath(f1) == os.path.abspath(f2) def maybe_relative_path(path): if not os.path.isabs(path): return path # already relative dir = path names = [] while True: prevdir = dir dir, name = os.path.split(prevdir) if dir == prevdir or not dir: return path # failed to make it relative names.append(name) try: if samefile(dir, os.curdir): names.reverse() return os.path.join(*names) except OSError: pass # ____________________________________________________________ try: int_or_long = (int, long) import cStringIO except NameError: int_or_long = int # Python 3 import io as cStringIO def _flatten(x, f): if isinstance(x, str): f.write('%ds%s' % (len(x), x)) elif isinstance(x, dict): keys = sorted(x.keys()) f.write('%dd' % len(keys)) for key in keys: _flatten(key, f) _flatten(x[key], f) elif isinstance(x, (list, tuple)): f.write('%dl' % len(x)) for value in x: _flatten(value, f) elif isinstance(x, int_or_long): f.write('%di' % (x,)) else: raise TypeError( "the keywords to verify() contains unsupported object %r" % (x,)) def flatten(x): f = cStringIO.StringIO() _flatten(x, f) return f.getvalue() def _hack_at_distutils(): # Windows-only workaround for some configurations: see # https://bugs.python.org/issue23246 (Python 2.7 with # a specific MS compiler suite download) if sys.platform == "win32": try: import setuptools # for side-effects, patches distutils except ImportError: pass PK %�\�`C�4h 4h vengine_gen.pynu �[��� # # DEPRECATED: implementation for ffi.verify() # import sys, os import types from . import model from .error import VerificationError class VGenericEngine(object): _class_key = 'g' _gen_python_module = False def __init__(self, verifier): self.verifier = verifier self.ffi = verifier.ffi self.export_symbols = [] self._struct_pending_verification = {} def patch_extension_kwds(self, kwds): # add 'export_symbols' to the dictionary. Note that we add the # list before filling it. When we fill it, it will thus also show # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) def find_module(self, module_name, path, so_suffixes): for so_suffix in so_suffixes: basename = module_name + so_suffix if path is None: path = sys.path for dirname in path: filename = os.path.join(dirname, basename) if os.path.isfile(filename): return filename def collect_types(self): pass # not needed in the generic engine def _prnt(self, what=''): self._f.write(what + '\n') def write_source_to_f(self): prnt = self._prnt # first paste some standard set of lines that are mostly '#include' prnt(cffimod_header) # then paste the C source given by the user, verbatim. prnt(self.verifier.preamble) # # call generate_gen_xxx_decl(), for every xxx found from # ffi._parser._declarations. This generates all the functions. self._generate('decl') # # on Windows, distutils insists on putting init_cffi_xyz in # 'export_symbols', so instead of fighting it, just give up and # give it one if sys.platform == 'win32': if sys.version_info >= (3,): prefix = 'PyInit_' else: prefix = 'init' modname = self.verifier.get_module_name() prnt("void %s%s(void) { }\n" % (prefix, modname)) def load_library(self, flags=0): # import it with the CFFI backend backend = self.ffi._backend # needs to make a path that contains '/', on Posix filename = os.path.join(os.curdir, self.verifier.modulefilename) module = backend.load_library(filename, flags) # # call loading_gen_struct() to get the struct layout inferred by # the C compiler self._load(module, 'loading') # build the FFILibrary class and instance, this is a module subclass # because modules are expected to have usually-constant-attributes and # in PyPy this means the JIT is able to treat attributes as constant, # which we want. class FFILibrary(types.ModuleType): _cffi_generic_module = module _cffi_ffi = self.ffi _cffi_dir = [] def __dir__(self): return FFILibrary._cffi_dir library = FFILibrary("") # # finally, call the loaded_gen_xxx() functions. This will set # up the 'library' object. self._load(module, 'loaded', library=library) 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_gen_%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_gen_%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 # ---------- # typedefs: generates no code so far _generate_gen_typedef_decl = _generate_nothing _loading_gen_typedef = _loaded_noop _loaded_gen_typedef = _loaded_noop # ---------- # function declarations def _generate_gen_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 _cffi_f_%s wrapper) self._generate_gen_const(False, name, tp) return prnt = self._prnt numargs = len(tp.args) argnames = [] for i, type in enumerate(tp.args): indirection = '' if isinstance(type, model.StructOrUnion): indirection = '*' argnames.append('%sx%d' % (indirection, i)) context = 'argument of %s' % name arglist = [type.get_c_name(' %s' % arg, context) for type, arg in zip(tp.args, argnames)] tpresult = tp.result if isinstance(tpresult, model.StructOrUnion): arglist.insert(0, tpresult.get_c_name(' *r', context)) tpresult = model.void_type arglist = ', '.join(arglist) or 'void' wrappername = '_cffi_f_%s' % name self.export_symbols.append(wrappername) if tp.abi: abi = tp.abi + ' ' else: abi = '' funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) context = 'result of %s' % name prnt(tpresult.get_c_name(funcdecl, context)) prnt('{') # if isinstance(tp.result, model.StructOrUnion): result_code = '*r = ' elif not isinstance(tp.result, model.VoidType): result_code = 'return ' else: result_code = '' prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) prnt('}') prnt() _loading_gen_function = _loaded_noop def _loaded_gen_function(self, tp, name, module, library): assert isinstance(tp, model.FunctionPtrType) if tp.ellipsis: newfunction = self._load_constant(False, tp, name, module) else: indirections = [] base_tp = tp if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) or isinstance(tp.result, model.StructOrUnion)): indirect_args = [] for i, typ in enumerate(tp.args): if isinstance(typ, model.StructOrUnion): typ = model.PointerType(typ) indirections.append((i, typ)) indirect_args.append(typ) indirect_result = tp.result if isinstance(indirect_result, model.StructOrUnion): if indirect_result.fldtypes is None: raise TypeError("'%s' is used as result type, " "but is opaque" % ( indirect_result._get_c_name(),)) indirect_result = model.PointerType(indirect_result) indirect_args.insert(0, indirect_result) indirections.insert(0, ("result", indirect_result)) indirect_result = model.void_type tp = model.FunctionPtrType(tuple(indirect_args), indirect_result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) for i, typ in indirections: newfunction = self._make_struct_wrapper(newfunction, i, typ, base_tp) setattr(library, name, newfunction) type(library)._cffi_dir.append(name) def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): backend = self.ffi._backend BType = self.ffi._get_cached_btype(tp) if i == "result": ffi = self.ffi def newfunc(*args): res = ffi.new(BType) oldfunc(res, *args) return res[0] else: def newfunc(*args): args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] return oldfunc(*args) newfunc._cffi_base_type = base_tp return newfunc # ---------- # named structs def _generate_gen_struct_decl(self, tp, name): assert name == tp.name self._generate_struct_or_union_decl(tp, 'struct', name) def _loading_gen_struct(self, tp, name, module): self._loading_struct_or_union(tp, 'struct', name, module) def _loaded_gen_struct(self, tp, name, module, **kwds): self._loaded_struct_or_union(tp) def _generate_gen_union_decl(self, tp, name): assert name == tp.name self._generate_struct_or_union_decl(tp, 'union', name) def _loading_gen_union(self, tp, name, module): self._loading_struct_or_union(tp, 'union', name, module) def _loaded_gen_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('}') self.export_symbols.append(layoutfuncname) prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) prnt('{') prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) prnt(' static intptr_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(' return nums[i];') prnt(' /* the next line is not executed, but compiled */') prnt(' %s(0);' % (checkfuncname,)) prnt('}') prnt() 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) # BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] function = module.load_function(BFunc, layoutfuncname) layout = [] num = 0 while True: x = function(num) if x < 0: break layout.append(x) num += 1 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. def _generate_gen_anonymous_decl(self, tp, name): if isinstance(tp, model.EnumType): self._generate_gen_enum_decl(tp, name, '') else: self._generate_struct_or_union_decl(tp, '', name) def _loading_gen_anonymous(self, tp, name, module): if isinstance(tp, model.EnumType): self._loading_gen_enum(tp, name, module, '') else: self._loading_struct_or_union(tp, '', name, module) def _loaded_gen_anonymous(self, tp, name, module, **kwds): if isinstance(tp, model.EnumType): self._loaded_gen_enum(tp, name, module, **kwds) else: self._loaded_struct_or_union(tp) # ---------- # constants, likely declared with '#define' def _generate_gen_const(self, is_int, name, tp=None, category='const', check_value=None): prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) self.export_symbols.append(funcname) if check_value is not None: assert is_int assert category == 'const' prnt('int %s(char *out_error)' % funcname) prnt('{') self._check_int_constant_value(name, check_value) prnt(' return 0;') prnt('}') elif is_int: assert category == 'const' prnt('int %s(long long *out_value)' % funcname) prnt('{') prnt(' *out_value = (long long)(%s);' % (name,)) prnt(' return (%s) <= 0;' % (name,)) prnt('}') else: assert tp is not None assert check_value is None if category == 'var': ampersand = '&' else: ampersand = '' extra = '' if category == 'const' and isinstance(tp, model.StructOrUnion): extra = 'const *' ampersand = '&' prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) prnt('{') prnt(' return (%s%s);' % (ampersand, name)) prnt('}') prnt() def _generate_gen_constant_decl(self, tp, name): is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() self._generate_gen_const(is_int, name, tp) _loading_gen_constant = _loaded_noop def _load_constant(self, is_int, tp, name, module, check_value=None): funcname = '_cffi_const_%s' % name if check_value is not None: assert is_int self._load_known_int_constant(module, funcname) value = check_value elif is_int: BType = self.ffi._typeof_locked("long long*")[0] BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] function = module.load_function(BFunc, funcname) p = self.ffi.new(BType) negative = function(p) value = int(p[0]) if value < 0 and not negative: BLongLong = self.ffi._typeof_locked("long long")[0] value += (1 << (8*self.ffi.sizeof(BLongLong))) else: assert check_value is None fntypeextra = '(*)(void)' if isinstance(tp, model.StructOrUnion): fntypeextra = '*' + fntypeextra BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] function = module.load_function(BFunc, funcname) value = function() if isinstance(tp, model.StructOrUnion): value = value[0] return value def _loaded_gen_constant(self, tp, name, module, library): is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() value = self._load_constant(is_int, tp, name, module) setattr(library, name, value) type(library)._cffi_dir.append(name) # ---------- # enums def _check_int_constant_value(self, name, value): 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(' sprintf(buf, "%%ld", (long)(%s));' % name) prnt(' else') prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % name) prnt(' sprintf(out_error, "%s has the real value %s, not %s",') prnt(' "%s", buf, "%d");' % (name[:100], value)) prnt(' return -1;') prnt(' }') def _load_known_int_constant(self, module, funcname): BType = self.ffi._typeof_locked("char[]")[0] BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] function = module.load_function(BFunc, funcname) p = self.ffi.new(BType, 256) if function(p) < 0: error = self.ffi.string(p) if sys.version_info >= (3,): error = str(error, 'utf-8') raise VerificationError(error) 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_gen_enum_decl(self, tp, name, prefix='enum'): if tp.partial: for enumerator in tp.enumerators: self._generate_gen_const(True, enumerator) return # funcname = self._enum_funcname(prefix, name) self.export_symbols.append(funcname) prnt = self._prnt prnt('int %s(char *out_error)' % funcname) prnt('{') for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): self._check_int_constant_value(enumerator, enumvalue) prnt(' return 0;') prnt('}') prnt() def _loading_gen_enum(self, tp, name, module, prefix='enum'): if tp.partial: enumvalues = [self._load_constant(True, tp, enumerator, module) for enumerator in tp.enumerators] tp.enumvalues = tuple(enumvalues) tp.partial_resolved = True else: funcname = self._enum_funcname(prefix, name) self._load_known_int_constant(module, funcname) def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): setattr(library, enumerator, enumvalue) type(library)._cffi_dir.append(enumerator) # ---------- # macros: for now only for integers def _generate_gen_macro_decl(self, tp, name): if tp == '...': check_value = None else: check_value = tp # an integer self._generate_gen_const(True, name, check_value=check_value) _loading_gen_macro = _loaded_noop def _loaded_gen_macro(self, tp, name, module, library): if tp == '...': check_value = None else: check_value = tp # an integer value = self._load_constant(True, tp, name, module, check_value=check_value) setattr(library, name, value) type(library)._cffi_dir.append(name) # ---------- # global variables def _generate_gen_variable_decl(self, tp, name): if isinstance(tp, model.ArrayType): if tp.length == '...': prnt = self._prnt funcname = '_cffi_sizeof_%s' % (name,) self.export_symbols.append(funcname) prnt("size_t %s(void)" % funcname) prnt("{") prnt(" return sizeof(%s);" % (name,)) prnt("}") tp_ptr = model.PointerType(tp.item) self._generate_gen_const(False, name, tp_ptr) else: tp_ptr = model.PointerType(tp) self._generate_gen_const(False, name, tp_ptr, category='var') _loading_gen_variable = _loaded_noop 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 == '...': funcname = '_cffi_sizeof_%s' % (name,) BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] function = module.load_function(BFunc, funcname) size = function() 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) tp_ptr = model.PointerType(tp.item) value = self._load_constant(False, tp_ptr, name, module) # '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) type(library)._cffi_dir.append(name) return # remove ptr=<cdata 'int *'> from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. funcname = '_cffi_var_%s' % name BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] function = module.load_function(BFunc, funcname) ptr = function() 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) cffimod_header = r''' #include <stdio.h> #include <stddef.h> #include <stdarg.h> #include <errno.h> #include <sys/types.h> /* XXX for ssize_t on some platforms */ /* 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 #else # include <stdint.h> # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include <alloca.h> # endif #endif ''' PK %�\�� � __init__.pynu �[��� __all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', 'FFIError'] from .api import FFI from .error import CDefError, FFIError, VerificationError, VerificationMissing __version__ = "1.11.5" __version_info__ = (1, 11, 5) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ # if nothing is clearly incompatible. __version_verifier_modules__ = "0.8.6" PK %�\��kX X parse_c_type.hnu �[��� /* This part is from file 'cffi/parse_c_type.h'. It is copied at the beginning of C sources generated by CFFI's ffi.set_source(). */ typedef void *_cffi_opcode_t; #define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) #define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) #define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) #define _CFFI_OP_PRIMITIVE 1 #define _CFFI_OP_POINTER 3 #define _CFFI_OP_ARRAY 5 #define _CFFI_OP_OPEN_ARRAY 7 #define _CFFI_OP_STRUCT_UNION 9 #define _CFFI_OP_ENUM 11 #define _CFFI_OP_FUNCTION 13 #define _CFFI_OP_FUNCTION_END 15 #define _CFFI_OP_NOOP 17 #define _CFFI_OP_BITFIELD 19 #define _CFFI_OP_TYPENAME 21 #define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs #define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs #define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) #define _CFFI_OP_CONSTANT 29 #define _CFFI_OP_CONSTANT_INT 31 #define _CFFI_OP_GLOBAL_VAR 33 #define _CFFI_OP_DLOPEN_FUNC 35 #define _CFFI_OP_DLOPEN_CONST 37 #define _CFFI_OP_GLOBAL_VAR_F 39 #define _CFFI_OP_EXTERN_PYTHON 41 #define _CFFI_PRIM_VOID 0 #define _CFFI_PRIM_BOOL 1 #define _CFFI_PRIM_CHAR 2 #define _CFFI_PRIM_SCHAR 3 #define _CFFI_PRIM_UCHAR 4 #define _CFFI_PRIM_SHORT 5 #define _CFFI_PRIM_USHORT 6 #define _CFFI_PRIM_INT 7 #define _CFFI_PRIM_UINT 8 #define _CFFI_PRIM_LONG 9 #define _CFFI_PRIM_ULONG 10 #define _CFFI_PRIM_LONGLONG 11 #define _CFFI_PRIM_ULONGLONG 12 #define _CFFI_PRIM_FLOAT 13 #define _CFFI_PRIM_DOUBLE 14 #define _CFFI_PRIM_LONGDOUBLE 15 #define _CFFI_PRIM_WCHAR 16 #define _CFFI_PRIM_INT8 17 #define _CFFI_PRIM_UINT8 18 #define _CFFI_PRIM_INT16 19 #define _CFFI_PRIM_UINT16 20 #define _CFFI_PRIM_INT32 21 #define _CFFI_PRIM_UINT32 22 #define _CFFI_PRIM_INT64 23 #define _CFFI_PRIM_UINT64 24 #define _CFFI_PRIM_INTPTR 25 #define _CFFI_PRIM_UINTPTR 26 #define _CFFI_PRIM_PTRDIFF 27 #define _CFFI_PRIM_SIZE 28 #define _CFFI_PRIM_SSIZE 29 #define _CFFI_PRIM_INT_LEAST8 30 #define _CFFI_PRIM_UINT_LEAST8 31 #define _CFFI_PRIM_INT_LEAST16 32 #define _CFFI_PRIM_UINT_LEAST16 33 #define _CFFI_PRIM_INT_LEAST32 34 #define _CFFI_PRIM_UINT_LEAST32 35 #define _CFFI_PRIM_INT_LEAST64 36 #define _CFFI_PRIM_UINT_LEAST64 37 #define _CFFI_PRIM_INT_FAST8 38 #define _CFFI_PRIM_UINT_FAST8 39 #define _CFFI_PRIM_INT_FAST16 40 #define _CFFI_PRIM_UINT_FAST16 41 #define _CFFI_PRIM_INT_FAST32 42 #define _CFFI_PRIM_UINT_FAST32 43 #define _CFFI_PRIM_INT_FAST64 44 #define _CFFI_PRIM_UINT_FAST64 45 #define _CFFI_PRIM_INTMAX 46 #define _CFFI_PRIM_UINTMAX 47 #define _CFFI_PRIM_FLOATCOMPLEX 48 #define _CFFI_PRIM_DOUBLECOMPLEX 49 #define _CFFI_PRIM_CHAR16 50 #define _CFFI_PRIM_CHAR32 51 #define _CFFI__NUM_PRIM 52 #define _CFFI__UNKNOWN_PRIM (-1) #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) #define _CFFI__IO_FILE_STRUCT (-1) struct _cffi_global_s { const char *name; void *address; _cffi_opcode_t type_op; void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown // OP_CPYTHON_BLTN_*: addr of direct function }; struct _cffi_getconst_s { unsigned long long value; const struct _cffi_type_context_s *ctx; int gindex; }; struct _cffi_struct_union_s { const char *name; int type_index; // -> _cffi_types, on a OP_STRUCT_UNION int flags; // _CFFI_F_* flags below size_t size; int alignment; int first_field_index; // -> _cffi_fields array int num_fields; }; #define _CFFI_F_UNION 0x01 // is a union, not a struct #define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the // "standard layout" or if some are missing #define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct #define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() #define _CFFI_F_OPAQUE 0x10 // opaque struct _cffi_field_s { const char *name; size_t field_offset; size_t field_size; _cffi_opcode_t field_type_op; }; struct _cffi_enum_s { const char *name; int type_index; // -> _cffi_types, on a OP_ENUM int type_prim; // _CFFI_PRIM_xxx const char *enumerators; // comma-delimited string }; struct _cffi_typename_s { const char *name; int type_index; /* if opaque, points to a possibly artificial OP_STRUCT which is itself opaque */ }; struct _cffi_type_context_s { _cffi_opcode_t *types; const struct _cffi_global_s *globals; const struct _cffi_field_s *fields; const struct _cffi_struct_union_s *struct_unions; const struct _cffi_enum_s *enums; const struct _cffi_typename_s *typenames; int num_globals; int num_struct_unions; int num_enums; int num_typenames; const char *const *includes; int num_types; int flags; /* future extension */ }; struct _cffi_parse_info_s { const struct _cffi_type_context_s *ctx; _cffi_opcode_t *output; unsigned int output_size; size_t error_location; const char *error_message; }; struct _cffi_externpy_s { const char *name; size_t size_of_result; void *reserved1, *reserved2; }; #ifdef _CFFI_INTERNAL static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); static int search_in_globals(const struct _cffi_type_context_s *ctx, const char *search, size_t search_len); static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, const char *search, size_t search_len); #endif PK %�\��;�f� f� backend_ctypes.pynu �[��� import ctypes, ctypes.util, operator, sys from . import model if sys.version_info < (3,): bytechr = chr else: unicode = str long = int xrange = range bytechr = lambda num: bytes([num]) class CTypesType(type): pass class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] __name__ = '<cdata>' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @classmethod def _newp(cls, init): raise TypeError("expected a pointer or array ctype, got '%s'" % (cls._get_c_name(),)) @staticmethod def _to_ctypes(value): raise TypeError @classmethod def _arg_to_ctypes(cls, *value): try: ctype = cls._ctype except AttributeError: raise TypeError("cannot create an instance of %r" % (cls,)) if value: res = cls._to_ctypes(*value) if not isinstance(res, ctype): res = cls._ctype(res) else: res = cls._ctype() return res @classmethod def _create_ctype_obj(cls, init): if init is None: return cls._arg_to_ctypes() else: return cls._arg_to_ctypes(init) @staticmethod def _from_ctypes(ctypes_value): raise TypeError @classmethod def _get_c_name(cls, replace_with=''): return cls._reftypename.replace(' &', replace_with) @classmethod def _fix_class(cls): cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) cls.__module__ = 'ffi' def _get_own_repr(self): raise NotImplementedError def _addr_repr(self, address): if address == 0: return 'NULL' else: if address < 0: address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) return '0x%x' % address def __repr__(self, c_name=None): own = self._get_own_repr() return '<cdata %r %s>' % (c_name or self._get_c_name(), own) def _convert_to_address(self, BClass): if BClass is None: raise TypeError("cannot convert %r to an address" % ( self._get_c_name(),)) else: raise TypeError("cannot convert %r to %r" % ( self._get_c_name(), BClass._get_c_name())) @classmethod def _get_size(cls): return ctypes.sizeof(cls._ctype) def _get_size_of_instance(self): return ctypes.sizeof(self._ctype) @classmethod def _cast_from(cls, source): raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) def _cast_to_integer(self): return self._convert_to_address(None) @classmethod def _alignment(cls): return ctypes.alignment(cls._ctype) def __iter__(self): raise TypeError("cdata %r does not support iteration" % ( self._get_c_name()),) def _make_cmp(name): cmpfunc = getattr(operator, name) def cmp(self, other): v_is_ptr = not isinstance(self, CTypesGenericPrimitive) w_is_ptr = (isinstance(other, CTypesData) and not isinstance(other, CTypesGenericPrimitive)) if v_is_ptr and w_is_ptr: return cmpfunc(self._convert_to_address(None), other._convert_to_address(None)) elif v_is_ptr or w_is_ptr: return NotImplemented else: if isinstance(self, CTypesGenericPrimitive): self = self._value if isinstance(other, CTypesGenericPrimitive): other = other._value return cmpfunc(self, other) cmp.func_name = name return cmp __eq__ = _make_cmp('__eq__') __ne__ = _make_cmp('__ne__') __lt__ = _make_cmp('__lt__') __le__ = _make_cmp('__le__') __gt__ = _make_cmp('__gt__') __ge__ = _make_cmp('__ge__') def __hash__(self): return hash(self._convert_to_address(None)) def _to_string(self, maxlen): raise TypeError("string(): %r" % (self,)) class CTypesGenericPrimitive(CTypesData): __slots__ = [] def __hash__(self): return hash(self._value) def _get_own_repr(self): return repr(self._from_ctypes(self._value)) class CTypesGenericArray(CTypesData): __slots__ = [] @classmethod def _newp(cls, init): return cls(init) def __iter__(self): for i in xrange(len(self)): yield self[i] def _get_own_repr(self): return self._addr_repr(ctypes.addressof(self._blob)) class CTypesGenericPtr(CTypesData): __slots__ = ['_address', '_as_ctype_ptr'] _automatic_casts = False kind = "pointer" @classmethod def _newp(cls, init): return cls(init) @classmethod def _cast_from(cls, source): if source is None: address = 0 elif isinstance(source, CTypesData): address = source._cast_to_integer() elif isinstance(source, (int, long)): address = source else: raise TypeError("bad type for cast to %r: %r" % (cls, type(source).__name__)) return cls._new_pointer_at(address) @classmethod def _new_pointer_at(cls, address): self = cls.__new__(cls) self._address = address self._as_ctype_ptr = ctypes.cast(address, cls._ctype) return self def _get_own_repr(self): try: return self._addr_repr(self._address) except AttributeError: return '???' def _cast_to_integer(self): return self._address def __nonzero__(self): return bool(self._address) __bool__ = __nonzero__ @classmethod def _to_ctypes(cls, value): if not isinstance(value, CTypesData): raise TypeError("unexpected %s object" % type(value).__name__) address = value._convert_to_address(cls) return ctypes.cast(address, cls._ctype) @classmethod def _from_ctypes(cls, ctypes_ptr): address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 return cls._new_pointer_at(address) @classmethod def _initialize(cls, ctypes_ptr, value): if value: ctypes_ptr.contents = cls._to_ctypes(value).contents def _convert_to_address(self, BClass): if (BClass in (self.__class__, None) or BClass._automatic_casts or self._automatic_casts): return self._address else: return CTypesData._convert_to_address(self, BClass) class CTypesBaseStructOrUnion(CTypesData): __slots__ = ['_blob'] @classmethod def _create_ctype_obj(cls, init): # may be overridden raise TypeError("cannot instantiate opaque type %s" % (cls,)) def _get_own_repr(self): return self._addr_repr(ctypes.addressof(self._blob)) @classmethod def _offsetof(cls, fieldname): return getattr(cls._ctype, fieldname).offset def _convert_to_address(self, BClass): if getattr(BClass, '_BItem', None) is self.__class__: return ctypes.addressof(self._blob) else: return CTypesData._convert_to_address(self, BClass) @classmethod def _from_ctypes(cls, ctypes_struct_or_union): self = cls.__new__(cls) self._blob = ctypes_struct_or_union return self @classmethod def _to_ctypes(cls, value): return value._blob def __repr__(self, c_name=None): return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) class CTypesBackend(object): PRIMITIVE_TYPES = { 'char': ctypes.c_char, 'short': ctypes.c_short, 'int': ctypes.c_int, 'long': ctypes.c_long, 'long long': ctypes.c_longlong, 'signed char': ctypes.c_byte, 'unsigned char': ctypes.c_ubyte, 'unsigned short': ctypes.c_ushort, 'unsigned int': ctypes.c_uint, 'unsigned long': ctypes.c_ulong, 'unsigned long long': ctypes.c_ulonglong, 'float': ctypes.c_float, 'double': ctypes.c_double, '_Bool': ctypes.c_bool, } for _name in ['unsigned long long', 'unsigned long', 'unsigned int', 'unsigned short', 'unsigned char']: _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] if _size == ctypes.sizeof(ctypes.c_void_p): PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] if _size == ctypes.sizeof(ctypes.c_size_t): PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] for _name in ['long long', 'long', 'int', 'short', 'signed char']: _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] if _size == ctypes.sizeof(ctypes.c_void_p): PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] if _size == ctypes.sizeof(ctypes.c_size_t): PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] def __init__(self): self.RTLD_LAZY = 0 # not supported anyway by ctypes self.RTLD_NOW = 0 self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL self.RTLD_LOCAL = ctypes.RTLD_LOCAL def set_ffi(self, ffi): self.ffi = ffi def _get_types(self): return CTypesData, CTypesType def load_library(self, path, flags=0): cdll = ctypes.CDLL(path, flags) return CTypesLibrary(self, cdll) def new_void_type(self): class CTypesVoid(CTypesData): __slots__ = [] _reftypename = 'void &' @staticmethod def _from_ctypes(novalue): return None @staticmethod def _to_ctypes(novalue): if novalue is not None: raise TypeError("None expected, got %s object" % (type(novalue).__name__,)) return None CTypesVoid._fix_class() return CTypesVoid def new_primitive_type(self, name): if name == 'wchar_t': raise NotImplementedError(name) ctype = self.PRIMITIVE_TYPES[name] if name == 'char': kind = 'char' elif name in ('float', 'double'): kind = 'float' else: if name in ('signed char', 'unsigned char'): kind = 'byte' elif name == '_Bool': kind = 'bool' else: kind = 'int' is_signed = (ctype(-1).value == -1) # def _cast_source_to_int(source): if isinstance(source, (int, long, float)): source = int(source) elif isinstance(source, CTypesData): source = source._cast_to_integer() elif isinstance(source, bytes): source = ord(source) elif source is None: source = 0 else: raise TypeError("bad type for cast to %r: %r" % (CTypesPrimitive, type(source).__name__)) return source # kind1 = kind class CTypesPrimitive(CTypesGenericPrimitive): __slots__ = ['_value'] _ctype = ctype _reftypename = '%s &' % name kind = kind1 def __init__(self, value): self._value = value @staticmethod def _create_ctype_obj(init): if init is None: return ctype() return ctype(CTypesPrimitive._to_ctypes(init)) if kind == 'int' or kind == 'byte': @classmethod def _cast_from(cls, source): source = _cast_source_to_int(source) source = ctype(source).value # cast within range return cls(source) def __int__(self): return self._value if kind == 'bool': @classmethod def _cast_from(cls, source): if not isinstance(source, (int, long, float)): source = _cast_source_to_int(source) return cls(bool(source)) def __int__(self): return self._value if kind == 'char': @classmethod def _cast_from(cls, source): source = _cast_source_to_int(source) source = bytechr(source & 0xFF) return cls(source) def __int__(self): return ord(self._value) if kind == 'float': @classmethod def _cast_from(cls, source): if isinstance(source, float): pass elif isinstance(source, CTypesGenericPrimitive): if hasattr(source, '__float__'): source = float(source) else: source = int(source) else: source = _cast_source_to_int(source) source = ctype(source).value # fix precision return cls(source) def __int__(self): return int(self._value) def __float__(self): return self._value _cast_to_integer = __int__ if kind == 'int' or kind == 'byte' or kind == 'bool': @staticmethod def _to_ctypes(x): if not isinstance(x, (int, long)): if isinstance(x, CTypesData): x = int(x) else: raise TypeError("integer expected, got %s" % type(x).__name__) if ctype(x).value != x: if not is_signed and x < 0: raise OverflowError("%s: negative integer" % name) else: raise OverflowError("%s: integer out of bounds" % name) return x if kind == 'char': @staticmethod def _to_ctypes(x): if isinstance(x, bytes) and len(x) == 1: return x if isinstance(x, CTypesPrimitive): # <CData <char>> return x._value raise TypeError("character expected, got %s" % type(x).__name__) def __nonzero__(self): return ord(self._value) != 0 else: def __nonzero__(self): return self._value != 0 __bool__ = __nonzero__ if kind == 'float': @staticmethod def _to_ctypes(x): if not isinstance(x, (int, long, float, CTypesData)): raise TypeError("float expected, got %s" % type(x).__name__) return ctype(x).value @staticmethod def _from_ctypes(value): return getattr(value, 'value', value) @staticmethod def _initialize(blob, init): blob.value = CTypesPrimitive._to_ctypes(init) if kind == 'char': def _to_string(self, maxlen): return self._value if kind == 'byte': def _to_string(self, maxlen): return chr(self._value & 0xff) # CTypesPrimitive._fix_class() return CTypesPrimitive def new_pointer_type(self, BItem): getbtype = self.ffi._get_cached_btype if BItem is getbtype(model.PrimitiveType('char')): kind = 'charp' elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' elif BItem is getbtype(model.void_type): kind = 'voidp' else: kind = 'generic' # class CTypesPtr(CTypesGenericPtr): __slots__ = ['_own'] if kind == 'charp': __slots__ += ['__as_strbuf'] _BItem = BItem if hasattr(BItem, '_ctype'): _ctype = ctypes.POINTER(BItem._ctype) _bitem_size = ctypes.sizeof(BItem._ctype) else: _ctype = ctypes.c_void_p if issubclass(BItem, CTypesGenericArray): _reftypename = BItem._get_c_name('(* &)') else: _reftypename = BItem._get_c_name(' * &') def __init__(self, init): ctypeobj = BItem._create_ctype_obj(init) if kind == 'charp': self.__as_strbuf = ctypes.create_string_buffer( ctypeobj.value + b'\x00') self._as_ctype_ptr = ctypes.cast( self.__as_strbuf, self._ctype) else: self._as_ctype_ptr = ctypes.pointer(ctypeobj) self._address = ctypes.cast(self._as_ctype_ptr, ctypes.c_void_p).value self._own = True def __add__(self, other): if isinstance(other, (int, long)): return self._new_pointer_at(self._address + other * self._bitem_size) else: return NotImplemented def __sub__(self, other): if isinstance(other, (int, long)): return self._new_pointer_at(self._address - other * self._bitem_size) elif type(self) is type(other): return (self._address - other._address) // self._bitem_size else: return NotImplemented def __getitem__(self, index): if getattr(self, '_own', False) and index != 0: raise IndexError return BItem._from_ctypes(self._as_ctype_ptr[index]) def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) if kind == 'charp' or kind == 'voidp': @classmethod def _arg_to_ctypes(cls, *value): if value and isinstance(value[0], bytes): return ctypes.c_char_p(value[0]) else: return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): if maxlen < 0: maxlen = sys.maxsize p = ctypes.cast(self._as_ctype_ptr, ctypes.POINTER(ctypes.c_char)) n = 0 while n < maxlen and p[n] != b'\x00': n += 1 return b''.join([p[i] for i in range(n)]) def _get_own_repr(self): if getattr(self, '_own', False): return 'owning %d bytes' % ( ctypes.sizeof(self._as_ctype_ptr.contents),) return super(CTypesPtr, self)._get_own_repr() # if (BItem is self.ffi._get_cached_btype(model.void_type) or BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): CTypesPtr._automatic_casts = True # CTypesPtr._fix_class() return CTypesPtr def new_array_type(self, CTypesPtr, length): if length is None: brackets = ' &[]' else: brackets = ' &[%d]' % length BItem = CTypesPtr._BItem getbtype = self.ffi._get_cached_btype if BItem is getbtype(model.PrimitiveType('char')): kind = 'char' elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'byte' else: kind = 'generic' # class CTypesArray(CTypesGenericArray): __slots__ = ['_blob', '_own'] if length is not None: _ctype = BItem._ctype * length else: __slots__.append('_ctype') _reftypename = BItem._get_c_name(brackets) _declared_length = length _CTPtr = CTypesPtr def __init__(self, init): if length is None: if isinstance(init, (int, long)): len1 = init init = None elif kind == 'char' and isinstance(init, bytes): len1 = len(init) + 1 # extra null else: init = tuple(init) len1 = len(init) self._ctype = BItem._ctype * len1 self._blob = self._ctype() self._own = True if init is not None: self._initialize(self._blob, init) @staticmethod def _initialize(blob, init): if isinstance(init, bytes): init = [init[i:i+1] for i in range(len(init))] else: init = tuple(init) if len(init) > len(blob): raise IndexError("too many initializers") addr = ctypes.cast(blob, ctypes.c_void_p).value PTR = ctypes.POINTER(BItem._ctype) itemsize = ctypes.sizeof(BItem._ctype) for i, value in enumerate(init): p = ctypes.cast(addr + i * itemsize, PTR) BItem._initialize(p.contents, value) def __len__(self): return len(self._blob) def __getitem__(self, index): if not (0 <= index < len(self._blob)): raise IndexError return BItem._from_ctypes(self._blob[index]) def __setitem__(self, index, value): if not (0 <= index < len(self._blob)): raise IndexError self._blob[index] = BItem._to_ctypes(value) if kind == 'char' or kind == 'byte': def _to_string(self, maxlen): if maxlen < 0: maxlen = len(self._blob) p = ctypes.cast(self._blob, ctypes.POINTER(ctypes.c_char)) n = 0 while n < maxlen and p[n] != b'\x00': n += 1 return b''.join([p[i] for i in range(n)]) def _get_own_repr(self): if getattr(self, '_own', False): return 'owning %d bytes' % (ctypes.sizeof(self._blob),) return super(CTypesArray, self)._get_own_repr() def _convert_to_address(self, BClass): if BClass in (CTypesPtr, None) or BClass._automatic_casts: return ctypes.addressof(self._blob) else: return CTypesData._convert_to_address(self, BClass) @staticmethod def _from_ctypes(ctypes_array): self = CTypesArray.__new__(CTypesArray) self._blob = ctypes_array return self @staticmethod def _arg_to_ctypes(value): return CTypesPtr._arg_to_ctypes(value) def __add__(self, other): if isinstance(other, (int, long)): return CTypesPtr._new_pointer_at( ctypes.addressof(self._blob) + other * ctypes.sizeof(BItem._ctype)) else: return NotImplemented @classmethod def _cast_from(cls, source): raise NotImplementedError("casting to %r" % ( cls._get_c_name(),)) # CTypesArray._fix_class() return CTypesArray def _new_struct_or_union(self, kind, name, base_ctypes_class): # class struct_or_union(base_ctypes_class): pass struct_or_union.__name__ = '%s_%s' % (kind, name) kind1 = kind # class CTypesStructOrUnion(CTypesBaseStructOrUnion): __slots__ = ['_blob'] _ctype = struct_or_union _reftypename = '%s &' % (name,) _kind = kind = kind1 # CTypesStructOrUnion._fix_class() return CTypesStructOrUnion def new_struct_type(self, name): return self._new_struct_or_union('struct', name, ctypes.Structure) def new_union_type(self, name): return self._new_struct_or_union('union', name, ctypes.Union) def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, totalsize=-1, totalalignment=-1, sflags=0): if totalsize >= 0 or totalalignment >= 0: raise NotImplementedError("the ctypes backend of CFFI does not support " "structures completed by verify(); please " "compile and install the _cffi_backend module.") struct_or_union = CTypesStructOrUnion._ctype fnames = [fname for (fname, BField, bitsize) in fields] btypes = [BField for (fname, BField, bitsize) in fields] bitfields = [bitsize for (fname, BField, bitsize) in fields] # bfield_types = {} cfields = [] for (fname, BField, bitsize) in fields: if bitsize < 0: cfields.append((fname, BField._ctype)) bfield_types[fname] = BField else: cfields.append((fname, BField._ctype, bitsize)) bfield_types[fname] = Ellipsis if sflags & 8: struct_or_union._pack_ = 1 struct_or_union._fields_ = cfields CTypesStructOrUnion._bfield_types = bfield_types # @staticmethod def _create_ctype_obj(init): result = struct_or_union() if init is not None: initialize(result, init) return result CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj # def initialize(blob, init): if is_union: if len(init) > 1: raise ValueError("union initializer: %d items given, but " "only one supported (use a dict if needed)" % (len(init),)) if not isinstance(init, dict): if isinstance(init, (bytes, unicode)): raise TypeError("union initializer: got a str") init = tuple(init) if len(init) > len(fnames): raise ValueError("too many values for %s initializer" % CTypesStructOrUnion._get_c_name()) init = dict(zip(fnames, init)) addr = ctypes.addressof(blob) for fname, value in init.items(): BField, bitsize = name2fieldtype[fname] assert bitsize < 0, \ "not implemented: initializer with bit fields" offset = CTypesStructOrUnion._offsetof(fname) PTR = ctypes.POINTER(BField._ctype) p = ctypes.cast(addr + offset, PTR) BField._initialize(p.contents, value) is_union = CTypesStructOrUnion._kind == 'union' name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) # for fname, BField, bitsize in fields: if fname == '': raise NotImplementedError("nested anonymous structs/unions") if hasattr(CTypesStructOrUnion, fname): raise ValueError("the field name %r conflicts in " "the ctypes backend" % fname) if bitsize < 0: def getter(self, fname=fname, BField=BField, offset=CTypesStructOrUnion._offsetof(fname), PTR=ctypes.POINTER(BField._ctype)): addr = ctypes.addressof(self._blob) p = ctypes.cast(addr + offset, PTR) return BField._from_ctypes(p.contents) def setter(self, value, fname=fname, BField=BField): setattr(self._blob, fname, BField._to_ctypes(value)) # if issubclass(BField, CTypesGenericArray): setter = None if BField._declared_length == 0: def getter(self, fname=fname, BFieldPtr=BField._CTPtr, offset=CTypesStructOrUnion._offsetof(fname), PTR=ctypes.POINTER(BField._ctype)): addr = ctypes.addressof(self._blob) p = ctypes.cast(addr + offset, PTR) return BFieldPtr._from_ctypes(p) # else: def getter(self, fname=fname, BField=BField): return BField._from_ctypes(getattr(self._blob, fname)) def setter(self, value, fname=fname, BField=BField): # xxx obscure workaround value = BField._to_ctypes(value) oldvalue = getattr(self._blob, fname) setattr(self._blob, fname, value) if value != getattr(self._blob, fname): setattr(self._blob, fname, oldvalue) raise OverflowError("value too large for bitfield") setattr(CTypesStructOrUnion, fname, property(getter, setter)) # CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) for fname in fnames: if hasattr(CTypesPtr, fname): raise ValueError("the field name %r conflicts in " "the ctypes backend" % fname) def getter(self, fname=fname): return getattr(self[0], fname) def setter(self, value, fname=fname): setattr(self[0], fname, value) setattr(CTypesPtr, fname, property(getter, setter)) def new_function_type(self, BArgs, BResult, has_varargs): nameargs = [BArg._get_c_name() for BArg in BArgs] if has_varargs: nameargs.append('...') nameargs = ', '.join(nameargs) # class CTypesFunctionPtr(CTypesGenericPtr): __slots__ = ['_own_callback', '_name'] _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), *[BArg._ctype for BArg in BArgs], use_errno=True) _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) def __init__(self, init, error=None): # create a callback to the Python callable init() import traceback assert not has_varargs, "varargs not supported for callbacks" if getattr(BResult, '_ctype', None) is not None: error = BResult._from_ctypes( BResult._create_ctype_obj(error)) else: error = None def callback(*args): args2 = [] for arg, BArg in zip(args, BArgs): args2.append(BArg._from_ctypes(arg)) try: res2 = init(*args2) res2 = BResult._to_ctypes(res2) except: traceback.print_exc() res2 = error if issubclass(BResult, CTypesGenericPtr): if res2: res2 = ctypes.cast(res2, ctypes.c_void_p).value # .value: http://bugs.python.org/issue1574593 else: res2 = None #print repr(res2) return res2 if issubclass(BResult, CTypesGenericPtr): # The only pointers callbacks can return are void*s: # http://bugs.python.org/issue5710 callback_ctype = ctypes.CFUNCTYPE( ctypes.c_void_p, *[BArg._ctype for BArg in BArgs], use_errno=True) else: callback_ctype = CTypesFunctionPtr._ctype self._as_ctype_ptr = callback_ctype(callback) self._address = ctypes.cast(self._as_ctype_ptr, ctypes.c_void_p).value self._own_callback = init @staticmethod def _initialize(ctypes_ptr, value): if value: raise NotImplementedError("ctypes backend: not supported: " "initializers for function pointers") def __repr__(self): c_name = getattr(self, '_name', None) if c_name: i = self._reftypename.index('(* &)') if self._reftypename[i-1] not in ' )*': c_name = ' ' + c_name c_name = self._reftypename.replace('(* &)', c_name) return CTypesData.__repr__(self, c_name) def _get_own_repr(self): if getattr(self, '_own_callback', None) is not None: return 'calling %r' % (self._own_callback,) return super(CTypesFunctionPtr, self)._get_own_repr() def __call__(self, *args): if has_varargs: assert len(args) >= len(BArgs) extraargs = args[len(BArgs):] args = args[:len(BArgs)] else: assert len(args) == len(BArgs) ctypes_args = [] for arg, BArg in zip(args, BArgs): ctypes_args.append(BArg._arg_to_ctypes(arg)) if has_varargs: for i, arg in enumerate(extraargs): if arg is None: ctypes_args.append(ctypes.c_void_p(0)) # NULL continue if not isinstance(arg, CTypesData): raise TypeError( "argument %d passed in the variadic part " "needs to be a cdata object (got %s)" % (1 + len(BArgs) + i, type(arg).__name__)) ctypes_args.append(arg._arg_to_ctypes(arg)) result = self._as_ctype_ptr(*ctypes_args) return BResult._from_ctypes(result) # CTypesFunctionPtr._fix_class() return CTypesFunctionPtr def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): assert isinstance(name, str) reverse_mapping = dict(zip(reversed(enumvalues), reversed(enumerators))) # class CTypesEnum(CTypesInt): __slots__ = [] _reftypename = '%s &' % name def _get_own_repr(self): value = self._value try: return '%d: %s' % (value, reverse_mapping[value]) except KeyError: return str(value) def _to_string(self, maxlen): value = self._value try: return reverse_mapping[value] except KeyError: return str(value) # CTypesEnum._fix_class() return CTypesEnum def get_errno(self): return ctypes.get_errno() def set_errno(self, value): ctypes.set_errno(value) def string(self, b, maxlen=-1): return b._to_string(maxlen) def buffer(self, bptr, size=-1): raise NotImplementedError("buffer() with ctypes backend") def sizeof(self, cdata_or_BType): if isinstance(cdata_or_BType, CTypesData): return cdata_or_BType._get_size_of_instance() else: assert issubclass(cdata_or_BType, CTypesData) return cdata_or_BType._get_size() def alignof(self, BType): assert issubclass(BType, CTypesData) return BType._alignment() def newp(self, BType, source): if not issubclass(BType, CTypesData): raise TypeError return BType._newp(source) def cast(self, BType, source): return BType._cast_from(source) def callback(self, BType, source, error, onerror): assert onerror is None # XXX not implemented return BType(source, error) _weakref_cache_ref = None def gcp(self, cdata, destructor, size=0): if self._weakref_cache_ref is None: import weakref class MyRef(weakref.ref): def __eq__(self, other): myref = self() return self is other or ( myref is not None and myref is other()) def __ne__(self, other): return not (self == other) def __hash__(self): try: return self._hash except AttributeError: self._hash = hash(self()) return self._hash self._weakref_cache_ref = {}, MyRef weak_cache, MyRef = self._weakref_cache_ref if destructor is None: try: del weak_cache[MyRef(cdata)] except KeyError: raise TypeError("Can remove destructor only on a object " "previously returned by ffi.gc()") return None def remove(k): cdata, destructor = weak_cache.pop(k, (None, None)) if destructor is not None: destructor(cdata) new_cdata = self.cast(self.typeof(cdata), cdata) assert new_cdata is not cdata weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) return new_cdata typeof = type def getcname(self, BType, replace_with): return BType._get_c_name(replace_with) def typeoffsetof(self, BType, fieldname, num=0): if isinstance(fieldname, str): if num == 0 and issubclass(BType, CTypesGenericPtr): BType = BType._BItem if not issubclass(BType, CTypesBaseStructOrUnion): raise TypeError("expected a struct or union ctype") BField = BType._bfield_types[fieldname] if BField is Ellipsis: raise TypeError("not supported for bitfields") return (BField, BType._offsetof(fieldname)) elif isinstance(fieldname, (int, long)): if issubclass(BType, CTypesGenericArray): BType = BType._CTPtr if not issubclass(BType, CTypesGenericPtr): raise TypeError("expected an array or ptr ctype") BItem = BType._BItem offset = BItem._get_size() * fieldname if offset > sys.maxsize: raise OverflowError return (BItem, offset) else: raise TypeError(type(fieldname)) def rawaddressof(self, BTypePtr, cdata, offset=None): if isinstance(cdata, CTypesBaseStructOrUnion): ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) elif isinstance(cdata, CTypesGenericPtr): if offset is None or not issubclass(type(cdata)._BItem, CTypesBaseStructOrUnion): raise TypeError("unexpected cdata type") ptr = type(cdata)._to_ctypes(cdata) elif isinstance(cdata, CTypesGenericArray): ptr = type(cdata)._to_ctypes(cdata) else: raise TypeError("expected a <cdata 'struct-or-union'>") if offset: ptr = ctypes.cast( ctypes.c_void_p( ctypes.cast(ptr, ctypes.c_void_p).value + offset), type(ptr)) return BTypePtr._from_ctypes(ptr) class CTypesLibrary(object): def __init__(self, backend, cdll): self.backend = backend self.cdll = cdll def load_function(self, BType, name): c_func = getattr(self.cdll, name) funcobj = BType._from_ctypes(c_func) funcobj._name = name return funcobj def read_variable(self, BType, name): try: ctypes_obj = BType._ctype.in_dll(self.cdll, name) except AttributeError as e: raise NotImplementedError(e) return BType._from_ctypes(ctypes_obj) def write_variable(self, BType, name, value): new_ctypes_obj = BType._to_ctypes(value) ctypes_obj = BType._ctype.in_dll(self.cdll, name) ctypes.memmove(ctypes.addressof(ctypes_obj), ctypes.addressof(new_ctypes_obj), ctypes.sizeof(BType._ctype)) PK %�\2@�� � api.pynu �[��� import sys, types from .lock import allocate_lock from .error import CDefError from . import model try: callable except NameError: # Python 3.1 from collections import Callable callable = lambda x: isinstance(x, Callable) try: basestring except NameError: # Python 3.x basestring = str class FFI(object): r''' The main top-level class that you instantiate once, or once per module. Example usage: ffi = FFI() ffi.cdef(""" int printf(const char *, ...); """) C = ffi.dlopen(None) # standard library -or- C = ffi.verify() # use a C compiler: verify the decl above is right C.printf("hello, %s!\n", ffi.new("char[]", "world")) ''' def __init__(self, backend=None): """Create an FFI instance. The 'backend' argument is used to select a non-default backend, mostly for tests. """ if backend is None: # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with # _cffi_backend.so compiled. import _cffi_backend as backend from . import __version__ if backend.__version__ != __version__: # bad version! Try to be as explicit as possible. if hasattr(backend, '__file__'): # CPython raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( __version__, __file__, backend.__version__, backend.__file__)) else: # PyPy raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( __version__, __file__, backend.__version__)) # (If you insist you can also try to pass the option # 'backend=backend_ctypes.CTypesBackend()', but don't # rely on it! It's probably not going to work well.) from . import cparser self._backend = backend self._lock = allocate_lock() self._parser = cparser.Parser() self._cached_btypes = {} self._parsed_types = types.ModuleType('parsed_types').__dict__ self._new_types = types.ModuleType('new_types').__dict__ self._function_caches = [] self._libraries = [] self._cdefsources = [] self._included_ffis = [] self._windows_unicode = None self._init_once_cache = {} self._cdef_version = None self._embedding = None self._typecache = model.get_typecache(backend) if hasattr(backend, 'set_ffi'): backend.set_ffi(self) for name in list(backend.__dict__): if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # with self._lock: self.BVoidP = self._get_cached_btype(model.voidp_type) self.BCharA = self._get_cached_btype(model.char_array_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() self.buffer = backend.buffer def cdef(self, csource, override=False, packed=False): """Parse the given C source. This registers all declared functions, types, and global variables. The functions and global variables can then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. The types can be used in 'ffi.new()' and other functions. If 'packed' is specified as True, all structs declared inside this cdef are packed, i.e. laid out without any field alignment at all. """ self._cdef(csource, override=override, packed=packed) def embedding_api(self, csource, packed=False): self._cdef(csource, packed=packed, dllexport=True) if self._embedding is None: self._embedding = '' def _cdef(self, csource, override=False, **options): if not isinstance(csource, str): # unicode, on Python 2 if not isinstance(csource, basestring): raise TypeError("cdef() argument must be a string") csource = csource.encode('ascii') with self._lock: self._cdef_version = object() self._parser.parse(csource, override=override, **options) self._cdefsources.append(csource) if override: for cache in self._function_caches: cache.clear() finishlist = self._parser._recomplete if finishlist: self._parser._recomplete = [] for tp in finishlist: tp.finish_backend_type(self, finishlist) def dlopen(self, name, flags=0): """Load and return a dynamic library identified by 'name'. The standard C library can be loaded by passing None. Note that functions and types declared by 'ffi.cdef()' are not linked to a particular library, just like C headers; in the library we only look for the actual (untyped) symbols. """ assert isinstance(name, basestring) or name is None with self._lock: lib, function_cache = _make_ffi_library(self, name, flags) self._function_caches.append(function_cache) self._libraries.append(lib) return lib def dlclose(self, lib): """Close a library obtained with ffi.dlopen(). After this call, access to functions or variables from the library will fail (possibly with a segmentation fault). """ type(lib).__cffi_close__(lib) def _typeof_locked(self, cdecl): # call me with the lock! key = cdecl if key in self._parsed_types: return self._parsed_types[key] # if not isinstance(cdecl, str): # unicode, on Python 2 cdecl = cdecl.encode('ascii') # type = self._parser.parse_type(cdecl) really_a_function_type = type.is_raw_function if really_a_function_type: type = type.as_function_pointer() btype = self._get_cached_btype(type) result = btype, really_a_function_type self._parsed_types[key] = result return result def _typeof(self, cdecl, consider_function_as_funcptr=False): # string -> ctype object try: result = self._parsed_types[cdecl] except KeyError: with self._lock: result = self._typeof_locked(cdecl) # btype, really_a_function_type = result if really_a_function_type and not consider_function_as_funcptr: raise CDefError("the type %r is a function type, not a " "pointer-to-function type" % (cdecl,)) return btype def typeof(self, cdecl): """Parse the C type given as a string and return the corresponding <ctype> object. It can also be used on 'cdata' instance to get its C type. """ if isinstance(cdecl, basestring): return self._typeof(cdecl) if isinstance(cdecl, self.CData): return self._backend.typeof(cdecl) if isinstance(cdecl, types.BuiltinFunctionType): res = _builtin_function_type(cdecl) if res is not None: return res if (isinstance(cdecl, types.FunctionType) and hasattr(cdecl, '_cffi_base_type')): with self._lock: return self._get_cached_btype(cdecl._cffi_base_type) raise TypeError(type(cdecl)) def sizeof(self, cdecl): """Return the size in bytes of the argument. It can be a string naming a C type, or a 'cdata' instance. """ if isinstance(cdecl, basestring): BType = self._typeof(cdecl) return self._backend.sizeof(BType) else: return self._backend.sizeof(cdecl) def alignof(self, cdecl): """Return the natural alignment size in bytes of the C type given as a string. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) return self._backend.alignof(cdecl) def offsetof(self, cdecl, *fields_or_indexes): """Return the offset of the named field inside the given structure or array, which must be given as a C type name. You can give several field names in case of nested structures. You can also give numeric values which correspond to array items, in case of an array type. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) return self._typeoffsetof(cdecl, *fields_or_indexes)[1] def new(self, cdecl, init=None): """Allocate an instance according to the specified C type and return a pointer to it. The specified C type must be either a pointer or an array: ``new('X *')`` allocates an X and returns a pointer to it, whereas ``new('X[n]')`` allocates an array of n X'es and returns an array referencing it (which works mostly like a pointer, like in C). You can also use ``new('X[]', n)`` to allocate an array of a non-constant length n. The memory is initialized following the rules of declaring a global variable in C: by default it is zero-initialized, but an explicit initializer can be given which can be used to fill all or part of the memory. When the returned <cdata> object goes out of scope, the memory is freed. In other words the returned <cdata> object has ownership of the value of type 'cdecl' that it points to. This means that the raw data can be used as long as this object is kept alive, but must not be used for a longer time. Be careful about that when copying the pointer to the memory somewhere else, e.g. into another structure. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) return self._backend.newp(cdecl, init) def new_allocator(self, alloc=None, free=None, should_clear_after_alloc=True): """Return a new allocator, i.e. a function that behaves like ffi.new() but uses the provided low-level 'alloc' and 'free' functions. 'alloc' is called with the size as argument. If it returns NULL, a MemoryError is raised. 'free' is called with the result of 'alloc' as argument. Both can be either Python function or directly C functions. If 'free' is None, then no free function is called. If both 'alloc' and 'free' are None, the default is used. If 'should_clear_after_alloc' is set to False, then the memory returned by 'alloc' is assumed to be already cleared (or you are fine with garbage); otherwise CFFI will clear it. """ compiled_ffi = self._backend.FFI() allocator = compiled_ffi.new_allocator(alloc, free, should_clear_after_alloc) def allocate(cdecl, init=None): if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) return allocator(cdecl, init) return allocate def cast(self, cdecl, source): """Similar to a C cast: returns an instance of the named C type initialized with the given 'source'. The source is casted between integers or pointers of any type. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) return self._backend.cast(cdecl, source) def string(self, cdata, maxlen=-1): """Return a Python string (or unicode string) from the 'cdata'. If 'cdata' is a pointer or array of characters or bytes, returns the null-terminated string. The returned string extends until the first null character, or at most 'maxlen' characters. If 'cdata' is an array then 'maxlen' defaults to its length. If 'cdata' is a pointer or array of wchar_t, returns a unicode string following the same rules. If 'cdata' is a single character or byte or a wchar_t, returns it as a string or unicode string. If 'cdata' is an enum, returns the value of the enumerator as a string, or 'NUMBER' if the value is out of range. """ return self._backend.string(cdata, maxlen) def unpack(self, cdata, length): """Unpack an array of C data of the given length, returning a Python string/unicode/list. If 'cdata' is a pointer to 'char', returns a byte string. It does not stop at the first null. This is equivalent to: ffi.buffer(cdata, length)[:] If 'cdata' is a pointer to 'wchar_t', returns a unicode string. 'length' is measured in wchar_t's; it is not the size in bytes. If 'cdata' is a pointer to anything else, returns a list of 'length' items. This is a faster equivalent to: [cdata[i] for i in range(length)] """ return self._backend.unpack(cdata, length) #def buffer(self, cdata, size=-1): # """Return a read-write buffer object that references the raw C data # pointed to by the given 'cdata'. The 'cdata' must be a pointer or # an array. Can be passed to functions expecting a buffer, or directly # manipulated with: # # buf[:] get a copy of it in a regular string, or # buf[idx] as a single character # buf[:] = ... # buf[idx] = ... change the content # """ # note that 'buffer' is a type, set on this instance by __init__ def from_buffer(self, python_buffer, require_writable=False): """Return a <cdata 'char[]'> that points to the data of the given Python object, which must support the buffer interface. Note that this is not meant to be used on the built-in types str or unicode (you can build 'char[]' arrays explicitly) but only on objects containing large quantities of raw data in some other format, like 'array.array' or numpy arrays. """ return self._backend.from_buffer(self.BCharA, python_buffer, require_writable) def memmove(self, dest, src, n): """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. Like the C function memmove(), the memory areas may overlap; apart from that it behaves like the C function memcpy(). 'src' can be any cdata ptr or array, or any Python buffer object. 'dest' can be any cdata ptr or array, or a writable Python buffer object. The size to copy, 'n', is always measured in bytes. Unlike other methods, this one supports all Python buffer including byte strings and bytearrays---but it still does not support non-contiguous buffers. """ return self._backend.memmove(dest, src, n) def callback(self, cdecl, python_callable=None, error=None, onerror=None): """Return a callback object or a decorator making such a callback object. 'cdecl' must name a C function pointer type. The callback invokes the specified 'python_callable' (which may be provided either directly or via a decorator). Important: the callback object must be manually kept alive for as long as the callback may be invoked from the C level. """ def callback_decorator_wrap(python_callable): if not callable(python_callable): raise TypeError("the 'python_callable' argument " "is not callable") return self._backend.callback(cdecl, python_callable, error, onerror) if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) if python_callable is None: return callback_decorator_wrap # decorator mode else: return callback_decorator_wrap(python_callable) # direct mode def getctype(self, cdecl, replace_with=''): """Return a string giving the C type 'cdecl', which may be itself a string or a <ctype> object. If 'replace_with' is given, it gives extra text to append (or insert for more complicated C types), like a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) replace_with = replace_with.strip() if (replace_with.startswith('*') and '&[' in self._backend.getcname(cdecl, '&')): replace_with = '(%s)' % replace_with elif replace_with and not replace_with[0] in '[(': replace_with = ' ' + replace_with return self._backend.getcname(cdecl, replace_with) def gc(self, cdata, destructor, size=0): """Return a new cdata object that points to the same data. Later, when this new cdata object is garbage-collected, 'destructor(old_cdata_object)' will be called. The optional 'size' gives an estimate of the size, used to trigger the garbage collection more eagerly. So far only used on PyPy. It tells the GC that the returned object keeps alive roughly 'size' bytes of external memory. """ return self._backend.gcp(cdata, destructor, size) def _get_cached_btype(self, type): assert self._lock.acquire(False) is False # call me with the lock! try: BType = self._cached_btypes[type] except KeyError: finishlist = [] BType = type.get_cached_btype(self, finishlist) for type in finishlist: type.finish_backend_type(self, finishlist) return BType def verify(self, source='', tmpdir=None, **kwargs): """Verify that the current ffi signatures compile on this machine, and return a dynamic library object. The dynamic library can be used to call functions and access global variables declared in this 'ffi'. The library is compiled by the C compiler: it gives you C-level API compatibility (including calling macros). This is unlike 'ffi.dlopen()', which requires binary compatibility in the signatures. """ from .verifier import Verifier, _caller_dir_pycache # # If set_unicode(True) was called, insert the UNICODE and # _UNICODE macro declarations if self._windows_unicode: self._apply_windows_unicode(kwargs) # # Set the tmpdir here, and not in Verifier.__init__: it picks # up the caller's directory, which we want to be the caller of # ffi.verify(), as opposed to the caller of Veritier(). tmpdir = tmpdir or _caller_dir_pycache() # # Make a Verifier() and use it to load the library. self.verifier = Verifier(self, source, tmpdir, **kwargs) lib = self.verifier.load_library() # # Save the loaded library for keep-alive purposes, even # if the caller doesn't keep it alive itself (it should). self._libraries.append(lib) return lib def _get_errno(self): return self._backend.get_errno() def _set_errno(self, errno): self._backend.set_errno(errno) errno = property(_get_errno, _set_errno, None, "the value of 'errno' from/to the C calls") def getwinerror(self, code=-1): return self._backend.getwinerror(code) def _pointer_to(self, ctype): with self._lock: return model.pointer_cache(self, ctype) def addressof(self, cdata, *fields_or_indexes): """Return the address of a <cdata 'struct-or-union'>. If 'fields_or_indexes' are given, returns the address of that field or array item in the structure or array, recursively in case of nested structures. """ try: ctype = self._backend.typeof(cdata) except TypeError: if '__addressof__' in type(cdata).__dict__: return type(cdata).__addressof__(cdata, *fields_or_indexes) raise if fields_or_indexes: ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) else: if ctype.kind == "pointer": raise TypeError("addressof(pointer)") offset = 0 ctypeptr = self._pointer_to(ctype) return self._backend.rawaddressof(ctypeptr, cdata, offset) def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) for field1 in fields_or_indexes: ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) offset += offset1 return ctype, offset def include(self, ffi_to_include): """Includes the typedefs, structs, unions and enums defined in another FFI instance. Usage is similar to a #include in C, where a part of the program might include types defined in another part for its own usage. Note that the include() method has no effect on functions, constants and global variables, which must anyway be accessed directly from the lib object returned by the original FFI instance. """ if not isinstance(ffi_to_include, FFI): raise TypeError("ffi.include() expects an argument that is also of" " type cffi.FFI, not %r" % ( type(ffi_to_include).__name__,)) if ffi_to_include is self: raise ValueError("self.include(self)") with ffi_to_include._lock: with self._lock: self._parser.include(ffi_to_include._parser) self._cdefsources.append('[') self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') self._included_ffis.append(ffi_to_include) def new_handle(self, x): return self._backend.newp_handle(self.BVoidP, x) def from_handle(self, x): return self._backend.from_handle(x) def set_unicode(self, enabled_flag): """Windows: if 'enabled_flag' is True, enable the UNICODE and _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR to be (pointers to) wchar_t. If 'enabled_flag' is False, declare these types to be (pointers to) plain 8-bit characters. This is mostly for backward compatibility; you usually want True. """ if self._windows_unicode is not None: raise ValueError("set_unicode() can only be called once") enabled_flag = bool(enabled_flag) if enabled_flag: self.cdef("typedef wchar_t TBYTE;" "typedef wchar_t TCHAR;" "typedef const wchar_t *LPCTSTR;" "typedef const wchar_t *PCTSTR;" "typedef wchar_t *LPTSTR;" "typedef wchar_t *PTSTR;" "typedef TBYTE *PTBYTE;" "typedef TCHAR *PTCHAR;") else: self.cdef("typedef char TBYTE;" "typedef char TCHAR;" "typedef const char *LPCTSTR;" "typedef const char *PCTSTR;" "typedef char *LPTSTR;" "typedef char *PTSTR;" "typedef TBYTE *PTBYTE;" "typedef TCHAR *PTCHAR;") self._windows_unicode = enabled_flag def _apply_windows_unicode(self, kwds): defmacros = kwds.get('define_macros', ()) if not isinstance(defmacros, (list, tuple)): raise TypeError("'define_macros' must be a list or tuple") defmacros = list(defmacros) + [('UNICODE', '1'), ('_UNICODE', '1')] kwds['define_macros'] = defmacros def _apply_embedding_fix(self, kwds): # must include an argument like "-lpython2.7" for the compiler def ensure(key, value): lst = kwds.setdefault(key, []) if value not in lst: lst.append(value) # if '__pypy__' in sys.builtin_module_names: import os if sys.platform == "win32": # we need 'libpypy-c.lib'. Current distributions of # pypy (>= 4.1) contain it as 'libs/python27.lib'. pythonlib = "python27" if hasattr(sys, 'prefix'): ensure('library_dirs', os.path.join(sys.prefix, 'libs')) else: # we need 'libpypy-c.{so,dylib}', which should be by # default located in 'sys.prefix/bin' for installed # systems. if sys.version_info < (3,): pythonlib = "pypy-c" else: pythonlib = "pypy3-c" if hasattr(sys, 'prefix'): ensure('library_dirs', os.path.join(sys.prefix, 'bin')) # On uninstalled pypy's, the libpypy-c is typically found in # .../pypy/goal/. if hasattr(sys, 'prefix'): ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) else: if sys.platform == "win32": template = "python%d%d" if hasattr(sys, 'gettotalrefcount'): template += '_d' else: try: import sysconfig except ImportError: # 2.6 from distutils import sysconfig template = "python%d.%d" if sysconfig.get_config_var('DEBUG_EXT'): template += sysconfig.get_config_var('DEBUG_EXT') pythonlib = (template % (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) if hasattr(sys, 'abiflags'): pythonlib += sys.abiflags ensure('libraries', pythonlib) if sys.platform == "win32": ensure('extra_link_args', '/MANIFEST') def set_source(self, module_name, source, source_extension='.c', **kwds): import os if hasattr(self, '_assigned_source'): raise ValueError("set_source() cannot be called several times " "per ffi object") if not isinstance(module_name, basestring): raise TypeError("'module_name' must be a string") if os.sep in module_name or (os.altsep and os.altsep in module_name): raise ValueError("'module_name' must not contain '/': use a dotted " "name to make a 'package.module' location") self._assigned_source = (str(module_name), source, source_extension, kwds) def distutils_extension(self, tmpdir='build', verbose=True): from distutils.dir_util import mkpath from .recompiler import recompile # if not hasattr(self, '_assigned_source'): if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored return self.verifier.get_extension() raise ValueError("set_source() must be called before" " distutils_extension()") module_name, source, source_extension, kwds = self._assigned_source if source is None: raise TypeError("distutils_extension() is only for C extension " "modules, not for dlopen()-style pure Python " "modules") mkpath(tmpdir) ext, updated = recompile(self, module_name, source, tmpdir=tmpdir, extradir=tmpdir, source_extension=source_extension, call_c_compiler=False, **kwds) if verbose: if updated: sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) else: sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) return ext def emit_c_code(self, filename): from .recompiler import recompile # if not hasattr(self, '_assigned_source'): raise ValueError("set_source() must be called before emit_c_code()") module_name, source, source_extension, kwds = self._assigned_source if source is None: raise TypeError("emit_c_code() is only for C extension modules, " "not for dlopen()-style pure Python modules") recompile(self, module_name, source, c_file=filename, call_c_compiler=False, **kwds) def emit_python_code(self, filename): from .recompiler import recompile # if not hasattr(self, '_assigned_source'): raise ValueError("set_source() must be called before emit_c_code()") module_name, source, source_extension, kwds = self._assigned_source if source is not None: raise TypeError("emit_python_code() is only for dlopen()-style " "pure Python modules, not for C extension modules") recompile(self, module_name, source, c_file=filename, call_c_compiler=False, **kwds) def compile(self, tmpdir='.', verbose=0, target=None, debug=None): """The 'target' argument gives the final file name of the compiled DLL. Use '*' to force distutils' choice, suitable for regular CPython C API modules. Use a file name ending in '.*' to ask for the system's default extension for dynamic libraries (.so/.dll/.dylib). The default is '*' when building a non-embedded C API extension, and (module_name + '.*') when building an embedded library. """ from .recompiler import recompile # if not hasattr(self, '_assigned_source'): raise ValueError("set_source() must be called before compile()") module_name, source, source_extension, kwds = self._assigned_source return recompile(self, module_name, source, tmpdir=tmpdir, target=target, source_extension=source_extension, compiler_verbose=verbose, debug=debug, **kwds) def init_once(self, func, tag): # Read _init_once_cache[tag], which is either (False, lock) if # we're calling the function now in some thread, or (True, result). # Don't call setdefault() in most cases, to avoid allocating and # immediately freeing a lock; but still use setdefaut() to avoid # races. try: x = self._init_once_cache[tag] except KeyError: x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) # Common case: we got (True, result), so we return the result. if x[0]: return x[1] # Else, it's a lock. Acquire it to serialize the following tests. with x[1]: # Read again from _init_once_cache the current status. x = self._init_once_cache[tag] if x[0]: return x[1] # Call the function and store the result back. result = func() self._init_once_cache[tag] = (True, result) return result def embedding_init_code(self, pysource): if self._embedding: raise ValueError("embedding_init_code() can only be called once") # fix 'pysource' before it gets dumped into the C file: # - remove empty lines at the beginning, so it starts at "line 1" # - dedent, if all non-empty lines are indented # - check for SyntaxErrors import re match = re.match(r'\s*\n', pysource) if match: pysource = pysource[match.end():] lines = pysource.splitlines() or [''] prefix = re.match(r'\s*', lines[0]).group() for i in range(1, len(lines)): line = lines[i] if line.rstrip(): while not line.startswith(prefix): prefix = prefix[:-1] i = len(prefix) lines = [line[i:]+'\n' for line in lines] pysource = ''.join(lines) # compile(pysource, "cffi_init", "exec") # self._embedding = pysource def def_extern(self, *args, **kwds): raise ValueError("ffi.def_extern() is only available on API-mode FFI " "objects") def list_types(self): """Returns the user type names known to this FFI instance. This returns a tuple containing three lists of names: (typedef_names, names_of_structs, names_of_unions) """ typedefs = [] structs = [] unions = [] for key in self._parser._declarations: if key.startswith('typedef '): typedefs.append(key[8:]) elif key.startswith('struct '): structs.append(key[7:]) elif key.startswith('union '): unions.append(key[6:]) typedefs.sort() structs.sort() unions.sort() return (typedefs, structs, unions) def _load_backend_lib(backend, name, flags): import os if name is None: if sys.platform != "win32": return backend.load_library(None, flags) name = "c" # Windows: load_library(None) fails, but this works # on Python 2 (backward compatibility hack only) first_error = None if '.' in name or '/' in name or os.sep in name: try: return backend.load_library(name, flags) except OSError as e: first_error = e import ctypes.util path = ctypes.util.find_library(name) if path is None: if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): raise OSError("dlopen(None) cannot work on Windows for Python 3 " "(see http://bugs.python.org/issue23606)") msg = ("ctypes.util.find_library() did not manage " "to locate a library called %r" % (name,)) if first_error is not None: msg = "%s. Additionally, %s" % (first_error, msg) raise OSError(msg) return backend.load_library(path, flags) def _make_ffi_library(ffi, libname, flags): backend = ffi._backend backendlib = _load_backend_lib(backend, libname, flags) # def accessor_function(name): key = 'function ' + name tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) value = backendlib.load_function(BType, name) library.__dict__[name] = value # def accessor_variable(name): key = 'variable ' + name tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) read_variable = backendlib.read_variable write_variable = backendlib.write_variable setattr(FFILibrary, name, property( lambda self: read_variable(BType, name), lambda self, value: write_variable(BType, name, value))) # def addressof_var(name): try: return addr_variables[name] except KeyError: with ffi._lock: if name not in addr_variables: key = 'variable ' + name tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) if BType.kind != 'array': BType = model.pointer_cache(ffi, BType) p = backendlib.load_function(BType, name) addr_variables[name] = p return addr_variables[name] # def accessor_constant(name): raise NotImplementedError("non-integer constant '%s' cannot be " "accessed from a dlopen() library" % (name,)) # def accessor_int_constant(name): library.__dict__[name] = ffi._parser._int_constants[name] # accessors = {} accessors_version = [False] addr_variables = {} # def update_accessors(): if accessors_version[0] is ffi._cdef_version: return # for key, (tp, _) in ffi._parser._declarations.items(): if not isinstance(tp, model.EnumType): tag, name = key.split(' ', 1) if tag == 'function': accessors[name] = accessor_function elif tag == 'variable': accessors[name] = accessor_variable elif tag == 'constant': accessors[name] = accessor_constant else: for i, enumname in enumerate(tp.enumerators): def accessor_enum(name, tp=tp, i=i): tp.check_not_partial() library.__dict__[name] = tp.enumvalues[i] accessors[enumname] = accessor_enum for name in ffi._parser._int_constants: accessors.setdefault(name, accessor_int_constant) accessors_version[0] = ffi._cdef_version # def make_accessor(name): with ffi._lock: if name in library.__dict__ or name in FFILibrary.__dict__: return # added by another thread while waiting for the lock if name not in accessors: update_accessors() if name not in accessors: raise AttributeError(name) accessors[name](name) # class FFILibrary(object): def __getattr__(self, name): make_accessor(name) return getattr(self, name) def __setattr__(self, name, value): try: property = getattr(self.__class__, name) except AttributeError: make_accessor(name) setattr(self, name, value) else: property.__set__(self, value) def __dir__(self): with ffi._lock: update_accessors() return accessors.keys() def __addressof__(self, name): if name in library.__dict__: return library.__dict__[name] if name in FFILibrary.__dict__: return addressof_var(name) make_accessor(name) if name in library.__dict__: return library.__dict__[name] if name in FFILibrary.__dict__: return addressof_var(name) raise AttributeError("cffi library has no function or " "global variable named '%s'" % (name,)) def __cffi_close__(self): backendlib.close_lib() self.__dict__.clear() # if libname is not None: try: if not isinstance(libname, str): # unicode, on Python 2 libname = libname.encode('utf-8') FFILibrary.__name__ = 'FFILibrary_%s' % libname except UnicodeError: pass library = FFILibrary() return library, library.__dict__ def _builtin_function_type(func): # a hack to make at least ffi.typeof(builtin_function) work, # if the builtin function was obtained by 'vengine_cpy'. import sys try: module = sys.modules[func.__module__] ffi = module._cffi_original_ffi types_of_builtin_funcs = module._cffi_types_of_builtin_funcs tp = types_of_builtin_funcs[func] except (KeyError, AttributeError, TypeError): return None else: with ffi._lock: return ffi._get_cached_btype(tp) PK %�\��3�R� R� cparser.pynu �[��� from . import model from .commontypes import COMMON_TYPES, resolve_common_type from .error import FFIError, CDefError try: from . import _pycparser as pycparser except ImportError: import pycparser import weakref, re, sys try: if sys.version_info < (3,): import thread as _thread else: import _thread lock = _thread.allocate_lock() except ImportError: lock = None CDEF_SOURCE_STRING = "<cdef source string>" _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", re.DOTALL | re.MULTILINE) _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" r"\b((?:[^\n\\]|\\.)*?)$", re.DOTALL | re.MULTILINE) _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 _r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) _r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") _r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") _r_cdecl = re.compile(r"\b__cdecl\b") _r_extern_python = re.compile(r'\bextern\s*"' r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') _r_star_const_space = re.compile( # matches "* const " r"[*]\s*((const|volatile|restrict)\b\s*)+") _r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" r"\.\.\.") _r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") def _get_parser(): global _parser_cache if _parser_cache is None: _parser_cache = pycparser.CParser() return _parser_cache def _workaround_for_old_pycparser(csource): # Workaround for a pycparser issue (fixed between pycparser 2.10 and # 2.14): "char*const***" gives us a wrong syntax tree, the same as # for "char***(*const)". This means we can't tell the difference # afterwards. But "char(*const(***))" gives us the right syntax # tree. The issue only occurs if there are several stars in # sequence with no parenthesis inbetween, just possibly qualifiers. # Attempt to fix it by adding some parentheses in the source: each # time we see "* const" or "* const *", we add an opening # parenthesis before each star---the hard part is figuring out where # to close them. parts = [] while True: match = _r_star_const_space.search(csource) if not match: break #print repr(''.join(parts)+csource), '=>', parts.append(csource[:match.start()]) parts.append('('); closing = ')' parts.append(match.group()) # e.g. "* const " endpos = match.end() if csource.startswith('*', endpos): parts.append('('); closing += ')' level = 0 i = endpos while i < len(csource): c = csource[i] if c == '(': level += 1 elif c == ')': if level == 0: break level -= 1 elif c in ',;=': if level == 0: break i += 1 csource = csource[endpos:i] + closing + csource[i:] #print repr(''.join(parts)+csource) parts.append(csource) return ''.join(parts) def _preprocess_extern_python(csource): # input: `extern "Python" int foo(int);` or # `extern "Python" { int foo(int); }` # output: # void __cffi_extern_python_start; # int foo(int); # void __cffi_extern_python_stop; # # input: `extern "Python+C" int foo(int);` # output: # void __cffi_extern_python_plus_c_start; # int foo(int); # void __cffi_extern_python_stop; parts = [] while True: match = _r_extern_python.search(csource) if not match: break endpos = match.end() - 1 #print #print ''.join(parts)+csource #print '=>' parts.append(csource[:match.start()]) if 'C' in match.group(1): parts.append('void __cffi_extern_python_plus_c_start; ') else: parts.append('void __cffi_extern_python_start; ') if csource[endpos] == '{': # grouping variant closing = csource.find('}', endpos) if closing < 0: raise CDefError("'extern \"Python\" {': no '}' found") if csource.find('{', endpos + 1, closing) >= 0: raise NotImplementedError("cannot use { } inside a block " "'extern \"Python\" { ... }'") parts.append(csource[endpos+1:closing]) csource = csource[closing+1:] else: # non-grouping variant semicolon = csource.find(';', endpos) if semicolon < 0: raise CDefError("'extern \"Python\": no ';' found") parts.append(csource[endpos:semicolon+1]) csource = csource[semicolon+1:] parts.append(' void __cffi_extern_python_stop;') #print ''.join(parts)+csource #print parts.append(csource) return ''.join(parts) def _preprocess(csource): # Remove comments. NOTE: this only work because the cdef() section # should not contain any string literal! csource = _r_comment.sub(' ', csource) # Remove the "#define FOO x" lines macros = {} for match in _r_define.finditer(csource): macroname, macrovalue = match.groups() macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) # if pycparser.__version__ < '2.14': csource = _workaround_for_old_pycparser(csource) # # BIG HACK: replace WINAPI or __stdcall with "volatile const". # It doesn't make sense for the return type of a function to be # "volatile volatile const", so we abuse it to detect __stdcall... # Hack number 2 is that "int(volatile *fptr)();" is not valid C # syntax, so we place the "volatile" before the opening parenthesis. csource = _r_stdcall2.sub(' volatile volatile const(', csource) csource = _r_stdcall1.sub(' volatile volatile const ', csource) csource = _r_cdecl.sub(' ', csource) # # Replace `extern "Python"` with start/end markers csource = _preprocess_extern_python(csource) # # Replace "[...]" with "[__dotdotdotarray__]" csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) # # Replace "...}" with "__dotdotdotNUM__}". This construction should # occur only at the end of enums; at the end of structs we have "...;}" # and at the end of vararg functions "...);". Also replace "=...[,}]" # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when # giving an unknown value. matches = list(_r_partial_enum.finditer(csource)) for number, match in enumerate(reversed(matches)): p = match.start() if csource[p] == '=': p2 = csource.find('...', p, match.end()) assert p2 > p csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, csource[p2+3:]) else: assert csource[p:p+3] == '...' csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, csource[p+3:]) # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) # Replace "float ..." or "double..." with "__dotdotdotfloat__" csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) # Replace all remaining "..." with the same name, "__dotdotdot__", # 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(',') look_for_words.add('(') look_for_words.add(')') look_for_words.add('typedef') words_used = set() is_typedef = False paren = 0 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 paren = 0 elif word == '(': paren += 1 elif word == ')': paren -= 1 elif word == ',': if is_typedef and paren == 0: words_used.discard(previous_word) look_for_words.discard(previous_word) else: # word in COMMON_TYPES words_used.add(word) previous_word = word return words_used class Parser(object): def __init__(self): self._declarations = {} self._included_declarations = set() self._anonymous_counter = 0 self._structnode2type = weakref.WeakKeyDictionary() self._options = {} self._int_constants = {} self._recomplete = [] self._uses_new_feature = None 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) ctn = _common_type_names(csource) typenames = [] for name in sorted(self._declarations): if name.startswith('typedef '): name = name[8:] typenames.append(name) ctn.discard(name) typenames += sorted(ctn) # csourcelines = [] csourcelines.append('# 1 "<cdef automatic initialization code>"') for typename in typenames: csourcelines.append('typedef int %s;' % typename) csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' ' __dotdotdot__;') # this forces pycparser to consider the following in the file # called <cdef source string> from line 1 csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) csourcelines.append(csource) fullcsource = '\n'.join(csourcelines) if lock is not None: lock.acquire() # pycparser is not thread-safe... try: ast = _get_parser().parse(fullcsource) except pycparser.c_parser.ParseError as e: self.convert_pycparser_error(e, csource) finally: if lock is not None: lock.release() # csource will be used to find buggy source text return ast, macros, csource def _convert_pycparser_error(self, e, csource): # xxx look for "<cdef source string>:NUM:" at the start of str(e) # and interpret that as a line number. This will not work if # the user gives explicit ``# NUM "FILE"`` directives. line = None msg = str(e) match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) if match: linenum = int(match.group(1), 10) csourcelines = csource.splitlines() if 1 <= linenum <= len(csourcelines): line = csourcelines[linenum-1] return line def convert_pycparser_error(self, e, csource): line = self._convert_pycparser_error(e, csource) msg = str(e) if line: msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) else: msg = 'parse error\n%s' % (msg,) raise CDefError(msg) def parse(self, csource, override=False, packed=False, dllexport=False): prev_options = self._options try: self._options = {'override': override, 'packed': packed, 'dllexport': dllexport} self._internal_parse(csource) finally: self._options = prev_options def _internal_parse(self, csource): ast, macros, csource = self._parse(csource) # add the macros self._process_macros(macros) # find the first "__dotdotdot__" and use that as a separator # between the repeated typedefs and the real csource iterator = iter(ast.ext) for decl in iterator: if decl.name == '__dotdotdot__': break else: assert 0 current_decl = None # try: self._inside_extern_python = '__cffi_extern_python_stop' for decl in iterator: current_decl = decl if isinstance(decl, pycparser.c_ast.Decl): self._parse_decl(decl) elif isinstance(decl, pycparser.c_ast.Typedef): if not decl.name: raise CDefError("typedef does not declare any name", decl) quals = 0 if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and decl.type.type.names[-1].startswith('__dotdotdot')): realtype = self._get_unknown_type(decl) elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and isinstance(decl.type.type.type, pycparser.c_ast.IdentifierType) and decl.type.type.type.names[-1].startswith('__dotdotdot')): realtype = self._get_unknown_ptr_type(decl) else: realtype, quals = self._get_type_and_quals( decl.type, name=decl.name, partial_length_ok=True) self._declare('typedef ' + decl.name, realtype, quals=quals) elif decl.__class__.__name__ == 'Pragma': pass # skip pragma, only in pycparser 2.15 else: raise CDefError("unexpected <%s>: this construct is valid " "C but not valid in cdef()" % decl.__class__.__name__, decl) except CDefError as e: if len(e.args) == 1: e.args = e.args + (current_decl,) raise except FFIError as e: msg = self._convert_pycparser_error(e, csource) if msg: e.args = (e.args[0] + "\n *** Err: %s" % msg,) raise def _add_constants(self, key, val): if key in self._int_constants: if self._int_constants[key] == val: return # ignore identical double declarations raise FFIError( "multiple declarations of constant: %s" % (key,)) self._int_constants[key] = val def _add_integer_constant(self, name, int_str): int_str = int_str.lower().rstrip("ul") neg = int_str.startswith('-') if neg: int_str = int_str[1:] # "010" is not valid oct in py3 if (int_str.startswith("0") and int_str != '0' and not int_str.startswith("0x")): int_str = "0o" + int_str[1:] pyvalue = int(int_str, 0) if neg: pyvalue = -pyvalue self._add_constants(name, pyvalue) self._declare('macro ' + name, pyvalue) def _process_macros(self, macros): for key, value in macros.items(): value = value.strip() if _r_int_literal.match(value): self._add_integer_constant(key, value) elif value == '...': self._declare('macro ' + key, value) else: raise CDefError( 'only supports one of the following syntax:\n' ' #define %s ... (literally dot-dot-dot)\n' ' #define %s NUMBER (with NUMBER an integer' ' constant, decimal/hex/octal)\n' 'got:\n' ' #define %s %s' % (key, key, key, value)) def _declare_function(self, tp, quals, decl): tp = self._get_type_pointer(tp, quals) if self._options.get('dllexport'): tag = 'dllexport_python ' elif self._inside_extern_python == '__cffi_extern_python_start': tag = 'extern_python ' elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': tag = 'extern_python_plus_c ' else: tag = 'function ' self._declare(tag + decl.name, tp) def _parse_decl(self, decl): node = decl.type if isinstance(node, pycparser.c_ast.FuncDecl): tp, quals = self._get_type_and_quals(node, name=decl.name) assert isinstance(tp, model.RawFunctionType) self._declare_function(tp, quals, decl) else: if isinstance(node, pycparser.c_ast.Struct): self._get_struct_union_enum_type('struct', node) elif isinstance(node, pycparser.c_ast.Union): self._get_struct_union_enum_type('union', node) elif isinstance(node, pycparser.c_ast.Enum): self._get_struct_union_enum_type('enum', node) elif not decl.name: raise CDefError("construct does not declare any variable", decl) # if decl.name: tp, quals = self._get_type_and_quals(node, partial_length_ok=True) if tp.is_raw_function: self._declare_function(tp, quals, decl) elif (tp.is_integer_type() and hasattr(decl, 'init') and hasattr(decl.init, 'value') and _r_int_literal.match(decl.init.value)): self._add_integer_constant(decl.name, decl.init.value) elif (tp.is_integer_type() and isinstance(decl.init, pycparser.c_ast.UnaryOp) and decl.init.op == '-' and hasattr(decl.init.expr, 'value') and _r_int_literal.match(decl.init.expr.value)): self._add_integer_constant(decl.name, '-' + decl.init.expr.value) elif (tp is model.void_type and decl.name.startswith('__cffi_extern_python_')): # hack: `extern "Python"` in the C source is replaced # with "void __cffi_extern_python_start;" and # "void __cffi_extern_python_stop;" self._inside_extern_python = decl.name else: if self._inside_extern_python !='__cffi_extern_python_stop': raise CDefError( "cannot declare constants or " "variables with 'extern \"Python\"'") if (quals & model.Q_CONST) and not tp.is_array_type: self._declare('constant ' + decl.name, tp, quals=quals) else: self._declare('variable ' + decl.name, tp, quals=quals) def parse_type(self, cdecl): return self.parse_type_and_quals(cdecl)[0] def parse_type_and_quals(self, cdecl): ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] assert not macros exprnode = ast.ext[-1].type.args.params[0] if isinstance(exprnode, pycparser.c_ast.ID): raise CDefError("unknown identifier '%s'" % (exprnode.name,)) return self._get_type_and_quals(exprnode.type) def _declare(self, name, obj, included=False, quals=0): if name in self._declarations: prevobj, prevquals = self._declarations[name] if prevobj is obj and prevquals == quals: return if not self._options.get('override'): raise FFIError( "multiple declarations of %s (for interactive usage, " "try cdef(xx, override=True))" % (name,)) assert '__dotdotdot__' not in name.split() self._declarations[name] = (obj, quals) if included: self._included_declarations.add(obj) def _extract_quals(self, type): quals = 0 if isinstance(type, (pycparser.c_ast.TypeDecl, pycparser.c_ast.PtrDecl)): if 'const' in type.quals: quals |= model.Q_CONST if 'volatile' in type.quals: quals |= model.Q_VOLATILE if 'restrict' in type.quals: quals |= model.Q_RESTRICT return quals def _get_type_pointer(self, type, quals, declname=None): if isinstance(type, model.RawFunctionType): return type.as_function_pointer() if (isinstance(type, model.StructOrUnionOrEnum) and type.name.startswith('$') and type.name[1:].isdigit() and type.forcename is None and declname is not None): return model.NamedPointerType(type, declname, quals) return model.PointerType(type, quals) def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False): # 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 len(typenode.type.names) == 1 and ('typedef ' + typenode.type.names[0]) in self._declarations): tp, quals = self._declarations['typedef ' + typenode.type.names[0]] quals |= self._extract_quals(typenode) return tp, quals # if isinstance(typenode, pycparser.c_ast.ArrayDecl): # array type if typenode.dim is None: length = None else: length = self._parse_constant( typenode.dim, partial_length_ok=partial_length_ok) tp, quals = self._get_type_and_quals(typenode.type, partial_length_ok=partial_length_ok) return model.ArrayType(tp, length), quals # if isinstance(typenode, pycparser.c_ast.PtrDecl): # pointer type itemtype, itemquals = self._get_type_and_quals(typenode.type) tp = self._get_type_pointer(itemtype, itemquals, declname=name) quals = self._extract_quals(typenode) return tp, quals # if isinstance(typenode, pycparser.c_ast.TypeDecl): quals = self._extract_quals(typenode) type = typenode.type if isinstance(type, pycparser.c_ast.IdentifierType): # assume a primitive type. get it from .names, but reduce # synonyms to a single chosen combination names = list(type.names) if names != ['signed', 'char']: # keep this unmodified prefixes = {} while names: name = names[0] if name in ('short', 'long', 'signed', 'unsigned'): prefixes[name] = prefixes.get(name, 0) + 1 del names[0] else: break # ignore the 'signed' prefix below, and reorder the others newnames = [] for prefix in ('unsigned', 'short', 'long'): for i in range(prefixes.get(prefix, 0)): newnames.append(prefix) if not names: names = ['int'] # implicitly if names == ['int']: # but kill it if 'short' or 'long' if 'short' in prefixes or 'long' in prefixes: names = [] names = newnames + names ident = ' '.join(names) if ident == 'void': return model.void_type, quals if ident == '__dotdotdot__': raise FFIError(':%d: bad usage of "..."' % typenode.coord.line) tp0, quals0 = resolve_common_type(self, ident) return tp0, (quals | quals0) # if isinstance(type, pycparser.c_ast.Struct): # 'struct foobar' tp = self._get_struct_union_enum_type('struct', type, name) return tp, quals # if isinstance(type, pycparser.c_ast.Union): # 'union foobar' tp = self._get_struct_union_enum_type('union', type, name) return tp, quals # if isinstance(type, pycparser.c_ast.Enum): # 'enum foobar' tp = self._get_struct_union_enum_type('enum', type, name) return tp, quals # if isinstance(typenode, pycparser.c_ast.FuncDecl): # a function type return self._parse_function_type(typenode, name), 0 # # nested anonymous structs or unions end up here if isinstance(typenode, pycparser.c_ast.Struct): return self._get_struct_union_enum_type('struct', typenode, name, nested=True), 0 if isinstance(typenode, pycparser.c_ast.Union): return self._get_struct_union_enum_type('union', typenode, name, nested=True), 0 # raise FFIError(":%d: bad or unsupported type declaration" % typenode.coord.line) def _parse_function_type(self, typenode, funcname=None): params = list(getattr(typenode.args, 'params', [])) for i, arg in enumerate(params): if not hasattr(arg, 'type'): raise CDefError("%s arg %d: unknown type '%s'" " (if you meant to use the old C syntax of giving" " untyped arguments, it is not supported)" % (funcname or 'in expression', i + 1, getattr(arg, 'name', '?'))) ellipsis = ( len(params) > 0 and isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and isinstance(params[-1].type.type, pycparser.c_ast.IdentifierType) and params[-1].type.type.names == ['__dotdotdot__']) if ellipsis: params.pop() if not params: raise CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) for argdeclnode in params] if not ellipsis and args == [model.void_type]: args = [] result, quals = self._get_type_and_quals(typenode.type) # the 'quals' on the result type are ignored. HACK: we absure them # to detect __stdcall functions: we textually replace "__stdcall" # with "volatile volatile const" above. abi = None if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: abi = '__stdcall' return model.RawFunctionType(tuple(args), result, ellipsis, abi) def _as_func_arg(self, type, quals): if isinstance(type, model.ArrayType): return model.PointerType(type.item, quals) elif isinstance(type, model.RawFunctionType): return type.as_function_pointer() else: return type def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): # First, a level of caching on the exact 'type' node of the AST. # This is obscure, but needed because pycparser "unrolls" declarations # such as "typedef struct { } foo_t, *foo_p" and we end up with # an AST that is not a tree, but a DAG, with the "type" node of the # two branches foo_t and foo_p of the trees being the same node. # It's a bit silly but detecting "DAG-ness" in the AST tree seems # to be the only way to distinguish this case from two independent # structs. See test_struct_with_two_usages. try: return self._structnode2type[type] except KeyError: pass # # Note that this must handle parsing "struct foo" any number of # times and always return the same StructType object. Additionally, # one of these times (not necessarily the first), the fields of # the struct can be specified with "struct foo { ...fields... }". # If no name is given, then we have to create a new anonymous struct # with no caching; in this case, the fields are either specified # right now or never. # force_name = name name = type.name # # get the type or create it if needed if name is None: # 'force_name' is used to guess a more readable name for # anonymous structs, for the common case "typedef struct { } foo". if force_name is not None: explicit_name = '$%s' % force_name else: self._anonymous_counter += 1 explicit_name = '$%d' % self._anonymous_counter tp = None else: explicit_name = name key = '%s %s' % (kind, name) tp, _ = self._declarations.get(key, (None, None)) # if tp is None: if kind == 'struct': tp = model.StructType(explicit_name, None, None, None) elif kind == 'union': tp = model.UnionType(explicit_name, None, None, None) elif kind == 'enum': if explicit_name == '__dotdotdot__': raise CDefError("Enums cannot be declared with ...") tp = self._build_enum_type(explicit_name, type.values) else: raise AssertionError("kind = %r" % (kind,)) if name is not None: self._declare(key, tp) else: if kind == 'enum' and type.values is not None: raise NotImplementedError( "enum %s: the '{}' declaration should appear on the first " "time the enum is mentioned, not later" % explicit_name) if not tp.forcename: tp.force_the_name(force_name) if tp.forcename and '$' in tp.name: self._declare('anonymous %s' % tp.forcename, tp) # self._structnode2type[type] = tp # # enums: done here if kind == 'enum': return tp # # is there a 'type.decls'? If yes, then this is the place in the # C sources that declare the fields. If no, then just return the # existing type, possibly still incomplete. if type.decls is None: return tp # if tp.fldnames is not None: raise CDefError("duplicate declaration of struct %s" % name) fldnames = [] fldtypes = [] fldbitsize = [] fldquals = [] for decl in type.decls: if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and ''.join(decl.type.names) == '__dotdotdot__'): # XXX pycparser is inconsistent: 'names' should be a list # of strings, but is sometimes just one string. Use # str.join() as a way to cope with both. self._make_partial(tp, nested) continue if decl.bitsize is None: bitsize = -1 else: bitsize = self._parse_constant(decl.bitsize) self._partial_length = False type, fqual = self._get_type_and_quals(decl.type, partial_length_ok=True) if self._partial_length: self._make_partial(tp, nested) if isinstance(type, model.StructType) and type.partial: self._make_partial(tp, nested) fldnames.append(decl.name or '') fldtypes.append(type) fldbitsize.append(bitsize) fldquals.append(fqual) tp.fldnames = tuple(fldnames) tp.fldtypes = tuple(fldtypes) tp.fldbitsize = tuple(fldbitsize) tp.fldquals = tuple(fldquals) if fldbitsize != [-1] * len(fldbitsize): if isinstance(tp, model.StructType) and tp.partial: raise NotImplementedError("%s: using both bitfields and '...;'" % (tp,)) tp.packed = self._options.get('packed') if tp.completed: # must be re-completed: it is not opaque any more tp.completed = 0 self._recomplete.append(tp) return tp def _make_partial(self, tp, nested): if not isinstance(tp, model.StructOrUnion): raise CDefError("%s cannot be partial" % (tp,)) if not tp.has_c_name() and not nested: raise NotImplementedError("%s is partial but has no C name" %(tp,)) tp.partial = True def _parse_constant(self, exprnode, partial_length_ok=False): # for now, limited to expressions that are an immediate number # or positive/negative number if isinstance(exprnode, pycparser.c_ast.Constant): s = exprnode.value if s.startswith('0'): if s.startswith('0x') or s.startswith('0X'): return int(s, 16) return int(s, 8) elif '1' <= s[0] <= '9': return int(s, 10) elif s[0] == "'" and s[-1] == "'" and ( len(s) == 3 or (len(s) == 4 and s[1] == "\\")): return ord(s[-2]) else: raise CDefError("invalid constant %r" % (s,)) # if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and exprnode.op == '+'): return self._parse_constant(exprnode.expr) # if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and exprnode.op == '-'): return -self._parse_constant(exprnode.expr) # load previously defined int constant if (isinstance(exprnode, pycparser.c_ast.ID) and exprnode.name in self._int_constants): return self._int_constants[exprnode.name] # if (isinstance(exprnode, pycparser.c_ast.ID) and exprnode.name == '__dotdotdotarray__'): if partial_length_ok: self._partial_length = True return '...' raise FFIError(":%d: unsupported '[...]' here, cannot derive " "the actual array length in this context" % exprnode.coord.line) # if (isinstance(exprnode, pycparser.c_ast.BinaryOp) and exprnode.op == '+'): return (self._parse_constant(exprnode.left) + self._parse_constant(exprnode.right)) # if (isinstance(exprnode, pycparser.c_ast.BinaryOp) and exprnode.op == '-'): return (self._parse_constant(exprnode.left) - self._parse_constant(exprnode.right)) # raise FFIError(":%d: unsupported expression: expected a " "simple numeric constant" % exprnode.coord.line) def _build_enum_type(self, explicit_name, decls): if decls is not None: partial = False enumerators = [] enumvalues = [] nextenumvalue = 0 for enum in decls.enumerators: if _r_enum_dotdotdot.match(enum.name): partial = True continue if enum.value is not None: nextenumvalue = self._parse_constant(enum.value) enumerators.append(enum.name) enumvalues.append(nextenumvalue) self._add_constants(enum.name, nextenumvalue) nextenumvalue += 1 enumerators = tuple(enumerators) enumvalues = tuple(enumvalues) tp = model.EnumType(explicit_name, enumerators, enumvalues) tp.partial = partial else: # opaque enum tp = model.EnumType(explicit_name, (), ()) return tp def include(self, other): for name, (tp, quals) in other._declarations.items(): if name.startswith('anonymous $enum_$'): continue # fix for test_anonymous_enum_include kind = name.split(' ', 1)[0] if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): self._declare(name, tp, included=True, quals=quals) for k, v in other._int_constants.items(): self._add_constants(k, v) def _get_unknown_type(self, decl): typenames = decl.type.type.names if typenames == ['__dotdotdot__']: return model.unknown_type(decl.name) if typenames == ['__dotdotdotint__']: if self._uses_new_feature is None: self._uses_new_feature = "'typedef int... %s'" % decl.name return model.UnknownIntegerType(decl.name) if typenames == ['__dotdotdotfloat__']: # note: not for 'long double' so far if self._uses_new_feature is None: self._uses_new_feature = "'typedef float... %s'" % decl.name return model.UnknownFloatType(decl.name) raise FFIError(':%d: unsupported usage of "..." in typedef' % decl.coord.line) def _get_unknown_ptr_type(self, decl): if decl.type.type.type.names == ['__dotdotdot__']: return model.unknown_ptr_type(decl.name) raise FFIError(':%d: unsupported usage of "..." in typedef' % decl.coord.line) PK %�\�M� � _cffi_errors.hnu �[��� #ifndef CFFI_MESSAGEBOX # ifdef _MSC_VER # define CFFI_MESSAGEBOX 1 # else # define CFFI_MESSAGEBOX 0 # endif #endif #if CFFI_MESSAGEBOX /* Windows only: logic to take the Python-CFFI embedding logic initialization errors and display them in a background thread with MessageBox. The idea is that if the whole program closes as a result of this problem, then likely it is already a console program and you can read the stderr output in the console too. If it is not a console program, then it will likely show its own dialog to complain, or generally not abruptly close, and for this case the background thread should stay alive. */ static void *volatile _cffi_bootstrap_text; static PyObject *_cffi_start_error_capture(void) { PyObject *result = NULL; PyObject *x, *m, *bi; if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, (void *)1, NULL) != NULL) return (PyObject *)1; m = PyImport_AddModule("_cffi_error_capture"); if (m == NULL) goto error; result = PyModule_GetDict(m); if (result == NULL) goto error; #if PY_MAJOR_VERSION >= 3 bi = PyImport_ImportModule("builtins"); #else bi = PyImport_ImportModule("__builtin__"); #endif if (bi == NULL) goto error; PyDict_SetItemString(result, "__builtins__", bi); Py_DECREF(bi); x = PyRun_String( "import sys\n" "class FileLike:\n" " def write(self, x):\n" " of.write(x)\n" " self.buf += x\n" "fl = FileLike()\n" "fl.buf = ''\n" "of = sys.stderr\n" "sys.stderr = fl\n" "def done():\n" " sys.stderr = of\n" " return fl.buf\n", /* make sure the returned value stays alive */ Py_file_input, result, result); Py_XDECREF(x); error: if (PyErr_Occurred()) { PyErr_WriteUnraisable(Py_None); PyErr_Clear(); } return result; } #pragma comment(lib, "user32.lib") static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) { Sleep(666); /* may be interrupted if the whole process is closing */ #if PY_MAJOR_VERSION >= 3 MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, L"Python-CFFI error", MB_OK | MB_ICONERROR); #else MessageBoxA(NULL, (char *)_cffi_bootstrap_text, "Python-CFFI error", MB_OK | MB_ICONERROR); #endif _cffi_bootstrap_text = NULL; return 0; } static void _cffi_stop_error_capture(PyObject *ecap) { PyObject *s; void *text; if (ecap == (PyObject *)1) return; if (ecap == NULL) goto error; s = PyRun_String("done()", Py_eval_input, ecap, ecap); if (s == NULL) goto error; /* Show a dialog box, but in a background thread, and never show multiple dialog boxes at once. */ #if PY_MAJOR_VERSION >= 3 text = PyUnicode_AsWideCharString(s, NULL); #else text = PyString_AsString(s); #endif _cffi_bootstrap_text = text; if (text != NULL) { HANDLE h; h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, NULL, 0, NULL); if (h != NULL) CloseHandle(h); } /* decref the string, but it should stay alive as 'fl.buf' in the small module above. It will really be freed only if we later get another similar error. So it's a leak of at most one copy of the small module. That's fine for this situation which is usually a "fatal error" anyway. */ Py_DECREF(s); PyErr_Clear(); return; error: _cffi_bootstrap_text = NULL; PyErr_Clear(); } #else static PyObject *_cffi_start_error_capture(void) { return NULL; } static void _cffi_stop_error_capture(PyObject *ecap) { } #endif PK %�\ �au/ u/ _cffi_include.hnu �[��� #define _CFFI_ /* We try to define Py_LIMITED_API before including Python.h. Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and Py_REF_DEBUG are not defined. This is a best-effort approximation: we can learn about Py_DEBUG from pyconfig.h, but it is unclear if the same works for the other two macros. Py_DEBUG implies them, but not the other way around. Issue #350 is still open: on Windows, the code here causes it to link with PYTHON36.DLL (for example) instead of PYTHON3.DLL. A fix was attempted in 164e526a5515 and 14ce6985e1c3, but reverted: virtualenv does not make PYTHON3.DLL available, and so the "correctly" compiled version would not run inside a virtualenv. We will re-apply the fix after virtualenv has been fixed for some time. For explanation, see issue #355. For a workaround if you want PYTHON3.DLL and don't worry about virtualenv, see issue #350. See also 'py_limited_api' in setuptools_ext.py. */ #if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) # include <pyconfig.h> # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) # define Py_LIMITED_API # endif #endif #include <Python.h> #ifdef __cplusplus extern "C" { #endif #include <stddef.h> #include "parse_c_type.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 #else # include <stdint.h> # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include <alloca.h> # endif #endif #ifdef __GNUC__ # define _CFFI_UNUSED_FN __attribute__((unused)) #else # define _CFFI_UNUSED_FN /* nothing */ #endif #ifdef __cplusplus # ifndef _Bool typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ # endif #endif /********** CPython-specific section **********/ #ifndef PYPY_VERSION #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(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 *, struct _cffi_ctypedescr *))_cffi_exports[10]) #define _cffi_to_c_pointer \ ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) #define _cffi_get_struct_layout \ not used any more #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 *, struct _cffi_ctypedescr *))_cffi_exports[16]) #define _cffi_to_c \ ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) #define _cffi_from_c_struct \ ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) #define _cffi_to_c_wchar_t \ ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) #define _cffi_from_c_wchar_t \ ((PyObject *(*)(_cffi_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(*)(struct _cffi_ctypedescr *, \ PyObject *, char **))_cffi_exports[23]) #define _cffi_convert_array_from_object \ ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) #define _CFFI_CPIDX 25 #define _cffi_call_python \ ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) #define _cffi_to_c_wchar3216_t \ ((int(*)(PyObject *))_cffi_exports[26]) #define _cffi_from_c_wchar3216_t \ ((PyObject *(*)(int))_cffi_exports[27]) #define _CFFI_NUM_EXPORTS 28 struct _cffi_ctypedescr; static void *_cffi_exports[_CFFI_NUM_EXPORTS]; #define _cffi_type(index) ( \ assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ (struct _cffi_ctypedescr *)_cffi_types[index]) static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, const struct _cffi_type_context_s *ctx) { PyObject *module, *o_arg, *new_module; void *raw[] = { (void *)module_name, (void *)version, (void *)_cffi_exports, (void *)ctx, }; module = PyImport_ImportModule("_cffi_backend"); if (module == NULL) goto failure; o_arg = PyLong_FromVoidPtr((void *)raw); if (o_arg == NULL) goto failure; new_module = PyObject_CallMethod( module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); Py_DECREF(o_arg); Py_DECREF(module); return new_module; failure: Py_XDECREF(module); return NULL; } #ifdef HAVE_WCHAR_H typedef wchar_t _cffi_wchar_t; #else typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ #endif _CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) { if (sizeof(_cffi_wchar_t) == 2) return (uint16_t)_cffi_to_c_wchar_t(o); else return (uint16_t)_cffi_to_c_wchar3216_t(o); } _CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) { if (sizeof(_cffi_wchar_t) == 2) return _cffi_from_c_wchar_t((_cffi_wchar_t)x); else return _cffi_from_c_wchar3216_t((int)x); } _CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) { if (sizeof(_cffi_wchar_t) == 4) return (int)_cffi_to_c_wchar_t(o); else return (int)_cffi_to_c_wchar3216_t(o); } _CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(int x) { if (sizeof(_cffi_wchar_t) == 4) return _cffi_from_c_wchar_t((_cffi_wchar_t)x); else return _cffi_from_c_wchar3216_t(x); } /********** end CPython-specific section **********/ #else _CFFI_UNUSED_FN static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); # define _cffi_call_python _cffi_call_python_org #endif #define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) #define _cffi_prim_int(size, sign) \ ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) #define _cffi_prim_float(size) \ ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ _CFFI__UNKNOWN_FLOAT_PRIM) #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) #ifdef MS_WIN32 # define _cffi_stdcall __stdcall #else # define _cffi_stdcall /* nothing */ #endif #ifdef __cplusplus } #endif PK %�\JЁ�1R 1R &