Author: Armin Rigo <[email protected]>
Branch:
Changeset: r2049:c870763046a6
Date: 2015-05-18 18:22 +0200
http://bitbucket.org/cffi/cffi/changeset/c870763046a6/
Log: hg merge cffi-1.0
diff too long, truncating to 2000 out of 19486 lines
diff --git a/MANIFEST.in b/MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,6 @@
-recursive-include cffi *.py
+recursive-include cffi *.py *.h
recursive-include c *.c *.h *.asm *.py win64.obj
recursive-include testing *.py
recursive-include doc *.py *.rst Makefile *.bat
-recursive-include demo py.cleanup *.py
-include LICENSE setup_base.py
+recursive-include demo py.cleanup *.py manual.c
+include AUTHORS LICENSE setup.py setup_base.py
diff --git a/TODO b/TODO
deleted file mode 100644
--- a/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-Add other required types from stdint.h
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -72,6 +72,7 @@
# define PyText_FromString PyUnicode_FromString
# define PyText_FromStringAndSize PyUnicode_FromStringAndSize
# define PyText_InternInPlace PyUnicode_InternInPlace
+# define PyText_InternFromString PyUnicode_InternFromString
# define PyIntOrLong_Check PyLong_Check
#else
# define STR_OR_BYTES "str"
@@ -85,6 +86,7 @@
# define PyText_FromString PyString_FromString
# define PyText_FromStringAndSize PyString_FromStringAndSize
# define PyText_InternInPlace PyString_InternInPlace
+# define PyText_InternFromString PyString_InternFromString
# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op))
#endif
@@ -92,6 +94,7 @@
# define PyInt_FromLong PyLong_FromLong
# define PyInt_FromSsize_t PyLong_FromSsize_t
# define PyInt_AsSsize_t PyLong_AsSsize_t
+# define PyInt_AsLong PyLong_AsLong
#endif
#if PY_MAJOR_VERSION >= 3
@@ -131,6 +134,7 @@
#define CT_IS_VOID_PTR 524288
#define CT_WITH_VAR_ARRAY 1048576
#define CT_IS_UNSIZED_CHAR_A 2097152
+#define CT_LAZY_FIELD_LIST 4194304
#define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \
CT_PRIMITIVE_UNSIGNED | \
CT_PRIMITIVE_CHAR | \
@@ -270,6 +274,8 @@
# include "wchar_helper.h"
#endif
+static PyObject *FFIError;
+
/************************************************************/
static CTypeDescrObject *
@@ -420,12 +426,21 @@
static PyObject *
get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */
+#define force_lazy_struct(ct) \
+ ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct))
+
+static int do_realize_lazy_struct(CTypeDescrObject *ct);
+/* forward, implemented in realize_c_type.c */
+
static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context)
{
if (ct->ct_flags & (CT_STRUCT | CT_UNION)) {
if (!(ct->ct_flags & CT_IS_OPAQUE)) {
CFieldObject *cf;
- PyObject *res = PyList_New(0);
+ PyObject *res;
+ if (force_lazy_struct(ct) < 0)
+ return NULL;
+ res = PyList_New(0);
if (res == NULL)
return NULL;
for (cf = (CFieldObject *)ct->ct_extra;
@@ -1217,6 +1232,9 @@
{
const char *expected;
+ if (force_lazy_struct(ct) < 0)
+ return -1;
+
if (ct->ct_flags & CT_UNION) {
Py_ssize_t n = PyObject_Size(init);
if (n < 0)
@@ -1478,6 +1496,10 @@
if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) &&
!(ct->ct_flags & CT_IS_OPAQUE)) {
align = ct->ct_length;
+ if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) {
+ force_lazy_struct(ct);
+ align = ct->ct_length;
+ }
}
else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) {
struct aligncheck_ptr { char x; char *y; };
@@ -1903,7 +1925,7 @@
}
static PyObject *
-new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj); /* forward */
+new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length); /* forward */
static CTypeDescrObject *
_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[])
@@ -1968,7 +1990,7 @@
return NULL;
if (ct->ct_stuff == NULL) {
- ct->ct_stuff = new_array_type(ct, Py_None);
+ ct->ct_stuff = new_array_type(ct, -1);
if (ct->ct_stuff == NULL)
return NULL;
}
@@ -2220,18 +2242,26 @@
if (ct->ct_flags & CT_POINTER)
ct = ct->ct_itemdescr;
- if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
- cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
- if (cf != NULL) {
- /* read the field 'cf' */
- char *data = cd->c_data + cf->cf_offset;
- if (cf->cf_bitshift == BS_REGULAR)
- return convert_to_object(data, cf->cf_type);
- else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
- return new_simple_cdata(data,
- (CTypeDescrObject *)cf->cf_type->ct_stuff);
- else
- return convert_to_object_bitfield(data, cf);
+ if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+ switch (force_lazy_struct(ct)) {
+ case 1:
+ cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+ if (cf != NULL) {
+ /* read the field 'cf' */
+ char *data = cd->c_data + cf->cf_offset;
+ if (cf->cf_bitshift == BS_REGULAR)
+ return convert_to_object(data, cf->cf_type);
+ else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
+ return new_simple_cdata(data,
+ (CTypeDescrObject *)cf->cf_type->ct_stuff);
+ else
+ return convert_to_object_bitfield(data, cf);
+ }
+ break;
+ case -1:
+ return NULL;
+ default:
+ break;
}
}
return PyObject_GenericGetAttr((PyObject *)cd, attr);
@@ -2246,18 +2276,26 @@
if (ct->ct_flags & CT_POINTER)
ct = ct->ct_itemdescr;
- if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
- cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
- if (cf != NULL) {
- /* write the field 'cf' */
- if (value != NULL) {
- return convert_field_from_object(cd->c_data, cf, value);
+ if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+ switch (force_lazy_struct(ct)) {
+ case 1:
+ cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+ if (cf != NULL) {
+ /* write the field 'cf' */
+ if (value != NULL) {
+ return convert_field_from_object(cd->c_data, cf, value);
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError,
+ "cannot delete struct field");
+ return -1;
+ }
}
- else {
- PyErr_SetString(PyExc_AttributeError,
- "cannot delete struct field");
- return -1;
- }
+ break;
+ case -1:
+ return -1;
+ default:
+ break;
}
}
return PyObject_GenericSetAttr((PyObject *)cd, attr, value);
@@ -2269,18 +2307,13 @@
static cif_description_t *
fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, ffi_abi); /*forward*/
-static PyObject *
-b_new_primitive_type(PyObject *self, PyObject *args); /*forward*/
+static PyObject *new_primitive_type(const char *name); /*forward*/
static CTypeDescrObject *_get_ct_int(void)
{
static CTypeDescrObject *ct_int = NULL;
if (ct_int == NULL) {
- PyObject *args = Py_BuildValue("(s)", "int");
- if (args == NULL)
- return NULL;
- ct_int = (CTypeDescrObject *)b_new_primitive_type(NULL, args);
- Py_DECREF(args);
+ ct_int = (CTypeDescrObject *)new_primitive_type("int");
}
return ct_int;
}
@@ -2801,14 +2834,11 @@
return (PyObject *)cd;
}
-static PyObject *b_newp(PyObject *self, PyObject *args)
-{
- CTypeDescrObject *ct, *ctitem;
+static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init)
+{
+ CTypeDescrObject *ctitem;
CDataObject *cd;
- PyObject *init = Py_None;
Py_ssize_t dataoffset, datasize, explicitlength;
- if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
- return NULL;
explicitlength = -1;
if (ct->ct_flags & CT_POINTER) {
@@ -2824,11 +2854,16 @@
if (ctitem->ct_flags & CT_PRIMITIVE_CHAR)
datasize *= 2; /* forcefully add another character: a null */
- if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) {
- Py_ssize_t optvarsize = datasize;
- if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0)
+ if ((ctitem->ct_flags & (CT_STRUCT | CT_UNION)) && init != Py_None) {
+ if (force_lazy_struct(ctitem) < 0) /* for CT_WITH_VAR_ARRAY */
return NULL;
- datasize = optvarsize;
+ if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) {
+ Py_ssize_t optvarsize = datasize;
+ if (convert_struct_from_object(NULL,ctitem, init,
+ &optvarsize) < 0)
+ return NULL;
+ datasize = optvarsize;
+ }
}
}
else if (ct->ct_flags & CT_ARRAY) {
@@ -2899,6 +2934,15 @@
return (PyObject *)cd;
}
+static PyObject *b_newp(PyObject *self, PyObject *args)
+{
+ CTypeDescrObject *ct;
+ PyObject *init = Py_None;
+ if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
+ return NULL;
+ return direct_newp(ct, init);
+}
+
static int
_my_PyObject_AsBool(PyObject *ob)
{
@@ -3029,13 +3073,9 @@
return cd;
}
-static PyObject *b_cast(PyObject *self, PyObject *args)
-{
- CTypeDescrObject *ct;
+static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob)
+{
CDataObject *cd;
- PyObject *ob;
- if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob))
- return NULL;
if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) &&
ct->ct_size >= 0) {
@@ -3152,6 +3192,16 @@
return NULL;
}
+static PyObject *b_cast(PyObject *self, PyObject *args)
+{
+ CTypeDescrObject *ct;
+ PyObject *ob;
+ if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob))
+ return NULL;
+
+ return do_cast(ct, ob);
+}
+
/************************************************************/
typedef struct {
@@ -3338,7 +3388,58 @@
/************************************************************/
-static PyObject *b_new_primitive_type(PyObject *self, PyObject *args)
+static PyObject *unique_cache;
+
+static PyObject *get_unique_type(CTypeDescrObject *x,
+ const void *unique_key[], long keylength)
+{
+ /* Replace the CTypeDescrObject 'x' with a standardized one.
+ This either just returns x, or x is decrefed and a new reference
+ to the already-existing equivalent is returned.
+
+ In this function, 'x' always contains a reference that must be
+ either decrefed or returned.
+
+ Keys:
+ void ["void"]
+ primitive [&static_struct]
+ pointer [ctype]
+ array [ctype, length]
+ funcptr [ctresult, ellipsis+abi, num_args, ctargs...]
+ */
+ long i;
+ PyObject *key, *y;
+ const void **pkey;
+ int err;
+
+ key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *));
+ if (key == NULL)
+ goto error;
+
+ pkey = (const void **)PyBytes_AS_STRING(key);
+ for (i = 0; i < keylength; i++)
+ pkey[i] = unique_key[i];
+
+ y = PyDict_GetItem(unique_cache, key);
+ if (y != NULL) {
+ Py_DECREF(key);
+ Py_INCREF(y);
+ Py_DECREF(x);
+ return y;
+ }
+ err = PyDict_SetItem(unique_cache, key, (PyObject *)x);
+ Py_DECREF(key);
+ if (err < 0)
+ goto error;
+
+ return (PyObject *)x;
+
+ error:
+ Py_DECREF(x);
+ return NULL;
+}
+
+static PyObject *new_primitive_type(const char *name)
{
#define ENUM_PRIMITIVE_TYPES \
EPTYPE(c, char, CT_PRIMITIVE_CHAR) \
@@ -3403,7 +3504,6 @@
#undef EPTYPE
CTypeDescrObject *td;
- const char *name;
static const struct descr_s { const char *name; int size, align, flags; }
types[] = {
#define EPTYPE(code, typename, flags) \
@@ -3419,12 +3519,10 @@
{ NULL }
};
const struct descr_s *ptypes;
+ const void *unique_key[1];
int name_size;
ffi_type *ffitype;
- if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name))
- return NULL;
-
for (ptypes=types; ; ptypes++) {
if (ptypes->name == NULL) {
#ifndef HAVE_WCHAR_H
@@ -3487,7 +3585,8 @@
td->ct_flags |= CT_PRIMITIVE_FITS_LONG;
}
td->ct_name_position = strlen(td->ct_name);
- return (PyObject *)td;
+ unique_key[0] = ptypes;
+ return get_unique_type(td, unique_key, 1);
bad_ffi_type:
PyErr_Format(PyExc_NotImplementedError,
@@ -3497,14 +3596,19 @@
return NULL;
}
-static PyObject *b_new_pointer_type(PyObject *self, PyObject *args)
-{
- CTypeDescrObject *td, *ctitem;
+static PyObject *b_new_primitive_type(PyObject *self, PyObject *args)
+{
+ char *name;
+ if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name))
+ return NULL;
+ return new_primitive_type(name);
+}
+
+static PyObject *new_pointer_type(CTypeDescrObject *ctitem)
+{
+ CTypeDescrObject *td;
const char *extra;
-
- if (!PyArg_ParseTuple(args, "O!:new_pointer_type",
- &CTypeDescr_Type, &ctitem))
- return NULL;
+ const void *unique_key[1];
if (ctitem->ct_flags & CT_ARRAY)
extra = "(*)"; /* obscure case: see test_array_add */
@@ -3525,47 +3629,31 @@
((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
ctitem->ct_size == sizeof(char)))
td->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */
- return (PyObject *)td;
+ unique_key[0] = ctitem;
+ return get_unique_type(td, unique_key, 1);
+}
+
+static PyObject *b_new_pointer_type(PyObject *self, PyObject *args)
+{
+ CTypeDescrObject *ctitem;
+ if (!PyArg_ParseTuple(args, "O!:new_pointer_type",
+ &CTypeDescr_Type, &ctitem))
+ return NULL;
+ return new_pointer_type(ctitem);
}
static PyObject *b_new_array_type(PyObject *self, PyObject *args)
{
PyObject *lengthobj;
+ Py_ssize_t length;
CTypeDescrObject *ctptr;
if (!PyArg_ParseTuple(args, "O!O:new_array_type",
&CTypeDescr_Type, &ctptr, &lengthobj))
return NULL;
- return new_array_type(ctptr, lengthobj);
-}
-
-static PyObject *
-new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj)
-{
- CTypeDescrObject *td, *ctitem;
- char extra_text[32];
- Py_ssize_t length, arraysize;
- int flags = CT_ARRAY;
-
- if (!(ctptr->ct_flags & CT_POINTER)) {
- PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype");
- return NULL;
- }
- ctitem = ctptr->ct_itemdescr;
- if (ctitem->ct_size < 0) {
- PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'",
- ctitem->ct_name);
- return NULL;
- }
-
if (lengthobj == Py_None) {
- sprintf(extra_text, "[]");
length = -1;
- arraysize = -1;
- if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
- ctitem->ct_size == sizeof(char))
- flags |= CT_IS_UNSIZED_CHAR_A;
}
else {
length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError);
@@ -3574,6 +3662,39 @@
PyErr_SetString(PyExc_ValueError, "negative array length");
return NULL;
}
+ }
+ return new_array_type(ctptr, length);
+}
+
+static PyObject *
+new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length)
+{
+ CTypeDescrObject *td, *ctitem;
+ char extra_text[32];
+ Py_ssize_t arraysize;
+ int flags = CT_ARRAY;
+ const void *unique_key[2];
+
+ if (!(ctptr->ct_flags & CT_POINTER)) {
+ PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype");
+ return NULL;
+ }
+ ctitem = ctptr->ct_itemdescr;
+ if (ctitem->ct_size < 0) {
+ PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'",
+ ctitem->ct_name);
+ return NULL;
+ }
+
+ if (length < 0) {
+ sprintf(extra_text, "[]");
+ length = -1;
+ arraysize = -1;
+ if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
+ ctitem->ct_size == sizeof(char))
+ flags |= CT_IS_UNSIZED_CHAR_A;
+ }
+ else {
sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length);
arraysize = length * ctitem->ct_size;
if (length > 0 && (arraysize / length) != ctitem->ct_size) {
@@ -3591,12 +3712,15 @@
td->ct_size = arraysize;
td->ct_length = length;
td->ct_flags = flags;
- return (PyObject *)td;
-}
-
-static PyObject *b_new_void_type(PyObject *self, PyObject *args)
+ unique_key[0] = ctptr;
+ unique_key[1] = (void *)length;
+ return get_unique_type(td, unique_key, 2);
+}
+
+static PyObject *new_void_type(void)
{
int name_size = strlen("void") + 1;
+ const void *unique_key[1];
CTypeDescrObject *td = ctypedescr_new(name_size);
if (td == NULL)
return NULL;
@@ -3605,10 +3729,16 @@
td->ct_size = -1;
td->ct_flags = CT_VOID | CT_IS_OPAQUE;
td->ct_name_position = strlen("void");
- return (PyObject *)td;
-}
-
-static PyObject *_b_struct_or_union_type(const char *name, int flag)
+ unique_key[0] = "void";
+ return get_unique_type(td, unique_key, 1);
+}
+
+static PyObject *b_new_void_type(PyObject *self, PyObject *args)
+{
+ return new_void_type();
+}
+
+static PyObject *new_struct_or_union_type(const char *name, int flag)
{
int namelen = strlen(name);
CTypeDescrObject *td = ctypedescr_new(namelen + 1);
@@ -3618,6 +3748,7 @@
td->ct_size = -1;
td->ct_length = -1;
td->ct_flags = flag | CT_IS_OPAQUE;
+ td->ct_extra = NULL;
memcpy(td->ct_name, name, namelen + 1);
td->ct_name_position = namelen;
return (PyObject *)td;
@@ -3633,7 +3764,7 @@
flag = CT_STRUCT;
if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0)
flag |= CT_IS_FILE;
- return _b_struct_or_union_type(name, flag);
+ return new_struct_or_union_type(name, flag);
}
static PyObject *b_new_union_type(PyObject *self, PyObject *args)
@@ -3641,7 +3772,7 @@
char *name;
if (!PyArg_ParseTuple(args, "s:new_union_type", &name))
return NULL;
- return _b_struct_or_union_type(name, CT_UNION);
+ return new_struct_or_union_type(name, CT_UNION);
}
static CFieldObject *
@@ -3685,6 +3816,7 @@
#define SF_GCC_LITTLE_ENDIAN 0x40
#define SF_PACKED 0x08
+#define SF_STD_FIELD_POS 0x80
static int complete_sflags(int sflags)
{
@@ -3712,12 +3844,34 @@
return sflags;
}
+static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
+ Py_ssize_t cdef_value,
+ Py_ssize_t compiler_value,
+ const char *msg1, const char *txt,
+ const char *msg2)
+{
+ if (compiler_value != cdef_value) {
+ if (sflags & SF_STD_FIELD_POS) {
+ PyErr_Format(FFIError,
+ "%s: %s%s%s (cdef says %zd, but C compiler says %zd)."
+ " fix it or use \"...;\" in the cdef for %s to "
+ "make it flexible",
+ ct->ct_name, msg1, txt, msg2,
+ cdef_value, compiler_value,
+ ct->ct_name);
+ return -1;
+ }
+ ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+ }
+ return 0;
+}
+
static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
PyObject *fields, *interned_fields, *ignored;
int is_union, alignment;
- Py_ssize_t boffset, i, nb_fields, boffsetmax;
+ Py_ssize_t boffset, i, nb_fields, boffsetmax, alignedsize;
Py_ssize_t totalsize = -1;
int totalalignment = -1;
CFieldObject **previous;
@@ -3745,6 +3899,7 @@
"first arg must be a non-initialized struct or union ctype");
return NULL;
}
+ ct->ct_flags &= ~CT_CUSTOM_FIELD_POS;
alignment = 1;
boffset = 0; /* this number is in *bits*, not bytes! */
@@ -3822,8 +3977,10 @@
if (foffset >= 0) {
/* a forced field position: ignore the offset just computed,
except to know if we must set CT_CUSTOM_FIELD_POS */
- if (boffset != foffset * 8)
- ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+ if (detect_custom_layout(ct, sflags, boffset / 8, foffset,
+ "wrong offset for field '",
+ PyText_AS_UTF8(fname), "'") < 0)
+ goto error;
boffset = foffset * 8;
}
@@ -3996,19 +4153,35 @@
as 1 instead. But for ctypes support, we allow the manually-
specified totalsize to be zero in this case. */
boffsetmax = (boffsetmax + 7) / 8; /* bits -> bytes */
+ alignedsize = (boffsetmax + alignment - 1) & ~(alignment-1);
+ if (alignedsize == 0)
+ alignedsize = 1;
+
if (totalsize < 0) {
- totalsize = (boffsetmax + alignment - 1) & ~(alignment-1);
- if (totalsize == 0)
- totalsize = 1;
- }
- else if (totalsize < boffsetmax) {
- PyErr_Format(PyExc_TypeError,
- "%s cannot be of size %zd: there are fields at least "
- "up to %zd", ct->ct_name, totalsize, boffsetmax);
- goto error;
- }
+ totalsize = alignedsize;
+ }
+ else {
+ if (detect_custom_layout(ct, sflags, alignedsize,
+ totalsize, "wrong total size", "", "") < 0)
+ goto error;
+ if (totalsize < boffsetmax) {
+ PyErr_Format(PyExc_TypeError,
+ "%s cannot be of size %zd: there are fields at least "
+ "up to %zd", ct->ct_name, totalsize, boffsetmax);
+ goto error;
+ }
+ }
+ if (totalalignment < 0) {
+ totalalignment = alignment;
+ }
+ else {
+ if (detect_custom_layout(ct, sflags, alignment, totalalignment,
+ "wrong total alignment", "", "") < 0)
+ goto error;
+ }
+
ct->ct_size = totalsize;
- ct->ct_length = totalalignment < 0 ? alignment : totalalignment;
+ ct->ct_length = totalalignment;
ct->ct_stuff = interned_fields;
ct->ct_flags &= ~CT_IS_OPAQUE;
@@ -4016,6 +4189,7 @@
return Py_None;
error:
+ ct->ct_extra = NULL;
Py_DECREF(interned_fields);
return NULL;
}
@@ -4045,6 +4219,8 @@
static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
int is_result_type)
{
+ const char *place = is_result_type ? "return value" : "argument";
+
if (ct->ct_flags & CT_PRIMITIVE_ANY) {
return (ffi_type *)ct->ct_extra;
}
@@ -4081,10 +4257,15 @@
here, so better safe (and forbid it) than sorry (and maybe
crash).
*/
+ if (force_lazy_struct(ct) < 0)
+ return NULL;
if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
- PyErr_SetString(PyExc_TypeError,
- "cannot pass as an argument a struct that was completed "
- "with verify() (see _cffi_backend.c for details of why)");
+ /* these NotImplementedErrors may be caught and ignored until
+ a real call is made to a function of this type */
+ PyErr_Format(PyExc_NotImplementedError,
+ "ctype '%s' not supported as %s (it is a struct declared "
+ "with \"...;\", but the C calling convention may depend "
+ "on the missing fields)", ct->ct_name, place);
return NULL;
}
@@ -4100,9 +4281,9 @@
assert(cf != NULL);
if (cf->cf_bitshift >= 0) {
PyErr_Format(PyExc_NotImplementedError,
- "ctype '%s' not supported as argument or return value"
+ "ctype '%s' not supported as %s"
" (it is a struct with bit fields)",
- ct->ct_name);
+ ct->ct_name, place);
return NULL;
}
flat = 1;
@@ -4113,9 +4294,9 @@
}
if (flat <= 0) {
PyErr_Format(PyExc_NotImplementedError,
- "ctype '%s' not supported as argument or return value"
+ "ctype '%s' not supported as %s"
" (it is a struct with a zero-length array)",
- ct->ct_name);
+ ct->ct_name, place);
return NULL;
}
nflat += flat;
@@ -4154,7 +4335,6 @@
return ffistruct;
}
else {
- const char *place = is_result_type ? "return value" : "argument";
PyErr_Format(PyExc_NotImplementedError,
"ctype '%s' (size %zd) not supported as %s",
ct->ct_name, ct->ct_size, place);
@@ -4370,21 +4550,15 @@
return NULL;
}
-static PyObject *b_new_function_type(PyObject *self, PyObject *args)
-{
- PyObject *fargs, *fabiobj;
- CTypeDescrObject *fresult;
+static PyObject *new_function_type(PyObject *fargs, /* tuple */
+ CTypeDescrObject *fresult,
+ int ellipsis, int fabi)
+{
+ PyObject *fabiobj;
CTypeDescrObject *fct;
- int ellipsis = 0, fabi = FFI_DEFAULT_ABI;
struct funcbuilder_s funcbuilder;
Py_ssize_t i;
-
- if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type",
- &PyTuple_Type, &fargs,
- &CTypeDescr_Type, &fresult,
- &ellipsis,
- &fabi))
- return NULL;
+ const void **unique_key;
if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) ||
(fresult->ct_flags & CT_ARRAY)) {
@@ -4440,15 +4614,37 @@
Py_INCREF(o);
PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o);
}
- fct->ct_size = sizeof(void(*)(void));
- fct->ct_flags = CT_FUNCTIONPTR;
- return (PyObject *)fct;
+
+ /* [ctresult, ellipsis+abi, num_args, ctargs...] */
+ unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *));
+ unique_key[0] = fresult;
+ unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis);
+ unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs);
+ for (i=0; i<funcbuilder.nargs; i++)
+ unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i);
+ return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs);
error:
Py_DECREF(fct);
return NULL;
}
+static PyObject *b_new_function_type(PyObject *self, PyObject *args)
+{
+ PyObject *fargs;
+ CTypeDescrObject *fresult;
+ int ellipsis = 0, fabi = FFI_DEFAULT_ABI;
+
+ if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type",
+ &PyTuple_Type, &fargs,
+ &CTypeDescr_Type, &fresult,
+ &ellipsis,
+ &fabi))
+ return NULL;
+
+ return new_function_type(fargs, fresult, ellipsis, fabi);
+}
+
static int convert_from_object_fficallback(char *result,
CTypeDescrObject *ctype,
PyObject *pyobj)
@@ -4831,25 +5027,26 @@
return res;
}
-static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
-{
- PyObject *res, *fieldname;
- CTypeDescrObject *ct;
+static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct,
+ PyObject *fieldname,
+ int following, Py_ssize_t *offset)
+{
+ /* Does not return a new reference! */
+ CTypeDescrObject *res;
CFieldObject *cf;
- Py_ssize_t offset;
- int following = 0;
-
- if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
- &CTypeDescr_Type, &ct, &fieldname, &following))
- return NULL;
if (PyTextAny_Check(fieldname)) {
if (!following && (ct->ct_flags & CT_POINTER))
ct = ct->ct_itemdescr;
- if (!(ct->ct_flags & (CT_STRUCT|CT_UNION)) || ct->ct_stuff == NULL) {
+ if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) {
PyErr_SetString(PyExc_TypeError,
- "with a field name argument, expected an "
- "initialized struct or union ctype");
+ "with a field name argument, expected a "
+ "struct or union ctype");
+ return NULL;
+ }
+ if (force_lazy_struct(ct) <= 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError, "struct/union is opaque");
return NULL;
}
cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname);
@@ -4861,8 +5058,8 @@
PyErr_SetString(PyExc_TypeError, "not supported for bitfields");
return NULL;
}
- res = (PyObject *)cf->cf_type;
- offset = cf->cf_offset;
+ res = cf->cf_type;
+ *offset = cf->cf_offset;
}
else {
ssize_t index = PyInt_AsSsize_t(fieldname);
@@ -4879,14 +5076,32 @@
"pointer to non-opaque");
return NULL;
}
- res = (PyObject *)ct->ct_itemdescr;
- offset = index * ct->ct_itemdescr->ct_size;
- if ((offset / ct->ct_itemdescr->ct_size) != index) {
+ res = ct->ct_itemdescr;
+ *offset = index * ct->ct_itemdescr->ct_size;
+ if ((*offset / ct->ct_itemdescr->ct_size) != index) {
PyErr_SetString(PyExc_OverflowError,
"array offset would overflow a Py_ssize_t");
return NULL;
}
}
+ return res;
+}
+
+static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
+{
+ PyObject *res, *fieldname;
+ CTypeDescrObject *ct;
+ Py_ssize_t offset;
+ int following = 0;
+
+ if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
+ &CTypeDescr_Type, &ct, &fieldname, &following))
+ return NULL;
+
+ res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset);
+ if (res == NULL)
+ return NULL;
+
return Py_BuildValue("(On)", res, offset);
}
@@ -5069,12 +5284,16 @@
return PyInt_FromLong(err);
}
-static PyObject *b_set_errno(PyObject *self, PyObject *args)
-{
- int i;
- if (!PyArg_ParseTuple(args, "i:set_errno", &i))
+static PyObject *b_set_errno(PyObject *self, PyObject *arg)
+{
+ long ival = PyInt_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
return NULL;
- errno = i;
+ else if (ival < INT_MIN || ival > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "errno value too large");
+ return NULL;
+ }
+ errno = (int)ival;
save_errno_only();
errno = 0;
Py_INCREF(Py_None);
@@ -5211,21 +5430,11 @@
return 0;
}
-static PyObject *b_from_buffer(PyObject *self, PyObject *args)
-{
- CTypeDescrObject *ct;
+static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x)
+{
CDataObject *cd;
- PyObject *x;
Py_buffer *view;
- if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
- return NULL;
-
- if (!(ct->ct_flags & CT_IS_UNSIZED_CHAR_A)) {
- PyErr_Format(PyExc_TypeError, "needs 'char[]', got '%s'", ct->ct_name);
- return NULL;
- }
-
if (invalid_input_buffer_type(x)) {
PyErr_SetString(PyExc_TypeError,
"from_buffer() cannot return the address of the "
@@ -5259,6 +5468,21 @@
return NULL;
}
+static PyObject *b_from_buffer(PyObject *self, PyObject *args)
+{
+ CTypeDescrObject *ct;
+ PyObject *x;
+
+ if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
+ return NULL;
+
+ if (!(ct->ct_flags & CT_IS_UNSIZED_CHAR_A)) {
+ PyErr_Format(PyExc_TypeError, "needs 'char[]', got '%s'", ct->ct_name);
+ return NULL;
+ }
+ return direct_from_buffer(ct, x);
+}
+
static PyObject *b__get_types(PyObject *self, PyObject *noarg)
{
return PyTuple_Pack(2, (PyObject *)&CData_Type,
@@ -5539,6 +5763,10 @@
return Py_None;
}
+static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *);
+/* forward, see cffi1_module.c */
+
+
static PyMethodDef FFIBackendMethods[] = {
{"load_library", b_load_library, METH_VARARGS},
{"new_primitive_type", b_new_primitive_type, METH_VARARGS},
@@ -5562,7 +5790,7 @@
{"string", b_string, METH_VARARGS},
{"buffer", b_buffer, METH_VARARGS},
{"get_errno", b_get_errno, METH_NOARGS},
- {"set_errno", b_set_errno, METH_VARARGS},
+ {"set_errno", b_set_errno, METH_O},
{"newp_handle", b_newp_handle, METH_VARARGS},
{"from_handle", b_from_handle, METH_O},
{"from_buffer", b_from_buffer, METH_VARARGS},
@@ -5572,6 +5800,7 @@
{"_get_types", b__get_types, METH_NOARGS},
{"_testfunc", b__testfunc, METH_VARARGS},
{"_testbuff", b__testbuff, METH_VARARGS},
+ {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module,
METH_O},
{NULL, NULL} /* Sentinel */
};
@@ -5685,7 +5914,7 @@
#endif
static void *cffi_exports[] = {
- 0,
+ NULL,
_cffi_to_c_i8,
_cffi_to_c_u8,
_cffi_to_c_i16,
@@ -5717,6 +5946,32 @@
convert_array_from_object,
};
+static struct { const char *name; int value; } all_dlopen_flags[] = {
+ { "RTLD_LAZY", RTLD_LAZY },
+ { "RTLD_NOW", RTLD_NOW },
+ { "RTLD_GLOBAL", RTLD_GLOBAL },
+#ifdef RTLD_LOCAL
+ { "RTLD_LOCAL", RTLD_LOCAL },
+#else
+ { "RTLD_LOCAL", 0 },
+#endif
+#ifdef RTLD_NODELETE
+ { "RTLD_NODELETE", RTLD_NODELETE },
+#endif
+#ifdef RTLD_NOLOAD
+ { "RTLD_NOLOAD", RTLD_NOLOAD },
+#endif
+#ifdef RTLD_DEEPBIND
+ { "RTLD_DEEPBIND", RTLD_DEEPBIND },
+#endif
+ { NULL, 0 }
+};
+
+
+/************************************************************/
+
+#include "cffi1_module.c"
+
/************************************************************/
#if PY_MAJOR_VERSION >= 3
@@ -5740,6 +5995,7 @@
#endif
{
PyObject *m, *v;
+ int i;
v = PySys_GetObject("version");
if (v == NULL || !PyText_Check(v) ||
@@ -5758,6 +6014,11 @@
if (m == NULL)
INITERROR;
+
+ unique_cache = PyDict_New();
+ if (unique_cache == NULL)
+ INITERROR;
+
if (PyType_Ready(&dl_type) < 0)
INITERROR;
if (PyType_Ready(&CTypeDescr_Type) < 0)
@@ -5784,11 +6045,12 @@
"__name__", v) < 0)
INITERROR;
+ /* this is for backward compatibility only */
v = PyCapsule_New((void *)cffi_exports, "cffi", NULL);
if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
INITERROR;
- v = PyText_FromString("0.9.2");
+ v = PyText_FromString("1.0.0");
if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
INITERROR;
@@ -5809,29 +6071,21 @@
PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */
# endif
#endif
-
- PyModule_AddIntConstant(m, "RTLD_LAZY", RTLD_LAZY) < 0 ||
- PyModule_AddIntConstant(m, "RTLD_NOW", RTLD_NOW) < 0 ||
- PyModule_AddIntConstant(m, "RTLD_GLOBAL", RTLD_GLOBAL) < 0 ||
-#ifdef RTLD_LOCAL
- PyModule_AddIntConstant(m, "RTLD_LOCAL", RTLD_LOCAL) < 0 ||
-#else
- PyModule_AddIntConstant(m, "RTLD_LOCAL", 0) < 0 ||
-#endif
-#ifdef RTLD_NODELETE
- PyModule_AddIntConstant(m, "RTLD_NODELETE", RTLD_NODELETE) < 0 ||
-#endif
-#ifdef RTLD_NOLOAD
- PyModule_AddIntConstant(m, "RTLD_NOLOAD", RTLD_NOLOAD) < 0 ||
-#endif
-#ifdef RTLD_DEEPBIND
- PyModule_AddIntConstant(m, "RTLD_DEEPBIND", RTLD_DEEPBIND) < 0 ||
-#endif
0)
INITERROR;
+ for (i = 0; all_dlopen_flags[i].name != NULL; i++) {
+ if (PyModule_AddIntConstant(m,
+ all_dlopen_flags[i].name,
+ all_dlopen_flags[i].value) < 0)
+ INITERROR;
+ }
+
init_errno();
+ if (init_ffi_lib(m) < 0)
+ INITERROR;
+
#if PY_MAJOR_VERSION >= 3
if (init_file_emulator() < 0)
INITERROR;
diff --git a/c/cdlopen.c b/c/cdlopen.c
new file mode 100644
--- /dev/null
+++ b/c/cdlopen.c
@@ -0,0 +1,382 @@
+/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
+
+static void *cdlopen_fetch(PyObject *libname, void *libhandle, 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)
+{
+ char *filename_or_null, *printable_filename;
+ void *handle;
+ int flags = 0;
+
+ if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
+ PyObject *dummy;
+ if (!PyArg_ParseTuple(args, "|Oi:load_library",
+ &dummy, &flags))
+ return NULL;
+ filename_or_null = NULL;
+ }
+ else if (!PyArg_ParseTuple(args, "et|i:load_library",
+ Py_FileSystemDefaultEncoding, &filename_or_null,
+ &flags))
+ return NULL;
+
+ if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
+ flags |= RTLD_NOW;
+ printable_filename = filename_or_null ? filename_or_null : "<None>";
+
+ handle = dlopen(filename_or_null, flags);
+ if (handle == NULL) {
+ const char *error = dlerror();
+ PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
+ printable_filename, error);
+ return NULL;
+ }
+ return (PyObject *)lib_internal_new((FFIObject *)self,
+ printable_filename, handle);
+}
+
+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;
+ lib->l_libhandle = NULL;
+
+ if (libhandle == NULL) {
+ PyErr_Format(FFIError, "library '%s' is already closed "
+ "or was not created with ffi.dlopen()",
+ PyText_AS_UTF8(lib->l_libname));
+ return 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;
+}
diff --git a/c/cffi1_module.c b/c/cffi1_module.c
new file mode 100644
--- /dev/null
+++ b/c/cffi1_module.c
@@ -0,0 +1,193 @@
+
+#include "parse_c_type.c"
+#include "realize_c_type.c"
+
+#define CFFI_VERSION_MIN 0x2601
+#define CFFI_VERSION_MAX 0x26FF
+
+typedef struct FFIObject_s FFIObject;
+typedef struct LibObject_s LibObject;
+
+static PyTypeObject FFI_Type; /* forward */
+static PyTypeObject Lib_Type; /* forward */
+
+#include "ffi_obj.c"
+#include "cglob.c"
+#include "cgc.c"
+#include "lib_obj.c"
+#include "cdlopen.c"
+
+
+static int init_ffi_lib(PyObject *m)
+{
+ PyObject *x;
+ int i;
+
+ if (PyType_Ready(&FFI_Type) < 0)
+ return -1;
+ if (PyType_Ready(&Lib_Type) < 0)
+ return -1;
+ if (init_global_types_dict(FFI_Type.tp_dict) < 0)
+ return -1;
+
+ FFIError = PyErr_NewException("ffi.error", NULL, NULL);
+ if (FFIError == NULL)
+ return -1;
+ if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0)
+ return -1;
+ if (PyDict_SetItemString(FFI_Type.tp_dict, "CType",
+ (PyObject *)&CTypeDescr_Type) < 0)
+ return -1;
+ if (PyDict_SetItemString(FFI_Type.tp_dict, "CData",
+ (PyObject *)&CData_Type) < 0)
+ return -1;
+
+ for (i = 0; all_dlopen_flags[i].name != NULL; i++) {
+ x = PyInt_FromLong(all_dlopen_flags[i].value);
+ if (x == NULL || PyDict_SetItemString(FFI_Type.tp_dict,
+ all_dlopen_flags[i].name,
+ x) < 0)
+ return -1;
+ Py_DECREF(x);
+ }
+
+ x = (PyObject *)&FFI_Type;
+ Py_INCREF(x);
+ if (PyModule_AddObject(m, "FFI", x) < 0)
+ return -1;
+ x = (PyObject *)&Lib_Type;
+ Py_INCREF(x);
+ if (PyModule_AddObject(m, "Lib", x) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int make_included_tuples(char *module_name,
+ const char *const *ctx_includes,
+ PyObject **included_ffis,
+ PyObject **included_libs)
+{
+ Py_ssize_t num = 0;
+ const char *const *p_include;
+
+ if (ctx_includes == NULL)
+ return 0;
+
+ for (p_include = ctx_includes; *p_include; p_include++) {
+ num++;
+ }
+ *included_ffis = PyTuple_New(num);
+ *included_libs = PyTuple_New(num);
+ if (*included_ffis == NULL || *included_libs == NULL)
+ goto error;
+
+ num = 0;
+ for (p_include = ctx_includes; *p_include; p_include++) {
+ PyObject *included_ffi, *included_lib;
+ PyObject *m = PyImport_ImportModule(*p_include);
+ if (m == NULL)
+ goto import_error;
+
+ included_ffi = PyObject_GetAttrString(m, "ffi");
+ PyTuple_SET_ITEM(*included_ffis, num, included_ffi);
+
+ included_lib = (included_ffi == NULL) ? NULL :
+ PyObject_GetAttrString(m, "lib");
+ PyTuple_SET_ITEM(*included_libs, num, included_lib);
+
+ Py_DECREF(m);
+ if (included_lib == NULL)
+ goto import_error;
+
+ if (!FFIObject_Check(included_ffi) ||
+ !LibObject_Check(included_lib))
+ goto import_error;
+ num++;
+ }
+ return 0;
+
+ import_error:
+ PyErr_Format(PyExc_ImportError,
+ "while loading %.200s: failed to import ffi, lib from %.200s",
+ module_name, *p_include);
+ error:
+ Py_XDECREF(*included_ffis); *included_ffis = NULL;
+ Py_XDECREF(*included_libs); *included_libs = NULL;
+ return -1;
+}
+
+static PyObject *_my_Py_InitModule(char *module_name)
+{
+#if PY_MAJOR_VERSION >= 3
+ struct PyModuleDef *module_def, local_module_def = {
+ PyModuleDef_HEAD_INIT,
+ module_name,
+ NULL,
+ -1,
+ NULL, NULL, NULL, NULL, NULL
+ };
+ /* note: the 'module_def' is allocated dynamically and leaks,
+ but anyway the C extension module can never be unloaded */
+ module_def = PyMem_Malloc(sizeof(struct PyModuleDef));
+ if (module_def == NULL)
+ return PyErr_NoMemory();
+ *module_def = local_module_def;
+ return PyModule_Create(module_def);
+#else
+ return Py_InitModule(module_name, NULL);
+#endif
+}
+
+static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg)
+{
+ PyObject *m;
+ FFIObject *ffi;
+ LibObject *lib;
+ Py_ssize_t version;
+ char *module_name, *exports;
+ void **raw;
+ const struct _cffi_type_context_s *ctx;
+
+ raw = (void **)PyLong_AsVoidPtr(arg);
+ if (raw == NULL)
+ return NULL;
+
+ module_name = (char *)raw[0];
+ version = (Py_ssize_t)raw[1];
+ exports = (char *)raw[2];
+ ctx = (const struct _cffi_type_context_s *)raw[3];
+
+ if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
+ if (!PyErr_Occurred())
+ PyErr_Format(PyExc_ImportError,
+ "cffi extension module '%s' has unknown version %p",
+ module_name, (void *)version);
+ return NULL;
+ }
+
+ /* initialize the exports array */
+ memcpy(exports, (char *)cffi_exports, sizeof(cffi_exports));
+
+ /* make the module object */
+ m = _my_Py_InitModule(module_name);
+ if (m == NULL)
+ return NULL;
+
+ /* build the FFI and Lib object inside this new module */
+ ffi = ffi_internal_new(&FFI_Type, ctx);
+ Py_XINCREF(ffi); /* make the ffi object really immortal */
+ if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
+ return NULL;
+
+ lib = lib_internal_new(ffi, module_name, NULL);
+ if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
+ return NULL;
+
+ if (make_included_tuples(module_name, ctx->includes,
+ &ffi->types_builder.included_ffis,
+ &lib->l_types_builder->included_libs) < 0)
+ return NULL;
+
+ return m;
+}
diff --git a/c/cgc.c b/c/cgc.c
new file mode 100644
--- /dev/null
+++ b/c/cgc.c
@@ -0,0 +1,80 @@
+
+/* translated to C from cffi/gc_weakref.py */
+
+
+static PyObject *const_name_pop;
+
+static PyObject *gc_wref_remove(PyObject *ffi_wref_data, PyObject *arg)
+{
+ PyObject *destructor, *cdata, *x;
+ PyObject *res = PyObject_CallMethodObjArgs(ffi_wref_data,
+ const_name_pop, arg, NULL);
+ if (res == NULL)
+ return NULL;
+
+ assert(PyTuple_Check(res));
+ destructor = PyTuple_GET_ITEM(res, 0);
+ cdata = PyTuple_GET_ITEM(res, 1);
+ x = PyObject_CallFunctionObjArgs(destructor, cdata, NULL);
+ Py_DECREF(res);
+ if (x == NULL)
+ return NULL;
+ Py_DECREF(x);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef remove_callback = {
+ "gc_wref_remove", (PyCFunction)gc_wref_remove, METH_O
+};
+
+static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cd,
+ PyObject *destructor)
+{
+ PyObject *new_cdata, *ref = NULL, *tup = NULL;
+
+ if (ffi->gc_wrefs == NULL) {
+ /* initialize */
+ PyObject *data;
+
+ if (const_name_pop == NULL) {
+ const_name_pop = PyText_InternFromString("pop");
+ if (const_name_pop == NULL)
+ return NULL;
+ }
+ data = PyDict_New();
+ if (data == NULL)
+ return NULL;
+ ffi->gc_wrefs = PyCFunction_New(&remove_callback, data);
+ Py_DECREF(data);
+ if (ffi->gc_wrefs == NULL)
+ return NULL;
+ }
+
+ new_cdata = do_cast(cd->c_type, (PyObject *)cd);
+ if (new_cdata == NULL)
+ goto error;
+
+ ref = PyWeakref_NewRef(new_cdata, ffi->gc_wrefs);
+ if (ref == NULL)
+ goto error;
+
+ tup = PyTuple_Pack(2, destructor, cd);
+ if (tup == NULL)
+ goto error;
+
+ /* the 'self' of the function 'gc_wrefs' is actually the data dict */
+ if (PyDict_SetItem(PyCFunction_GET_SELF(ffi->gc_wrefs), ref, tup) < 0)
+ goto error;
+
+ Py_DECREF(tup);
+ Py_DECREF(ref);
+ return new_cdata;
+
+ error:
+ Py_XDECREF(new_cdata);
+ Py_XDECREF(ref);
+ Py_XDECREF(tup);
+ return NULL;
+}
diff --git a/c/cglob.c b/c/cglob.c
new file mode 100644
--- /dev/null
+++ b/c/cglob.c
@@ -0,0 +1,72 @@
+
+typedef struct {
+ PyObject_HEAD
+
+ CTypeDescrObject *gs_type;
+ char *gs_data;
+
+} GlobSupportObject;
+
+static void glob_support_dealloc(GlobSupportObject *gs)
+{
+ Py_DECREF(gs->gs_type);
+ PyObject_Del(gs);
+}
+
+static PyTypeObject GlobSupport_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FFIGlobSupport",
+ sizeof(GlobSupportObject),
+ 0,
+ (destructor)glob_support_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+};
+
+#define GlobSupport_Check(ob) (Py_TYPE(ob) == &GlobSupport_Type)
+
+static PyObject *make_global_var(CTypeDescrObject *type, char *addr)
+{
+ GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type);
+ if (gs == NULL)
+ return NULL;
+
+ Py_INCREF(type);
+ gs->gs_type = type;
+ gs->gs_data = addr;
+ return (PyObject *)gs;
+}
+
+static PyObject *read_global_var(GlobSupportObject *gs)
+{
+ return convert_to_object(gs->gs_data, gs->gs_type);
+}
+
+static int write_global_var(GlobSupportObject *gs, PyObject *obj)
+{
+ return convert_from_object(gs->gs_data, gs->gs_type, obj);
+}
+
+static PyObject *cg_addressof_global_var(GlobSupportObject *gs)
+{
+ PyObject *x, *ptrtype = new_pointer_type(gs->gs_type);
+ if (ptrtype == NULL)
+ return NULL;
+
+ x = new_simple_cdata(gs->gs_data, (CTypeDescrObject *)ptrtype);
+ Py_DECREF(ptrtype);
+ return x;
+}
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
new file mode 100644
--- /dev/null
+++ b/c/ffi_obj.c
@@ -0,0 +1,887 @@
+
+/* An FFI object has methods like ffi.new(). It is also a container
+ for the type declarations (typedefs and structs) that you can use,
+ say in ffi.new().
+
+ CTypeDescrObjects are internally stored in the dict 'types_dict'.
+ The types_dict is lazily filled with CTypeDescrObjects made from
+ reading a _cffi_type_context_s structure.
+
+ In "modern" mode, the FFI instance is made by the C extension
+ module originally created by recompile(). The _cffi_type_context_s
+ structure comes from global data in the C extension module.
+
+ In "compatibility" mode, an FFI instance is created explicitly by
+ the user, and its _cffi_type_context_s is initially empty. You
+ need to call ffi.cdef() to add more information to it.
+*/
+
+#define FFI_COMPLEXITY_OUTPUT 1200 /* xxx should grow as needed */
+
+#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type)
+#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type))
+
+struct FFIObject_s {
+ PyObject_HEAD
+ PyObject *gc_wrefs;
+ struct _cffi_parse_info_s info;
+ char ctx_is_static, ctx_is_nonempty;
+ builder_c_t types_builder;
+};
+
+static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
+ const struct _cffi_type_context_s *static_ctx)
+{
+ static _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT];
+
+ FFIObject *ffi;
+ if (static_ctx != NULL) {
+ ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype);
+ /* we don't call PyObject_GC_Track() here: from _cffi_init_module()
+ it is not needed, because in this case the ffi object is immortal */
+ }
+ else {
+ ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0);
+ }
+ if (ffi == NULL)
+ return NULL;
+
+ if (init_builder_c(&ffi->types_builder, static_ctx) < 0) {
+ Py_DECREF(ffi);
+ return NULL;
+ }
+ ffi->gc_wrefs = NULL;
+ ffi->info.ctx = &ffi->types_builder.ctx;
+ ffi->info.output = internal_output;
+ ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
+ ffi->ctx_is_static = (static_ctx != NULL);
+ ffi->ctx_is_nonempty = (static_ctx != NULL);
+ return ffi;
+}
+
+static void ffi_dealloc(FFIObject *ffi)
+{
+ PyObject_GC_UnTrack(ffi);
+ Py_XDECREF(ffi->gc_wrefs);
+
+ free_builder_c(&ffi->types_builder, ffi->ctx_is_static);
+
+ Py_TYPE(ffi)->tp_free((PyObject *)ffi);
+}
+
+static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg)
+{
+ Py_VISIT(ffi->types_builder.types_dict);
+ Py_VISIT(ffi->types_builder.included_ffis);
+ Py_VISIT(ffi->types_builder.included_libs);
+ Py_VISIT(ffi->gc_wrefs);
+ return 0;
+}
+
+static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ /* user-facing initialization code, for explicit FFI() calls */
+ return (PyObject *)ffi_internal_new(type, NULL);
+}
+
+/* forward, declared in cdlopen.c because it's mostly useful for this case */
+static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds);
+
+static PyObject *ffi_fetch_int_constant(FFIObject *ffi, char *name,
+ int recursion)
+{
+ int index;
+
+ index = search_in_globals(&ffi->types_builder.ctx, name, strlen(name));
+ if (index >= 0) {
+ const struct _cffi_global_s *g;
+ g = &ffi->types_builder.ctx.globals[index];
+
+ switch (_CFFI_GETOP(g->type_op)) {
+ case _CFFI_OP_CONSTANT_INT:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit