commit 31f0826614c17ef69f3cc654f9ede3ca9452522e
parent b12d41f95452f06360d4879bc466469686d167a8
Author: tgoodwin <tgoodwin>
Date: Thu, 5 Feb 1998 14:51:54 +0000
Initial revision
Diffstat:
A | except.c | | | 140 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 140 insertions(+), 0 deletions(-)
diff --git a/except.c b/except.c
@@ -0,0 +1,140 @@
+#include <setjmp.h>
+#include <signal.h>
+#include "rc.h"
+#include "jbwrap.h"
+
+/*
+ A return goes back stack frames to the last return. A break does
+ not. A signal goes to the last interactive level. (see below)
+*/
+
+bool nl_on_intr = TRUE;
+
+static Estack *estack;
+
+/* add an exception to the input stack. */
+
+extern void except(ecodes e, Edata data, Estack *ex) {
+ ex->prev = estack;
+ estack = ex;
+ estack->e = e;
+ estack->data = data;
+ if (e == eError || e == eBreak || e == eReturn)
+ estack->interactive = interactive;
+}
+
+/* remove an exception, restore last interactive value */
+
+extern void unexcept() {
+ switch (estack->e) {
+ default:
+ break;
+ case eError:
+ interactive = estack->interactive;
+ break;
+ case eArena:
+ restoreblock(estack->data.b);
+ break;
+ case eFifo:
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ close(estack->data.fd);
+ break;
+ }
+ estack = estack->prev;
+}
+
+/*
+ Raise an exception. The rules are pretty complicated: you can return
+ from a loop inside a function, but you can't break from a function
+ inside of a loop. On errors, rc_raise() goes back to the LAST
+ INTERACTIVE stack frame. If no such frame exists, then rc_raise()
+ exits the shell. This is what happens, say, when there is a syntax
+ error in a noninteractive shell script. While traversing the
+ exception stack backwards, rc_raise() also removes input sources
+ (closing file-descriptors, etc.) and pops instances of variables
+ that have been pushed onto the variable stack (e.g., for a function
+ call (for $*) or a local assignment).
+*/
+
+extern void rc_raise(ecodes e) {
+ if (e == eError && rc_pid != getpid())
+ exit(1); /* child processes exit on an error/signal */
+ for (; estack != NULL; estack = estack->prev)
+ if (estack->e != e) {
+ if (e == eBreak && estack->e != eArena)
+ rc_error("break outside of loop");
+ else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */
+ rc_error("return outside of function");
+ switch (estack->e) {
+ default:
+ break;
+ case eVarstack:
+ varrm(estack->data.name, TRUE);
+ break;
+ case eArena:
+ restoreblock(estack->data.b);
+ break;
+ case eFifo:
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ close(estack->data.fd);
+ break;
+ }
+ } else {
+ if (e == eError && !estack->interactive) {
+ popinput();
+ } else {
+ Jbwrap *j = estack->data.jb;
+
+ interactive = estack->interactive;
+ estack = estack->prev;
+ longjmp(j->j, 1);
+ }
+ }
+ rc_exit(1); /* top of exception stack */
+}
+
+extern bool outstanding_cmdarg() {
+ return estack->e == eFifo || estack->e == eFd;
+}
+
+extern void pop_cmdarg(bool remove) {
+ for (; estack != NULL; estack = estack->prev)
+ switch (estack->e) {
+ case eFifo:
+ if (remove)
+ unlink(estack->data.name);
+ break;
+ case eFd:
+ if (remove)
+ close(estack->data.fd);
+ break;
+ default:
+ return;
+ }
+}
+
+/* exception handlers */
+
+extern void rc_error(char *s) {
+ pr_error(s);
+ set(FALSE);
+ redirq = NULL;
+ cond = FALSE; /* no longer inside conditional */
+ rc_raise(eError);
+}
+
+extern void sigint(int s) {
+ if (s != SIGINT)
+ panic("s != SIGINT in sigint catcher");
+ /* this is the newline you see when you hit ^C while typing a command */
+ if (interactive && nl_on_intr)
+ fprint(2, "\n");
+ nl_on_intr = TRUE;
+ redirq = NULL;
+ cond = FALSE;
+ rc_raise(eError);
+}