/*
 *	mcfktns.c
 */

#include <signal.h>
#include <varargs.h>
#include "os.h"
#include "mcfktns.h"
#include "mclocal.h"
#include "rpcfktns.h"


/*
 * Signal-Steuerung
 */
sigreturntype	((*(sig_save[NSIG+1])) ());	/* +1 damit der Index stimmt; sig_save [0] ist frei */
sigreturntype	(*sig_exception) () = NULL;	/* fuer Exceptions */

void
sig_init()
{
	int	i;
	
	for (i = 1; i <= NSIG; i++) {
		sig_save [i] = signal (i, SIG_DFL);
	}

	if ((sig_exception = signal (SIGILL, SIG_DFL)) == NULL) {
		sig_exception = signal (SIGFPE, SIG_DFL);
	}
	
	return;
}


void
sig_ign()
{
	int	i;
	
	for (i = 1; i <= NSIG; i++) {
		signal (i, SIG_IGN);
	}
	return;
}


void
sig_neu(sig, func)
	int	sig;
	sigreturntype	(*func) ();
{
	if (sig < 0 || sig > NSIG) {
		runtime_error (P_WARN, "Signal %d not available! Ignored!", sig);
	} else {
		sig_save [sig] = func;
	}
}

void
m0_raise(sc)
	m0_shortcard	sc;
{
	if (sig_exception != NULL) {
		errno = sc;
		sig_exception ();
	} else {
		runtime_error (P_INTERN, "m0_raise: RAISE (%u) called without defined Exception Handler (PROCESSID %d, PROCESSNO %d)", (unsigned int) sc, m0_processid, m0_processno);
	}
}


/*
 * Prozess-Identifikation und -Steuerung
 */

	/* Die Variable m0_processid wird beim Start eines Prozesses belegt! */
int	m0_processid = 0;
	/* Die Variable m0_processno wird beim Start eines Prozesses belegt! */
int	m0_processno = 0;


/*
 * Ein-Ausgabe-Funktionen
 */
FILE	*IN_FILE = stdin;
FILE	*OUT_FILE = stdout;
int	done = 0;

unsigned long	read_longunsigned;
long	read_long;
double	read_double;
char	read_stringbuf[257];

char *
get_filename(mode)
	char	*mode;
{
	char	fn[128];

	do {
		printf ("\nFilename for ");

		if (mode [0] == 'w')
			printf ("output? ");
		else
			printf ("intput? ");

		gets (fn);

	} while (strlen (fn) == 0);

	return (fn);
}


/*
 * Weitere Runtime-Funktionen
 */
void
runtime_error(level, fmt, va_alist)
	int	level;
	char	*fmt;
	va_dcl
{
	va_list	pvar;

	va_start (pvar);
	vfprintf (stderr, fmt, pvar);
	fprintf (stderr, "\n");
	va_end (pvar);

	switch (level) {
	case P_INFO:
	case P_WARN:
		return;
	case P_EXCEPTION256:
		/*
	nocht nicht !!!!!!!!!
		m0_raise (256);
		break;
		*/
	case P_INTERN:
		if (strcmp (processtype, "COMMUNICATION") == 0) {
				/* Communication */
			fprintf (stderr, "Execution of the current communication server process is stopped.\n");
			rpc_service_stop_1 (NULL);
		} else {
				/* lokaler Prozess */
			fprintf (stderr, "Execution of the current process is stopped.\nSemaphores and Shared Memory Segments are tried to be deleted!\n");
			modula_p_abort ();
		}
		exit (1);
	default:
		runtime_error (P_INTERN, "Errorlevel invalid!");
	}
}

char
*mk_str(c)
	char	c;
{
	static	int	i = 0;
	static	char	str[16][2];

	i = (i + 1) & 0xF;	/* Inkrement modulo 16 */

	str [i][0] = c;
	
	return (str [i]);
}

char
*mem_save(p, s)
	char	*p;
	int	s;
{
	char	*cp;

	if ((cp = (char *) malloc (s + 1)) == NULL) {
		runtime_error (P_INTERN, "memsave (malloc): No more memory!");
	}

	memcpy (cp, p, s);
	cp [s] = '\0';
	return (cp);
}


char	*
str_save(s, i)
	char	*s;
	int	i;
{
	char	*help;

	if ((help = (char *) malloc (i + 1)) == NULL) {
		runtime_error (P_INTERN, "str_save: No more memory for String '%s' to save", s);
	}

	strncpy (help, s, i);
	help [i] = '\0';
	return (help);
}


long
range_check(v, lb, hb, line, filename)
	long	v, lb, hb;
	int	line;
	char	*filename;
{
	if (v < lb || v > hb) {
		if (sig_exception != NULL) {
			errno = EDOM;
			sig_exception ();
			return (0);
		} else {
			runtime_error (P_INTERN, "range_check (\"%s\" line %d): 0x%lx out of Range (0x%lx, 0x%lx)", filename, line, v, lb, hb);
		}
	}
	return (v - lb);
}


