mirror of
https://github.com/python/cpython.git
synced 2025-11-25 04:34:37 +00:00
ctypes instances no longer have the internal and undocumented '_as_parameter_' attribute which was used to adapt them to foreign function calls; this mechanism is replaced by a function pointer in the type's stgdict. In the 'from_param' class methods, try the _as_parameter_ attribute if other conversions are not possible. This makes the documented _as_parameter_ mechanism work as intended. Change the ctypes version number to 1.0.1.
This commit is contained in:
parent
040f76b79c
commit
867200483b
8 changed files with 412 additions and 182 deletions
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import os as _os, sys as _sys
|
||||
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.0.1"
|
||||
|
||||
from _ctypes import Union, Structure, Array
|
||||
from _ctypes import _Pointer
|
||||
|
|
|
|||
214
Lib/ctypes/test/test_as_parameter.py
Normal file
214
Lib/ctypes/test/test_as_parameter.py
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
import unittest
|
||||
from ctypes import *
|
||||
import _ctypes_test
|
||||
|
||||
dll = CDLL(_ctypes_test.__file__)
|
||||
|
||||
try:
|
||||
CALLBACK_FUNCTYPE = WINFUNCTYPE
|
||||
except NameError:
|
||||
# fake to enable this test on Linux
|
||||
CALLBACK_FUNCTYPE = CFUNCTYPE
|
||||
|
||||
class POINT(Structure):
|
||||
_fields_ = [("x", c_int), ("y", c_int)]
|
||||
|
||||
class BasicWrapTestCase(unittest.TestCase):
|
||||
def wrap(self, param):
|
||||
return param
|
||||
|
||||
def test_wchar_parm(self):
|
||||
try:
|
||||
c_wchar
|
||||
except NameError:
|
||||
return
|
||||
f = dll._testfunc_i_bhilfd
|
||||
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
|
||||
result = f(self.wrap(1), self.wrap(u"x"), self.wrap(3), self.wrap(4), self.wrap(5.0), self.wrap(6.0))
|
||||
self.failUnlessEqual(result, 139)
|
||||
self.failUnless(type(result), int)
|
||||
|
||||
def test_pointers(self):
|
||||
f = dll._testfunc_p_p
|
||||
f.restype = POINTER(c_int)
|
||||
f.argtypes = [POINTER(c_int)]
|
||||
|
||||
# This only works if the value c_int(42) passed to the
|
||||
# function is still alive while the pointer (the result) is
|
||||
# used.
|
||||
|
||||
v = c_int(42)
|
||||
|
||||
self.failUnlessEqual(pointer(v).contents.value, 42)
|
||||
result = f(self.wrap(pointer(v)))
|
||||
self.failUnlessEqual(type(result), POINTER(c_int))
|
||||
self.failUnlessEqual(result.contents.value, 42)
|
||||
|
||||
# This on works...
|
||||
result = f(self.wrap(pointer(v)))
|
||||
self.failUnlessEqual(result.contents.value, v.value)
|
||||
|
||||
p = pointer(c_int(99))
|
||||
result = f(self.wrap(p))
|
||||
self.failUnlessEqual(result.contents.value, 99)
|
||||
|
||||
def test_shorts(self):
|
||||
f = dll._testfunc_callback_i_if
|
||||
|
||||
args = []
|
||||
expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
|
||||
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
|
||||
|
||||
def callback(v):
|
||||
args.append(v)
|
||||
|
||||
CallBack = CFUNCTYPE(c_int, c_int)
|
||||
|
||||
cb = CallBack(callback)
|
||||
f(self.wrap(2**18), self.wrap(cb))
|
||||
self.failUnlessEqual(args, expected)
|
||||
|
||||
################################################################
|
||||
|
||||
def test_callbacks(self):
|
||||
f = dll._testfunc_callback_i_if
|
||||
f.restype = c_int
|
||||
|
||||
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||
|
||||
def callback(value):
|
||||
#print "called back with", value
|
||||
return value
|
||||
|
||||
cb = MyCallback(callback)
|
||||
|
||||
result = f(self.wrap(-10), self.wrap(cb))
|
||||
self.failUnlessEqual(result, -18)
|
||||
|
||||
# test with prototype
|
||||
f.argtypes = [c_int, MyCallback]
|
||||
cb = MyCallback(callback)
|
||||
|
||||
result = f(self.wrap(-10), self.wrap(cb))
|
||||
self.failUnlessEqual(result, -18)
|
||||
|
||||
result = f(self.wrap(-10), self.wrap(cb))
|
||||
self.failUnlessEqual(result, -18)
|
||||
|
||||
AnotherCallback = CALLBACK_FUNCTYPE(c_int, c_int, c_int, c_int, c_int)
|
||||
|
||||
# check that the prototype works: we call f with wrong
|
||||
# argument types
|
||||
cb = AnotherCallback(callback)
|
||||
self.assertRaises(ArgumentError, f, self.wrap(-10), self.wrap(cb))
|
||||
|
||||
def test_callbacks_2(self):
|
||||
# Can also use simple datatypes as argument type specifiers
|
||||
# for the callback function.
|
||||
# In this case the call receives an instance of that type
|
||||
f = dll._testfunc_callback_i_if
|
||||
f.restype = c_int
|
||||
|
||||
MyCallback = CFUNCTYPE(c_int, c_int)
|
||||
|
||||
f.argtypes = [c_int, MyCallback]
|
||||
|
||||
def callback(value):
|
||||
#print "called back with", value
|
||||
self.failUnlessEqual(type(value), int)
|
||||
return value
|
||||
|
||||
cb = MyCallback(callback)
|
||||
result = f(self.wrap(-10), self.wrap(cb))
|
||||
self.failUnlessEqual(result, -18)
|
||||
|
||||
def test_longlong_callbacks(self):
|
||||
|
||||
f = dll._testfunc_callback_q_qf
|
||||
f.restype = c_longlong
|
||||
|
||||
MyCallback = CFUNCTYPE(c_longlong, c_longlong)
|
||||
|
||||
f.argtypes = [c_longlong, MyCallback]
|
||||
|
||||
def callback(value):
|
||||
self.failUnless(isinstance(value, (int, long)))
|
||||
return value & 0x7FFFFFFF
|
||||
|
||||
cb = MyCallback(callback)
|
||||
|
||||
self.failUnlessEqual(13577625587, int(f(self.wrap(1000000000000), self.wrap(cb))))
|
||||
|
||||
def test_byval(self):
|
||||
# without prototype
|
||||
ptin = POINT(1, 2)
|
||||
ptout = POINT()
|
||||
# EXPORT int _testfunc_byval(point in, point *pout)
|
||||
result = dll._testfunc_byval(ptin, byref(ptout))
|
||||
got = result, ptout.x, ptout.y
|
||||
expected = 3, 1, 2
|
||||
self.failUnlessEqual(got, expected)
|
||||
|
||||
# with prototype
|
||||
ptin = POINT(101, 102)
|
||||
ptout = POINT()
|
||||
dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
|
||||
dll._testfunc_byval.restype = c_int
|
||||
result = dll._testfunc_byval(self.wrap(ptin), byref(ptout))
|
||||
got = result, ptout.x, ptout.y
|
||||
expected = 203, 101, 102
|
||||
self.failUnlessEqual(got, expected)
|
||||
|
||||
def test_struct_return_2H(self):
|
||||
class S2H(Structure):
|
||||
_fields_ = [("x", c_short),
|
||||
("y", c_short)]
|
||||
dll.ret_2h_func.restype = S2H
|
||||
dll.ret_2h_func.argtypes = [S2H]
|
||||
inp = S2H(99, 88)
|
||||
s2h = dll.ret_2h_func(self.wrap(inp))
|
||||
self.failUnlessEqual((s2h.x, s2h.y), (99*2, 88*3))
|
||||
|
||||
def test_struct_return_8H(self):
|
||||
class S8I(Structure):
|
||||
_fields_ = [("a", c_int),
|
||||
("b", c_int),
|
||||
("c", c_int),
|
||||
("d", c_int),
|
||||
("e", c_int),
|
||||
("f", c_int),
|
||||
("g", c_int),
|
||||
("h", c_int)]
|
||||
dll.ret_8i_func.restype = S8I
|
||||
dll.ret_8i_func.argtypes = [S8I]
|
||||
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
|
||||
s8i = dll.ret_8i_func(self.wrap(inp))
|
||||
self.failUnlessEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
|
||||
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
class AsParamWrapper(object):
|
||||
def __init__(self, param):
|
||||
self._as_parameter_ = param
|
||||
|
||||
class AsParamWrapperTestCase(BasicWrapTestCase):
|
||||
wrap = AsParamWrapper
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
class AsParamPropertyWrapper(object):
|
||||
def __init__(self, param):
|
||||
self._param = param
|
||||
|
||||
def getParameter(self):
|
||||
return self._param
|
||||
_as_parameter_ = property(getParameter)
|
||||
|
||||
class AsParamPropertyWrapperTestCase(BasicWrapTestCase):
|
||||
wrap = AsParamPropertyWrapper
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -19,7 +19,7 @@ def valid_ranges(*types):
|
|||
result.append((min(a, b, c, d), max(a, b, c, d)))
|
||||
return result
|
||||
|
||||
ArgType = type(c_int(0)._as_parameter_)
|
||||
ArgType = type(byref(c_int(0)))
|
||||
|
||||
unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
|
||||
signed_types = [c_byte, c_short, c_int, c_long, c_longlong]
|
||||
|
|
@ -80,19 +80,6 @@ class NumberTestCase(unittest.TestCase):
|
|||
for t in signed_types + unsigned_types + float_types:
|
||||
self.failUnlessEqual(ArgType, type(t.from_param(0)))
|
||||
|
||||
def test_as_parameter(self):
|
||||
# The _as_parameter_ property must also
|
||||
# be a PyCArgObject instance
|
||||
for t in signed_types + unsigned_types + float_types:
|
||||
parm = t()._as_parameter_
|
||||
self.failUnlessEqual(ArgType, type(parm))
|
||||
|
||||
# _as_parameter_ is readonly!
|
||||
#
|
||||
# Python 2.3 and 2.4 raise a TypeError when trying to set
|
||||
# a readonly attribute, 2.5 raises an AttributeError.
|
||||
self.assertRaises((AttributeError, TypeError), setattr, t(), "_as_parameter_", None)
|
||||
|
||||
def test_byref(self):
|
||||
# calling byref returns also a PyCArgObject instance
|
||||
for t in signed_types + unsigned_types + float_types:
|
||||
|
|
|
|||
|
|
@ -125,13 +125,18 @@ class CharPointersTestCase(unittest.TestCase):
|
|||
self.failUnlessEqual(None, func(c_wchar_p(None)))
|
||||
self.failUnlessEqual(u"123", func(c_wchar_p(u"123")))
|
||||
|
||||
## def test_instance(self):
|
||||
## func = testdll._testfunc_p_p
|
||||
def test_instance(self):
|
||||
func = testdll._testfunc_p_p
|
||||
func.restype = c_void_p
|
||||
|
||||
## class X:
|
||||
## _as_parameter_ = 0
|
||||
class X:
|
||||
_as_parameter_ = None
|
||||
|
||||
## self.failUnlessEqual(0, func(X()))
|
||||
func.argtypes = c_void_p,
|
||||
self.failUnlessEqual(None, func(X()))
|
||||
|
||||
func.argtypes = None
|
||||
self.failUnlessEqual(None, func(X()))
|
||||
|
||||
try:
|
||||
c_wchar
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ Library
|
|||
Extension Modules
|
||||
-----------------
|
||||
|
||||
- Patch #1532975 was applied, which fixes Bug #1533481: ctypes now
|
||||
uses the _as_parameter_ attribute when objects are passed to foreign
|
||||
function calls. The ctypes version number was changed to 1.0.1.
|
||||
|
||||
- Bug #1530559, struct.pack raises TypeError where it used to convert.
|
||||
Passing float arguments to struct.pack when integers are expected
|
||||
now triggers a DeprecationWarning.
|
||||
|
|
|
|||
|
|
@ -140,6 +140,31 @@ char *conversion_mode_errors = NULL;
|
|||
accessible fields somehow.
|
||||
*/
|
||||
|
||||
static PyCArgObject *
|
||||
StructUnionType_paramfunc(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
StgDictObject *stgdict;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'V';
|
||||
stgdict = PyObject_stgdict((PyObject *)self);
|
||||
assert(stgdict);
|
||||
parg->pffi_type = &stgdict->ffi_type_pointer;
|
||||
/* For structure parameters (by value), parg->value doesn't contain the structure
|
||||
data itself, instead parg->value.p *points* to the structure's data
|
||||
See also _ctypes.c, function _call_function_pointer().
|
||||
*/
|
||||
parg->value.p = self->b_ptr;
|
||||
parg->size = self->b_size;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
return parg;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isStruct)
|
||||
{
|
||||
|
|
@ -172,6 +197,8 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
|
|||
Py_DECREF(result->tp_dict);
|
||||
result->tp_dict = (PyObject *)dict;
|
||||
|
||||
dict->paramfunc = StructUnionType_paramfunc;
|
||||
|
||||
fields = PyDict_GetItemString((PyObject *)dict, "_fields_");
|
||||
if (!fields) {
|
||||
StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base);
|
||||
|
|
@ -287,6 +314,7 @@ static char from_param_doc[] =
|
|||
static PyObject *
|
||||
CDataType_from_param(PyObject *type, PyObject *value)
|
||||
{
|
||||
PyObject *as_parameter;
|
||||
if (1 == PyObject_IsInstance(value, type)) {
|
||||
Py_INCREF(value);
|
||||
return value;
|
||||
|
|
@ -330,6 +358,13 @@ CDataType_from_param(PyObject *type, PyObject *value)
|
|||
}
|
||||
/* ... and leave the rest */
|
||||
#endif
|
||||
|
||||
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
|
||||
if (as_parameter) {
|
||||
value = CDataType_from_param(type, as_parameter);
|
||||
Py_DECREF(as_parameter);
|
||||
return value;
|
||||
}
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expected %s instance instead of %s",
|
||||
((PyTypeObject *)type)->tp_name,
|
||||
|
|
@ -540,6 +575,23 @@ PointerType_SetProto(StgDictObject *stgdict, PyObject *proto)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyCArgObject *
|
||||
PointerType_paramfunc(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'P';
|
||||
parg->pffi_type = &ffi_type_pointer;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
parg->value.p = *(void **)self->b_ptr;
|
||||
return parg;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
|
@ -563,6 +615,7 @@ PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
stgdict->align = getentry("P")->pffi_type->alignment;
|
||||
stgdict->length = 1;
|
||||
stgdict->ffi_type_pointer = ffi_type_pointer;
|
||||
stgdict->paramfunc = PointerType_paramfunc;
|
||||
|
||||
proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */
|
||||
if (proto && -1 == PointerType_SetProto(stgdict, proto)) {
|
||||
|
|
@ -906,6 +959,19 @@ add_getset(PyTypeObject *type, PyGetSetDef *gsp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyCArgObject *
|
||||
ArrayType_paramfunc(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *p = new_CArgObject();
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p->tag = 'P';
|
||||
p->pffi_type = &ffi_type_pointer;
|
||||
p->value.p = (char *)self->b_ptr;
|
||||
Py_INCREF(self);
|
||||
p->obj = (PyObject *)self;
|
||||
return p;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
|
|
@ -961,6 +1027,8 @@ ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
Py_INCREF(proto);
|
||||
stgdict->proto = proto;
|
||||
|
||||
stgdict->paramfunc = &ArrayType_paramfunc;
|
||||
|
||||
/* Arrays are passed as pointers to function calls. */
|
||||
stgdict->ffi_type_pointer = ffi_type_pointer;
|
||||
|
||||
|
|
@ -1055,6 +1123,7 @@ static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv";
|
|||
static PyObject *
|
||||
c_wchar_p_from_param(PyObject *type, PyObject *value)
|
||||
{
|
||||
PyObject *as_parameter;
|
||||
#if (PYTHON_API_VERSION < 1012)
|
||||
# error not supported
|
||||
#endif
|
||||
|
|
@ -1100,6 +1169,13 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
|
|||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
|
||||
if (as_parameter) {
|
||||
value = c_wchar_p_from_param(type, as_parameter);
|
||||
Py_DECREF(as_parameter);
|
||||
return value;
|
||||
}
|
||||
/* XXX better message */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"wrong type");
|
||||
|
|
@ -1109,6 +1185,7 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
|
|||
static PyObject *
|
||||
c_char_p_from_param(PyObject *type, PyObject *value)
|
||||
{
|
||||
PyObject *as_parameter;
|
||||
#if (PYTHON_API_VERSION < 1012)
|
||||
# error not supported
|
||||
#endif
|
||||
|
|
@ -1154,6 +1231,13 @@ c_char_p_from_param(PyObject *type, PyObject *value)
|
|||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
|
||||
if (as_parameter) {
|
||||
value = c_char_p_from_param(type, as_parameter);
|
||||
Py_DECREF(as_parameter);
|
||||
return value;
|
||||
}
|
||||
/* XXX better message */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"wrong type");
|
||||
|
|
@ -1164,6 +1248,7 @@ static PyObject *
|
|||
c_void_p_from_param(PyObject *type, PyObject *value)
|
||||
{
|
||||
StgDictObject *stgd;
|
||||
PyObject *as_parameter;
|
||||
#if (PYTHON_API_VERSION < 1012)
|
||||
# error not supported
|
||||
#endif
|
||||
|
|
@ -1275,6 +1360,13 @@ c_void_p_from_param(PyObject *type, PyObject *value)
|
|||
return (PyObject *)parg;
|
||||
}
|
||||
}
|
||||
|
||||
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
|
||||
if (as_parameter) {
|
||||
value = c_void_p_from_param(type, as_parameter);
|
||||
Py_DECREF(as_parameter);
|
||||
return value;
|
||||
}
|
||||
/* XXX better message */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"wrong type");
|
||||
|
|
@ -1361,6 +1453,33 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
|
|||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
static PyCArgObject *
|
||||
SimpleType_paramfunc(CDataObject *self)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
char *fmt;
|
||||
PyCArgObject *parg;
|
||||
struct fielddesc *fd;
|
||||
|
||||
dict = PyObject_stgdict((PyObject *)self);
|
||||
assert(dict);
|
||||
fmt = PyString_AsString(dict->proto);
|
||||
assert(fmt);
|
||||
|
||||
fd = getentry(fmt);
|
||||
assert(fd);
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = fmt[0];
|
||||
parg->pffi_type = fd->pffi_type;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
memcpy(&parg->value, self->b_ptr, self->b_size);
|
||||
return parg;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
|
|
@ -1410,6 +1529,8 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
stgdict->size = fmt->pffi_type->size;
|
||||
stgdict->setfunc = fmt->setfunc;
|
||||
stgdict->getfunc = fmt->getfunc;
|
||||
|
||||
stgdict->paramfunc = SimpleType_paramfunc;
|
||||
/*
|
||||
if (result->tp_base != &Simple_Type) {
|
||||
stgdict->setfunc = NULL;
|
||||
|
|
@ -1508,23 +1629,6 @@ SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
/*
|
||||
* This is a *class method*.
|
||||
* Convert a parameter into something that ConvParam can handle.
|
||||
*
|
||||
* This is either an instance of the requested type, a Python integer, or a
|
||||
* 'magic' 3-tuple.
|
||||
*
|
||||
* (These are somewhat related to Martin v. Loewis 'Enhanced Argument Tuples',
|
||||
* described in PEP 286.)
|
||||
*
|
||||
* The tuple must contain
|
||||
*
|
||||
* - a format character, currently 'ifdqc' are understood
|
||||
* which will inform ConvParam about how to push the argument on the stack.
|
||||
*
|
||||
* - a corresponding Python object: i - integer, f - float, d - float,
|
||||
* q - longlong, c - integer
|
||||
*
|
||||
* - any object which can be used to keep the original parameter alive
|
||||
* as long as the tuple lives.
|
||||
*/
|
||||
static PyObject *
|
||||
SimpleType_from_param(PyObject *type, PyObject *value)
|
||||
|
|
@ -1533,6 +1637,7 @@ SimpleType_from_param(PyObject *type, PyObject *value)
|
|||
char *fmt;
|
||||
PyCArgObject *parg;
|
||||
struct fielddesc *fd;
|
||||
PyObject *as_parameter;
|
||||
|
||||
/* If the value is already an instance of the requested type,
|
||||
we can use it as is */
|
||||
|
|
@ -1558,11 +1663,20 @@ SimpleType_from_param(PyObject *type, PyObject *value)
|
|||
parg->tag = fmt[0];
|
||||
parg->pffi_type = fd->pffi_type;
|
||||
parg->obj = fd->setfunc(&parg->value, value, 0);
|
||||
if (parg->obj == NULL) {
|
||||
Py_DECREF(parg);
|
||||
return NULL;
|
||||
if (parg->obj)
|
||||
return (PyObject *)parg;
|
||||
PyErr_Clear();
|
||||
Py_DECREF(parg);
|
||||
|
||||
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
|
||||
if (as_parameter) {
|
||||
value = SimpleType_from_param(type, as_parameter);
|
||||
Py_DECREF(as_parameter);
|
||||
return value;
|
||||
}
|
||||
return (PyObject *)parg;
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"wrong type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyMethodDef SimpleType_methods[] = {
|
||||
|
|
@ -1727,6 +1841,23 @@ make_funcptrtype_dict(StgDictObject *stgdict)
|
|||
|
||||
}
|
||||
|
||||
static PyCArgObject *
|
||||
CFuncPtrType_paramfunc(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'P';
|
||||
parg->pffi_type = &ffi_type_pointer;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
parg->value.p = *(void **)self->b_ptr;
|
||||
return parg;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
CFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
|
@ -1738,6 +1869,8 @@ CFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
if (!stgdict)
|
||||
return NULL;
|
||||
|
||||
stgdict->paramfunc = CFuncPtrType_paramfunc;
|
||||
|
||||
/* create the new instance (which is a class,
|
||||
since we are a metatype!) */
|
||||
result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
|
||||
|
|
@ -2314,23 +2447,6 @@ GenericCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
CFuncPtr_Type
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
CFuncPtr_as_parameter(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'P';
|
||||
parg->pffi_type = &ffi_type_pointer;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
parg->value.p = *(void **)self->b_ptr;
|
||||
return (PyObject *)parg;
|
||||
}
|
||||
|
||||
static int
|
||||
CFuncPtr_set_errcheck(CFuncPtrObject *self, PyObject *ob)
|
||||
{
|
||||
|
|
@ -2450,9 +2566,6 @@ static PyGetSetDef CFuncPtr_getsets[] = {
|
|||
{ "argtypes", (getter)CFuncPtr_get_argtypes,
|
||||
(setter)CFuncPtr_set_argtypes,
|
||||
"specify the argument types", NULL },
|
||||
{ "_as_parameter_", (getter)CFuncPtr_as_parameter, NULL,
|
||||
"return a magic value so that this can be converted to a C parameter (readonly)",
|
||||
NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -3361,30 +3474,6 @@ IBUG(char *msg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Struct_as_parameter(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
StgDictObject *stgdict;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'V';
|
||||
stgdict = PyObject_stgdict((PyObject *)self);
|
||||
parg->pffi_type = &stgdict->ffi_type_pointer;
|
||||
/* For structure parameters (by value), parg->value doesn't contain the structure
|
||||
data itself, instead parg->value.p *points* to the structure's data
|
||||
See also _ctypes.c, function _call_function_pointer().
|
||||
*/
|
||||
parg->value.p = self->b_ptr;
|
||||
parg->size = self->b_size;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
return (PyObject *)parg;
|
||||
}
|
||||
|
||||
static int
|
||||
Struct_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
|
|
@ -3459,13 +3548,6 @@ Struct_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef Struct_getsets[] = {
|
||||
{ "_as_parameter_", (getter)Struct_as_parameter, NULL,
|
||||
"return a magic value so that this can be converted to a C parameter (readonly)",
|
||||
NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static PyTypeObject Struct_Type = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0,
|
||||
|
|
@ -3497,7 +3579,7 @@ static PyTypeObject Struct_Type = {
|
|||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Struct_getsets, /* tp_getset */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
|
|
@ -3540,7 +3622,7 @@ static PyTypeObject Union_Type = {
|
|||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Struct_getsets, /* tp_getset */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
|
|
@ -3738,26 +3820,6 @@ static PySequenceMethods Array_as_sequence = {
|
|||
0, /* sq_inplace_repeat; */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
Array_as_parameter(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *p = new_CArgObject();
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p->tag = 'P';
|
||||
p->pffi_type = &ffi_type_pointer;
|
||||
p->value.p = (char *)self->b_ptr;
|
||||
Py_INCREF(self);
|
||||
p->obj = (PyObject *)self;
|
||||
return (PyObject *)p;
|
||||
}
|
||||
|
||||
static PyGetSetDef Array_getsets[] = {
|
||||
{ "_as_parameter_", (getter)Array_as_parameter,
|
||||
(setter)NULL, "convert to a parameter", NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
PyTypeObject Array_Type = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0,
|
||||
|
|
@ -3789,7 +3851,7 @@ PyTypeObject Array_Type = {
|
|||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Array_getsets, /* tp_getset */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
|
|
@ -3903,35 +3965,9 @@ Simple_get_value(CDataObject *self)
|
|||
return dict->getfunc(self->b_ptr, self->b_size);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Simple_as_parameter(CDataObject *self)
|
||||
{
|
||||
StgDictObject *dict = PyObject_stgdict((PyObject *)self);
|
||||
char *fmt = PyString_AsString(dict->proto);
|
||||
PyCArgObject *parg;
|
||||
struct fielddesc *fd;
|
||||
|
||||
fd = getentry(fmt);
|
||||
assert(fd);
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = fmt[0];
|
||||
parg->pffi_type = fd->pffi_type;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
memcpy(&parg->value, self->b_ptr, self->b_size);
|
||||
return (PyObject *)parg;
|
||||
}
|
||||
|
||||
static PyGetSetDef Simple_getsets[] = {
|
||||
{ "value", (getter)Simple_get_value, (setter)Simple_set_value,
|
||||
"current value", NULL },
|
||||
{ "_as_parameter_", (getter)Simple_as_parameter, NULL,
|
||||
"return a magic value so that this can be converted to a C parameter (readonly)",
|
||||
NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -4206,30 +4242,10 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure)
|
|||
return KeepRef(self, 0, keep);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Pointer_as_parameter(CDataObject *self)
|
||||
{
|
||||
PyCArgObject *parg;
|
||||
|
||||
parg = new_CArgObject();
|
||||
if (parg == NULL)
|
||||
return NULL;
|
||||
|
||||
parg->tag = 'P';
|
||||
parg->pffi_type = &ffi_type_pointer;
|
||||
Py_INCREF(self);
|
||||
parg->obj = (PyObject *)self;
|
||||
parg->value.p = *(void **)self->b_ptr;
|
||||
return (PyObject *)parg;
|
||||
}
|
||||
|
||||
static PyGetSetDef Pointer_getsets[] = {
|
||||
{ "contents", (getter)Pointer_get_contents,
|
||||
(setter)Pointer_set_contents,
|
||||
"the object this pointer points to (read-write)", NULL },
|
||||
{ "_as_parameter_", (getter)Pointer_as_parameter, NULL,
|
||||
"return a magic value so that this can be converted to a C parameter (readonly)",
|
||||
NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -4690,7 +4706,7 @@ init_ctypes(void)
|
|||
#endif
|
||||
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL));
|
||||
PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI));
|
||||
PyModule_AddStringConstant(m, "__version__", "1.0.0");
|
||||
PyModule_AddStringConstant(m, "__version__", "1.0.1");
|
||||
|
||||
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
|
||||
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
|
||||
|
|
|
|||
|
|
@ -465,7 +465,21 @@ struct argument {
|
|||
*/
|
||||
static int ConvParam(PyObject *obj, int index, struct argument *pa)
|
||||
{
|
||||
StgDictObject *dict;
|
||||
pa->keep = NULL; /* so we cannot forget it later */
|
||||
|
||||
dict = PyObject_stgdict(obj);
|
||||
if (dict) {
|
||||
PyCArgObject *carg;
|
||||
assert(dict->paramfunc);
|
||||
/* If it has an stgdict, it is a CDataObject */
|
||||
carg = dict->paramfunc((CDataObject *)obj);
|
||||
pa->ffi_type = carg->pffi_type;
|
||||
memcpy(&pa->value, &carg->value, sizeof(pa->value));
|
||||
pa->keep = (PyObject *)carg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyCArg_CheckExact(obj)) {
|
||||
PyCArgObject *carg = (PyCArgObject *)obj;
|
||||
pa->ffi_type = carg->pffi_type;
|
||||
|
|
@ -548,25 +562,12 @@ static int ConvParam(PyObject *obj, int index, struct argument *pa)
|
|||
as parameters (they have to expose the '_as_parameter_'
|
||||
attribute)
|
||||
*/
|
||||
if (arg == 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Don't know how to convert parameter %d", index);
|
||||
return -1;
|
||||
if (arg) {
|
||||
int result;
|
||||
result = ConvParam(arg, index, pa);
|
||||
Py_DECREF(arg);
|
||||
return result;
|
||||
}
|
||||
if (PyCArg_CheckExact(arg)) {
|
||||
PyCArgObject *carg = (PyCArgObject *)arg;
|
||||
pa->ffi_type = carg->pffi_type;
|
||||
memcpy(&pa->value, &carg->value, sizeof(pa->value));
|
||||
pa->keep = arg;
|
||||
return 0;
|
||||
}
|
||||
if (PyInt_Check(arg)) {
|
||||
pa->ffi_type = &ffi_type_sint;
|
||||
pa->value.i = PyInt_AS_LONG(arg);
|
||||
pa->keep = arg;
|
||||
return 0;
|
||||
}
|
||||
Py_DECREF(arg);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Don't know how to convert parameter %d", index);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ typedef int Py_ssize_t;
|
|||
#define PY_LONG_LONG LONG_LONG
|
||||
#endif
|
||||
|
||||
typedef struct tagPyCArgObject PyCArgObject;
|
||||
typedef struct tagCDataObject CDataObject;
|
||||
typedef PyObject *(* GETFUNC)(void *, unsigned size);
|
||||
typedef PyObject *(* SETFUNC)(void *, PyObject *value, unsigned size);
|
||||
typedef PyCArgObject *(* PARAMFUNC)(CDataObject *obj);
|
||||
|
||||
/* A default buffer in CDataObject, which can be used for small C types. If
|
||||
this buffer is too small, PyMem_Malloc will be called to create a larger one,
|
||||
|
|
@ -205,6 +207,7 @@ typedef struct {
|
|||
PyObject *proto; /* Only for Pointer/ArrayObject */
|
||||
SETFUNC setfunc; /* Only for simple objects */
|
||||
GETFUNC getfunc; /* Only for simple objects */
|
||||
PARAMFUNC paramfunc;
|
||||
|
||||
/* Following fields only used by CFuncPtrType_Type instances */
|
||||
PyObject *argtypes; /* tuple of CDataObjects */
|
||||
|
|
@ -283,7 +286,7 @@ PyObject *_CallProc(PPROC pProc,
|
|||
|
||||
#define DICTFLAG_FINAL 0x1000
|
||||
|
||||
typedef struct {
|
||||
struct tagPyCArgObject {
|
||||
PyObject_HEAD
|
||||
ffi_type *pffi_type;
|
||||
char tag;
|
||||
|
|
@ -302,7 +305,7 @@ typedef struct {
|
|||
} value;
|
||||
PyObject *obj;
|
||||
int size; /* for the 'V' tag */
|
||||
} PyCArgObject;
|
||||
};
|
||||
|
||||
extern PyTypeObject PyCArg_Type;
|
||||
extern PyCArgObject *new_CArgObject(void);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue