/* -*- Mode: C; c-file-style: "gnu" -*-
   jninativ.c -- Java Native Interface native method operations.
   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 "method.h"
#include "qop.h"
#include "exceptions.h"

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

typedef struct natives {
  struct natives *prev;
  struct natives *next;

  jclass clazz;
  const JNINativeMethod *methods;
  jint nMethods;
} natives;

static natives *natives_list = NULL;

jint
JNIFUNC(RegisterNatives)(JNIEnv *env,
			 jclass clazz,
			 const JNINativeMethod *methods,
			 jint nMethods)
{
  int i = 0;
  HungryJNIEnv *henv = (HungryJNIEnv*)env;
  HungryJavaVM *vm = henv->_vm;
  natives *new_natives = (natives*)calloc(1, sizeof(natives));
  ClazzFile *cls = NULL;
  char *class_name = NULL;

  if (new_natives == NULL) return -1; /* XXX exception? */

  if (vm->_verbose_flags & VERBOSE_JNI)
    {
      cls = jclass_to_clazzfile(env, clazz);
      class_name = getClassName(env, cls);
    }

  new_natives->clazz = clazz;
  new_natives->methods = methods;
  new_natives->nMethods = nMethods;

  for (i = 0; i < nMethods; i++)
    {
      jmethodID method;
      method = find_static_method(env, clazz,
				  methods[i].name, methods[i].signature);

      if (NULL == method)
	method = find_method(env, clazz,
			     methods[i].name, methods[i].signature);

      if (NULL == method)
	{
	  throw_Exception(env, "java/lang/NoSuchMethodError", methods[i].name);
	  return -1;
	}
      else
	{
	  if (vm->_verbose_flags & VERBOSE_JNI)
	    printf ("[Registering JNI native method %s.%s]\n", class_name, method->name);

#ifndef PROFILING /* if we're profiling we need stubs -- at least on freebsd 2.2 */
	  method->native_func = (NativeFunc)methods[i].fnPtr;
#endif
	}
    }

  MONITOR_enter(vm->_mon);
  ENQUEUE(new_natives, natives_list);
  MONITOR_exit(vm->_mon);

  return 0;
}

static natives *
find_natives(jclass clazz)
{
  natives *n;

  for (n = natives_list; n != NULL; n=n->next)
    {
      if (n->clazz == clazz)
	{
	  return n;
	}
    }

  return NULL;
}

jint
JNIFUNC(UnregisterNatives)(JNIEnv *env,
			   jclass clazz)
{
  int i = 0;
  HungryJNIEnv *henv = (HungryJNIEnv*)env;
  HungryJavaVM *vm = henv->_vm;
  natives *n = find_natives(clazz);

  if (!n) return -1; /* exception? */

  MONITOR_enter(vm->_mon);
  UNQUEUE(n, natives_list);
  MONITOR_exit(vm->_mon);

  for (i = 0; i < n->nMethods; i++)
    {
      jmethodID method;
      method = find_static_method(env, n->clazz,
				  n->methods[i].name,
				  n->methods[i].signature);
      if (NULL == method)
	method = find_method(env, n->clazz,
			     n->methods[i].name,
			     n->methods[i].signature);

      if (NULL != method)
	method->native_func = NULL;
    }

  return 0;
}

