/*
    PIP - Platform Independent Primitives
    Signals
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "pisignals.h"

#include "piincludes.h"
#ifdef BLACKBERRY
#  include <signal.h>
#else
#  include <csignal>
#endif
#ifdef WINDOWS
#  define SIGUSR1 10
#  define SIGUSR2 12
#endif

PISignals::SignalEvent PISignals::ret_func;


void PISignals::grabSignals(PIFlags<PISignals::Signal> signals_) {
	if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), PISignals::signal_event);
	if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), PISignals::signal_event);
	if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), PISignals::signal_event);
	if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), PISignals::signal_event);
	if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), PISignals::signal_event);
	if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), PISignals::signal_event);
#ifndef CC_VC
	if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), PISignals::signal_event);
	if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), PISignals::signal_event);
#endif
#ifndef WINDOWS
	if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), PISignals::signal_event);
	if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), PISignals::signal_event);
	if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), PISignals::signal_event);
	if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), PISignals::signal_event);
	if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), PISignals::signal_event);
	if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), PISignals::signal_event);
	if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), PISignals::signal_event);
	if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), PISignals::signal_event);
	if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), PISignals::signal_event);
	if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), PISignals::signal_event);
	if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), PISignals::signal_event);
#endif
}


void PISignals::releaseSignals(PIFlags<Signal> signals_) {
	if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), SIG_DFL);
	if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), SIG_DFL);
	if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), SIG_DFL);
	if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), SIG_DFL);
	if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), SIG_DFL);
	if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), SIG_DFL);
#ifndef CC_VC
	if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), SIG_DFL);
	if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), SIG_DFL);
#endif
#ifndef WINDOWS
	if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), SIG_DFL);
	if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), SIG_DFL);
	if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), SIG_DFL);
	if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), SIG_DFL);
	if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), SIG_DFL);
	if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), SIG_DFL);
	if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), SIG_DFL);
	if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), SIG_DFL);
	if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), SIG_DFL);
	if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), SIG_DFL);
	if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), SIG_DFL);
#endif
}


void PISignals::raiseSignal(PISignals::Signal signal) {
	raise(signalCode(signal));
}


int PISignals::signalCode(PISignals::Signal signal) {
	switch (signal) {
	case PISignals::Interrupt: return SIGINT;
	case PISignals::Illegal: return SIGILL;
	case PISignals::Abort: return SIGABRT;
	case PISignals::FPE: return SIGFPE;
	case PISignals::SegFault: return SIGSEGV;
	case PISignals::Termination: return SIGTERM;
#ifndef CC_VC
	case PISignals::UserDefined1: return SIGUSR1;
	case PISignals::UserDefined2: return SIGUSR2;
#endif
#ifndef WINDOWS
	case PISignals::Hangup: return SIGHUP;
	case PISignals::Quit: return SIGQUIT;
	case PISignals::Kill: return SIGKILL;
	case PISignals::BrokenPipe: return SIGPIPE;
	case PISignals::Timer: return SIGALRM;
	case PISignals::ChildStopped: return SIGCHLD;
	case PISignals::Continue: return SIGCONT;
	case PISignals::StopProcess: return SIGSTOP;
	case PISignals::StopTTY: return SIGTSTP;
	case PISignals::StopTTYInput: return SIGTTIN;
	case PISignals::StopTTYOutput: return SIGTTOU;
#endif
	default: break;
	}
	return 0;
}


PISignals::Signal PISignals::signalFromCode(int signal) {
	switch (signal) {
	case SIGINT: return PISignals::Interrupt;
	case SIGILL: return PISignals::Illegal;
	case SIGABRT: return PISignals::Abort;
	case SIGFPE: return PISignals::FPE;
	case SIGSEGV: return PISignals::SegFault;
	case SIGTERM: return PISignals::Termination;
#ifndef CC_VC
	case SIGUSR1: return PISignals::UserDefined1;
	case SIGUSR2: return PISignals::UserDefined2;
#endif
#ifndef WINDOWS
	case SIGHUP: return PISignals::Hangup;
	case SIGQUIT: return PISignals::Quit;
	case SIGKILL: return PISignals::Kill;
	case SIGPIPE: return PISignals::BrokenPipe;
	case SIGALRM: return PISignals::Timer;
	case SIGCHLD: return PISignals::ChildStopped;
	case SIGCONT: return PISignals::Continue;
	case SIGSTOP: return PISignals::StopProcess;
	case SIGTSTP: return PISignals::StopTTY;
	case SIGTTIN: return PISignals::StopTTYInput;
	case SIGTTOU: return PISignals::StopTTYOutput;
#endif
	default: break;
	}
	return PISignals::Termination;
}


void PISignals::signal_event(int signal) {
	if (!PISignals::ret_func) return;
	PISignals::ret_func(PISignals::signalFromCode(signal));
}
