|
@@ -1,362 +1,362 @@
|
|
|
-/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
|
|
|
-
|
|
|
+/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
|
|
|
+
|
|
|
static void *cdlopen_fetch(PyObject *libname, void *libhandle,
|
|
|
const char *symbol)
|
|
|
-{
|
|
|
- void *address;
|
|
|
-
|
|
|
- if (libhandle == NULL) {
|
|
|
- PyErr_Format(FFIError, "library '%s' has been closed",
|
|
|
- PyText_AS_UTF8(libname));
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- dlerror(); /* clear error condition */
|
|
|
- address = dlsym(libhandle, symbol);
|
|
|
- if (address == NULL) {
|
|
|
- const char *error = dlerror();
|
|
|
- PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s",
|
|
|
- symbol, PyText_AS_UTF8(libname), error);
|
|
|
- }
|
|
|
- return address;
|
|
|
-}
|
|
|
-
|
|
|
-static void cdlopen_close_ignore_errors(void *libhandle)
|
|
|
-{
|
|
|
- if (libhandle != NULL)
|
|
|
- dlclose(libhandle);
|
|
|
-}
|
|
|
-
|
|
|
-static int cdlopen_close(PyObject *libname, void *libhandle)
|
|
|
-{
|
|
|
- if (libhandle != NULL && dlclose(libhandle) != 0) {
|
|
|
- const char *error = dlerror();
|
|
|
- PyErr_Format(FFIError, "closing library '%s': %s",
|
|
|
- PyText_AS_UTF8(libname), error);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
|
|
|
-{
|
|
|
+{
|
|
|
+ void *address;
|
|
|
+
|
|
|
+ if (libhandle == NULL) {
|
|
|
+ PyErr_Format(FFIError, "library '%s' has been closed",
|
|
|
+ PyText_AS_UTF8(libname));
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ dlerror(); /* clear error condition */
|
|
|
+ address = dlsym(libhandle, symbol);
|
|
|
+ if (address == NULL) {
|
|
|
+ const char *error = dlerror();
|
|
|
+ PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s",
|
|
|
+ symbol, PyText_AS_UTF8(libname), error);
|
|
|
+ }
|
|
|
+ return address;
|
|
|
+}
|
|
|
+
|
|
|
+static void cdlopen_close_ignore_errors(void *libhandle)
|
|
|
+{
|
|
|
+ if (libhandle != NULL)
|
|
|
+ dlclose(libhandle);
|
|
|
+}
|
|
|
+
|
|
|
+static int cdlopen_close(PyObject *libname, void *libhandle)
|
|
|
+{
|
|
|
+ if (libhandle != NULL && dlclose(libhandle) != 0) {
|
|
|
+ const char *error = dlerror();
|
|
|
+ PyErr_Format(FFIError, "closing library '%s': %s",
|
|
|
+ PyText_AS_UTF8(libname), error);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
|
|
|
+{
|
|
|
const char *modname;
|
|
|
PyObject *temp, *result = NULL;
|
|
|
- void *handle;
|
|
|
+ void *handle;
|
|
|
int auto_close;
|
|
|
-
|
|
|
+
|
|
|
handle = b_do_dlopen(args, &modname, &temp, &auto_close);
|
|
|
if (handle != NULL)
|
|
|
{
|
|
|
result = (PyObject *)lib_internal_new((FFIObject *)self,
|
|
|
modname, handle, auto_close);
|
|
|
- }
|
|
|
+ }
|
|
|
Py_XDECREF(temp);
|
|
|
return result;
|
|
|
-}
|
|
|
-
|
|
|
-static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
|
|
|
-{
|
|
|
- LibObject *lib;
|
|
|
- void *libhandle;
|
|
|
- if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- libhandle = lib->l_libhandle;
|
|
|
+}
|
|
|
+
|
|
|
+static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
|
|
|
+{
|
|
|
+ LibObject *lib;
|
|
|
+ void *libhandle;
|
|
|
+ if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ libhandle = lib->l_libhandle;
|
|
|
if (libhandle != NULL)
|
|
|
{
|
|
|
lib->l_libhandle = NULL;
|
|
|
-
|
|
|
+
|
|
|
/* Clear the dict to force further accesses to do cdlopen_fetch()
|
|
|
again, and fail because the library was closed. */
|
|
|
PyDict_Clear(lib->l_dict);
|
|
|
|
|
|
if (cdlopen_close(lib->l_libname, libhandle) < 0)
|
|
|
return NULL;
|
|
|
- }
|
|
|
- Py_INCREF(Py_None);
|
|
|
- return Py_None;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static Py_ssize_t cdl_4bytes(char *src)
|
|
|
-{
|
|
|
- /* read 4 bytes in little-endian order; return it as a signed integer */
|
|
|
- signed char *ssrc = (signed char *)src;
|
|
|
- unsigned char *usrc = (unsigned char *)src;
|
|
|
- return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
|
|
|
-}
|
|
|
-
|
|
|
-static _cffi_opcode_t cdl_opcode(char *src)
|
|
|
-{
|
|
|
- return (_cffi_opcode_t)cdl_4bytes(src);
|
|
|
-}
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- unsigned long long value;
|
|
|
- int neg;
|
|
|
-} cdl_intconst_t;
|
|
|
-
|
|
|
-static int _cdl_realize_global_int(struct _cffi_getconst_s *gc)
|
|
|
-{
|
|
|
- /* The 'address' field of 'struct _cffi_global_s' is set to point
|
|
|
- to this function in case ffiobj_init() sees constant integers.
|
|
|
- This fishes around after the 'ctx->globals' array, which is
|
|
|
- initialized to contain another array, this time of
|
|
|
- 'cdl_intconst_t' structures. We get the nth one and it tells
|
|
|
- us what to return.
|
|
|
- */
|
|
|
- cdl_intconst_t *ic;
|
|
|
- ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals);
|
|
|
- ic += gc->gindex;
|
|
|
- gc->value = ic->value;
|
|
|
- return ic->neg;
|
|
|
-}
|
|
|
-
|
|
|
-static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|
|
-{
|
|
|
- FFIObject *ffi;
|
|
|
- static char *keywords[] = {"module_name", "_version", "_types",
|
|
|
- "_globals", "_struct_unions", "_enums",
|
|
|
- "_typenames", "_includes", NULL};
|
|
|
- char *ffiname = "?", *types = NULL, *building = NULL;
|
|
|
- Py_ssize_t version = -1;
|
|
|
- Py_ssize_t types_len = 0;
|
|
|
- PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
|
|
|
- PyObject *typenames = NULL, *includes = NULL;
|
|
|
-
|
|
|
- if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
- "|sns#O!O!O!O!O!:FFI", keywords,
|
|
|
- &ffiname, &version, &types, &types_len,
|
|
|
- &PyTuple_Type, &globals,
|
|
|
- &PyTuple_Type, &struct_unions,
|
|
|
- &PyTuple_Type, &enums,
|
|
|
- &PyTuple_Type, &typenames,
|
|
|
- &PyTuple_Type, &includes))
|
|
|
- return -1;
|
|
|
-
|
|
|
- ffi = (FFIObject *)self;
|
|
|
- if (ffi->ctx_is_nonempty) {
|
|
|
- PyErr_SetString(PyExc_ValueError,
|
|
|
- "cannot call FFI.__init__() more than once");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- ffi->ctx_is_nonempty = 1;
|
|
|
-
|
|
|
- if (version == -1 && types_len == 0)
|
|
|
- return 0;
|
|
|
- if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
|
|
|
- PyErr_Format(PyExc_ImportError,
|
|
|
- "cffi out-of-line Python module '%s' has unknown "
|
|
|
- "version %p", ffiname, (void *)version);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (types_len > 0) {
|
|
|
- /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */
|
|
|
- _cffi_opcode_t *ntypes;
|
|
|
- Py_ssize_t i, n = types_len / 4;
|
|
|
-
|
|
|
- building = PyMem_Malloc(n * sizeof(_cffi_opcode_t));
|
|
|
- if (building == NULL)
|
|
|
- goto error;
|
|
|
- ntypes = (_cffi_opcode_t *)building;
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- ntypes[i] = cdl_opcode(types);
|
|
|
- types += 4;
|
|
|
- }
|
|
|
- ffi->types_builder.ctx.types = ntypes;
|
|
|
- ffi->types_builder.ctx.num_types = n;
|
|
|
- building = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (globals != NULL) {
|
|
|
- /* unpack a tuple alternating strings and ints, each two together
|
|
|
- describing one global_s entry with no specified address or size.
|
|
|
- The int is only used with integer constants. */
|
|
|
- struct _cffi_global_s *nglobs;
|
|
|
- cdl_intconst_t *nintconsts;
|
|
|
- Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
|
|
|
-
|
|
|
- i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t));
|
|
|
- building = PyMem_Malloc(i);
|
|
|
- if (building == NULL)
|
|
|
- goto error;
|
|
|
- memset(building, 0, i);
|
|
|
- nglobs = (struct _cffi_global_s *)building;
|
|
|
- nintconsts = (cdl_intconst_t *)(nglobs + n);
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2));
|
|
|
- nglobs[i].type_op = cdl_opcode(g); g += 4;
|
|
|
- nglobs[i].name = g;
|
|
|
- if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT ||
|
|
|
- _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) {
|
|
|
- PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1);
|
|
|
- nglobs[i].address = &_cdl_realize_global_int;
|
|
|
-#if PY_MAJOR_VERSION < 3
|
|
|
- if (PyInt_Check(o)) {
|
|
|
- nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
|
|
|
- nintconsts[i].value = (long long)PyInt_AS_LONG(o);
|
|
|
- }
|
|
|
- else
|
|
|
-#endif
|
|
|
- {
|
|
|
- nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False,
|
|
|
- Py_LE);
|
|
|
- nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o);
|
|
|
- if (PyErr_Occurred())
|
|
|
- goto error;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- ffi->types_builder.ctx.globals = nglobs;
|
|
|
- ffi->types_builder.ctx.num_globals = n;
|
|
|
- building = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (struct_unions != NULL) {
|
|
|
- /* unpack a tuple of struct/unions, each described as a sub-tuple;
|
|
|
- the item 0 of each sub-tuple describes the struct/union, and
|
|
|
- the items 1..N-1 describe the fields, if any */
|
|
|
- struct _cffi_struct_union_s *nstructs;
|
|
|
- struct _cffi_field_s *nfields;
|
|
|
- Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions);
|
|
|
- Py_ssize_t nf = 0; /* total number of fields */
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1;
|
|
|
- }
|
|
|
- i = (n * sizeof(struct _cffi_struct_union_s) +
|
|
|
- nf * sizeof(struct _cffi_field_s));
|
|
|
- building = PyMem_Malloc(i);
|
|
|
- if (building == NULL)
|
|
|
- goto error;
|
|
|
- memset(building, 0, i);
|
|
|
- nstructs = (struct _cffi_struct_union_s *)building;
|
|
|
- nfields = (struct _cffi_field_s *)(nstructs + n);
|
|
|
- nf = 0;
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */
|
|
|
- PyObject *desc = PyTuple_GET_ITEM(struct_unions, i);
|
|
|
- Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
|
|
|
- char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0));
|
|
|
- /* 's' is the first string, describing the struct/union */
|
|
|
- nstructs[i].type_index = cdl_4bytes(s); s += 4;
|
|
|
- nstructs[i].flags = cdl_4bytes(s); s += 4;
|
|
|
- nstructs[i].name = s;
|
|
|
- if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) {
|
|
|
- nstructs[i].size = (size_t)-1;
|
|
|
- nstructs[i].alignment = -1;
|
|
|
- nstructs[i].first_field_index = -1;
|
|
|
- nstructs[i].num_fields = 0;
|
|
|
- assert(nf1 == 0);
|
|
|
- }
|
|
|
- else {
|
|
|
- nstructs[i].size = (size_t)-2;
|
|
|
- nstructs[i].alignment = -2;
|
|
|
- nstructs[i].first_field_index = nf;
|
|
|
- nstructs[i].num_fields = nf1;
|
|
|
- }
|
|
|
- for (j = 0; j < nf1; j++) {
|
|
|
- char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1));
|
|
|
- /* 'f' is one of the other strings beyond the first one,
|
|
|
- describing one field each */
|
|
|
- nfields[nf].field_type_op = cdl_opcode(f); f += 4;
|
|
|
- nfields[nf].field_offset = (size_t)-1;
|
|
|
- if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) {
|
|
|
- nfields[nf].field_size = cdl_4bytes(f); f += 4;
|
|
|
- }
|
|
|
- else {
|
|
|
- nfields[nf].field_size = (size_t)-1;
|
|
|
- }
|
|
|
- nfields[nf].name = f;
|
|
|
- nf++;
|
|
|
- }
|
|
|
- }
|
|
|
- ffi->types_builder.ctx.struct_unions = nstructs;
|
|
|
- ffi->types_builder.ctx.fields = nfields;
|
|
|
- ffi->types_builder.ctx.num_struct_unions = n;
|
|
|
- building = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (enums != NULL) {
|
|
|
- /* unpack a tuple of strings, each of which describes one enum_s
|
|
|
- entry */
|
|
|
- struct _cffi_enum_s *nenums;
|
|
|
- Py_ssize_t i, n = PyTuple_GET_SIZE(enums);
|
|
|
-
|
|
|
- i = n * sizeof(struct _cffi_enum_s);
|
|
|
- building = PyMem_Malloc(i);
|
|
|
- if (building == NULL)
|
|
|
- goto error;
|
|
|
- memset(building, 0, i);
|
|
|
- nenums = (struct _cffi_enum_s *)building;
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i));
|
|
|
- /* 'e' is a string describing the enum */
|
|
|
- nenums[i].type_index = cdl_4bytes(e); e += 4;
|
|
|
- nenums[i].type_prim = cdl_4bytes(e); e += 4;
|
|
|
- nenums[i].name = e; e += strlen(e) + 1;
|
|
|
- nenums[i].enumerators = e;
|
|
|
- }
|
|
|
- ffi->types_builder.ctx.enums = nenums;
|
|
|
- ffi->types_builder.ctx.num_enums = n;
|
|
|
- building = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (typenames != NULL) {
|
|
|
- /* unpack a tuple of strings, each of which describes one typename_s
|
|
|
- entry */
|
|
|
- struct _cffi_typename_s *ntypenames;
|
|
|
- Py_ssize_t i, n = PyTuple_GET_SIZE(typenames);
|
|
|
-
|
|
|
- i = n * sizeof(struct _cffi_typename_s);
|
|
|
- building = PyMem_Malloc(i);
|
|
|
- if (building == NULL)
|
|
|
- goto error;
|
|
|
- memset(building, 0, i);
|
|
|
- ntypenames = (struct _cffi_typename_s *)building;
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i));
|
|
|
- /* 't' is a string describing the typename */
|
|
|
- ntypenames[i].type_index = cdl_4bytes(t); t += 4;
|
|
|
- ntypenames[i].name = t;
|
|
|
- }
|
|
|
- ffi->types_builder.ctx.typenames = ntypenames;
|
|
|
- ffi->types_builder.ctx.num_typenames = n;
|
|
|
- building = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (includes != NULL) {
|
|
|
- PyObject *included_libs;
|
|
|
-
|
|
|
- included_libs = PyTuple_New(PyTuple_GET_SIZE(includes));
|
|
|
- if (included_libs == NULL)
|
|
|
- return -1;
|
|
|
-
|
|
|
- Py_INCREF(includes);
|
|
|
- ffi->types_builder.included_ffis = includes;
|
|
|
- ffi->types_builder.included_libs = included_libs;
|
|
|
- }
|
|
|
-
|
|
|
- /* Above, we took directly some "char *" strings out of the strings,
|
|
|
- typically from somewhere inside tuples. Keep them alive by
|
|
|
- incref'ing the whole input arguments. */
|
|
|
- Py_INCREF(args);
|
|
|
- Py_XINCREF(kwds);
|
|
|
- ffi->types_builder._keepalive1 = args;
|
|
|
- ffi->types_builder._keepalive2 = kwds;
|
|
|
- return 0;
|
|
|
-
|
|
|
- error:
|
|
|
- if (building != NULL)
|
|
|
- PyMem_Free(building);
|
|
|
- if (!PyErr_Occurred())
|
|
|
- PyErr_NoMemory();
|
|
|
- return -1;
|
|
|
-}
|
|
|
+ }
|
|
|
+ Py_INCREF(Py_None);
|
|
|
+ return Py_None;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static Py_ssize_t cdl_4bytes(char *src)
|
|
|
+{
|
|
|
+ /* read 4 bytes in little-endian order; return it as a signed integer */
|
|
|
+ signed char *ssrc = (signed char *)src;
|
|
|
+ unsigned char *usrc = (unsigned char *)src;
|
|
|
+ return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
|
|
|
+}
|
|
|
+
|
|
|
+static _cffi_opcode_t cdl_opcode(char *src)
|
|
|
+{
|
|
|
+ return (_cffi_opcode_t)cdl_4bytes(src);
|
|
|
+}
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ unsigned long long value;
|
|
|
+ int neg;
|
|
|
+} cdl_intconst_t;
|
|
|
+
|
|
|
+static int _cdl_realize_global_int(struct _cffi_getconst_s *gc)
|
|
|
+{
|
|
|
+ /* The 'address' field of 'struct _cffi_global_s' is set to point
|
|
|
+ to this function in case ffiobj_init() sees constant integers.
|
|
|
+ This fishes around after the 'ctx->globals' array, which is
|
|
|
+ initialized to contain another array, this time of
|
|
|
+ 'cdl_intconst_t' structures. We get the nth one and it tells
|
|
|
+ us what to return.
|
|
|
+ */
|
|
|
+ cdl_intconst_t *ic;
|
|
|
+ ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals);
|
|
|
+ ic += gc->gindex;
|
|
|
+ gc->value = ic->value;
|
|
|
+ return ic->neg;
|
|
|
+}
|
|
|
+
|
|
|
+static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|
|
+{
|
|
|
+ FFIObject *ffi;
|
|
|
+ static char *keywords[] = {"module_name", "_version", "_types",
|
|
|
+ "_globals", "_struct_unions", "_enums",
|
|
|
+ "_typenames", "_includes", NULL};
|
|
|
+ char *ffiname = "?", *types = NULL, *building = NULL;
|
|
|
+ Py_ssize_t version = -1;
|
|
|
+ Py_ssize_t types_len = 0;
|
|
|
+ PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
|
|
|
+ PyObject *typenames = NULL, *includes = NULL;
|
|
|
+
|
|
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
|
|
+ "|sns#O!O!O!O!O!:FFI", keywords,
|
|
|
+ &ffiname, &version, &types, &types_len,
|
|
|
+ &PyTuple_Type, &globals,
|
|
|
+ &PyTuple_Type, &struct_unions,
|
|
|
+ &PyTuple_Type, &enums,
|
|
|
+ &PyTuple_Type, &typenames,
|
|
|
+ &PyTuple_Type, &includes))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ ffi = (FFIObject *)self;
|
|
|
+ if (ffi->ctx_is_nonempty) {
|
|
|
+ PyErr_SetString(PyExc_ValueError,
|
|
|
+ "cannot call FFI.__init__() more than once");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ffi->ctx_is_nonempty = 1;
|
|
|
+
|
|
|
+ if (version == -1 && types_len == 0)
|
|
|
+ return 0;
|
|
|
+ if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
|
|
|
+ PyErr_Format(PyExc_ImportError,
|
|
|
+ "cffi out-of-line Python module '%s' has unknown "
|
|
|
+ "version %p", ffiname, (void *)version);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (types_len > 0) {
|
|
|
+ /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */
|
|
|
+ _cffi_opcode_t *ntypes;
|
|
|
+ Py_ssize_t i, n = types_len / 4;
|
|
|
+
|
|
|
+ building = PyMem_Malloc(n * sizeof(_cffi_opcode_t));
|
|
|
+ if (building == NULL)
|
|
|
+ goto error;
|
|
|
+ ntypes = (_cffi_opcode_t *)building;
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ ntypes[i] = cdl_opcode(types);
|
|
|
+ types += 4;
|
|
|
+ }
|
|
|
+ ffi->types_builder.ctx.types = ntypes;
|
|
|
+ ffi->types_builder.ctx.num_types = n;
|
|
|
+ building = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (globals != NULL) {
|
|
|
+ /* unpack a tuple alternating strings and ints, each two together
|
|
|
+ describing one global_s entry with no specified address or size.
|
|
|
+ The int is only used with integer constants. */
|
|
|
+ struct _cffi_global_s *nglobs;
|
|
|
+ cdl_intconst_t *nintconsts;
|
|
|
+ Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
|
|
|
+
|
|
|
+ i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t));
|
|
|
+ building = PyMem_Malloc(i);
|
|
|
+ if (building == NULL)
|
|
|
+ goto error;
|
|
|
+ memset(building, 0, i);
|
|
|
+ nglobs = (struct _cffi_global_s *)building;
|
|
|
+ nintconsts = (cdl_intconst_t *)(nglobs + n);
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2));
|
|
|
+ nglobs[i].type_op = cdl_opcode(g); g += 4;
|
|
|
+ nglobs[i].name = g;
|
|
|
+ if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT ||
|
|
|
+ _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) {
|
|
|
+ PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1);
|
|
|
+ nglobs[i].address = &_cdl_realize_global_int;
|
|
|
+#if PY_MAJOR_VERSION < 3
|
|
|
+ if (PyInt_Check(o)) {
|
|
|
+ nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
|
|
|
+ nintconsts[i].value = (long long)PyInt_AS_LONG(o);
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False,
|
|
|
+ Py_LE);
|
|
|
+ nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o);
|
|
|
+ if (PyErr_Occurred())
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ffi->types_builder.ctx.globals = nglobs;
|
|
|
+ ffi->types_builder.ctx.num_globals = n;
|
|
|
+ building = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (struct_unions != NULL) {
|
|
|
+ /* unpack a tuple of struct/unions, each described as a sub-tuple;
|
|
|
+ the item 0 of each sub-tuple describes the struct/union, and
|
|
|
+ the items 1..N-1 describe the fields, if any */
|
|
|
+ struct _cffi_struct_union_s *nstructs;
|
|
|
+ struct _cffi_field_s *nfields;
|
|
|
+ Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions);
|
|
|
+ Py_ssize_t nf = 0; /* total number of fields */
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1;
|
|
|
+ }
|
|
|
+ i = (n * sizeof(struct _cffi_struct_union_s) +
|
|
|
+ nf * sizeof(struct _cffi_field_s));
|
|
|
+ building = PyMem_Malloc(i);
|
|
|
+ if (building == NULL)
|
|
|
+ goto error;
|
|
|
+ memset(building, 0, i);
|
|
|
+ nstructs = (struct _cffi_struct_union_s *)building;
|
|
|
+ nfields = (struct _cffi_field_s *)(nstructs + n);
|
|
|
+ nf = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */
|
|
|
+ PyObject *desc = PyTuple_GET_ITEM(struct_unions, i);
|
|
|
+ Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
|
|
|
+ char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0));
|
|
|
+ /* 's' is the first string, describing the struct/union */
|
|
|
+ nstructs[i].type_index = cdl_4bytes(s); s += 4;
|
|
|
+ nstructs[i].flags = cdl_4bytes(s); s += 4;
|
|
|
+ nstructs[i].name = s;
|
|
|
+ if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) {
|
|
|
+ nstructs[i].size = (size_t)-1;
|
|
|
+ nstructs[i].alignment = -1;
|
|
|
+ nstructs[i].first_field_index = -1;
|
|
|
+ nstructs[i].num_fields = 0;
|
|
|
+ assert(nf1 == 0);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ nstructs[i].size = (size_t)-2;
|
|
|
+ nstructs[i].alignment = -2;
|
|
|
+ nstructs[i].first_field_index = nf;
|
|
|
+ nstructs[i].num_fields = nf1;
|
|
|
+ }
|
|
|
+ for (j = 0; j < nf1; j++) {
|
|
|
+ char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1));
|
|
|
+ /* 'f' is one of the other strings beyond the first one,
|
|
|
+ describing one field each */
|
|
|
+ nfields[nf].field_type_op = cdl_opcode(f); f += 4;
|
|
|
+ nfields[nf].field_offset = (size_t)-1;
|
|
|
+ if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) {
|
|
|
+ nfields[nf].field_size = cdl_4bytes(f); f += 4;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ nfields[nf].field_size = (size_t)-1;
|
|
|
+ }
|
|
|
+ nfields[nf].name = f;
|
|
|
+ nf++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ffi->types_builder.ctx.struct_unions = nstructs;
|
|
|
+ ffi->types_builder.ctx.fields = nfields;
|
|
|
+ ffi->types_builder.ctx.num_struct_unions = n;
|
|
|
+ building = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enums != NULL) {
|
|
|
+ /* unpack a tuple of strings, each of which describes one enum_s
|
|
|
+ entry */
|
|
|
+ struct _cffi_enum_s *nenums;
|
|
|
+ Py_ssize_t i, n = PyTuple_GET_SIZE(enums);
|
|
|
+
|
|
|
+ i = n * sizeof(struct _cffi_enum_s);
|
|
|
+ building = PyMem_Malloc(i);
|
|
|
+ if (building == NULL)
|
|
|
+ goto error;
|
|
|
+ memset(building, 0, i);
|
|
|
+ nenums = (struct _cffi_enum_s *)building;
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i));
|
|
|
+ /* 'e' is a string describing the enum */
|
|
|
+ nenums[i].type_index = cdl_4bytes(e); e += 4;
|
|
|
+ nenums[i].type_prim = cdl_4bytes(e); e += 4;
|
|
|
+ nenums[i].name = e; e += strlen(e) + 1;
|
|
|
+ nenums[i].enumerators = e;
|
|
|
+ }
|
|
|
+ ffi->types_builder.ctx.enums = nenums;
|
|
|
+ ffi->types_builder.ctx.num_enums = n;
|
|
|
+ building = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typenames != NULL) {
|
|
|
+ /* unpack a tuple of strings, each of which describes one typename_s
|
|
|
+ entry */
|
|
|
+ struct _cffi_typename_s *ntypenames;
|
|
|
+ Py_ssize_t i, n = PyTuple_GET_SIZE(typenames);
|
|
|
+
|
|
|
+ i = n * sizeof(struct _cffi_typename_s);
|
|
|
+ building = PyMem_Malloc(i);
|
|
|
+ if (building == NULL)
|
|
|
+ goto error;
|
|
|
+ memset(building, 0, i);
|
|
|
+ ntypenames = (struct _cffi_typename_s *)building;
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i));
|
|
|
+ /* 't' is a string describing the typename */
|
|
|
+ ntypenames[i].type_index = cdl_4bytes(t); t += 4;
|
|
|
+ ntypenames[i].name = t;
|
|
|
+ }
|
|
|
+ ffi->types_builder.ctx.typenames = ntypenames;
|
|
|
+ ffi->types_builder.ctx.num_typenames = n;
|
|
|
+ building = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (includes != NULL) {
|
|
|
+ PyObject *included_libs;
|
|
|
+
|
|
|
+ included_libs = PyTuple_New(PyTuple_GET_SIZE(includes));
|
|
|
+ if (included_libs == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ Py_INCREF(includes);
|
|
|
+ ffi->types_builder.included_ffis = includes;
|
|
|
+ ffi->types_builder.included_libs = included_libs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Above, we took directly some "char *" strings out of the strings,
|
|
|
+ typically from somewhere inside tuples. Keep them alive by
|
|
|
+ incref'ing the whole input arguments. */
|
|
|
+ Py_INCREF(args);
|
|
|
+ Py_XINCREF(kwds);
|
|
|
+ ffi->types_builder._keepalive1 = args;
|
|
|
+ ffi->types_builder._keepalive2 = kwds;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ error:
|
|
|
+ if (building != NULL)
|
|
|
+ PyMem_Free(building);
|
|
|
+ if (!PyErr_Occurred())
|
|
|
+ PyErr_NoMemory();
|
|
|
+ return -1;
|
|
|
+}
|