github.com/whamcloud/lemur@v0.0.0-20190827193804-4655df8a52af/packaging/ci/lambda/GitPullS3/cffi/vengine_cpy.py (about)

     1  #
     2  # DEPRECATED: implementation for ffi.verify()
     3  #
     4  import sys, imp
     5  from . import model, ffiplatform
     6  
     7  
     8  class VCPythonEngine(object):
     9      _class_key = 'x'
    10      _gen_python_module = True
    11  
    12      def __init__(self, verifier):
    13          self.verifier = verifier
    14          self.ffi = verifier.ffi
    15          self._struct_pending_verification = {}
    16          self._types_of_builtin_functions = {}
    17  
    18      def patch_extension_kwds(self, kwds):
    19          pass
    20  
    21      def find_module(self, module_name, path, so_suffixes):
    22          try:
    23              f, filename, descr = imp.find_module(module_name, path)
    24          except ImportError:
    25              return None
    26          if f is not None:
    27              f.close()
    28          # Note that after a setuptools installation, there are both .py
    29          # and .so files with the same basename.  The code here relies on
    30          # imp.find_module() locating the .so in priority.
    31          if descr[0] not in so_suffixes:
    32              return None
    33          return filename
    34  
    35      def collect_types(self):
    36          self._typesdict = {}
    37          self._generate("collecttype")
    38  
    39      def _prnt(self, what=''):
    40          self._f.write(what + '\n')
    41  
    42      def _gettypenum(self, type):
    43          # a KeyError here is a bug.  please report it! :-)
    44          return self._typesdict[type]
    45  
    46      def _do_collect_type(self, tp):
    47          if ((not isinstance(tp, model.PrimitiveType)
    48               or tp.name == 'long double')
    49                  and tp not in self._typesdict):
    50              num = len(self._typesdict)
    51              self._typesdict[tp] = num
    52  
    53      def write_source_to_f(self):
    54          self.collect_types()
    55          #
    56          # The new module will have a _cffi_setup() function that receives
    57          # objects from the ffi world, and that calls some setup code in
    58          # the module.  This setup code is split in several independent
    59          # functions, e.g. one per constant.  The functions are "chained"
    60          # by ending in a tail call to each other.
    61          #
    62          # This is further split in two chained lists, depending on if we
    63          # can do it at import-time or if we must wait for _cffi_setup() to
    64          # provide us with the <ctype> objects.  This is needed because we
    65          # need the values of the enum constants in order to build the
    66          # <ctype 'enum'> that we may have to pass to _cffi_setup().
    67          #
    68          # The following two 'chained_list_constants' items contains
    69          # the head of these two chained lists, as a string that gives the
    70          # call to do, if any.
    71          self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)']
    72          #
    73          prnt = self._prnt
    74          # first paste some standard set of lines that are mostly '#define'
    75          prnt(cffimod_header)
    76          prnt()
    77          # then paste the C source given by the user, verbatim.
    78          prnt(self.verifier.preamble)
    79          prnt()
    80          #
    81          # call generate_cpy_xxx_decl(), for every xxx found from
    82          # ffi._parser._declarations.  This generates all the functions.
    83          self._generate("decl")
    84          #
    85          # implement the function _cffi_setup_custom() as calling the
    86          # head of the chained list.
    87          self._generate_setup_custom()
    88          prnt()
    89          #
    90          # produce the method table, including the entries for the
    91          # generated Python->C function wrappers, which are done
    92          # by generate_cpy_function_method().
    93          prnt('static PyMethodDef _cffi_methods[] = {')
    94          self._generate("method")
    95          prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},')
    96          prnt('  {NULL, NULL, 0, NULL}    /* Sentinel */')
    97          prnt('};')
    98          prnt()
    99          #
   100          # standard init.
   101          modname = self.verifier.get_module_name()
   102          constants = self._chained_list_constants[False]
   103          prnt('#if PY_MAJOR_VERSION >= 3')
   104          prnt()
   105          prnt('static struct PyModuleDef _cffi_module_def = {')
   106          prnt('  PyModuleDef_HEAD_INIT,')
   107          prnt('  "%s",' % modname)
   108          prnt('  NULL,')
   109          prnt('  -1,')
   110          prnt('  _cffi_methods,')
   111          prnt('  NULL, NULL, NULL, NULL')
   112          prnt('};')
   113          prnt()
   114          prnt('PyMODINIT_FUNC')
   115          prnt('PyInit_%s(void)' % modname)
   116          prnt('{')
   117          prnt('  PyObject *lib;')
   118          prnt('  lib = PyModule_Create(&_cffi_module_def);')
   119          prnt('  if (lib == NULL)')
   120          prnt('    return NULL;')
   121          prnt('  if (%s < 0 || _cffi_init() < 0) {' % (constants,))
   122          prnt('    Py_DECREF(lib);')
   123          prnt('    return NULL;')
   124          prnt('  }')
   125          prnt('  return lib;')
   126          prnt('}')
   127          prnt()
   128          prnt('#else')
   129          prnt()
   130          prnt('PyMODINIT_FUNC')
   131          prnt('init%s(void)' % modname)
   132          prnt('{')
   133          prnt('  PyObject *lib;')
   134          prnt('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
   135          prnt('  if (lib == NULL)')
   136          prnt('    return;')
   137          prnt('  if (%s < 0 || _cffi_init() < 0)' % (constants,))
   138          prnt('    return;')
   139          prnt('  return;')
   140          prnt('}')
   141          prnt()
   142          prnt('#endif')
   143  
   144      def load_library(self, flags=None):
   145          # XXX review all usages of 'self' here!
   146          # import it as a new extension module
   147          imp.acquire_lock()
   148          try:
   149              if hasattr(sys, "getdlopenflags"):
   150                  previous_flags = sys.getdlopenflags()
   151              try:
   152                  if hasattr(sys, "setdlopenflags") and flags is not None:
   153                      sys.setdlopenflags(flags)
   154                  module = imp.load_dynamic(self.verifier.get_module_name(),
   155                                            self.verifier.modulefilename)
   156              except ImportError as e:
   157                  error = "importing %r: %s" % (self.verifier.modulefilename, e)
   158                  raise ffiplatform.VerificationError(error)
   159              finally:
   160                  if hasattr(sys, "setdlopenflags"):
   161                      sys.setdlopenflags(previous_flags)
   162          finally:
   163              imp.release_lock()
   164          #
   165          # call loading_cpy_struct() to get the struct layout inferred by
   166          # the C compiler
   167          self._load(module, 'loading')
   168          #
   169          # the C code will need the <ctype> objects.  Collect them in
   170          # order in a list.
   171          revmapping = dict([(value, key)
   172                             for (key, value) in self._typesdict.items()])
   173          lst = [revmapping[i] for i in range(len(revmapping))]
   174          lst = list(map(self.ffi._get_cached_btype, lst))
   175          #
   176          # build the FFILibrary class and instance and call _cffi_setup().
   177          # this will set up some fields like '_cffi_types', and only then
   178          # it will invoke the chained list of functions that will really
   179          # build (notably) the constant objects, as <cdata> if they are
   180          # pointers, and store them as attributes on the 'library' object.
   181          class FFILibrary(object):
   182              _cffi_python_module = module
   183              _cffi_ffi = self.ffi
   184              _cffi_dir = []
   185              def __dir__(self):
   186                  return FFILibrary._cffi_dir + list(self.__dict__)
   187          library = FFILibrary()
   188          if module._cffi_setup(lst, ffiplatform.VerificationError, library):
   189              import warnings
   190              warnings.warn("reimporting %r might overwrite older definitions"
   191                            % (self.verifier.get_module_name()))
   192          #
   193          # finally, call the loaded_cpy_xxx() functions.  This will perform
   194          # the final adjustments, like copying the Python->C wrapper
   195          # functions from the module to the 'library' object, and setting
   196          # up the FFILibrary class with properties for the global C variables.
   197          self._load(module, 'loaded', library=library)
   198          module._cffi_original_ffi = self.ffi
   199          module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions
   200          return library
   201  
   202      def _get_declarations(self):
   203          lst = [(key, tp) for (key, (tp, qual)) in
   204                                  self.ffi._parser._declarations.items()]
   205          lst.sort()
   206          return lst
   207  
   208      def _generate(self, step_name):
   209          for name, tp in self._get_declarations():
   210              kind, realname = name.split(' ', 1)
   211              try:
   212                  method = getattr(self, '_generate_cpy_%s_%s' % (kind,
   213                                                                  step_name))
   214              except AttributeError:
   215                  raise ffiplatform.VerificationError(
   216                      "not implemented in verify(): %r" % name)
   217              try:
   218                  method(tp, realname)
   219              except Exception as e:
   220                  model.attach_exception_info(e, name)
   221                  raise
   222  
   223      def _load(self, module, step_name, **kwds):
   224          for name, tp in self._get_declarations():
   225              kind, realname = name.split(' ', 1)
   226              method = getattr(self, '_%s_cpy_%s' % (step_name, kind))
   227              try:
   228                  method(tp, realname, module, **kwds)
   229              except Exception as e:
   230                  model.attach_exception_info(e, name)
   231                  raise
   232  
   233      def _generate_nothing(self, tp, name):
   234          pass
   235  
   236      def _loaded_noop(self, tp, name, module, **kwds):
   237          pass
   238  
   239      # ----------
   240  
   241      def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
   242          extraarg = ''
   243          if isinstance(tp, model.PrimitiveType):
   244              if tp.is_integer_type() and tp.name != '_Bool':
   245                  converter = '_cffi_to_c_int'
   246                  extraarg = ', %s' % tp.name
   247              else:
   248                  converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
   249                                                     tp.name.replace(' ', '_'))
   250              errvalue = '-1'
   251          #
   252          elif isinstance(tp, model.PointerType):
   253              self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
   254                                                      tovar, errcode)
   255              return
   256          #
   257          elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
   258              # a struct (not a struct pointer) as a function argument
   259              self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
   260                        % (tovar, self._gettypenum(tp), fromvar))
   261              self._prnt('    %s;' % errcode)
   262              return
   263          #
   264          elif isinstance(tp, model.FunctionPtrType):
   265              converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
   266              extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
   267              errvalue = 'NULL'
   268          #
   269          else:
   270              raise NotImplementedError(tp)
   271          #
   272          self._prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
   273          self._prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
   274              tovar, tp.get_c_name(''), errvalue))
   275          self._prnt('    %s;' % errcode)
   276  
   277      def _extra_local_variables(self, tp, localvars):
   278          if isinstance(tp, model.PointerType):
   279              localvars.add('Py_ssize_t datasize')
   280  
   281      def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
   282          self._prnt('  datasize = _cffi_prepare_pointer_call_argument(')
   283          self._prnt('      _cffi_type(%d), %s, (char **)&%s);' % (
   284              self._gettypenum(tp), fromvar, tovar))
   285          self._prnt('  if (datasize != 0) {')
   286          self._prnt('    if (datasize < 0)')
   287          self._prnt('      %s;' % errcode)
   288          self._prnt('    %s = alloca((size_t)datasize);' % (tovar,))
   289          self._prnt('    memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
   290          self._prnt('    if (_cffi_convert_array_from_object('
   291                     '(char *)%s, _cffi_type(%d), %s) < 0)' % (
   292              tovar, self._gettypenum(tp), fromvar))
   293          self._prnt('      %s;' % errcode)
   294          self._prnt('  }')
   295  
   296      def _convert_expr_from_c(self, tp, var, context):
   297          if isinstance(tp, model.PrimitiveType):
   298              if tp.is_integer_type():
   299                  return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
   300              elif tp.name != 'long double':
   301                  return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
   302              else:
   303                  return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
   304                      var, self._gettypenum(tp))
   305          elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
   306              return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
   307                  var, self._gettypenum(tp))
   308          elif isinstance(tp, model.ArrayType):
   309              return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
   310                  var, self._gettypenum(model.PointerType(tp.item)))
   311          elif isinstance(tp, model.StructType):
   312              if tp.fldnames is None:
   313                  raise TypeError("'%s' is used as %s, but is opaque" % (
   314                      tp._get_c_name(), context))
   315              return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
   316                  var, self._gettypenum(tp))
   317          elif isinstance(tp, model.EnumType):
   318              return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
   319                  var, self._gettypenum(tp))
   320          else:
   321              raise NotImplementedError(tp)
   322  
   323      # ----------
   324      # typedefs: generates no code so far
   325  
   326      _generate_cpy_typedef_collecttype = _generate_nothing
   327      _generate_cpy_typedef_decl   = _generate_nothing
   328      _generate_cpy_typedef_method = _generate_nothing
   329      _loading_cpy_typedef         = _loaded_noop
   330      _loaded_cpy_typedef          = _loaded_noop
   331  
   332      # ----------
   333      # function declarations
   334  
   335      def _generate_cpy_function_collecttype(self, tp, name):
   336          assert isinstance(tp, model.FunctionPtrType)
   337          if tp.ellipsis:
   338              self._do_collect_type(tp)
   339          else:
   340              # don't call _do_collect_type(tp) in this common case,
   341              # otherwise test_autofilled_struct_as_argument fails
   342              for type in tp.args:
   343                  self._do_collect_type(type)
   344              self._do_collect_type(tp.result)
   345  
   346      def _generate_cpy_function_decl(self, tp, name):
   347          assert isinstance(tp, model.FunctionPtrType)
   348          if tp.ellipsis:
   349              # cannot support vararg functions better than this: check for its
   350              # exact type (including the fixed arguments), and build it as a
   351              # constant function pointer (no CPython wrapper)
   352              self._generate_cpy_const(False, name, tp)
   353              return
   354          prnt = self._prnt
   355          numargs = len(tp.args)
   356          if numargs == 0:
   357              argname = 'noarg'
   358          elif numargs == 1:
   359              argname = 'arg0'
   360          else:
   361              argname = 'args'
   362          prnt('static PyObject *')
   363          prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
   364          prnt('{')
   365          #
   366          context = 'argument of %s' % name
   367          for i, type in enumerate(tp.args):
   368              prnt('  %s;' % type.get_c_name(' x%d' % i, context))
   369          #
   370          localvars = set()
   371          for type in tp.args:
   372              self._extra_local_variables(type, localvars)
   373          for decl in localvars:
   374              prnt('  %s;' % (decl,))
   375          #
   376          if not isinstance(tp.result, model.VoidType):
   377              result_code = 'result = '
   378              context = 'result of %s' % name
   379              prnt('  %s;' % tp.result.get_c_name(' result', context))
   380          else:
   381              result_code = ''
   382          #
   383          if len(tp.args) > 1:
   384              rng = range(len(tp.args))
   385              for i in rng:
   386                  prnt('  PyObject *arg%d;' % i)
   387              prnt()
   388              prnt('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
   389                  'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
   390              prnt('    return NULL;')
   391          prnt()
   392          #
   393          for i, type in enumerate(tp.args):
   394              self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
   395                                         'return NULL')
   396              prnt()
   397          #
   398          prnt('  Py_BEGIN_ALLOW_THREADS')
   399          prnt('  _cffi_restore_errno();')
   400          prnt('  { %s%s(%s); }' % (
   401              result_code, name,
   402              ', '.join(['x%d' % i for i in range(len(tp.args))])))
   403          prnt('  _cffi_save_errno();')
   404          prnt('  Py_END_ALLOW_THREADS')
   405          prnt()
   406          #
   407          prnt('  (void)self; /* unused */')
   408          if numargs == 0:
   409              prnt('  (void)noarg; /* unused */')
   410          if result_code:
   411              prnt('  return %s;' %
   412                   self._convert_expr_from_c(tp.result, 'result', 'result type'))
   413          else:
   414              prnt('  Py_INCREF(Py_None);')
   415              prnt('  return Py_None;')
   416          prnt('}')
   417          prnt()
   418  
   419      def _generate_cpy_function_method(self, tp, name):
   420          if tp.ellipsis:
   421              return
   422          numargs = len(tp.args)
   423          if numargs == 0:
   424              meth = 'METH_NOARGS'
   425          elif numargs == 1:
   426              meth = 'METH_O'
   427          else:
   428              meth = 'METH_VARARGS'
   429          self._prnt('  {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth))
   430  
   431      _loading_cpy_function = _loaded_noop
   432  
   433      def _loaded_cpy_function(self, tp, name, module, library):
   434          if tp.ellipsis:
   435              return
   436          func = getattr(module, name)
   437          setattr(library, name, func)
   438          self._types_of_builtin_functions[func] = tp
   439  
   440      # ----------
   441      # named structs
   442  
   443      _generate_cpy_struct_collecttype = _generate_nothing
   444      def _generate_cpy_struct_decl(self, tp, name):
   445          assert name == tp.name
   446          self._generate_struct_or_union_decl(tp, 'struct', name)
   447      def _generate_cpy_struct_method(self, tp, name):
   448          self._generate_struct_or_union_method(tp, 'struct', name)
   449      def _loading_cpy_struct(self, tp, name, module):
   450          self._loading_struct_or_union(tp, 'struct', name, module)
   451      def _loaded_cpy_struct(self, tp, name, module, **kwds):
   452          self._loaded_struct_or_union(tp)
   453  
   454      _generate_cpy_union_collecttype = _generate_nothing
   455      def _generate_cpy_union_decl(self, tp, name):
   456          assert name == tp.name
   457          self._generate_struct_or_union_decl(tp, 'union', name)
   458      def _generate_cpy_union_method(self, tp, name):
   459          self._generate_struct_or_union_method(tp, 'union', name)
   460      def _loading_cpy_union(self, tp, name, module):
   461          self._loading_struct_or_union(tp, 'union', name, module)
   462      def _loaded_cpy_union(self, tp, name, module, **kwds):
   463          self._loaded_struct_or_union(tp)
   464  
   465      def _generate_struct_or_union_decl(self, tp, prefix, name):
   466          if tp.fldnames is None:
   467              return     # nothing to do with opaque structs
   468          checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
   469          layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
   470          cname = ('%s %s' % (prefix, name)).strip()
   471          #
   472          prnt = self._prnt
   473          prnt('static void %s(%s *p)' % (checkfuncname, cname))
   474          prnt('{')
   475          prnt('  /* only to generate compile-time warnings or errors */')
   476          prnt('  (void)p;')
   477          for fname, ftype, fbitsize, fqual in tp.enumfields():
   478              if (isinstance(ftype, model.PrimitiveType)
   479                  and ftype.is_integer_type()) or fbitsize >= 0:
   480                  # accept all integers, but complain on float or double
   481                  prnt('  (void)((p->%s) << 1);' % fname)
   482              else:
   483                  # only accept exactly the type declared.
   484                  try:
   485                      prnt('  { %s = &p->%s; (void)tmp; }' % (
   486                          ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
   487                          fname))
   488                  except ffiplatform.VerificationError as e:
   489                      prnt('  /* %s */' % str(e))   # cannot verify it, ignore
   490          prnt('}')
   491          prnt('static PyObject *')
   492          prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
   493          prnt('{')
   494          prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
   495          prnt('  static Py_ssize_t nums[] = {')
   496          prnt('    sizeof(%s),' % cname)
   497          prnt('    offsetof(struct _cffi_aligncheck, y),')
   498          for fname, ftype, fbitsize, fqual in tp.enumfields():
   499              if fbitsize >= 0:
   500                  continue      # xxx ignore fbitsize for now
   501              prnt('    offsetof(%s, %s),' % (cname, fname))
   502              if isinstance(ftype, model.ArrayType) and ftype.length is None:
   503                  prnt('    0,  /* %s */' % ftype._get_c_name())
   504              else:
   505                  prnt('    sizeof(((%s *)0)->%s),' % (cname, fname))
   506          prnt('    -1')
   507          prnt('  };')
   508          prnt('  (void)self; /* unused */')
   509          prnt('  (void)noarg; /* unused */')
   510          prnt('  return _cffi_get_struct_layout(nums);')
   511          prnt('  /* the next line is not executed, but compiled */')
   512          prnt('  %s(0);' % (checkfuncname,))
   513          prnt('}')
   514          prnt()
   515  
   516      def _generate_struct_or_union_method(self, tp, prefix, name):
   517          if tp.fldnames is None:
   518              return     # nothing to do with opaque structs
   519          layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
   520          self._prnt('  {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname,
   521                                                           layoutfuncname))
   522  
   523      def _loading_struct_or_union(self, tp, prefix, name, module):
   524          if tp.fldnames is None:
   525              return     # nothing to do with opaque structs
   526          layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
   527          #
   528          function = getattr(module, layoutfuncname)
   529          layout = function()
   530          if isinstance(tp, model.StructOrUnion) and tp.partial:
   531              # use the function()'s sizes and offsets to guide the
   532              # layout of the struct
   533              totalsize = layout[0]
   534              totalalignment = layout[1]
   535              fieldofs = layout[2::2]
   536              fieldsize = layout[3::2]
   537              tp.force_flatten()
   538              assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
   539              tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
   540          else:
   541              cname = ('%s %s' % (prefix, name)).strip()
   542              self._struct_pending_verification[tp] = layout, cname
   543  
   544      def _loaded_struct_or_union(self, tp):
   545          if tp.fldnames is None:
   546              return     # nothing to do with opaque structs
   547          self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered
   548  
   549          if tp in self._struct_pending_verification:
   550              # check that the layout sizes and offsets match the real ones
   551              def check(realvalue, expectedvalue, msg):
   552                  if realvalue != expectedvalue:
   553                      raise ffiplatform.VerificationError(
   554                          "%s (we have %d, but C compiler says %d)"
   555                          % (msg, expectedvalue, realvalue))
   556              ffi = self.ffi
   557              BStruct = ffi._get_cached_btype(tp)
   558              layout, cname = self._struct_pending_verification.pop(tp)
   559              check(layout[0], ffi.sizeof(BStruct), "wrong total size")
   560              check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
   561              i = 2
   562              for fname, ftype, fbitsize, fqual in tp.enumfields():
   563                  if fbitsize >= 0:
   564                      continue        # xxx ignore fbitsize for now
   565                  check(layout[i], ffi.offsetof(BStruct, fname),
   566                        "wrong offset for field %r" % (fname,))
   567                  if layout[i+1] != 0:
   568                      BField = ffi._get_cached_btype(ftype)
   569                      check(layout[i+1], ffi.sizeof(BField),
   570                            "wrong size for field %r" % (fname,))
   571                  i += 2
   572              assert i == len(layout)
   573  
   574      # ----------
   575      # 'anonymous' declarations.  These are produced for anonymous structs
   576      # or unions; the 'name' is obtained by a typedef.
   577  
   578      _generate_cpy_anonymous_collecttype = _generate_nothing
   579  
   580      def _generate_cpy_anonymous_decl(self, tp, name):
   581          if isinstance(tp, model.EnumType):
   582              self._generate_cpy_enum_decl(tp, name, '')
   583          else:
   584              self._generate_struct_or_union_decl(tp, '', name)
   585  
   586      def _generate_cpy_anonymous_method(self, tp, name):
   587          if not isinstance(tp, model.EnumType):
   588              self._generate_struct_or_union_method(tp, '', name)
   589  
   590      def _loading_cpy_anonymous(self, tp, name, module):
   591          if isinstance(tp, model.EnumType):
   592              self._loading_cpy_enum(tp, name, module)
   593          else:
   594              self._loading_struct_or_union(tp, '', name, module)
   595  
   596      def _loaded_cpy_anonymous(self, tp, name, module, **kwds):
   597          if isinstance(tp, model.EnumType):
   598              self._loaded_cpy_enum(tp, name, module, **kwds)
   599          else:
   600              self._loaded_struct_or_union(tp)
   601  
   602      # ----------
   603      # constants, likely declared with '#define'
   604  
   605      def _generate_cpy_const(self, is_int, name, tp=None, category='const',
   606                              vartp=None, delayed=True, size_too=False,
   607                              check_value=None):
   608          prnt = self._prnt
   609          funcname = '_cffi_%s_%s' % (category, name)
   610          prnt('static int %s(PyObject *lib)' % funcname)
   611          prnt('{')
   612          prnt('  PyObject *o;')
   613          prnt('  int res;')
   614          if not is_int:
   615              prnt('  %s;' % (vartp or tp).get_c_name(' i', name))
   616          else:
   617              assert category == 'const'
   618          #
   619          if check_value is not None:
   620              self._check_int_constant_value(name, check_value)
   621          #
   622          if not is_int:
   623              if category == 'var':
   624                  realexpr = '&' + name
   625              else:
   626                  realexpr = name
   627              prnt('  i = (%s);' % (realexpr,))
   628              prnt('  o = %s;' % (self._convert_expr_from_c(tp, 'i',
   629                                                            'variable type'),))
   630              assert delayed
   631          else:
   632              prnt('  o = _cffi_from_c_int_const(%s);' % name)
   633          prnt('  if (o == NULL)')
   634          prnt('    return -1;')
   635          if size_too:
   636              prnt('  {')
   637              prnt('    PyObject *o1 = o;')
   638              prnt('    o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));'
   639                   % (name,))
   640              prnt('    Py_DECREF(o1);')
   641              prnt('    if (o == NULL)')
   642              prnt('      return -1;')
   643              prnt('  }')
   644          prnt('  res = PyObject_SetAttrString(lib, "%s", o);' % name)
   645          prnt('  Py_DECREF(o);')
   646          prnt('  if (res < 0)')
   647          prnt('    return -1;')
   648          prnt('  return %s;' % self._chained_list_constants[delayed])
   649          self._chained_list_constants[delayed] = funcname + '(lib)'
   650          prnt('}')
   651          prnt()
   652  
   653      def _generate_cpy_constant_collecttype(self, tp, name):
   654          is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
   655          if not is_int:
   656              self._do_collect_type(tp)
   657  
   658      def _generate_cpy_constant_decl(self, tp, name):
   659          is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
   660          self._generate_cpy_const(is_int, name, tp)
   661  
   662      _generate_cpy_constant_method = _generate_nothing
   663      _loading_cpy_constant = _loaded_noop
   664      _loaded_cpy_constant  = _loaded_noop
   665  
   666      # ----------
   667      # enums
   668  
   669      def _check_int_constant_value(self, name, value, err_prefix=''):
   670          prnt = self._prnt
   671          if value <= 0:
   672              prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
   673                  name, name, value))
   674          else:
   675              prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
   676                  name, name, value))
   677          prnt('    char buf[64];')
   678          prnt('    if ((%s) <= 0)' % name)
   679          prnt('        snprintf(buf, 63, "%%ld", (long)(%s));' % name)
   680          prnt('    else')
   681          prnt('        snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
   682               name)
   683          prnt('    PyErr_Format(_cffi_VerificationError,')
   684          prnt('                 "%s%s has the real value %s, not %s",')
   685          prnt('                 "%s", "%s", buf, "%d");' % (
   686              err_prefix, name, value))
   687          prnt('    return -1;')
   688          prnt('  }')
   689  
   690      def _enum_funcname(self, prefix, name):
   691          # "$enum_$1" => "___D_enum____D_1"
   692          name = name.replace('$', '___D_')
   693          return '_cffi_e_%s_%s' % (prefix, name)
   694  
   695      def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
   696          if tp.partial:
   697              for enumerator in tp.enumerators:
   698                  self._generate_cpy_const(True, enumerator, delayed=False)
   699              return
   700          #
   701          funcname = self._enum_funcname(prefix, name)
   702          prnt = self._prnt
   703          prnt('static int %s(PyObject *lib)' % funcname)
   704          prnt('{')
   705          for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
   706              self._check_int_constant_value(enumerator, enumvalue,
   707                                             "enum %s: " % name)
   708          prnt('  return %s;' % self._chained_list_constants[True])
   709          self._chained_list_constants[True] = funcname + '(lib)'
   710          prnt('}')
   711          prnt()
   712  
   713      _generate_cpy_enum_collecttype = _generate_nothing
   714      _generate_cpy_enum_method = _generate_nothing
   715  
   716      def _loading_cpy_enum(self, tp, name, module):
   717          if tp.partial:
   718              enumvalues = [getattr(module, enumerator)
   719                            for enumerator in tp.enumerators]
   720              tp.enumvalues = tuple(enumvalues)
   721              tp.partial_resolved = True
   722  
   723      def _loaded_cpy_enum(self, tp, name, module, library):
   724          for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
   725              setattr(library, enumerator, enumvalue)
   726  
   727      # ----------
   728      # macros: for now only for integers
   729  
   730      def _generate_cpy_macro_decl(self, tp, name):
   731          if tp == '...':
   732              check_value = None
   733          else:
   734              check_value = tp     # an integer
   735          self._generate_cpy_const(True, name, check_value=check_value)
   736  
   737      _generate_cpy_macro_collecttype = _generate_nothing
   738      _generate_cpy_macro_method = _generate_nothing
   739      _loading_cpy_macro = _loaded_noop
   740      _loaded_cpy_macro  = _loaded_noop
   741  
   742      # ----------
   743      # global variables
   744  
   745      def _generate_cpy_variable_collecttype(self, tp, name):
   746          if isinstance(tp, model.ArrayType):
   747              tp_ptr = model.PointerType(tp.item)
   748          else:
   749              tp_ptr = model.PointerType(tp)
   750          self._do_collect_type(tp_ptr)
   751  
   752      def _generate_cpy_variable_decl(self, tp, name):
   753          if isinstance(tp, model.ArrayType):
   754              tp_ptr = model.PointerType(tp.item)
   755              self._generate_cpy_const(False, name, tp, vartp=tp_ptr,
   756                                       size_too = (tp.length == '...'))
   757          else:
   758              tp_ptr = model.PointerType(tp)
   759              self._generate_cpy_const(False, name, tp_ptr, category='var')
   760  
   761      _generate_cpy_variable_method = _generate_nothing
   762      _loading_cpy_variable = _loaded_noop
   763  
   764      def _loaded_cpy_variable(self, tp, name, module, library):
   765          value = getattr(library, name)
   766          if isinstance(tp, model.ArrayType):   # int a[5] is "constant" in the
   767                                                # sense that "a=..." is forbidden
   768              if tp.length == '...':
   769                  assert isinstance(value, tuple)
   770                  (value, size) = value
   771                  BItemType = self.ffi._get_cached_btype(tp.item)
   772                  length, rest = divmod(size, self.ffi.sizeof(BItemType))
   773                  if rest != 0:
   774                      raise ffiplatform.VerificationError(
   775                          "bad size: %r does not seem to be an array of %s" %
   776                          (name, tp.item))
   777                  tp = tp.resolve_length(length)
   778              # 'value' is a <cdata 'type *'> which we have to replace with
   779              # a <cdata 'type[N]'> if the N is actually known
   780              if tp.length is not None:
   781                  BArray = self.ffi._get_cached_btype(tp)
   782                  value = self.ffi.cast(BArray, value)
   783                  setattr(library, name, value)
   784              return
   785          # remove ptr=<cdata 'int *'> from the library instance, and replace
   786          # it by a property on the class, which reads/writes into ptr[0].
   787          ptr = value
   788          delattr(library, name)
   789          def getter(library):
   790              return ptr[0]
   791          def setter(library, value):
   792              ptr[0] = value
   793          setattr(type(library), name, property(getter, setter))
   794          type(library)._cffi_dir.append(name)
   795  
   796      # ----------
   797  
   798      def _generate_setup_custom(self):
   799          prnt = self._prnt
   800          prnt('static int _cffi_setup_custom(PyObject *lib)')
   801          prnt('{')
   802          prnt('  return %s;' % self._chained_list_constants[True])
   803          prnt('}')
   804  
   805  cffimod_header = r'''
   806  #include <Python.h>
   807  #include <stddef.h>
   808  
   809  /* this block of #ifs should be kept exactly identical between
   810     c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
   811  #if defined(_MSC_VER)
   812  # include <malloc.h>   /* for alloca() */
   813  # if _MSC_VER < 1600   /* MSVC < 2010 */
   814     typedef __int8 int8_t;
   815     typedef __int16 int16_t;
   816     typedef __int32 int32_t;
   817     typedef __int64 int64_t;
   818     typedef unsigned __int8 uint8_t;
   819     typedef unsigned __int16 uint16_t;
   820     typedef unsigned __int32 uint32_t;
   821     typedef unsigned __int64 uint64_t;
   822     typedef __int8 int_least8_t;
   823     typedef __int16 int_least16_t;
   824     typedef __int32 int_least32_t;
   825     typedef __int64 int_least64_t;
   826     typedef unsigned __int8 uint_least8_t;
   827     typedef unsigned __int16 uint_least16_t;
   828     typedef unsigned __int32 uint_least32_t;
   829     typedef unsigned __int64 uint_least64_t;
   830     typedef __int8 int_fast8_t;
   831     typedef __int16 int_fast16_t;
   832     typedef __int32 int_fast32_t;
   833     typedef __int64 int_fast64_t;
   834     typedef unsigned __int8 uint_fast8_t;
   835     typedef unsigned __int16 uint_fast16_t;
   836     typedef unsigned __int32 uint_fast32_t;
   837     typedef unsigned __int64 uint_fast64_t;
   838     typedef __int64 intmax_t;
   839     typedef unsigned __int64 uintmax_t;
   840  # else
   841  #  include <stdint.h>
   842  # endif
   843  # if _MSC_VER < 1800   /* MSVC < 2013 */
   844     typedef unsigned char _Bool;
   845  # endif
   846  #else
   847  # include <stdint.h>
   848  # if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
   849  #  include <alloca.h>
   850  # endif
   851  #endif
   852  
   853  #if PY_MAJOR_VERSION < 3
   854  # undef PyCapsule_CheckExact
   855  # undef PyCapsule_GetPointer
   856  # define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
   857  # define PyCapsule_GetPointer(capsule, name) \
   858      (PyCObject_AsVoidPtr(capsule))
   859  #endif
   860  
   861  #if PY_MAJOR_VERSION >= 3
   862  # define PyInt_FromLong PyLong_FromLong
   863  #endif
   864  
   865  #define _cffi_from_c_double PyFloat_FromDouble
   866  #define _cffi_from_c_float PyFloat_FromDouble
   867  #define _cffi_from_c_long PyInt_FromLong
   868  #define _cffi_from_c_ulong PyLong_FromUnsignedLong
   869  #define _cffi_from_c_longlong PyLong_FromLongLong
   870  #define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
   871  
   872  #define _cffi_to_c_double PyFloat_AsDouble
   873  #define _cffi_to_c_float PyFloat_AsDouble
   874  
   875  #define _cffi_from_c_int_const(x)                                        \
   876      (((x) > 0) ?                                                         \
   877          ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ?      \
   878              PyInt_FromLong((long)(x)) :                                  \
   879              PyLong_FromUnsignedLongLong((unsigned long long)(x)) :       \
   880          ((long long)(x) >= (long long)LONG_MIN) ?                        \
   881              PyInt_FromLong((long)(x)) :                                  \
   882              PyLong_FromLongLong((long long)(x)))
   883  
   884  #define _cffi_from_c_int(x, type)                                        \
   885      (((type)-1) > 0 ? /* unsigned */                                     \
   886          (sizeof(type) < sizeof(long) ?                                   \
   887              PyInt_FromLong((long)x) :                                    \
   888           sizeof(type) == sizeof(long) ?                                  \
   889              PyLong_FromUnsignedLong((unsigned long)x) :                  \
   890              PyLong_FromUnsignedLongLong((unsigned long long)x)) :        \
   891          (sizeof(type) <= sizeof(long) ?                                  \
   892              PyInt_FromLong((long)x) :                                    \
   893              PyLong_FromLongLong((long long)x)))
   894  
   895  #define _cffi_to_c_int(o, type)                                          \
   896      ((type)(                                                             \
   897       sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o)        \
   898                                           : (type)_cffi_to_c_i8(o)) :     \
   899       sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o)       \
   900                                           : (type)_cffi_to_c_i16(o)) :    \
   901       sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o)       \
   902                                           : (type)_cffi_to_c_i32(o)) :    \
   903       sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o)       \
   904                                           : (type)_cffi_to_c_i64(o)) :    \
   905       (Py_FatalError("unsupported size for type " #type), (type)0)))
   906  
   907  #define _cffi_to_c_i8                                                    \
   908                   ((int(*)(PyObject *))_cffi_exports[1])
   909  #define _cffi_to_c_u8                                                    \
   910                   ((int(*)(PyObject *))_cffi_exports[2])
   911  #define _cffi_to_c_i16                                                   \
   912                   ((int(*)(PyObject *))_cffi_exports[3])
   913  #define _cffi_to_c_u16                                                   \
   914                   ((int(*)(PyObject *))_cffi_exports[4])
   915  #define _cffi_to_c_i32                                                   \
   916                   ((int(*)(PyObject *))_cffi_exports[5])
   917  #define _cffi_to_c_u32                                                   \
   918                   ((unsigned int(*)(PyObject *))_cffi_exports[6])
   919  #define _cffi_to_c_i64                                                   \
   920                   ((long long(*)(PyObject *))_cffi_exports[7])
   921  #define _cffi_to_c_u64                                                   \
   922                   ((unsigned long long(*)(PyObject *))_cffi_exports[8])
   923  #define _cffi_to_c_char                                                  \
   924                   ((int(*)(PyObject *))_cffi_exports[9])
   925  #define _cffi_from_c_pointer                                             \
   926      ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
   927  #define _cffi_to_c_pointer                                               \
   928      ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
   929  #define _cffi_get_struct_layout                                          \
   930      ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
   931  #define _cffi_restore_errno                                              \
   932      ((void(*)(void))_cffi_exports[13])
   933  #define _cffi_save_errno                                                 \
   934      ((void(*)(void))_cffi_exports[14])
   935  #define _cffi_from_c_char                                                \
   936      ((PyObject *(*)(char))_cffi_exports[15])
   937  #define _cffi_from_c_deref                                               \
   938      ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
   939  #define _cffi_to_c                                                       \
   940      ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
   941  #define _cffi_from_c_struct                                              \
   942      ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
   943  #define _cffi_to_c_wchar_t                                               \
   944      ((wchar_t(*)(PyObject *))_cffi_exports[19])
   945  #define _cffi_from_c_wchar_t                                             \
   946      ((PyObject *(*)(wchar_t))_cffi_exports[20])
   947  #define _cffi_to_c_long_double                                           \
   948      ((long double(*)(PyObject *))_cffi_exports[21])
   949  #define _cffi_to_c__Bool                                                 \
   950      ((_Bool(*)(PyObject *))_cffi_exports[22])
   951  #define _cffi_prepare_pointer_call_argument                              \
   952      ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
   953  #define _cffi_convert_array_from_object                                  \
   954      ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
   955  #define _CFFI_NUM_EXPORTS 25
   956  
   957  typedef struct _ctypedescr CTypeDescrObject;
   958  
   959  static void *_cffi_exports[_CFFI_NUM_EXPORTS];
   960  static PyObject *_cffi_types, *_cffi_VerificationError;
   961  
   962  static int _cffi_setup_custom(PyObject *lib);   /* forward */
   963  
   964  static PyObject *_cffi_setup(PyObject *self, PyObject *args)
   965  {
   966      PyObject *library;
   967      int was_alive = (_cffi_types != NULL);
   968      (void)self; /* unused */
   969      if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
   970                                         &library))
   971          return NULL;
   972      Py_INCREF(_cffi_types);
   973      Py_INCREF(_cffi_VerificationError);
   974      if (_cffi_setup_custom(library) < 0)
   975          return NULL;
   976      return PyBool_FromLong(was_alive);
   977  }
   978  
   979  static int _cffi_init(void)
   980  {
   981      PyObject *module, *c_api_object = NULL;
   982  
   983      module = PyImport_ImportModule("_cffi_backend");
   984      if (module == NULL)
   985          goto failure;
   986  
   987      c_api_object = PyObject_GetAttrString(module, "_C_API");
   988      if (c_api_object == NULL)
   989          goto failure;
   990      if (!PyCapsule_CheckExact(c_api_object)) {
   991          PyErr_SetNone(PyExc_ImportError);
   992          goto failure;
   993      }
   994      memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
   995             _CFFI_NUM_EXPORTS * sizeof(void *));
   996  
   997      Py_DECREF(module);
   998      Py_DECREF(c_api_object);
   999      return 0;
  1000  
  1001    failure:
  1002      Py_XDECREF(module);
  1003      Py_XDECREF(c_api_object);
  1004      return -1;
  1005  }
  1006  
  1007  #define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
  1008  
  1009  /**********/
  1010  '''