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