tcl = self.interp
self.assertRaises(TclError,tcl.unsetvar,'a')
- integers = (0, 1, -1, 2**31-1, -2**31)
- if tcl_version >= (8, 4): # wideInt was added in Tcl 8.4
- integers += (2**31, -2**31-1, 2**63-1, -2**63)
+ def get_integers(self):
++ integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63)
+ if tcl_version >= (8, 5): # bignum was added in Tcl 8.5
+ integers += (2**63, -2**63-1, 2**1000, -2**1000)
+ return integers
+
def test_getint(self):
tcl = self.interp.tk
- self.assertEqual(tcl.getint(' 42 '), 42)
+ for i in self.get_integers():
+ self.assertEqual(tcl.getint(' %d ' % i), i)
+ self.assertEqual(tcl.getint(' %#o ' % i), i)
+ self.assertEqual(tcl.getint(' %#x ' % i), i)
+ if tcl_version < (8, 5): # bignum was added in Tcl 8.5
+ self.assertRaises(TclError, tcl.getint, str(2**1000))
self.assertEqual(tcl.getint(42), 42)
self.assertRaises(TypeError, tcl.getint)
self.assertRaises(TypeError, tcl.getint, '42', '10')
#include "tkinter.h"
-/* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */
-#ifndef CONST84_RETURN
-#define CONST84_RETURN
-#undef CONST
-#define CONST
-#endif
-
-#if TK_VERSION_HEX < 0x08030102
-#error "Tk older than 8.3.1 not supported"
+#if TK_VERSION_HEX < 0x08040002
+#error "Tk older than 8.4 not supported"
#endif
+ #if TK_VERSION_HEX >= 0x08050000
+ #define HAVE_LIBTOMMAMTH
+ #include <tclTomMath.h>
+ #endif
+
#if !(defined(MS_WINDOWS) || defined(__CYGWIN__))
#define HAVE_CREATEFILEHANDLER
#endif
AsObj(PyObject *value)
{
Tcl_Obj *result;
- long longVal;
- int overflow;
- if (PyBytes_Check(value))
+ if (PyBytes_Check(value)) {
+ if (PyBytes_GET_SIZE(value) >= INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
+ return NULL;
+ }
return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value),
- PyBytes_GET_SIZE(value));
+ (int)PyBytes_GET_SIZE(value));
+ }
- else if (PyBool_Check(value))
+
+ if (PyBool_Check(value))
return Tcl_NewBooleanObj(PyObject_IsTrue(value));
- else if (PyLong_CheckExact(value) &&
- ((longVal = PyLong_AsLongAndOverflow(value, &overflow)),
- !overflow)) {
+
+ if (PyLong_CheckExact(value)) {
+ int overflow;
+ long longValue;
+ #ifdef TCL_WIDE_INT_TYPE
+ Tcl_WideInt wideValue;
+ #endif
+ longValue = PyLong_AsLongAndOverflow(value, &overflow);
+ if (!overflow) {
+ return Tcl_NewLongObj(longValue);
+ }
/* If there is an overflow in the long conversion,
+ fall through to wideInt handling. */
+ #ifdef TCL_WIDE_INT_TYPE
+ if (_PyLong_AsByteArray((PyLongObject *)value,
+ (unsigned char *)(void *)&wideValue,
+ sizeof(wideValue),
+ PY_LITTLE_ENDIAN,
+ /* signed */ 1) == 0) {
+ return Tcl_NewWideIntObj(wideValue);
+ }
+ PyErr_Clear();
+ #endif
+ /* If there is an overflow in the wideInt conversion,
+ fall through to bignum handling. */
+ #ifdef HAVE_LIBTOMMAMTH
+ return asBignumObj(value);
+ #endif
+ /* If there is no wideInt or bignum support,
fall through to default object handling. */
- return Tcl_NewLongObj(longVal);
}
- else if (PyFloat_Check(value))
+
+ if (PyFloat_Check(value))
return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
- else if (PyTuple_Check(value) || PyList_Check(value)) {
+
- if (PyTuple_Check(value)) {
++ if (PyTuple_Check(value) || PyList_Check(value)) {
Tcl_Obj **argv;
Py_ssize_t size, i;
if (size == 0)
return Tcl_NewListObj(0, NULL);
if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
- PyErr_SetString(PyExc_OverflowError, "tuple is too long");
+ PyErr_SetString(PyExc_OverflowError,
+ PyTuple_Check(value) ? "tuple is too long" :
+ "list is too long");
return NULL;
}
- argv = (Tcl_Obj **) attemptckalloc(((size_t)size) * sizeof(Tcl_Obj *));
- if(!argv)
- return 0;
+ argv = (Tcl_Obj **) PyMem_Malloc(((size_t)size) * sizeof(Tcl_Obj *));
+ if (!argv) {
+ PyErr_NoMemory();
+ return NULL;
+ }
for (i = 0; i < size; i++)
- argv[i] = AsObj(PyTuple_GetItem(value,i));
- result = Tcl_NewListObj(PyTuple_Size(value), argv);
- ckfree(FREECAST argv);
+ argv[i] = AsObj(PySequence_Fast_GET_ITEM(value,i));
+ result = Tcl_NewListObj((int)size, argv);
+ PyMem_Free(argv);
return result;
}
- else if (PyUnicode_Check(value)) {
+
+ if (PyUnicode_Check(value)) {
void *inbuf;
Py_ssize_t size;
int kind;
#endif
outbuf[i] = ch;
}
- result = Tcl_NewUnicodeObj(outbuf, size);
- ckfree(FREECAST outbuf);
+ result = Tcl_NewUnicodeObj(outbuf, (int)size);
+ PyMem_Free(outbuf);
return result;
}
- else if(PyTclObject_Check(value)) {
+
+ if (PyTclObject_Check(value)) {
Tcl_Obj *v = ((PyTclObject*)value)->value;
Tcl_IncrRefCount(v);
return v;
return PyBool_FromLong(boolValue);
}
-#ifdef TCL_WIDE_INT_TYPE
+ static PyObject*
+ fromWideIntObj(PyObject* tkapp, Tcl_Obj *value)
+ {
+ Tcl_WideInt wideValue;
+ if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) {
+ #ifdef HAVE_LONG_LONG
+ if (sizeof(wideValue) <= SIZEOF_LONG_LONG)
+ return PyLong_FromLongLong(wideValue);
+ #endif
+ return _PyLong_FromByteArray((unsigned char *)(void *)&wideValue,
+ sizeof(wideValue),
+ PY_LITTLE_ENDIAN,
+ /* signed */ 1);
+ }
+ return NULL;
+ }
-#endif
+
+ #ifdef HAVE_LIBTOMMAMTH
+ static PyObject*
+ fromBignumObj(PyObject* tkapp, Tcl_Obj *value)
+ {
+ mp_int bigValue;
+ unsigned long numBytes;
+ unsigned char *bytes;
+ PyObject *res;
+
+ if (Tcl_GetBignumFromObj(Tkapp_Interp(tkapp), value, &bigValue) != TCL_OK)
+ return Tkinter_Error(tkapp);
+ numBytes = mp_unsigned_bin_size(&bigValue);
+ bytes = PyMem_Malloc(numBytes);
+ if (bytes == NULL) {
+ mp_clear(&bigValue);
+ return PyErr_NoMemory();
+ }
+ if (mp_to_unsigned_bin_n(&bigValue, bytes,
+ &numBytes) != MP_OKAY) {
+ mp_clear(&bigValue);
+ PyMem_Free(bytes);
+ return PyErr_NoMemory();
+ }
+ res = _PyLong_FromByteArray(bytes, numBytes,
+ /* big-endian */ 0,
+ /* unsigned */ 0);
+ PyMem_Free(bytes);
+ if (res != NULL && bigValue.sign == MP_NEG) {
+ PyObject *res2 = PyNumber_Negative(res);
+ Py_DECREF(res);
+ res = res2;
+ }
+ mp_clear(&bigValue);
+ return res;
+ }
+ #endif
+
static PyObject*
FromObj(PyObject* tkapp, Tcl_Obj *value)
{
}
if (value->typePtr == app->IntType) {
- return PyLong_FromLong(value->internalRep.longValue);
+ long longValue;
+ if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
+ return PyLong_FromLong(longValue);
+ /* If there is an error in the long conversion,
+ fall through to wideInt handling. */
+ }
+
-#ifdef TCL_WIDE_INT_TYPE
+ if (value->typePtr == app->IntType ||
+ value->typePtr == app->WideIntType) {
+ result = fromWideIntObj(tkapp, value);
+ if (result != NULL || PyErr_Occurred())
+ return result;
+ Tcl_ResetResult(interp);
+ /* If there is an error in the wideInt conversion,
+ fall through to bignum handling. */
+ }
-#endif
+
+ #ifdef HAVE_LIBTOMMAMTH
+ if (value->typePtr == app->IntType ||
+ value->typePtr == app->WideIntType ||
+ value->typePtr == app->BignumType) {
+ return fromBignumObj(tkapp, value);
}
+ #endif
if (value->typePtr == app->ListType) {
int size;
Tkapp_GetInt(PyObject *self, PyObject *args)
{
char *s;
- int v;
-#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
+ Tcl_Obj *value;
+ PyObject *result;
-#else
- int intValue;
-#endif
if (PyTuple_Size(args) == 1) {
PyObject* o = PyTuple_GetItem(args, 0);
if (!PyArg_ParseTuple(args, "s:getint", &s))
return NULL;
CHECK_STRING_LENGTH(s);
- if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
-#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
+ value = Tcl_NewStringObj(s, -1);
+ if (value == NULL)
return Tkinter_Error(self);
- return Py_BuildValue("i", v);
+ /* Don't use Tcl_GetInt() because it returns ambiguous result for value
+ in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform).
+
+ Prefer bignum because Tcl_GetWideIntFromObj returns ambiguous result for
+ value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).
+ */
+ #ifdef HAVE_LIBTOMMAMTH
+ result = fromBignumObj(self, value);
+ #else
+ result = fromWideIntObj(self, value);
+ #endif
+ Tcl_DecrRefCount(value);
+ if (result != NULL || PyErr_Occurred())
+ return result;
-#else
- if (Tcl_GetInt(Tkapp_Interp(self), s, &intValue) == TCL_OK)
- return PyLong_FromLong(intValue);
-#endif
+ return Tkinter_Error(self);
}
static PyObject *