mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
Issue #16840: Tkinter now supports 64-bit integers added in Tcl 8.4 and
arbitrary precision integers added in Tcl 8.5.
This commit is contained in:
commit
4c7dc48ea5
3 changed files with 233 additions and 23 deletions
|
@ -56,6 +56,11 @@ Copyright (C) 1994 Steen Lumholt.
|
|||
#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
|
||||
|
@ -234,6 +239,8 @@ typedef struct {
|
|||
const Tcl_ObjType *ByteArrayType;
|
||||
const Tcl_ObjType *DoubleType;
|
||||
const Tcl_ObjType *IntType;
|
||||
const Tcl_ObjType *WideIntType;
|
||||
const Tcl_ObjType *BignumType;
|
||||
const Tcl_ObjType *ListType;
|
||||
const Tcl_ObjType *ProcBodyType;
|
||||
const Tcl_ObjType *StringType;
|
||||
|
@ -591,6 +598,8 @@ Tkapp_New(const char *screenName, const char *className,
|
|||
v->ByteArrayType = Tcl_GetObjType("bytearray");
|
||||
v->DoubleType = Tcl_GetObjType("double");
|
||||
v->IntType = Tcl_GetObjType("int");
|
||||
v->WideIntType = Tcl_GetObjType("wideInt");
|
||||
v->BignumType = Tcl_GetObjType("bignum");
|
||||
v->ListType = Tcl_GetObjType("list");
|
||||
v->ProcBodyType = Tcl_GetObjType("procbody");
|
||||
v->StringType = Tcl_GetObjType("string");
|
||||
|
@ -883,12 +892,49 @@ static PyType_Spec PyTclObject_Type_spec = {
|
|||
#define CHECK_STRING_LENGTH(s)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBTOMMAMTH
|
||||
static Tcl_Obj*
|
||||
asBignumObj(PyObject *value)
|
||||
{
|
||||
Tcl_Obj *result;
|
||||
int neg;
|
||||
PyObject *hexstr;
|
||||
char *hexchars;
|
||||
mp_int bigValue;
|
||||
|
||||
neg = Py_SIZE(value) < 0;
|
||||
hexstr = _PyLong_Format(value, 16);
|
||||
if (hexstr == NULL)
|
||||
return NULL;
|
||||
hexchars = PyUnicode_AsUTF8(hexstr);
|
||||
if (hexchars == NULL) {
|
||||
Py_DECREF(hexstr);
|
||||
return NULL;
|
||||
}
|
||||
hexchars += neg + 2; /* skip sign and "0x" */
|
||||
mp_init(&bigValue);
|
||||
if (mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) {
|
||||
mp_clear(&bigValue);
|
||||
Py_DECREF(hexstr);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(hexstr);
|
||||
bigValue.sign = neg ? MP_NEG : MP_ZPOS;
|
||||
result = Tcl_NewBignumObj(&bigValue);
|
||||
mp_clear(&bigValue);
|
||||
if (result == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Tcl_Obj*
|
||||
AsObj(PyObject *value)
|
||||
{
|
||||
Tcl_Obj *result;
|
||||
long longVal;
|
||||
int overflow;
|
||||
|
||||
if (PyBytes_Check(value)) {
|
||||
if (PyBytes_GET_SIZE(value) >= INT_MAX) {
|
||||
|
@ -898,18 +944,45 @@ AsObj(PyObject *value)
|
|||
return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(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) || PyList_Check(value)) {
|
||||
Tcl_Obj **argv;
|
||||
Py_ssize_t size, i;
|
||||
|
||||
|
@ -933,7 +1006,8 @@ AsObj(PyObject *value)
|
|||
PyMem_Free(argv);
|
||||
return result;
|
||||
}
|
||||
else if (PyUnicode_Check(value)) {
|
||||
|
||||
if (PyUnicode_Check(value)) {
|
||||
void *inbuf;
|
||||
Py_ssize_t size;
|
||||
int kind;
|
||||
|
@ -983,12 +1057,14 @@ AsObj(PyObject *value)
|
|||
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;
|
||||
}
|
||||
else {
|
||||
|
||||
{
|
||||
PyObject *v = PyObject_Str(value);
|
||||
if (!v)
|
||||
return 0;
|
||||
|
@ -1007,6 +1083,60 @@ fromBoolean(PyObject* tkapp, Tcl_Obj *value)
|
|||
return PyBool_FromLong(boolValue);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -1034,9 +1164,31 @@ 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. */
|
||||
}
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
#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;
|
||||
int i, status;
|
||||
|
@ -1084,6 +1236,15 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBTOMMAMTH
|
||||
if (app->BignumType == NULL &&
|
||||
strcmp(value->typePtr->name, "bignum") == 0) {
|
||||
/* bignum type is not registered in Tcl */
|
||||
app->BignumType = value->typePtr;
|
||||
return fromBignumObj(tkapp, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
return newPyTclObject(value);
|
||||
}
|
||||
|
||||
|
@ -1718,7 +1879,8 @@ static PyObject *
|
|||
Tkapp_GetInt(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *s;
|
||||
int v;
|
||||
Tcl_Obj *value;
|
||||
PyObject *result;
|
||||
|
||||
if (PyTuple_Size(args) == 1) {
|
||||
PyObject* o = PyTuple_GetItem(args, 0);
|
||||
|
@ -1730,9 +1892,24 @@ Tkapp_GetInt(PyObject *self, PyObject *args)
|
|||
if (!PyArg_ParseTuple(args, "s:getint", &s))
|
||||
return NULL;
|
||||
CHECK_STRING_LENGTH(s);
|
||||
if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
|
||||
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;
|
||||
return Tkinter_Error(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue