[pypy-commit] cffi cffi-1.0: enums, integer constants
arigo
noreply at buildbot.pypy.org
Mon May 11 19:29:52 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1977:f3745cfa00a0
Date: 2015-05-11 19:30 +0200
http://bitbucket.org/cffi/cffi/changeset/f3745cfa00a0/
Log: enums, integer constants
diff --git a/_cffi1/cdlopen.c b/_cffi1/cdlopen.c
--- a/_cffi1/cdlopen.c
+++ b/_cffi1/cdlopen.c
@@ -95,15 +95,38 @@
}
-static int cdl_int(char *src)
+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 (usrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
+ return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
}
static _cffi_opcode_t cdl_opcode(char *src)
{
- return (_cffi_opcode_t)(Py_ssize_t)cdl_int(src);
+ return (_cffi_opcode_t)cdl_4bytes(src);
+}
+
+typedef struct {
+ unsigned long long value;
+ int neg;
+} cdl_intconst_t;
+
+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)
@@ -111,18 +134,19 @@
FFIObject *ffi;
static char *keywords[] = {"module_name", "_version", "_types",
"_globals", "_struct_unions", "_enums",
- "_typenames", "_consts", NULL};
+ "_typenames", NULL};
char *ffiname = NULL, *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, *consts = NULL;
+ PyObject *typenames = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!OOOO:FFI", keywords,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!O!O!O!:FFI", keywords,
&ffiname, &version, &types, &types_len,
&PyTuple_Type, &globals,
- &struct_unions, &enums,
- &typenames, &consts))
+ &PyTuple_Type, &struct_unions,
+ &PyTuple_Type, &enums,
+ &PyTuple_Type, &typenames))
return -1;
ffi = (FFIObject *)self;
@@ -153,22 +177,41 @@
}
if (globals != NULL) {
- /* unpack a tuple of strings, each of which describes one global_s
- entry with no specified address or size */
+ /* 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;
- Py_ssize_t i, n = PyTuple_GET_SIZE(globals);
+ cdl_intconst_t *nintconsts;
+ Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
- i = n * sizeof(struct _cffi_global_s);
+ 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 = PyString_AS_STRING(PyTuple_GET_ITEM(globals, i));
- nglobs[i].type_op = cdl_opcode(g);
- nglobs[i].name = g + 4;
+ char *g = PyString_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 (PyInt_Check(o)) {
+ nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
+ nintconsts[i].value = (long long)PyInt_AS_LONG(o);
+ }
+ else {
+ 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;
@@ -203,9 +246,9 @@
Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
char *s = PyString_AS_STRING(PyTuple_GET_ITEM(desc, 0));
/* 's' is the first string, describing the struct/union */
- nstructs[i].type_index = cdl_int(s);
- nstructs[i].flags = cdl_int(s + 4);
- nstructs[i].name = s + 8;
+ 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) {
nstructs[i].size = (size_t)-1;
nstructs[i].alignment = -1;
@@ -223,11 +266,10 @@
char *f = PyString_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);
- nfields[nf].name = f + 4;
+ nfields[nf].field_type_op = cdl_opcode(f); f += 4;
nfields[nf].field_offset = (size_t)-1;
- nfields[nf].field_size = (size_t)-1;
- /* XXXXXXXXXXX BITFIELD MISSING XXXXXXXXXXXXXXXX */
+ nfields[nf].field_size = cdl_4bytes(f); f += 4;
+ nfields[nf].name = f;
nf++;
}
}
@@ -237,9 +279,30 @@
building = NULL;
}
- if (consts != NULL) {
- Py_INCREF(consts);
- ffi->types_builder.known_constants = consts;
+ 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 = PyString_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;
}
/* Above, we took directly some "char *" strings out of the strings,
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -166,14 +166,6 @@
index = search_in_globals(&lib->l_types_builder->ctx, s, strlen(s));
if (index < 0) {
- if (lib->l_types_builder->known_constants != NULL) {
- x = PyDict_GetItem(lib->l_types_builder->known_constants, name);
- if (x != NULL) {
- Py_INCREF(x);
- goto found;
- }
- }
-
if (lib->l_includes != NULL) {
Py_ssize_t i;
@@ -232,7 +224,7 @@
{
/* a constant integer whose value, in an "unsigned long long",
is obtained by calling the function at g->address */
- x = realize_global_int(g);
+ x = realize_global_int(lib->l_types_builder, index);
break;
}
diff --git a/_cffi1/manual2.py b/_cffi1/manual2.py
--- a/_cffi1/manual2.py
+++ b/_cffi1/manual2.py
@@ -3,11 +3,10 @@
ffi = _cffi_backend.FFI(b"manual2",
_version = 0x2600,
_types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x00\x09\x00\x00\x00\x0B\x00\x00\x01\x03',
- _globals = (b'\x00\x00\x00#close',b'\x00\x00\x05#stdout'),
- _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x00point_s',b'\x00\x00\x01\x11x',b'\x00\x00\x01\x11y'),),
- _enums = (b'\x00\x00\x00\x04\x00\x00\x00\x01myenum_e\x00AA,BB,CC',),
+ _globals = (b'\xff\xff\xff\x0bAA',0,b'\xff\xff\xff\x0bBB',1,b'\xff\xff\xff\x0bCC',2,b'\x00\x00\x00\x1fFOO',-42,b'\x00\x00\x00#close',0,b'\x00\x00\x05#stdout',0),
+ _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x00point_s',b'\x00\x00\x01\x11\xff\xff\xff\xffx',b'\x00\x00\x01\x11\xff\xff\xff\xffy'),),
+ _enums = (b'\x00\x00\x00\x04\x00\x00\x00\x07myenum_e\x00AA,BB,CC',),
_typenames = (b'\x00\x00\x00\x01myint_t',),
- _consts = {'AA':0,'BB':1,'CC':2},
)
@@ -15,6 +14,7 @@
# trying it out
lib = ffi.dlopen(None)
assert lib.BB == 1
+assert lib.FOO == -42
x = lib.close(-42)
assert x == -1
@@ -24,4 +24,6 @@
print ffi.offsetof("struct point_s", "x")
print ffi.offsetof("struct point_s", "y")
-del ffi
+print ffi.cast("enum myenum_e", 2)
+
+del ffi, lib
diff --git a/_cffi1/parse_c_type.c b/_cffi1/parse_c_type.c
--- a/_cffi1/parse_c_type.c
+++ b/_cffi1/parse_c_type.c
@@ -370,16 +370,21 @@
g = &tok->info->ctx->globals[gindex];
if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT ||
_CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) {
- unsigned long long value;
- int neg = ((int(*)(unsigned long long*))g->address)
- (&value);
- if (!neg && value > MAX_SSIZE_T)
+ struct _cffi_getconst_s gc;
+ gc.ctx = tok->info->ctx;
+ gc.gindex = gindex;
+ int neg = ((int(*)(struct _cffi_getconst_s*))g->address)
+ (&gc);
+ if (neg == 0 && gc.value > MAX_SSIZE_T)
return parse_error(tok,
"integer constant too large");
- if (!neg || value == 0) {
- length = (size_t)value;
+ if (neg == 0 || gc.value == 0) {
+ length = (size_t)gc.value;
break;
}
+ if (neg != 1)
+ return parse_error(tok, "disagreement about"
+ " this constant's value");
}
}
/* fall-through to the default case */
diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h
--- a/_cffi1/parse_c_type.h
+++ b/_cffi1/parse_c_type.h
@@ -84,6 +84,12 @@
size_t size; // 0 if unknown
};
+struct _cffi_getconst_s {
+ unsigned long long value;
+ const struct _cffi_type_context_s *ctx;
+ int gindex;
+};
+
struct _cffi_struct_union_s {
const char *name;
int type_index; // -> _cffi_types, on a OP_STRUCT_UNION
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -3,7 +3,6 @@
struct _cffi_type_context_s ctx; /* inlined substructure */
PyObject *types_dict;
PyObject *included_ffis;
- PyObject *known_constants;
PyObject *_keepalive1;
PyObject *_keepalive2;
} builder_c_t;
@@ -73,7 +72,6 @@
}
Py_XDECREF(builder->included_ffis);
Py_XDECREF(builder->types_dict);
- Py_XDECREF(builder->known_constants);
Py_XDECREF(builder->_keepalive1);
Py_XDECREF(builder->_keepalive2);
}
@@ -92,7 +90,6 @@
builder->types_dict = ldict;
builder->included_ffis = NULL;
- builder->known_constants = NULL;
builder->_keepalive1 = NULL;
builder->_keepalive2 = NULL;
return 0;
@@ -170,13 +167,22 @@
return x;
}
-static PyObject *realize_global_int(const struct _cffi_global_s *g)
+static PyObject *realize_global_int(builder_c_t *builder, int gindex)
{
+ int neg;
char got[64];
unsigned long long value;
+ struct _cffi_getconst_s gc;
+ const struct _cffi_global_s *g = &builder->ctx.globals[gindex];
+ gc.ctx = &builder->ctx;
+ gc.gindex = gindex;
/* note: we cast g->address to this function type; we do the same
- in parse_c_type:parse_sequel() too */
- int neg = ((int(*)(unsigned long long*))g->address)(&value);
+ in parse_c_type:parse_sequel() too. Note that the called function
+ may be declared simply with "unsigned long long *" as argument,
+ which is fine as it is the first field in _cffi_getconst_s. */
+ assert(&gc.value == (unsigned long long *)&gc);
+ neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc);
+ value = gc.value;
switch (neg) {
@@ -440,7 +446,6 @@
PyObject *enumerators = NULL, *enumvalues = NULL, *tmp;
Py_ssize_t i, j, n = 0;
const char *p;
- const struct _cffi_global_s *g;
int gindex;
PyObject *args;
PyObject *basetd = get_primitive_type(e->type_prim);
@@ -474,10 +479,10 @@
gindex = search_in_globals(&builder->ctx, p, j);
assert(gindex >= 0);
- g = &builder->ctx.globals[gindex];
- assert(g->type_op == _CFFI_OP(_CFFI_OP_ENUM, -1));
+ assert(builder->ctx.globals[gindex].type_op ==
+ _CFFI_OP(_CFFI_OP_ENUM, -1));
- tmp = realize_global_int(g);
+ tmp = realize_global_int(builder, gindex);
if (tmp == NULL)
break;
PyTuple_SET_ITEM(enumvalues, i, tmp);
More information about the pypy-commit
mailing list