Index: Doc/lib/libctypes.tex =================================================================== --- Doc/lib/libctypes.tex (revision 53606) +++ Doc/lib/libctypes.tex (working copy) @@ -2294,6 +2294,12 @@ an integer address, or a string. \end{classdesc*} +\begin{classdesc*}{c_bool} +Represent the C \code{bool} datatype (more accurately, _Bool from C99). +Its value can be True or False, and the constructor accepts any object that +has a truth value. +\end{classdesc*} + \begin{classdesc*}{HRESULT} Windows only: Represents a \class{HRESULT} value, which contains success or error information for a function or method call. Index: Lib/ctypes/test/test_repr.py =================================================================== --- Lib/ctypes/test/test_repr.py (revision 53606) +++ Lib/ctypes/test/test_repr.py (working copy) @@ -8,6 +8,10 @@ class X(base): pass subclasses.append(X) + try: + subclasses.append(c_bool) + except NameError: + pass class X(c_char): pass Index: Lib/ctypes/test/test_numbers.py =================================================================== --- Lib/ctypes/test/test_numbers.py (revision 53606) +++ Lib/ctypes/test/test_numbers.py (working copy) @@ -24,6 +24,8 @@ unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong] signed_types = [c_byte, c_short, c_int, c_long, c_longlong] +bool_types = [] + float_types = [c_double, c_float] try: @@ -35,8 +37,16 @@ unsigned_types.append(c_ulonglong) signed_types.append(c_longlong) +try: + c_bool +except NameError: + pass +else: + bool_types.append(c_bool) + unsigned_ranges = valid_ranges(*unsigned_types) signed_ranges = valid_ranges(*signed_types) +bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] ################################################################ @@ -59,6 +69,11 @@ for t, (l, h) in zip(signed_types, signed_ranges): self.failUnlessEqual(t(l).value, l) self.failUnlessEqual(t(h).value, h) + + def test_bool_values(self): + from operator import truth + for t, v in zip(bool_types, bool_values): + self.failUnlessEqual(t(v).value, truth(v)) def test_typeerror(self): # Only numbers are allowed in the contructor, @@ -82,7 +97,7 @@ def test_byref(self): # calling byref returns also a PyCArgObject instance - for t in signed_types + unsigned_types + float_types: + for t in signed_types + unsigned_types + float_types + bool_types: parm = byref(t()) self.failUnlessEqual(ArgType, type(parm)) @@ -101,7 +116,7 @@ self.assertRaises(TypeError, t, 3.14) def test_sizes(self): - for t in signed_types + unsigned_types + float_types: + for t in signed_types + unsigned_types + float_types + bool_type: size = struct.calcsize(t._type_) # sizeof of the type... self.failUnlessEqual(sizeof(t), size) @@ -163,6 +178,18 @@ a[0] = '?' self.failUnlessEqual(v.value, a[0]) + + # array does not support c_bool / 't' + # def test_bool_from_address(self): + # from ctypes import c_bool + # from array import array + # a = array(c_bool._type_, [True]) + # v = t.from_address(a.buffer_info()[0]) + # self.failUnlessEqual(v.value, a[0]) + # self.failUnlessEqual(type(v) is t) + # a[0] = False + # self.failUnlessEqual(v.value, a[0]) + # self.failUnlessEqual(type(v) is t) def test_init(self): # c_int() can be initialized from Python's int, and c_int. Index: Lib/ctypes/__init__.py =================================================================== --- Lib/ctypes/__init__.py (revision 53606) +++ Lib/ctypes/__init__.py (working copy) @@ -15,6 +15,7 @@ from _ctypes import ArgumentError from struct import calcsize as _calcsize +from struct import error as struct_error if __version__ != _ctypes_version: raise Exception, ("Version number mismatch", __version__, _ctypes_version) @@ -233,6 +234,25 @@ c_voidp = c_void_p # backwards compatibility (to a bug) _check_size(c_void_p) +try: + class c_bool(_SimpleCData): + _type_ = "t" + _check_size(c_bool, "t") +except ValueError: + # fallback on an integer type on systems that have an emulated 't' + try: + boolsize = _calcsize('t') + if boolsize == _calcsize('B'): + c_bool = c_ubyte + elif boolsize == _calcsize('H'): + c_bool = c_ushort + elif boolsize == _calcsize('I'): + c_bool = c_uint + elif boolsize == _calcsize('L'): + c_bool = c_ulong + except struct_error: + c_bool = c_ubyte + # This cache maps types to pointers to them. _pointer_type_cache = {} Index: Modules/_ctypes/_ctypes.c =================================================================== --- Modules/_ctypes/_ctypes.c (revision 53606) +++ Modules/_ctypes/_ctypes.c (working copy) @@ -1119,7 +1119,7 @@ */ -static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv"; +static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvt"; static PyObject * c_wchar_p_from_param(PyObject *type, PyObject *value) Index: Modules/_ctypes/cfield.c =================================================================== --- Modules/_ctypes/cfield.c (revision 53606) +++ Modules/_ctypes/cfield.c (working copy) @@ -725,7 +725,30 @@ } #endif +#ifdef HAVE_C99_BOOL static PyObject * +t_set(void *ptr, PyObject *value, unsigned size) +{ + switch (PyObject_IsTrue(value)) { + case -1: + return NULL; + case 0: + *(_Bool *)ptr = 0; + _RET(value); + default: + *(_Bool *)ptr = 1; + _RET(value); + } +} + +static PyObject * +t_get(void *ptr, unsigned size) +{ + return PyBool_FromLong((long)*(_Bool *)ptr); +} +#endif + +static PyObject * I_set(void *ptr, PyObject *value, unsigned size) { unsigned long val; @@ -1585,6 +1608,19 @@ { 'X', BSTR_set, BSTR_get, &ffi_type_pointer}, { 'v', vBOOL_set, vBOOL_get, &ffi_type_sshort}, #endif +#ifdef HAVE_C99_BOOL +#if SIZEOF__BOOL == 1 + { 't', t_set, t_get, &ffi_type_uchar}, +#elif SIZEOF__BOOL == SIZEOF_SHORT + { 't', t_set, t_get, &ffi_type_ushort}, +#elif SIZEOF__BOOL == SIZEOF_INT + { 't', t_set, t_get, &ffi_type_uint, I_set_sw, I_get_sw}, +#elif SIZEOF__BOOL == SIZEOF_LONG + { 't', t_set, t_get, &ffi_type_ulong, L_set_sw, L_get_sw}, +#elif SIZEOF__BOOL == SIZEOF_LONG_LONG + { 't', t_set, t_get, &ffi_type_ulong, Q_set_sw, Q_get_sw}, +#endif /* SIZEOF__BOOL */ +#endif /* HAVE_C99_BOOL */ { 'O', O_set, O_get, &ffi_type_pointer}, { 0, NULL, NULL, NULL}, };