summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Make_mvc.mak2
-rw-r--r--src/if_tcl.c123
-rw-r--r--src/version.c2
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,