fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
/* Primitives Package */

#include "copyright.h"

#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>

#include "config.h"
#include "db.h"
#include "tune.h"
#include "inst.h"
#include "externs.h"
#include "match.h"
#include "interface.h"
#include "params.h"
#include "fbstrings.h"
#include "interp.h"

static struct inst *oper1, *oper2, *oper3, *oper4;
static int result;
static char buf[BUFFER_LEN];

union error_mask {
	struct {
		unsigned int div_zero:1;	/* Divide by zero */
		unsigned int nan:1;		/* Result would not be a number */
		unsigned int imaginary:1;	/* Result would be imaginary */
		unsigned int f_bounds:1;	/* Float boundary error */
		unsigned int i_bounds:1;	/* Integer boundary error */
	} error_flags;
	int is_flags;
};

#define ERROR_NAME_MAX_LEN 15
#define ERROR_STRING_MAX_LEN 80
#define ERROR_NUM 5

union error_mask err_bits[ERROR_NUM];

struct err_type {
	int error_bit;
	char error_name[ERROR_NAME_MAX_LEN];
	char error_string[ERROR_STRING_MAX_LEN];
};

static struct err_type err_defs[] = {
	{0, "DIV_ZERO", "Division by zero attempted."},
	{1, "NAN", "Result was not a number."},
	{2, "IMAGINARY", "Result was imaginary."},
	{3, "FBOUNDS", "Floating-point inputs were infinite or out of range."},
	{4, "IBOUNDS", "Calculation resulted in an integer overflow."},
	{5, "", ""}
};

static int err_init = 0;

void
init_err_val(void)
{
	int i;

	for (i = 0; i < ERROR_NUM; i++)
		err_bits[i].is_flags = 0;
	err_bits[0].error_flags.div_zero = 1;
	err_bits[1].error_flags.nan = 1;
	err_bits[2].error_flags.imaginary = 1;
	err_bits[3].error_flags.f_bounds = 1;
	err_bits[4].error_flags.i_bounds = 1;
	err_init = 1;
}

void
prim_clear(PRIM_PROTOTYPE)
{
	CHECKOP(0);
	fr->error.is_flags = 0;
}

void
prim_error_num(PRIM_PROTOTYPE)
{
	CHECKOP(0);
	CHECKOFLOW(1);
	result = ERROR_NUM;
	PushInt(result);
}

void
prim_clear_error(PRIM_PROTOTYPE)
{
	int loop;

	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_STRING && oper1->type != PROG_INTEGER)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if (oper1->type == PROG_INTEGER) {
		if ((oper1->data.number < 0) || (oper1->data.number >= ERROR_NUM)) {
			result = 0;
		} else {
			fr->error.is_flags = fr->error.is_flags & (~err_bits[oper1->data.number].is_flags);
			result = 1;
		}
	} else {
		if (!oper1->data.string) {
			result = 0;
		} else {
			loop = 0;
			result = strlen(oper1->data.string->data);
			for (loop = 0; loop < result; loop++)
				buf[loop] = toupper(oper1->data.string->data[loop]);
			result = 0;
			loop = 0;
			while (loop < ERROR_NUM) {
				if (!strcmp(buf, err_defs[loop].error_name)) {
					result = 1;
					loop = ERROR_NUM;
					fr->error.is_flags = fr->error.is_flags & (~err_bits[loop].is_flags);
				} else {
					loop++;
				}
			}
		}
	}
	CLEAR(oper1);
	PushInt(result);
}

void
prim_set_error(PRIM_PROTOTYPE)
{
	int loop;

	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_STRING && oper1->type != PROG_INTEGER)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if (oper1->type == PROG_INTEGER) {
		if ((oper1->data.number < 0) || (oper1->data.number >= ERROR_NUM)) {
			result = 0;
		} else {
			fr->error.is_flags = fr->error.is_flags | err_bits[oper1->data.number].is_flags;
			result = 1;
		}
	} else {
		if (!oper1->data.string) {
			result = 0;
		} else {
			loop = 0;
			result = strlen(oper1->data.string->data);
			for (loop = 0; loop < result; loop++)
				buf[loop] = toupper(oper1->data.string->data[loop]);
			result = 0;
			loop = 0;
			while (loop < ERROR_NUM) {
				if (!strcmp(buf, err_defs[loop].error_name)) {
					result = 1;
					loop = ERROR_NUM;
					fr->error.is_flags = fr->error.is_flags | err_bits[loop].is_flags;
				} else {
					loop++;
				}
			}
		}
	}
	CLEAR(oper1);
	PushInt(result);
}

void
prim_is_set(PRIM_PROTOTYPE)
{
	int loop;

	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_STRING && oper1->type != PROG_INTEGER)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if (oper1->type == PROG_INTEGER) {
		if ((oper1->data.number < 0) || (oper1->data.number >= ERROR_NUM)) {
			result = 0;
		} else {
			result = ((fr->error.is_flags & err_bits[oper1->data.number].is_flags) != 0);
		}
	} else {
		if (!oper1->data.string) {
			result = 0;
		} else {
			loop = 0;
			result = strlen(oper1->data.string->data);
			for (loop = 0; loop < result; loop++)
				buf[loop] = toupper(oper1->data.string->data[loop]);
			result = 0;
			loop = 0;
			while (loop < ERROR_NUM) {
				if (!strcmp(buf, err_defs[loop].error_name)) {
					loop = ERROR_NUM;
					result = ((fr->error.is_flags & err_bits[loop].is_flags) != 0);
				} else {
					loop++;
				}
			}
		}
	}
	CLEAR(oper1);
	PushInt(result);
}

void
prim_error_str(PRIM_PROTOTYPE)
{
	int loop;

	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_STRING && oper1->type != PROG_INTEGER)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if (oper1->type == PROG_INTEGER) {
		if ((oper1->data.number < 0) || (oper1->data.number >= ERROR_NUM)) {
			result = -1;
		} else {
			result = oper1->data.number;
		}
	} else {
		if (!oper1->data.string) {
			result = -1;
		} else {
			loop = 0;
			result = strlen(oper1->data.string->data);
			for (loop = 0; loop < result; loop++)
				buf[loop] = toupper(oper1->data.string->data[loop]);
			result = -1;
			loop = 0;
			while (loop < ERROR_NUM) {
				if (!strcmp(buf, err_defs[loop].error_name)) {
					result = loop;
					loop = ERROR_NUM;
				} else {
					loop++;
				}
			}
		}
	}
	CLEAR(oper1);
	if (result == -1) {
		PushNullStr;
	} else {
		PushString(err_defs[result].error_string);
	}
}

void
prim_error_name(PRIM_PROTOTYPE)
{
	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_INTEGER)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if ((oper1->data.number < 0) || (oper1->data.number >= ERROR_NUM)) {
		result = -1;
	} else {
		result = oper1->data.number;
	}
	CLEAR(oper1);
	if (result == -1) {
		PushNullStr;
	} else {
		PushString(err_defs[result].error_name);
	}
}

void
prim_error_bit(PRIM_PROTOTYPE)
{
	int loop;

	CHECKOP(1);
	oper1 = POP();
	if (oper1->type != PROG_STRING)
		abort_interp("Invalid argument type. (1)");
	if (!err_init)
		init_err_val();
	if (!oper1->data.string) {
		result = -1;
	} else {
		loop = 0;
		result = strlen(oper1->data.string->data);
		for (loop = 0; loop < result; loop++)
			buf[loop] = toupper(oper1->data.string->data[loop]);
		result = -1;
		loop = 0;
		while (loop < ERROR_NUM) {
			if (!strcmp(buf, err_defs[loop].error_name)) {
				result = loop;
				loop = ERROR_NUM;
			} else {
				loop++;
			}
		}
	}
	CLEAR(oper1);
	PushInt(result);
}

void
prim_is_error(PRIM_PROTOTYPE)
{
	CHECKOP(0);
	CHECKOFLOW(1);
	result = ((fr->error.is_flags) != 0);
	PushInt(result);
}