/* sigaction() for MiNT; placed in the public domain */

#include <errno.h>
#include <osbind.h>
#include <mintbind.h>
#include <signal.h>

/* vector of signal handlers (for TOS, or for MiNT with -mshort) */
extern __Sigfunc _sig_handler[NSIG];

#ifdef __MSHORT__
typedef void __CDECL (*__KerSigfunc) __PROTO((long));
__EXTERN void __CDECL _trampoline __PROTO((long sig));
#else
typedef void __CDECL (*__KerSigfunc) __PROTO((int));
#endif

int
sigaction(sig, act, oact)
	int sig;
	const struct sigaction *act;
	struct sigaction *oact;
{
	long r;
	extern int __mint;
	__Sigfunc oldfunc;

	if (__mint >= 95) {
		struct ksigact {
			__KerSigfunc	sa_handler;	/* pointer to signal handler */
			long		sa_mask;	/* additional signals masked during delivery */
			union {
				short	kernel;
				int		posix;
			} sa_flags;		/* signal specific flags, kernel */
		} temp;
		
#ifdef __MSHORT__
/* NOTE: MiNT passes 32 bit numbers for signals, so we want our
 * own signal dispatcher to switch these to 16 bit ints
 */
		if (sig < 0 || sig >= NSIG) {
			errno = ERANGE;
			return -1;
		}
		oldfunc = _sig_handler[sig];
		if (act) {
			temp = *(struct ksigact *)act;
			_sig_handler[sig] = (__Sigfunc)temp.sa_handler;
			if (_sig_handler[sig] != SIG_DFL && _sig_handler[sig] != SIG_IGN) {
				temp.sa_handler = _trampoline;
			}
			act = (struct sigaction *)&temp;
		}
#else
		if (act) {
			temp = *(struct ksigact *)act;	/* dept. of sleaze */
			temp.sa_flags.kernel = temp.sa_flags.posix;
			act = (struct sigaction *)&temp;
		}
#endif
		r = Psigaction(sig, act, oact);
#ifdef __MSHORT__
		if (oact && oact->sa_handler == (__Sigfunc) _trampoline)
			oact->sa_handler = oldfunc;
#else
		if (oact)
			oact->sa_flags = ((struct ksigact *)oact)->sa_flags.kernel;
#endif
		if (r < 0) {
			errno = (int) -r;
			return -1;
		}
	}
	else {
		if (act)
			oldfunc = signal(sig, act->sa_handler);
		else {
			long omask;

			omask = sigblock(sig);
			oldfunc = signal(sig, SIG_DFL);
			signal(sig, oldfunc);	/* need to put it back */
			sigsetmask(omask);	/* may remask sig (this is what we want) */
		}
		if (oldfunc == SIG_ERR)
			return -1;
		if (oact) {
			oact->sa_handler = oldfunc;
			/* we could do something useful with sa_mask when __mint */
			oact->sa_flags = 0;
			oact->sa_mask = 0;
		}
	}
	return 0;
}
