/*  throw.c -- runtime exception tossers for Toba  */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>             /* Support for variadic printf-like throws */
#ifdef SCOUT
#include <scout/errno.h>
/* Pretend like Scout has this function */
#define strerror(_ern) errnoDecode ((ErrorCode) (_ern))
#else /* SCOUT */
#include <errno.h>              /* strerror support */
#endif /* SCOUT */

#include "toba.h"
#include "runtime.h"

#ifndef MAX_ERRMSG_LENGTH
/* Maximum "reasonable" length of a generated string error message.  Too
 * bad we can't use vnsprintf to check this. */
#define MAX_ERRMSG_LENGTH (512)
#endif /* MAX_ERRMSG_LENGTH */

#include "java_lang_Throwable.h"
#include "java_lang_Error.h"
#include "java_lang_NullPointerException.h"
#include "java_lang_NegativeArraySizeException.h"
#include "java_lang_IndexOutOfBoundsException.h"
#include "java_lang_ArrayIndexOutOfBoundsException.h"
#include "java_lang_NumberFormatException.h"
#include "java_lang_ArithmeticException.h"
#include "java_lang_ArrayStoreException.h"
#include "java_lang_OutOfMemoryError.h"
#include "java_lang_NoSuchMethodError.h"
#include "java_lang_InstantiationException.h"
#include "java_lang_IncompatibleClassChangeError.h"
#include "java_lang_ClassCastException.h"
#include "java_lang_ClassCircularityError.h"
#include "java_lang_ClassNotFoundException.h"
#include "java_lang_IllegalAccessException.h"
#include "java_lang_InternalError.h"
#include "java_io_IOException.h"
#include "java_io_FileNotFoundException.h"
#include "java_io_InterruptedIOException.h"
#include "java_io_EOFException.h"
#include "java_net_UnknownHostException.h"


/*
 *  athrow(o) -- throw an arbitrary exception
 *
 *  called from generated code and from below.
 */
void athrow(Object o)
{
    struct mythread *thr = mythread();

    if (NULL == o) {
	o = construct(&cl_java_lang_NullPointerException.C);
    }

    thr->exception = o;
    longjmp(thr->jmpbuf, 1);
}

static void
vthrowMesg (Class etype,
            char * msg,
            va_list ap)
{
    struct in_java_lang_Throwable *e;

    e = (struct in_java_lang_Throwable *)construct(etype);
    if (msg) {
        char mbuf [MAX_ERRMSG_LENGTH];

        vsprintf(mbuf, msg, ap);
        e->detailMessage = (Object)javastring(mbuf);
    }
    athrow(e);
}

/*  throwMesg(c, mesg) -- throw an exception with a descriptive message  */
void throwMesg(Class etype,
               char *mesg,
               ...)
{
    va_list ap;

    va_start (ap, mesg);
    vthrowMesg(etype, mesg, ap);
    /*NOTREACHED*/
}

/*  throw specific exceptions  */

/* Call this to throw a java.lang.InternalError, e.g. for when runtime
 * assumptions are violated.  This is a varargs function like printf */
void
throwInternalError (char *msg,
                    ...)
{
   va_list ap;

   va_start (ap, msg);
   vthrowMesg (&cl_java_lang_InternalError.C, msg, ap);
   /*NOTREACHED*/
}


void throwNullPointerException(char *mesg)
{
    throwMesg(&cl_java_lang_NullPointerException.C, mesg);
}


void throwNegativeArraySizeException(int size)
{
    throwMesg(&cl_java_lang_NegativeArraySizeException.C, "%d", size);
}


void throwIndexOutOfBoundsException(char *mesg)
{
    throwMesg(&cl_java_lang_IndexOutOfBoundsException.C, mesg);
}


void throwArrayIndexOutOfBoundsException(Object o, int index)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_ArrayIndexOutOfBoundsException.C, "%d", index);
}


void throwDivisionByZeroException(void)
{
    throwMesg(&cl_java_lang_ArithmeticException.C, "/ by zero");
}


void throwIOException(char *mesg, int xerrno)
{
    throwMesg(&cl_java_io_IOException.C, "%s: %s", mesg, strerror (xerrno));
}


void throwFileNotFoundException(char *mesg, int xerrno)
{
    throwMesg(&cl_java_io_FileNotFoundException.C, "%s: %s", mesg, strerror (xerrno));
}


void throwEOFException(char *mesg, int xerrno)
{
    throwMesg(&cl_java_io_EOFException.C, "%s: %s", mesg, strerror (xerrno));
}


void throwInterruptedIOException(char *mesg, int xerrno)
{
    throwMesg(&cl_java_io_InterruptedIOException.C, "%s: %s", mesg, strerror (xerrno));
}


void throwNumberFormatException(char *mesg)
{
    throwMesg(&cl_java_lang_NumberFormatException.C, mesg);
}


void throwArrayStoreException(char *mesg)
{
    throwMesg(&cl_java_lang_ArrayStoreException.C, mesg);
}


void throwOutOfMemoryError(int nbytes)
{
    throwMesg(&cl_java_lang_OutOfMemoryError.C, "Out of memory allocating %d bytes", nbytes);
}


void throwUnknownHostException(char *mesg)
{
    throwMesg(&cl_java_net_UnknownHostException.C, mesg);
}


void throwClassCastException(Object o)
/*ARGSUSED*/
{
   char * msg = NULL;
   
   /* OK, what we're doing here is, if we were given an object which
    * failed the class cast, get its name, and use that as the default
    * message. */
   if (NULL != o) {
      Class cl;

      /* o is an in_java_lang_Object, which starts with a pointer
       * to an cl_java_lang_Object, which starts with a class structure,
       * which has a member name which is an in_java_lang_String which
       * names the class.  God help us if somebody changes the runtime
       * data structures. */
      cl = * (struct class **) o;
      if (NULL != cl) {
         if (NULL != cl->elemclass) {
            /* Arrays come off as java.lang.Objects. */
            msg = "java.lang.Object";
         } else {
            msg = cstring (cl->name);
         }
      }
   }
   throwMesg(&cl_java_lang_ClassCastException.C, msg);
}


void throwNoSuchMethodError(Object o)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_NoSuchMethodError.C, 0);
}


void throwInstantiationException(Object o)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_InstantiationException.C, 0);
}


void throwClassCircularityError(Object o)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_ClassCircularityError.C, 0);
}


void throwClassNotFoundException(char *mesg)
{
    throwMesg(&cl_java_lang_ClassNotFoundException.C, mesg);
}

void throwIllegalAccessException(char *mesg)
{
    throwMesg(&cl_java_lang_IllegalAccessException.C, mesg);
}


void throwIncompatibleClassChangeError(Object o)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_IncompatibleClassChangeError.C, 0);
}


/* ExceptionInInitializerError doesn't seem to exist yet; throw Error */

void throwExceptionInInitializerError(Object o)
/*ARGSUSED*/
{
    throwMesg(&cl_java_lang_Error.C, "exception in initializer");
}
