Loading ...
Sorry, an error occurred while loading the content.

Patch 6.3.040

Expand Messages
  • Bram Moolenaar
    Patch 6.3.040 Problem: Error handling does not always work properly and may cause a buffer to be marked as if it s viewed in a window while it isn t. Also
    Message 1 of 1 , Dec 5, 2004
    • 0 Attachment
      Patch 6.3.040
      Problem: Error handling does not always work properly and may cause a
      buffer to be marked as if it's viewed in a window while it isn't.
      Also when selecting "Abort" at the attention prompt.
      Solution: Add enter_cleanup() and leave_cleanup() functions to move
      saving/restoring things for error handling to one place.
      Clear a buffer read error when it's unloaded.
      Files: src/buffer.c, src/ex_docmd.c, src/ex_eval.c,
      src/proto/ex_eval.pro, src/structs.h, src/vim.h


      *** ../vim-6.3.039/src/buffer.c Wed Jun 9 14:56:27 2004
      --- src/buffer.c Sun Dec 5 16:15:05 2004
      ***************
      *** 408,415 ****
      if (!buf_valid(buf))
      return;
      # ifdef FEAT_EVAL
      ! /* Autocommands may abort script processing. */
      ! if (aborting())
      return;
      # endif

      --- 408,414 ----
      if (!buf_valid(buf))
      return;
      # ifdef FEAT_EVAL
      ! if (aborting()) /* autocmds may abort script processing */
      return;
      # endif

      ***************
      *** 564,569 ****
      --- 563,569 ----
      #ifdef FEAT_SYN_HL
      syntax_clear(buf); /* reset syntax info */
      #endif
      + buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
      }

      /*
      ***************
      *** 666,674 ****
      --- 666,688 ----
      && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
      if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + cleanup_T cs;
      +
      + /* Reset the error/interrupt/exception state here so that
      + * aborting() returns FALSE when closing a window. */
      + enter_cleanup(&cs);
      + # endif
      +
      /* Quitting means closing the split window, nothing else. */
      win_close(curwin, TRUE);
      swap_exists_action = SEA_NONE;
      +
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Restore the error/interrupt/exception state if not discarded by a
      + * new aborting error, interrupt, or uncaught exception. */
      + leave_cleanup(&cs);
      + # endif
      }
      else
      handle_swap_exists(old_curbuf);
      ***************
      *** 685,712 ****
      handle_swap_exists(old_curbuf)
      buf_T *old_curbuf;
      {
      if (swap_exists_action == SEA_QUIT)
      {
      /* User selected Quit at ATTENTION prompt. Go back to previous
      * buffer. If that buffer is gone or the same as the current one,
      * open a new, empty buffer. */
      swap_exists_action = SEA_NONE; /* don't want it again */
      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 | BLN_FORCE);
      if (old_curbuf != NULL)
      enter_buffer(old_curbuf);
      /* If "old_curbuf" is NULL we are in big trouble here... */
      }
      else if (swap_exists_action == SEA_RECOVER)
      {
      /* User selected Recover at ATTENTION prompt. */
      msg_scroll = TRUE;
      ml_recover();
      MSG_PUTS("\n"); /* don't overwrite the last message */
      cmdline_row = msg_row;
      do_modelines();
      }
      swap_exists_action = SEA_NONE;
      }
      --- 699,753 ----
      handle_swap_exists(old_curbuf)
      buf_T *old_curbuf;
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + cleanup_T cs;
      + # endif
      +
      if (swap_exists_action == SEA_QUIT)
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Reset the error/interrupt/exception state here so that
      + * aborting() returns FALSE when closing a buffer. */
      + enter_cleanup(&cs);
      + # endif
      +
      /* User selected Quit at ATTENTION prompt. Go back to previous
      * buffer. If that buffer is gone or the same as the current one,
      * open a new, empty buffer. */
      swap_exists_action = SEA_NONE; /* don't want it again */
      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)
      enter_buffer(old_curbuf);
      /* If "old_curbuf" is NULL we are in big trouble here... */
      +
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Restore the error/interrupt/exception state if not discarded by a
      + * new aborting error, interrupt, or uncaught exception. */
      + leave_cleanup(&cs);
      + # endif
      }
      else if (swap_exists_action == SEA_RECOVER)
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Reset the error/interrupt/exception state here so that
      + * aborting() returns FALSE when closing a buffer. */
      + enter_cleanup(&cs);
      + # endif
      +
      /* User selected Recover at ATTENTION prompt. */
      msg_scroll = TRUE;
      ml_recover();
      MSG_PUTS("\n"); /* don't overwrite the last message */
      cmdline_row = msg_row;
      do_modelines();
      +
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Restore the error/interrupt/exception state if not discarded by a
      + * new aborting error, interrupt, or uncaught exception. */
      + leave_cleanup(&cs);
      + # endif
      }
      swap_exists_action = SEA_NONE;
      }
      ***************
      *** 1380,1386 ****
      * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
      * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
      * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
      - * If (flags & BLN_FORCE) is TRUE, don't abort on an error.
      * This is the ONLY way to create a new buffer.
      */
      static int top_file_num = 1; /* highest file number */
      --- 1421,1426 ----
      ***************
      *** 1455,1462 ****
      if (buf == curbuf)
      apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
      # ifdef FEAT_EVAL
      ! /* autocmds may abort script processing */
      ! if (!(flags & BLN_FORCE) && aborting())
      return NULL;
      # endif
      #endif
      --- 1495,1501 ----
      if (buf == curbuf)
      apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
      # ifdef FEAT_EVAL
      ! if (aborting()) /* autocmds may abort script processing */
      return NULL;
      # endif
      #endif
      ***************
      *** 1509,1516 ****
      if (buf != curbuf) /* autocommands deleted the buffer! */
      return NULL;
      #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      ! /* autocmds may abort script processing */
      ! if (!(flags & BLN_FORCE) && aborting())
      return NULL;
      #endif
      /* buf->b_nwindows = 0; why was this here? */
      --- 1548,1554 ----
      if (buf != curbuf) /* autocommands deleted the buffer! */
      return NULL;
      #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      ! if (aborting()) /* autocmds may abort script processing */
      return NULL;
      #endif
      /* buf->b_nwindows = 0; why was this here? */
      ***************
      *** 1586,1593 ****
      if (flags & BLN_LISTED)
      apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
      # ifdef FEAT_EVAL
      ! /* autocmds may abort script processing */
      ! if (!(flags & BLN_FORCE) && aborting())
      return NULL;
      # endif
      }
      --- 1624,1630 ----
      if (flags & BLN_LISTED)
      apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
      # ifdef FEAT_EVAL
      ! if (aborting()) /* autocmds may abort script processing */
      return NULL;
      # endif
      }
      ***************
      *** 4217,4229 ****
      #endif
      set_curbuf(buf, DOBUF_GOTO);
      #ifdef FEAT_AUTOCMD
      - # ifdef FEAT_EVAL
      - /* Autocommands deleted the buffer or aborted script
      - * processing!!! */
      - if (!buf_valid(buf) || aborting())
      - # else
      if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
      - # endif
      {
      #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
      swap_exists_action = SEA_NONE;
      --- 4254,4260 ----
      ***************
      *** 4234,4243 ****
      --- 4265,4289 ----
      #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
      if (swap_exists_action == SEA_QUIT)
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + cleanup_T cs;
      +
      + /* Reset the error/interrupt/exception state here so that
      + * aborting() returns FALSE when closing a window. */
      + enter_cleanup(&cs);
      + # endif
      +
      /* User selected Quit at ATTENTION prompt; close this window. */
      win_close(curwin, TRUE);
      --open_wins;
      swap_exists_action = SEA_NONE;
      +
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Restore the error/interrupt/exception state if not
      + * discarded by a new aborting error, interrupt, or uncaught
      + * exception. */
      + leave_cleanup(&cs);
      + # endif
      }
      else
      handle_swap_exists(NULL);
      ***************
      *** 4250,4255 ****
      --- 4296,4306 ----
      (void)vgetc(); /* only break the file loading, not the rest */
      break;
      }
      + #ifdef FEAT_EVAL
      + /* Autocommands deleted the buffer or aborted script processing!!! */
      + if (aborting())
      + break;
      + #endif
      }
      #ifdef FEAT_AUTOCMD
      --autocmd_no_enter;
      *** ../vim-6.3.039/src/ex_docmd.c Wed Jun 9 14:59:11 2004
      --- src/ex_docmd.c Sun Dec 5 15:24:08 2004
      ***************
      *** 6610,6619 ****
      --- 6610,6633 ----
      need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1);
      if (!need_hide || P_HID(curbuf))
      {
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + cleanup_T cs;
      +
      + /* Reset the error/interrupt/exception state here so that
      + * aborting() returns FALSE when closing a window. */
      + enter_cleanup(&cs);
      + # endif
      # ifdef FEAT_GUI
      need_mouse_correct = TRUE;
      # endif
      win_close(curwin, !need_hide && !P_HID(curbuf));
      +
      + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
      + /* Restore the error/interrupt/exception state if not
      + * discarded by a new aborting error, interrupt, or
      + * uncaught exception. */
      + leave_cleanup(&cs);
      + # endif
      }
      }
      #endif
      *** ../vim-6.3.039/src/ex_eval.c Wed Jun 9 14:56:26 2004
      --- src/ex_eval.c Sun Dec 5 15:25:04 2004
      ***************
      *** 1820,1825 ****
      --- 1820,1979 ----
      }

      /*
      + * enter_cleanup() and leave_cleanup()
      + *
      + * Functions to be called before/after invoking a sequence of autocommands for
      + * cleanup for a failed command. (Failure means here that a call to emsg()
      + * has been made, an interrupt occurred, or there is an uncaught exception
      + * from a previous autocommand execution of the same command.)
      + *
      + * Call enter_cleanup() with a pointer to a cleanup_T and pass the same
      + * pointer to leave_cleanup(). The cleanup_T structure stores the pending
      + * error/interrupt/exception state.
      + */
      +
      + /*
      + * This function works a bit like ex_finally() except that there was not
      + * actually an extra try block around the part that failed and an error or
      + * interrupt has not (yet) been converted to an exception. This function
      + * saves the error/interrupt/ exception state and prepares for the call to
      + * do_cmdline() that is going to be made for the cleanup autocommand
      + * execution.
      + */
      + void
      + enter_cleanup(csp)
      + cleanup_T *csp;
      + {
      + int pending = CSTP_NONE;
      +
      + /*
      + * Postpone did_emsg, got_int, did_throw. The pending values will be
      + * restored by leave_cleanup() except if there was an aborting error,
      + * interrupt, or uncaught exception after this function ends.
      + */
      + if (did_emsg || got_int || did_throw || need_rethrow)
      + {
      + csp->pending = (did_emsg ? CSTP_ERROR : 0)
      + | (got_int ? CSTP_INTERRUPT : 0)
      + | (did_throw ? CSTP_THROW : 0)
      + | (need_rethrow ? CSTP_THROW : 0);
      +
      + /* If we are currently throwing an exception (did_throw), save it as
      + * well. On an error not yet converted to an exception, update
      + * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
      + * This is needed for the do_cmdline() call that is going to be made
      + * for autocommand execution. We need not save *msg_list because
      + * there is an extra instance for every call of do_cmdline(), anyway.
      + */
      + if (did_throw || need_rethrow)
      + csp->exception = current_exception;
      + else
      + {
      + csp->exception = NULL;
      + if (did_emsg)
      + {
      + force_abort |= cause_abort;
      + cause_abort = FALSE;
      + }
      + }
      + did_emsg = got_int = did_throw = need_rethrow = FALSE;
      +
      + /* Report if required by the 'verbose' option or when debugging. */
      + report_make_pending(pending, csp->exception);
      + }
      + else
      + {
      + csp->pending = CSTP_NONE;
      + csp->exception = NULL;
      + }
      + }
      +
      + /*
      + * See comment above enter_cleanup() for how this function is used.
      + *
      + * This function is a bit like ex_endtry() except that there was not actually
      + * an extra try block around the part that failed and an error or interrupt
      + * had not (yet) been converted to an exception when the cleanup autocommand
      + * sequence was invoked.
      + *
      + * This function has to be called with the address of the cleanup_T structure
      + * filled by enter_cleanup() as an argument; it restores the error/interrupt/
      + * exception state saved by that function - except there was an aborting
      + * error, an interrupt or an uncaught exception during execution of the
      + * cleanup autocommands. In the latter case, the saved error/interrupt/
      + * exception state is discarded.
      + */
      + void
      + leave_cleanup(csp)
      + cleanup_T *csp;
      + {
      + int pending = csp->pending;
      +
      + if (pending == CSTP_NONE) /* nothing to do */
      + return;
      +
      + /* If there was an aborting error, an interrupt, or an uncaught exception
      + * after the corresponding call to enter_cleanup(), discard what has been
      + * made pending by it. Report this to the user if required by the
      + * 'verbose' option or when debugging. */
      + if (aborting() || need_rethrow)
      + {
      + if (pending & CSTP_THROW)
      + /* Cancel the pending exception (includes report). */
      + discard_exception((except_T *)csp->exception, FALSE);
      + else
      + report_discard_pending(pending, NULL);
      +
      + /* If an error was about to be converted to an exception when
      + * enter_cleanup() was called, free the message list. */
      + free_msglist(*msg_list);
      + *msg_list = NULL;
      + }
      +
      + /*
      + * If there was no new error, interrupt, or throw between the calls
      + * to enter_cleanup() and leave_cleanup(), restore the pending
      + * error/interrupt/exception state.
      + */
      + else
      + {
      + /*
      + * If there was an exception being thrown when enter_cleanup() was
      + * called, we need to rethrow it. Make it the exception currently
      + * being thrown.
      + */
      + if (pending & CSTP_THROW)
      + current_exception = csp->exception;
      +
      + /*
      + * If an error was about to be converted to an exception when
      + * enter_cleanup() was called, let "cause_abort" take the part of
      + * "force_abort" (as done by cause_errthrow()).
      + */
      + else if (pending & CSTP_ERROR)
      + {
      + cause_abort = force_abort;
      + force_abort = FALSE;
      + }
      +
      + /*
      + * Restore the pending values of did_emsg, got_int, and did_throw.
      + */
      + if (pending & CSTP_ERROR)
      + did_emsg = TRUE;
      + if (pending & CSTP_INTERRUPT)
      + got_int = TRUE;
      + if (pending & CSTP_THROW)
      + need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
      +
      + /* Report if required by the 'verbose' option or when debugging. */
      + report_resume_pending(pending,
      + (pending & CSTP_THROW) ? (void *)current_exception : NULL);
      + }
      + }
      +
      +
      + /*
      * Make conditionals inactive and discard what's pending in finally clauses
      * until the conditional type searched for or a try conditional not in its
      * finally clause is reached. If this is in an active catch clause, finish the
      *** ../vim-6.3.039/src/proto/ex_eval.pro Wed Jun 9 14:56:24 2004
      --- src/proto/ex_eval.pro Sun Dec 5 15:25:27 2004
      ***************
      *** 23,28 ****
      --- 23,30 ----
      void ex_catch __ARGS((exarg_T *eap));
      void ex_finally __ARGS((exarg_T *eap));
      void ex_endtry __ARGS((exarg_T *eap));
      + void enter_cleanup __ARGS((cleanup_T *csp));
      + void leave_cleanup __ARGS((cleanup_T *csp));
      int cleanup_conditionals __ARGS((struct condstack *cstack, int searched_cond, int inclusive));
      void ex_endfunction __ARGS((exarg_T *eap));
      int has_while_cmd __ARGS((char_u *p));
      *** ../vim-6.3.039/src/structs.h Sat Sep 18 20:28:07 2004
      --- src/structs.h Sun Dec 5 15:26:11 2004
      ***************
      *** 665,670 ****
      --- 665,681 ----
      #define ET_ERROR 1 /* error exception */
      #define ET_INTERRUPT 2 /* interrupt exception triggered by Ctrl-C */

      + /*
      + * Structure to save the error/interrupt/exception state between calls to
      + * enter_cleanup() and leave_cleanup(). Must be allocated as an automatic
      + * variable by the (common) caller of these functions.
      + */
      + typedef struct cleanup_stuff cleanup_T;
      + struct cleanup_stuff
      + {
      + int pending; /* error/interrupt/exception state */
      + except_T *exception; /* exception value */
      + };

      #ifdef FEAT_SYN_HL
      /* struct passed to in_id_list() */
      *** ../vim-6.3.039/src/vim.h Sat Sep 4 19:43:59 2004
      --- src/vim.h Sun Dec 5 15:26:56 2004
      ***************
      *** 714,720 ****
      #define BLN_CURBUF 1 /* May re-use curbuf for new buffer */
      #define BLN_LISTED 2 /* Put new buffer in buffer list */
      #define BLN_DUMMY 4 /* Allocating dummy buffer */
      - #define BLN_FORCE 8 /* Don't abort on error */

      /* Values for in_cinkeys() */
      #define KEY_OPEN_FORW 0x101
      --- 714,719 ----
      *** ../vim-6.3.039/src/version.c Sun Dec 5 14:57:15 2004
      --- src/version.c Sun Dec 5 16:16:22 2004
      ***************
      *** 643,644 ****
      --- 643,646 ----
      { /* Add new patch number below this line */
      + /**/
      + 40,
      /**/

      --
      If your company is not involved in something called "ISO 9000" you probably
      have no idea what it is. If your company _is_ involved in ISO 9000 then you
      definitely have no idea what it is.
      (Scott Adams - The Dilbert principle)

      /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
      /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
      \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
      \\\ Buy LOTR 3 and help AIDS victims -- http://ICCF.nl/lotr.html ///
    Your message has been successfully submitted and would be delivered to recipients shortly.