mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-13153: Use OS native encoding for converting between Python and Tcl. (GH-16545)
On Windows use UTF-16 (or UTF-32 for 32-bit Tcl_UniChar) with the "surrogatepass" error handler for converting to/from Tcl Unicode objects. On Linux use UTF-8 with the "surrogateescape" error handler for converting to/from Tcl String objects. Converting strings from Tcl to Python and back now never fails (except MemoryError).
This commit is contained in:
		
							parent
							
								
									2290b23dfc
								
							
						
					
					
						commit
						06cb94bc84
					
				
					 9 changed files with 241 additions and 242 deletions
				
			
		|  | @ -358,21 +358,6 @@ def set_width(self): | |||
|             Font(text, font=text.cget('font')).measure('0') | ||||
|         self.width = pixel_width // zero_char_width | ||||
| 
 | ||||
|     def _filename_to_unicode(self, filename): | ||||
|         """Return filename as BMP unicode so displayable in Tk.""" | ||||
|         # Decode bytes to unicode. | ||||
|         if isinstance(filename, bytes): | ||||
|             try: | ||||
|                 filename = filename.decode(self.filesystemencoding) | ||||
|             except UnicodeDecodeError: | ||||
|                 try: | ||||
|                     filename = filename.decode(self.encoding) | ||||
|                 except UnicodeDecodeError: | ||||
|                     # byte-to-byte conversion | ||||
|                     filename = filename.decode('iso8859-1') | ||||
|         # Replace non-BMP char with diamond questionmark. | ||||
|         return re.sub('[\U00010000-\U0010FFFF]', '\ufffd', filename) | ||||
| 
 | ||||
|     def new_callback(self, event): | ||||
|         dirname, basename = self.io.defaultfilename() | ||||
|         self.flist.new(dirname) | ||||
|  | @ -963,10 +948,8 @@ def update_recent_files_list(self, new_file=None): | |||
|             menu.delete(0, END)  # clear, and rebuild: | ||||
|             for i, file_name in enumerate(rf_list): | ||||
|                 file_name = file_name.rstrip()  # zap \n | ||||
|                 # make unicode string to display non-ASCII chars correctly | ||||
|                 ufile_name = self._filename_to_unicode(file_name) | ||||
|                 callback = instance.__recent_file_callback(file_name) | ||||
|                 menu.add_command(label=ulchars[i] + " " + ufile_name, | ||||
|                 menu.add_command(label=ulchars[i] + " " + file_name, | ||||
|                                  command=callback, | ||||
|                                  underline=0) | ||||
| 
 | ||||
|  | @ -1004,16 +987,10 @@ def reset_undo(self): | |||
| 
 | ||||
|     def short_title(self): | ||||
|         filename = self.io.filename | ||||
|         if filename: | ||||
|             filename = os.path.basename(filename) | ||||
|         else: | ||||
|             filename = "untitled" | ||||
|         # return unicode string to display non-ASCII chars correctly | ||||
|         return self._filename_to_unicode(filename) | ||||
|         return os.path.basename(filename) if filename else "untitled" | ||||
| 
 | ||||
|     def long_title(self): | ||||
|         # return unicode string to display non-ASCII chars correctly | ||||
|         return self._filename_to_unicode(self.io.filename or "") | ||||
|         return self.io.filename or "" | ||||
| 
 | ||||
|     def center_insert_event(self, event): | ||||
|         self.center() | ||||
|  |  | |||
|  | @ -30,18 +30,6 @@ def test_init(self): | |||
|         e._close() | ||||
| 
 | ||||
| 
 | ||||
| class EditorFunctionTest(unittest.TestCase): | ||||
| 
 | ||||
|     def test_filename_to_unicode(self): | ||||
|         func = Editor._filename_to_unicode | ||||
|         class dummy(): | ||||
|             filesystemencoding = 'utf-8' | ||||
|         pairs = (('abc', 'abc'), ('a\U00011111c', 'a\ufffdc'), | ||||
|                  (b'abc', 'abc'), (b'a\xf0\x91\x84\x91c', 'a\ufffdc')) | ||||
|         for inp, out in pairs: | ||||
|             self.assertEqual(func(dummy, inp), out) | ||||
| 
 | ||||
| 
 | ||||
| class TestGetLineIndent(unittest.TestCase): | ||||
|     def test_empty_lines(self): | ||||
|         for tabwidth in [1, 2, 4, 6, 8]: | ||||
|  |  | |||
|  | @ -679,14 +679,6 @@ def runsource(self, source): | |||
|         self.more = 0 | ||||
|         # at the moment, InteractiveInterpreter expects str | ||||
|         assert isinstance(source, str) | ||||
|         #if isinstance(source, str): | ||||
|         #    from idlelib import iomenu | ||||
|         #    try: | ||||
|         #        source = source.encode(iomenu.encoding) | ||||
|         #    except UnicodeError: | ||||
|         #        self.tkconsole.resetoutput() | ||||
|         #        self.write("Unsupported characters in input\n") | ||||
|         #        return | ||||
|         # InteractiveInterpreter.runsource() calls its runcode() method, | ||||
|         # which is overridden (see below) | ||||
|         return InteractiveInterpreter.runsource(self, source, filename) | ||||
|  | @ -1298,16 +1290,6 @@ def resetoutput(self): | |||
|         self.set_line_and_column() | ||||
| 
 | ||||
|     def write(self, s, tags=()): | ||||
|         if isinstance(s, str) and len(s) and max(s) > '\uffff': | ||||
|             # Tk doesn't support outputting non-BMP characters | ||||
|             # Let's assume what printed string is not very long, | ||||
|             # find first non-BMP character and construct informative | ||||
|             # UnicodeEncodeError exception. | ||||
|             for start, char in enumerate(s): | ||||
|                 if char > '\uffff': | ||||
|                     break | ||||
|             raise UnicodeEncodeError("UCS-2", char, start, start+1, | ||||
|                                      'Non-BMP character not supported in Tk') | ||||
|         try: | ||||
|             self.text.mark_gravity("iomark", "right") | ||||
|             count = OutputWindow.write(self, s, tags, "iomark") | ||||
|  |  | |||
|  | @ -147,8 +147,7 @@ def _run_module_event(self, event, *, customize=False): | |||
|         interp = self.shell.interp | ||||
|         if pyshell.use_subprocess and restart: | ||||
|             interp.restart_subprocess( | ||||
|                     with_cwd=False, filename= | ||||
|                     self.editwin._filename_to_unicode(filename)) | ||||
|                     with_cwd=False, filename=filename) | ||||
|         dirname = os.path.dirname(filename) | ||||
|         argv = [filename] | ||||
|         if self.cli_args: | ||||
|  |  | |||
|  | @ -429,9 +429,12 @@ def passValue(value): | |||
|         self.assertEqual(passValue(False), False if self.wantobjects else '0') | ||||
|         self.assertEqual(passValue('string'), 'string') | ||||
|         self.assertEqual(passValue('string\u20ac'), 'string\u20ac') | ||||
|         self.assertEqual(passValue('string\U0001f4bb'), 'string\U0001f4bb') | ||||
|         self.assertEqual(passValue('str\x00ing'), 'str\x00ing') | ||||
|         self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd') | ||||
|         self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac') | ||||
|         self.assertEqual(passValue('str\x00ing\U0001f4bb'), | ||||
|                          'str\x00ing\U0001f4bb') | ||||
|         self.assertEqual(passValue(b'str\x00ing'), | ||||
|                          b'str\x00ing' if self.wantobjects else 'str\x00ing') | ||||
|         self.assertEqual(passValue(b'str\xc0\x80ing'), | ||||
|  | @ -490,6 +493,7 @@ def float_eq(actual, expected): | |||
|         check('string') | ||||
|         check('string\xbd') | ||||
|         check('string\u20ac') | ||||
|         check('string\U0001f4bb') | ||||
|         check('') | ||||
|         check(b'string', 'string') | ||||
|         check(b'string\xe2\x82\xac', 'string\xe2\x82\xac') | ||||
|  | @ -531,6 +535,7 @@ def test_splitlist(self): | |||
|             ('a\n b\t\r c\n ', ('a', 'b', 'c')), | ||||
|             (b'a\n b\t\r c\n ', ('a', 'b', 'c')), | ||||
|             ('a \u20ac', ('a', '\u20ac')), | ||||
|             ('a \U0001f4bb', ('a', '\U0001f4bb')), | ||||
|             (b'a \xe2\x82\xac', ('a', '\u20ac')), | ||||
|             (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')), | ||||
|             ('a {b c}', ('a', 'b c')), | ||||
|  |  | |||
|  | @ -170,6 +170,28 @@ def callback(): | |||
|         with self.assertRaises(tkinter.TclError): | ||||
|             root.tk.call('after', 'info', idle1) | ||||
| 
 | ||||
|     def test_clipboard(self): | ||||
|         root = self.root | ||||
|         root.clipboard_clear() | ||||
|         root.clipboard_append('Ùñî') | ||||
|         self.assertEqual(root.clipboard_get(), 'Ùñî') | ||||
|         root.clipboard_append('çōđě') | ||||
|         self.assertEqual(root.clipboard_get(), 'Ùñîçōđě') | ||||
|         root.clipboard_clear() | ||||
|         with self.assertRaises(tkinter.TclError): | ||||
|             root.clipboard_get() | ||||
| 
 | ||||
|     def test_clipboard_astral(self): | ||||
|         root = self.root | ||||
|         root.clipboard_clear() | ||||
|         root.clipboard_append('𝔘𝔫𝔦') | ||||
|         self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦') | ||||
|         root.clipboard_append('𝔠𝔬𝔡𝔢') | ||||
|         self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦𝔠𝔬𝔡𝔢') | ||||
|         root.clipboard_clear() | ||||
|         with self.assertRaises(tkinter.TclError): | ||||
|             root.clipboard_get() | ||||
| 
 | ||||
| 
 | ||||
| tests_gui = (MiscTest, ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -489,8 +489,7 @@ def check_get_current(getval, currval): | |||
|                         expected=('mon', 'tue', 'wed', 'thur')) | ||||
|         self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur')) | ||||
|         self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string')) | ||||
|         self.checkParam(self.combo, 'values', '', | ||||
|                         expected='' if get_tk_patchlevel() < (8, 5, 10) else ()) | ||||
|         self.checkParam(self.combo, 'values', '') | ||||
| 
 | ||||
|         self.combo['values'] = ['a', 1, 'c'] | ||||
| 
 | ||||
|  | @ -1245,12 +1244,7 @@ def test_values(self): | |||
|                         expected=('mon', 'tue', 'wed', 'thur')) | ||||
|         self.checkParam(self.spin, 'values', ('mon', 'tue', 'wed', 'thur')) | ||||
|         self.checkParam(self.spin, 'values', (42, 3.14, '', 'any string')) | ||||
|         self.checkParam( | ||||
|             self.spin, | ||||
|             'values', | ||||
|             '', | ||||
|             expected='' if get_tk_patchlevel() < (8, 5, 10) else () | ||||
|         ) | ||||
|         self.checkParam(self.spin, 'values', '') | ||||
| 
 | ||||
|         self.spin['values'] = ['a', 1, 'c'] | ||||
| 
 | ||||
|  | @ -1308,8 +1302,7 @@ def test_columns(self): | |||
|         self.checkParam(widget, 'columns', 'a b c', | ||||
|                         expected=('a', 'b', 'c')) | ||||
|         self.checkParam(widget, 'columns', ('a', 'b', 'c')) | ||||
|         self.checkParam(widget, 'columns', (), | ||||
|                         expected='' if get_tk_patchlevel() < (8, 5, 10) else ()) | ||||
|         self.checkParam(widget, 'columns', '') | ||||
| 
 | ||||
|     def test_displaycolumns(self): | ||||
|         widget = self.create() | ||||
|  |  | |||
|  | @ -0,0 +1,4 @@ | |||
| OS native encoding is now used for converting between Python strings and | ||||
| Tcl objects.  This allows to display, copy and paste to clipboard emoji and | ||||
| other non-BMP characters.  Converting strings from Tcl to Python and back | ||||
| now never fails (except MemoryError). | ||||
|  | @ -96,6 +96,24 @@ Copyright (C) 1994 Steen Lumholt. | |||
| 
 | ||||
| #endif /* HAVE_CREATEFILEHANDLER */ | ||||
| 
 | ||||
| /* Use OS native encoding for converting between Python strings and
 | ||||
|    Tcl objects. | ||||
|    On Windows use UTF-16 (or UTF-32 for 32-bit Tcl_UniChar) with the | ||||
|    "surrogatepass" error handler for converting to/from Tcl Unicode objects. | ||||
|    On Linux use UTF-8 with the "surrogateescape" error handler for converting | ||||
|    to/from Tcl String objects. */ | ||||
| #ifdef MS_WINDOWS | ||||
| #define USE_TCL_UNICODE 1 | ||||
| #else | ||||
| #define USE_TCL_UNICODE 0 | ||||
| #endif | ||||
| 
 | ||||
| #if PY_LITTLE_ENDIAN | ||||
| #define NATIVE_BYTEORDER -1 | ||||
| #else | ||||
| #define NATIVE_BYTEORDER 1 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef MS_WINDOWS | ||||
| #include <conio.h> | ||||
| #define WAIT_FOR_STDIN | ||||
|  | @ -290,7 +308,6 @@ typedef struct { | |||
| } TkappObject; | ||||
| 
 | ||||
| #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, Py_REFCNT(v))) | ||||
|  | @ -311,10 +328,16 @@ static int tk_load_failed = 0; | |||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| static PyObject *Tkapp_UnicodeResult(TkappObject *); | ||||
| 
 | ||||
| static PyObject * | ||||
| Tkinter_Error(PyObject *v) | ||||
| Tkinter_Error(TkappObject *self) | ||||
| { | ||||
|     PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); | ||||
|     PyObject *res = Tkapp_UnicodeResult(self); | ||||
|     if (res != NULL) { | ||||
|         PyErr_SetObject(Tkinter_TclError, res); | ||||
|         Py_DECREF(res); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
|  | @ -368,30 +391,35 @@ static PyObject * | |||
| unicodeFromTclStringAndSize(const char *s, Py_ssize_t size) | ||||
| { | ||||
|     PyObject *r = PyUnicode_DecodeUTF8(s, size, NULL); | ||||
|     if (!r && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { | ||||
|         /* Tcl encodes null character as \xc0\x80 */ | ||||
|         if (memchr(s, '\xc0', size)) { | ||||
|             char *buf, *q; | ||||
|             const char *e = s + size; | ||||
|             PyErr_Clear(); | ||||
|             q = buf = (char *)PyMem_Malloc(size); | ||||
|             if (buf == NULL) { | ||||
|                 PyErr_NoMemory(); | ||||
|                 return NULL; | ||||
|             } | ||||
|             while (s != e) { | ||||
|                 if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') { | ||||
|                     *q++ = '\0'; | ||||
|                     s += 2; | ||||
|                 } | ||||
|                 else | ||||
|                     *q++ = *s++; | ||||
|             } | ||||
|             s = buf; | ||||
|             size = q - s; | ||||
|             r = PyUnicode_DecodeUTF8(s, size, NULL); | ||||
|             PyMem_Free(buf); | ||||
|     if (r != NULL || !PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { | ||||
|         return r; | ||||
|     } | ||||
| 
 | ||||
|     char *buf = NULL; | ||||
|     PyErr_Clear(); | ||||
|     /* Tcl encodes null character as \xc0\x80 */ | ||||
|     if (memchr(s, '\xc0', size)) { | ||||
|         char *q; | ||||
|         const char *e = s + size; | ||||
|         q = buf = (char *)PyMem_Malloc(size); | ||||
|         if (buf == NULL) { | ||||
|             PyErr_NoMemory(); | ||||
|             return NULL; | ||||
|         } | ||||
|         while (s != e) { | ||||
|             if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') { | ||||
|                 *q++ = '\0'; | ||||
|                 s += 2; | ||||
|             } | ||||
|             else | ||||
|                 *q++ = *s++; | ||||
|         } | ||||
|         s = buf; | ||||
|         size = q - s; | ||||
|     } | ||||
|     r = PyUnicode_DecodeUTF8(s, size, "surrogateescape"); | ||||
|     if (buf != NULL) { | ||||
|         PyMem_Free(buf); | ||||
|     } | ||||
|     return r; | ||||
| } | ||||
|  | @ -406,8 +434,21 @@ static PyObject * | |||
| unicodeFromTclObj(Tcl_Obj *value) | ||||
| { | ||||
|     int len; | ||||
|     char *s = Tcl_GetStringFromObj(value, &len); | ||||
| #if USE_TCL_UNICODE | ||||
|     int byteorder = NATIVE_BYTEORDER; | ||||
|     const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len); | ||||
|     if (sizeof(Tcl_UniChar) == 2) | ||||
|         return PyUnicode_DecodeUTF16((const char *)u, len * 2, | ||||
|                                      "surrogatepass", &byteorder); | ||||
|     else if (sizeof(Tcl_UniChar) == 4) | ||||
|         return PyUnicode_DecodeUTF32((const char *)u, len * 4, | ||||
|                                      "surrogatepass", &byteorder); | ||||
|     else | ||||
|         Py_UNREACHABLE(); | ||||
| #else | ||||
|     const char *s = Tcl_GetStringFromObj(value, &len); | ||||
|     return unicodeFromTclStringAndSize(s, len); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -746,7 +787,7 @@ Tkapp_New(const char *screenName, const char *className, | |||
| #endif | ||||
| 
 | ||||
|     if (Tcl_AppInit(v->interp) != TCL_OK) { | ||||
|         PyObject *result = Tkinter_Error((PyObject *)v); | ||||
|         PyObject *result = Tkinter_Error(v); | ||||
| #ifdef TKINTER_PROTECT_LOADTK | ||||
|         if (wantTk) { | ||||
|             const char *_tkinter_tk_failed; | ||||
|  | @ -817,12 +858,6 @@ PyTclObject_dealloc(PyTclObject *self) | |||
|     Py_DECREF(tp); | ||||
| } | ||||
| 
 | ||||
| static const char * | ||||
| PyTclObject_TclString(PyObject *self) | ||||
| { | ||||
|     return Tcl_GetString(((PyTclObject*)self)->value); | ||||
| } | ||||
| 
 | ||||
| /* Like _str, but create Unicode if necessary. */ | ||||
| PyDoc_STRVAR(PyTclObject_string__doc__, | ||||
| "the string representation of this object, either as str or bytes"); | ||||
|  | @ -1048,53 +1083,51 @@ AsObj(PyObject *value) | |||
|     } | ||||
| 
 | ||||
|     if (PyUnicode_Check(value)) { | ||||
|         void *inbuf; | ||||
|         Py_ssize_t size; | ||||
|         int kind; | ||||
|         Tcl_UniChar *outbuf = NULL; | ||||
|         Py_ssize_t i; | ||||
|         size_t allocsize; | ||||
| 
 | ||||
|         if (PyUnicode_READY(value) == -1) | ||||
|             return NULL; | ||||
| 
 | ||||
|         inbuf = PyUnicode_DATA(value); | ||||
|         size = PyUnicode_GET_LENGTH(value); | ||||
|         if (size == 0) | ||||
|             return Tcl_NewUnicodeObj((const void *)"", 0); | ||||
|         Py_ssize_t size = PyUnicode_GET_LENGTH(value); | ||||
|         if (size == 0) { | ||||
|             return Tcl_NewStringObj("", 0); | ||||
|         } | ||||
|         if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) { | ||||
|             PyErr_SetString(PyExc_OverflowError, "string is too long"); | ||||
|             return NULL; | ||||
|         } | ||||
|         kind = PyUnicode_KIND(value); | ||||
|         if (kind == sizeof(Tcl_UniChar)) | ||||
|             return Tcl_NewUnicodeObj(inbuf, (int)size); | ||||
|         allocsize = ((size_t)size) * sizeof(Tcl_UniChar); | ||||
|         outbuf = (Tcl_UniChar*)PyMem_Malloc(allocsize); | ||||
|         /* Else overflow occurred, and we take the next exit */ | ||||
|         if (!outbuf) { | ||||
|             PyErr_NoMemory(); | ||||
|         if (PyUnicode_IS_ASCII(value)) { | ||||
|             return Tcl_NewStringObj((const char *)PyUnicode_DATA(value), | ||||
|                                     (int)size); | ||||
|         } | ||||
| 
 | ||||
|         PyObject *encoded; | ||||
| #if USE_TCL_UNICODE | ||||
|         if (sizeof(Tcl_UniChar) == 2) | ||||
|             encoded = _PyUnicode_EncodeUTF16(value, | ||||
|                     "surrogatepass", NATIVE_BYTEORDER); | ||||
|         else if (sizeof(Tcl_UniChar) == 4) | ||||
|             encoded = _PyUnicode_EncodeUTF32(value, | ||||
|                     "surrogatepass", NATIVE_BYTEORDER); | ||||
|         else | ||||
|             Py_UNREACHABLE(); | ||||
| #else | ||||
|         encoded = _PyUnicode_AsUTF8String(value, "surrogateescape"); | ||||
| #endif | ||||
|         if (!encoded) { | ||||
|             return NULL; | ||||
|         } | ||||
|         for (i = 0; i < size; i++) { | ||||
|             Py_UCS4 ch = PyUnicode_READ(kind, inbuf, i); | ||||
|             /* We cannot test for sizeof(Tcl_UniChar) directly,
 | ||||
|                so we test for UTF-8 size instead. */ | ||||
| #if TCL_UTF_MAX == 3 | ||||
|             if (ch >= 0x10000) { | ||||
|                 /* Tcl doesn't do UTF-16, yet. */ | ||||
|                 PyErr_Format(Tkinter_TclError, | ||||
|                              "character U+%x is above the range " | ||||
|                              "(U+0000-U+FFFF) allowed by Tcl", | ||||
|                              ch); | ||||
|                 PyMem_Free(outbuf); | ||||
|                 return NULL; | ||||
|             } | ||||
| #endif | ||||
|             outbuf[i] = ch; | ||||
|         size = PyBytes_GET_SIZE(encoded); | ||||
|         if (size > INT_MAX) { | ||||
|             Py_DECREF(encoded); | ||||
|             PyErr_SetString(PyExc_OverflowError, "string is too long"); | ||||
|             return NULL; | ||||
|         } | ||||
|         result = Tcl_NewUnicodeObj(outbuf, (int)size); | ||||
|         PyMem_Free(outbuf); | ||||
| #if USE_TCL_UNICODE | ||||
|         result = Tcl_NewUnicodeObj((const Tcl_UniChar *)PyBytes_AS_STRING(encoded), | ||||
|                                    (int)(size / sizeof(Tcl_UniChar))); | ||||
| #else | ||||
|         result = Tcl_NewStringObj(PyBytes_AS_STRING(encoded), (int)size); | ||||
| #endif | ||||
|         Py_DECREF(encoded); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|  | @ -1113,7 +1146,7 @@ AsObj(PyObject *value) | |||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| fromBoolean(PyObject* tkapp, Tcl_Obj *value) | ||||
| fromBoolean(TkappObject *tkapp, Tcl_Obj *value) | ||||
| { | ||||
|     int boolValue; | ||||
|     if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR) | ||||
|  | @ -1122,7 +1155,7 @@ fromBoolean(PyObject* tkapp, Tcl_Obj *value) | |||
| } | ||||
| 
 | ||||
| static PyObject* | ||||
| fromWideIntObj(PyObject* tkapp, Tcl_Obj *value) | ||||
| fromWideIntObj(TkappObject *tkapp, Tcl_Obj *value) | ||||
| { | ||||
|         Tcl_WideInt wideValue; | ||||
|         if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) { | ||||
|  | @ -1138,7 +1171,7 @@ fromWideIntObj(PyObject* tkapp, Tcl_Obj *value) | |||
| 
 | ||||
| #ifdef HAVE_LIBTOMMAMTH | ||||
| static PyObject* | ||||
| fromBignumObj(PyObject* tkapp, Tcl_Obj *value) | ||||
| fromBignumObj(TkappObject *tkapp, Tcl_Obj *value) | ||||
| { | ||||
|     mp_int bigValue; | ||||
|     unsigned long numBytes; | ||||
|  | @ -1174,32 +1207,31 @@ fromBignumObj(PyObject* tkapp, Tcl_Obj *value) | |||
| #endif | ||||
| 
 | ||||
| static PyObject* | ||||
| FromObj(PyObject* tkapp, Tcl_Obj *value) | ||||
| FromObj(TkappObject *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); | ||||
|         return unicodeFromTclObj(value); | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->BooleanType || | ||||
|         value->typePtr == app->OldBooleanType) { | ||||
|     if (value->typePtr == tkapp->BooleanType || | ||||
|         value->typePtr == tkapp->OldBooleanType) { | ||||
|         return fromBoolean(tkapp, value); | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->ByteArrayType) { | ||||
|     if (value->typePtr == tkapp->ByteArrayType) { | ||||
|         int size; | ||||
|         char *data = (char*)Tcl_GetByteArrayFromObj(value, &size); | ||||
|         return PyBytes_FromStringAndSize(data, size); | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->DoubleType) { | ||||
|     if (value->typePtr == tkapp->DoubleType) { | ||||
|         return PyFloat_FromDouble(value->internalRep.doubleValue); | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->IntType) { | ||||
|     if (value->typePtr == tkapp->IntType) { | ||||
|         long longValue; | ||||
|         if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK) | ||||
|             return PyLong_FromLong(longValue); | ||||
|  | @ -1207,8 +1239,8 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) | |||
|            fall through to wideInt handling. */ | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->IntType || | ||||
|         value->typePtr == app->WideIntType) { | ||||
|     if (value->typePtr == tkapp->IntType || | ||||
|         value->typePtr == tkapp->WideIntType) { | ||||
|         result = fromWideIntObj(tkapp, value); | ||||
|         if (result != NULL || PyErr_Occurred()) | ||||
|             return result; | ||||
|  | @ -1218,14 +1250,14 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) | |||
|     } | ||||
| 
 | ||||
| #ifdef HAVE_LIBTOMMAMTH | ||||
|     if (value->typePtr == app->IntType || | ||||
|         value->typePtr == app->WideIntType || | ||||
|         value->typePtr == app->BignumType) { | ||||
|     if (value->typePtr == tkapp->IntType || | ||||
|         value->typePtr == tkapp->WideIntType || | ||||
|         value->typePtr == tkapp->BignumType) { | ||||
|         return fromBignumObj(tkapp, value); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     if (value->typePtr == app->ListType) { | ||||
|     if (value->typePtr == tkapp->ListType) { | ||||
|         int size; | ||||
|         int i, status; | ||||
|         PyObject *elem; | ||||
|  | @ -1253,30 +1285,28 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) | |||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->ProcBodyType) { | ||||
|     if (value->typePtr == tkapp->ProcBodyType) { | ||||
|       /* fall through: return tcl object. */ | ||||
|     } | ||||
| 
 | ||||
|     if (value->typePtr == app->StringType) { | ||||
|         return PyUnicode_FromKindAndData( | ||||
|             sizeof(Tcl_UniChar), Tcl_GetUnicode(value), | ||||
|             Tcl_GetCharLength(value)); | ||||
|     if (value->typePtr == tkapp->StringType) { | ||||
|         return unicodeFromTclObj(value); | ||||
|     } | ||||
| 
 | ||||
| #if TK_HEX_VERSION >= 0x08050000 | ||||
|     if (app->BooleanType == NULL && | ||||
|     if (tkapp->BooleanType == NULL && | ||||
|         strcmp(value->typePtr->name, "booleanString") == 0) { | ||||
|         /* booleanString type is not registered in Tcl */ | ||||
|         app->BooleanType = value->typePtr; | ||||
|         tkapp->BooleanType = value->typePtr; | ||||
|         return fromBoolean(tkapp, value); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef HAVE_LIBTOMMAMTH | ||||
|     if (app->BignumType == NULL && | ||||
|     if (tkapp->BignumType == NULL && | ||||
|         strcmp(value->typePtr->name, "bignum") == 0) { | ||||
|         /* bignum type is not registered in Tcl */ | ||||
|         app->BignumType = value->typePtr; | ||||
|         tkapp->BignumType = value->typePtr; | ||||
|         return fromBignumObj(tkapp, value); | ||||
|     } | ||||
| #endif | ||||
|  | @ -1366,19 +1396,28 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) | |||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Convert the results of a command call into a Python string. */ | ||||
| 
 | ||||
| static PyObject * | ||||
| Tkapp_UnicodeResult(TkappObject *self) | ||||
| { | ||||
|     return unicodeFromTclObj(Tcl_GetObjResult(self->interp)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Convert the results of a command call into a Python objects. */ | ||||
| 
 | ||||
| static PyObject* | ||||
| Tkapp_CallResult(TkappObject *self) | ||||
| static PyObject * | ||||
| Tkapp_ObjectResult(TkappObject *self) | ||||
| { | ||||
|     PyObject *res = NULL; | ||||
|     Tcl_Obj *value = Tcl_GetObjResult(self->interp); | ||||
|     if(self->wantobjects) { | ||||
|     if (self->wantobjects) { | ||||
|         /* Not sure whether the IncrRef is necessary, but something
 | ||||
|            may overwrite the interpreter result while we are | ||||
|            converting it. */ | ||||
|         Tcl_IncrRefCount(value); | ||||
|         res = FromObj((PyObject*)self, value); | ||||
|         res = FromObj(self, value); | ||||
|         Tcl_DecrRefCount(value); | ||||
|     } else { | ||||
|         res = unicodeFromTclObj(value); | ||||
|  | @ -1410,15 +1449,13 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags) | |||
|     i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags); | ||||
|     ENTER_PYTHON | ||||
|     if (i == TCL_ERROR) { | ||||
|         *(e->res) = NULL; | ||||
|         *(e->exc_type) = NULL; | ||||
|         *(e->exc_tb) = NULL; | ||||
|         *(e->exc_value) = PyObject_CallFunction( | ||||
|             Tkinter_TclError, "s", | ||||
|             Tcl_GetStringResult(e->self->interp)); | ||||
|         *(e->res) = Tkinter_Error(e->self); | ||||
|     } | ||||
|     else { | ||||
|         *(e->res) = Tkapp_CallResult(e->self); | ||||
|         *(e->res) = Tkapp_ObjectResult(e->self); | ||||
|     } | ||||
|     if (*(e->res) == NULL) { | ||||
|         PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb); | ||||
|     } | ||||
|     LEAVE_PYTHON | ||||
| 
 | ||||
|  | @ -1506,9 +1543,9 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) | |||
|         ENTER_OVERLAP | ||||
| 
 | ||||
|         if (i == TCL_ERROR) | ||||
|             Tkinter_Error(selfptr); | ||||
|             Tkinter_Error(self); | ||||
|         else | ||||
|             res = Tkapp_CallResult(self); | ||||
|             res = Tkapp_ObjectResult(self); | ||||
| 
 | ||||
|         LEAVE_OVERLAP_TCL | ||||
| 
 | ||||
|  | @ -1540,9 +1577,9 @@ _tkinter_tkapp_eval_impl(TkappObject *self, const char *script) | |||
|     err = Tcl_Eval(Tkapp_Interp(self), script); | ||||
|     ENTER_OVERLAP | ||||
|     if (err == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = unicodeFromTclString(Tkapp_Result(self)); | ||||
|         res = Tkapp_UnicodeResult(self); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|     return res; | ||||
| } | ||||
|  | @ -1569,9 +1606,9 @@ _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName) | |||
|     err = Tcl_EvalFile(Tkapp_Interp(self), fileName); | ||||
|     ENTER_OVERLAP | ||||
|     if (err == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = unicodeFromTclString(Tkapp_Result(self)); | ||||
|         res = Tkapp_UnicodeResult(self); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|     return res; | ||||
| } | ||||
|  | @ -1598,9 +1635,9 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script) | |||
|     err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL); | ||||
|     ENTER_OVERLAP | ||||
|     if (err == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = unicodeFromTclString(Tkapp_Result(self)); | ||||
|         res = Tkapp_UnicodeResult(self); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|     return res; | ||||
| } | ||||
|  | @ -1631,13 +1668,13 @@ _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg) | |||
| 
 | ||||
| /** Tcl Variable **/ | ||||
| 
 | ||||
| typedef PyObject* (*EventFunc)(PyObject*, PyObject *args, int flags); | ||||
| typedef PyObject* (*EventFunc)(TkappObject *, PyObject *, int); | ||||
| 
 | ||||
| TCL_DECLARE_MUTEX(var_mutex) | ||||
| 
 | ||||
| typedef struct VarEvent { | ||||
|     Tcl_Event ev; /* must be first */ | ||||
|     PyObject *self; | ||||
|     TkappObject *self; | ||||
|     PyObject *args; | ||||
|     int flags; | ||||
|     EventFunc func; | ||||
|  | @ -1692,7 +1729,7 @@ varname_converter(PyObject *in, void *_out) | |||
|         return 1; | ||||
|     } | ||||
|     if (PyTclObject_Check(in)) { | ||||
|         *out = PyTclObject_TclString(in); | ||||
|         *out = Tcl_GetString(((PyTclObject *)in)->value); | ||||
|         return 1; | ||||
|     } | ||||
|     PyErr_Format(PyExc_TypeError, | ||||
|  | @ -1750,7 +1787,7 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) | |||
|             PyErr_NoMemory(); | ||||
|             return NULL; | ||||
|         } | ||||
|         ev->self = selfptr; | ||||
|         ev->self = self; | ||||
|         ev->args = args; | ||||
|         ev->flags = flags; | ||||
|         ev->func = func; | ||||
|  | @ -1770,11 +1807,11 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) | |||
|         return res; | ||||
|     } | ||||
|     /* Tcl is not threaded, or this is the interpreter thread. */ | ||||
|     return func(selfptr, args, flags); | ||||
|     return func(self, args, flags); | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| SetVar(PyObject *self, PyObject *args, int flags) | ||||
| SetVar(TkappObject *self, PyObject *args, int flags) | ||||
| { | ||||
|     const char *name1, *name2; | ||||
|     PyObject *newValue; | ||||
|  | @ -1843,7 +1880,7 @@ Tkapp_GlobalSetVar(PyObject *self, PyObject *args) | |||
| 
 | ||||
| 
 | ||||
| static PyObject * | ||||
| GetVar(PyObject *self, PyObject *args, int flags) | ||||
| GetVar(TkappObject *self, PyObject *args, int flags) | ||||
| { | ||||
|     const char *name1, *name2=NULL; | ||||
|     PyObject *res = NULL; | ||||
|  | @ -1858,10 +1895,9 @@ GetVar(PyObject *self, PyObject *args, int flags) | |||
|     tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); | ||||
|     ENTER_OVERLAP | ||||
|     if (tres == NULL) { | ||||
|         PyErr_SetString(Tkinter_TclError, | ||||
|                         Tcl_GetStringResult(Tkapp_Interp(self))); | ||||
|         Tkinter_Error(self); | ||||
|     } else { | ||||
|         if (((TkappObject*)self)->wantobjects) { | ||||
|         if (self->wantobjects) { | ||||
|             res = FromObj(self, tres); | ||||
|         } | ||||
|         else { | ||||
|  | @ -1887,7 +1923,7 @@ Tkapp_GlobalGetVar(PyObject *self, PyObject *args) | |||
| 
 | ||||
| 
 | ||||
| static PyObject * | ||||
| UnsetVar(PyObject *self, PyObject *args, int flags) | ||||
| UnsetVar(TkappObject *self, PyObject *args, int flags) | ||||
| { | ||||
|     char *name1, *name2=NULL; | ||||
|     int code; | ||||
|  | @ -1959,7 +1995,7 @@ _tkinter_tkapp_getint(TkappObject *self, PyObject *arg) | |||
|         CHECK_STRING_LENGTH(s); | ||||
|         value = Tcl_NewStringObj(s, -1); | ||||
|         if (value == NULL) | ||||
|             return Tkinter_Error((PyObject *)self); | ||||
|             return Tkinter_Error(self); | ||||
|     } | ||||
|     /* 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). | ||||
|  | @ -1968,14 +2004,14 @@ _tkinter_tkapp_getint(TkappObject *self, PyObject *arg) | |||
|        value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform). | ||||
|      */ | ||||
| #ifdef HAVE_LIBTOMMAMTH | ||||
|     result = fromBignumObj((PyObject *)self, value); | ||||
|     result = fromBignumObj(self, value); | ||||
| #else | ||||
|     result = fromWideIntObj((PyObject *)self, value); | ||||
|     result = fromWideIntObj(self, value); | ||||
| #endif | ||||
|     Tcl_DecrRefCount(value); | ||||
|     if (result != NULL || PyErr_Occurred()) | ||||
|         return result; | ||||
|     return Tkinter_Error((PyObject *)self); | ||||
|     return Tkinter_Error(self); | ||||
| } | ||||
| 
 | ||||
| /*[clinic input]
 | ||||
|  | @ -2006,7 +2042,7 @@ _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg) | |||
|         if (Tcl_GetDoubleFromObj(Tkapp_Interp(self), | ||||
|                                  ((PyTclObject*)arg)->value, | ||||
|                                  &v) == TCL_ERROR) | ||||
|             return Tkinter_Error((PyObject *)self); | ||||
|             return Tkinter_Error(self); | ||||
|         return PyFloat_FromDouble(v); | ||||
|     } | ||||
| 
 | ||||
|  | @ -2014,7 +2050,7 @@ _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg) | |||
|         return NULL; | ||||
|     CHECK_STRING_LENGTH(s); | ||||
|     if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) | ||||
|         return Tkinter_Error((PyObject *)self); | ||||
|         return Tkinter_Error(self); | ||||
|     return PyFloat_FromDouble(v); | ||||
| } | ||||
| 
 | ||||
|  | @ -2041,7 +2077,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg) | |||
|         if (Tcl_GetBooleanFromObj(Tkapp_Interp(self), | ||||
|                                   ((PyTclObject*)arg)->value, | ||||
|                                   &v) == TCL_ERROR) | ||||
|             return Tkinter_Error((PyObject *)self); | ||||
|             return Tkinter_Error(self); | ||||
|         return PyBool_FromLong(v); | ||||
|     } | ||||
| 
 | ||||
|  | @ -2049,7 +2085,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg) | |||
|         return NULL; | ||||
|     CHECK_STRING_LENGTH(s); | ||||
|     if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) | ||||
|         return Tkinter_Error((PyObject *)self); | ||||
|         return Tkinter_Error(self); | ||||
|     return PyBool_FromLong(v); | ||||
| } | ||||
| 
 | ||||
|  | @ -2075,9 +2111,9 @@ _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s) | |||
|     retval = Tcl_ExprString(Tkapp_Interp(self), s); | ||||
|     ENTER_OVERLAP | ||||
|     if (retval == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = unicodeFromTclString(Tkapp_Result(self)); | ||||
|         res = Tkapp_UnicodeResult(self); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|     return res; | ||||
| } | ||||
|  | @ -2105,7 +2141,7 @@ _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s) | |||
|     retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v); | ||||
|     ENTER_OVERLAP | ||||
|     if (retval == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = PyLong_FromLong(v); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|  | @ -2136,7 +2172,7 @@ _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s) | |||
|     ENTER_OVERLAP | ||||
|     PyFPE_END_PROTECT(retval) | ||||
|     if (retval == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = PyFloat_FromDouble(v); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|  | @ -2165,7 +2201,7 @@ _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s) | |||
|     retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); | ||||
|     ENTER_OVERLAP | ||||
|     if (retval == TCL_ERROR) | ||||
|         res = Tkinter_Error((PyObject *)self); | ||||
|         res = Tkinter_Error(self); | ||||
|     else | ||||
|         res = PyLong_FromLong(v); | ||||
|     LEAVE_OVERLAP_TCL | ||||
|  | @ -2198,12 +2234,12 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg) | |||
|         if (Tcl_ListObjGetElements(Tkapp_Interp(self), | ||||
|                                    ((PyTclObject*)arg)->value, | ||||
|                                    &objc, &objv) == TCL_ERROR) { | ||||
|             return Tkinter_Error((PyObject *)self); | ||||
|             return Tkinter_Error(self); | ||||
|         } | ||||
|         if (!(v = PyTuple_New(objc))) | ||||
|             return NULL; | ||||
|         for (i = 0; i < objc; i++) { | ||||
|             PyObject *s = FromObj((PyObject*)self, objv[i]); | ||||
|             PyObject *s = FromObj(self, objv[i]); | ||||
|             if (!s) { | ||||
|                 Py_DECREF(v); | ||||
|                 return NULL; | ||||
|  | @ -2231,7 +2267,7 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg) | |||
|     if (Tcl_SplitList(Tkapp_Interp(self), list, | ||||
|                       &argc, &argv) == TCL_ERROR)  { | ||||
|         PyMem_Free(list); | ||||
|         return Tkinter_Error((PyObject *)self); | ||||
|         return Tkinter_Error(self); | ||||
|     } | ||||
| 
 | ||||
|     if (!(v = PyTuple_New(argc))) | ||||
|  | @ -2275,16 +2311,16 @@ _tkinter_tkapp_split(TkappObject *self, PyObject *arg) | |||
|         int i; | ||||
|         if (Tcl_ListObjGetElements(Tkapp_Interp(self), value, | ||||
|                                    &objc, &objv) == TCL_ERROR) { | ||||
|             return FromObj((PyObject*)self, value); | ||||
|             return FromObj(self, value); | ||||
|         } | ||||
|         if (objc == 0) | ||||
|             return PyUnicode_FromString(""); | ||||
|         if (objc == 1) | ||||
|             return FromObj((PyObject*)self, objv[0]); | ||||
|             return FromObj(self, objv[0]); | ||||
|         if (!(v = PyTuple_New(objc))) | ||||
|             return NULL; | ||||
|         for (i = 0; i < objc; i++) { | ||||
|             PyObject *s = FromObj((PyObject*)self, objv[i]); | ||||
|             PyObject *s = FromObj(self, objv[i]); | ||||
|             if (!s) { | ||||
|                 Py_DECREF(v); | ||||
|                 return NULL; | ||||
|  | @ -2331,34 +2367,31 @@ PythonCmd_Error(Tcl_Interp *interp) | |||
|  * function or method. | ||||
|  */ | ||||
| static int | ||||
| PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) | ||||
| PythonCmd(ClientData clientData, Tcl_Interp *interp, | ||||
|           int objc, Tcl_Obj *const objv[]) | ||||
| { | ||||
|     PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; | ||||
|     PyObject *func, *arg, *res; | ||||
|     int i, rv; | ||||
|     PyObject *args, *res; | ||||
|     int i; | ||||
|     Tcl_Obj *obj_res; | ||||
| 
 | ||||
|     ENTER_PYTHON | ||||
| 
 | ||||
|     /* TBD: no error checking here since we know, via the
 | ||||
|      * Tkapp_CreateCommand() that the client data is a two-tuple | ||||
|      */ | ||||
|     func = data->func; | ||||
| 
 | ||||
|     /* Create argument list (argv1, ..., argvN) */ | ||||
|     if (!(arg = PyTuple_New(argc - 1))) | ||||
|     /* Create argument tuple (objv1, ..., objvN) */ | ||||
|     if (!(args = PyTuple_New(objc - 1))) | ||||
|         return PythonCmd_Error(interp); | ||||
| 
 | ||||
|     for (i = 0; i < (argc - 1); i++) { | ||||
|         PyObject *s = unicodeFromTclString(argv[i + 1]); | ||||
|     for (i = 0; i < (objc - 1); i++) { | ||||
|         PyObject *s = unicodeFromTclObj(objv[i + 1]); | ||||
|         if (!s) { | ||||
|             Py_DECREF(arg); | ||||
|             Py_DECREF(args); | ||||
|             return PythonCmd_Error(interp); | ||||
|         } | ||||
|         PyTuple_SET_ITEM(arg, i, s); | ||||
|         PyTuple_SET_ITEM(args, i, s); | ||||
|     } | ||||
|     res = PyObject_Call(func, arg, NULL); | ||||
|     Py_DECREF(arg); | ||||
| 
 | ||||
|     res = PyObject_Call(data->func, args, NULL); | ||||
|     Py_DECREF(args); | ||||
| 
 | ||||
|     if (res == NULL) | ||||
|         return PythonCmd_Error(interp); | ||||
|  | @ -2368,18 +2401,15 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[ | |||
|         Py_DECREF(res); | ||||
|         return PythonCmd_Error(interp); | ||||
|     } | ||||
|     else { | ||||
|         Tcl_SetObjResult(interp, obj_res); | ||||
|         rv = TCL_OK; | ||||
|     } | ||||
| 
 | ||||
|     Tcl_SetObjResult(interp, obj_res); | ||||
|     Py_DECREF(res); | ||||
| 
 | ||||
|     LEAVE_PYTHON | ||||
| 
 | ||||
|     return rv; | ||||
|     return TCL_OK; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| PythonCmdDelete(ClientData clientData) | ||||
| { | ||||
|  | @ -2411,7 +2441,7 @@ static int | |||
| Tkapp_CommandProc(CommandEvent *ev, int flags) | ||||
| { | ||||
|     if (ev->create) | ||||
|         *ev->status = Tcl_CreateCommand( | ||||
|         *ev->status = Tcl_CreateObjCommand( | ||||
|             ev->interp, ev->name, PythonCmd, | ||||
|             ev->data, PythonCmdDelete) == NULL; | ||||
|     else | ||||
|  | @ -2477,7 +2507,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name, | |||
|     else | ||||
|     { | ||||
|         ENTER_TCL | ||||
|         err = Tcl_CreateCommand( | ||||
|         err = Tcl_CreateObjCommand( | ||||
|             Tkapp_Interp(self), name, PythonCmd, | ||||
|             (ClientData)data, PythonCmdDelete) == NULL; | ||||
|         LEAVE_TCL | ||||
|  | @ -2953,9 +2983,9 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) | |||
|     if (err == TCL_ERROR) { | ||||
|         /* This sets an exception, but we cannot return right
 | ||||
|            away because we need to exit the overlap first. */ | ||||
|         Tkinter_Error((PyObject *)self); | ||||
|         Tkinter_Error(self); | ||||
|     } else { | ||||
|         _tk_exists = Tkapp_Result(self); | ||||
|         _tk_exists = Tcl_GetStringResult(Tkapp_Interp(self)); | ||||
|     } | ||||
|     LEAVE_OVERLAP_TCL | ||||
|     if (err == TCL_ERROR) { | ||||
|  | @ -2963,8 +2993,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) | |||
|     } | ||||
|     if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0)     { | ||||
|         if (Tk_Init(interp)             == TCL_ERROR) { | ||||
|             PyErr_SetString(Tkinter_TclError, | ||||
|                             Tcl_GetStringResult(Tkapp_Interp(self))); | ||||
|             Tkinter_Error(self); | ||||
| #ifdef TKINTER_PROTECT_LOADTK | ||||
|             tk_load_failed = 1; | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka