Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1971:758808b32477 Date: 2015-05-11 15:36 +0200 http://bitbucket.org/cffi/cffi/changeset/758808b32477/
Log: Reasonably messy to implement: ffi.addressof(lib, "var") diff --git a/_cffi1/cglob.c b/_cffi1/cglob.c --- a/_cffi1/cglob.c +++ b/_cffi1/cglob.c @@ -60,9 +60,13 @@ return convert_from_object(gs->gs_data, gs->gs_type, obj); } -#if 0 -static PyObject *addressof_global_var(GlobSupportObject *gs) +static PyObject *cg_addressof_global_var(GlobSupportObject *gs) { - return new_simple_cdata(gs->gs_data, gs->gs_type); + 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; } -#endif diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c --- a/_cffi1/ffi_obj.c +++ b/_cffi1/ffi_obj.c @@ -19,6 +19,7 @@ #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 @@ -368,10 +369,19 @@ } PyDoc_STRVAR(ffi_addressof_doc, -"With a single arg, return the address of a <cdata 'struct-or-union'>.\n" -"If 'fields_or_indexes' are given, returns the address of that field or\n" -"array item in the structure or array, recursively in case of nested\n" -"structures."); +"Limited equivalent to the '&' operator in C:\n" +"\n" +"1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a\n" +"pointer to this struct or union.\n" +"\n" +"2. ffi.addressof(<cdata>, field-or-index...) returns the address of a\n" +"field or array item inside the given structure or array, recursively\n" +"in case of nested structures or arrays.\n" +"\n" +"3. ffi.addressof(<library>, \"name\") returns the address of the named\n" +"global variable."); + +static PyObject *address_of_global_var(PyObject *args); /* forward */ static PyObject *ffi_addressof(FFIObject *self, PyObject *args) { @@ -387,11 +397,17 @@ } arg = PyTuple_GET_ITEM(args, 0); + if (LibObject_Check(arg)) { + /* case 3 in the docstring */ + return address_of_global_var(args); + } + ct = _ffi_type(self, arg, ACCEPT_CDATA); if (ct == NULL) return NULL; if (PyTuple_GET_SIZE(args) == 1) { + /* case 1 in the docstring */ accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY; if ((ct->ct_flags & accepted_flags) == 0) { PyErr_SetString(PyExc_TypeError, @@ -400,6 +416,7 @@ } } else { + /* case 2 in the docstring */ accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; if ((ct->ct_flags & accepted_flags) == 0) { PyErr_SetString(PyExc_TypeError, diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c --- a/_cffi1/lib_obj.c +++ b/_cffi1/lib_obj.c @@ -27,15 +27,9 @@ FFIObject *l_ffi; /* reference back to the ffi object */ }; -#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type)) - -static PyObject *_cpyextfunc_type_index(PyObject *x) +static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) { struct CPyExtFunc_s *exf; - LibObject *lib; - PyObject *tuple, *result; - - assert(PyErr_Occurred()); if (!PyCFunction_Check(x)) return NULL; @@ -46,6 +40,20 @@ if (exf->md.ml_doc != cpyextfunc_doc) return NULL; + return exf; +} + +static PyObject *_cpyextfunc_type_index(PyObject *x) +{ + struct CPyExtFunc_s *exf; + LibObject *lib; + PyObject *tuple, *result; + + assert(PyErr_Occurred()); + exf = _cpyextfunc_get(x); + if (exf == NULL) + return NULL; /* still the same exception is set */ + PyErr_Clear(); lib = (LibObject *)PyCFunction_GET_SELF(x); @@ -269,14 +277,21 @@ return x; } +#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ + do { \ + x = PyDict_GetItem(lib->l_dict, name); \ + if (x == NULL) { \ + x = lib_build_and_cache_attr(lib, name, 0); \ + if (x == NULL) { \ + error; \ + } \ + } \ + } while (0) + static PyObject *lib_getattr(LibObject *lib, PyObject *name) { - PyObject *x = PyDict_GetItem(lib->l_dict, name); - if (x == NULL) { - x = lib_build_and_cache_attr(lib, name, 0); - if (x == NULL) - return NULL; - } + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, return NULL); if (GlobSupport_Check(x)) { return read_global_var((GlobSupportObject *)x); @@ -287,12 +302,8 @@ static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) { - PyObject *x = PyDict_GetItem(lib->l_dict, name); - if (x == NULL) { - x = lib_build_and_cache_attr(lib, name, 0); - if (x == NULL) - return -1; - } + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); if (val == NULL) { PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); @@ -396,3 +407,44 @@ lib->l_ffi = ffi; return lib; } + +static PyObject *address_of_global_var(PyObject *args) +{ + LibObject *lib; + PyObject *x, *o_varname; + char *varname; + + if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) + return NULL; + + /* rebuild a string from 'varname', to do typechecks and to force + a unicode back to a plain string */ + o_varname = PyString_FromString(varname); + if (o_varname == NULL) + return NULL; + + LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); + Py_DECREF(o_varname); + if (GlobSupport_Check(x)) { + return cg_addressof_global_var((GlobSupportObject *)x); + } + else { + struct CPyExtFunc_s *exf = _cpyextfunc_get(x); + if (exf != NULL || /* an OP_CPYTHON_BLTN: '&func' is 'func' in C */ + ((CData_Check(x) && /* or, a constant functionptr cdata: same */ + (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0))) { + Py_INCREF(x); + return x; + } + else { + PyErr_Format(PyExc_AttributeError, + "cannot take the address of the constant '%.200s'", + varname); + return NULL; + } + } + + error: + Py_DECREF(o_varname); + return NULL; +} diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py --- a/_cffi1/test_recompiler.py +++ b/_cffi1/test_recompiler.py @@ -707,3 +707,39 @@ assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>" assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>" assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>" + +def test_address_of_global_var(): + ffi = FFI() + ffi.cdef(""" + long bottom, bottoms[2]; + long FetchRectBottom(void); + long FetchRectBottoms1(void); + #define FOOBAR 42 + """) + lib = verify(ffi, "test_address_of_global_var", """ + long bottom, bottoms[2]; + long FetchRectBottom(void) { return bottom; } + long FetchRectBottoms1(void) { return bottoms[1]; } + #define FOOBAR 42 + """) + lib.bottom = 300 + assert lib.FetchRectBottom() == 300 + lib.bottom += 1 + assert lib.FetchRectBottom() == 301 + lib.bottoms[1] = 500 + assert lib.FetchRectBottoms1() == 500 + lib.bottoms[1] += 2 + assert lib.FetchRectBottoms1() == 502 + # + p = ffi.addressof(lib, 'bottom') + assert ffi.typeof(p) == ffi.typeof("long *") + assert p[0] == 301 + p[0] += 1 + assert lib.FetchRectBottom() == 302 + p = ffi.addressof(lib, 'bottoms') + assert ffi.typeof(p) == ffi.typeof("long(*)[2]") + assert p[0] == lib.bottoms + # + py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var') + py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR") + assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit