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