#include <fcntl.h>
#include <signal.h>
#include <qdos.h>
#include <assert.h>
#include "qsignal.h"


#define assert(expr) ((expr) ? (void)0 \
: _assert( __FILE__":" _STR(__LINE__)"\n" #expr ))


struct sig {void (*sigaction)();char flag;};


struct sig _sigtable[_NSIG+1];
struct QDOS_SIGH _sigstruct;

chanid_t _sigch;
long _sigflag=0;
long _inlib=0;

extern long _spbase;
extern long _stackmargin;



void (* signal(int signr,void (*action) (int)) )(int)
{
  void *r=_sigtable[signr].sigaction;
  if(signr<1 || signr>_NSIG) return ((void (*)())-4);
  _sigtable[signr].flag=0;
  _sigtable[signr].sigaction=action;
  return r;
}

void _init_sigrec()
{
int i;

for(i=0;i<=_NSIG;i++) signal(i,SIG_DFL);
/*     {_sigtable[i].sigaction=SIG_DFL;
      _sigtable[i].flag=0;}  */

_sigstruct.m1=0x4afc;
_sigstruct.m2=0x25534947;      /* '%SIG' */
_sigstruct.sighandler=_sigwrap;  /* assembler wrapper routine */
_sigstruct.stackmin=_spbase+_stackmargin+400;   /* stack bottom     */
*(long *)&(_sigstruct.priority)=0;   /* clear all reserved bits */
_sigstruct.priority.norm=0;
_sigstruct.priority.wfio=0;
_sigstruct.priority.wfjob=0;
_sigstruct.priority.susp=0;

_sigch=io_open("*signal_r",(long)&_sigstruct); /* tell QDOS about the hanlder */

}

/* this is the routine called by _sigwrap */

void _sig_handler(long signr,long pri,long usrval,
                  struct SREGS regs, struct SIGSVB svb)
{
  void (*fptr)(int);

  assert(stackcheck());

  if(signr<1 || signr>_NSIG)  return;              /* ignore unknown signals */

  if(_sigtable[signr].sigaction==SIG_IGN) return;  /* ignore */
  if(_sigtable[signr].sigaction==SIG_DFL) return;  /* ignore is default */

  if(_inlib)
     {   _sigtable[signr].flag=_sigflag=1; return; }
  else
  fptr=_sigtable[signr].sigaction;
  _sigtable[signr].sigaction=SIG_DFL;
  _sigtable[signr].flag=0;
  (*fptr)(signr);                          /* DO the signalhandling */
  _sigtable[signr].sigaction=fptr;
}

void checksig()
{ int signr;
  void (*fptr)(int);

  if(_inlib) return;
  assert(stackcheck());

  for(signr=1;signr<=_NSIG;signr++)
    if(_sigtable[signr].flag )
       {_sigtable[signr].flag=0;
        if(_sigtable[signr].sigaction>2)
           {fptr=_sigtable[signr].sigaction;
            _sigtable[signr].sigaction=SIG_DFL;
            (*fptr)(signr);                 /* DO the signalhandling */
            _sigtable[signr].sigaction=fptr;
        }}
  _sigflag=0;
}


int kill(pid_t j,int i)
{
if (i==SIGKILL) return mt_frjob(j,0);
return sendsig(_sigch,j,i,06666,0);
}

int abort()         /* c68 abort broken with my kill definition */
{
 int c;
 if(isatty(0)) io_fbyte(getchid(0),400,&c);
 return mt_frjob(-1,0);
}


int sendsig(ch,jobid,intrnr,pri,usrval)
int ch,jobid,intrnr,pri,usrval;
{struct REGS rgs;
 rgs.D0=0x2f;       /* trap nr $2f */
 rgs.D1=jobid;
 rgs.D2=intrnr;
 rgs.D3=-1;
 rgs.A0=ch;
 rgs.A1=pri;
 rgs.A2=usrval;
return qdos3(&rgs,&rgs);
}



#define SYSCALLRET(call,rtype)  {rtype r;int i=_inlib;_inlib=1;r=(call);\
_inlib=i;if(_sigflag) checksig();return r; }

#define SYSCALLV(call)  {int i=_inlib;_inlib=1;call;\
_inlib=i;if(_sigflag) checksig(); }


void * _s_malloc(size_t sze)
{
SYSCALLRET(malloc(sze),void *)
}

/*
void * _s_calloc(size_t sz1,size_t sz2)
{return calloc(sz1,sz2);} */


void * _s_realloc(void *ptr, size_t siz)
{SYSCALLRET(_Realloc(ptr,siz),void *)}

void _s_free(void * ptr)
{SYSCALLV(free(ptr))}

off_t _s_lseek(int fn,off_t o,int m)
{SYSCALLRET(lseek(fn,o,m),off_t)}

int _s_close(int fno)
{SYSCALLRET(close(fno),int)}

int _s_dup(int fno)
{SYSCALLRET(dup(fno),int)}

/*
int _s_dup2(int f,int e)
{return dup2(f,e);} */

int _s_open(const char * n,int io, int md)
{SYSCALLRET(open(n,io,md),int)}

int _s_creat(const char *n,int md)
{SYSCALLRET(creat(n,md),int)}

/*
int _s_fdmode(int f,int m)
{return fdmode(f,m);} */

/*
int _s_iomode(int f,int m)
{return iomode(f,m);} */

/*
int _s_fcntl(int f,int a , int b)
{return fcntl(f,a,b);} */

/*
int _s_opene(const char * nm,mode_t m,int i)
{return _s_opene(nm,m,i);} */

int _s_read(int fn,void * buf,unsigned s)
{SYSCALLRET(read(fn,buf,s),int)}

int _s_write(int fn,void * buf,unsigned s)
{SYSCALLRET(write(fn,buf,s),int)}





