+static struct catcher *current_catcher;
+
+static SIGJMP_BUF *
+catcher_init (struct ui_out *func_uiout,
+ char *errstring,
+ char **gdberrmsg,
+ return_mask mask)
+{
+ struct catcher *new_catcher = XZALLOC (struct catcher);
+
+ new_catcher->gdberrmsg = gdberrmsg;
+ new_catcher->mask = mask;
+
+ /* Override error/quit messages during FUNC. */
+ new_catcher->saved_error_pre_print = error_pre_print;
+ new_catcher->saved_quit_pre_print = quit_pre_print;
+ if (mask & RETURN_MASK_ERROR)
+ error_pre_print = errstring;
+ if (mask & RETURN_MASK_QUIT)
+ quit_pre_print = errstring;
+
+ /* Override the global ``struct ui_out'' builder. */
+ new_catcher->saved_uiout = uiout;
+ uiout = func_uiout;
+
+ /* Prevent error/quit during FUNC from calling cleanups established
+ prior to here. */
+ new_catcher->saved_cleanup_chain = save_cleanups ();
+
+ /* Push this new catcher on the top. */
+ new_catcher->prev = current_catcher;
+ current_catcher = new_catcher;
+ new_catcher->state = CATCHER_CREATED;
+
+ return &new_catcher->buf;
+}
+
+static void
+catcher_pop (void)
+{
+ struct catcher *old_catcher = current_catcher;
+ current_catcher = old_catcher->prev;
+
+ /* Restore the cleanup chain, the error/quit messages, and the uiout
+ builder, to their original states. */
+
+ restore_cleanups (old_catcher->saved_cleanup_chain);
+
+ uiout = old_catcher->saved_uiout;
+
+ quit_pre_print = old_catcher->saved_quit_pre_print;
+ error_pre_print = old_catcher->saved_error_pre_print;
+
+ xfree (old_catcher);
+}
+
+/* Catcher state machine. Returns non-zero if the m/c should be run
+ again, zero if it should abort. */
+
+int
+catcher_state_machine (enum catcher_action action)
+{
+ switch (current_catcher->state)
+ {
+ case CATCHER_CREATED:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* Allow the code to run the catcher. */
+ current_catcher->state = CATCHER_RUNNING;
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, "bad state");
+ }
+ case CATCHER_RUNNING:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* No error/quit has occured. Just clean up. */
+ catcher_pop ();
+ return 0;
+ case CATCH_ITER_1:
+ current_catcher->state = CATCHER_RUNNING_1;
+ return 1;
+ case CATCH_THROWING:
+ current_catcher->state = CATCHER_ABORTING;
+ /* See also throw_exception. */
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ case CATCHER_RUNNING_1:
+ switch (action)
+ {
+ case CATCH_ITER:
+ /* The did a "break" from the inner while loop. */
+ catcher_pop ();
+ return 0;
+ case CATCH_ITER_1:
+ current_catcher->state = CATCHER_RUNNING;
+ return 0;
+ case CATCH_THROWING:
+ current_catcher->state = CATCHER_ABORTING;
+ /* See also throw_exception. */
+ return 1;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ case CATCHER_ABORTING:
+ switch (action)
+ {
+ case CATCH_ITER:
+ {
+ int reason = current_catcher->reason;
+ /* If caller wants a copy of the low-level error message,
+ make one. This is used in the case of a silent error
+ whereby the caller may optionally want to issue the
+ message. */
+ if (current_catcher->gdberrmsg != NULL)
+ *(current_catcher->gdberrmsg) = error_last_message ();
+ if (current_catcher->mask & RETURN_MASK (reason))
+ {
+ /* Exit normally if this catcher can handle this
+ exception. The caller analyses the func return
+ values. */
+ catcher_pop ();
+ return 0;
+ }
+ /* The caller didn't request that the event be caught,
+ relay the event to the next containing
+ catch_errors(). */
+ catcher_pop ();
+ throw_exception (reason);
+ }
+ default:
+ internal_error (__FILE__, __LINE__, "bad state");
+ }
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+}