[Python-3000-checkins] r62597 - in python/branches/py3k: Lib/ctypes/test/test_pep3118.py Misc/NEWS Modules/_ctypes/_ctypes.c Modules/_ctypes/callbacks.c Modules/_ctypes/callproc.c Modules/_ctypes/ctypes.h Modules/_ctypes/stgdict.c

thomas.heller python-3000-checkins at python.org
Wed Apr 30 19:11:47 CEST 2008


Author: thomas.heller
Date: Wed Apr 30 19:11:46 2008
New Revision: 62597

Log:
Merged revisions 60056-60071,60073-60127,60129-60261,60263-60284,60286-62589,62591-62594 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/branches/py3k-ctypes-pep3118

........
  r60059 | thomas.heller | 2008-01-18 22:17:05 +0100 (Fri, 18 Jan 2008) | 1 line
  
  Implement pep3118 format strings for SimpleCData types.
........
  r60108 | thomas.heller | 2008-01-19 22:56:12 +0100 (Sat, 19 Jan 2008) | 3 lines
  
  Always use explicit endian specifiers for simple types, and a bug fix
  too.  Add unittest.
........
  r60112 | thomas.heller | 2008-01-19 23:25:14 +0100 (Sat, 19 Jan 2008) | 2 lines
  
  Fully implement tp_asbuffer for pointer types.
........
  r60261 | thomas.heller | 2008-01-24 22:01:29 +0100 (Thu, 24 Jan 2008) | 4 lines
  
  Added shape and ndim field to StgDictObject.  Implemented pep3118
  format string, ndim, and shape for array types.  Added a
  buffer_info(type_or_object) for testing.
........
  r60278 | thomas.heller | 2008-01-25 11:53:33 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Implement pep3118 format strings for ctypes.Structure and ctypes.Union.
........
  r60288 | thomas.heller | 2008-01-25 17:58:30 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  All ctypes types now use the same CData_GetBuffer function.
........
  r60289 | thomas.heller | 2008-01-25 19:59:45 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Fix format string for structures, and itemsize for arrays.
........
  r60290 | thomas.heller | 2008-01-25 20:09:03 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Implement to format string for function pointers.
........
  r60292 | thomas.heller | 2008-01-25 20:32:20 +0100 (Fri, 25 Jan 2008) | 3 lines
  
  Only structures with native packing implement the pep.  Unions, or
  packed structures do not.
........
  r60293 | thomas.heller | 2008-01-25 20:34:31 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Update the test.
........
  r60295 | thomas.heller | 2008-01-25 20:44:41 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Fixed a few XXX markers.
........
  r60298 | thomas.heller | 2008-01-25 21:11:08 +0100 (Fri, 25 Jan 2008) | 1 line
  
  Fix test for 64-bt platform.
........
  r60299 | thomas.heller | 2008-01-25 21:34:11 +0100 (Fri, 25 Jan 2008) | 2 lines
  
  Add test for the readonly bit.
........
  r60384 | thomas.heller | 2008-01-28 08:45:04 +0100 (Mon, 28 Jan 2008) | 4 lines
  
  Restructure the test so that it contains little endian format strings.
  On big endian machines, the format strings are converted by replacing
  '<' with '>'.
........
  r60385 | thomas.heller | 2008-01-28 08:58:46 +0100 (Mon, 28 Jan 2008) | 1 line
  
  Bugfix and test for explicit big and little endian types.
........
  r60428 | thomas.heller | 2008-01-29 22:00:37 +0100 (Tue, 29 Jan 2008) | 1 line
  
  Add comments to clarify the tests.
........
  r62589 | thomas.heller | 2008-04-30 13:49:46 +0200 (Wed, 30 Apr 2008) | 1 line
  
  Fix compiler warnings.
........


Added:
   python/branches/py3k/Lib/ctypes/test/test_pep3118.py
      - copied, changed from r60112, /python/branches/py3k-ctypes-pep3118/Lib/ctypes/test/test_pep3118.py
Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_ctypes/_ctypes.c
   python/branches/py3k/Modules/_ctypes/callbacks.c
   python/branches/py3k/Modules/_ctypes/callproc.c
   python/branches/py3k/Modules/_ctypes/ctypes.h
   python/branches/py3k/Modules/_ctypes/stgdict.c

Copied: python/branches/py3k/Lib/ctypes/test/test_pep3118.py (from r60112, /python/branches/py3k-ctypes-pep3118/Lib/ctypes/test/test_pep3118.py)
==============================================================================
--- /python/branches/py3k-ctypes-pep3118/Lib/ctypes/test/test_pep3118.py	(original)
+++ python/branches/py3k/Lib/ctypes/test/test_pep3118.py	Wed Apr 30 19:11:46 2008
@@ -1,69 +1,170 @@
 import unittest
 from ctypes import *
-import struct, sys
+import re, struct, sys
 
 if sys.byteorder == "little":
-    ENDIAN = "<"
+    THIS_ENDIAN = "<"
+    OTHER_ENDIAN = ">"
 else:
-    ENDIAN = ">"
+    THIS_ENDIAN = ">"
+    OTHER_ENDIAN = "<"
 
-simple_types = [
-    ("b", c_byte),
-    ("B", c_ubyte),
-    ("h", c_short),
-    ("H", c_ushort),
-# c_int and c_uint may be aliases to c_long
-##    ("i", c_int),
-##    ("I", c_uint),
-    ("l", c_long),
-    ("L", c_ulong),
-    ("q", c_longlong),
-    ("Q", c_ulonglong),
-    ("f", c_float),
-    ("d", c_double),
-# c_longdouble may be an alias to c_double
-##    ("g", c_longdouble),
-    ("t", c_bool),
-# struct doesn't support this (yet)
-##    ("O", py_object),
-]
+def normalize(format):
+    # Remove current endian specifier and white space from a format
+    # string
+    format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
+    return re.sub(r"\s", "", format)
 
 class Test(unittest.TestCase):
 
-    def test_simpletypes(self):
-        # simple types in native byte order
-        for fmt, typ in simple_types:
-            v = memoryview(typ())
-
-            # check the PEP3118 format string
-            self.failUnlessEqual(v.format, ENDIAN + fmt)
-
-            # shape and strides are None for integral types
-            self.failUnlessEqual((v.shape, v.strides),
-                                 (None, None))
-
-            # size and itemsize must be what struct.calcsize reports
-            struct_size = struct.calcsize(fmt)
-            self.failUnlessEqual((v.size, v.itemsize),
-                                 (struct_size, struct_size))
-
-    def test_pointertypes(self):
-        for fmt, typ in simple_types:
-            v = memoryview(POINTER(typ)())
-
-            # check the PEP3118 format string
-            self.failUnlessEqual(v.format, "&" + ENDIAN + fmt)
-
-            # shape and strides are None for integral types
-            self.failUnlessEqual((v.shape, v.strides),
-                                 (None, None))
-
-            # size and itemsize must be what struct.calcsize reports
-            # for pointers
-            struct_size = struct.calcsize("P")
-            self.failUnlessEqual((v.size, v.itemsize),
-                                 (struct_size, struct_size))
-
+    def test_native_types(self):
+        for tp, fmt, shape, itemtp in native_types:
+            ob = tp()
+            v = memoryview(ob)
+            try:
+                self.failUnlessEqual(normalize(v.format), normalize(fmt))
+                self.failUnlessEqual(v.size, sizeof(ob))
+                self.failUnlessEqual(v.itemsize, sizeof(itemtp))
+                self.failUnlessEqual(v.shape, shape)
+                # ctypes object always have a non-strided memory block
+                self.failUnlessEqual(v.strides, None)
+                # they are always read/write
+                self.failIf(v.readonly)
+
+                if v.shape:
+                    n = 1
+                    for dim in v.shape:
+                        n = n * dim
+                    self.failUnlessEqual(v.itemsize * n, v.size)
+            except:
+                # so that we can see the failing type
+                print(tp)
+                raise
+
+    def test_endian_types(self):
+        for tp, fmt, shape, itemtp in endian_types:
+            ob = tp()
+            v = memoryview(ob)
+            try:
+                self.failUnlessEqual(v.format, fmt)
+                self.failUnlessEqual(v.size, sizeof(ob))
+                self.failUnlessEqual(v.itemsize, sizeof(itemtp))
+                self.failUnlessEqual(v.shape, shape)
+                # ctypes object always have a non-strided memory block
+                self.failUnlessEqual(v.strides, None)
+                # they are always read/write
+                self.failIf(v.readonly)
+
+                if v.shape:
+                    n = 1
+                    for dim in v.shape:
+                        n = n * dim
+                    self.failUnlessEqual(v.itemsize * n, v.size)
+            except:
+                # so that we can see the failing type
+                print(tp)
+                raise
+
+# define some structure classes
+
+class Point(Structure):
+    _fields_ = [("x", c_long), ("y", c_long)]
+
+class PackedPoint(Structure):
+    _pack_ = 2
+    _fields_ = [("x", c_long), ("y", c_long)]
+
+class Point2(Structure):
+    pass
+Point2._fields_ = [("x", c_long), ("y", c_long)]
+
+class EmptyStruct(Structure):
+    _fields_ = []
+
+class aUnion(Union):
+    _fields_ = [("a", c_int)]
+
+################################################################
+#
+# This table contains format strings as they look on little endian
+# machines.  The test replaces '<' with '>' on big endian machines.
+#
+native_types = [
+    # type                      format                  shape           calc itemsize
+
+    ## simple types
+
+    (c_char,                    "<c",                   None,           c_char),
+    (c_byte,                    "<b",                   None,           c_byte),
+    (c_ubyte,                   "<B",                   None,           c_ubyte),
+    (c_short,                   "<h",                   None,           c_short),
+    (c_ushort,                  "<H",                   None,           c_ushort),
+
+    # c_int and c_uint may be aliases to c_long
+    #(c_int,                     "<i",                   None,           c_int),
+    #(c_uint,                    "<I",                   None,           c_uint),
+
+    (c_long,                    "<l",                   None,           c_long),
+    (c_ulong,                   "<L",                   None,           c_ulong),
+
+    # c_longlong and c_ulonglong are aliases on 64-bit platforms
+    #(c_longlong,                "<q",                   None,           c_longlong),
+    #(c_ulonglong,               "<Q",                   None,           c_ulonglong),
+
+    (c_float,                   "<f",                   None,           c_float),
+    (c_double,                  "<d",                   None,           c_double),
+    # c_longdouble may be an alias to c_double
+
+    (c_bool,                    "<?",                   None,           c_bool),
+    (py_object,                 "<O",                   None,           py_object),
+
+    ## pointers
+
+    (POINTER(c_byte),           "&<b",                  None,           POINTER(c_byte)),
+    (POINTER(POINTER(c_long)),  "&&<l",                 None,           POINTER(POINTER(c_long))),
+
+    ## arrays and pointers
+
+    (c_double * 4,              "(4)<d",                (4,),           c_double),
+    (c_float * 4 * 3 * 2,       "(2,3,4)<f",            (2,3,4),        c_float),
+    (POINTER(c_short) * 2,      "(2)&<h",               (2,),           POINTER(c_short)),
+    (POINTER(c_short) * 2 * 3,  "(3,2)&<h",             (3,2,),         POINTER(c_short)),
+    (POINTER(c_short * 2),      "&(2)<h",               None,           POINTER(c_short)),
+
+    ## structures and unions
+
+    (Point,                     "T{<l:x:<l:y:}",        None,           Point),
+    # packed structures do not implement the pep
+    (PackedPoint,               "B",                    None,           PackedPoint),
+    (Point2,                    "T{<l:x:<l:y:}",        None,           Point2),
+    (EmptyStruct,               "T{}",                  None,           EmptyStruct),
+    # the pep does't support unions
+    (aUnion,                    "B",                    None,           aUnion),
+
+    ## other
+
+    # function signatures are not implemented
+    (CFUNCTYPE(None),           "X{}",                  None,           CFUNCTYPE(None)),
+
+    ]
+
+class BEPoint(BigEndianStructure):
+    _fields_ = [("x", c_long), ("y", c_long)]
+
+class LEPoint(LittleEndianStructure):
+    _fields_ = [("x", c_long), ("y", c_long)]
+
+################################################################
+#
+# This table contains format strings as they really look, on both big
+# and little endian machines.
+#
+endian_types = [
+    (BEPoint,                   "T{>l:x:>l:y:}",        None,           BEPoint),
+    (LEPoint,                   "T{<l:x:<l:y:}",        None,           LEPoint),
+    (POINTER(BEPoint),          "&T{>l:x:>l:y:}",       None,           POINTER(BEPoint)),
+    (POINTER(LEPoint),          "&T{<l:x:<l:y:}",       None,           POINTER(LEPoint)),
+    ]
 
 if __name__ == "__main__":
     unittest.main()

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Wed Apr 30 19:11:46 2008
@@ -35,6 +35,8 @@
 Library
 -------
 
+- ctypes objects now support the PEP3118 buffer interface
+
 - Issue #2682: ctypes callback functions now longer contain a cyclic
   reference to themselves.
 

Modified: python/branches/py3k/Modules/_ctypes/_ctypes.c
==============================================================================
--- python/branches/py3k/Modules/_ctypes/_ctypes.c	(original)
+++ python/branches/py3k/Modules/_ctypes/_ctypes.c	Wed Apr 30 19:11:46 2008
@@ -261,6 +261,36 @@
 
 /******************************************************************/
 /*
+  Allocate a memory block for a pep3118 format string, copy prefix (if
+  non-null) and suffix into it.  Returns NULL on failure, with the error
+  indicator set.  If called with a suffix of NULL the error indicator must
+  already be set.
+ */
+char *
+alloc_format_string(const char *prefix, const char *suffix)
+{
+	size_t len;
+	char *result;
+
+	if (suffix == NULL) {
+		assert(PyErr_Occurred());
+		return NULL;
+	}
+	len = strlen(suffix);
+	if (prefix)
+		len += strlen(prefix);
+	result = PyMem_Malloc(len + 1);
+	if (result == NULL)
+		return NULL;
+	if (prefix)
+		strcpy(result, prefix);
+	else
+		result[0] = '\0';
+	strcat(result, suffix);
+	return result;
+}
+
+/*
   StructType_Type - a meta type/class.  Creating a new class using this one as
   __metaclass__ will call the contructor StructUnionType_new.  It replaces the
   tp_dict member with a new instance of StgDict, and initializes the C
@@ -727,6 +757,16 @@
 		return NULL;
 	}
 
+	if (proto) {
+		StgDictObject *itemdict = PyType_stgdict(proto);
+		assert(itemdict);
+		stgdict->format = alloc_format_string("&", itemdict->format);
+		if (stgdict->format == NULL) {
+			Py_DECREF((PyObject *)stgdict);
+			return NULL;
+		}
+	}
+
 	/* create the new instance (which is a class,
 	   since we are a metatype!) */
 	result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
@@ -1101,6 +1141,7 @@
 	long length;
 	int overflow;
 	Py_ssize_t itemsize, itemalign;
+	char buf[32];
 
 	typedict = PyTuple_GetItem(args, 2);
 	if (!typedict)
@@ -1140,6 +1181,28 @@
 		return NULL;
 	}
 
+	assert(itemdict->format);
+	if (itemdict->format[0] == '(') {
+		sprintf(buf, "(%ld,", length);
+		stgdict->format = alloc_format_string(buf, itemdict->format+1);
+	} else {
+		sprintf(buf, "(%ld)", length);
+		stgdict->format = alloc_format_string(buf, itemdict->format);
+	}
+	if (stgdict->format == NULL) {
+		Py_DECREF((PyObject *)stgdict);
+		return NULL;
+	}
+	stgdict->ndim = itemdict->ndim + 1;
+	stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t *) * stgdict->ndim);
+	if (stgdict->shape == NULL) {
+		Py_DECREF((PyObject *)stgdict);
+		return NULL;
+	}
+	stgdict->shape[0] = length;
+	memmove(&stgdict->shape[1], itemdict->shape,
+		sizeof(Py_ssize_t) * (stgdict->ndim - 1));
+
 	itemsize = itemdict->size;
 	if (length * itemsize < 0) {
 		PyErr_SetString(PyExc_OverflowError,
@@ -1691,6 +1754,16 @@
 	stgdict->size = fmt->pffi_type->size;
 	stgdict->setfunc = fmt->setfunc;
 	stgdict->getfunc = fmt->getfunc;
+#ifdef WORDS_BIGENDIAN
+	stgdict->format = alloc_format_string(">", proto_str);
+#else
+	stgdict->format = alloc_format_string("<", proto_str);
+#endif
+	if (stgdict->format == NULL) {
+		Py_DECREF(result);
+		Py_DECREF((PyObject *)stgdict);
+		return NULL;
+	}
 
 	stgdict->paramfunc = SimpleType_paramfunc;
 /*
@@ -1760,22 +1833,32 @@
 	if (type == &SimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) {
 		PyObject *swapped = CreateSwappedType(type, args, kwds,
 						      proto, fmt);
+		StgDictObject *sw_dict;
 		if (swapped == NULL) {
 			Py_DECREF(result);
 			return NULL;
 		}
+		sw_dict = PyType_stgdict(swapped);
 #ifdef WORDS_BIGENDIAN
 		PyObject_SetAttrString((PyObject *)result, "__ctype_le__", swapped);
 		PyObject_SetAttrString((PyObject *)result, "__ctype_be__", (PyObject *)result);
 		PyObject_SetAttrString(swapped, "__ctype_be__", (PyObject *)result);
 		PyObject_SetAttrString(swapped, "__ctype_le__", swapped);
+		/* We are creating the type for the OTHER endian */
+		sw_dict->format = alloc_format_string("<", stgdict->format+1);
 #else
 		PyObject_SetAttrString((PyObject *)result, "__ctype_be__", swapped);
 		PyObject_SetAttrString((PyObject *)result, "__ctype_le__", (PyObject *)result);
 		PyObject_SetAttrString(swapped, "__ctype_le__", (PyObject *)result);
 		PyObject_SetAttrString(swapped, "__ctype_be__", swapped);
+		/* We are creating the type for the OTHER endian */
+		sw_dict->format = alloc_format_string(">", stgdict->format+1);
 #endif
 		Py_DECREF(swapped);
+		if (PyErr_Occurred()) {
+			Py_DECREF(result);
+			return NULL;
+		}
 	};
 
 	return (PyObject *)result;
@@ -2025,6 +2108,13 @@
 		return NULL;
 
 	stgdict->paramfunc = CFuncPtrType_paramfunc;
+	/* We do NOT expose the function signature in the format string.  It
+	   is impossible, generally, because the only requirement for the
+	   argtypes items is that they have a .from_param method - we do not
+	   know the types of the arguments (although, in practice, most
+	   argtypes would be a ctypes type).
+	*/
+	stgdict->format = alloc_format_string(NULL, "X{}");
 	stgdict->flags |= TYPEFLAG_ISPOINTER;
 
 	/* create the new instance (which is a class,
@@ -2240,7 +2330,31 @@
 static int CData_GetBuffer(PyObject *_self, Py_buffer *view, int flags)
 {
 	CDataObject *self = (CDataObject *)_self;
-        return PyBuffer_FillInfo(view, self->b_ptr, self->b_size, 0, flags);
+	StgDictObject *dict = PyObject_stgdict(_self);
+	Py_ssize_t i;
+
+	if (view == NULL) return 0;
+	if (((flags & PyBUF_LOCK) == PyBUF_LOCK)) {
+		PyErr_SetString(PyExc_BufferError,
+				"Cannot lock this object.");
+		return -1;
+	}
+
+	view->buf = self->b_ptr;
+	view->len = self->b_size;
+	view->readonly = 0;
+	/* use default format character if not set */
+	view->format = dict->format ? dict->format : "B";
+	view->ndim = dict->ndim;
+	view->shape = dict->shape;
+	view->itemsize = self->b_size;
+	for (i = 0; i < view->ndim; ++i) {
+		view->itemsize /= dict->shape[i];
+	}
+	view->strides = NULL;
+	view->suboffsets = NULL;
+	view->internal = NULL;
+	return 0;
 }
 
 static PyBufferProcs CData_as_buffer = {

Modified: python/branches/py3k/Modules/_ctypes/callbacks.c
==============================================================================
--- python/branches/py3k/Modules/_ctypes/callbacks.c	(original)
+++ python/branches/py3k/Modules/_ctypes/callbacks.c	Wed Apr 30 19:11:46 2008
@@ -9,7 +9,8 @@
 
 /**************************************************************/
 
-static CThunkObject_dealloc(PyObject *_self)
+static void
+CThunkObject_dealloc(PyObject *_self)
 {
 	CThunkObject *self = (CThunkObject *)_self;
 	Py_XDECREF(self->converters);

Modified: python/branches/py3k/Modules/_ctypes/callproc.c
==============================================================================
--- python/branches/py3k/Modules/_ctypes/callproc.c	(original)
+++ python/branches/py3k/Modules/_ctypes/callproc.c	Wed Apr 30 19:11:46 2008
@@ -1632,10 +1632,36 @@
 	return result;
 }
 
+static PyObject *
+buffer_info(PyObject *self, PyObject *arg)
+{
+	StgDictObject *dict = PyType_stgdict(arg);
+	PyObject *shape;
+	Py_ssize_t i;
+
+	if (dict == NULL)
+		dict = PyObject_stgdict(arg);
+	if (dict == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+				"not a ctypes type or object");
+		return NULL;
+	}
+	shape = PyTuple_New(dict->ndim);
+	for (i = 0; i < (int)dict->ndim; ++i)
+		PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(dict->shape[i]));
+
+	if (PyErr_Occurred()) {
+		Py_DECREF(shape);
+		return NULL;
+	}
+	return Py_BuildValue("siN", dict->format, dict->ndim, shape);
+}
+
 PyMethodDef module_methods[] = {
 	{"POINTER", POINTER, METH_O },
 	{"pointer", pointer, METH_O },
 	{"_unpickle", unpickle, METH_VARARGS },
+	{"buffer_info", buffer_info, METH_O, "Return buffer interface information"},
 	{"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"},
 #ifdef CTYPES_UNICODE
 	{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},

Modified: python/branches/py3k/Modules/_ctypes/ctypes.h
==============================================================================
--- python/branches/py3k/Modules/_ctypes/ctypes.h	(original)
+++ python/branches/py3k/Modules/_ctypes/ctypes.h	Wed Apr 30 19:11:46 2008
@@ -204,6 +204,14 @@
 	PyObject *restype;	/* CDataObject or NULL */
 	PyObject *checker;
 	int flags;		/* calling convention and such */
+
+	/* pep3118 fields, pointers neeed PyMem_Free */
+	char *format;
+	int ndim;
+	Py_ssize_t *shape;
+/*	Py_ssize_t *strides;	*/ /* unused in ctypes */
+/*	Py_ssize_t *suboffsets;	*/ /* unused in ctypes */
+
 } StgDictObject;
 
 /****************************************************************
@@ -342,6 +350,7 @@
 extern void _AddTraceback(char *, char *, int);
 
 extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr);
+extern char *alloc_format_string(const char *prefix, const char *suffix);
 
 /* XXX better name needed! */
 extern int IsSimpleSubType(PyObject *obj);

Modified: python/branches/py3k/Modules/_ctypes/stgdict.c
==============================================================================
--- python/branches/py3k/Modules/_ctypes/stgdict.c	(original)
+++ python/branches/py3k/Modules/_ctypes/stgdict.c	Wed Apr 30 19:11:46 2008
@@ -2,6 +2,7 @@
 #include <ffi.h>
 #ifdef MS_WIN32
 #include <windows.h>
+#include <malloc.h>
 #endif
 #include "ctypes.h"
 
@@ -20,6 +21,9 @@
 {
 	if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
 		return -1;
+	self->format = NULL;
+	self->ndim = 0;
+	self->shape = NULL;
 	return 0;
 }
 
@@ -38,6 +42,8 @@
 StgDict_dealloc(StgDictObject *self)
 {
 	StgDict_clear(self);
+	PyMem_Free(self->format);
+	PyMem_Free(self->shape);
 	PyMem_Free(self->ffi_type_pointer.elements);
 	PyDict_Type.tp_dealloc((PyObject *)self);
 }
@@ -50,6 +56,10 @@
 
 	StgDict_clear(dst);
 	PyMem_Free(dst->ffi_type_pointer.elements);
+	PyMem_Free(dst->format);
+	dst->format = NULL;
+	PyMem_Free(dst->shape);
+	dst->shape = NULL;
 	dst->ffi_type_pointer.elements = NULL;
 
 	d = (char *)dst;
@@ -64,6 +74,20 @@
 	Py_XINCREF(dst->restype);
 	Py_XINCREF(dst->checker);
 
+	if (src->format) {
+		dst->format = PyMem_Malloc(strlen(src->format) + 1);
+		if (dst->format == NULL)
+			return -1;
+		strcpy(dst->format, src->format);
+	}
+	if (src->shape) {
+		dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim);
+		if (dst->shape == NULL)
+			return -1;
+		memcpy(dst->shape, src->shape,
+		       sizeof(Py_ssize_t) * src->ndim);
+	}
+
 	if (src->ffi_type_pointer.elements == NULL)
 		return 0;
 	size = sizeof(ffi_type *) * (src->length + 1);
@@ -341,6 +365,11 @@
 		return -1;
 	}
 
+	if (stgdict->format) {
+		PyMem_Free(stgdict->format);
+		stgdict->format = NULL;
+	}
+
 	if (stgdict->ffi_type_pointer.elements)
 		PyMem_Free(stgdict->ffi_type_pointer.elements);
 
@@ -379,6 +408,15 @@
 		ffi_ofs = 0;
 	}
 
+	if (isStruct && !isPacked) {
+		stgdict->format = alloc_format_string(NULL, "T{");
+	} else {
+		/* PEP3118 doesn't support union, or packed structures (well,
+		   only standard packing, but we dont support the pep for
+		   that). Use 'B' for bytes. */
+		stgdict->format = alloc_format_string(NULL, "B");
+	}
+
 #define realdict ((PyObject *)&stgdict->dict)
 	for (i = 0; i < len; ++i) {
 		PyObject *name = NULL, *desc = NULL;
@@ -439,6 +477,24 @@
 			}
 		} else
 			bitsize = 0;
+		if (isStruct && !isPacked) {
+			char *fieldfmt = dict->format ? dict->format : "B";
+			char *fieldname = PyUnicode_AsString(name);
+			char *ptr;
+			Py_ssize_t len = strlen(fieldname) + strlen(fieldfmt);
+			char *buf = alloca(len + 2 + 1);
+
+			sprintf(buf, "%s:%s:", fieldfmt, fieldname);
+
+			ptr = stgdict->format;
+			stgdict->format = alloc_format_string(stgdict->format, buf);
+			PyMem_Free(ptr);
+
+			if (stgdict->format == NULL) {
+				Py_DECREF(pair);
+				return -1;
+			}
+		}
 		if (isStruct) {
 			prop = CField_FromDesc(desc, i,
 					       &field_size, bitsize, &bitofs,
@@ -469,6 +525,13 @@
 		Py_DECREF(prop);
 	}
 #undef realdict
+
+	if (isStruct && !isPacked) {
+		stgdict->format = alloc_format_string(stgdict->format, "}");
+		if (stgdict->format == NULL)
+			return -1;
+	}
+
 	if (!isStruct)
 		size = union_size;
 


More information about the Python-3000-checkins mailing list