--- longobject.c.orig 2009-12-17 21:48:43.820928178 -0800 +++ longobject.c 2009-12-17 21:57:56.530933907 -0800 @@ -227,49 +227,110 @@ Returns -1 and sets an error condition if overflow occurs. */ long -PyLong_AsLong(PyObject *vv) +PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) { /* This version by Tim Peters */ register PyLongObject *v; unsigned long x, prev; + long res; Py_ssize_t i; int sign; + int do_decref = 0; /* if nb_int was called */ - if (vv == NULL || !PyLong_Check(vv)) { - if (vv != NULL && PyInt_Check(vv)) - return PyInt_AsLong(vv); + *overflow = 0; + if (vv == NULL) { PyErr_BadInternalCall(); return -1; } - v = (PyLongObject *)vv; - i = v->ob_size; - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } - while (--i >= 0) { - prev = x; - x = (x << PyLong_SHIFT) | v->ob_digit[i]; - if ((x >> PyLong_SHIFT) != prev) - goto overflow; + + if(PyInt_Check(vv)) + return PyInt_AsLong(vv); + + if (!PyLong_Check(vv)) { + PyNumberMethods *nb; + if ((nb = vv->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + vv = (*nb->nb_int) (vv); + if (vv == NULL) + return -1; + do_decref = 1; + if(PyInt_Check(vv)) { + res = PyInt_AsLong(vv); + goto exit; + } + if (!PyLong_Check(vv)) { + Py_DECREF(vv); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return -1; + } } - /* Haven't lost any bits, but casting to long requires extra care - * (see comment above). - */ - if (x <= (unsigned long)LONG_MAX) { - return (long)x * sign; + + res = -1; + v = (PyLongObject *)vv; + i = Py_SIZE(v); + + switch (i) { + case -1: + res = -(sdigit)v->ob_digit[0]; + break; + case 0: + res = 0; + break; + case 1: + res = v->ob_digit[0]; + break; + default: + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } + while (--i >= 0) { + prev = x; + x = (x << PyLong_SHIFT) + v->ob_digit[i]; + if ((x >> PyLong_SHIFT) != prev) { + *overflow = Py_SIZE(v) > 0 ? 1 : -1; + goto exit; + } + } + /* Haven't lost any bits, but casting to long requires extra care + * (see comment above). + */ + if (x <= (unsigned long)LONG_MAX) { + res = (long)x * sign; + } + else if (sign < 0 && x == PY_ABS_LONG_MIN) { + res = LONG_MIN; + } + else { + *overflow = Py_SIZE(v) > 0 ? 1 : -1; + /* res is already set to -1 */ + } } - else if (sign < 0 && x == PY_ABS_LONG_MIN) { - return LONG_MIN; + exit: + if (do_decref) { + Py_DECREF(vv); } - /* else overflow */ + return res; +} - overflow: - PyErr_SetString(PyExc_OverflowError, - "long int too large to convert to int"); - return -1; +long +PyLong_AsLong(PyObject *obj) +{ + int overflow; + long result = PyLong_AsLongAndOverflow(obj, &overflow); + if (overflow) { + /* XXX: could be cute and give a different + message for overflow == -1 */ + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C long"); + } + return result; } /* Get a Py_ssize_t from a long int object. --- longobject.h.orig 2009-12-17 21:59:20.220943524 -0800 +++ longobject.h 2009-12-17 22:00:17.331635763 -0800 @@ -21,6 +21,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t); PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t); PyAPI_FUNC(long) PyLong_AsLong(PyObject *); +PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);