home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / rc / part01 / except.c < prev    next >
C/C++ Source or Header  |  1991-10-18  |  2KB  |  87 lines

  1. #include "jbwrap.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, void *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:
  29.     case BREAK:
  30.     case RETURN:
  31.         estack->interactive = interactive;
  32.         estack->jb = (jbwrap *) jb;
  33.         break;
  34.     case VARSTACK:
  35.         estack->name = (char *) jb;
  36.         break;
  37.     }
  38. }
  39.  
  40. /* remove an exception, restore last interactive value */
  41.  
  42. void unexcept() {
  43.     if (estack->e == ERROR)
  44.         interactive = estack->interactive;
  45.     else if (estack->e == ARENA)
  46.         restoreblock(estack->b);
  47.     estack = estack->prev;
  48. }
  49.  
  50. /*
  51.    Raise an exception. The rules are pretty complicated: you can return from a loop inside a
  52.    function, but you can't break from a function inside of a loop. On errors, rc_raise() goes back
  53.    to the LAST INTERACTIVE stack frame. If no such frame exists, then rc_raise() exits the shell.
  54.    This is what happens, say, when there is a syntax error in a noninteractive shell script. While
  55.    traversing the exception stack backwards, rc_raise() also removes input sources (closing
  56.    file-descriptors, etc.) and pops instances of $* that have been pushed onto the variable stack
  57.    (e.g., for a function call).
  58. */
  59.  
  60. void rc_raise(enum except e) {
  61.     if (e == ERROR && rc_pid != getpid())
  62.             exit(1); /* child processes exit on an error/signal */
  63.  
  64.     for (; estack != NULL; estack = estack->prev)
  65.         if (estack->e != e) {
  66.             if (e == BREAK && estack->e != ARENA)
  67.                 rc_error("break outside of loop");
  68.             else if (e == RETURN && estack->e == ERROR) /* can return from loops inside functions */
  69.                 rc_error("return outside of function");
  70.             if (estack->e == VARSTACK)
  71.                 varrm(estack->name, TRUE);
  72.             else if (estack->e == ARENA)
  73.                 restoreblock(estack->b);
  74.         } else {
  75.             if (e == ERROR && !estack->interactive) {
  76.                 popinput();
  77.             } else {
  78.                 jbwrap *j = estack->jb;
  79.  
  80.                 interactive = estack->interactive;
  81.                 estack = estack->prev;
  82.                 longjmp(j->j, 1);
  83.             }
  84.         }
  85.     rc_exit(1); /* top of exception stack */
  86. }
  87.