/* -*- Mode: C; c-file-style: "gnu" -*-
   jnismeth.c -- Java Native Interface methods relating to static methods.
   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 "interp.h"
#include "method.h"

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

jmethodID
JNIFUNC(GetStaticMethodID)(JNIEnv *env,
			   jclass clazz,
			   const char *name,
			   const char *sig)
{
  MethodStruct* method;

  method = find_static_method(env, clazz, name, sig);

  if (method == NULL)
    {
      jclass no_such_method = (*env)->FindClass(env, "java/lang/NoSuchMethodError");
      if (no_such_method)
	(*env)->ThrowNew(env, no_such_method, name);
      else
	(*env)->FatalError(env, "Could not load java/lang/NoSuchMethodError");
    }

  return method;
}

#define STATIC_METHOD_FOO(jtype, JType, unionselector) \
 \
jtype \
JNIFUNC(CallStatic##JType##Method)(JNIEnv *env, \
				   jclass clazz, \
				   jmethodID methodID, \
				   ...) \
{ \
  va_list varargs; \
  jtype result; \
 \
  va_start(varargs, methodID); \
  result = JNIFUNC(CallStatic##JType##MethodV)(env, clazz, methodID, varargs); \
  va_end(varargs); \
 \
  return result; \
} \
 \
jtype \
JNIFUNC(CallStatic##JType##MethodA)(JNIEnv *env, \
				    jclass clazz, \
				    jmethodID methodID, \
				    jvalue *args) \
{ \
  jvalue value; \
 \
  value = CallStaticJavaMethod(env,\
			       (MethodStruct*)methodID, \
			       args); \
 \
  return value.unionselector; \
} \
 \
jtype \
JNIFUNC(CallStatic##JType##MethodV)(JNIEnv *env, \
				    jclass clazz, \
				    jmethodID methodID, \
				    va_list args) \
{ \
  jvalue *params; \
  int i; \
  MethodStruct *method = (MethodStruct*)methodID; \
  Signature *sig = SIG_parseFromJavaSig(env, method->sig_str); \
  int num_params = SIG_numParams(env, sig); \
  jtype result; \
   \
  params = (jvalue*)calloc(num_params, sizeof(jvalue*)); \
 \
  for (i = 0; i < num_params; i ++) \
    { \
      if (sig->method.params[i]->any.tag != SIG_PRIM) /* XXX punt... */ \
	{ \
	  params[i].l = va_arg(args, void*); \
	} \
      else \
	{ \
	  switch (sig->method.params[i]->prim.type) \
	    { \
	    case SIG_JBOOLEAN: \
	    case SIG_JBYTE: \
	    case SIG_JCHAR: \
	    case SIG_JSHORT: \
	    case SIG_JINT: \
	    case SIG_JOBJECT: \
	    case SIG_JFLOAT: \
	      params[i].i = va_arg(args, jint); \
	      break; \
	    case SIG_JLONG: \
	    case SIG_JDOUBLE: \
	      params[i].j = va_arg(args, jlong); \
	      break; \
	    default: \
	      abort(); \
	    } \
	} \
    } \
 \
  SIG_free(env, sig); \
\
  result = JNIFUNC(CallStatic##JType##MethodA)(env, clazz, methodID, params); \
   \
  free(params); \
 \
  return result; \
}

STATIC_METHOD_FOO(jboolean, Boolean, z)
STATIC_METHOD_FOO(jbyte, Byte, b)
STATIC_METHOD_FOO(jchar, Char, c)
STATIC_METHOD_FOO(jshort, Short, s)
STATIC_METHOD_FOO(jint, Int, i)
STATIC_METHOD_FOO(jlong, Long, j)
STATIC_METHOD_FOO(jobject, Object, l)
STATIC_METHOD_FOO(jfloat, Float, f)
STATIC_METHOD_FOO(jdouble, Double, d)

void
JNIFUNC(CallStaticVoidMethod)(JNIEnv *env,
			      jclass clazz,
			      jmethodID methodID, 
			      ...)
{
  va_list varargs;

  va_start(varargs, methodID);
  JNIFUNC(CallStaticVoidMethodV)(env, clazz, methodID, varargs);
  va_end(varargs);
}

void
JNIFUNC(CallStaticVoidMethodA)(JNIEnv *env, 
			       jclass clazz,
			       jmethodID methodID, 
			       jvalue *args)
{
  CallStaticJavaMethod(env,\
		       (MethodStruct*)methodID,
		       args);
}

void
JNIFUNC(CallStaticVoidMethodV)(JNIEnv *env, 
			       jclass clazz,
			       jmethodID methodID, 
			       va_list args)
{
  jvalue *params = NULL;
  MethodStruct *method = (MethodStruct*)methodID;
  Signature *sig = SIG_parseFromJavaSig(env, method->sig_str);
  int num_params = SIG_numParams(env, sig);
  int i;

  if (0 < num_params)
    params = (jvalue*)calloc(num_params, sizeof(jvalue*));

  for (i = 0; i < num_params; i ++)
    {
      if (sig->method.params[i]->any.tag != SIG_PRIM) /* XXX punt... */
	{
	  params[i].l = va_arg(args, void*);
	}
      else
	{
	  switch (sig->method.params[i]->prim.type)
	    {
	    case SIG_JBOOLEAN:
	    case SIG_JBYTE:
	    case SIG_JCHAR:
	    case SIG_JSHORT:
	    case SIG_JINT:
	    case SIG_JOBJECT:
	    case SIG_JFLOAT:
	      params[i].i = va_arg(args, jint);
	      break;
	    case SIG_JLONG:
	    case SIG_JDOUBLE:
	      params[i].j = va_arg(args, jlong);
	      break;
	    default:
	      abort();
	    }
	}
    }

  SIG_free(env, sig);

  JNIFUNC(CallStaticVoidMethodA)(env, clazz, methodID, params);

  if (NULL != params)
    free(params);
}
