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 -- [email protected] -- 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    ///

-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

Raspunde prin e-mail lui