BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / rc-1.4 / except.c
CommitLineData
ac39d190
C
1#include <setjmp.h>
2#include <signal.h>
3#include "rc.h"
4#include "jbwrap.h"
5
6/*
7 A return goes back stack frames to the last return. A break does
8 not. A signal goes to the last interactive level. (see below)
9*/
10
11bool nl_on_intr = TRUE;
12
13static Estack *estack;
14
15/* add an exception to the input stack. */
16
17extern void except(ecodes e, Edata data, Estack *ex) {
18 ex->prev = estack;
19 estack = ex;
20 estack->e = e;
21 estack->data = data;
22 if (e == eError || e == eBreak || e == eReturn)
23 estack->interactive = interactive;
24}
25
26/* remove an exception, restore last interactive value */
27
28extern void unexcept() {
29 switch (estack->e) {
30 default:
31 break;
32 case eError:
33 interactive = estack->interactive;
34 break;
35 case eArena:
36 restoreblock(estack->data.b);
37 break;
38 case eFifo:
39 unlink(estack->data.name);
40 break;
41 case eFd:
42 close(estack->data.fd);
43 break;
44 }
45 estack = estack->prev;
46}
47
48/*
49 Raise an exception. The rules are pretty complicated: you can return
50 from a loop inside a function, but you can't break from a function
51 inside of a loop. On errors, rc_raise() goes back to the LAST
52 INTERACTIVE stack frame. If no such frame exists, then rc_raise()
53 exits the shell. This is what happens, say, when there is a syntax
54 error in a noninteractive shell script. While traversing the
55 exception stack backwards, rc_raise() also removes input sources
56 (closing file-descriptors, etc.) and pops instances of variables
57 that have been pushed onto the variable stack (e.g., for a function
58 call (for $*) or a local assignment).
59*/
60
61extern void rc_raise(ecodes e) {
62 if (e == eError && rc_pid != getpid())
63 exit(1); /* child processes exit on an error/signal */
64 for (; estack != NULL; estack = estack->prev)
65 if (estack->e != e) {
66 if (e == eBreak && estack->e != eArena)
67 rc_error("break outside of loop");
68 else if (e == eReturn && estack->e == eError) /* can return from loops inside functions */
69 rc_error("return outside of function");
70 switch (estack->e) {
71 default:
72 break;
73 case eVarstack:
74 varrm(estack->data.name, TRUE);
75 break;
76 case eArena:
77 restoreblock(estack->data.b);
78 break;
79 case eFifo:
80 unlink(estack->data.name);
81 break;
82 case eFd:
83 close(estack->data.fd);
84 break;
85 }
86 } else {
87 if (e == eError && !estack->interactive) {
88 popinput();
89 } else {
90 Jbwrap *j = estack->data.jb;
91
92 interactive = estack->interactive;
93 estack = estack->prev;
94 longjmp(j->j, 1);
95 }
96 }
97 rc_exit(1); /* top of exception stack */
98}
99
100extern bool outstanding_cmdarg() {
101 return estack->e == eFifo || estack->e == eFd;
102}
103
104extern void pop_cmdarg(bool remove) {
105 for (; estack != NULL; estack = estack->prev)
106 switch (estack->e) {
107 case eFifo:
108 if (remove)
109 unlink(estack->data.name);
110 break;
111 case eFd:
112 if (remove)
113 close(estack->data.fd);
114 break;
115 default:
116 return;
117 }
118}
119
120/* exception handlers */
121
122extern void rc_error(char *s) {
123 pr_error(s);
124 set(FALSE);
125 redirq = NULL;
126 cond = FALSE; /* no longer inside conditional */
127 rc_raise(eError);
128}
129
130extern void sigint(int s) {
131 if (s != SIGINT)
132 panic("s != SIGINT in sigint catcher");
133 /* this is the newline you see when you hit ^C while typing a command */
134 if (nl_on_intr)
135 fprint(2, "\n");
136 nl_on_intr = TRUE;
137 redirq = NULL;
138 cond = FALSE;
139 rc_raise(eError);
140}