]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Merge changes from the upstream version:
authorThomas Heller <theller@ctypes.org>
Fri, 17 Mar 2006 15:52:58 +0000 (15:52 +0000)
committerThomas Heller <theller@ctypes.org>
Fri, 17 Mar 2006 15:52:58 +0000 (15:52 +0000)
- cast is implemented as a foreign function now
- On Windows, it is now possible to access functions exported by ordinal only

Lib/ctypes/__init__.py
Lib/ctypes/test/test_byteswap.py
Lib/ctypes/test/test_cfuncs.py
Lib/ctypes/test/test_loading.py
Lib/ctypes/test/test_sizes.py
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callproc.c

index dd0f640d9f22fcb5250302490e6c578e3831cb43..a005594d66bb77693dd0b24c0c86c1b4b670f225 100644 (file)
@@ -304,10 +304,11 @@ class CDLL(object):
             raise AttributeError, name
         return self.__getitem__(name)
 
-    def __getitem__(self, name):
-        func = self._FuncPtr(name, self)
-        func.__name__ = name
-        setattr(self, name, func)
+    def __getitem__(self, name_or_ordinal):
+        func = self._FuncPtr((name_or_ordinal, self))
+        if not isinstance(name_or_ordinal, (int, long)):
+            func.__name__ = name_or_ordinal
+            setattr(self, name_or_ordinal, func)
         return func
 
 class PyDLL(CDLL):
@@ -384,21 +385,29 @@ if _os.name in ("nt", "ce"):
 
 _pointer_type_cache[None] = c_void_p
 
-# functions
-
-from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, cast
-
 if sizeof(c_uint) == sizeof(c_void_p):
     c_size_t = c_uint
 elif sizeof(c_ulong) == sizeof(c_void_p):
     c_size_t = c_ulong
 
+# functions
+
+from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
+
 ## void *memmove(void *, const void *, size_t);
 memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
 
 ## void *memset(void *, int, size_t)
 memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
 
+def PYFUNCTYPE(restype, *argtypes):
+    class CFunctionType(_CFuncPtr):
+        _argtypes_ = argtypes
+        _restype_ = restype
+        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
+    return CFunctionType
+cast = PYFUNCTYPE(py_object, c_void_p, py_object)(_cast_addr)
+
 _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
 def string_at(ptr, size=0):
     """string_at(addr[, size]) -> string
index 1b31f902298c5a7d9c59f1baa47746de80f40eab..55a264c12c460cda9569715361c05cab0f11e413 100644 (file)
@@ -2,6 +2,7 @@ import sys, unittest, struct, math
 from binascii import hexlify
 
 from ctypes import *
+from ctypes.test import is_resource_enabled
 
 def bin(s):
     return hexlify(buffer(s)).upper()
@@ -149,7 +150,7 @@ class Test(unittest.TestCase):
         self.failUnless(c_char.__ctype_le__ is c_char)
         self.failUnless(c_char.__ctype_be__ is c_char)
 
-    def test_struct_fields(self):
+    def test_struct_fields_1(self):
         if sys.byteorder == "little":
             base = BigEndianStructure
         else:
@@ -198,17 +199,20 @@ class Test(unittest.TestCase):
             pass
         self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
 
-    # crashes on solaris with a core dump.
-    def X_test_struct_fields(self):
+    def test_struct_fields_2(self):
+        # standard packing in struct uses no alignment.
+        # So, we have to align using pad bytes.
+        #
+        # Unaligned accesses will crash Python (on those platforms that
+        # don't allow it, like sparc solaris).
         if sys.byteorder == "little":
             base = BigEndianStructure
-            fmt = ">bhid"
+            fmt = ">bxhid"
         else:
             base = LittleEndianStructure
-            fmt = "<bhid"
+            fmt = "<bxhid"
 
         class S(base):
-            _pack_ = 1 # struct with '<' or '>' uses standard alignment.
             _fields_ = [("b", c_byte),
                         ("h", c_short),
                         ("i", c_int),
@@ -218,5 +222,54 @@ class Test(unittest.TestCase):
         s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
         self.failUnlessEqual(bin(s1), bin(s2))
 
+    if is_resource_enabled("unaligned_access"):
+
+        def test_unaligned_nonnative_struct_fields(self):
+            if sys.byteorder == "little":
+                base = BigEndianStructure
+                fmt = ">b h xi xd"
+            else:
+                base = LittleEndianStructure
+                fmt = "<b h xi xd"
+
+            class S(base):
+                _pack_ = 1
+                _fields_ = [("b", c_byte),
+
+                            ("h", c_short),
+
+                            ("_1", c_byte),
+                            ("i", c_int),
+
+                            ("_2", c_byte),
+                            ("d", c_double)]
+
+            s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
+            s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
+            self.failUnlessEqual(bin(s1), bin(s2))
+
+        def test_unaligned_native_struct_fields(self):
+            if sys.byteorder == "little":
+                fmt = "<b h xi xd"
+            else:
+                base = LittleEndianStructure
+                fmt = ">b h xi xd"
+
+            class S(Structure):
+                _pack_ = 1
+                _fields_ = [("b", c_byte),
+
+                            ("h", c_short),
+
+                            ("_1", c_byte),
+                            ("i", c_int),
+
+                            ("_2", c_byte),
+                            ("d", c_double)]
+
+            s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
+            s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
+            self.failUnlessEqual(bin(s1), bin(s2))
+
 if __name__ == "__main__":
     unittest.main()
index 7c2b28be7cc1b111f19a9162d2c9862c56a4cd22..6e0798d1f4d1c7e31aa27033832b95297c8372b0 100644 (file)
@@ -179,7 +179,7 @@ else:
         def __getattr__(self, name):
             if name[:2] == '__' and name[-2:] == '__':
                 raise AttributeError, name
-            func = self._FuncPtr("s_" + name, self)
+            func = self._FuncPtr(("s_" + name, self))
             setattr(self, name, func)
             return func
 
index 80564b8295bc20f4e0388a1adc4ef952b0d772d9..5a76bb4cfdad63f4c76ded8f38be7df07d87a283 100644 (file)
@@ -17,8 +17,11 @@ class LoaderTest(unittest.TestCase):
             name = "libc.so"
         elif sys.platform == "sunos5":
             name = "libc.so"
+        elif sys.platform.startswith("netbsd"):
+            name = "libc.so"
         else:
             name = "libc.so.6"
+##        print (sys.platform, os.name)
         cdll.load(name)
         self.assertRaises(OSError, cdll.load, self.unknowndll)
 
@@ -37,5 +40,31 @@ class LoaderTest(unittest.TestCase):
             cdll.find(name)
             self.assertRaises(OSError, cdll.find, self.unknowndll)
 
+    def test_load_library(self):
+        if os.name == "nt":
+            windll.load_library("kernel32").GetModuleHandleW
+            windll.LoadLibrary("kernel32").GetModuleHandleW
+            WinDLL("kernel32").GetModuleHandleW
+        elif os.name == "ce":
+            windll.load_library("coredll").GetModuleHandleW
+            windll.LoadLibrary("coredll").GetModuleHandleW
+            WinDLL("coredll").GetModuleHandleW
+
+    def test_load_ordinal_functions(self):
+        if os.name in ("nt", "ce"):
+            import _ctypes_test
+            dll = WinDLL(_ctypes_test.__file__)
+            # We load the same function both via ordinal and name
+            func_ord = dll[2]
+            func_name = dll.GetString
+            # addressof gets the address where the function pointer is stored
+            a_ord = addressof(func_ord)
+            a_name = addressof(func_name)
+            f_ord_addr = c_void_p.from_address(a_ord).value
+            f_name_addr = c_void_p.from_address(a_name).value
+            self.failUnlessEqual(hex(f_ord_addr), hex(f_name_addr))
+
+            self.failUnlessRaises(AttributeError, dll.__getitem__, 1234)
+
 if __name__ == "__main__":
     unittest.main()
index 6fb9ca03771125bc4f19bde90be523c0f9f85afb..208c00efcbdfb9cd5ebc0c39409d1821cec0bc1e 100644 (file)
@@ -20,5 +20,8 @@ class SizesTestCase(unittest.TestCase):
         self.failUnlessEqual(8, sizeof(c_int64))
         self.failUnlessEqual(8, sizeof(c_uint64))
 
+    def test_size_t(self):
+        self.failUnlessEqual(sizeof(c_void_p), sizeof(c_size_t))
+
 if __name__ == "__main__":
     unittest.main()
index 604c590db77cfeda5b51f6ec7f20bc2fc844f96f..0be8f697ffdad22c19f3453eb980e380fb7fbf8c 100644 (file)
@@ -2388,6 +2388,11 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
        address = (PPROC)GetProcAddress(handle, name);
        if (address)
                return address;
+
+       if (((size_t)name & ~0xFFFF) == 0) {
+               return NULL;
+       }
+
        /* It should not happen that dict is NULL, but better be safe */
        if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
                return address;
@@ -2493,6 +2498,28 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
        return 1;
 }
 
+static int
+_get_name(PyObject *obj, char **pname)
+{
+#ifdef MS_WIN32
+       if (PyInt_Check(obj) || PyLong_Check(obj)) {
+               /* We have to use MAKEINTRESOURCEA for Windows CE.
+                  Works on Windows as well, of course.
+               */
+               *pname = MAKEINTRESOURCEA(PyInt_AsUnsignedLongMask(obj) & 0xFFFF);
+               return 1;
+       }
+#endif
+       if (PyString_Check(obj) || PyUnicode_Check(obj)) {
+               *pname = PyString_AsString(obj);
+               return pname ? 1 : 0;
+       }
+       PyErr_SetString(PyExc_TypeError,
+                       "function name must be string or integer");
+       return 0;
+}
+
+
 static PyObject *
 CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -2504,7 +2531,7 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
        void *handle;
        PyObject *paramflags = NULL;
 
-       if (!PyArg_ParseTuple(args, "sO|O", &name, &dll, &paramflags))
+       if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, &paramflags))
                return NULL;
        if (paramflags == Py_None)
                paramflags = NULL;
@@ -2529,9 +2556,14 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
 #ifdef MS_WIN32
        address = FindAddress(handle, name, (PyObject *)type);
        if (!address) {
-               PyErr_Format(PyExc_AttributeError,
-                            "function '%s' not found",
-                            name);
+               if ((size_t)name & ~0xFFFF)
+                       PyErr_Format(PyExc_AttributeError,
+                                    "function '%s' not found",
+                                    name);
+               else
+                       PyErr_Format(PyExc_AttributeError,
+                                    "function ordinal %d not found",
+                                    name);
                return NULL;
        }
 #else
@@ -2608,8 +2640,9 @@ CFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
   "O" - must be a callable, creates a C callable function
 
   two or more argument forms (the third argument is a paramflags tuple)
-  "sO|O" - function name, dll object (with an integer handle)
-  "is|O" - vtable index, method name, creates callable calling COM vtbl
+  "(sO)|..." - (function name, dll object (with an integer handle)), paramflags
+  "(iO)|..." - (function ordinal, dll object (with an integer handle)), paramflags
+  "is|..." - vtable index, method name, creates callable calling COM vtbl
 */
 static PyObject *
 CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -2622,14 +2655,13 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        if (PyTuple_GET_SIZE(args) == 0)
                return GenericCData_new(type, args, kwds);
 
-       /* Shouldn't the following better be done in __init__? */
-       if (2 <= PyTuple_GET_SIZE(args)) {
+       if (1 <= PyTuple_GET_SIZE(args) && PyTuple_Check(PyTuple_GET_ITEM(args, 0)))
+               return CFuncPtr_FromDll(type, args, kwds);
+
 #ifdef MS_WIN32
-               if (PyInt_Check(PyTuple_GET_ITEM(args, 0)))
-                       return CFuncPtr_FromVtblIndex(type, args, kwds);
+       if (2 <= PyTuple_GET_SIZE(args) && PyInt_Check(PyTuple_GET_ITEM(args, 0)))
+               return CFuncPtr_FromVtblIndex(type, args, kwds);
 #endif
-               return CFuncPtr_FromDll(type, args, kwds);
-       }
 
        if (1 == PyTuple_GET_SIZE(args)
            && (PyInt_Check(PyTuple_GET_ITEM(args, 0))
@@ -4351,6 +4383,42 @@ string_at(const char *ptr, Py_ssize_t size)
        return PyString_FromStringAndSize(ptr, size);
 }
 
+static int
+cast_check_pointertype(PyObject *arg)
+{
+       StgDictObject *dict;
+
+       if (PointerTypeObject_Check(arg))
+               return 1;
+       dict = PyType_stgdict(arg);
+       if (dict) {
+               if (PyString_Check(dict->proto)
+                   && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
+                       /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
+                       return 1;
+               }
+       }
+       PyErr_Format(PyExc_TypeError,
+                    "cast() argument 2 must be a pointer type, not %s",
+                    PyType_Check(arg)
+                    ? ((PyTypeObject *)arg)->tp_name
+                    : arg->ob_type->tp_name);
+       return 0;
+}
+
+static PyObject *
+cast(void *ptr, PyObject *ctype)
+{
+       CDataObject *result;
+       if (0 == cast_check_pointertype(ctype))
+               return NULL;
+       result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
+       if (result == NULL)
+               return NULL;
+       /* Should we assert that result is a pointer type? */
+       memcpy(result->b_ptr, &ptr, sizeof(void *));
+       return (PyObject *)result;
+}
 
 #ifdef CTYPES_UNICODE
 static PyObject *
@@ -4486,6 +4554,7 @@ init_ctypes(void)
        PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
        PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
        PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
+       PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
 #ifdef CTYPES_UNICODE
        PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
 #endif
index 9d9e32296e53366be9c503bec0cb15d908bd14bf..c019af7be676db40cf1fc3dcacbfadd6dc2d63f5 100644 (file)
@@ -1423,71 +1423,7 @@ set_conversion_mode(PyObject *self, PyObject *args)
 }
 #endif
 
-static char cast_doc[] =
-"cast(cobject, ctype) -> ctype-instance\n\
-\n\
-Create an instance of ctype, and copy the internal memory buffer\n\
-of cobject to the new instance.  Should be used to cast one type\n\
-of pointer to another type of pointer.\n\
-Doesn't work correctly with ctypes integers.\n";
-
-static int cast_check_pointertype(PyObject *arg, PyObject **pobj)
-{
-       StgDictObject *dict;
-
-       if (PointerTypeObject_Check(arg)) {
-               *pobj = arg;
-               return 1;
-       }
-       dict = PyType_stgdict(arg);
-       if (dict) {
-               if (PyString_Check(dict->proto)
-                   && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
-                       /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
-                       *pobj = arg;
-                       return 1;
-               }
-       }
-       if (PyType_Check(arg)) {
-               PyErr_Format(PyExc_TypeError,
-                            "cast() argument 2 must be a pointer type, not %s",
-                            ((PyTypeObject *)arg)->tp_name);
-       } else {
-               PyErr_Format(PyExc_TypeError,
-                            "cast() argument 2 must be a pointer type, not a %s",
-                            arg->ob_type->tp_name);
-       }
-       return 0;
-}
-
-static PyObject *cast(PyObject *self, PyObject *args)
-{
-       PyObject *obj, *ctype;
-       struct argument a;
-       CDataObject *result;
-
-       /* We could and should allow array types for the second argument
-          also, but we cannot use the simple memcpy below for them. */
-       if (!PyArg_ParseTuple(args, "OO&:cast", &obj, &cast_check_pointertype, &ctype))
-               return NULL;
-       if (-1 == ConvParam(obj, 1, &a))
-               return NULL;
-       result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
-       if (result == NULL) {
-               Py_XDECREF(a.keep);
-               return NULL;
-       }
-       // result->b_size
-       // a.ffi_type->size
-       memcpy(result->b_ptr, &a.value,
-              min(result->b_size, (int)a.ffi_type->size));
-       Py_XDECREF(a.keep);
-       return (PyObject *)result;
-}
-
-
 PyMethodDef module_methods[] = {
-       {"cast", cast, METH_VARARGS, cast_doc},
 #ifdef CTYPES_UNICODE
        {"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
 #endif