/*
 *                        --- EON SOFTWARE ---
 *
 *         19 Stapleton Road. Headington. Oxford. OX3 7LX UK.
 *                   Phone or Fax: +44 (0)865 741452
 *                    eMail: eonsw@eonsw.demon.co.uk
 *
 *                   Eon/Eiffel (c) 1994 Eon Software
 *     This is the unpublished proprietary source code of Eon Software
 *
 *             See the accompanying NOTICE file for details.
*/

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

#define HAS_LONGJMP			/* longjmp implemented */
#define CAN_HACK_C_TO_CPP	/* Pass current object as first argument */

#ifdef NO_SAFE_SIGNALS
#define sigset signal
#endif

#ifdef HAS_LONGJMP
#include <setjmp.h>
#endif

int okay = 0;

extern "C" {

#ifdef HAS_LONGJMP
struct {
	jmp_buf jmpenv;
	void *addr;
} Env;
#endif

struct {
	char *mess;
	void (*isr)(...);
	int mode;				/* 1:Continue  2:Exit */
} Signals[3] = { 	"Bad signal number", 0, 1,
				"Hangup", 0,  1,
		   		"Keyboard", 0, 1,
};
	

void 
global_error_handler(int n) 
{
	printf ( "INTERRUPT (%s) %x\n", Signals[n].mess, n);
	if ( n == SIGINT) {
		printf ( "Received SIGINT in C scope okay\n");
		okay++;
	}

#ifdef CAN_HACK_C_TO_CPP
	Signals[n].isr(Env.addr, n);
#else
	Signals[n].isr(n);
#endif

#ifdef NO_SAFE_SIGNALS
	signal ( SIGINT, global_error_handler);
#endif

#ifdef HAS_LONGJMP
	if ( Signals[n].mode) {
		sigset ( SIGINT, global_error_handler);
		longjmp ( Env.jmpenv, 1);
	}
#else
	printf ( "Terminating\n");
	exit ( 1);
#endif
}
}



class X {

public:

	void
	test() {

#ifdef HAS_LONGJMP
   		if ( setjmp ( Env.jmpenv))
      		goto _rescue;

		Env.addr = this;
		printf ( "Class address: %x\n", this);
#endif


_restart:
		Signals[SIGINT].isr = (void(*)(...)) &xisr;
		Signals[SIGINT].mode = Signals[SIGINT].mode ? 0 : 1;

		printf ( "Mode: %d\n", Signals[SIGINT].mode);
		printf ( "Hit DEL/^C now, ENTER to end "); fflush ( stdout);

		if ( getchar () != '\n') {
			if ( Signals[SIGINT].mode == 1)
				printf ( "*** SHOULDN'T BE HERE 0 longjmp() failed ***\n");
	
			printf ( "Try again\n");
			goto _restart;

		}

		return;
_rescue:
		printf ( "RESCUE\n");
		goto _restart;
	}

	void xisr(int n) {
		printf ( "C++ INTERRUPT (%s) %x\n", Signals[n].mess, n);
		if ( n == SIGINT) {
			printf ( "Received SIGINT n C++ scope okay\n");
			okay++;
		}

		printf ( "\n\n");
		if ( okay != 2)
			printf ( "**** FAILED ****\n");
		else
			printf ( "Passed test okay\n");

		okay = 0;

	}


};

int
main()
{
	X *x;

	printf ( "\nThis is a test program to establish if a C++ compiler\n");
	printf ( "  passes a class address as it's first argument and picks\n");
	printf ( "  up the signal number correctly.\n\n");
	printf ( "If it doesn't EON/Eiffel exceptions will not work\n");
	printf ( "  for signal() style interrupts.\n");
	printf ( "To test, hit the keyboard interrupt a few times and make\n");
	printf ( "  sure that there are no error messages.\n");
	printf ( "\n\n\n");

	sigset ( SIGINT, global_error_handler);
	x = new X;

	/*signal ( SIGINT, (void (*)(int)) I);*/

	x->test ();

	return 0;
}

