home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume20 / rc / part04 / except.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-22  |  2.2 KB  |  84 lines

  1. #include <setjmp.h>
  2. #include <stdarg.h>
  3. #include "rc.h"
  4. #include "utils.h"
  5. #include "except.h"
  6. #include "status.h"
  7. #include "hash.h"
  8. #include "input.h"
  9. #include "nalloc.h"
  10.  
  11. /*
  12.    a return goes back stack frames to the last return. A break does not. A signal
  13.    goes to the last interactive level.
  14. */
  15.  
  16. static Estack *estack;
  17.  
  18. /* add an exception to the input stack. */
  19.  
  20. void except(enum except e, jmp_buf jb, Estack *ex) {
  21.     ex->prev = estack;
  22.     estack = ex;
  23.  
  24.     switch (estack->e = e) {
  25.     case ARENA:
  26.         estack->b = newblock();
  27.         break;
  28.     case ERROR: case BREAK: case RETURN:
  29.         estack->interactive = interactive;
  30.         estack->jb = (jmp_buf *) jb;
  31.         break;
  32.     case STAR:
  33.         break;
  34.     }
  35. }
  36.  
  37. /* remove an exception, restore last interactive value */
  38.  
  39. void unexcept(void) {
  40.     if (estack->e == ERROR)
  41.         interactive = estack->interactive;
  42.     else if (estack->e == ARENA)
  43.         restoreblock(estack->b);
  44.     estack = estack->prev;
  45. }
  46.  
  47. /*
  48.    Raise an exception. The rules are pretty complicated: you can return from a loop inside a
  49.    function, but you can't break from a function inside of a loop. On errors, rc_raise() goes back
  50.    to the LAST INTERACTIVE stack frame. If no such frame exists, then rc_raise() exits the shell.
  51.    This is what happens, say, when there is a syntax error in a noninteractive shell script. While
  52.    traversing the exception stack backwards, rc_raise() also removes input sources (closing
  53.    file-descriptors, etc.) and pops instances of $* that have been pushed onto the variable stack
  54.    (e.g., for a function call).
  55. */
  56.  
  57. void rc_raise(enum except e) {
  58.     if (e == ERROR && rc_pid != getpid())
  59.             exit(1); /* child processes exit on an error/signal */
  60.  
  61.     for (; estack != NULL; estack = estack->prev)
  62.         if (estack->e != e) {
  63.             if (e == BREAK && estack->e != ARENA)
  64.                 rc_error("break outside of loop");
  65.             else if (e == RETURN && estack->e == ERROR) /* can return from loops inside functions */
  66.                 rc_error("return outside of function");
  67.             if (estack->e == STAR)
  68.                 varrm("*", TRUE);
  69.             else if (estack->e == ARENA)
  70.                 restoreblock(estack->b);
  71.         } else {
  72.             if (e == ERROR && !estack->interactive) {
  73.                 popinput();
  74.             } else {
  75.                 jmp_buf *j = estack->jb;
  76.  
  77.                 interactive = estack->interactive;
  78.                 estack = estack->prev;
  79.                 longjmp(*j, 1);
  80.             }
  81.         }
  82.     rc_exit(1); /* top of exception stack */
  83. }
  84.