home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume30 / rc / part06 / except.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-30  |  3.3 KB  |  141 lines

  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.  
  11. bool nl_on_intr = TRUE;
  12.  
  13. static Estack *estack;
  14.  
  15. /* add an exception to the input stack. */
  16.  
  17. extern 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.  
  28. extern 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.  
  61. extern 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.  
  100. extern bool outstanding_cmdarg() {
  101.     return estack->e == eFifo || estack->e == eFd;
  102. }
  103.  
  104. extern 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.  
  122. extern 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.  
  130. extern 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. }
  141.