/*
 * Exception Handling
 *
 * Copyright (c) 2000
 *    Issei Suzuki <issei@issei.org>   All rights reserved.
 *
 * $Id: except.c,v 1.8 2000/08/20 13:07:58 issei Exp $
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include "except.h"

static const char rcsid[] =
  "$Id: except.c,v 1.8 2000/08/20 13:07:58 issei Exp $";

struct except {
	jmp_buf ex_env;
	int ex_type;
	int ex_hold;
	const char *ex_msg;
};

struct except except_data[ EXCEPT_NESTMAX ];
struct except *except_ptr = except_data;
const int except_inflag = 0;	/* 例外ハンドラの中にいるかどうか */
static except_handler_t except_handler = (except_handler_t)0;

int
except_nestlevel(void)
{
	return except_ptr - except_data;
}

void
except_stack_shrink_xxx(void)
{
	assert(except_nestlevel() > 0);
	--except_ptr;
}

void
except_stack_grow_xxx(void)
{
	++except_ptr;
}

jmp_buf *
except_try_xxx(void)
{
	assert(except_nestlevel() < EXCEPT_NESTMAX);
	except_ptr->ex_type = except_ptr->ex_hold = 0;
	except_stack_grow_xxx();
	return &except_ptr->ex_env;
}

void
except_throw_xxx(const char *msg, int type)
{
	register struct except *p = except_ptr - 1;
	assert(except_nestlevel() > 0);
	p->ex_msg = msg;
	p->ex_type = type;
	p->ex_hold = 1;
	longjmp(except_ptr->ex_env, type);
	/* NOTREACHED */
}

void
except_throwup_xxx(void)
{
	except_stack_shrink_xxx();
	/* Now, except_ptr points the exception that is
	   currently hold */
	except_throw_xxx(except_ptr->ex_msg, except_ptr->ex_type);
	/* NOTREACHED */
}

void
except_catch_xxx(void)
{
	assert(except_nestlevel() > 0);
	(except_ptr - 1)->ex_hold = 0;
}

int
except_ishold_xxx(void)
{
	assert(except_nestlevel() > 0);
	return (except_ptr - 1)->ex_hold;
}

const char *
except_message(void)
{
	assert(except_ptr - except_data > 0);
	return (except_ptr - 1)->ex_type == 0
	    ? "(no exception)"
	    : (except_ptr - 1)->ex_msg;
}

int
except_type(void)
{
	assert(except_nestlevel() > 0);
	return (except_ptr - 1)->ex_type;
}

except_handler_t
except_handler_regist(except_handler_t handler_new)
{
	except_handler_t handler_old;
	
	handler_old = except_handler;
	except_handler = handler_new;
	return handler_old;
}

void
except_handler_exec_xxx(const char *file, int line)
{
	if (except_handler)
		except_handler();
	fprintf(stderr, "except : [%s line# %d] failed to handle exception.\n",
		file, line);
	exit(-1);
}
