/*
  (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
  See the copyright notice in the ACK home directory, in the file "Copyright".
*/

/*
  Module:	default modula-2 trap handler
  Author:	Ceriel J.H. Jacobs
  Version:	$Id$
*/
#include <em_abs.h>
#include <m2_traps.h>
#include <signal.h>
#include "libm2.h"

static struct errm
{
	int errno;
	char* errmes;
} errors[] = { { EARRAY, "array bound error" },
	           { ERANGE, "range bound error" },
	           { ESET, "set bound error" },
	           { EIOVFL, "integer overflow" },
	           { EFOVFL, "real overflow" },
	           { EFUNFL, "real underflow" },
	           { EIDIVZ, "divide by 0" },
	           { EFDIVZ, "divide by 0.0" },
	           { EIUND, "undefined integer" },
	           { EFUND, "undefined real" },
	           { ECONV, "conversion error" },

	           { ESTACK, "stack overflow" },
	           { EHEAP, "heap overflow" },
	           { EILLINS, "illegal instruction" },
	           { EODDZ, "illegal size argument" },
	           { ECASE, "case error" },
	           { EMEMFLT, "addressing non existent memory" },
	           { EBADPTR, "bad pointer used" },
	           { EBADPC, "program counter out of range" },
	           { EBADLAE, "bad argument of lae" },
	           { EBADMON, "bad monitor call" },
	           { EBADLIN, "argument if LIN too high" },
	           { EBADGTO, "GTO descriptor error" },

	           { M2_TOOLARGE, "stack size of process too large" },
	           { M2_TOOMANY, "too many nested traps + handlers" },
	           { M2_NORESULT, "no RETURN from function procedure" },
	           { M2_UOVFL, "cardinal overflow" },
	           { M2_FORCH, "(warning) FOR-loop control variable was changed in the body" },
	           { M2_UUVFL, "cardinal underflow" },
	           { M2_INTERNAL, "internal error; ask an expert for help" },
	           { M2_UNIXSIG, "got a unix signal" },
	           { -1, 0 } };

void catch (int trapno)
{
	register struct errm* ep = &errors[0];
	char* errmessage;
	char buf[20];
	register char *p, *s;

	while (ep->errno != trapno && ep->errmes != 0)
		ep++;
	if (p = ep->errmes)
	{
		while (*p)
			p++;
		_Traps__Message(ep->errmes, 0, (int)(p - ep->errmes), 1);
	}
	else
	{
		int i = trapno;
		static char q[] = "error number xxxxxxxxxxxxx";

		p = &q[13];
		s = buf;
		if (i < 0)
		{
			i = -i;
			*p++ = '-';
		}
		do
			*s++ = i % 10 + '0';
		while (i /= 10);
		while (s > buf)
			*p++ = *--s;
		*p = 0;
		_Traps__Message(q, 0, (int)(p - q), 1);
	}
#if !defined(__em24) && !defined(__em44) && !defined(__em22)
	if (trapno == M2_UNIXSIG)
	{
		extern int __signo;
		signal(__signo, SIG_DFL);
		_cleanup();
		kill(getpid(), __signo);
		_exit(trapno + 1);
	}
#endif
	if (trapno != M2_FORCH)
	{
		_cleanup();
		_exit(trapno + 1);
	}
	SIG(catch);
}