/*
 * $Id: jexc_java_lang.c,v 1.11 2002/03/29 20:16:00 m-hirano Exp $
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */

#include "jexc.h"
#include "jexc_runtime.h"
#include "jexc_sys_class.h"
#include <sys/wait.h>
#include <signal.h>

#define STR_BUF_INCR_SIZE 16

struct jexc_string_buffer {
    int buf_len;
    int cur_len;
    char buf[1];
};

void abstractMethod() { jexc_error("abstract method is called"); }

void Lang_Object_CLINIT(){ /* nop */ }

void Lang_Object_INIT() { /* nop */ }

void jexc_init_Lang_class()
{
    jexc_class *cp;
    jexc_any t;

    cp = jexc_find_class("java/lang/Double");
    t.d = DOUBLE_MIN_VALUE;
    ICVAR(jexc_int,cp,Lang_Double_MIN_VALUE) = t.HL.low;
    ICVAR(jexc_int,cp,Lang_Double_MIN_VALUE+4) = t.HL.high;
    t.d = DOUBLE_MAX_VALUE;
    ICVAR(jexc_int,cp,Lang_Double_MAX_VALUE) = t.HL.low;
    ICVAR(jexc_int,cp,Lang_Double_MAX_VALUE+4) = t.HL.high;

    cp = jexc_find_class("java/lang/Float");
    ICVAR(jexc_float,cp,Lang_Float_MIN_VALUE) = FLOAT_MIN_VALUE;
    ICVAR(jexc_float,cp,Lang_Float_MAX_VALUE) = FLOAT_MAX_VALUE;
}


DEFINE_C_METHOD(Lang_Object_toString)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_word x;

    GC_OFF;
    if(fp[0]->class == ARRAY_OBJECT)
	sprintf(buf,"[ARRAY,0x%lx]",(unsigned long int)fp[0]);
    else if(fp[0]->class == IARRAY_OBJECT)
	sprintf(buf,"[IARRAY,0x%lx]",(unsigned long int)fp[0]);
    else if(fp[0]->class == jexc_string_class){
	RETURN_C_METHOD(fp[0]);
    } else
	sprintf(buf,"[%s,0x%lx]",
		fp[0]->class->name,
		(unsigned long int)fp[0]);
    x = (jexc_word) jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_Object_equals)
{
    DECL_C_METHOD_VAR;
    int z;
    if(fp[0] == fp[1]) z = 1;
    else z = 0;
    RETURN_C_METHOD_INT(z);
}


/* 
 * String
 */
/* method <init> (Ljava/lang/StringBuffer;)V  	Lang_String_INIT1 */
DEFINE_C_METHOD(Lang_String_INIT1)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    struct jexc_string_buffer *p;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    p = VAR0_OPAQUE(struct jexc_string_buffer *,fp[1]);
    sp->op = jexc_alloc_string_opaque(p->cur_len,p->buf);
    GC_ON;
}

/*  method <init>  ([C)V	       Lang_String_INIT2 */
DEFINE_C_METHOD(Lang_String_INIT2)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    jexc_iarray *ap;
    jexc_char *cp;
    char buf[MAX_STR_LEN];
    int i;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    ap = (jexc_iarray *)fp[1];
    if(ap->length >= MAX_STR_LEN) jexc_error("String.<init>([C): too long");
    cp = (jexc_char *)ap->base;
    for(i = 0; i < ap->length; i++) buf[i] = *cp++;
    sp->op = jexc_alloc_string_opaque(ap->length,buf);
    GC_ON;
}

/* method <init> ([CII)V		Lang_String_INIT3 */
DEFINE_C_METHOD(Lang_String_INIT3)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    jexc_iarray *ap;
    jexc_char *cp;
    char buf[MAX_STR_LEN];
    int i,off,len;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    ap = (jexc_iarray *)fp[1];
    off = (jexc_int)((_omAddrInt_t)fp[2]);
    len = (jexc_int)((_omAddrInt_t)fp[3]);
    if(len >= MAX_STR_LEN) jexc_error("String.<init>([CII): too long");
    cp = ((jexc_char *)ap->base)+off;
    for(i = 0; i < len; i++) buf[i] = *cp++;
    sp->op = jexc_alloc_string_opaque(len,buf);
    GC_ON;
}

/* method intern ()Ljava/lang/String; 	Lang_String_intern */
DEFINE_C_METHOD(Lang_String_intern)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    sp = (jexc_string *)fp[0];
    RETURN_C_METHOD((jexc_word)jexc_intern_string(sp));
}

DEFINE_C_METHOD(Lang_String_equals)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int z;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    if(sp == sq) z = 1;
    else if(sp == NULL || sq == NULL) z = 0;
    else if(sp->op->length == sq->op->length &&
	    strncmp(sp->op->str,sq->op->str,sp->op->length) == 0) 
	z = 1;
    else z = 0;
    RETURN_C_METHOD_INT(z);
}

/* call toString Method */
DEFINE_C_METHOD(Lang_String_valueOf_Object)
{
    DECL_C_METHOD_VAR;
    jexc_object *p;
    jexc_class *cp;
    p = fp[0];
    cp = p->class;
    if(cp == ARRAY_OBJECT || cp == IARRAY_OBJECT) cp = jexc_object_class;
    (*cp->methods[JEXC_TOSTRING_METHOD])(_spp);
}


/* method charAt (I)C	Lang_String_charAt */
DEFINE_C_METHOD(Lang_String_charAt)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    int pos;
    sp = (jexc_string *)fp[0];
    pos = (jexc_int)((_omAddrInt_t)fp[1]);
    RETURN_C_METHOD_INT(sp->op->str[pos]);
}

/* method compareTo (Ljava/lang/String;)I Lang_String_compareTo */
DEFINE_C_METHOD(Lang_String_compareTo)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int z;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    z = strcmp(sp->op->str,sq->op->str);
    RETURN_C_METHOD_INT(z);
}

int string_indexof(jexc_string *sp,jexc_string *sq,int from)
{
    int len;
    char *p,*q;

    p = sp->op->str;
    q = sq->op->str;
    if(from > sp->op->length){
	return -1;
    }
    len = sq->op->length;
    p += from;
    while(1){
	p = strchr(p,*q);
	if(p == NULL) break;
	if(strncmp(p,q,len) == 0){
	    return p - sp->op->str;
	}
    }
    return -1;
}

/* method indexOf (Ljava/lang/String;I)I  Lang_String_indexOf */
DEFINE_C_METHOD(Lang_String_indexOf)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int from;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    from = (jexc_int)((_omAddrInt_t)fp[2]);
    RETURN_C_METHOD_INT(string_indexof(sp,sq,from));
}

/* method indexOf (Ljava/lang/String;)I   Lang_String_indexOf_0 */
DEFINE_C_METHOD(Lang_String_indexOf_0)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    RETURN_C_METHOD_INT(string_indexof(sp,sq,0));
}

DEFINE_C_METHOD(Lang_String_length)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    sp = (jexc_string *)fp[0];
    RETURN_C_METHOD_INT(sp->op->length);
}

int string_lastindexof(jexc_string *sp, jexc_string *sq, int from)
{
    int len;
    char *p, *q;

    if (from < 0) {
	return -1;
    }
    if (from > sp->op->length){
	from = sp->op->length - 1;
    }
    p = sp->op->str;
    q = sq->op->str;
    len = sq->op->length;
    p += from;
    while (1) {
	p = strrchr(p, *q);
	if (p == NULL) break;
	if (strncmp(p, q, len) == 0){
	    return p - sp->op->str;
	}
    }
    return -1;
}

/* method lastIndexOf (Ljava/lang/String;I)I  Lang_String_lastIndexOf */
DEFINE_C_METHOD(Lang_String_lastIndexOf)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int from;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    from = (jexc_int)((_omAddrInt_t)fp[2]);
    RETURN_C_METHOD_INT(string_lastindexof(sp,sq,from));
}

/* method lastIndexOf (Ljava/lang/String;)I   Lang_String_lastIndexOf_0 */
DEFINE_C_METHOD(Lang_String_lastIndexOf_0)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    RETURN_C_METHOD_INT(string_lastindexof(sp,sq,0));
}

/* method substring (I)Ljava/lang/String; Lang_String_substring */
DEFINE_C_METHOD(Lang_String_substring)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    int begin;
    jexc_word x;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    begin = (jexc_int)((_omAddrInt_t)fp[1]);
    x = (jexc_word)jexc_new_string_n(sp->op->str+begin,sp->op->length-begin);
    GC_ON;
    RETURN_C_METHOD(x);
}

/* method substring (II)Ljava/lang/String; Lang_String_substring2 */
DEFINE_C_METHOD(Lang_String_substring2)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    int begin,end;
    jexc_word x;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    begin = (jexc_int)((_omAddrInt_t)fp[1]);
    end = (jexc_int)((_omAddrInt_t)fp[2]);
    x = (jexc_word)jexc_new_string_n(sp->op->str+begin,end-begin);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_AChar)
{
    DECL_C_METHOD_VAR;
    jexc_iarray *p;
    char buf[MAX_STR_LEN];
    int i;
    jexc_char *pp;
    jexc_word x;

    GC_OFF;
    p = (jexc_iarray *)fp[0];
    if(p->length > MAX_STR_LEN) jexc_error("String.valueOf(): too long");
    pp = (jexc_char *)(p->base);
    for(i = 0; i < p->length; i++) buf[i] = *pp++;
    x = (jexc_word) jexc_new_string_n(buf,p->length);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_I)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_int i;
    jexc_word x;

    GC_OFF;
    i = (jexc_int)((_omAddrInt_t)fp[0]);
    sprintf(buf,"%d",i);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_F)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_any t;
    jexc_word x;

    GC_OFF;
    t.i = (jexc_int)((_omAddrInt_t)fp[0]);
    float_toString(buf,(double)t.f);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_C)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_int i;
    jexc_word x;

    GC_OFF;
    i = (jexc_int)((_omAddrInt_t)fp[0]);
    sprintf(buf,"%c",i);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_D)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_any t;
    jexc_word x;

    GC_OFF;
    t.HL.low = (jexc_int)((_omAddrInt_t)fp[0]);
    t.HL.high = (jexc_int)((_omAddrInt_t)fp[1]);
    float_toString(buf,t.d);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_valueOf_J)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_any t;
    jexc_word x;

    GC_OFF;
    t.HL.low = (jexc_int)((_omAddrInt_t)fp[0]);
    t.HL.high = (jexc_int)((_omAddrInt_t)fp[1]);

    sprintf(buf,"%lld",t.l);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_String_concat)
{
    DECL_C_METHOD_VAR;
    char buf[MAX_STR_LEN];
    jexc_string *sp,*sq;
    int len;
    jexc_word x;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    if((len = sp->op->length+sq->op->length) >= MAX_STR_LEN)
	jexc_error("String.concat: too long");
    strncpy(buf,sp->op->str,sp->op->length);
    strncpy(buf+sp->op->length,sq->op->str,sq->op->length);
    x = (jexc_word) jexc_new_string_n(buf,len);
    GC_ON;
    RETURN_C_METHOD(x);
}

/* method endsWith (Ljava/lang/String;)Z   Lang_String_endsWith */
DEFINE_C_METHOD(Lang_String_endsWith)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int r;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    if(sp != NULL && sq != NULL &&
       sp->op->length >= sq->op->length &&
       strncmp(sp->op->str+(sp->op->length-sq->op->length),
	       sq->op->str,sq->op->length) == 0)
	r = 1;
    else r = 0;
    RETURN_C_METHOD_INT(r);
}

/* method startsWith (Ljava/lang/String;)Z Lang_String_startsWith */
DEFINE_C_METHOD(Lang_String_startsWith)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp,*sq;
    int r;
    sp = (jexc_string *)fp[0];
    sq = (jexc_string *)fp[1];
    if(sp != NULL && sq != NULL &&
       sp->op->length >= sq->op->length &&
       strncmp(sp->op->str,sq->op->str,sq->op->length) == 0)
	r = 1;
    else r = 0;
    RETURN_C_METHOD_INT(r);
}

/* method toCharArray ()[C	Lang_String_toCharArray */
DEFINE_C_METHOD(Lang_String_toCharArray)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    jexc_iarray *ap;
    int l,i;

    GC_OFF;
    sp = (jexc_string *)fp[0];
    l = sp->op->length;
    ap = jexc_new_iarray(l,IARRAY_CHAR);
    for(i = 0; i < l; i++)
	*((jexc_char *)ap->base+i) = sp->op->str[i];
    GC_ON;
    RETURN_C_METHOD((jexc_word)ap);
}



/*
 * Integer
 */
/* method <init> (I)V			Lang_Integer_INIT */
DEFINE_C_METHOD(Lang_Integer_INIT)
{
    DECL_C_METHOD_VAR;
    jexc_int *ip;
    int i;
    ip = ((jexc_int *)(fp[0]->i_var_base));
    i = (jexc_int)((_omAddrInt_t)fp[1]);
    *ip = i;
}

DEFINE_C_METHOD(Lang_Integer_toString)
{
    DECL_C_METHOD_VAR;
    jexc_int *ip;
    char buf[100];
    jexc_word x;

    GC_OFF;
    ip = ((jexc_int *)(fp[0]->i_var_base));
    sprintf(buf,"%d",*ip);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_Integer_toString_I)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_word x;

    GC_OFF;
    sprintf(buf,"%d",(jexc_int)((_omAddrInt_t)fp[0]));
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_Integer_toHexString)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_word x;

    GC_OFF;
    sprintf(buf,"%x",(jexc_int)((_omAddrInt_t)fp[0]));
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_Integer_toOctalString)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_word x;

    GC_OFF;
    sprintf(buf,"%o",(jexc_int)((_omAddrInt_t)fp[0]));
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

/* method parseInt (Ljava/lang/String;I)I	 Lang_Integer_parseInt */
DEFINE_C_METHOD(Lang_Integer_parseInt)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    int radix;
    char *p;
    int sign = 1;
    int r;

    sp = (jexc_string *)fp[0];
    radix = (jexc_int)((_omAddrInt_t)fp[1]);
    p = sp->op->str;
    if(*p == '-'){
	p++;
	sign = -1;
    }
    switch(radix){
    case 8:
	if(sscanf(p,"%o",&r) != 1) goto err;
	break;
    case 10:
	if(sscanf(p,"%d",&r) != 1) goto err;
	break;
    case 16:
	if(sscanf(p,"%x",&r) != 1) goto err;
	break;
    default:
	jexc_error("Integer.parseInt: bad radix");
    }
    RETURN_C_METHOD_INT(r*sign);
err:
    jexc_error("Integer.parseInt: NumberFormatException");
}

/* method intValue ()I			 Lang_Integer_intValue */
DEFINE_C_METHOD(Lang_Integer_intValue)
{
    DECL_C_METHOD_VAR;
    jexc_int *ip;
    ip = ((jexc_int *)(fp[0]->i_var_base));
    RETURN_C_METHOD_INT(*ip);
}


DEFINE_C_METHOD(Lang_Integer_equals)
{
    DECL_C_METHOD_VAR;
    int r;
    if(fp[0]->class == fp[1]->class &&
       *((jexc_int *)(fp[0]->i_var_base)) == 
       *((jexc_int *)(fp[1]->i_var_base)))
	r = 1;
    else r = 0;
    RETURN_C_METHOD_INT(r);
}

/*
 * Double
 */
/* method doubleToLongBits (D)J 		Lang_Double_D2J */
DEFINE_C_METHOD(Lang_Double_D2J)
{
#if 0
    DECL_C_METHOD_VAR;
#endif
    *(_spp) += 2; return;
}

/* method longBitsToDouble (J)D		Lang_Double_J2D */
DEFINE_C_METHOD(Lang_Double_J2D)
{
#if 0
    DECL_C_METHOD_VAR;
#endif
    *(_spp) += 2; return;
}

DEFINE_C_METHOD(Lang_Double_equals)
{
    DECL_C_METHOD_VAR;
    int r;
    if(fp[0]->class == fp[1]->class &&
       *((jexc_double *)(fp[0]->i_var_base)) == 
       *((jexc_double *)(fp[1]->i_var_base)))
	r = 1;
    else r = 0;
    RETURN_C_METHOD_INT(r);
}

/* 
 * Long
 */
/* method toHexString (J)Ljava/lang/String; Lang_Long_toHexString */
DEFINE_C_METHOD(Lang_Long_toHexString)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_any t;
    jexc_word x;

    GC_OFF;
    t.HL.low = (jexc_int)((_omAddrInt_t)fp[0]);
    t.HL.high = (jexc_int)((_omAddrInt_t)fp[1]);
    sprintf(buf,"%llx",t.l);
    x = (jexc_word)jexc_new_string(buf);
    GC_ON;
    RETURN_C_METHOD(x);
}

DEFINE_C_METHOD(Lang_Long_equals)
{
    DECL_C_METHOD_VAR;
    int r;
    if(fp[0]->class == fp[1]->class &&
       *((jexc_long *)(fp[0]->i_var_base)) == 
       *((jexc_long *)(fp[1]->i_var_base)))
	r = 1;
    else r = 0;
    RETURN_C_METHOD_INT(r);
}

/*
 * StringBuffer 
 */
static jexc_opaque *string_buffer_append(jexc_opaque *op,char *str,int len);

jexc_opaque *string_buffer_opaque(int buf_len)
{
    jexc_opaque *op;
    struct jexc_string_buffer *p;
    op = jexc_alloc_opaque(sizeof(struct jexc_string_buffer)+buf_len-1);
    p = (struct jexc_string_buffer *)(op->base);
    p->buf_len = buf_len;
    return op;
}

DEFINE_C_METHOD(Lang_StringBuffer_INIT)
{
    DECL_C_METHOD_VAR;
    GC_OFF;
    VAR0(fp[0]) = (jexc_word)string_buffer_opaque(STR_BUF_INCR_SIZE);
    GC_ON;
}

/* method <init> (Ljava/lang/String;)V    Lang_StringBuffer_INIT1 */
DEFINE_C_METHOD(Lang_StringBuffer_INIT1)
{
    DECL_C_METHOD_VAR;
    struct jexc_string_buffer *p;
    jexc_string *sp;

    GC_OFF;
    sp = (jexc_string *)fp[1];
    VAR0(fp[0]) = 
	(jexc_word)string_buffer_opaque(sp->op->length+STR_BUF_INCR_SIZE);
    p = VAR0_OPAQUE(struct jexc_string_buffer *,fp[0]);
    p->cur_len = sp->op->length;
    memcpy(p->buf,sp->op->str,sp->op->length);
    GC_ON;
}

static jexc_opaque *string_buffer_append(jexc_opaque *op,char *str,int len)
{
    jexc_opaque *oq;
    struct jexc_string_buffer *p,*q;

    p = (struct jexc_string_buffer *)(op->base);
    if((p->cur_len + len) > p->buf_len){
	/* reallocate */
	oq = string_buffer_opaque(p->cur_len+len+STR_BUF_INCR_SIZE);
	q = (struct jexc_string_buffer *)(oq->base);
	q->cur_len = p->cur_len;
	memcpy(q->buf,p->buf,p->cur_len);
	op = oq;
	p = q;
    }
    memcpy(p->buf+p->cur_len,str,len);
    p->cur_len += len;
    return op;
}

DEFINE_C_METHOD(Lang_StringBuffer_append_I)
{
    DECL_C_METHOD_VAR;
    char buf[100];

    GC_OFF;
    sprintf(buf,"%d",(jexc_int)((_omAddrInt_t)fp[1]));
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					 buf,strlen(buf));
    GC_ON;
    RETURN_C_METHOD_THIS;
}

DEFINE_C_METHOD(Lang_StringBuffer_append_Lstring)
{
    DECL_C_METHOD_VAR;
    jexc_string *p;

    GC_OFF;
    p = (jexc_string *)fp[1];
    if(p == NULL){
	VAR0(fp[0]) = 
	    (jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					     "null",4);
    } else {
	VAR0(fp[0]) = 
	    (jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					     p->op->str,p->op->length);
    }
    GC_ON;
    /* return this buffer */
    RETURN_C_METHOD_THIS;
}

DEFINE_C_METHOD(Lang_StringBuffer_append_L)
{
    DECL_C_METHOD_VAR;
    jexc_string *p;
    jexc_word *sp0;

    GC_OFF;
    sp0 = fp+1;
    (*(fp[1]->class->methods[JEXC_TOSTRING_METHOD]))(&sp0); /* call toString */
    p = (jexc_string *)fp[1];
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					 p->op->str,p->op->length);
    GC_ON;
    /* return this buffer */
    RETURN_C_METHOD_THIS;
}

/* method append (C)Ljava/lang/StringBuffer; Lang_StringBuffer_append_C */
DEFINE_C_METHOD(Lang_StringBuffer_append_C)
{
    DECL_C_METHOD_VAR;
    char buf[2];

    GC_OFF;
    buf[0] = (jexc_int)((_omAddrInt_t)fp[1]);
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),buf,1);
    GC_ON;
    RETURN_C_METHOD_THIS;
}

/* method append (J)Ljava/lang/StringBuffer; Lang_StringBuffer_append_J */
DEFINE_C_METHOD(Lang_StringBuffer_append_J)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_any t;

    GC_OFF;
    t.HL.low = (jexc_int)((_omAddrInt_t)fp[1]);
    t.HL.high = (jexc_int)((_omAddrInt_t)fp[2]);

    sprintf(buf,"%lld",t.l);
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					 buf,strlen(buf));
    GC_ON;
    RETURN_C_METHOD_THIS;
}

/* print floating-point number in java-spec format */
void float_toString(char *buf,double d)
{
    if(d == 0.0) 
	strcpy(buf,"0.0");
#ifdef not
    else if(d >= 1.0e-3 && d <= 10e+7)
	sprintf(buf,"%f",d);
    else sprintf(buf,"%E",d);
#endif
    else sprintf(buf,"%.16E",d);
}

/* method append (D)Ljava/lang/StringBuffer; Lang_StringBuffer_append_D */
DEFINE_C_METHOD(Lang_StringBuffer_append_D)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_any t;

    GC_OFF;
    t.HL.low = (jexc_int)((_omAddrInt_t)fp[1]);
    t.HL.high = (jexc_int)((_omAddrInt_t)fp[2]);
    float_toString(buf,t.d);
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					 buf,strlen(buf));
    GC_ON;
    RETURN_C_METHOD_THIS;
}

/* method append (F)Ljava/lang/StringBuffer; Lang_StringBuffer_append_F */
DEFINE_C_METHOD(Lang_StringBuffer_append_F)
{
    DECL_C_METHOD_VAR;
    char buf[100];
    jexc_float f;

    GC_OFF;
    f = (jexc_float)((_omAddrInt_t)fp[1]);
    float_toString(buf,f);
    VAR0(fp[0]) = 
	(jexc_word) string_buffer_append((jexc_opaque *)VAR0(fp[0]),
					 buf,strlen(buf));
    GC_ON;
    RETURN_C_METHOD_THIS;
}

/* method toString ()Ljava/lang/String;   Lang_StringBuffer_toString */
DEFINE_C_METHOD(Lang_StringBuffer_toString)
{
    DECL_C_METHOD_VAR;
    struct jexc_string_buffer *p;
    jexc_word x;

    GC_OFF;
    p = VAR0_OPAQUE(struct jexc_string_buffer *,fp[0]);
    x = (jexc_word) jexc_new_string_n(p->buf,p->cur_len);
    GC_ON;
    RETURN_C_METHOD(x);
}


/* 
 * System
 */
void Lang_System_CLINIT()
{
    jexc_class *this_class;
    jexc_object *out_stream;

    GC_OFF;
    this_class = jexc_find_class("java/lang/System");

    out_stream = jexc_new_object(jexc_find_class("java/io/PrintStream"));
    VAR0(out_stream) = 
	(jexc_word)jexc_alloc_opaque(sizeof(struct jexc_io_stream));
    VAR0_OPAQUE(struct jexc_io_stream *,out_stream)->fp = stdout;
    CVAR(this_class,Lang_System_out) = out_stream;

    out_stream = jexc_new_object(jexc_find_class("java/io/PrintStream"));
    VAR0(out_stream) = 
	(jexc_word)jexc_alloc_opaque(sizeof(struct jexc_io_stream));
    VAR0_OPAQUE(struct jexc_io_stream *,out_stream)->fp = stderr;
    CVAR(this_class,Lang_System_err) = out_stream;
    GC_ON;
}

/*  method getProperty (Ljava/lang/String;)Ljava/lang/String; */
DEFINE_C_METHOD(Lang_System_getProperty)
{
    DECL_C_METHOD_VAR;
    jexc_string *sp;
    int i;
    jexc_word x;

    sp = (jexc_string *)fp[0];
    for(i = 0; i < n_system_property; i++)
	if(strcmp(sp->op->str,system_property_names[i]) == 0){
	    GC_OFF;
	    x = (jexc_word)jexc_new_string(system_property_vals[i]);
	    GC_ON;
	    RETURN_C_METHOD(x);
	}
    RETURN_C_METHOD(0);
}

void Lang_System_INIT()
{ jexc_error("cannot create java/lang/System"); }

DEFINE_C_METHOD(Lang_System_exit)
{
    DECL_C_METHOD_VAR;
    exit((int)((_omAddrInt_t)fp[0]));
}

DEFINE_C_METHOD(Lang_Thread_dumpStack)
{
#if 0
    DECL_C_METHOD_VAR;
#endif
    jexc_error("Thread.dumpStack() is called!");
}

/* 
 * Process & Runtime 
 */
#define MAX_EXEC_ARGS 20
static int child_pid;
static FILE *child_stderr;
static int child_exit_status;

/* method getRuntime ()Ljava/lang/Runtime; Lang_Runtime_getRuntime */
DEFINE_C_METHOD(Lang_Runtime_getRuntime)
{
    DECL_C_METHOD_VAR;
    RETURN_C_METHOD(jexc_new_object(jexc_find_class("java/lang/Runtime")));
}

/* method exec ([Ljava/lang/String;)Ljava/lang/Process; Lang_Runtime_exec */
DEFINE_C_METHOD(Lang_Runtime_exec)
{
    DECL_C_METHOD_VAR;
    char *args[MAX_EXEC_ARGS];
    jexc_array *ap;
    int i;
    int pdes[2];

    ap = (jexc_array *)fp[1];
    for(i = 0; i < ap->length; i++) 
	args[i] = ((jexc_string *)(ap->elem[i]))->op->str;
    args[i] = NULL;
    pipe(pdes);

    switch(child_pid = vfork()){
    case 0:
	dup2(pdes[1],2);
	close(pdes[1]);
	close(pdes[0]);
	execvp(args[0],args);
    case -1:
	jexc_error("Runtime.exec failed");
	break;
    }
    /* parent */
    child_stderr = fdopen(pdes[0],"r");
    close(pdes[1]);

    RETURN_C_METHOD(jexc_new_object(jexc_find_class("java/lang/Process")));
}

/* method getErrorStream ()Ljava/io/InputStream; Lang_Process_getErrorStream */
DEFINE_C_METHOD(Lang_Process_getErrorStream)
{
    DECL_C_METHOD_VAR;
    jexc_object *p;

    p = jexc_new_object(jexc_find_class("java/io/InputStream"));
    VAR0(p)=(jexc_word)jexc_alloc_opaque(sizeof(struct jexc_io_stream));
    VAR0_OPAQUE(struct jexc_io_stream *,p)->fp = child_stderr;
    RETURN_C_METHOD(p);
}

/* method waitFor ()I			Lang_Process_waitFor*/
DEFINE_C_METHOD(Lang_Process_waitFor)
{
    DECL_C_METHOD_VAR;
    waitpid(child_pid,&child_exit_status,0);
    fclose(child_stderr);
    RETURN_C_METHOD_INT(child_exit_status);
}

/* method exitValue ()I			Lang_Process_exitValue */
DEFINE_C_METHOD(Lang_Process_exitValue)
{
    DECL_C_METHOD_VAR;
    RETURN_C_METHOD_INT(child_exit_status);
}

