|
|
|
@ -69,6 +69,11 @@ Copyright (C) 1994 Steen Lumholt. |
|
|
|
#error "Tk older than 8.3.1 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 |
|
|
|
@ -247,6 +252,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; |
|
|
|
@ -583,6 +590,8 @@ Tkapp_New(char *screenName, 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"); |
|
|
|
@ -875,28 +884,92 @@ 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)) |
|
|
|
return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value), |
|
|
|
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)) { |
|
|
|
|
|
|
|
if (PyTuple_Check(value)) { |
|
|
|
Tcl_Obj **argv; |
|
|
|
Py_ssize_t size, i; |
|
|
|
|
|
|
|
@ -916,7 +989,8 @@ AsObj(PyObject *value) |
|
|
|
ckfree(FREECAST argv); |
|
|
|
return result; |
|
|
|
} |
|
|
|
else if (PyUnicode_Check(value)) { |
|
|
|
|
|
|
|
if (PyUnicode_Check(value)) { |
|
|
|
void *inbuf; |
|
|
|
Py_ssize_t size; |
|
|
|
int kind; |
|
|
|
@ -966,12 +1040,14 @@ AsObj(PyObject *value) |
|
|
|
ckfree(FREECAST 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; |
|
|
|
@ -990,6 +1066,62 @@ fromBoolean(PyObject* tkapp, Tcl_Obj *value) |
|
|
|
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) |
|
|
|
{ |
|
|
|
@ -1017,8 +1149,32 @@ 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; |
|
|
|
@ -1067,6 +1223,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); |
|
|
|
} |
|
|
|
|
|
|
|
@ -1700,7 +1865,12 @@ static PyObject * |
|
|
|
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); |
|
|
|
@ -1712,9 +1882,29 @@ 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) |
|
|
|
#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 * |
|
|
|
|