/* -*- Mode: C; c-file-style: "gnu" -*-
   jnithrow.c -- Java Native Interface methods relating to exceptions.
   Created: Chris Toshok <toshok@hungry.com>, 26-Jul-1997
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "jni.h"
#include "jniint.h"
#include "ClazzFile.h"
#include "exceptions.h"

#include <stdlib.h>
#include <assert.h>

jint
JNIFUNC(Throw)(JNIEnv *env,
	       jthrowable obj)
{
  HungryJNIEnv *henv = (HungryJNIEnv*)env;

  if (henv->_exception != NULL)
    {
      return -1;
    }
  else
    {
      ExceptionInfo *exc_info;

      henv->_exception = (*env)->NewGlobalRef(env, obj);

      if (!NSA_GetNativeState(henv->_exception))
	{
	  exc_info = (ExceptionInfo*)calloc(1, sizeof(ExceptionInfo));
	  NSA_SetNativeState(henv->_exception, exc_info);
	}

      return 0;
    }
}

jint
JNIFUNC(ThrowNew)(JNIEnv *env,
		  jclass clazz,
		  const char *message)
{
  HungryJNIEnv *henv = (HungryJNIEnv*)env;
  jmethodID constructor;
  jstring string;

  if (message)
    constructor = (*env)->GetMethodID(env, clazz, "<init>", "(Ljava/lang/String;)V");
  else
    constructor = (*env)->GetMethodID(env, clazz, "<init>", "()V");

  if (constructor == NULL)
    {
      (*env)->FatalError(env, "ThrowNew called on object with no constructor");
    }

  if (message)
    {
      string = (*env)->NewStringUTF(env, message);
      if (string == NULL)
	{
	  (*env)->FatalError(env, "ThrowNew unable to allocate message");
	}
	  
      henv->_exception = (*env)->NewObject(env, clazz, constructor, string);
      henv->_exception = (*env)->NewGlobalRef(env, henv->_exception);
    }
  else
    {
      henv->_exception = (*env)->NewObject(env, clazz, constructor);
      henv->_exception = (*env)->NewGlobalRef(env, henv->_exception);
    }

  return 0;
}

jthrowable
JNIFUNC(ExceptionOccurred)(JNIEnv *env)
{
  HungryJNIEnv *henv = (HungryJNIEnv*)env;

  return henv->_exception;
}

void
JNIFUNC(ExceptionDescribe)(JNIEnv *env)
{
  HungryJNIEnv *henv = (HungryJNIEnv*)env;
  jobject exception = henv->_exception;

  /* if there really wasn't an exception, just return. */
  if (!exception) return;

  toplevel_exception_handler(env, exception);
}
    
void
JNIFUNC(ExceptionClear)(JNIEnv *env)
{
  HungryJNIEnv *henv = (HungryJNIEnv*)env;

  henv->_exception = NULL;
}

void
JNIFUNC(FatalError)(JNIEnv *env,
		    const char *msg)
{
  fprintf(stderr, "Fatal Java VM Error: %s\n", msg);

  /* our version of abort() will take care of calling
     the abort hook for this vm, if any. */
  abort();
}
