// Test signal handling part of i77 perms.

#include <stdio.h>
#include <stdlib.h>

#include "psignal.h"
#include "pbacktrace.h"

void toplevel(void) {
  
  void recursive_nested_proc(int I) {
    int Localvariable = I;

    // %on %event * %start
    if (sigsetjmp(_imp_on_event_enter(((_imp_eventfm *)malloc(sizeof(_imp_eventfm))))->env, 1)) {
      fprintf(stderr, "%%SIGNAL %d,%d,%d trapped by recursive_nested_proc(%d)\n\n",
              _imp_event.EVENT, _imp_event.SUBEVENT, _imp_event.EXTRA, I);
      fprintf(stderr, "LOCALVARIABLE = %d\n\n", Localvariable);
      
      // This has to be inserted before any signal call *in an on-event block*:
      _imp_on_event_leave(&_imp_event);  // unfortunately putting it at the top of the block stops the user accessing EVENT_EVENT etc.
                                        // Although I suppose _imp_on_event_leave could copy all those fields to the replacement.
      
      // %signal event, sub, extra+1 (and hidden message field)
      _imp_event.EVENT = 15; _imp_event.SUBEVENT = 42; _imp_event.EXTRA += 1; _imp_event.MESSAGE = _imp_str_literal(""); raise(SIGUSR1);
      // WARNING: only outstanding problem is if we drop through here without resignalling,
      //          any following signals will go wrong.  And probably cause an infinite loop.
    } // %finish

    if (I >= 10) {
      // %signal 15,42,17
      _imp_event.EVENT = 15; _imp_event.SUBEVENT = 42; _imp_event.EXTRA = 17; _imp_event.MESSAGE = _imp_str_literal(""); raise(SIGUSR1);
    }
    
    recursive_nested_proc(I + 3);

    _imp_on_event_leave(&_imp_event);
  } // end of recursive_nested_proc(int I)

  // set up another handler at the top level.
  if (sigsetjmp(_imp_on_event_enter(((_imp_eventfm *)malloc(sizeof(_imp_eventfm))))->env, 1)) {
    fprintf(stderr, "END OF toplevel: caught propagated %%signal %d, %d, %d\n", _imp_event.EVENT, _imp_event.SUBEVENT, _imp_event.EXTRA);
    _imp_on_event_leave(&_imp_event);

    print_back_trace(); // simulate %monitor
      
    return;
  }

  recursive_nested_proc(1);

  _imp_on_event_leave(&_imp_event);
}

// An IMP program might install a signal handler at the very top level which does
// the IMP diagnostic thing, to catch any events that the user program does not trap.
int main(void) {
  init_back_trace("/tmp/bt.dat");
  toplevel();
  fprintf(stderr, "Returned from toplevel to exit main()\n");
  return 0;
}
