diff --git a/7.3.449 b/7.3.449 new file mode 100644 index 0000000..9b5bdea --- /dev/null +++ b/7.3.449 @@ -0,0 +1,455 @@ +To: vim_dev@googlegroups.com +Subject: Patch 7.3.449 +Fcc: outbox +From: Bram Moolenaar +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 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. +Files: src/buffer.c, src/proto/buffer.pro, src/ex_cmds.c, src/ex_getln.c, + src/misc2.c, src/quickfix.c, src/window.c, src/proto/window.pro + + +*** ../vim-7.3.448/src/buffer.c 2012-01-20 20:44:38.000000000 +0100 +--- src/buffer.c 2012-02-22 14:50:42.000000000 +0100 +*************** +*** 64,69 **** +--- 64,72 ---- + 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,102 **** + * 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); + for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) + if (curbuf->b_ml.ml_mfp != NULL) + break; +--- 99,105 ---- + * 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, FALSE); + for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next) + if (curbuf->b_ml.ml_mfp != NULL) + break; +*************** +*** 316,327 **** + * get a new buffer very soon! + * + * The 'bufhidden' option can force freeing and deleting. + */ + void +! close_buffer(win, buf, action) + win_T *win; /* if not NULL, set b_last_cursor */ + buf_T *buf; + int action; + { + #ifdef FEAT_AUTOCMD + int is_curbuf; +--- 319,335 ---- + * 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, 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,378 **** + { + apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, + FALSE, buf); +! if (!buf_valid(buf)) /* autocommands may delete the buffer */ + return; + + /* When the buffer becomes hidden, but is not unloaded, trigger + * BufHidden */ +--- 379,390 ---- + { + apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, + FALSE, buf); +! /* 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,387 **** + { + apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, + FALSE, buf); +! if (!buf_valid(buf)) /* autocmds may delete the buffer */ + return; + } + # ifdef FEAT_EVAL + if (aborting()) /* autocmds may abort script processing */ +--- 392,404 ---- + { + apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, + FALSE, buf); +! /* 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,781 **** + * 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); + if (!buf_valid(old_curbuf) || old_curbuf == curbuf) + old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); + if (old_curbuf != NULL) +--- 792,798 ---- + * 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, 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,1128 **** + * if the buffer still exists. + */ + if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) +! close_buffer(NULL, buf, action); + return retval; + } + +--- 1139,1145 ---- + * if the buffer still exists. + */ + if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) +! close_buffer(NULL, buf, action, FALSE); + return retval; + } + +*************** +*** 1146,1152 **** + close_windows(buf, FALSE); + #endif + if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) +! close_buffer(NULL, buf, action); + return OK; + } + +--- 1163,1169 ---- + close_windows(buf, FALSE); + #endif + if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) +! close_buffer(NULL, buf, action, FALSE); + return OK; + } + +*************** +*** 1378,1384 **** + close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, + unload ? action : (action == DOBUF_GOTO + && !P_HID(prevbuf) +! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0); + } + } + #ifdef FEAT_AUTOCMD +--- 1395,1401 ---- + close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, + unload ? action : (action == DOBUF_GOTO + && !P_HID(prevbuf) +! && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); + } + } + #ifdef FEAT_AUTOCMD +*************** +*** 2708,2714 **** + vim_free(ffname); + return FAIL; + } +! close_buffer(NULL, obuf, DOBUF_WIPE); /* delete from the list */ + } + sfname = vim_strsave(sfname); + if (ffname == NULL || sfname == NULL) +--- 2725,2732 ---- + vim_free(ffname); + return FAIL; + } +! /* delete from the list */ +! close_buffer(NULL, obuf, DOBUF_WIPE, FALSE); + } + sfname = vim_strsave(sfname); + if (ffname == NULL || sfname == NULL) +*************** +*** 5638,5644 **** + if (!aucmd) /* Don't trigger BufDelete autocommands here. */ + block_autocmds(); + #endif +! close_buffer(NULL, buf, DOBUF_WIPE); + #ifdef FEAT_AUTOCMD + if (!aucmd) + unblock_autocmds(); +--- 5656,5662 ---- + if (!aucmd) /* Don't trigger BufDelete autocommands here. */ + block_autocmds(); + #endif +! close_buffer(NULL, buf, DOBUF_WIPE, FALSE); + #ifdef FEAT_AUTOCMD + if (!aucmd) + unblock_autocmds(); +*** ../vim-7.3.448/src/proto/buffer.pro 2010-08-15 21:57:28.000000000 +0200 +--- src/proto/buffer.pro 2012-02-22 14:04:26.000000000 +0100 +*************** +*** 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 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)); +--- 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, 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)); +*** ../vim-7.3.448/src/ex_cmds.c 2011-12-30 15:01:55.000000000 +0100 +--- src/ex_cmds.c 2012-02-22 14:00:32.000000000 +0100 +*************** +*** 3387,3393 **** + /* close the link to the current buffer */ + u_sync(FALSE); + close_buffer(oldwin, curbuf, +! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD); + + #ifdef FEAT_AUTOCMD + /* Autocommands may open a new window and leave oldwin open +--- 3387,3393 ---- + /* close the link to the current buffer */ + u_sync(FALSE); + close_buffer(oldwin, curbuf, +! (flags & ECMD_HIDE) ? 0 : DOBUF_UNLOAD, FALSE); + + #ifdef FEAT_AUTOCMD + /* Autocommands may open a new window and leave oldwin open +*** ../vim-7.3.448/src/ex_getln.c 2012-02-04 22:44:27.000000000 +0100 +--- src/ex_getln.c 2012-02-22 14:01:56.000000000 +0100 +*************** +*** 6443,6449 **** + /* win_close() may have already wiped the buffer when 'bh' is + * set to 'wipe' */ + if (buf_valid(bp)) +! close_buffer(NULL, bp, DOBUF_WIPE); + + /* Restore window sizes. */ + win_size_restore(&winsizes); +--- 6443,6449 ---- + /* win_close() may have already wiped the buffer when 'bh' is + * set to 'wipe' */ + if (buf_valid(bp)) +! close_buffer(NULL, bp, DOBUF_WIPE, FALSE); + + /* Restore window sizes. */ + win_size_restore(&winsizes); +*** ../vim-7.3.448/src/misc2.c 2012-02-20 22:18:22.000000000 +0100 +--- src/misc2.c 2012-02-22 14:02:12.000000000 +0100 +*************** +*** 1173,1179 **** + for (buf = firstbuf; buf != NULL; ) + { + nextbuf = buf->b_next; +! close_buffer(NULL, buf, DOBUF_WIPE); + if (buf_valid(buf)) + buf = nextbuf; /* didn't work, try next one */ + else +--- 1173,1179 ---- + for (buf = firstbuf; buf != NULL; ) + { + nextbuf = buf->b_next; +! close_buffer(NULL, buf, DOBUF_WIPE, FALSE); + if (buf_valid(buf)) + buf = nextbuf; /* didn't work, try next one */ + else +*** ../vim-7.3.448/src/quickfix.c 2012-01-20 13:39:03.000000000 +0100 +--- src/quickfix.c 2012-02-22 14:02:20.000000000 +0100 +*************** +*** 3565,3571 **** + buf_T *buf; + { + if (curbuf != buf) /* safety check */ +! close_buffer(NULL, buf, DOBUF_UNLOAD); + } + + #if defined(FEAT_EVAL) || defined(PROTO) +--- 3565,3571 ---- + buf_T *buf; + { + if (curbuf != buf) /* safety check */ +! close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE); + } + + #if defined(FEAT_EVAL) || defined(PROTO) +*** ../vim-7.3.448/src/window.c 2012-01-10 22:26:12.000000000 +0100 +--- src/window.c 2012-02-22 14:08:13.000000000 +0100 +*************** +*** 23,29 **** + 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)); +--- 23,28 ---- +*************** +*** 2083,2089 **** + * Return TRUE if there is only one window other than "aucmd_win" in the + * current tab page. + */ +! static int + one_window() + { + #ifdef FEAT_AUTOCMD +--- 2082,2088 ---- + * Return TRUE if there is only one window other than "aucmd_win" in the + * current tab page. + */ +! int + one_window() + { + #ifdef FEAT_AUTOCMD +*************** +*** 2109,2115 **** + * 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() + */ + void + win_close(win, free_buf) +--- 2108,2114 ---- + * 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(). + */ + void + win_close(win, free_buf) +*************** +*** 2222,2228 **** + * Close the link to the buffer. + */ + if (win->w_buffer != NULL) +! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); + + /* Autocommands may have closed the window already, or closed the only + * other window or moved to another tab page. */ +--- 2221,2227 ---- + * Close the link to the buffer. + */ + if (win->w_buffer != NULL) +! 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,2334 **** + int free_tp = FALSE; + + /* Close the link to the buffer. */ +! close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); + + /* Careful: Autocommands may have closed the tab page or made it the + * current tab page. */ +--- 2327,2333 ---- + int free_tp = FALSE; + + /* Close the link to the buffer. */ +! 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. */ +*** ../vim-7.3.448/src/proto/window.pro 2010-08-15 21:57:28.000000000 +0200 +--- src/proto/window.pro 2012-02-22 14:08:28.000000000 +0100 +*************** +*** 1,13 **** + /* 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_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)); + 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)); +--- 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 *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)); +*** ../vim-7.3.448/src/version.c 2012-02-22 13:07:02.000000000 +0100 +--- src/version.c 2012-02-22 14:55:21.000000000 +0100 +*************** +*** 716,717 **** +--- 716,719 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 449, + /**/ + +-- +From "know your smileys": + :-)-O Smiling doctor with stethoscope + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org ///