From 16a47e287f44f4ea154f9bfc1d3a6fa083a0f43e Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Fri, 21 Nov 2014 19:36:01 +0100 Subject: finally implemented the CLOSE and QUIT hooks the QUIT hook is actually not that trivial and required some architectural changes. First, the QUIT hook execution and any error that might occurr cannot always be attached to an existing error stack frame. Thereforce, to give a stack frame for QUIT hooks and to improve the readability of error traces for ED hooks in general, a special EDHookFrame is added to every ED hook execution error. Secondly, since QUIT hooks can themselves throw errors, we cannot run it from an atexit() handler. Instead it's always called manually before __successful__ program termination. An error in a QUIT hook will result in a failure return code nevertheless. Thirdly, errors in QUIT hooks should not prevent program termination (in interactive mode), therefore they are only invoked from main() and always in batch mode. I.e. if the interactive mode is terminated (EX$$), SciTECO will switch back to batch mode and run the QUIT hook there. This is also symmetric to program startup, which is always in batch mode. This means that Interface::event_loop() no longer runs indefinitely. If it returns, this signals that the interface shut down and batch mode may be restored by SciTECO. --- src/qregisters.cpp | 54 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) (limited to 'src/qregisters.cpp') diff --git a/src/qregisters.cpp b/src/qregisters.cpp index 89b2afd..230dc5b 100644 --- a/src/qregisters.cpp +++ b/src/qregisters.cpp @@ -366,32 +366,46 @@ QRegisterStack::~QRegisterStack() void QRegisters::hook(Hook type) { + static const gchar *type2name[] = { + /* [HOOK_ADD-1] = */ "ADD", + /* [HOOK_EDIT-1] = */ "EDIT", + /* [HOOK_CLOSE-1] = */ "CLOSE", + /* [HOOK_QUIT-1] = */ "QUIT", + }; + QRegister *reg; if (!(Flags::ed & Flags::ED_HOOKS)) return; - reg = globals["ED"]; - if (!reg) - throw Error("Undefined ED-hook register (\"ED\")"); + try { + reg = globals["ED"]; + if (!reg) + throw Error("Undefined ED-hook register (\"ED\")"); - /* - * ED-hook execution should not see any - * integer parameters but the hook type. - * Such parameters could confuse the ED macro - * and macro authors do not expect side effects - * of ED macros on the expression stack. - * Also make sure it does not leave behind - * additional arguments on the stack. - * - * So this effectively executes: - * (typeM[ED]^[) - */ - expressions.push(Expressions::OP_BRACE); - expressions.push(type); - reg->execute(); - expressions.discard_args(); - expressions.eval(true); + /* + * ED-hook execution should not see any + * integer parameters but the hook type. + * Such parameters could confuse the ED macro + * and macro authors do not expect side effects + * of ED macros on the expression stack. + * Also make sure it does not leave behind + * additional arguments on the stack. + * + * So this effectively executes: + * (typeM[ED]^[) + */ + expressions.push(Expressions::OP_BRACE); + expressions.push(type); + reg->execute(); + expressions.discard_args(); + expressions.eval(true); + } catch (Error &error) { + const gchar *type_str = type2name[type-1]; + + error.add_frame(new Error::EDHookFrame(type_str)); + throw; /* forward */ + } } void -- cgit v1.2.3