Mercurial > hg > RemoteEditor > vim7
diff 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 |
line wrap: on
line diff
--- a/src/if_tcl.c Wed Aug 01 18:03:06 2012 +0900 +++ b/src/if_tcl.c Wed Aug 01 18:08:28 2012 +0900 @@ -74,18 +74,18 @@ #endif #include <tcl.h> -#include <errno.h> #include <string.h> 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)" @@ -280,16 +280,19 @@ ****************************************************************************/ /* - * 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; @@ -306,51 +309,16 @@ break; /* FALLTHROUGH */ case 1: - Tcl_SetObjResult(interp, Tcl_NewIntObj(value)); - return TCL_EXIT; + tclinfo.exitvalue = value; + + Tcl_DeleteInterp(interp); + break; default: Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); } return TCL_ERROR; } - 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; - default: - Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?"); - } - return TCL_ERROR; -} - /* * "::vim::beep" - what Vi[m] does best :-) */ @@ -373,6 +341,7 @@ /* * "::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 @@ -1664,7 +1633,7 @@ static Tcl_ChannelType channel_type = { "vimmessage", /* typeName */ - NULL, /* version */ + TCL_CHANNEL_VERSION_2, /* version */ channel_close, /* closeProc */ channel_input, /* inputProc */ channel_output, /* outputProc */ @@ -1679,6 +1648,8 @@ 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 @@ -1742,7 +1713,9 @@ 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); @@ -1762,15 +1735,18 @@ #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, @@ -1822,6 +1798,8 @@ tclinfo.range_end = row2tcl(eap->line2); tclupdatevars(); } + + tclinfo.exitvalue = 0; return OK; } @@ -1885,30 +1863,23 @@ { 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(); } @@ -2022,7 +1993,12 @@ 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)