diff options
author | Thomas Heller <theller@ctypes.org> | 2003-04-17 18:55:45 +0000 |
---|---|---|
committer | Thomas Heller <theller@ctypes.org> | 2003-04-17 18:55:45 +0000 |
commit | 8918456ec400a2ea60452ae49c780f496207143d (patch) | |
tree | 9b0ce3f7bd13d0aa34c3bfbcc63578d3871f2525 | |
parent | bd8d0ed849f4b09ace911d2195769cac70a4e0e6 (diff) | |
download | cpython-8918456ec400a2ea60452ae49c780f496207143d.tar.gz |
SF # 595026: support for masks in getargs.c.
New functions:
unsigned long PyInt_AsUnsignedLongMask(PyObject *);
unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *);
unsigned long PyLong_AsUnsignedLongMask(PyObject *);
unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
New and changed format codes:
b unsigned char 0..UCHAR_MAX
B unsigned char none **
h unsigned short 0..USHRT_MAX
H unsigned short none **
i int INT_MIN..INT_MAX
I * unsigned int 0..UINT_MAX
l long LONG_MIN..LONG_MAX
k * unsigned long none
L long long LLONG_MIN..LLONG_MAX
K * unsigned long long none
Notes:
* New format codes.
** Changed from previous "range-and-a-half" to "none"; the
range-and-a-half checking wasn't particularly useful.
New test test_getargs2.py, to verify all this.
-rw-r--r-- | Include/intobject.h | 5 | ||||
-rw-r--r-- | Include/longobject.h | 2 | ||||
-rw-r--r-- | Lib/test/test_getargs2.py | 245 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 149 | ||||
-rw-r--r-- | Objects/intobject.c | 91 | ||||
-rw-r--r-- | Objects/longobject.c | 55 | ||||
-rw-r--r-- | Python/getargs.c | 76 |
7 files changed, 596 insertions, 27 deletions
diff --git a/Include/intobject.h b/Include/intobject.h index ab936b2615..61ef0f0f52 100644 --- a/Include/intobject.h +++ b/Include/intobject.h @@ -36,6 +36,11 @@ PyAPI_FUNC(PyObject *) PyInt_FromUnicode(Py_UNICODE*, int, int); #endif PyAPI_FUNC(PyObject *) PyInt_FromLong(long); PyAPI_FUNC(long) PyInt_AsLong(PyObject *); +PyAPI_FUNC(unsigned long) PyInt_AsUnsignedLongMask(PyObject *); +#ifdef HAVE_LONG_LONG +PyAPI_FUNC(unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *); +#endif + PyAPI_FUNC(long) PyInt_GetMax(void); /* Macro, trading safety for speed */ diff --git a/Include/longobject.h b/Include/longobject.h index 63ca1135db..8354963efc 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -19,6 +19,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); PyAPI_FUNC(long) PyLong_AsLong(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); +PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); /* _PyLong_AsScaledDouble returns a double x and an exponent e such that the true value is approximately equal to x * 2**(SHIFT*e). e is >= 0. @@ -37,6 +38,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG); PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG); PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *); PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *); +PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); #endif /* HAVE_LONG_LONG */ PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int); diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py new file mode 100644 index 0000000000..4cf876a389 --- /dev/null +++ b/Lib/test/test_getargs2.py @@ -0,0 +1,245 @@ +import unittest +from test import test_support +import sys + +import warnings, re +warnings.filterwarnings("ignore", category=DeprecationWarning, module=__name__) + +""" +> How about the following counterproposal. This also changes some of +> the other format codes to be a little more regular. +> +> Code C type Range check +> +> b unsigned char 0..UCHAR_MAX +> h unsigned short 0..USHRT_MAX +> B unsigned char none ** +> H unsigned short none ** +> k * unsigned long none +> I * unsigned int 0..UINT_MAX + + +> i int INT_MIN..INT_MAX +> l long LONG_MIN..LONG_MAX + +> K * unsigned long long none +> L long long LLONG_MIN..LLONG_MAX + +> Notes: +> +> * New format codes. +> +> ** Changed from previous "range-and-a-half" to "none"; the +> range-and-a-half checking wasn't particularly useful. + +Plus a C API or two, e.g. PyInt_AsLongMask() -> +unsigned long and PyInt_AsLongLongMask() -> unsigned +long long (if that exists). +""" + +LARGE = 0x7FFFFFFF +VERY_LARGE = 0xFF0000121212121212121242L + +from _testcapi import UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, INT_MAX, \ + INT_MIN, LONG_MIN, LONG_MAX + +from _testcapi import getargs_ul as ul_convert +from _testcapi import getargs_l as l_convert +try: + from _testcapi import getargs_ll as ll_convert + from _testcapi import getargs_ull as ull_convert +except ImportError: + pass + +# fake, they are not defined in Python's header files +LLONG_MAX = 2**63-1 +LLONG_MIN = -2**63 +ULLONG_MAX = 2**64-1 + +class Long: + def __int__(self): + return 99L + +class Int: + def __int__(self): + return 99 + +class Unsigned_TestCase(unittest.TestCase): + def test_b(self): + # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX) + self.failUnlessEqual(3, ul_convert("b", 3.14)) + self.failUnlessEqual(99, ul_convert("b", Long())) + self.failUnlessEqual(99, ul_convert("b", Int())) + + self.assertRaises(OverflowError, ul_convert, "b", -1) + self.failUnlessEqual(0, ul_convert("b", 0)) + self.failUnlessEqual(UCHAR_MAX, ul_convert("b", UCHAR_MAX)) + self.assertRaises(OverflowError, ul_convert, "b", UCHAR_MAX + 1) + + self.failUnlessEqual(42, ul_convert("b", 42)) + self.failUnlessEqual(42, ul_convert("b", 42L)) + self.assertRaises(OverflowError, ul_convert, "b", VERY_LARGE) + + def test_h(self): + # h returns 'unsigned short', and does range checking (0 ... USHRT_MAX) + self.failUnlessEqual(3, ul_convert("h", 3.14)) + self.failUnlessEqual(99, ul_convert("h", Long())) + self.failUnlessEqual(99, ul_convert("h", Int())) + + self.assertRaises(OverflowError, ul_convert, "h", -1) + self.failUnlessEqual(0, ul_convert("h", 0)) + self.failUnlessEqual(USHRT_MAX, ul_convert("h", USHRT_MAX)) + self.assertRaises(OverflowError, ul_convert, "h", USHRT_MAX+1) + + self.failUnlessEqual(42, ul_convert("h", 42)) + self.failUnlessEqual(42, ul_convert("h", 42L)) + self.assertRaises(OverflowError, ul_convert, "h", VERY_LARGE) + + def test_B(self): + # B returns 'unsigned char', no range checking + self.failUnless(3 == ul_convert("B", 3.14)) + self.failUnlessEqual(99, ul_convert("B", Long())) + self.failUnlessEqual(99, ul_convert("B", Int())) + + self.failUnlessEqual(UCHAR_MAX, ul_convert("B", -1)) + self.failUnlessEqual(UCHAR_MAX, ul_convert("B", -1L)) + self.failUnlessEqual(0, ul_convert("B", 0)) + self.failUnlessEqual(UCHAR_MAX, ul_convert("B", UCHAR_MAX)) + self.failUnlessEqual(0, ul_convert("B", UCHAR_MAX+1)) + + self.failUnlessEqual(42, ul_convert("B", 42)) + self.failUnlessEqual(42, ul_convert("B", 42L)) + self.failUnlessEqual(UCHAR_MAX & VERY_LARGE, ul_convert("B", VERY_LARGE)) + + def test_H(self): + # H returns 'unsigned short', no range checking + self.failUnlessEqual(3, ul_convert("H", 3.14)) + self.failUnlessEqual(99, ul_convert("H", Long())) + self.failUnlessEqual(99, ul_convert("H", Int())) + + self.failUnlessEqual(USHRT_MAX, ul_convert("H", -1)) + self.failUnlessEqual(0, ul_convert("H", 0)) + self.failUnlessEqual(USHRT_MAX, ul_convert("H", USHRT_MAX)) + self.failUnlessEqual(0, ul_convert("H", USHRT_MAX+1)) + + self.failUnlessEqual(42, ul_convert("H", 42)) + self.failUnlessEqual(42, ul_convert("H", 42L)) + + self.failUnlessEqual(VERY_LARGE & USHRT_MAX, ul_convert("H", VERY_LARGE)) + + def test_I(self): + # I returns 'unsigned int', no range checking + self.failUnlessEqual(3, ul_convert("I", 3.14)) + self.failUnlessEqual(99, ul_convert("I", Long())) + self.failUnlessEqual(99, ul_convert("I", Int())) + + self.failUnlessEqual(UINT_MAX, ul_convert("I", -1)) + self.failUnlessEqual(0, ul_convert("I", 0)) + self.failUnlessEqual(UINT_MAX, ul_convert("I", UINT_MAX)) + self.failUnlessEqual(0, ul_convert("I", UINT_MAX+1)) + + self.failUnlessEqual(42, ul_convert("I", 42)) + self.failUnlessEqual(42, ul_convert("I", 42L)) + + self.failUnlessEqual(VERY_LARGE & UINT_MAX, ul_convert("I", VERY_LARGE)) + + def test_k(self): + # k returns 'unsigned long', no range checking + # it does not accept float, or instances with __int__ + self.assertRaises(TypeError, ul_convert, "k", 3.14) + self.assertRaises(TypeError, ul_convert, "k", Long()) + self.assertRaises(TypeError, ul_convert, "k", Int()) + + self.failUnlessEqual(ULONG_MAX, ul_convert("k", -1)) + self.failUnlessEqual(0, ul_convert("k", 0)) + self.failUnlessEqual(ULONG_MAX, ul_convert("k", ULONG_MAX)) + self.failUnlessEqual(0, ul_convert("k", ULONG_MAX+1)) + + self.failUnlessEqual(42, ul_convert("k", 42)) + self.failUnlessEqual(42, ul_convert("k", 42L)) + + self.failUnlessEqual(VERY_LARGE & ULONG_MAX, ul_convert("k", VERY_LARGE)) + +class Signed_TestCase(unittest.TestCase): + def test_i(self): + # i returns 'int', and does range checking (INT_MIN ... INT_MAX) + self.failUnlessEqual(3, l_convert("i", 3.14)) + self.failUnlessEqual(99, l_convert("i", Long())) + self.failUnlessEqual(99, l_convert("i", Int())) + + self.assertRaises(OverflowError, l_convert, "i", INT_MIN-1) + self.failUnlessEqual(INT_MIN, l_convert("i", INT_MIN)) + self.failUnlessEqual(INT_MAX, l_convert("i", INT_MAX)) + self.assertRaises(OverflowError, l_convert, "i", INT_MAX+1) + + self.failUnlessEqual(42, l_convert("i", 42)) + self.failUnlessEqual(42, l_convert("i", 42L)) + self.assertRaises(OverflowError, l_convert, "i", VERY_LARGE) + + def test_l(self): + # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX) + self.failUnlessEqual(3, l_convert("l", 3.14)) + self.failUnlessEqual(99, l_convert("l", Long())) + self.failUnlessEqual(99, l_convert("l", Int())) + + self.assertRaises(OverflowError, l_convert, "l", LONG_MIN-1) + self.failUnlessEqual(LONG_MIN, l_convert("l", LONG_MIN)) + self.failUnlessEqual(LONG_MAX, l_convert("l", LONG_MAX)) + self.assertRaises(OverflowError, l_convert, "l", LONG_MAX+1) + + self.failUnlessEqual(42, l_convert("l", 42)) + self.failUnlessEqual(42, l_convert("l", 42L)) + self.assertRaises(OverflowError, l_convert, "l", VERY_LARGE) + + +class LongLong_TestCase(unittest.TestCase): + def test_L(self): + # L returns 'long long', and does range checking (LLONG_MIN ... LLONG_MAX) + + # XXX There's a bug in getargs.c, format code "L": + # If you pass something else than a Python long, you + # get "Bad argument to internal function". + + # So these three tests are commented out: + +## self.failUnlessEqual(3, ll_convert("L", 3.14)) +## self.failUnlessEqual(99, ll_convert("L", Long())) +## self.failUnlessEqual(99, ll_convert("L", Int())) + + self.assertRaises(OverflowError, ll_convert, "L", LLONG_MIN-1) + self.failUnlessEqual(LLONG_MIN, ll_convert("L", LLONG_MIN)) + self.failUnlessEqual(LLONG_MAX, ll_convert("L", LLONG_MAX)) + self.assertRaises(OverflowError, ll_convert, "L", LLONG_MAX+1) + + self.failUnlessEqual(42, ll_convert("L", 42)) + self.failUnlessEqual(42, ll_convert("L", 42L)) + self.assertRaises(OverflowError, ll_convert, "L", VERY_LARGE) + + def test_K(self): + # K return 'unsigned long long', no range checking + self.assertRaises(TypeError, ull_convert, "K", 3.14) + self.assertRaises(TypeError, ull_convert, "K", Long()) + self.assertRaises(TypeError, ull_convert, "K", Int()) + self.failUnlessEqual(ULLONG_MAX, ull_convert("K", ULLONG_MAX)) + self.failUnlessEqual(0, ull_convert("K", 0)) + self.failUnlessEqual(0, ull_convert("K", ULLONG_MAX+1)) + + self.failUnlessEqual(42, ull_convert("K", 42)) + self.failUnlessEqual(42, ull_convert("K", 42L)) + + self.failUnlessEqual(VERY_LARGE & ULLONG_MAX, ull_convert("K", VERY_LARGE)) + +def test_main(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(Signed_TestCase)) + suite.addTest(unittest.makeSuite(Unsigned_TestCase)) + try: + ll_convert + except NameError: + pass # PY_LONG_LONG not available + else: + suite.addTest(unittest.makeSuite(LongLong_TestCase)) + test_support.run_suite(suite) + +if __name__ == "__main__": + test_main() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c08dbb7e9b..b3da398355 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -290,6 +290,139 @@ test_L_code(PyObject *self) #endif /* ifdef HAVE_LONG_LONG */ +/* Call PyArg_ParseTuple, and return the result as unsigned long */ +static PyObject * +getargs_ul(PyObject *self, PyObject *args) +{ + PyObject *ob, *result = NULL, *argtuple; + char *fmt; + unsigned long value = 0; + + if (!PyArg_ParseTuple(args, "sO", &fmt, &ob)) + return NULL; + argtuple = PyTuple_New(1); + Py_INCREF(ob); + PyTuple_SET_ITEM(argtuple, 0, ob); + if (PyArg_ParseTuple(argtuple, fmt, &value)) + result = PyLong_FromUnsignedLong(value); + Py_DECREF(argtuple); + return result; +} + +/* Call PyArg_ParseTuple, and return the result as signed long */ +static PyObject * +getargs_l(PyObject *self, PyObject *args) +{ + PyObject *ob, *result = NULL, *argtuple; + char *fmt; + long value = 0; + + if (!PyArg_ParseTuple(args, "sO", &fmt, &ob)) + return NULL; + argtuple = PyTuple_New(1); + Py_INCREF(ob); + PyTuple_SET_ITEM(argtuple, 0, ob); + if (PyArg_ParseTuple(argtuple, fmt, &value)) + result = PyLong_FromLong(value); + Py_DECREF(argtuple); + return result; +} + +#ifdef HAVE_LONG_LONG +/* Call PyArg_ParseTuple, and return the result as signed long long */ +static PyObject * +getargs_ll(PyObject *self, PyObject *args) +{ + PyObject *ob, *result = NULL, *argtuple; + char *fmt; + PY_LONG_LONG value = 0; + + if (!PyArg_ParseTuple(args, "sO", &fmt, &ob)) + return NULL; + argtuple = PyTuple_New(1); + Py_INCREF(ob); + PyTuple_SET_ITEM(argtuple, 0, ob); + if (PyArg_ParseTuple(argtuple, fmt, &value)) + result = PyLong_FromLongLong(value); + Py_DECREF(argtuple); + return result; +} + +/* Call PyArg_ParseTuple, and return the result as unsigned long long */ +static PyObject * +getargs_ull(PyObject *self, PyObject *args) +{ + PyObject *ob, *result = NULL, *argtuple; + char *fmt; + unsigned PY_LONG_LONG value = 0; + + if (!PyArg_ParseTuple(args, "sO", &fmt, &ob)) + return NULL; + argtuple = PyTuple_New(1); + Py_INCREF(ob); + PyTuple_SET_ITEM(argtuple, 0, ob); + if (PyArg_ParseTuple(argtuple, fmt, &value)) + result = PyLong_FromUnsignedLongLong(value); + Py_DECREF(argtuple); + return result; +} +#endif + +/* This function not only tests the 'k' getargs code, but also the + PyInt_AsUnsignedLongMask() and PyInt_AsUnsignedLongMask() functions. */ +static PyObject * +test_k_code(PyObject *self) +{ + PyObject *tuple, *num; + unsigned long value; + + tuple = PyTuple_New(1); + if (tuple == NULL) + return NULL; + + /* a number larger than UINT_MAX even on 64-bit platforms */ + num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); + if (num == NULL) + return NULL; + + value = PyInt_AsUnsignedLongMask(num); + if (value != UINT_MAX) + return raiseTestError("test_k_code", + "PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); + + PyTuple_SET_ITEM(tuple, 0, num); + + value = -1; + if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + return NULL; + if (value != UINT_MAX) + return raiseTestError("test_k_code", + "k code returned wrong value for long 0xFFF...FFF"); + + Py_DECREF(num); + num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); + if (num == NULL) + return NULL; + + value = PyInt_AsUnsignedLongMask(num); + if (value != (unsigned long)-0x42) + return raiseTestError("test_k_code", + "PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); + + PyTuple_SET_ITEM(tuple, 0, num); + + value = -1; + if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + return NULL; + if (value != (unsigned long)-0x42) + return raiseTestError("test_k_code", + "k code returned wrong value for long -0xFFF..000042"); + + Py_DECREF(tuple); + Py_INCREF(Py_None); + return Py_None; +} + #ifdef Py_USING_UNICODE /* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case @@ -409,7 +542,12 @@ static PyMethodDef TestMethods[] = { {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, {"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS}, + {"test_k_code", (PyCFunction)test_k_code, METH_NOARGS}, + {"getargs_ul", (PyCFunction)getargs_ul, METH_VARARGS}, + {"getargs_l", (PyCFunction)getargs_l, METH_VARARGS}, #ifdef HAVE_LONG_LONG + {"getargs_ll", (PyCFunction)getargs_ll, METH_VARARGS}, + {"getargs_ull", (PyCFunction)getargs_ull, METH_VARARGS}, {"test_longlong_api", (PyCFunction)test_longlong_api, METH_NOARGS}, {"test_L_code", (PyCFunction)test_L_code, METH_NOARGS}, #endif @@ -419,6 +557,8 @@ static PyMethodDef TestMethods[] = { {NULL, NULL} /* sentinel */ }; +#define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);} + PyMODINIT_FUNC init_testcapi(void) { @@ -426,6 +566,15 @@ init_testcapi(void) m = Py_InitModule("_testcapi", TestMethods); + PyModule_AddObject(m, "UCHAR_MAX", PyInt_FromLong(UCHAR_MAX)); + PyModule_AddObject(m, "USHRT_MAX", PyInt_FromLong(USHRT_MAX)); + PyModule_AddObject(m, "UINT_MAX", PyLong_FromUnsignedLong(UINT_MAX)); + PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX)); + PyModule_AddObject(m, "INT_MIN", PyInt_FromLong(INT_MIN)); + PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN)); + PyModule_AddObject(m, "INT_MAX", PyInt_FromLong(INT_MAX)); + PyModule_AddObject(m, "LONG_MAX", PyInt_FromLong(LONG_MAX)); + TestError = PyErr_NewException("_testcapi.error", NULL, NULL); Py_INCREF(TestError); PyModule_AddObject(m, "error", TestError); diff --git a/Objects/intobject.c b/Objects/intobject.c index 611aedf9f4..4b5dc55632 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -169,6 +169,51 @@ PyInt_AsLong(register PyObject *op) } else { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return -1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +} + +unsigned long +PyInt_AsUnsignedLongMask(register PyObject *op) +{ + PyNumberMethods *nb; + PyIntObject *io; + unsigned long val; + + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + if (op && PyLong_Check(op)) + return PyLong_AsUnsignedLongMask(op); + + if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + io = (PyIntObject*) (*nb->nb_int) (op); + if (io == NULL) + return -1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + val = PyLong_AsUnsignedLongMask((PyObject *)io); + Py_DECREF(io); + if (PyErr_Occurred()) + return -1; + return val; + } + else + { + Py_DECREF(io); PyErr_SetString(PyExc_TypeError, "nb_int should return int object"); return -1; @@ -181,6 +226,52 @@ PyInt_AsLong(register PyObject *op) return val; } +#ifdef HAVE_LONG_LONG +unsigned PY_LONG_LONG +PyInt_AsUnsignedLongLongMask(register PyObject *op) +{ + PyNumberMethods *nb; + PyIntObject *io; + unsigned PY_LONG_LONG val; + + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + if (op && PyLong_Check(op)) + return PyLong_AsUnsignedLongLongMask(op); + + if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + io = (PyIntObject*) (*nb->nb_int) (op); + if (io == NULL) + return -1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + val = PyLong_AsUnsignedLongLongMask((PyObject *)io); + Py_DECREF(io); + if (PyErr_Occurred()) + return -1; + return val; + } + else + { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return -1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +} +#endif + PyObject * PyInt_FromString(char *s, char **pend, int base) { diff --git a/Objects/longobject.c b/Objects/longobject.c index e02bce4610..663befc5f3 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -260,6 +260,34 @@ PyLong_AsUnsignedLong(PyObject *vv) return x; } +/* Get a C unsigned long int from a long int object, ignoring the high bits. + Returns -1 and sets an error condition if an error occurs. */ + +unsigned long +PyLong_AsUnsignedLongMask(PyObject *vv) +{ + register PyLongObject *v; + unsigned long x; + int i, sign; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return (unsigned long) -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -i; + } + while (--i >= 0) { + x = (x << SHIFT) + v->ob_digit[i]; + } + return x * sign; +} + int _PyLong_Sign(PyObject *vv) { @@ -779,6 +807,33 @@ PyLong_AsUnsignedLongLong(PyObject *vv) return bytes; } +/* Get a C unsigned long int from a long int object, ignoring the high bits. + Returns -1 and sets an error condition if an error occurs. */ + +unsigned PY_LONG_LONG +PyLong_AsUnsignedLongLongMask(PyObject *vv) +{ + register PyLongObject *v; + unsigned PY_LONG_LONG x; + int i, sign; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return (unsigned long) -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -i; + } + while (--i >= 0) { + x = (x << SHIFT) + v->ob_digit[i]; + } + return x * sign; +} #undef IS_LITTLE_ENDIAN #endif /* HAVE_LONG_LONG */ diff --git a/Python/getargs.c b/Python/getargs.c index 1f37e41d83..e9808d541a 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -448,25 +448,15 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, long ival; if (float_argument_error(arg)) return NULL; - ival = PyInt_AsLong(arg); + ival = PyInt_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer<b>", arg, msgbuf, bufsize); - else if (ival < SCHAR_MIN) { - PyErr_SetString(PyExc_OverflowError, - "byte-sized integer bitfield is less than minimum"); return converterr("integer<B>", arg, msgbuf, bufsize); - } - else if (ival > (int)UCHAR_MAX) { - PyErr_SetString(PyExc_OverflowError, - "byte-sized integer bitfield is greater than maximum"); - return converterr("integer<B>", arg, msgbuf, bufsize); - } else *p = (unsigned char) ival; break; } - case 'h': {/* signed short int */ + case 'h': {/* unsigned short int */ short *p = va_arg(*p_va, short *); long ival; if (float_argument_error(arg)) @@ -474,14 +464,14 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return converterr("integer<h>", arg, msgbuf, bufsize); - else if (ival < SHRT_MIN) { + else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "unsigned short integer is less than minimum"); return converterr("integer<h>", arg, msgbuf, bufsize); } - else if (ival > SHRT_MAX) { + else if (ival > USHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "unsigned short integer is greater than maximum"); return converterr("integer<h>", arg, msgbuf, bufsize); } else @@ -495,19 +485,9 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, long ival; if (float_argument_error(arg)) return NULL; - ival = PyInt_AsLong(arg); + ival = PyInt_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) return converterr("integer<H>", arg, msgbuf, bufsize); - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "short integer bitfield is less than minimum"); - return converterr("integer<H>", arg, msgbuf, bufsize); - } - else if (ival > USHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "short integer bitfield is greater than maximum"); - return converterr("integer<H>", arg, msgbuf, bufsize); - } else *p = (unsigned short) ival; break; @@ -536,6 +516,20 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, break; } + case 'I': { /* int sized bitfield, both signed and + unsigned allowed */ + unsigned int *p = va_arg(*p_va, unsigned int *); + unsigned int ival; + if (float_argument_error(arg)) + return NULL; + ival = PyInt_AsUnsignedLongMask(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<I>", arg, msgbuf, bufsize); + else + *p = ival; + break; + } + case 'l': {/* long int */ long *p = va_arg(*p_va, long *); long ival; @@ -548,6 +542,19 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, *p = ival; break; } + + case 'k': { /* long sized bitfield */ + unsigned long *p = va_arg(*p_va, unsigned long *); + unsigned long ival; + if (PyInt_Check(arg)) + ival = PyInt_AsUnsignedLongMask(arg); + else if (PyLong_Check(arg)) + ival = PyLong_AsUnsignedLongMask(arg); + else + return converterr("integer<k>", arg, msgbuf, bufsize); + *p = ival; + break; + } #ifdef HAVE_LONG_LONG case 'L': {/* PY_LONG_LONG */ @@ -560,6 +567,21 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, } break; } + + case 'K': { /* long long sized bitfield */ + unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *); + unsigned PY_LONG_LONG ival; + if (float_argument_error(arg)) + return NULL; + if (PyInt_Check(arg)) + ival = PyInt_AsUnsignedLongMask(arg); + else if (PyLong_Check(arg)) + ival = PyLong_AsUnsignedLongLongMask(arg); + else + return converterr("integer<K>", arg, msgbuf, bufsize); + *p = ival; + break; + } #endif case 'f': {/* float */ |