4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=ISO-8859-1
7 Content-Transfer-Encoding: 8bit
11 Problem: Error handling does not always work properly and may cause a
12 buffer to be marked as if it's viewed in a window while it isn't.
13 Also when selecting "Abort" at the attention prompt.
14 Solution: Add enter_cleanup() and leave_cleanup() functions to move
15 saving/restoring things for error handling to one place.
16 Clear a buffer read error when it's unloaded.
17 Files: src/buffer.c, src/ex_docmd.c, src/ex_eval.c,
18 src/proto/ex_eval.pro, src/structs.h, src/vim.h
21 *** ../vim-6.3.039/src/buffer.c Wed Jun 9 14:56:27 2004
22 --- src/buffer.c Sun Dec 5 16:15:05 2004
28 ! /* Autocommands may abort script processing. */
37 ! if (aborting()) /* autocmds may abort script processing */
45 syntax_clear(buf); /* reset syntax info */
47 + buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
54 && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
55 if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
57 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
60 + /* Reset the error/interrupt/exception state here so that
61 + * aborting() returns FALSE when closing a window. */
65 /* Quitting means closing the split window, nothing else. */
66 win_close(curwin, TRUE);
67 swap_exists_action = SEA_NONE;
69 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
70 + /* Restore the error/interrupt/exception state if not discarded by a
71 + * new aborting error, interrupt, or uncaught exception. */
76 handle_swap_exists(old_curbuf);
79 handle_swap_exists(old_curbuf)
82 if (swap_exists_action == SEA_QUIT)
84 /* User selected Quit at ATTENTION prompt. Go back to previous
85 * buffer. If that buffer is gone or the same as the current one,
86 * open a new, empty buffer. */
87 swap_exists_action = SEA_NONE; /* don't want it again */
88 close_buffer(curwin, curbuf, DOBUF_UNLOAD);
89 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
90 ! old_curbuf = buflist_new(NULL, NULL, 1L,
91 ! BLN_CURBUF | BLN_LISTED | BLN_FORCE);
92 if (old_curbuf != NULL)
93 enter_buffer(old_curbuf);
94 /* If "old_curbuf" is NULL we are in big trouble here... */
96 else if (swap_exists_action == SEA_RECOVER)
98 /* User selected Recover at ATTENTION prompt. */
101 MSG_PUTS("\n"); /* don't overwrite the last message */
102 cmdline_row = msg_row;
105 swap_exists_action = SEA_NONE;
108 handle_swap_exists(old_curbuf)
111 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
115 if (swap_exists_action == SEA_QUIT)
117 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
118 + /* Reset the error/interrupt/exception state here so that
119 + * aborting() returns FALSE when closing a buffer. */
120 + enter_cleanup(&cs);
123 /* User selected Quit at ATTENTION prompt. Go back to previous
124 * buffer. If that buffer is gone or the same as the current one,
125 * open a new, empty buffer. */
126 swap_exists_action = SEA_NONE; /* don't want it again */
127 close_buffer(curwin, curbuf, DOBUF_UNLOAD);
128 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
129 ! old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
130 if (old_curbuf != NULL)
131 enter_buffer(old_curbuf);
132 /* If "old_curbuf" is NULL we are in big trouble here... */
134 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
135 + /* Restore the error/interrupt/exception state if not discarded by a
136 + * new aborting error, interrupt, or uncaught exception. */
137 + leave_cleanup(&cs);
140 else if (swap_exists_action == SEA_RECOVER)
142 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
143 + /* Reset the error/interrupt/exception state here so that
144 + * aborting() returns FALSE when closing a buffer. */
145 + enter_cleanup(&cs);
148 /* User selected Recover at ATTENTION prompt. */
151 MSG_PUTS("\n"); /* don't overwrite the last message */
152 cmdline_row = msg_row;
155 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
156 + /* Restore the error/interrupt/exception state if not discarded by a
157 + * new aborting error, interrupt, or uncaught exception. */
158 + leave_cleanup(&cs);
161 swap_exists_action = SEA_NONE;
165 * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
166 * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
167 * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
168 - * If (flags & BLN_FORCE) is TRUE, don't abort on an error.
169 * This is the ONLY way to create a new buffer.
171 static int top_file_num = 1; /* highest file number */
176 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
178 ! /* autocmds may abort script processing */
179 ! if (!(flags & BLN_FORCE) && aborting())
185 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
187 ! if (aborting()) /* autocmds may abort script processing */
193 if (buf != curbuf) /* autocommands deleted the buffer! */
195 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
196 ! /* autocmds may abort script processing */
197 ! if (!(flags & BLN_FORCE) && aborting())
200 /* buf->b_nwindows = 0; why was this here? */
202 if (buf != curbuf) /* autocommands deleted the buffer! */
204 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
205 ! if (aborting()) /* autocmds may abort script processing */
208 /* buf->b_nwindows = 0; why was this here? */
211 if (flags & BLN_LISTED)
212 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
214 ! /* autocmds may abort script processing */
215 ! if (!(flags & BLN_FORCE) && aborting())
220 if (flags & BLN_LISTED)
221 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
223 ! if (aborting()) /* autocmds may abort script processing */
230 set_curbuf(buf, DOBUF_GOTO);
233 - /* Autocommands deleted the buffer or aborted script
235 - if (!buf_valid(buf) || aborting())
237 if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
240 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
241 swap_exists_action = SEA_NONE;
246 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
247 if (swap_exists_action == SEA_QUIT)
249 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
252 + /* Reset the error/interrupt/exception state here so that
253 + * aborting() returns FALSE when closing a window. */
254 + enter_cleanup(&cs);
257 /* User selected Quit at ATTENTION prompt; close this window. */
258 win_close(curwin, TRUE);
260 swap_exists_action = SEA_NONE;
262 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
263 + /* Restore the error/interrupt/exception state if not
264 + * discarded by a new aborting error, interrupt, or uncaught
266 + leave_cleanup(&cs);
270 handle_swap_exists(NULL);
274 (void)vgetc(); /* only break the file loading, not the rest */
278 + /* Autocommands deleted the buffer or aborted script processing!!! */
285 *** ../vim-6.3.039/src/ex_docmd.c Wed Jun 9 14:59:11 2004
286 --- src/ex_docmd.c Sun Dec 5 15:24:08 2004
290 need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1);
291 if (!need_hide || P_HID(curbuf))
293 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
296 + /* Reset the error/interrupt/exception state here so that
297 + * aborting() returns FALSE when closing a window. */
298 + enter_cleanup(&cs);
301 need_mouse_correct = TRUE;
303 win_close(curwin, !need_hide && !P_HID(curbuf));
305 + # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
306 + /* Restore the error/interrupt/exception state if not
307 + * discarded by a new aborting error, interrupt, or
308 + * uncaught exception. */
309 + leave_cleanup(&cs);
314 *** ../vim-6.3.039/src/ex_eval.c Wed Jun 9 14:56:26 2004
315 --- src/ex_eval.c Sun Dec 5 15:25:04 2004
322 + * enter_cleanup() and leave_cleanup()
324 + * Functions to be called before/after invoking a sequence of autocommands for
325 + * cleanup for a failed command. (Failure means here that a call to emsg()
326 + * has been made, an interrupt occurred, or there is an uncaught exception
327 + * from a previous autocommand execution of the same command.)
329 + * Call enter_cleanup() with a pointer to a cleanup_T and pass the same
330 + * pointer to leave_cleanup(). The cleanup_T structure stores the pending
331 + * error/interrupt/exception state.
335 + * This function works a bit like ex_finally() except that there was not
336 + * actually an extra try block around the part that failed and an error or
337 + * interrupt has not (yet) been converted to an exception. This function
338 + * saves the error/interrupt/ exception state and prepares for the call to
339 + * do_cmdline() that is going to be made for the cleanup autocommand
346 + int pending = CSTP_NONE;
349 + * Postpone did_emsg, got_int, did_throw. The pending values will be
350 + * restored by leave_cleanup() except if there was an aborting error,
351 + * interrupt, or uncaught exception after this function ends.
353 + if (did_emsg || got_int || did_throw || need_rethrow)
355 + csp->pending = (did_emsg ? CSTP_ERROR : 0)
356 + | (got_int ? CSTP_INTERRUPT : 0)
357 + | (did_throw ? CSTP_THROW : 0)
358 + | (need_rethrow ? CSTP_THROW : 0);
360 + /* If we are currently throwing an exception (did_throw), save it as
361 + * well. On an error not yet converted to an exception, update
362 + * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
363 + * This is needed for the do_cmdline() call that is going to be made
364 + * for autocommand execution. We need not save *msg_list because
365 + * there is an extra instance for every call of do_cmdline(), anyway.
367 + if (did_throw || need_rethrow)
368 + csp->exception = current_exception;
371 + csp->exception = NULL;
374 + force_abort |= cause_abort;
375 + cause_abort = FALSE;
378 + did_emsg = got_int = did_throw = need_rethrow = FALSE;
380 + /* Report if required by the 'verbose' option or when debugging. */
381 + report_make_pending(pending, csp->exception);
385 + csp->pending = CSTP_NONE;
386 + csp->exception = NULL;
391 + * See comment above enter_cleanup() for how this function is used.
393 + * This function is a bit like ex_endtry() except that there was not actually
394 + * an extra try block around the part that failed and an error or interrupt
395 + * had not (yet) been converted to an exception when the cleanup autocommand
396 + * sequence was invoked.
398 + * This function has to be called with the address of the cleanup_T structure
399 + * filled by enter_cleanup() as an argument; it restores the error/interrupt/
400 + * exception state saved by that function - except there was an aborting
401 + * error, an interrupt or an uncaught exception during execution of the
402 + * cleanup autocommands. In the latter case, the saved error/interrupt/
403 + * exception state is discarded.
409 + int pending = csp->pending;
411 + if (pending == CSTP_NONE) /* nothing to do */
414 + /* If there was an aborting error, an interrupt, or an uncaught exception
415 + * after the corresponding call to enter_cleanup(), discard what has been
416 + * made pending by it. Report this to the user if required by the
417 + * 'verbose' option or when debugging. */
418 + if (aborting() || need_rethrow)
420 + if (pending & CSTP_THROW)
421 + /* Cancel the pending exception (includes report). */
422 + discard_exception((except_T *)csp->exception, FALSE);
424 + report_discard_pending(pending, NULL);
426 + /* If an error was about to be converted to an exception when
427 + * enter_cleanup() was called, free the message list. */
428 + free_msglist(*msg_list);
433 + * If there was no new error, interrupt, or throw between the calls
434 + * to enter_cleanup() and leave_cleanup(), restore the pending
435 + * error/interrupt/exception state.
440 + * If there was an exception being thrown when enter_cleanup() was
441 + * called, we need to rethrow it. Make it the exception currently
444 + if (pending & CSTP_THROW)
445 + current_exception = csp->exception;
448 + * If an error was about to be converted to an exception when
449 + * enter_cleanup() was called, let "cause_abort" take the part of
450 + * "force_abort" (as done by cause_errthrow()).
452 + else if (pending & CSTP_ERROR)
454 + cause_abort = force_abort;
455 + force_abort = FALSE;
459 + * Restore the pending values of did_emsg, got_int, and did_throw.
461 + if (pending & CSTP_ERROR)
463 + if (pending & CSTP_INTERRUPT)
465 + if (pending & CSTP_THROW)
466 + need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
468 + /* Report if required by the 'verbose' option or when debugging. */
469 + report_resume_pending(pending,
470 + (pending & CSTP_THROW) ? (void *)current_exception : NULL);
476 * Make conditionals inactive and discard what's pending in finally clauses
477 * until the conditional type searched for or a try conditional not in its
478 * finally clause is reached. If this is in an active catch clause, finish the
479 *** ../vim-6.3.039/src/proto/ex_eval.pro Wed Jun 9 14:56:24 2004
480 --- src/proto/ex_eval.pro Sun Dec 5 15:25:27 2004
484 void ex_catch __ARGS((exarg_T *eap));
485 void ex_finally __ARGS((exarg_T *eap));
486 void ex_endtry __ARGS((exarg_T *eap));
487 + void enter_cleanup __ARGS((cleanup_T *csp));
488 + void leave_cleanup __ARGS((cleanup_T *csp));
489 int cleanup_conditionals __ARGS((struct condstack *cstack, int searched_cond, int inclusive));
490 void ex_endfunction __ARGS((exarg_T *eap));
491 int has_while_cmd __ARGS((char_u *p));
492 *** ../vim-6.3.039/src/structs.h Sat Sep 18 20:28:07 2004
493 --- src/structs.h Sun Dec 5 15:26:11 2004
497 #define ET_ERROR 1 /* error exception */
498 #define ET_INTERRUPT 2 /* interrupt exception triggered by Ctrl-C */
501 + * Structure to save the error/interrupt/exception state between calls to
502 + * enter_cleanup() and leave_cleanup(). Must be allocated as an automatic
503 + * variable by the (common) caller of these functions.
505 + typedef struct cleanup_stuff cleanup_T;
506 + struct cleanup_stuff
508 + int pending; /* error/interrupt/exception state */
509 + except_T *exception; /* exception value */
513 /* struct passed to in_id_list() */
514 *** ../vim-6.3.039/src/vim.h Sat Sep 4 19:43:59 2004
515 --- src/vim.h Sun Dec 5 15:26:56 2004
518 #define BLN_CURBUF 1 /* May re-use curbuf for new buffer */
519 #define BLN_LISTED 2 /* Put new buffer in buffer list */
520 #define BLN_DUMMY 4 /* Allocating dummy buffer */
521 - #define BLN_FORCE 8 /* Don't abort on error */
523 /* Values for in_cinkeys() */
524 #define KEY_OPEN_FORW 0x101
526 *** ../vim-6.3.039/src/version.c Sun Dec 5 14:57:15 2004
527 --- src/version.c Sun Dec 5 16:16:22 2004
531 { /* Add new patch number below this line */
537 If your company is not involved in something called "ISO 9000" you probably
538 have no idea what it is. If your company _is_ involved in ISO 9000 then you
539 definitely have no idea what it is.
540 (Scott Adams - The Dilbert principle)
542 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
543 /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
544 \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
545 \\\ Buy LOTR 3 and help AIDS victims -- http://ICCF.nl/lotr.html ///