Compare commits

...

3 Commits

Author SHA1 Message Date
Bram Moolenaar
84a4c334e1 updated for version 7.3.451
Problem:    Tcl doesn't work on 64 MS-Windows.
Solution:   Make it work. (Dave Bodenstab)
2012-02-22 16:01:56 +01:00
Bram Moolenaar
ee7d100091 updated for version 7.3.450
Problem:    Win32: Still a problem with "!start /b".
Solution:   Fix pointer use. (Yasuhiro Matsumoto)
2012-02-22 15:34:08 +01:00
Bram Moolenaar
42ec656524 updated for version 7.3.449
Problem:    Crash when a BufWinLeave autocommand closes the only other window.
            (Daniel Hunt)
Solution:   Abort closing a buffer when it becomes the only one.
2012-02-22 14:58:37 +01:00
12 changed files with 102 additions and 99 deletions

View File

@@ -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

View File

@@ -64,6 +64,9 @@ static void buf_delete_signs __ARGS((buf_T *buf));
static char *msg_loclist = N_("[Location List]");
static char *msg_qflist = N_("[Quickfix List]");
#endif
#ifdef FEAT_AUTOCMD
static char *e_auabort = N_("E855: Autocommands caused command to abort");
#endif
/*
* Open current buffer, that is: open the memfile and read the file into
@@ -96,7 +99,7 @@ open_buffer(read_stdin, eap, flags)
* There MUST be a memfile, otherwise we can't do anything
* If we can't create one for the current buffer, take another buffer
*/
close_buffer(NULL, curbuf, 0);
close_buffer(NULL, curbuf, 0, FALSE);
for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
if (curbuf->b_ml.ml_mfp != NULL)
break;
@@ -316,12 +319,17 @@ buf_valid(buf)
* get a new buffer very soon!
*
* The 'bufhidden' option can force freeing and deleting.
*
* When "abort_if_last" is TRUE then do not close the buffer if autocommands
* cause there to be only one window with this buffer. e.g. when ":quit" is
* supposed to close the window but autocommands close all other windows.
*/
void
close_buffer(win, buf, action)
close_buffer(win, buf, action, abort_if_last)
win_T *win; /* if not NULL, set b_last_cursor */
buf_T *buf;
int action;
int abort_if_last;
{
#ifdef FEAT_AUTOCMD
int is_curbuf;
@@ -371,8 +379,12 @@ close_buffer(win, buf, action)
{
apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf);
if (!buf_valid(buf)) /* autocommands may delete the buffer */
/* Return if autocommands deleted the buffer or made it the only one. */
if (!buf_valid(buf) || (abort_if_last && one_window()))
{
EMSG(_(e_auabort));
return;
}
/* When the buffer becomes hidden, but is not unloaded, trigger
* BufHidden */
@@ -380,8 +392,13 @@ close_buffer(win, buf, action)
{
apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf);
if (!buf_valid(buf)) /* autocmds may delete the buffer */
/* Return if autocommands deleted the buffer or made it the only
* one. */
if (!buf_valid(buf) || (abort_if_last && one_window()))
{
EMSG(_(e_auabort));
return;
}
}
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
@@ -775,7 +792,7 @@ handle_swap_exists(old_curbuf)
* open a new, empty buffer. */
swap_exists_action = SEA_NONE; /* don't want it again */
swap_exists_did_quit = TRUE;
close_buffer(curwin, curbuf, DOBUF_UNLOAD);
close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
if (old_curbuf != NULL)
@@ -1122,7 +1139,7 @@ do_buffer(action, start, dir, count, forceit)
* if the buffer still exists.
*/
if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
close_buffer(NULL, buf, action);
close_buffer(NULL, buf, action, FALSE);
return retval;
}
@@ -1146,7 +1163,7 @@ do_buffer(action, start, dir, count, forceit)
close_windows(buf, FALSE);
#endif
if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
close_buffer(NULL, buf, action);
close_buffer(NULL, buf, action, FALSE);
return OK;
}
@@ -1378,7 +1395,7 @@ set_curbuf(buf, action)
close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
unload ? action : (action == DOBUF_GOTO
&& !P_HID(prevbuf)
&& !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0);
&& !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
}
}
#ifdef FEAT_AUTOCMD
@@ -2708,7 +2725,8 @@ setfname(buf, ffname, sfname, message)
vim_free(ffname);
return FAIL;
}
close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */
/* delete from the list */
close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
}
sfname = vim_strsave(sfname);
if (ffname == NULL || sfname == NULL)
@@ -5638,7 +5656,7 @@ wipe_buffer(buf, aucmd)
if (!aucmd) /* Don't trigger BufDelete autocommands here. */
block_autocmds();
#endif
close_buffer(NULL, buf, DOBUF_WIPE);
close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
#ifdef FEAT_AUTOCMD
if (!aucmd)
unblock_autocmds();

View File

@@ -3387,7 +3387,7 @@ do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin)
/* close the link to the current buffer */
u_sync(FALSE);
close_buffer(oldwin, curbuf,
(flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD);
(flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE);
#ifdef FEAT_AUTOCMD
/* Autocommands may open a new window and leave oldwin open

View File

@@ -6443,7 +6443,7 @@ ex_window()
/* win_close() may have already wiped the buffer when 'bh' is
* set to 'wipe' */
if (buf_valid(bp))
close_buffer(NULL, bp, DOBUF_WIPE);
close_buffer(NULL, bp, DOBUF_WIPE, FALSE);
/* Restore window sizes. */
win_size_restore(&winsizes);

View File

@@ -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,51 +309,16 @@ exitcmd(dummy, interp, objc, objv)
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 :-)
*/
@@ -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)

View File

@@ -1173,7 +1173,7 @@ free_all_mem()
for (buf = firstbuf; buf != NULL; )
{
nextbuf = buf->b_next;
close_buffer(NULL, buf, DOBUF_WIPE);
close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
if (buf_valid(buf))
buf = nextbuf; /* didn't work, try next one */
else

View File

@@ -4008,21 +4008,23 @@ mch_call_shell(
if (flags != CREATE_NEW_CONSOLE)
{
char_u *subcmd;
char_u *cmd_shell = default_shell();
char_u *cmd_shell = mch_getenv("COMSPEC");
if (cmd_shell == NULL || *cmd_shell == NUL)
cmd_shell = default_shell();
subcmd = vim_strsave_escaped_ext(cmdbase, "|", '^', FALSE);
if (subcmd != NULL)
{
/* make "cmd.exe /c arguments" */
cmdlen = STRLEN(cmd_shell) + STRLEN(subcmd) + 5;
vim_free(subcmd);
newcmd = lalloc(cmdlen, TRUE);
if (newcmd != NULL)
vim_snprintf((char *)newcmd, cmdlen, "%s /c %s",
default_shell, subcmd);
cmd_shell, subcmd);
else
newcmd = cmdbase;
vim_free(subcmd);
}
}

View File

@@ -1,7 +1,7 @@
/* buffer.c */
int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags));
int buf_valid __ARGS((buf_T *buf));
void close_buffer __ARGS((win_T *win, buf_T *buf, int action));
void close_buffer __ARGS((win_T *win, buf_T *buf, int action, int abort_if_last));
void buf_clear_file __ARGS((buf_T *buf));
void buf_freeall __ARGS((buf_T *buf, int flags));
void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count));

View File

@@ -1,13 +1,14 @@
/* window.c */
void do_window __ARGS((int nchar, long Prenum, int xchar));
int win_split __ARGS((int size, int flags));
int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir));
int win_valid __ARGS((win_T *win));
int win_count __ARGS((void));
int make_windows __ARGS((int count, int vertical));
void win_move_after __ARGS((win_T *win1, win_T *win2));
void win_equal __ARGS((win_T *next_curwin, int current, int dir));
void close_windows __ARGS((buf_T *buf, int keep_curwin));
int one_window __ARGS((void));
void win_close __ARGS((win_T *win, int free_buf));
void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp));
void win_free_all __ARGS((void));

View File

@@ -3565,7 +3565,7 @@ unload_dummy_buffer(buf)
buf_T *buf;
{
if (curbuf != buf) /* safety check */
close_buffer(NULL, buf, DOBUF_UNLOAD);
close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE);
}
#if defined(FEAT_EVAL) || defined(PROTO)

View File

@@ -714,6 +714,12 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
451,
/**/
450,
/**/
449,
/**/
448,
/**/

View File

@@ -23,7 +23,6 @@ static void win_rotate __ARGS((int, int));
static void win_totop __ARGS((int size, int flags));
static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height));
static int last_window __ARGS((void));
static int one_window __ARGS((void));
static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
static tabpage_T *alt_tabpage __ARGS((void));
@@ -2083,7 +2082,7 @@ last_window()
* Return TRUE if there is only one window other than "aucmd_win" in the
* current tab page.
*/
static int
int
one_window()
{
#ifdef FEAT_AUTOCMD
@@ -2109,7 +2108,7 @@ one_window()
* Close window "win". Only works for the current tab page.
* If "free_buf" is TRUE related buffer may be unloaded.
*
* called by :quit, :close, :xit, :wq and findtag()
* Called by :quit, :close, :xit, :wq and findtag().
*/
void
win_close(win, free_buf)
@@ -2222,7 +2221,7 @@ win_close(win, free_buf)
* Close the link to the buffer.
*/
if (win->w_buffer != NULL)
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
/* Autocommands may have closed the window already, or closed the only
* other window or moved to another tab page. */
@@ -2328,7 +2327,7 @@ win_close_othertab(win, free_buf, tp)
int free_tp = FALSE;
/* Close the link to the buffer. */
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
/* Careful: Autocommands may have closed the tab page or made it the
* current tab page. */