diff options
Diffstat (limited to 'Modules/_tkinter.c')
-rw-r--r-- | Modules/_tkinter.c | 1049 |
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 |