diff options
-rw-r--r-- | src/Make_mvc.mak | 2 | ||||
-rw-r--r-- | src/if_tcl.c | 123 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 53 insertions, 74 deletions
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index c6a8e3158..092e2b571 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -616,7 +616,7 @@ CFLAGS = $(CFLAGS) -DFEAT_TCL -DDYNAMIC_TCL -DDYNAMIC_TCL_DLL=\"$(TCL_DLL)\" \ -DDYNAMIC_TCL_VER=\"$(TCL_VER_LONG)\" TCL_OBJ = $(OUTDIR)\if_tcl.obj TCL_INC = /I "$(TCL)\Include" /I "$(TCL)" -TCL_LIB = $(TCL)\lib\tclstub$(TCL_VER).lib +TCL_LIB = "$(TCL)\lib\tclstub$(TCL_VER).lib" !else CFLAGS = $(CFLAGS) -DFEAT_TCL TCL_OBJ = $(OUTDIR)\if_tcl.obj diff --git a/src/if_tcl.c b/src/if_tcl.c index 5537b6356..36ff32063 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -79,12 +79,13 @@ TODO: typedef struct { Tcl_Interp *interp; + int exitvalue; int range_start, range_end; int lbase; char *curbuf, *curwin; } tcl_info; -static tcl_info tclinfo = { NULL, 0, 0, 0, NULL, NULL }; +static tcl_info tclinfo = { NULL, 0, 0, 0, 0, NULL, NULL }; #define VAR_RANGE1 "::vim::range(start)" #define VAR_RANGE2 "::vim::range(begin)" @@ -279,16 +280,19 @@ tcl_end() ****************************************************************************/ /* - * Replace standard "exit" and "catch" commands. + * Replace standard "exit" command. * - * This is a design flaw in Tcl - the standard "exit" command just calls - * exit() and kills the application. It should return TCL_EXIT to the - * app, which then decides if it wants to terminate or not. In our case, - * we just delete the Tcl interpreter (and create a new one with the next - * :tcl command). + * Delete the Tcl interpreter; a new one will be created with the next + * :tcl command). The exit code is saved (and retrieved in tclexit()). + * Since Tcl's exit is never expected to return and this replacement + * does, then (except for a trivial case) additional Tcl commands will + * be run. Since the interpreter is now marked as deleted, an error + * will be returned -- typically "attempt to call eval in deleted + * interpreter". Hopefully, at this point, checks for TCL_ERROR take + * place and control percolates back up to Vim -- but with this new error + * string in the interpreter's result value. Therefore it would be + * useless for this routine to return the exit code via Tcl_SetResult(). */ -#define TCL_EXIT 5 - static int exitcmd(dummy, interp, objc, objv) ClientData dummy UNUSED; @@ -305,47 +309,12 @@ exitcmd(dummy, interp, objc, objv) break; /* FALLTHROUGH */ case 1: - Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); - return TCL_EXIT; - default: - Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); - } - return TCL_ERROR; -} + tclinfo.exitvalue = value; - static int -catchcmd(dummy, interp, objc, objv) - ClientData dummy UNUSED; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -{ - char *varname = NULL; - int result; - - switch (objc) - { - case 3: - varname = Tcl_GetStringFromObj(objv[2], NULL); - /* fallthrough */ - case 2: - Tcl_ResetResult(interp); - Tcl_AllowExceptions(interp); - result = Tcl_EvalObj(interp, objv[1]); - if (result == TCL_EXIT) - return result; - if (varname) - { - if (Tcl_SetVar(interp, varname, Tcl_GetStringResult(interp), 0) == NULL) - { - Tcl_SetResult(interp, "couldn't save command result in variable", TCL_STATIC); - return TCL_ERROR; - } - } - Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); - return TCL_OK; + Tcl_DeleteInterp(interp); + break; default: - Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?"); + Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); } return TCL_ERROR; } @@ -372,6 +341,7 @@ beepcmd(dummy, interp, objc, objv) /* * "::vim::buffer list" - create a list of buffer commands. * "::vim::buffer {N}" - create buffer command for buffer N. + * "::vim::buffer exists {N}" - test if buffer N exists. * "::vim::buffer new" - create a new buffer (not implemented) */ static int @@ -1663,7 +1633,7 @@ channel_gethandle(instance, direction, handleptr) static Tcl_ChannelType channel_type = { "vimmessage", /* typeName */ - NULL, /* version */ + TCL_CHANNEL_VERSION_2, /* version */ channel_close, /* closeProc */ channel_input, /* inputProc */ channel_output, /* outputProc */ @@ -1678,6 +1648,8 @@ static Tcl_ChannelType channel_type = NULL, /* flushProc */ NULL, /* handlerProc */ #endif +/* The following should not be necessary since TCL_CHANNEL_VERSION_2 was + * set above */ #ifdef TCL_CHANNEL_VERSION_3 NULL, /* wideSeekProc */ #endif @@ -1741,7 +1713,9 @@ tclinit(eap) Tcl_Interp *interp; static Tcl_Channel ch1, ch2; - /* replace stdout and stderr */ + /* Create replacement channels for stdout and stderr; this has to be + * done each time an interpreter is created since the channels are closed + * when the interpreter is deleted */ ch1 = Tcl_CreateChannel(&channel_type, "vimout", VIMOUT, TCL_WRITABLE); ch2 = Tcl_CreateChannel(&channel_type, "vimerr", VIMERR, TCL_WRITABLE); Tcl_SetStdChannel(ch1, TCL_STDOUT); @@ -1761,15 +1735,18 @@ tclinit(eap) #endif Tcl_SetChannelOption(interp, ch1, "-buffering", "line"); +#ifdef WIN3264 + Tcl_SetChannelOption(interp, ch1, "-translation", "lf"); +#endif Tcl_SetChannelOption(interp, ch2, "-buffering", "line"); +#ifdef WIN3264 + Tcl_SetChannelOption(interp, ch2, "-translation", "lf"); +#endif - /* replace some standard Tcl commands */ + /* replace standard Tcl exit command */ Tcl_DeleteCommand(interp, "exit"); Tcl_CreateObjCommand(interp, "exit", exitcmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_DeleteCommand(interp, "catch"); - Tcl_CreateObjCommand(interp, "catch", catchcmd, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); /* new commands, in ::vim namespace */ Tcl_CreateObjCommand(interp, "::vim::buffer", buffercmd, @@ -1821,6 +1798,8 @@ tclinit(eap) tclinfo.range_end = row2tcl(eap->line2); tclupdatevars(); } + + tclinfo.exitvalue = 0; return OK; } @@ -1884,30 +1863,23 @@ tclexit(error) { int newerr = OK; - if (error == TCL_EXIT) + if (Tcl_InterpDeleted(tclinfo.interp) /* True if we intercepted Tcl's exit command */ +#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8 + || Tcl_LimitExceeded(tclinfo.interp) /* True if the interpreter cannot continue */ +#endif + ) { - int retval; char buf[50]; - Tcl_Obj *robj; - robj = Tcl_GetObjResult(tclinfo.interp); - if (Tcl_GetIntFromObj(tclinfo.interp, robj, &retval) != TCL_OK) + sprintf(buf, _("E572: exit code %d"), tclinfo.exitvalue); + tclerrmsg(buf); + if (tclinfo.exitvalue == 0) { - EMSG(_("E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org")); - newerr = FAIL; + did_emsg = 0; + newerr = OK; } else - { - sprintf(buf, _("E572: exit code %d"), retval); - tclerrmsg(buf); - if (retval == 0) - { - did_emsg = 0; - newerr = OK; - } - else - newerr = FAIL; - } + newerr = FAIL; tcldelthisinterp(); } @@ -2021,7 +1993,12 @@ ex_tcldo(eap) Tcl_SetVar(tclinfo.interp, var_line, line, 0); Tcl_AllowExceptions(tclinfo.interp); err = Tcl_Eval(tclinfo.interp, script); - if (err != TCL_OK) + if (err != TCL_OK + || Tcl_InterpDeleted(tclinfo.interp) +#if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5) || TCL_MAJOR_VERSION > 8 + || Tcl_LimitExceeded(tclinfo.interp) +#endif + ) break; line = (char *)Tcl_GetVar(tclinfo.interp, var_line, 0); if (line) diff --git a/src/version.c b/src/version.c index 119ad4876..f9da5db7a 100644 --- a/src/version.c +++ b/src/version.c @@ -715,6 +715,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 451, +/**/ 450, /**/ 449, |