comparison src/if_tcl.c @ 48:67300faee616 v7-3-618

v7-3-618
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 01 Aug 2012 18:08:28 +0900
parents c16898406ff2
children
comparison
equal deleted inserted replaced
47:6c0584ec21b1 48:67300faee616
72 #ifdef DYNAMIC_TCL 72 #ifdef DYNAMIC_TCL
73 # define USE_TCL_STUBS /* use tcl's stubs mechanism */ 73 # define USE_TCL_STUBS /* use tcl's stubs mechanism */
74 #endif 74 #endif
75 75
76 #include <tcl.h> 76 #include <tcl.h>
77 #include <errno.h>
78 #include <string.h> 77 #include <string.h>
79 78
80 typedef struct 79 typedef struct
81 { 80 {
82 Tcl_Interp *interp; 81 Tcl_Interp *interp;
82 int exitvalue;
83 int range_start, range_end; 83 int range_start, range_end;
84 int lbase; 84 int lbase;
85 char *curbuf, *curwin; 85 char *curbuf, *curwin;
86 } tcl_info; 86 } tcl_info;
87 87
88 static tcl_info tclinfo = { NULL, 0, 0, 0, NULL, NULL }; 88 static tcl_info tclinfo = { NULL, 0, 0, 0, 0, NULL, NULL };
89 89
90 #define VAR_RANGE1 "::vim::range(start)" 90 #define VAR_RANGE1 "::vim::range(start)"
91 #define VAR_RANGE2 "::vim::range(begin)" 91 #define VAR_RANGE2 "::vim::range(begin)"
92 #define VAR_RANGE3 "::vim::range(end)" 92 #define VAR_RANGE3 "::vim::range(end)"
93 #define VAR_CURBUF "::vim::current(buffer)" 93 #define VAR_CURBUF "::vim::current(buffer)"
278 /**************************************************************************** 278 /****************************************************************************
279 Tcl commands 279 Tcl commands
280 ****************************************************************************/ 280 ****************************************************************************/
281 281
282 /* 282 /*
283 * Replace standard "exit" and "catch" commands. 283 * Replace standard "exit" command.
284 * 284 *
285 * This is a design flaw in Tcl - the standard "exit" command just calls 285 * Delete the Tcl interpreter; a new one will be created with the next
286 * exit() and kills the application. It should return TCL_EXIT to the 286 * :tcl command). The exit code is saved (and retrieved in tclexit()).
287 * app, which then decides if it wants to terminate or not. In our case, 287 * Since Tcl's exit is never expected to return and this replacement
288 * we just delete the Tcl interpreter (and create a new one with the next 288 * does, then (except for a trivial case) additional Tcl commands will
289 * :tcl command). 289 * be run. Since the interpreter is now marked as deleted, an error
290 */ 290 * will be returned -- typically "attempt to call eval in deleted
291 #define TCL_EXIT 5 291 * interpreter". Hopefully, at this point, checks for TCL_ERROR take
292 292 * place and control percolates back up to Vim -- but with this new error
293 * string in the interpreter's result value. Therefore it would be
294 * useless for this routine to return the exit code via Tcl_SetResult().
295 */
293 static int 296 static int
294 exitcmd(dummy, interp, objc, objv) 297 exitcmd(dummy, interp, objc, objv)
295 ClientData dummy UNUSED; 298 ClientData dummy UNUSED;
296 Tcl_Interp *interp; 299 Tcl_Interp *interp;
297 int objc; 300 int objc;
304 case 2: 307 case 2:
305 if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK) 308 if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK)
306 break; 309 break;
307 /* FALLTHROUGH */ 310 /* FALLTHROUGH */
308 case 1: 311 case 1:
309 Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); 312 tclinfo.exitvalue = value;
310 return TCL_EXIT; 313
314 Tcl_DeleteInterp(interp);
315 break;
311 default: 316 default:
312 Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); 317 Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
313 }
314 return TCL_ERROR;
315 }
316
317 static int
318 catchcmd(dummy, interp, objc, objv)
319 ClientData dummy UNUSED;
320 Tcl_Interp *interp;
321 int objc;
322 Tcl_Obj *CONST objv[];
323 {
324 char *varname = NULL;
325 int result;
326
327 switch (objc)
328 {
329 case 3:
330 varname = Tcl_GetStringFromObj(objv[2], NULL);
331 /* fallthrough */
332 case 2:
333 Tcl_ResetResult(interp);
334 Tcl_AllowExceptions(interp);
335 result = Tcl_EvalObj(interp, objv[1]);
336 if (result == TCL_EXIT)
337 return result;
338 if (varname)
339 {
340 if (Tcl_SetVar(interp, varname, Tcl_GetStringResult(interp), 0) == NULL)
341 {
342 Tcl_SetResult(interp, "couldn't save command result in variable", TCL_STATIC);
343 return TCL_ERROR;
344 }
345 }
346 Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
347 return TCL_OK;
348 default:
349 Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?");
350 } 318 }
351 return TCL_ERROR; 319 return TCL_ERROR;
352 } 320 }
353 321
354 /* 322 /*
371 } 339 }
372 340
373 /* 341 /*
374 * "::vim::buffer list" - create a list of buffer commands. 342 * "::vim::buffer list" - create a list of buffer commands.
375 * "::vim::buffer {N}" - create buffer command for buffer N. 343 * "::vim::buffer {N}" - create buffer command for buffer N.
344 * "::vim::buffer exists {N}" - test if buffer N exists.
376 * "::vim::buffer new" - create a new buffer (not implemented) 345 * "::vim::buffer new" - create a new buffer (not implemented)
377 */ 346 */
378 static int 347 static int
379 buffercmd(dummy, interp, objc, objv) 348 buffercmd(dummy, interp, objc, objv)
380 ClientData dummy UNUSED; 349 ClientData dummy UNUSED;
1662 1631
1663 1632
1664 static Tcl_ChannelType channel_type = 1633 static Tcl_ChannelType channel_type =
1665 { 1634 {
1666 "vimmessage", /* typeName */ 1635 "vimmessage", /* typeName */
1667 NULL, /* version */ 1636 TCL_CHANNEL_VERSION_2, /* version */
1668 channel_close, /* closeProc */ 1637 channel_close, /* closeProc */
1669 channel_input, /* inputProc */ 1638 channel_input, /* inputProc */
1670 channel_output, /* outputProc */ 1639 channel_output, /* outputProc */
1671 NULL, /* seekProc */ 1640 NULL, /* seekProc */
1672 NULL, /* setOptionProc */ 1641 NULL, /* setOptionProc */
1677 NULL, /* blockModeProc */ 1646 NULL, /* blockModeProc */
1678 #ifdef TCL_CHANNEL_VERSION_2 1647 #ifdef TCL_CHANNEL_VERSION_2
1679 NULL, /* flushProc */ 1648 NULL, /* flushProc */
1680 NULL, /* handlerProc */ 1649 NULL, /* handlerProc */
1681 #endif 1650 #endif
1651 /* The following should not be necessary since TCL_CHANNEL_VERSION_2 was
1652 * set above */
1682 #ifdef TCL_CHANNEL_VERSION_3 1653 #ifdef TCL_CHANNEL_VERSION_3
1683 NULL, /* wideSeekProc */ 1654 NULL, /* wideSeekProc */
1684 #endif 1655 #endif
1685 #ifdef TCL_CHANNEL_VERSION_4 1656 #ifdef TCL_CHANNEL_VERSION_4
1686 NULL, /* threadActionProc */ 1657 NULL, /* threadActionProc */
1740 if (!tclinfo.interp) 1711 if (!tclinfo.interp)
1741 { 1712 {
1742 Tcl_Interp *interp; 1713 Tcl_Interp *interp;
1743 static Tcl_Channel ch1, ch2; 1714 static Tcl_Channel ch1, ch2;
1744 1715
1745 /* replace stdout and stderr */ 1716 /* Create replacement channels for stdout and stderr; this has to be
1717 * done each time an interpreter is created since the channels are closed
1718 * when the interpreter is deleted */
1746 ch1 = Tcl_CreateChannel(&channel_type, "vimout", VIMOUT, TCL_WRITABLE); 1719 ch1 = Tcl_CreateChannel(&channel_type, "vimout", VIMOUT, TCL_WRITABLE);
1747 ch2 = Tcl_CreateChannel(&channel_type, "vimerr", VIMERR, TCL_WRITABLE); 1720 ch2 = Tcl_CreateChannel(&channel_type, "vimerr", VIMERR, TCL_WRITABLE);
1748 Tcl_SetStdChannel(ch1, TCL_STDOUT); 1721 Tcl_SetStdChannel(ch1, TCL_STDOUT);
1749 Tcl_SetStdChannel(ch2, TCL_STDERR); 1722 Tcl_SetStdChannel(ch2, TCL_STDERR);
1750 1723
1760 /* VIM sure is interactive */ 1733 /* VIM sure is interactive */
1761 Tcl_SetVar(interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY); 1734 Tcl_SetVar(interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
1762 #endif 1735 #endif
1763 1736
1764 Tcl_SetChannelOption(interp, ch1, "-buffering", "line"); 1737 Tcl_SetChannelOption(interp, ch1, "-buffering", "line");
1738 #ifdef WIN3264
1739 Tcl_SetChannelOption(interp, ch1, "-translation", "lf");
1740 #endif
1765 Tcl_SetChannelOption(interp, ch2, "-buffering", "line"); 1741 Tcl_SetChannelOption(interp, ch2, "-buffering", "line");
1766 1742 #ifdef WIN3264
1767 /* replace some standard Tcl commands */ 1743 Tcl_SetChannelOption(interp, ch2, "-translation", "lf");
1744 #endif
1745
1746 /* replace standard Tcl exit command */
1768 Tcl_DeleteCommand(interp, "exit"); 1747 Tcl_DeleteCommand(interp, "exit");
1769 Tcl_CreateObjCommand(interp, "exit", exitcmd, 1748 Tcl_CreateObjCommand(interp, "exit", exitcmd,
1770 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1771 Tcl_DeleteCommand(interp, "catch");
1772 Tcl_CreateObjCommand(interp, "catch", catchcmd,
1773 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 1749 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1774 1750
1775 /* new commands, in ::vim namespace */ 1751 /* new commands, in ::vim namespace */
1776 Tcl_CreateObjCommand(interp, "::vim::buffer", buffercmd, 1752 Tcl_CreateObjCommand(interp, "::vim::buffer", buffercmd,
1777 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 1753 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
1820 /* Interpreter already exists, just update variables */ 1796 /* Interpreter already exists, just update variables */
1821 tclinfo.range_start = row2tcl(eap->line1); 1797 tclinfo.range_start = row2tcl(eap->line1);
1822 tclinfo.range_end = row2tcl(eap->line2); 1798 tclinfo.range_end = row2tcl(eap->line2);
1823 tclupdatevars(); 1799 tclupdatevars();
1824 } 1800 }
1801
1802 tclinfo.exitvalue = 0;
1825 return OK; 1803 return OK;
1826 } 1804 }
1827 1805
1828 static void 1806 static void
1829 tclerrmsg(text) 1807 tclerrmsg(text)
1883 tclexit(error) 1861 tclexit(error)
1884 int error; 1862 int error;
1885 { 1863 {
1886 int newerr = OK; 1864 int newerr = OK;
1887 1865
1888 if (error == TCL_EXIT ) 1866 if (Tcl_InterpDeleted(tclinfo.interp) /* True if we intercepted Tcl's exit command */
1889 { 1867 #if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
1890 int retval; 1868 || Tcl_LimitExceeded(tclinfo.interp) /* True if the interpreter cannot continue */
1869 #endif
1870 )
1871 {
1891 char buf[50]; 1872 char buf[50];
1892 Tcl_Obj *robj; 1873
1893 1874 sprintf(buf, _("E572: exit code %d"), tclinfo.exitvalue);
1894 robj = Tcl_GetObjResult(tclinfo.interp); 1875 tclerrmsg(buf);
1895 if( Tcl_GetIntFromObj(tclinfo.interp, robj, &retval) != TCL_OK ) 1876 if (tclinfo.exitvalue == 0)
1896 { 1877 {
1897 EMSG(_("E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org")); 1878 did_emsg = 0;
1898 newerr = FAIL; 1879 newerr = OK;
1899 } 1880 }
1900 else 1881 else
1901 { 1882 newerr = FAIL;
1902 sprintf(buf, _("E572: exit code %d"), retval);
1903 tclerrmsg(buf);
1904 if (retval == 0 )
1905 {
1906 did_emsg = 0;
1907 newerr = OK;
1908 }
1909 else
1910 newerr = FAIL;
1911 }
1912 1883
1913 tcldelthisinterp(); 1884 tcldelthisinterp();
1914 } 1885 }
1915 else 1886 else
1916 { 1887 {
2020 break; 1991 break;
2021 } 1992 }
2022 Tcl_SetVar(tclinfo.interp, var_line, line, 0); 1993 Tcl_SetVar(tclinfo.interp, var_line, line, 0);
2023 Tcl_AllowExceptions(tclinfo.interp); 1994 Tcl_AllowExceptions(tclinfo.interp);
2024 err = Tcl_Eval(tclinfo.interp, script); 1995 err = Tcl_Eval(tclinfo.interp, script);
2025 if (err != TCL_OK) 1996 if (err != TCL_OK
1997 || Tcl_InterpDeleted(tclinfo.interp)
1998 #if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8
1999 || Tcl_LimitExceeded(tclinfo.interp)
2000 #endif
2001 )
2026 break; 2002 break;
2027 line = (char *)Tcl_GetVar(tclinfo.interp, var_line, 0); 2003 line = (char *)Tcl_GetVar(tclinfo.interp, var_line, 0);
2028 if (line) 2004 if (line)
2029 { 2005 {
2030 if (ml_replace((linenr_T)rs, (char_u *)line, TRUE) != OK) 2006 if (ml_replace((linenr_T)rs, (char_u *)line, TRUE) != OK)