#ifndef __PSIGNAL_H__
#define __PSIGNAL_H__ 1

// Signal handling part of i77 perms.

// Setting this up so that *all* IMP %signal calls map to linux signal SUGUSR1
// Any other Linux signals (such as generated by say divide-by-zero) will need
// to be trapped and converted into an IMP signal.

#include <signal.h>
#include <setjmp.h>

#include "imptypes.h"

/*

  The structure below is multi-purpose: eventfm records can contain:

   1) The info needed to describe and implement an %onevent trap block
   2) A place to place the %signal parameters when raising a signal
   3) The value of the signal parameters of the last signal received
      (even after leaving the start/finish block of an %onevent trap)

  The top-level record (eventfm) event is the one referred to by
  Imp's user-visible EVENT record.  The linked-list stack of records
  used to unwind the stack are not explicitly visible to Imp users.
 */

typedef struct _imp_eventfm _imp_eventfm;
typedef struct _imp_eventfm {
  // These are values used in Imp77 signal mechanism, not relevant to C:
  int EVENT;
  union {
    int SUB;
    int SUBEVENT;
  };
  union {
    int INFO;
    int EXTRA;
  };
  // char *MESSAGE;
  _imp_string MESSAGE;

  _imp_string FILE;
  int LINE;
  // these are for the C signal mechanism:
  int mask; // The signal numbers that this event block is trapping.
  sigjmp_buf env;
  _imp_eventfm *prev;
} _imp_eventfm;

extern _imp_eventfm _imp_event;
extern sig_atomic_t _imp_last_signal;

static inline _imp_eventfm _imp_EVENT(void) { return _imp_event; }
static inline int _imp_EVENTNO(void) { return _imp_event.EVENT; }
static inline int _imp_SUBEVENT(void) { return _imp_event.SUB/*EVENT*/; }
static inline int _imp_EVENTINFO(void) { return _imp_event.INFO/*EXTRA*/; }
static inline _imp_string _imp_EVENTMESSAGE(void) {
  //if (_imp_event.MESSAGE == 0/*NULL*/) return _imp_str_literal("");
  return _imp_event.MESSAGE;
}

static inline int _imp_EVENTLINE(void) { return _imp_event.LINE; }

static inline _imp_string _imp_EVENTFILE(void) {
  //if (_imp_event.FILE == 0/*NULL*/) return _imp_str_literal("");
  return _imp_event.FILE;
}

extern void _imp_signal_handler(int sig);
extern _imp_eventfm *_imp_on_event_enter(_imp_eventfm *f, ...);
extern void _imp_on_event_leave(_imp_eventfm *f);

extern void _signal_event(_imp_string file,
                          int line,
                          _imp_string message,
                          int event, int subevent, int extra);

// (Use our internal file/line value if available)
#define _imp_signal(A,B,C,D)                                       \
             _signal_event(_imp_current_file                       \
                             ? _imp_c2istr(_imp_current_file)      \
                             : _imp_str_literal(__FILE__),         \
                             _imp_current_line                     \
                               ? _imp_current_line                 \
                               : __LINE__, _imp_c2istr(D), A,B,C)

#define _imp_on_event(...)                                            \
  sigsetjmp (                                                         \
    _imp_event.env,                                                   \
    1                                                                 \
  ) &&                                                                \
  _imp_on_event_enter(                                                \
    &_imp_event,                                                      \
    __VA_ARGS__, -1                                                   \
  )              /* -1 denotes end of arg list */

#endif // defined __PSIGNAL_H__
