/***********************************************************Copyright (C) 1994 Steen Lumholt. All Rights Reserved ******************************************************************/ /* _tkinter.c -- Interface to libtk.a and libtcl.a. */ /* TCL/TK VERSION INFO: Only Tcl/Tk 8.2 and later are supported. Older versions are not supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk libraries.)*/ /* XXX Further speed-up ideas, involving Tcl 8.0 features: - Register a new Tcl type, "Python callable", which can be called more efficiently and passed to Tcl_EvalObj() directly (if this is possible). */ #include "Python.h"#include <ctype.h> #ifdef WITH_THREAD#include "pythread.h"#endif #ifdef MS_WINDOWS#include <windows.h>#endif /* Allow using this code in Python 2.[12] */#ifndef PyDoc_STRVAR#define PyDoc_STRVAR(name,str) static char name[] = str#endif #ifndef PyMODINIT_FUNC#define PyMODINIT_FUNC void#endif #ifndef PyBool_Check#define PyBool_Check(o) 0#define PyBool_FromLong PyInt_FromLong#endif /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, making _tkinter correct for this API means to break earlier versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and earlier versions. Once Tcl releases before 8.4 don't need to be supported anymore, this should go. */#define USE_COMPAT_CONST /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define it always; if Tcl is not threaded, the thread functions in Tcl are empty. */#define TCL_THREADS #ifdef TK_FRAMEWORK#include <Tcl/tcl.h>#include <Tk/tk.h>#else#include <tcl.h>#include <tk.h>#endif /* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */#ifndef CONST84_RETURN#define CONST84_RETURN#undef CONST#define CONST#endif #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) #if TKMAJORMINOR < 8002#error "Tk older than 8.2 not supported"#endif /* Unicode conversion assumes that Tcl_UniChar is two bytes. We cannot test this directly, so we test UTF-8 size instead, expecting that TCL_UTF_MAX is changed if Tcl ever supports either UTF-16 or UCS-4. Redhat 8 sets TCL_UTF_MAX to 6, and uses wchar_t for Tcl_Unichar. This is also ok as long as Python uses UCS-4, as well.*/#if TCL_UTF_MAX != 3 && !(defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==6)#error "unsupported Tcl configuration"#endif #if !(defined(MS_WINDOWS) || defined(__CYGWIN__))#define HAVE_CREATEFILEHANDLER#endif #ifdef HAVE_CREATEFILEHANDLER /* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */#ifndef TCL_UNIX_FD# ifdef TCL_WIN_SOCKET# define TCL_UNIX_FD (! TCL_WIN_SOCKET)# else# define TCL_UNIX_FD 1# endif#endif /* Tcl_CreateFileHandler() changed several times; these macros deal with the messiness. In Tcl 8.0 and later, it is not available on Windows (and on Unix, only because Jack added it back); when available on Windows, it only applies to sockets. */ #ifdef MS_WINDOWS#define FHANDLETYPE TCL_WIN_SOCKET#else#define FHANDLETYPE TCL_UNIX_FD#endif /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine which uses this to handle Tcl events while the user is typing commands. */ #if FHANDLETYPE == TCL_UNIX_FD#define WAIT_FOR_STDIN#endif #endif /* HAVE_CREATEFILEHANDLER */ #ifdef MS_WINDOWS#include <conio.h>#define WAIT_FOR_STDIN#endif #ifdef WITH_THREAD /* 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. 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. */ static PyThread_type_lock tcl_lock = 0; #ifdef TCL_THREADSstatic Tcl_ThreadDataKey state_key;typedef PyThreadState *ThreadSpecificData;#define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*)))#elsestatic PyThreadState *tcl_tstate = NULL;#endif #define ENTER_TCL \ { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ 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} #define ENTER_OVERLAP \ Py_END_ALLOW_THREADS #define LEAVE_OVERLAP_TCL \ tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); } #define ENTER_PYTHON \ { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); } #define LEAVE_PYTHON \ { PyThreadState *tstate = PyEval_SaveThread(); \ if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; } #define CHECK_TCL_APPARTMENT \ if (((TkappObject *)self)->threaded && \ ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \ PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \ return 0; \ } #else #define ENTER_TCL#define LEAVE_TCL#define ENTER_OVERLAP#define LEAVE_OVERLAP_TCL#define ENTER_PYTHON#define LEAVE_PYTHON#define CHECK_TCL_APPARTMENT #endif #ifndef FREECAST#define FREECAST (char *)#endif /**** Tkapp Object Declaration ****/ static PyTypeObject Tkapp_Type; typedef struct { PyObject_HEAD Tcl_Interp *interp; int wantobjects; int threaded; /* True if tcl_platform[threaded] */ Tcl_ThreadId thread_id; 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;} TkappObject; #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \(void *) v, ((PyObject *) v)->ob_refcnt)) /**** Error Handling ****/ static PyObject *Tkinter_TclError;static int quitMainLoop = 0;static int errorInCmd = 0;static PyObject *excInCmd;static PyObject *valInCmd;static PyObject *trbInCmd; static PyObject *Tkinter_Error(PyObject *v){ PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); return NULL;} /**** Utils ****/ static int Tkinter_busywaitinterval = 20; #ifdef WITH_THREAD#ifndef MS_WINDOWS /* Millisecond sleep() for Unix platforms. */ static voidSleep(int milli){ /* XXX Too bad if you don't have select(). */ struct timeval t; t.tv_sec = milli/1000; t.tv_usec = (milli%1000) * 1000; select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);}#endif /* MS_WINDOWS */ /* Wait up to 1s for the mainloop to come up. */ static intWaitForMainloop(TkappObject* self){ int i; for (i = 0; i < 10; i++) { if (self->dispatching) return 1; Py_BEGIN_ALLOW_THREADS Sleep(100); Py_END_ALLOW_THREADS } if (self->dispatching) return 1; PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop"); return 0;}#endif /* WITH_THREAD */ static char *AsString(PyObject *value, PyObject *tmp){ if (PyString_Check(value)) return PyString_AsString(value);#ifdef Py_USING_UNICODE else if (PyUnicode_Check(value)) { PyObject *v = PyUnicode_AsUTF8String(value); if (v == NULL) return NULL; if (PyList_Append(tmp, v) != 0) { Py_DECREF(v); return NULL; } Py_DECREF(v); return PyString_AsString(v); }#endif 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 PyString_AsString(v); }} #define ARGSZ 64 static char *Merge(PyObject *args){ PyObject *tmp = NULL; char *argvStore[ARGSZ]; char **argv = NULL; int fvStore[ARGSZ]; int *fv = NULL; int 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) { argv = (char **)ckalloc(argc * sizeof(char *)); fv = (int *)ckalloc(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 *Split(char *list){ int argc; char **argv; PyObject *v; if (list == NULL) { Py_INCREF(Py_None); return Py_None; } if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { /* Not a list. * Could be a quoted string containing funnies, e.g. {"}. * Return the string itself. */ return PyString_FromString(list); } if (argc == 0) v = PyString_FromString(""); else if (argc == 1) v = PyString_FromString(argv[0]); else if ((v = PyTuple_New(argc)) != NULL) { int i; PyObject *w; for (i = 0; i < argc; i++) { if ((w = Split(argv[i])) == NULL) { Py_DECREF(v); v = NULL; break; } PyTuple_SetItem(v, i, w); } } Tcl_Free(FREECAST argv); 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. */ PyObject *SplitObj(PyObject *arg){ if (PyTuple_Check(arg)) { int i, size; PyObject *elem, *newelem, *result; size = PyTuple_Size(arg);Lines 1–500 of 3165. Load more
/*********************************************************** Copyright (C) 1994 Steen Lumholt. All Rights Reserved ******************************************************************/ /* _tkinter.c -- Interface to libtk.a and libtcl.a. */ /* TCL/TK VERSION INFO: Only Tcl/Tk 8.2 and later are supported. Older versions are not supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk libraries.) */ /* XXX Further speed-up ideas, involving Tcl 8.0 features: - Register a new Tcl type, "Python callable", which can be called more efficiently and passed to Tcl_EvalObj() directly (if this is possible). */ #include "Python.h" #include <ctype.h> #ifdef WITH_THREAD #include "pythread.h" #endif #ifdef MS_WINDOWS #include <windows.h> #endif /* Allow using this code in Python 2.[12] */ #ifndef PyDoc_STRVAR #define PyDoc_STRVAR(name,str) static char name[] = str #endif #ifndef PyMODINIT_FUNC #define PyMODINIT_FUNC void #endif #ifndef PyBool_Check #define PyBool_Check(o) 0 #define PyBool_FromLong PyInt_FromLong #endif /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, making _tkinter correct for this API means to break earlier versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and earlier versions. Once Tcl releases before 8.4 don't need to be supported anymore, this should go. */ #define USE_COMPAT_CONST /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define it always; if Tcl is not threaded, the thread functions in Tcl are empty. */ #define TCL_THREADS #ifdef TK_FRAMEWORK #include <Tcl/tcl.h> #include <Tk/tk.h> #else #include <tcl.h> #include <tk.h> #endif /* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */ #ifndef CONST84_RETURN #define CONST84_RETURN #undef CONST #define CONST #endif #define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) #if TKMAJORMINOR < 8002 #error "Tk older than 8.2 not supported" #endif /* Unicode conversion assumes that Tcl_UniChar is two bytes. We cannot test this directly, so we test UTF-8 size instead, expecting that TCL_UTF_MAX is changed if Tcl ever supports either UTF-16 or UCS-4. Redhat 8 sets TCL_UTF_MAX to 6, and uses wchar_t for Tcl_Unichar. This is also ok as long as Python uses UCS-4, as well. */ #if TCL_UTF_MAX != 3 && !(defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==6) #error "unsupported Tcl configuration" #endif #if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) #define HAVE_CREATEFILEHANDLER #endif #ifdef HAVE_CREATEFILEHANDLER /* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */ #ifndef TCL_UNIX_FD # ifdef TCL_WIN_SOCKET # define TCL_UNIX_FD (! TCL_WIN_SOCKET) # else # define TCL_UNIX_FD 1 # endif #endif /* Tcl_CreateFileHandler() changed several times; these macros deal with the messiness. In Tcl 8.0 and later, it is not available on Windows (and on Unix, only because Jack added it back); when available on Windows, it only applies to sockets. */ #ifdef MS_WINDOWS #define FHANDLETYPE TCL_WIN_SOCKET #else #define FHANDLETYPE TCL_UNIX_FD #endif /* If Tcl can wait for a Unix file descriptor, define the EventHook() routine which uses this to handle Tcl events while the user is typing commands. */ #if FHANDLETYPE == TCL_UNIX_FD #define WAIT_FOR_STDIN #endif #endif /* HAVE_CREATEFILEHANDLER */ #ifdef MS_WINDOWS #include <conio.h> #define WAIT_FOR_STDIN #endif #ifdef WITH_THREAD /* 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. 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. */ 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*))) #else static PyThreadState *tcl_tstate = NULL; #endif #define ENTER_TCL \ { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ 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} #define ENTER_OVERLAP \ Py_END_ALLOW_THREADS #define LEAVE_OVERLAP_TCL \ tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); } #define ENTER_PYTHON \ { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); } #define LEAVE_PYTHON \ { PyThreadState *tstate = PyEval_SaveThread(); \ if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; } #define CHECK_TCL_APPARTMENT \ if (((TkappObject *)self)->threaded && \ ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \ PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \ return 0; \ } #else #define ENTER_TCL #define LEAVE_TCL #define ENTER_OVERLAP #define LEAVE_OVERLAP_TCL #define ENTER_PYTHON #define LEAVE_PYTHON #define CHECK_TCL_APPARTMENT #endif #ifndef FREECAST #define FREECAST (char *) #endif /**** Tkapp Object Declaration ****/ static PyTypeObject Tkapp_Type; typedef struct { PyObject_HEAD Tcl_Interp *interp; int wantobjects; int threaded; /* True if tcl_platform[threaded] */ Tcl_ThreadId thread_id; 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; } TkappObject; #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type) #define Tkapp_Interp(v) (((TkappObject *) (v))->interp) #define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) #define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \ (void *) v, ((PyObject *) v)->ob_refcnt)) /**** Error Handling ****/ static PyObject *Tkinter_TclError; static int quitMainLoop = 0; static int errorInCmd = 0; static PyObject *excInCmd; static PyObject *valInCmd; static PyObject *trbInCmd; static PyObject * Tkinter_Error(PyObject *v) { PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); return NULL; } /**** Utils ****/ static int Tkinter_busywaitinterval = 20; #ifdef WITH_THREAD #ifndef MS_WINDOWS /* Millisecond sleep() for Unix platforms. */ static void Sleep(int milli) { /* XXX Too bad if you don't have select(). */ struct timeval t; t.tv_sec = milli/1000; t.tv_usec = (milli%1000) * 1000; select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); } #endif /* MS_WINDOWS */ /* Wait up to 1s for the mainloop to come up. */ static int WaitForMainloop(TkappObject* self) { int i; for (i = 0; i < 10; i++) { if (self->dispatching) return 1; Py_BEGIN_ALLOW_THREADS Sleep(100); Py_END_ALLOW_THREADS } if (self->dispatching) return 1; PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop"); return 0; } #endif /* WITH_THREAD */ static char * AsString(PyObject *value, PyObject *tmp) { if (PyString_Check(value)) return PyString_AsString(value); #ifdef Py_USING_UNICODE else if (PyUnicode_Check(value)) { PyObject *v = PyUnicode_AsUTF8String(value); if (v == NULL) return NULL; if (PyList_Append(tmp, v) != 0) { Py_DECREF(v); return NULL; } Py_DECREF(v); return PyString_AsString(v); } #endif 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 PyString_AsString(v); } } #define ARGSZ 64 static char * Merge(PyObject *args) { PyObject *tmp = NULL; char *argvStore[ARGSZ]; char **argv = NULL; int fvStore[ARGSZ]; int *fv = NULL; int 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) { argv = (char **)ckalloc(argc * sizeof(char *)); fv = (int *)ckalloc(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 * Split(char *list) { int argc; char **argv; PyObject *v; if (list == NULL) { Py_INCREF(Py_None); return Py_None; } if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { /* Not a list. * Could be a quoted string containing funnies, e.g. {"}. * Return the string itself. */ return PyString_FromString(list); } if (argc == 0) v = PyString_FromString(""); else if (argc == 1) v = PyString_FromString(argv[0]); else if ((v = PyTuple_New(argc)) != NULL) { int i; PyObject *w; for (i = 0; i < argc; i++) { if ((w = Split(argv[i])) == NULL) { Py_DECREF(v); v = NULL; break; } PyTuple_SetItem(v, i, w); } } Tcl_Free(FREECAST argv); 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. */ PyObject * SplitObj(PyObject *arg) { if (PyTuple_Check(arg)) { int i, size; PyObject *elem, *newelem, *result; size = PyTuple_Size(arg);