// -*- C++ -*-
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <sigtable.h>

#include <ert.H>

#include <any.H>
#include <core.H>
#include <string.H>
#include <array.H>
#include <except.H>

#include <stdlib.h>

#ifdef _TCC_
#include <setjmp.h>
#include <io.h>
#endif

#undef TRACE_STRING_CONSTANTS

int _ert_trace_mode = 0;
int _ert_debug_mode = 0;
int _ert_trace_depth = 0;
int _ert_signaled = 0;
int _ert_expand = 0;
int _ert_in_assertion = 0;
int _ert_exitcode = 1;		/* Set in except.e */

int _ert_depth = 0;
_ERT_ENV _ert_cenv[_ERT_JMP_MAX];
static void _ert_global_error_handler(int);

extern "C" {

   static int hash_string ( unsigned char*);

   INTEGER c_strcmp(POINTER,POINTER);
   char c_readchar(INTEGER);
   char* c_readline(INTEGER);
   INTEGER c_readint (int);
   REAL c_readreal(int);
   char* c_readstream(int,int);
   void c_next_line(int);
   void c_putint (INTEGER,INTEGER);
   INTEGER c_atoi ( POINTER);
   void c_itoa ( POINTER, INTEGER);
   void c_rtoa ( POINTER, REAL);
   void c_dtoa ( POINTER, DOUBLE);
   void c_btoa ( POINTER, BOOLEAN);
   int c_address_of ( POINTER);
   int c_file_open ( INTEGER, POINTER);
   POINTER c_alloc ( INTEGER);

#ifdef _TCC_
   int   strlen ( char *);
   char *strcpy ( char *, char *);
   char *strcat ( char *, char *);
   int   strcmp ( const char *, const char *);
   int   memcpy ( char *, char *, int);
   int   memcmp ( char *, char *, int);
   void  memset ( char *, int, int);
#endif

};


void _fatal_signal ( int);

typedef struct _S_ERT_CACHE_ {
   	STRING* str;
   	struct _S_ERT_CACHE_ *next;
} _ERT_CACHE_;

_ERT_CACHE_ *
   _ert_cache[MAX_CONST_STRINGS]; /* max. *cached* constant strings in system */

ARRAY*
_ert_make_array (int elements, ...)
{
	register i;
   	static ARRAY* result;
   	void* data;
   	va_list ap;

   	va_start ( ap, elements);

   	result = new ARRAY;
   	result->make ( 1, elements);
   
   	for ( i = 1; i <= elements; i++) {
      	data = va_arg ( ap, void*);
      	result->put ( (ANY*)data, i);
   	}

   	va_end ( ap);

   	return result;
}

ARRAY*
_ert_make_array_from_nv ( int argc, char *argv[])
{
	register i;
   	static ARRAY* result;
	STRING *str;

   	result = new ARRAY;
   	result->make ( 1, argc - 1);	

   	for ( i = 1; i < argc; i++) {
      	str = _ert_new_string ( (POINTER)argv[i]);
		result->put ( (ANY*)str, i);
   	}

   	return result;
}

ANY*
_ert_array_item ( POINTER area, INTEGER index)
{
	ANY *p;
	void **DATA_PTR = (void **) area;

	p = (ANY*) DATA_PTR[index];

   	return p;
}

void
_ert_array_put ( POINTER area, INTEGER index, ANY* data)
{
	char **DATA_AREA = (char **) area;

	DATA_AREA[index] = (char *) data;
}

/*
 * I/O interface
 *
 * Several of these could be direct calls to the C library but there are 
 * prototyping problems.
*/

INTEGER
c_open ( POINTER file_name, INTEGER mode)
{
	return open ( (char *) file_name, mode);
}

void
c_close ( INTEGER fd)
{
	close ( fd);
}

/*
INTEGER
c_read ( INTEGER fd, POINTER file_buffer, INTEGER len)
{
	return read ( fd, file_buffer, len);
}

INTEGER
c_write ( INTEGER fd, POINTER file_buffer, INTEGER len)
{
	return write ( fd, file_buffer, len);
}
*/

INTEGER
c_strlen ( POINTER s)
{
   return strlen ( (char*)s);
}

char
c_item ( POINTER s, INTEGER i)
{
   char* ptr;
   ptr = (char*)s;
   return ptr[i-1];
}

void
c_putstring ( INTEGER fd, POINTER buf)
{
   char* s;

   s = (char*)buf;

   (void)write ( fd, s, strlen ( s));
}

void
c_putchar ( INTEGER fd, char c)
{
   char c_buf[2];

   sprintf ( c_buf, "%c", c);

   (void)write ( fd, c_buf, strlen ( c_buf));
}

void
c_putint ( INTEGER fd, INTEGER i)
{
   char i_buf[12];

   sprintf ( i_buf, "%d", i);

   (void)write ( fd, i_buf, strlen ( i_buf));
}

void
c_putreal ( INTEGER fd, float d)
{
   	char d_buf[30];

	if ( d > 1000000.0)
   		sprintf ( d_buf, "%g", d);
	else
   		sprintf ( d_buf, "%f", d);

   	(void)write ( fd, d_buf, strlen ( d_buf));
}

void
c_putdouble ( INTEGER fd, double d)
{
   	char d_buf[30];

	if ( d > 1000000.0)
   		sprintf ( d_buf, "%g", d);
	else
   		sprintf ( d_buf, "%f", d);

   	(void)write ( fd, d_buf, strlen ( d_buf));
}

char
c_readchar ( INTEGER fd)
{
   char result[1];

   read ( fd, result, 1);

   return result[0];
}

static char _ert_input_buffer[1024];

char*
c_readline ( INTEGER fd)
{
   char c;
   int i;

   i = 0;
   do {
      if ( read ( fd, &c, 1) != 1)
         c = '\0';
      else
         if ( c == '\n')
            c = '\0';
      if ( c != '\0')
         _ert_input_buffer[i++] = c;
   } while ( i < sizeof(_ert_input_buffer) - 1 && c != '\n' && c != '\0');
   _ert_input_buffer[i] = '\0';

   return _ert_input_buffer;
}

int
c_readint ( int fd)
{
   int result;

/*
 * this should use "PLATFORM.Integer_bits", and also do byte-swapping when
 * appropriate
 */
   read ( fd, (char*)&result, sizeof ( result));

   return result;
}

REAL
c_readreal ( int fd)
{
   REAL result;

/*
 * this should use "PLATFORM.Real_bits", and also do byte-swapping when
 * appropriate
 */
   read ( fd, (char*)&result, sizeof ( result));

   return result;
}

DOUBLE
c_readdouble ( int fd)
{
   DOUBLE result;

/*
 * this should use "PLATFORM.Double_bits", and also do byte-swapping when
 * appropriate
 */
   read ( fd, (char*)&result, sizeof ( result));

   return result;
}

char*
c_readstream ( int fd, int len)
{
   char c;
   int i;

   i = 0;
   do {
      if ( read ( fd, &c, 1) != 1)
         c = '\0';
      else
         _ert_input_buffer[i++] = c;
   } while ( i < sizeof(_ert_input_buffer) && i < len && c != '\0');
   _ert_input_buffer[i] = '\0';

   return _ert_input_buffer;
}

void
c_next_line ( int fd) 
{
   char c;

   do {
      if ( read ( fd, &c, 1) != 1)
         c = '\0';
   } while ( c != '\n' && c != '\0');
}

/*
 * Strings
*/

STRING*
_ert_new_string ( POINTER s)
{
   	static STRING* result;
   	CORE* core;
   	int i, n, hashval;
     _ERT_CACHE_ *np;

	hashval = hash_string ( (unsigned char *) s);

     for ( np = _ert_cache[ hashval]; np; np = np->next)
          if ( !strcmp( (char *)s, (char *)np->str->space->space))
               return np->str;
	
   	result = new STRING;
/*
 *
 * Theoretically, this routine could now call "result->make_from_c ( s)" to
 * set the value of the result string.  But if assertion checking/tracing is
 * in use, then there is the danger that this routine will be called from the
 * argument display code, leading to infinite recursion.  The solution here
 * is to access STRING's read-only (in Eiffel, anyway) attributes to perform
 * the same action as `make_from_c'.  This is legal in C++ but not in Eiffel.
 */

/*
 * inline version of `make_from_c'
*/
   	n = strlen ( (char*)s);
   	core = new CORE;
   	core->allocate ( n+1);
   	core->capacity = n + 1;

   	c_strset ( core->space, s);
   	result->space = core;

     np = (_ERT_CACHE_ *) malloc ( (unsigned int) sizeof( _ERT_CACHE_));

     np->str = result;
	np->next = _ert_cache[hashval];
     _ert_cache[hashval] = np;

   	return result;
}

void 
c_strset ( POINTER tgt, POINTER src)
{

   	_eiffel_rt_Assert ( EXCEPT_PRECONDITION, "(eiffel_rt)",
			"valid destination", "c_strset", tgt != 0, _ert_longjmp());

	_eiffel_rt_Assert ( EXCEPT_PRECONDITION, "(eiffel_rt)",
			"valid source", "c_strset", src != 0, _ert_longjmp());

	(void)strcpy ( (char*)tgt, (char*)src);
}

void 
c_strcat ( POINTER tgt, POINTER src)
{
   	_eiffel_rt_Assert ( EXCEPT_PRECONDITION, "(eiffel_rt)", "valid source", 
			"c_strcat", src != 0, _ert_longjmp());

   	_eiffel_rt_Assert ( EXCEPT_PRECONDITION, "(eiffel_rt)", 
			"valid destination", "c_strcat", src != 0, _ert_longjmp());

   	(void)strcat ( (char*)tgt, (char*)src);
}

int
c_file_open ( INTEGER mode, POINTER filename)
{
   	return open ( (char*)filename, mode);
}

INTEGER
c_strcmp ( POINTER s1, POINTER s2)
{
   	return strcmp ( (const char*)s1, (const char*)s2);
}

INTEGER
c_atoi ( POINTER sp)
{
   return atoi ( (char *) sp);
}

void
c_itoa ( POINTER sp, INTEGER value)
{
   sprintf ( (char*)sp, "%d", value);
}

void
c_rtoa ( POINTER sp, REAL value)
{
   sprintf ( (char*)sp, "%f", value);
}

void
c_dtoa ( POINTER sp, DOUBLE value)
{
   sprintf ( (char*)sp, "%f", value);
}

void
c_btoa ( POINTER sp, BOOLEAN value)
{
   sprintf ( (char*)sp, "%s", value == true ? "true" : "false");
}

int
c_address_of ( POINTER sp)
{
	return (int) sp;
}

POINTER
c_alloc ( INTEGER nb)
{
   	static POINTER result;

   	result = (POINTER)malloc ( nb);

   	if ( result == 0) 
      	_ert_memory_error ( "c_alloc", nb);
   	
   	memset ( (char*)result, 0, nb);

   	return result;
}

void
c_free ( POINTER ptr)
{
	free ( (char *) ptr);
}

void
c_memcpy (POINTER tgt, POINTER src, INTEGER n)
{
   memcpy ( (char *) tgt, (char*)src, n);
}

static int
hash_string( unsigned char *s)
{
     int hashval;

     for(hashval = 0; *s != '\0'; )
          hashval += *s++;

     return hashval % MAX_CONST_STRINGS;
}

/*
 * If a POINTER type has been used as an attribute of a class, it can expect
 * to be _Clone'd. This presents a problem because we can generate the code
 * required to do it automatically (how long is the space it points to?).
 * We must fill in the implementation by hand.
*/

POINTER
_ert_CORE_space_Copy ( CORE *cl)
{
	POINTER p;

	p = (POINTER) c_alloc ( cl->capacity);
	memcpy ( (char *) p, (char *) cl->space, cl->capacity);

	return p;
}

POINTER
_ert_GENERAL_c_object_address_Copy ( GENERAL *cl)
{
	return (POINTER) cl;
}

POINTER
_ert_GENERAL_c_class_name_Copy ( GENERAL *cl)
{
	POINTER p;
	int l = strlen ( (char *) cl->c_class_name);

	p = c_alloc ( l + 1);
	memcpy ( (char *) p, (char *) cl->c_class_name, l);

	return p;
}

/*
 * Misc
*/

INTEGER
_ert_errno()
{
	extern int errno;

	return errno;
}

/*
 * Initialiasation
 *
 * _ert_initialise  --  set-up Eiffel run-time environment
*/

void
_ert_initialise( int trace_onoff, char *execname)
{
	_ert_exception_init ( trace_onoff, execname);
}

void
_ert_terminate ( int trace_onoff)
{
#ifdef _ERT_TRACE
	if ( trace_onoff) 
		_ert_close_trace ();
#endif
}

void 
_ert_set_exitcode(int code)
{
	_ert_exitcode = code;
}

void
_ert_set_trace_mode ()
{
	char *p;

   	if ( (p = getenv ( "EON_TRACE")) != (char *) 0)
   		_ert_trace_mode = atoi ( p);
	else
   		_ert_trace_mode = 0;
}

void
_ert_set_debug_mode ()
{
   	if ( getenv ( "EON_DEBUG") != (char *) 0)
   		_ert_debug_mode = 1;
	else
   		_ert_debug_mode = 0;
}

_set_class_assert ( int assertions)
{
	char *p;

	if ( (p = getenv ( "EON_ASSERT")) != (char *) 0) {
		
		if  ( *p)
			assertions = 0;

	  	while ( *p) switch ( *p++) {

			case 'r':
		   		assertions |= A_REQUIRE;
		   		break;
			case 'e':
		   		assertions |= A_ENSURE;
		   		break;
			case 'i':
		   		assertions |= A_INVARIANT;
		   		break;
			case 'l':
		   		assertions |= A_LOOP;
		   		break;
			case 'c':
		   		assertions |= A_CHECK;
		   		break;
			case 'n':
		   		assertions |= A_NONE;
		   		break;
			case 'a':
		   		assertions |= A_ALL;
		   		break;
	  	}

		if ( assertions & A_ALL)
			assertions = A_REQUIRE | A_ENSURE |
				A_INVARIANT | A_LOOP | A_CHECK;
		else if ( assertions & A_NONE)
			assertions = 0;

	}

	return assertions;
}

POINTER
_ert_object_address ( void* obj)
{
   static char buf[12];
   sprintf ( buf, "0x%x", (int)obj);
   return (POINTER)buf;
}

/*
 * BIBT Functions
 */

STRING*
_bibt_CHARACTER_out ( CHARACTER c)
{
   char buf[3];
   
   sprintf ( buf, "%c", c);

   return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_INTEGER_out ( INTEGER i)
{
   	char buf[12];
   
   	sprintf ( buf, "%d", i);

   	return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_REAL_out ( REAL r)
{
   char buf[12];
   
   sprintf ( buf, "%f", r);

   return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_DOUBLE_out ( DOUBLE r)
{
   char buf[12];
   
   sprintf ( buf, "%f", r);

   return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_NONE_out ( NONE n)
{
   char buf[12];

   sprintf ( buf, "0x%x", (int)&n);

   return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_POINTER_out ( POINTER n)
{
   char buf[12];

   sprintf ( buf, "0x%x", (int)&n);

   return _ert_new_string ( (POINTER)buf);
}

STRING*
_bibt_BOOLEAN_out ( BOOLEAN b)
{
   	if ( b == true)
      	return _ert_new_string ( (POINTER)"true");

	return _ert_new_string ( (POINTER)"false");
}

#ifdef OLD
void *
_ert_wrap_expr ( int idx, ...)
{
	va_list ap;
	static int n[WRAP_MAX_ARGS];
	static float f[WRAP_MAX_ARGS];
	static double d[WRAP_MAX_ARGS];
	int id;

	va_start ( ap, idx);

	id = va_arg ( ap, int);

	switch ( id) {

		case -7:			/* REAL */
			f[idx]= va_arg ( ap, double);	    /* NEEDS TO BE DOUBLE ?? */
			return &f[idx];
		case -8:			/* DOUBLE */
			d[idx] = va_arg ( ap, double);
			return &d[idx];

	}

	va_end ( ap);

	return 0;
}
#endif

#ifndef CHAR_MAX
# include <limits.h>
#endif

/*
 * functions used in PLATFORM
*/

INTEGER _ert_char_size() { return sizeof ( CHARACTER) * 8; }
INTEGER _ert_int_size() { return sizeof ( INTEGER) * 8; }
INTEGER _ert_real_size() { return sizeof ( REAL) * 8; }
INTEGER _ert_double_size() { return sizeof ( DOUBLE) * 8; }
INTEGER _ert_ptr_size() { return sizeof ( POINTER) * 8; }
INTEGER _ert_max_char() { return CHAR_MAX; }


/****
 **** Exceptions
****/

/*
* Flags and things that are used in the exception scheme
*/

static BOOLEAN _ert_flag_assertion_violation;	/* starts in unknown state */
static int except_modes[EXCEPT_MAX];
static int except_type;
static void * except_addr;
static char *except_class, *except_routine, *except_tag, *except_cond;
int _ert_show_traceback = true;
static int original_type = 0;
static char *original_name = 0, *original_class = 0;
static int show_trace_immediate = false;

void 
_ert_show_trace_on_failure(void)
{
	_ert_show_traceback = true;
}

void 
_ert_no_show_trace_on_failure(void)
{
	_ert_show_traceback = false;
}
void 
_ert_show_trace(void)
{	
	show_trace_immediate = true;
}

void 
_ert_no_show_trace(void)
{	
	show_trace_immediate = false;
}

void
_ert_except_mode ( int code, int mode)
{
	if ( code > 0 && code < EXCEPT_BUILTIN) {

		switch ( mode) {
			case EXCEPT_CONTINUE:
				sigset ( code, _ert_global_error_handler);
				signals[code].ssr_mode = 1;
				break;
			case EXCEPT_IGNORE:
				sigset ( 
						code, 
								SIG_IGN);
				signals[code].ssr_mode = 0;
				break;
			case EXCEPT_CATCH:
				sigset ( code, _ert_global_error_handler);
				signals[code].ssr_mode = 0;
				break;
		}
	}

	except_modes[code + EXCEPT_OFFSET] = mode;
}

int
_ert_except_status ( int code)
{
	return except_modes [ code + EXCEPT_OFFSET];
}

int
_ert_original_exception(void)
{
	return original_type;
}

STRING *
_ert_last_exception_name ()
{
	static STRING *str = (STRING *) 0;
	
	if ( original_class) {
		if ( str == ( STRING *) 0)
			str = _ert_new_string ( original_class);
		else 
			str->make_from_c ( original_class);
	} else
		str = (STRING *) 0;
		
	return str;
}

STRING *
_ert_routine_name(void)
{
	static STRING *str = (STRING *) 0;
	
	if ( original_name) {
		if ( str == ( STRING *) 0)
			str = _ert_new_string ( original_name);
		else 
			str->make_from_c ( original_name);
	} else
		str = (STRING *) 0;
		
	return str;
}

STRING *
_ert_tag_name(void)
{
	static STRING *str = (STRING *) 0;
	
	if ( except_tag) {
		if ( str == ( STRING *) 0)
			str = _ert_new_string ( except_tag);
		else 
			str->make_from_c ( except_tag);
	} else
		str = (STRING *) 0;
		
	return str;
}

STRING *
_ert_void_call_target(void)
{
	static STRING *str = (STRING *) 0;

	return str;
}


/* 
 * This is in the runtime rather than in the class code because g++ core-dumps
 * if longjmp() and setjmp() are in the function. It also make the invariant
 * assertion marginaly easier.
*/

void
_ert_longjmp()
{
	if ( _ert_depth)
		longjmp ( _ert_cenv[ _ert_depth - 1].jmpenv, 1);
}

int
_ert_last_exception()
{
	return except_type;
}

BOOLEAN
_ert_assertion_violation()
{
	return _ert_flag_assertion_violation;
}

void
_ert_reset_all_default()		/* Reset exception handlers */
{
	_ert_exception_init( 0, 0);
}

void
_ert_reset_default(int code)		/* Reset exception handler for `code'*/
{
	if ( signals[code].ssr_catch)	{
		sigset ( code, _ert_global_error_handler);
		signals[code].ssr_mode = 1;
	}

	except_modes[code + EXCEPT_OFFSET] = EXCEPT_CATCH;

}

void
_ert_exception_init( int trace_onoff, char *exec_name)
{
	register i;

/*
 * Don't confuse this with the eiffel Caught/Ignored thing.
 * This overrides signals() settings determined by the calling shell.
*/
	for ( i = 0; i < sizeof ( signals)/sizeof ( struct sig_table); i++)
		if ( signals[i].ssr_catch) {
			sigset ( i, _ert_global_error_handler);
			signals[i].ssr_mode = 1;
		}

	for ( i = 0; i < EXCEPT_MAX + EXCEPT_OFFSET; i++)
		except_modes[i] = EXCEPT_CATCH;

#ifdef _ERT_TRACE
	if ( trace_onoff)
		_ert_open_trace ( exec_name);
#endif
}

/* 
 * Raise an exception from a violated assertion or some non-user-specified
 * exception
*/

void
_ert_trace_log ( char *rec_class, char *rec_routine, int rcode, int depth)
{
	_trace_write_log ( rec_class, rec_routine, except_addr, except_type, 
		except_class, except_routine, 
				except_tag, except_cond, rcode, depth);

	if ( rcode == EXCEPT_FAIL) {
		if ( !original_type) {
			original_type = except_type;
			original_name = except_routine;
			original_class = except_class;
		}
	} else
		original_type = 0, original_class = original_name = 0;
}

void
_ert_raise ( int type, char *class_name, char *routine, char *tag, char *cond)
{
	except_type = type;				/* Record so the can be logged */
#ifdef _ERT_TRACE
	except_class = class_name;		/* by the routine receiving */
	except_routine = routine;		/* the exception */
	except_tag = tag;
	except_cond = type == EXCEPT_ROUTINE_FAILURE ? 0 : cond;
	except_addr = (void*) _ert_cenv[ _ert_depth - 1].caddr;
#endif


	if ( type < 0) {
		if ( except_modes[ type * -1] == EXCEPT_IGNORE)
			return;
	} else {
		if ( except_modes[ type + EXCEPT_OFFSET] == EXCEPT_IGNORE)
			return;
	}

	if ( show_trace_immediate) {
		if ( class_name)
			printf ( "Exception(%d): \"%s.%s\": %s %s %s\n", type, 
				class_name, routine, _ert_except_mesg ( type)->to_c(), 
				tag ? tag : "<none>", cond ? cond : "<none>");
		else
			printf ( "Signal: \"%s\" %s\n", tag, cond);
	}

	switch ( type) {
	
		case EXCEPT_PRECONDITION:
		case EXCEPT_POSTCONDITION:
		case EXCEPT_INVARIANT: 
			_ert_flag_assertion_violation = true;
			break;
		default:
			_ert_flag_assertion_violation = false;
			break;
	}
}

void
_ert_raise_developer_exception(int code)
{
	_ert_raise ( code, "<Unknown>", "<Unknown>", 0, 0);
	_ert_depth -= 2;	/* This is a cheat becuase we know we are two */
	_ert_longjmp ();	/* routines deep */
}
	
STRING *
_ert_except_mesg ( int n)
{
	char tmp[25], *m;
	static STRING *str = (STRING *) 0;

	switch ( n) {

		case EXCEPT_PRECONDITION:
			m = "Precondition"; break;
		case EXCEPT_POSTCONDITION:
			m = "Postcondition"; break;
		case EXCEPT_INVARIANT:
			m = "Class invariant"; break;
		case EXCEPT_LOOP_INVARIANT:
			m =  "Loop invariant"; break;
		case EXCEPT_LOOP_VARIANT:
			m = "Loop variant"; break;
		case EXCEPT_ROUTINE_FAILURE:
			m = "Routine failure"; break;
		case EXCEPT_VOID_TARGET_CALL:
			m = "Void target call"; break;
		case EXCEPT_NO_MORE_MEMORY:
			m = "No more memory"; break;
		case EXCEPT_CALL_TO_DEFERRED:
			m = "Call to deferred feature"; break;
		case EXCEPT_BAD_SIGNAL:
			m = "Bad signal number"; break;
		case EXCEPT_NESTED_FUNCTIONS:
			m = "Too many nested functions"; break;
		case EXCEPT_INSPECTION_VALUE:
			m = "Untrapped inspect value"; break;
   		case EXCEPT_ASSIGNED_TO_EXPANDED:
			m = "Assignment of void to an expanded entity"; break;
   		case EXCEPT_ARRAY_TYPE_ERROR:
			m = "Assignment of ARRAY[ANY].item to wrong type"; break;
   		case EXCEPT_RESCUE_FAILED:
			m = "Failure in rescue clause (check last code)"; break;
		default:
			if ( n < 0)
				sprintf ( m = tmp, "Developer exception (%d)", n);
			else if ( n < EXCEPT_BUILTIN)
				sprintf ( m = tmp, "Signal (%d)", n);
			else 
				sprintf ( m = tmp, "Unknown exception (%d)", n);
			break;
	}
	

	
	if ( m) {
		if ( str == ( STRING *) 0)
			str = _ert_new_string ( m);
		else 
			str->make_from_c ( m);
	} else
		str = (STRING *) 0;
		
	return str;
}

static void 
_ert_global_error_handler(int n) 
{
	_ert_raise ( n, 0, 0, signals[n].desc, signals[n].name);

	_ert_signaled = n;

#ifdef NO_SAFE_SIGNALS
	signal ( n, _ert_global_error_handler);
#endif

#ifdef HAS_LONGJMP
	if ( signals[n].ssr_mode) {
		sigset ( n, _ert_global_error_handler);
		longjmp ( _ert_cenv[ _ert_depth - 1].jmpenv, 1);
	}
#else
	_fatal_signal ( n);
#endif
}

/*
 * Signals
 * These declarations don't seem to stay the same for more than a few minutes.
 *
*/

void
_fatal_signal ( int sig)
{
   	printf ( "*** Fatal Signal %s (%s) received\n", signals[sig].name, signals[sig].desc);
   	printf ( "Eiffel call-stack (for monitored routines):\n");
   	_trace_back(1);
}

void
_ert_memory_error ( char* in_routine, int request)
{
	fprintf ( stderr, "*** Memory allocation error in `%s' (%d bytes)\n",
                                                         in_routine, request);
 
   	_trace_back(1);
}

/*
 * Numerical functions
*/

INTEGER 
_ert_INTEGER_POW(double base, int n)
{
	register i;
	int p = 1;

	for ( i = 0; i < n; i++)
		p = p * (INTEGER) base;

	return p;
}
	
REAL    
_ert_REAL_POW(double base, int n)
{
	register i;
	REAL p = 1.0;

	for ( i = 0; i < n; i++)
		p = p * (REAL) base;

	return p;
}

DOUBLE  
_ert_DOUBLE_POW(double base, int n)
{
	register i;
	DOUBLE p = 1.0;

	for ( i = 0; i < n; i++)
		p = p * (DOUBLE) base;

	return p;
}

