home *** CD-ROM | disk | FTP | other *** search
- #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 (nl_on_intr)
- fprint(2, "\n");
- nl_on_intr = TRUE;
- redirq = NULL;
- cond = FALSE;
- rc_raise(eError);
- }
-