[Python-checkins] r51277 - in python/trunk: Lib/ctypes/__init__.py Lib/ctypes/test/test_as_parameter.py Lib/ctypes/test/test_numbers.py Lib/ctypes/test/test_prototypes.py Misc/NEWS Modules/_ctypes/_ctypes.c Modules/_ctypes/callproc.c Modules/_ctypes/ctypes.h

thomas.heller python-checkins at python.org
Mon Aug 14 13:17:49 CEST 2006


Author: thomas.heller
Date: Mon Aug 14 13:17:48 2006
New Revision: 51277

Added:
   python/trunk/Lib/ctypes/test/test_as_parameter.py   (contents, props changed)
Modified:
   python/trunk/Lib/ctypes/__init__.py
   python/trunk/Lib/ctypes/test/test_numbers.py
   python/trunk/Lib/ctypes/test/test_prototypes.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/_ctypes/_ctypes.c
   python/trunk/Modules/_ctypes/callproc.c
   python/trunk/Modules/_ctypes/ctypes.h
Log:
Apply the patch #1532975 plus ideas from the patch #1533481.

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.

Modified: python/trunk/Lib/ctypes/__init__.py
==============================================================================
--- python/trunk/Lib/ctypes/__init__.py	(original)
+++ python/trunk/Lib/ctypes/__init__.py	Mon Aug 14 13:17:48 2006
@@ -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

Added: python/trunk/Lib/ctypes/test/test_as_parameter.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/ctypes/test/test_as_parameter.py	Mon Aug 14 13:17:48 2006
@@ -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()

Modified: python/trunk/Lib/ctypes/test/test_numbers.py
==============================================================================
--- python/trunk/Lib/ctypes/test/test_numbers.py	(original)
+++ python/trunk/Lib/ctypes/test/test_numbers.py	Mon Aug 14 13:17:48 2006
@@ -19,7 +19,7 @@
         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 @@
         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:

Modified: python/trunk/Lib/ctypes/test/test_prototypes.py
==============================================================================
--- python/trunk/Lib/ctypes/test/test_prototypes.py	(original)
+++ python/trunk/Lib/ctypes/test/test_prototypes.py	Mon Aug 14 13:17:48 2006
@@ -125,13 +125,18 @@
             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

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon Aug 14 13:17:48 2006
@@ -66,6 +66,10 @@
 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.

Modified: python/trunk/Modules/_ctypes/_ctypes.c
==============================================================================
--- python/trunk/Modules/_ctypes/_ctypes.c	(original)
+++ python/trunk/Modules/_ctypes/_ctypes.c	Mon Aug 14 13:17:48 2006
@@ -140,6 +140,31 @@
   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 @@
 	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 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 @@
 	}
 /* ... 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 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 @@
 			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 @@
 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 @@
 			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 @@
 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 @@
 			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 @@
 	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 @@
 	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 @@
 /*
  * 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 @@
 	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 @@
 	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 @@
 
 }
 
+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 @@
 	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 @@
   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 @@
 	{ "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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 #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));

Modified: python/trunk/Modules/_ctypes/callproc.c
==============================================================================
--- python/trunk/Modules/_ctypes/callproc.c	(original)
+++ python/trunk/Modules/_ctypes/callproc.c	Mon Aug 14 13:17:48 2006
@@ -465,7 +465,21 @@
  */
 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 @@
 		   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 (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;
+		if (arg) {
+			int result;
+			result = ConvParam(arg, index, pa);
+			Py_DECREF(arg);
+			return result;
 		}
-		Py_DECREF(arg);
 		PyErr_Format(PyExc_TypeError,
 			     "Don't know how to convert parameter %d", index);
 		return -1;

Modified: python/trunk/Modules/_ctypes/ctypes.h
==============================================================================
--- python/trunk/Modules/_ctypes/ctypes.h	(original)
+++ python/trunk/Modules/_ctypes/ctypes.h	Mon Aug 14 13:17:48 2006
@@ -23,9 +23,11 @@
 #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 @@
 	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 @@
 
 #define DICTFLAG_FINAL 0x1000
 
-typedef struct {
+struct tagPyCArgObject {
 	PyObject_HEAD
 	ffi_type *pffi_type;
 	char tag;
@@ -302,7 +305,7 @@
 	} value;
 	PyObject *obj;
 	int size; /* for the 'V' tag */
-} PyCArgObject;
+};
 
 extern PyTypeObject PyCArg_Type;
 extern PyCArgObject *new_CArgObject(void);


More information about the Python-checkins mailing list