summaryrefslogtreecommitdiffstats
path: root/Modules/_tkinter.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_tkinter.c')
-rw-r--r--Modules/_tkinter.c1049
1 files changed, 566 insertions, 483 deletions
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 262d679..52025bb 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -34,7 +34,7 @@ Copyright (C) 1994 Steen Lumholt.
#endif
#define CHECK_SIZE(size, elemsize) \
- ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize)))
+ ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize)))
/* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately,
making _tkinter correct for this API means to break earlier
@@ -65,10 +65,16 @@ Copyright (C) 1994 Steen Lumholt.
#define CONST
#endif
-#if TK_VERSION_HEX < 0x08030102
+#if TK_HEX_VERSION < 0x08030201
#error "Tk older than 8.3.1 not supported"
#endif
+#if TK_HEX_VERSION >= 0x08050208 && TK_HEX_VERSION < 0x08060000 || \
+ TK_HEX_VERSION >= 0x08060200
+#define HAVE_LIBTOMMAMTH
+#include <tclTomMath.h>
+#endif
+
#if !(defined(MS_WINDOWS) || defined(__CYGWIN__))
#define HAVE_CREATEFILEHANDLER
#endif
@@ -114,52 +120,60 @@ Copyright (C) 1994 Steen Lumholt.
/* The threading situation is complicated. Tcl is not thread-safe, except
when configured with --enable-threads.
- So we need to use a lock around all uses of Tcl. Previously, the Python
- interpreter lock was used for this. However, this causes problems when
- other Python threads need to run while Tcl is blocked waiting for events.
-
- To solve this problem, a separate lock for Tcl is introduced. Holding it
- is incompatible with holding Python's interpreter lock. The following four
- macros manipulate both locks together.
-
- ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and
- Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made
- that could call an event handler, or otherwise affect the state of a Tcl
- interpreter. These assume that the surrounding code has the Python
- interpreter lock; inside the brackets, the Python interpreter lock has been
- released and the lock for Tcl has been acquired.
-
- Sometimes, it is necessary to have both the Python lock and the Tcl lock.
- (For example, when transferring data from the Tcl interpreter result to a
- Python string object.) This can be done by using different macros to close
- the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores
- the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL
- releases the Tcl lock.
+
+ So we need to use a lock around all uses of Tcl. Previously, the
+ Python interpreter lock was used for this. However, this causes
+ problems when other Python threads need to run while Tcl is blocked
+ waiting for events.
+
+ To solve this problem, a separate lock for Tcl is introduced.
+ Holding it is incompatible with holding Python's interpreter lock.
+ The following four macros manipulate both locks together.
+
+ ENTER_TCL and LEAVE_TCL are brackets, just like
+ Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS. They should be
+ used whenever a call into Tcl is made that could call an event
+ handler, or otherwise affect the state of a Tcl interpreter. These
+ assume that the surrounding code has the Python interpreter lock;
+ inside the brackets, the Python interpreter lock has been released
+ and the lock for Tcl has been acquired.
+
+ Sometimes, it is necessary to have both the Python lock and the Tcl
+ lock. (For example, when transferring data from the Tcl
+ interpreter result to a Python string object.) This can be done by
+ using different macros to close the ENTER_TCL block: ENTER_OVERLAP
+ reacquires the Python lock (and restores the thread state) but
+ doesn't release the Tcl lock; LEAVE_OVERLAP_TCL releases the Tcl
+ lock.
By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event
- handlers when the handler needs to use Python. Such event handlers are
- entered while the lock for Tcl is held; the event handler presumably needs
- to use Python. ENTER_PYTHON releases the lock for Tcl and acquires
- the Python interpreter lock, restoring the appropriate thread state, and
- LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock
- for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside
- the code between ENTER_PYTHON and LEAVE_PYTHON.
-
- These locks expand to several statements and brackets; they should not be
- used in branches of if statements and the like.
-
- If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is
- only valid in the thread that created it, and all Tk activity must happen in this
- thread, also. That means that the mainloop must be invoked in the thread that
- created the interpreter. Invoking commands from other threads is possible;
- _tkinter will queue an event for the interpreter thread, which will then
- execute the command and pass back the result. If the main thread is not in the
- mainloop, and invoking commands causes an exception; if the main loop is running
- but not processing events, the command invocation will block.
-
- In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient
- anymore, since multiple Tcl interpreters may simultaneously dispatch in different
- threads. So we use the Tcl TLS API.
+ handlers when the handler needs to use Python. Such event handlers
+ are entered while the lock for Tcl is held; the event handler
+ presumably needs to use Python. ENTER_PYTHON releases the lock for
+ Tcl and acquires the Python interpreter lock, restoring the
+ appropriate thread state, and LEAVE_PYTHON releases the Python
+ interpreter lock and re-acquires the lock for Tcl. It is okay for
+ ENTER_TCL/LEAVE_TCL pairs to be contained inside the code between
+ ENTER_PYTHON and LEAVE_PYTHON.
+
+ These locks expand to several statements and brackets; they should
+ not be used in branches of if statements and the like.
+
+ If Tcl is threaded, this approach won't work anymore. The Tcl
+ interpreter is only valid in the thread that created it, and all Tk
+ activity must happen in this thread, also. That means that the
+ mainloop must be invoked in the thread that created the
+ interpreter. Invoking commands from other threads is possible;
+ _tkinter will queue an event for the interpreter thread, which will
+ then execute the command and pass back the result. If the main
+ thread is not in the mainloop, and invoking commands causes an
+ exception; if the main loop is running but not processing events,
+ the command invocation will block.
+
+ In addition, for a threaded Tcl, a single global tcl_tstate won't
+ be sufficient anymore, since multiple Tcl interpreters may
+ simultaneously dispatch in different threads. So we use the Tcl TLS
+ API.
*/
@@ -168,7 +182,8 @@ static PyThread_type_lock tcl_lock = 0;
#ifdef TCL_THREADS
static Tcl_ThreadDataKey state_key;
typedef PyThreadState *ThreadSpecificData;
-#define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
+#define tcl_tstate \
+ (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))
#else
static PyThreadState *tcl_tstate = NULL;
#endif
@@ -178,7 +193,8 @@ static PyThreadState *tcl_tstate = NULL;
if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate;
#define LEAVE_TCL \
- tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
+ tcl_tstate = NULL; \
+ if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS}
#define ENTER_OVERLAP \
Py_END_ALLOW_THREADS
@@ -188,7 +204,8 @@ static PyThreadState *tcl_tstate = NULL;
#define ENTER_PYTHON \
{ PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \
- if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
+ if(tcl_lock) \
+ PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); }
#define LEAVE_PYTHON \
{ PyThreadState *tstate = PyEval_SaveThread(); \
@@ -197,7 +214,8 @@ static PyThreadState *tcl_tstate = NULL;
#define CHECK_TCL_APPARTMENT \
if (((TkappObject *)self)->threaded && \
((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \
- PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "Calling Tcl from different appartment"); \
return 0; \
}
@@ -219,7 +237,7 @@ static PyThreadState *tcl_tstate = NULL;
/**** Tkapp Object Declaration ****/
-static PyTypeObject Tkapp_Type;
+static PyObject *Tkapp_Type;
typedef struct {
PyObject_HEAD
@@ -230,16 +248,18 @@ typedef struct {
int dispatching;
/* We cannot include tclInt.h, as this is internal.
So we cache interesting types here. */
- Tcl_ObjType *BooleanType;
- Tcl_ObjType *ByteArrayType;
- Tcl_ObjType *DoubleType;
- Tcl_ObjType *IntType;
- Tcl_ObjType *ListType;
- Tcl_ObjType *ProcBodyType;
- Tcl_ObjType *StringType;
+ const Tcl_ObjType *OldBooleanType;
+ const Tcl_ObjType *BooleanType;
+ 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;
} TkappObject;
-#define Tkapp_Check(v) (Py_TYPE(v) == &Tkapp_Type)
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
@@ -312,110 +332,9 @@ WaitForMainloop(TkappObject* self)
#endif /* WITH_THREAD */
-static char *
-AsString(PyObject *value, PyObject *tmp)
-{
- if (PyBytes_Check(value))
- return PyBytes_AsString(value);
- else if (PyUnicode_Check(value))
- return PyUnicode_AsUTF8(value);
- else {
- PyObject *v = PyObject_Str(value);
- if (v == NULL)
- return NULL;
- if (PyList_Append(tmp, v) != 0) {
- Py_DECREF(v);
- return NULL;
- }
- Py_DECREF(v);
- return PyUnicode_AsUTF8(v);
- }
-}
-
-
#define ARGSZ 64
-static char *
-Merge(PyObject *args)
-{
- PyObject *tmp = NULL;
- char *argvStore[ARGSZ];
- char **argv = NULL;
- int fvStore[ARGSZ];
- int *fv = NULL;
- Py_ssize_t argc = 0, fvc = 0, i;
- char *res = NULL;
-
- if (!(tmp = PyList_New(0)))
- return NULL;
-
- argv = argvStore;
- fv = fvStore;
-
- if (args == NULL)
- argc = 0;
-
- else if (!PyTuple_Check(args)) {
- argc = 1;
- fv[0] = 0;
- if (!(argv[0] = AsString(args, tmp)))
- goto finally;
- }
- else {
- argc = PyTuple_Size(args);
-
- if (argc > ARGSZ) {
- if (!CHECK_SIZE(argc, sizeof(char *))) {
- PyErr_SetString(PyExc_OverflowError, "tuple is too long");
- goto finally;
- }
- argv = (char **)ckalloc((size_t)argc * sizeof(char *));
- fv = (int *)ckalloc((size_t)argc * sizeof(int));
- if (argv == NULL || fv == NULL) {
- PyErr_NoMemory();
- goto finally;
- }
- }
-
- for (i = 0; i < argc; i++) {
- PyObject *v = PyTuple_GetItem(args, i);
- if (PyTuple_Check(v)) {
- fv[i] = 1;
- if (!(argv[i] = Merge(v)))
- goto finally;
- fvc++;
- }
- else if (v == Py_None) {
- argc = i;
- break;
- }
- else {
- fv[i] = 0;
- if (!(argv[i] = AsString(v, tmp)))
- goto finally;
- fvc++;
- }
- }
- }
- res = Tcl_Merge(argc, argv);
- if (res == NULL)
- PyErr_SetString(Tkinter_TclError, "merge failed");
-
- finally:
- for (i = 0; i < fvc; i++)
- if (fv[i]) {
- ckfree(argv[i]);
- }
- if (argv != argvStore)
- ckfree(FREECAST argv);
- if (fv != fvStore)
- ckfree(FREECAST fv);
-
- Py_DECREF(tmp);
- return res;
-}
-
static PyObject *
@@ -429,8 +348,10 @@ unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
const char *e = s + size;
PyErr_Clear();
q = buf = (char *)PyMem_Malloc(size);
- if (buf == NULL)
+ if (buf == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
while (s != e) {
if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') {
*q++ = '\0';
@@ -471,8 +392,7 @@ Split(char *list)
PyObject *v;
if (list == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) {
@@ -504,9 +424,9 @@ Split(char *list)
return v;
}
-/* In some cases, Tcl will still return strings that are supposed to be
- lists. SplitObj walks through a nested tuple, finding string objects that
- need to be split. */
+/* In some cases, Tcl will still return strings that are supposed to
+ be lists. SplitObj walks through a nested tuple, finding string
+ objects that need to be split. */
static PyObject *
SplitObj(PyObject *arg)
@@ -638,9 +558,10 @@ Tkapp_New(char *screenName, char *className,
TkappObject *v;
char *argv0;
- v = PyObject_New(TkappObject, &Tkapp_Type);
+ v = PyObject_New(TkappObject, (PyTypeObject *) Tkapp_Type);
if (v == NULL)
return NULL;
+ Py_INCREF(Tkapp_Type);
v->interp = Tcl_CreateInterp();
v->wantobjects = wantobjects;
@@ -651,7 +572,8 @@ Tkapp_New(char *screenName, char *className,
#ifndef TCL_THREADS
if (v->threaded) {
- PyErr_SetString(PyExc_RuntimeError, "Tcl is threaded but _tkinter is not");
+ PyErr_SetString(PyExc_RuntimeError,
+ "Tcl is threaded but _tkinter is not");
Py_DECREF(v);
return 0;
}
@@ -664,10 +586,13 @@ Tkapp_New(char *screenName, char *className,
}
#endif
- v->BooleanType = Tcl_GetObjType("boolean");
+ v->OldBooleanType = Tcl_GetObjType("boolean");
+ v->BooleanType = Tcl_GetObjType("booleanString");
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");
@@ -685,7 +610,7 @@ Tkapp_New(char *screenName, char *className,
Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
/* This is used to get the application class for Tk 4.1 and up */
- argv0 = (char*)ckalloc(strlen(className) + 1);
+ argv0 = (char*)attemptckalloc(strlen(className) + 1);
if (!argv0) {
PyErr_NoMemory();
Py_DECREF(v);
@@ -719,7 +644,7 @@ Tkapp_New(char *screenName, char *className,
if (use)
len += strlen(use) + sizeof "-use ";
- args = (char*)ckalloc(len);
+ args = (char*)attemptckalloc(len);
if (!args) {
PyErr_NoMemory();
Py_DECREF(v);
@@ -788,16 +713,17 @@ typedef struct {
PyObject *string; /* This cannot cause cycles. */
} PyTclObject;
-static PyTypeObject PyTclObject_Type;
-#define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type)
+static PyObject *PyTclObject_Type;
+#define PyTclObject_Check(v) ((v)->ob_type == (PyTypeObject *) PyTclObject_Type)
static PyObject *
newPyTclObject(Tcl_Obj *arg)
{
PyTclObject *self;
- self = PyObject_New(PyTclObject, &PyTclObject_Type);
+ self = PyObject_New(PyTclObject, (PyTypeObject *) PyTclObject_Type);
if (self == NULL)
return NULL;
+ Py_INCREF(PyTclObject_Type);
Tcl_IncrRefCount(arg);
self->value = arg;
self->string = NULL;
@@ -807,9 +733,11 @@ newPyTclObject(Tcl_Obj *arg)
static void
PyTclObject_dealloc(PyTclObject *self)
{
+ PyObject *tp = (PyObject *) Py_TYPE(self);
Tcl_DecrRefCount(self->value);
Py_XDECREF(self->string);
PyObject_Del(self);
+ Py_DECREF(tp);
}
static char*
@@ -848,8 +776,13 @@ PyTclObject_str(PyTclObject *self, void *ignored)
static PyObject *
PyTclObject_repr(PyTclObject *self)
{
- return PyUnicode_FromFormat("<%s object at %p>",
- self->value->typePtr->name, self->value);
+ PyObject *repr, *str = PyTclObject_str(self, NULL);
+ if (str == NULL)
+ return NULL;
+ repr = PyUnicode_FromFormat("<%s object: %R>",
+ self->value->typePtr->name, str);
+ Py_DECREF(str);
+ return repr;
}
#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
@@ -923,81 +856,132 @@ static PyGetSetDef PyTclObject_getsetlist[] = {
{0},
};
-static PyTypeObject PyTclObject_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_tkinter.Tcl_Obj", /*tp_name*/
- sizeof(PyTclObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)PyTclObject_dealloc,/*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_reserved*/
- (reprfunc)PyTclObject_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- (reprfunc)PyTclObject_str, /*tp_str*/
- PyObject_GenericGetAttr, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- PyTclObject_richcompare, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- 0, /*tp_methods*/
- 0, /*tp_members*/
- PyTclObject_getsetlist, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- 0, /*tp_init*/
- 0, /*tp_alloc*/
- 0, /*tp_new*/
- 0, /*tp_free*/
- 0, /*tp_is_gc*/
+static PyType_Slot PyTclObject_Type_slots[] = {
+ {Py_tp_dealloc, (destructor)PyTclObject_dealloc},
+ {Py_tp_repr, (reprfunc)PyTclObject_repr},
+ {Py_tp_str, (reprfunc)PyTclObject_str},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_richcompare, PyTclObject_richcompare},
+ {Py_tp_getset, PyTclObject_getsetlist},
+ {0, 0}
};
+static PyType_Spec PyTclObject_Type_spec = {
+ "_tkinter.Tcl_Obj",
+ sizeof(PyTclObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ PyTclObject_Type_slots,
+};
+
+
+#if PY_SIZE_MAX > INT_MAX
+#define CHECK_STRING_LENGTH(s) do { \
+ if (s != NULL && strlen(s) >= INT_MAX) { \
+ PyErr_SetString(PyExc_OverflowError, "string is too long"); \
+ return NULL; \
+ } } while(0)
+#else
+#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_NewStringObj(PyBytes_AS_STRING(value),
- PyBytes_GET_SIZE(value));
- else if (PyBool_Check(value))
+ return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value),
+ PyBytes_GET_SIZE(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;
size = PyTuple_Size(value);
+ if (size == 0)
+ return Tcl_NewListObj(0, NULL);
if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
PyErr_SetString(PyExc_OverflowError, "tuple is too long");
return NULL;
}
- argv = (Tcl_Obj **) ckalloc(((size_t)size) * sizeof(Tcl_Obj *));
+ argv = (Tcl_Obj **) attemptckalloc(((size_t)size) * sizeof(Tcl_Obj *));
if(!argv)
return 0;
for (i = 0; i < size; i++)
@@ -1006,7 +990,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;
@@ -1019,6 +1004,8 @@ AsObj(PyObject *value)
inbuf = PyUnicode_DATA(value);
size = PyUnicode_GET_LENGTH(value);
+ if (size == 0)
+ return Tcl_NewUnicodeObj((const void *)"", 0);
if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) {
PyErr_SetString(PyExc_OverflowError, "string is too long");
return NULL;
@@ -1027,7 +1014,7 @@ AsObj(PyObject *value)
if (kind == sizeof(Tcl_UniChar))
return Tcl_NewUnicodeObj(inbuf, size);
allocsize = ((size_t)size) * sizeof(Tcl_UniChar);
- outbuf = (Tcl_UniChar*)ckalloc(allocsize);
+ outbuf = (Tcl_UniChar*)attemptckalloc(allocsize);
/* Else overflow occurred, and we take the next exit */
if (!outbuf) {
PyErr_NoMemory();
@@ -1054,12 +1041,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;
@@ -1069,20 +1058,85 @@ AsObj(PyObject *value)
}
}
+static PyObject *
+fromBoolean(PyObject* tkapp, Tcl_Obj *value)
+{
+ int boolValue;
+ if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR)
+ return Tkinter_Error(tkapp);
+ 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)
{
PyObject *result = NULL;
TkappObject *app = (TkappObject*)tkapp;
+ Tcl_Interp *interp = Tkapp_Interp(tkapp);
if (value->typePtr == NULL) {
return unicodeFromTclStringAndSize(value->bytes, value->length);
}
- if (value->typePtr == app->BooleanType) {
- result = value->internalRep.longValue ? Py_True : Py_False;
- Py_INCREF(result);
- return result;
+ if (value->typePtr == app->BooleanType ||
+ value->typePtr == app->OldBooleanType) {
+ return fromBoolean(tkapp, value);
}
if (value->typePtr == app->ByteArrayType) {
@@ -1096,8 +1150,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;
@@ -1105,15 +1183,14 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
PyObject *elem;
Tcl_Obj *tcl_elem;
- status = Tcl_ListObjLength(Tkapp_Interp(tkapp), value, &size);
+ status = Tcl_ListObjLength(interp, value, &size);
if (status == TCL_ERROR)
return Tkinter_Error(tkapp);
result = PyTuple_New(size);
if (!result)
return NULL;
for (i = 0; i < size; i++) {
- status = Tcl_ListObjIndex(Tkapp_Interp(tkapp),
- value, i, &tcl_elem);
+ status = Tcl_ListObjIndex(interp, value, i, &tcl_elem);
if (status == TCL_ERROR) {
Py_DECREF(result);
return Tkinter_Error(tkapp);
@@ -1138,6 +1215,24 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
Tcl_GetCharLength(value));
}
+#if TK_HEX_VERSION >= 0x08050000
+ if (app->BooleanType == NULL &&
+ strcmp(value->typePtr->name, "booleanString") == 0) {
+ /* booleanString type is not registered in Tcl */
+ app->BooleanType = value->typePtr;
+ return fromBoolean(tkapp, 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);
}
@@ -1192,7 +1287,7 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
PyErr_SetString(PyExc_OverflowError, "tuple is too long");
return NULL;
}
- objv = (Tcl_Obj **)ckalloc(((size_t)objc) * sizeof(Tcl_Obj *));
+ objv = (Tcl_Obj **)attemptckalloc(((size_t)objc) * sizeof(Tcl_Obj *));
if (objv == NULL) {
PyErr_NoMemory();
objc = 0;
@@ -1328,7 +1423,11 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
PyObject *exc_type, *exc_value, *exc_tb;
if (!WaitForMainloop(self))
return NULL;
- ev = (Tkapp_CallEvent*)ckalloc(sizeof(Tkapp_CallEvent));
+ ev = (Tkapp_CallEvent*)attemptckalloc(sizeof(Tkapp_CallEvent));
+ if (ev == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc;
ev->self = self;
ev->args = args;
@@ -1376,42 +1475,6 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
static PyObject *
-Tkapp_GlobalCall(PyObject *self, PyObject *args)
-{
- /* Could do the same here as for Tkapp_Call(), but this is not used
- much, so I can't be bothered. Unfortunately Tcl doesn't export a
- way for the user to do what all its Global* variants do (save and
- reset the scope pointer, call the local version, restore the saved
- scope pointer). */
-
- char *cmd;
- PyObject *res = NULL;
-
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "globalcall is deprecated and will be removed in 3.4",
- 1) < 0)
- return 0;
-
- CHECK_TCL_APPARTMENT;
-
- cmd = Merge(args);
- if (cmd) {
- int err;
- ENTER_TCL
- err = Tcl_GlobalEval(Tkapp_Interp(self), cmd);
- ENTER_OVERLAP
- if (err == TCL_ERROR)
- res = Tkinter_Error(self);
- else
- res = PyUnicode_FromString(Tkapp_Result(self));
- LEAVE_OVERLAP_TCL
- ckfree(cmd);
- }
-
- return res;
-}
-
-static PyObject *
Tkapp_Eval(PyObject *self, PyObject *args)
{
char *script;
@@ -1421,6 +1484,7 @@ Tkapp_Eval(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:eval", &script))
return NULL;
+ CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -1435,34 +1499,6 @@ Tkapp_Eval(PyObject *self, PyObject *args)
}
static PyObject *
-Tkapp_GlobalEval(PyObject *self, PyObject *args)
-{
- char *script;
- PyObject *res = NULL;
- int err;
-
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "globaleval is deprecated and will be removed in 3.4",
- 1) < 0)
- return 0;
-
- if (!PyArg_ParseTuple(args, "s:globaleval", &script))
- return NULL;
-
- CHECK_TCL_APPARTMENT;
-
- ENTER_TCL
- err = Tcl_GlobalEval(Tkapp_Interp(self), script);
- ENTER_OVERLAP
- if (err == TCL_ERROR)
- res = Tkinter_Error(self);
- else
- res = PyUnicode_FromString(Tkapp_Result(self));
- LEAVE_OVERLAP_TCL
- return res;
-}
-
-static PyObject *
Tkapp_EvalFile(PyObject *self, PyObject *args)
{
char *fileName;
@@ -1472,6 +1508,7 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
return NULL;
+ CHECK_STRING_LENGTH(fileName);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -1492,9 +1529,10 @@ Tkapp_Record(PyObject *self, PyObject *args)
PyObject *res = NULL;
int err;
- if (!PyArg_ParseTuple(args, "s", &script))
+ if (!PyArg_ParseTuple(args, "s:record", &script))
return NULL;
+ CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -1515,14 +1553,14 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
return NULL;
+ CHECK_STRING_LENGTH(msg);
CHECK_TCL_APPARTMENT;
ENTER_TCL
Tcl_AddErrorInfo(Tkapp_Interp(self), msg);
LEAVE_TCL
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -1640,8 +1678,11 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
if (!WaitForMainloop(self))
return NULL;
- ev = (VarEvent*)ckalloc(sizeof(VarEvent));
-
+ ev = (VarEvent*)attemptckalloc(sizeof(VarEvent));
+ if (ev == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
ev->self = selfptr;
ev->args = args;
ev->flags = flags;
@@ -1699,6 +1740,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "ssO:setvar",
&name1, &name2, &newValue))
return NULL;
+ CHECK_STRING_LENGTH(name1);
+ CHECK_STRING_LENGTH(name2);
/* XXX must hold tcl lock already??? */
newval = AsObj(newValue);
ENTER_TCL
@@ -1744,11 +1787,13 @@ GetVar(PyObject *self, PyObject *args, int flags)
varname_converter, &name1, &name2))
return NULL;
+ CHECK_STRING_LENGTH(name2);
ENTER_TCL
tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
if (tres == NULL) {
- PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self)));
+ PyErr_SetString(Tkinter_TclError,
+ Tcl_GetStringResult(Tkapp_Interp(self)));
} else {
if (((TkappObject*)self)->wantobjects) {
res = FromObj(self, tres);
@@ -1785,6 +1830,8 @@ UnsetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
return NULL;
+ CHECK_STRING_LENGTH(name1);
+ CHECK_STRING_LENGTH(name2);
ENTER_TCL
code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
@@ -1807,7 +1854,8 @@ Tkapp_UnsetVar(PyObject *self, PyObject *args)
static PyObject *
Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args)
{
- return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
+ return var_invoke(UnsetVar, self, args,
+ TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
}
@@ -1818,7 +1866,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);
@@ -1829,9 +1882,30 @@ Tkapp_GetInt(PyObject *self, PyObject *args)
}
if (!PyArg_ParseTuple(args, "s:getint", &s))
return NULL;
- if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
+ CHECK_STRING_LENGTH(s);
+#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 *
@@ -1849,26 +1923,33 @@ Tkapp_GetDouble(PyObject *self, PyObject *args)
}
if (!PyArg_ParseTuple(args, "s:getdouble", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error(self);
return Py_BuildValue("d", v);
}
static PyObject *
-Tkapp_GetBoolean(PyObject *self, PyObject *args)
+Tkapp_GetBoolean(PyObject *self, PyObject *arg)
{
char *s;
int v;
- if (PyTuple_Size(args) == 1) {
- PyObject *o = PyTuple_GetItem(args, 0);
- if (PyLong_Check(o)) {
- Py_INCREF(o);
- return o;
- }
+ if (PyLong_Check(arg)) { /* int or bool */
+ return PyBool_FromLong(Py_SIZE(arg) != 0);
+ }
+
+ if (PyTclObject_Check(arg)) {
+ if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
+ ((PyTclObject*)arg)->value,
+ &v) == TCL_ERROR)
+ return Tkinter_Error(self);
+ return PyBool_FromLong(v);
}
- if (!PyArg_ParseTuple(args, "s:getboolean", &s))
+
+ if (!PyArg_Parse(arg, "s:getboolean", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error(self);
return PyBool_FromLong(v);
@@ -1884,6 +1965,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprstring", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -1908,6 +1990,7 @@ Tkapp_ExprLong(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprlong", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -1931,6 +2014,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
ENTER_TCL
@@ -1955,6 +2039,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
return NULL;
+ CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
@@ -2007,6 +2092,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
return NULL;
+ CHECK_STRING_LENGTH(list);
if (Tcl_SplitList(Tkapp_Interp(self), list,
&argc, &argv) == TCL_ERROR) {
PyMem_Free(list);
@@ -2068,32 +2154,12 @@ Tkapp_Split(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
return NULL;
+ CHECK_STRING_LENGTH(list);
v = Split(list);
PyMem_Free(list);
return v;
}
-static PyObject *
-Tkapp_Merge(PyObject *self, PyObject *args)
-{
- char *s;
- PyObject *res = NULL;
-
- if (PyErr_WarnEx(PyExc_DeprecationWarning,
- "merge is deprecated and will be removed in 3.4",
- 1) < 0)
- return 0;
-
- s = Merge(args);
-
- if (s) {
- res = PyUnicode_FromString(s);
- ckfree(s);
- }
-
- return res;
-}
-
/** Tcl Command **/
@@ -2220,6 +2286,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
return NULL;
+ CHECK_STRING_LENGTH(cmdName);
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "command not callable");
return NULL;
@@ -2241,7 +2308,12 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args)
#ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
Tcl_Condition cond = NULL;
- CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent));
+ CommandEvent *ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
+ if (ev == NULL) {
+ PyErr_NoMemory();
+ PyMem_DEL(data);
+ return NULL;
+ }
ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
ev->interp = self->interp;
ev->create = 1;
@@ -2267,8 +2339,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args)
return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -2282,12 +2353,17 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
return NULL;
+ CHECK_STRING_LENGTH(cmdName);
#ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
Tcl_Condition cond = NULL;
CommandEvent *ev;
- ev = (CommandEvent*)ckalloc(sizeof(CommandEvent));
+ ev = (CommandEvent*)attemptckalloc(sizeof(CommandEvent));
+ if (ev == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc;
ev->interp = self->interp;
ev->create = 0;
@@ -2309,8 +2385,7 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args)
PyErr_SetString(Tkinter_TclError, "can't delete Tcl command");
return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -2414,8 +2489,7 @@ Tkapp_CreateFileHandler(PyObject *self, PyObject *args)
ENTER_TCL
Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data);
LEAVE_TCL
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyObject *
@@ -2439,15 +2513,14 @@ Tkapp_DeleteFileHandler(PyObject *self, PyObject *args)
ENTER_TCL
Tcl_DeleteFileHandler(tfile);
LEAVE_TCL
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
#endif /* HAVE_CREATEFILEHANDLER */
/**** Tktt Object (timer token) ****/
-static PyTypeObject Tktt_Type;
+static PyObject *Tktt_Type;
typedef struct {
PyObject_HEAD
@@ -2472,8 +2545,7 @@ Tktt_DeleteTimerHandler(PyObject *self, PyObject *args)
Py_DECREF(func);
Py_DECREF(v); /* See Tktt_New() */
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyMethodDef Tktt_methods[] =
@@ -2487,9 +2559,10 @@ Tktt_New(PyObject *func)
{
TkttObject *v;
- v = PyObject_New(TkttObject, &Tktt_Type);
+ v = PyObject_New(TkttObject, (PyTypeObject *) Tktt_Type);
if (v == NULL)
return NULL;
+ Py_INCREF(Tktt_Type);
Py_INCREF(func);
v->token = NULL;
@@ -2505,10 +2578,12 @@ Tktt_Dealloc(PyObject *self)
{
TkttObject *v = (TkttObject *)self;
PyObject *func = v->func;
+ PyObject *tp = (PyObject *) Py_TYPE(self);
Py_XDECREF(func);
PyObject_Del(self);
+ Py_DECREF(tp);
}
static PyObject *
@@ -2520,38 +2595,20 @@ Tktt_Repr(PyObject *self)
v->func == NULL ? ", handler deleted" : "");
}
-static PyTypeObject Tktt_Type =
-{
- PyVarObject_HEAD_INIT(NULL, 0)
- "tktimertoken", /*tp_name */
- sizeof(TkttObject), /*tp_basicsize */
- 0, /*tp_itemsize */
- Tktt_Dealloc, /*tp_dealloc */
- 0, /*tp_print */
- 0, /*tp_getattr */
- 0, /*tp_setattr */
- 0, /*tp_reserved */
- Tktt_Repr, /*tp_repr */
- 0, /*tp_as_number */
- 0, /*tp_as_sequence */
- 0, /*tp_as_mapping */
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- Tktt_methods, /*tp_methods*/
+static PyType_Slot Tktt_Type_slots[] = {
+ {Py_tp_dealloc, Tktt_Dealloc},
+ {Py_tp_repr, Tktt_Repr},
+ {Py_tp_methods, Tktt_methods},
+ {0, 0}
};
+static PyType_Spec Tktt_Type_spec = {
+ "_tkinter.tktimertoken",
+ sizeof(TkttObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Tktt_Type_slots,
+};
/** Timer Handler **/
@@ -2673,8 +2730,7 @@ Tkapp_MainLoop(PyObject *selfptr, PyObject *args)
excInCmd = valInCmd = trbInCmd = NULL;
return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyObject *
@@ -2700,8 +2756,7 @@ Tkapp_Quit(PyObject *self, PyObject *args)
return NULL;
quitMainLoop = 1;
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyObject *
@@ -2751,15 +2806,15 @@ Tkapp_TkInit(PyObject *self, PyObject *args)
}
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
if (Tk_Init(interp) == TCL_ERROR) {
- PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self)));
+ PyErr_SetString(Tkinter_TclError,
+ Tcl_GetStringResult(Tkapp_Interp(self)));
#ifdef TKINTER_PROTECT_LOADTK
tk_load_failed = 1;
#endif
return NULL;
}
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyObject *
@@ -2773,8 +2828,7 @@ Tkapp_WantObjects(PyObject *self, PyObject *args)
return PyBool_FromLong(((TkappObject*)self)->wantobjects);
((TkappObject*)self)->wantobjects = wantobjects;
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static PyObject *
@@ -2783,8 +2837,7 @@ Tkapp_WillDispatch(PyObject *self, PyObject *args)
((TkappObject*)self)->dispatching = 1;
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -2795,9 +2848,7 @@ static PyMethodDef Tkapp_methods[] =
{"willdispatch", Tkapp_WillDispatch, METH_NOARGS},
{"wantobjects", Tkapp_WantObjects, METH_VARARGS},
{"call", Tkapp_Call, METH_VARARGS},
- {"globalcall", Tkapp_GlobalCall, METH_VARARGS},
{"eval", Tkapp_Eval, METH_VARARGS},
- {"globaleval", Tkapp_GlobalEval, METH_VARARGS},
{"evalfile", Tkapp_EvalFile, METH_VARARGS},
{"record", Tkapp_Record, METH_VARARGS},
{"adderrorinfo", Tkapp_AddErrorInfo, METH_VARARGS},
@@ -2809,14 +2860,13 @@ static PyMethodDef Tkapp_methods[] =
{"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS},
{"getint", Tkapp_GetInt, METH_VARARGS},
{"getdouble", Tkapp_GetDouble, METH_VARARGS},
- {"getboolean", Tkapp_GetBoolean, METH_VARARGS},
+ {"getboolean", Tkapp_GetBoolean, METH_O},
{"exprstring", Tkapp_ExprString, METH_VARARGS},
{"exprlong", Tkapp_ExprLong, METH_VARARGS},
{"exprdouble", Tkapp_ExprDouble, METH_VARARGS},
{"exprboolean", Tkapp_ExprBoolean, METH_VARARGS},
{"splitlist", Tkapp_SplitList, METH_VARARGS},
{"split", Tkapp_Split, METH_VARARGS},
- {"merge", Tkapp_Merge, METH_VARARGS},
{"createcommand", Tkapp_CreateCommand, METH_VARARGS},
{"deletecommand", Tkapp_DeleteCommand, METH_VARARGS},
#ifdef HAVE_CREATEFILEHANDLER
@@ -2839,44 +2889,29 @@ static PyMethodDef Tkapp_methods[] =
static void
Tkapp_Dealloc(PyObject *self)
{
+ PyObject *tp = (PyObject *) Py_TYPE(self);
/*CHECK_TCL_APPARTMENT;*/
ENTER_TCL
Tcl_DeleteInterp(Tkapp_Interp(self));
LEAVE_TCL
PyObject_Del(self);
+ Py_DECREF(tp);
DisableEventHook();
}
-static PyTypeObject Tkapp_Type =
-{
- PyVarObject_HEAD_INIT(NULL, 0)
- "tkapp", /*tp_name */
- sizeof(TkappObject), /*tp_basicsize */
- 0, /*tp_itemsize */
- Tkapp_Dealloc, /*tp_dealloc */
- 0, /*tp_print */
- 0, /*tp_getattr */
- 0, /*tp_setattr */
- 0, /*tp_reserved */
- 0, /*tp_repr */
- 0, /*tp_as_number */
- 0, /*tp_as_sequence */
- 0, /*tp_as_mapping */
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- Tkapp_methods, /*tp_methods*/
+static PyType_Slot Tkapp_Type_slots[] = {
+ {Py_tp_dealloc, Tkapp_Dealloc},
+ {Py_tp_methods, Tkapp_methods},
+ {0, 0}
+};
+
+
+static PyType_Spec Tkapp_Type_spec = {
+ "_tkinter.tkapp",
+ sizeof(TkappObject),
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ Tkapp_Type_slots,
};
@@ -3014,9 +3049,13 @@ Tkinter_Create(PyObject *self, PyObject *args)
&interactive, &wantobjects, &wantTk,
&sync, &use))
return NULL;
+ CHECK_STRING_LENGTH(screenName);
+ CHECK_STRING_LENGTH(baseName);
+ CHECK_STRING_LENGTH(className);
+ CHECK_STRING_LENGTH(use);
return (PyObject *) Tkapp_New(screenName, className,
- interactive, wantobjects, wantTk,
+ interactive, wantobjects, wantTk,
sync, use);
}
@@ -3032,8 +3071,7 @@ Tkinter_setbusywaitinterval(PyObject *self, PyObject *args)
return NULL;
}
Tkinter_busywaitinterval = new_val;
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static char setbusywaitinterval_doc[] =
@@ -3166,27 +3204,6 @@ DisableEventHook(void)
}
-/* all errors will be checked in one fell swoop in init_tkinter() */
-static void
-ins_long(PyObject *d, char *name, long val)
-{
- PyObject *v = PyLong_FromLong(val);
- if (v) {
- PyDict_SetItemString(d, name, v);
- Py_DECREF(v);
- }
-}
-static void
-ins_string(PyObject *d, char *name, char *val)
-{
- PyObject *v = PyUnicode_FromString(val);
- if (v) {
- PyDict_SetItemString(d, name, v);
- Py_DECREF(v);
- }
-}
-
-
static struct PyModuleDef _tkintermodule = {
PyModuleDef_HEAD_INIT,
"_tkinter",
@@ -3202,45 +3219,111 @@ static struct PyModuleDef _tkintermodule = {
PyMODINIT_FUNC
PyInit__tkinter(void)
{
- PyObject *m, *d, *uexe, *cexe;
-
- if (PyType_Ready(&Tkapp_Type) < 0)
- return NULL;
+ PyObject *m, *uexe, *cexe, *o;
#ifdef WITH_THREAD
tcl_lock = PyThread_allocate_lock();
+ if (tcl_lock == NULL)
+ return NULL;
#endif
m = PyModule_Create(&_tkintermodule);
if (m == NULL)
return NULL;
- d = PyModule_GetDict(m);
- Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL);
- PyDict_SetItemString(d, "TclError", Tkinter_TclError);
+ o = PyErr_NewException("_tkinter.TclError", NULL, NULL);
+ if (o == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ Py_INCREF(o);
+ if (PyModule_AddObject(m, "TclError", o)) {
+ Py_DECREF(o);
+ Py_DECREF(m);
+ return NULL;
+ }
+ Tkinter_TclError = o;
- ins_long(d, "READABLE", TCL_READABLE);
- ins_long(d, "WRITABLE", TCL_WRITABLE);
- ins_long(d, "EXCEPTION", TCL_EXCEPTION);
- ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS);
- ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS);
- ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS);
- ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS);
- ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS);
- ins_long(d, "DONT_WAIT", TCL_DONT_WAIT);
- ins_string(d, "TK_VERSION", TK_VERSION);
- ins_string(d, "TCL_VERSION", TCL_VERSION);
+ if (PyModule_AddIntConstant(m, "READABLE", TCL_READABLE)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "WRITABLE", TCL_WRITABLE)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "EXCEPTION", TCL_EXCEPTION)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "WINDOW_EVENTS", TCL_WINDOW_EVENTS)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "FILE_EVENTS", TCL_FILE_EVENTS)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "TIMER_EVENTS", TCL_TIMER_EVENTS)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "IDLE_EVENTS", TCL_IDLE_EVENTS)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "ALL_EVENTS", TCL_ALL_EVENTS)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "DONT_WAIT", TCL_DONT_WAIT)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddStringConstant(m, "TK_VERSION", TK_VERSION)) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddStringConstant(m, "TCL_VERSION", TCL_VERSION)) {
+ Py_DECREF(m);
+ return NULL;
+ }
- PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type);
+ o = PyType_FromSpec(&Tkapp_Type_spec);
+ if (o == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddObject(m, "TkappType", o)) {
+ Py_DECREF(o);
+ Py_DECREF(m);
+ return NULL;
+ }
+ Tkapp_Type = o;
- if (PyType_Ready(&Tktt_Type) < 0) {
+ o = PyType_FromSpec(&Tktt_Type_spec);
+ if (o == NULL) {
Py_DECREF(m);
return NULL;
}
- PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type);
+ if (PyModule_AddObject(m, "TkttType", o)) {
+ Py_DECREF(o);
+ Py_DECREF(m);
+ return NULL;
+ }
+ Tktt_Type = o;
- Py_TYPE(&PyTclObject_Type) = &PyType_Type;
- PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type);
+ o = PyType_FromSpec(&PyTclObject_Type_spec);
+ if (o == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ if (PyModule_AddObject(m, "Tcl_Obj", o)) {
+ Py_DECREF(o);
+ Py_DECREF(m);
+ return NULL;
+ }
+ PyTclObject_Type = o;
#ifdef TK_AQUA
/* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems