Milán Major

netscape-revival

1 branch
Code

sun-java/javah/javah.c

/* 
 * @(#)javah.c	1.51 95/10/16 James Gosling
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

/*
 * Modified for JRI -- Warren Harris
 * Copyright (c) 1996 Netscape Communications Corp. All Rights Reserved.
 */

/*-
 *      produce C header files from an java object file
 *      produce C stub files from an java object file
 */

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include "tree.h"
#include "oobj.h"
#include "interpreter.h"
#include "signature.h"
#include "io_md.h"	/* sysOpen() */
#include "prarena.h"

#ifndef RELEASE
#  define RELEASE "Unknown version"
#endif

static int renameIfDiff(char *tempfn, char *newfn, char *newdir);
struct fieldblock **makeslottable(ClassClass *);

long stubmode = 0;
long stubtable[2];

static FILE *outfp = 0;
static char *out = 0;
static char *dir = ".";
static char *tempfn = 0;
static char *tempdir = "/tmp";
static char *currentclassname;

static int jriMode = 0;
static int macMode = 0;
static int componentMode = 0;
static char* prefixString = NULL;

/*
    We will need the class name in two forms -
	1) in a form suitable for a file name.  To get this we replace
	   the slashes between package names with F_DELIM.
	2) in the form of a C-symbol.  To get this we replace the
	   slashes between package names with C_DELIM.

    NOTE - for now we use the same deliminter for both C symbols and
	   for filenames.  It is '_' which does not guarrantee no
	   conflicts in either case but at least is consistent.
*/

#define DIR_DELIM   '/'
#define C_DELIM     '_'
#define F_DELIM     '_'

struct structdecl {
    char *class;
    struct structdecl *next;
};
static struct structdecl *structdecls;

static char *
strsub(char *src, char *dst, char sub)
{
    char c;
    char *d = dst;

    while ((c = *src++) != 0)
	if (c == DIR_DELIM)
	    *d++ = sub;
	else
	    *d++ = c;
    *d = '\0';
    return dst;
}

static char *
strnsub(char *src, char *dst, char sub, int n)
{
    char c;
    char *d = dst;

    while (n-- > 0)
	if ((c = *src++) == DIR_DELIM)
	    *d++ = sub;
	else
	    *d++ = c;
    *d = '\0';
    return dst;
}

#define MAC_FILE_LENGTH	29	/* 32 - 2 (for the ".h" or ".c") - 1 (for the count) */

static void
GetFileName(char* src, char* hfname, size_t hfsize)
{
    strsub(src, hfname, F_DELIM);
    if (macMode) {
	int len = strlen(hfname);
	if (len > MAC_FILE_LENGTH) {
	    int i = 0, j = 0;
	    char c;

	  loop:
	    /* at least write the first character of each word */
	    hfname[j++] = src[i++]; 

	    if (len - i + j > MAC_FILE_LENGTH) {
		/*
		** if there's not enough room for all the rest, strip the
		** rest of the first package name and try again
		*/
		int k = i;
		while (k < MAC_FILE_LENGTH) {
		    if (src[k] == DIR_DELIM) {
			hfname[j++] = F_DELIM;
			i = k+1;
			if (i < MAC_FILE_LENGTH)
			    goto loop;
			else
			    break;
		    }
		    k++;
		}
	    }
	    /*
	    ** if we get here there are no more DIR_DELIMs, or the rest
	    ** fits -- so just copy the rest of whatever's left
	    */
	    while (j < MAC_FILE_LENGTH && (c = src[i++]) != 0) {
		if (c == DIR_DELIM)
		    hfname[j++] = F_DELIM;
		else
		    hfname[j++] = c;
	    }
	    hfname[j++] = '\0';
	}
    }
}

/*
** Open a temporary file
*/
static FILE *open_output(void) 
{
    if (outfp != 0) {
	return outfp;
    }
    tempfn = tempnam(tempdir, "javah");
    if ((outfp = fopen(tempfn, "w")) == 0) {
	perror(tempfn);
    }
    /* fprintf(stderr, "writing to %s\n", tempfn); */

    fprintf(outfp, "/* DO NOT EDIT THIS FILE - it is machine generated */\n");
    if (jriMode || componentMode) {
        fprintf(outfp, "#include \"jri.h\"\n\n");
    }
    else {
        if (stubmode) {
            fprintf(outfp, "#include \"StubPreamble.h\"\n");
        } else {
            fprintf(outfp, "#include \"native.h\"\n");
        }
    }
    return outfp;
}

/* Close the temporary file and rename it
 * to the final output file if the content
 * has changed. */
static int close_output(void) 
{
    char fname[300];

    if (outfp == 0) {
	return 0;
    }

    fclose(outfp);
    outfp = 0;

    while (structdecls) {
	struct structdecl *p = structdecls;
	structdecls = p->next;
	free(p->class);
	free(p);
    }

    structdecls = 0;

    if (out) {
	strncpy(fname, out, sizeof(fname));
    } else {
	char tempfname[300];
	GetFileName(currentclassname, tempfname, sizeof(tempfname));
	sprintf(fname, "%s/%s%s", dir, tempfname, stubmode ? ".c" : ".h");
    }

    /* fprintf(stderr, "rename %s to %s\n", tempfn, fname); */
    return renameIfDiff(tempfn, fname, dir);
}

static char*
SprintClassType(char* s, char* buf)
{
    register char *tn = buf;
    {
	register char *sp = (jriMode ? "struct " : "struct H");
	while (*sp)
	    *tn++ = *sp++;
    }
    for (; *s && *s != SIGNATURE_ENDCLASS;) {
	char c = *s++;
	
	if (c == DIR_DELIM)
	    *tn++ = C_DELIM;
	else
	    *tn++ = c;
    }
    *tn++ = ' ';
    *tn++ = '*';
    *tn = 0;
    if (*s == SIGNATURE_ENDCLASS)
	s++;
    return s;
}

static char *
SprintReverseType(char *s, char *fname, char *out)
{
    char buf[1000];
    register char *tn = "?";
    if (fname == 0)
	fname = "";
    switch (*s++) {
    default:
	switch (s[-1]) {
	case SIGNATURE_ANY:
	    tn = "void*";
	    break;
	case SIGNATURE_CHAR:
	    tn = (jriMode ? "jchar" : "unicode");
	    break;
	case SIGNATURE_BYTE:
	    tn = (jriMode ? "jbyte" : "char");
	    break;
	case SIGNATURE_ENUM:
	    tn = "enum";
	    break;
	case SIGNATURE_FLOAT:
	    tn = (jriMode ? "jfloat" : "float");
	    break;
	case SIGNATURE_DOUBLE:
	    tn = (jriMode ? "jdouble" : "double");
	    break;
	case SIGNATURE_BOOLEAN:
	    tn = (jriMode ? "jbool" : "/*boolean*/ long");
	    break;
	case SIGNATURE_INT:
	    tn = (jriMode ? "jint" : "long");
	    break;
	case SIGNATURE_LONG:
	    tn = (jriMode ? "jlong" : "int64_t");
	    break;
	case SIGNATURE_SHORT:
	    tn = (jriMode ? "jshort" : "short");
	    break;
	case SIGNATURE_CLASS:
	    s = SprintClassType(s, buf);
	    tn = buf;
	    break;
	case SIGNATURE_VOID:
	    tn = "void";
	    break;
	}
	sprintf(out, (*fname
	      ? (tn[strlen(tn) - 1] == '*'
		 ? "%s%s"
		 : "%s %s")
	      : "%s"),
	tn, fname);
	break;
    case 0:
	strcpy(out, fname);
	s--;
	break;
    case SIGNATURE_ARRAY:
	switch (*s++) {
	  case SIGNATURE_BYTE:
            if (jriMode)
                sprintf(out, *fname ? "jbyteArray %s" : "jbyteArray ", fname);
            else
                sprintf(out, *fname ? "HArrayOfByte *%s" : "HArrayOfByte *", fname);
	    break;
	  case SIGNATURE_CHAR:
            if (jriMode)
                sprintf(out, *fname ? "jcharArray %s" : "jcharArray ", fname);
            else
                sprintf(out, *fname ? "HArrayOfChar *%s" : "HArrayOfChar *", fname);
	    break;
	  case SIGNATURE_SHORT:
            if (jriMode)
                sprintf(out, *fname ? 
                        "jshortArray %s" : "jshortArray ", fname);
            else
                sprintf(out, *fname ? 
                        "HArrayOfShort *%s" : "HArrayOfShort *", fname);
	    break;
	  case SIGNATURE_INT:
            if (jriMode)
                sprintf(out, *fname ? "jintArray %s" : "jintArray ", fname);
            else
                sprintf(out, *fname ? "HArrayOfInt *%s" : "HArrayOfInt *", fname);
	    break;
	  case SIGNATURE_BOOLEAN:
            if (jriMode)
                sprintf(out, *fname ? "jbooleanArray %s" :
                        "jbooleanArray ", fname);
            else
                sprintf(out, *fname ? "/*boolean*/ HArrayOfInt *%s" :
                        "HArrayOfInt *", fname);
	    break;
	  case SIGNATURE_LONG:
            if (jriMode)
                sprintf(out, *fname ? "jlongArray %s" : "jlongArray ", fname);
            else
                sprintf(out, *fname ? "HArrayOfLong *%s" : "HArrayOfLong *", fname);
	    break;
	  case SIGNATURE_FLOAT:
            if (jriMode)
                sprintf(out, 
                        *fname ? "jfloatArray %s" : "jfloatArray ", fname);
            else
                sprintf(out, 
                        *fname ? "HArrayOfFloat *%s" : "HArrayOfFloat *", fname);
	    break;
	  case SIGNATURE_DOUBLE:
            if (jriMode)
                sprintf(out, 
                        *fname ? "jdoubleArray %s" : "jdoubleArray ", fname);
            else
                sprintf(out, 
                        *fname ? "HArrayOfDouble *%s" : "HArrayOfDouble *", fname);
	    break;
	  case SIGNATURE_CLASS:
	    if (!strncmp(s,"java/lang/String;", sizeof("java/lang/String;")-1)) {
	        s += sizeof("java/lang/String;") - 1;
                if (jriMode)
                    sprintf(out, *fname ? "jstringArray %s" : "jstringArray ",
                            fname);
                else
                    sprintf(out, *fname ? "HArrayOfString *%s" : "HArrayOfString *",
                            fname);
	    } else {
		while (*s++ != SIGNATURE_ENDCLASS);
                if (jriMode)
                    sprintf(out, *fname ? "jobjectArray %s" : "jobjectArray ",
                            fname);
                else
                    sprintf(out, *fname ? "HArrayOfObject *%s" : "HArrayOfObject *",
                            fname);
	    }
	    break;
	  case SIGNATURE_ARRAY:
	    while (*s == SIGNATURE_ARRAY) s++;
	    if (*s++ == SIGNATURE_CLASS)
		while (*s++ != SIGNATURE_ENDCLASS);
            if (jriMode)
                sprintf(out, 
                        *fname ? "jarrayArray %s" : "jarrayArray ", fname);
            else
                sprintf(out, 
                        *fname ? "HArrayOfArray *%s" : "HArrayOfArray *", fname);
	    break;
	}
	break;
    case SIGNATURE_FUNC:
	{
	    int constructor = strcmp(fname, "<init>") == 0;
	    char cname[300];

	    strsub(currentclassname, cname, C_DELIM);
	    sprintf(buf, (jriMode ? "%s_%s(JRIEnv* env, struct " : "%s_%s(struct H"),
		    cname,
		    constructor ? (jriMode ? "new" : "Initializor") : fname);
	    fname = buf + strlen(buf);
	    sprintf(fname, "%s* self,", cname);
	    fname += strlen(fname);
	    while (*s != SIGNATURE_ENDFUNC && *s) {
		s = SprintReverseType(s, (char *) 0, fname);
		fname += strlen(fname);
		*fname++ = ',';
	    }
	    if (fname[-1] == ',') fname--;
	    *fname++ = SIGNATURE_ENDFUNC;
	    *fname++ = 0;
	    s = SprintReverseType(constructor ? "" : *s ? s + 1 : s, buf, out);
	}
	break;
    }
    return s;
}

static char *
PrintType(FILE *f, char *s, char *fname)
{
    char buf[1000];
    char fnb[100];
    register char *src, *dst;
    dst = fnb;
    for (src = fname; *src && dst - fnb < sizeof fnb - 1 &&
        *src != SIGNATURE_FUNC;) {
	char c = *src++;
	if (c == DIR_DELIM)
	    *dst++ = C_DELIM;
	else
	    *dst++ = c;
    }
    *dst = 0;
    s = SprintReverseType(s, fnb, buf);
    fwrite(buf, strlen(buf), 1, f);
    return s;
}

static char*
ConsumeArg(char* sig)
{
    switch (*sig++) {
      case SIGNATURE_CLASS:
	while (*sig++ != SIGNATURE_ENDCLASS);
	return sig;
      case SIGNATURE_ARRAY:
	return ConsumeArg(sig);
    }
    return sig;
}

static void
PrintCallArgs(FILE *f, char* sig)
{
    char arg = 'a';
    sig++;
    while (sig[0] != SIGNATURE_ENDFUNC) {
	fputs(", ", f);
	sig = ConsumeArg(sig);
	fputc(arg++, f);
    }
}

static void
PrintDefArgs(FILE *f, char* sig)
{
    char buf[300];
    char arg[2] = { 'a', '\0' };
    char* s = &sig[1];	/* skip SIGNATURE_FUNC */
    while (*s != SIGNATURE_ENDFUNC) {
	fputs(", ", f);
	s = SprintReverseType(s, arg, buf);
	fputs(buf, f);
	arg[0]++;
    }
}

/*
 * Returns 1 if diff, 0 if same, -1 if error
 */
static int
renameIfDiff(char *tempfn, char *newfn, char *newdir)
{
    FILE *f, *nf;
    char buf[1024];
    long c;

    if ((f = fopen(tempfn, "r")) == 0) {
	perror(tempfn);
	return -1;
    } else if ((nf = fopen(newfn, "r"))) {
	while ((c = getc(f)) == getc(nf)) {
	    if (c == -1) {
		fclose(f);
		fclose(nf);
		unlink(tempfn);
		if (verbose)
		    fprintf(stderr, "  (no change)\n");
		return 0;
	    }
	}
    }

    rewind(f);
    if (nf) {
	fclose(nf);
    }
    if ((nf = fopen(newfn, "w")) == 0) {
	if (mkdir(newdir, 0777) != 0) {
	    perror(newdir);
	    return -1;
	}
	nf = fopen(newfn, "w");
    }
    if (nf == 0) {
	perror(newfn);
	return -1;
    }
    while ((c = fread(buf, sizeof(char), sizeof(buf), f)) > 0) {
	fwrite(buf, sizeof(char), c, nf);
    }
    fclose(f);
    fclose(nf);
    unlink(tempfn);
    if (verbose)
	fprintf(stderr, "  %s => %s\n", tempfn, newfn);
    return 1;
}

static void
generateForwardDeclaration(FILE *f, char *p, int len) {
    char buf[128];
    struct structdecl *s;
    strnsub(p, buf, '_', len);
    for (s = structdecls ; s ; s = s->next) {
	if (!strcmp(s->class, buf)) {
	    return;
	}
    }
    if (jriMode)
	fprintf(f, "struct %s;\n", strnsub(p, buf, '_', len));
    else
	fprintf(f, "struct H%s;\n", strnsub(p, buf, '_', len));
    s = (struct structdecl *)malloc(sizeof(struct structdecl));
    s->next = structdecls;
    s->class = strdup(buf);
    structdecls = s;
}

static void
forwardDeclare(FILE *f, struct fieldblock *fb) 
{
    char *fs = fieldsig(fb);
    if (*fs == SIGNATURE_FUNC) {
	for(fs++ ; *fs != '\0' ; fs++) {
	    if (*fs == SIGNATURE_CLASS) {
		char *p = ++fs;
		while (*fs != SIGNATURE_ENDCLASS) fs++;
		generateForwardDeclaration(f, p, fs - p);
	    }
	}
    } else {
	while (*fs == SIGNATURE_ARRAY) fs++;
	if (*fs == SIGNATURE_CLASS) {
	    char *p = ++fs;
	    while (*fs != SIGNATURE_ENDCLASS) fs++;
	    generateForwardDeclaration(f, p, fs - p);
	}
    }
}

static void
GetResultType(char* t, char* typeBuf, char* *suffix, char* *unionField)
{
    char* type;
    if (*t == SIGNATURE_FUNC) {
	t++;
	while (*t++ != SIGNATURE_ENDFUNC);
    }
    switch (t[0]) {
      case SIGNATURE_VOID:
        type = "void";
	*suffix = "";
	*unionField = ".r";
	break;
      case SIGNATURE_BOOLEAN:
        type = "jbool";
	*suffix = "Boolean";
	*unionField = ".z";
	break;
      case SIGNATURE_BYTE:
        type = "jbyte";
	*suffix = "Byte";
	*unionField = ".b";
	break;
      case SIGNATURE_CHAR:
        type = "jchar";
	*suffix = "Char";
	*unionField = ".c";
	break;
      case SIGNATURE_SHORT:
        type = "jshort";
	*suffix = "Short";
	*unionField = ".s";
	break;
      case SIGNATURE_INT:
        type = "jint";
	*suffix = "Int";
	*unionField = ".i";
	break;
      case SIGNATURE_LONG:
        type = "jlong";
	*suffix = "Long";
	*unionField = ".l";
	break;
      case SIGNATURE_FLOAT:
        type = "jfloat";
	*suffix = "Float";
	*unionField = ".f";
	break;
      case SIGNATURE_DOUBLE:
        type = "jdouble";
	*suffix = "Double";
	*unionField = ".d";
	break;
      case SIGNATURE_CLASS:
	*suffix = "";
	*unionField = ".r";
	SprintClassType(&t[1], typeBuf);
	return;
      default:
        type = "jref";
	*suffix = "";
	*unionField = ".r";
	break;
    }
    while ((*typeBuf++ = *type++));
}

void
CPPFieldName(ClassClass* cb, struct fieldblock* fb, int currentSlot, char* buf)
{
    char* fn = fieldname(fb);
    sprintf(buf, "%s", fn);
}

void
CFieldName(ClassClass* cb, struct fieldblock* fb, int currentSlot, char* buf)
{
    char* cname = classname(cb);
    char hcname[300];   /* C symbol name.  */
    char cppname[300];
    strsub(cname, hcname, C_DELIM);
    CPPFieldName(cb, fb, currentSlot, cppname);
    sprintf(buf, "%s_%s", prefixString, cppname);
}

void
CPPMethodName(ClassClass* cb, struct fieldblock* fb, int currentSlot, char* buf)
{
    char* fn = fieldname(fb);

    if (jriMode) {
	char* fn = fieldname(fb);
        if (strcmp(fn, "<init>") == 0)
            sprintf(buf, "_new");
	else
            sprintf(buf, "%s", fn);
    }
    else
        sprintf(buf, "%s", fn);
}

void
CMethodName1(ClassClass* cb, struct fieldblock* fb, int currentSlot, char* buf)
{
    char* fn = fieldname(fb);

    if (jriMode) {
	char fname[256];
	char suffix[10];
	int gensym = 0;
	int prevSlots;
	char* fn = fieldname(fb);
	struct methodblock* prevMb = cbMethods(cb);
	for (prevSlots = 0; prevSlots < currentSlot; prevSlots++, prevMb++) {
	    if (strcmp(fn, fieldname(&prevMb->fb)) == 0)
		gensym++;
	}
	sprintf(suffix, (gensym > 0 ? "_%d" : ""), gensym);
        if (strcmp(fn, "<init>") == 0)
            sprintf(fname, "_new");
	else
	    mangleUTFString(fn, fname, 256, MangleUTF_Field);
        sprintf(buf, "%s%s", fname, suffix);
    }
    else
        sprintf(buf, "%s", fn);
}

void
CMethodName(ClassClass* cb, struct fieldblock* fb, int currentSlot, char* buf)
{
    char* cname = classname(cb);
    char hcname[300];   /* C symbol name.  */
    char cppname[300];
    strsub(cname, hcname, C_DELIM);
    CMethodName1(cb, fb, currentSlot, cppname);
    if (strncmp(cppname, "_new", 4) == 0)
	sprintf(buf, "%s%s", hcname, cppname);
    else
	sprintf(buf, "%s_%s", prefixString, cppname);
}

void
PrintPreamble(FILE* f, struct fieldblock* fb)
{
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    int access = fb->access;
    fprintf(f, "/*** %s%s%s%s%s %s ***/\n", 
            (access & ACC_PUBLIC ? "public " : 
             (access & ACC_PROTECTED ? "protected " : 
              (access & ACC_PRIVATE ? "private " : ""))),
            (access & ACC_STATIC ? "static " : ""),
            (access & ACC_FINAL ? "final " : ""),
            (access & ACC_NATIVE ? "native " : ""),
            fn, fs);
}

void
PrintKnownValue(FILE* f, char* cfname, struct fieldblock* fb, char* hcname)
{
    char* fn = fb->name;
    char namebuf[300];
    char* name;
    if (jriMode)
	name = cfname;
    else {
	sprintf(namebuf, "%s_%s", hcname, fn);
	name = namebuf;
    }
    if (fb->signature[0] == SIGNATURE_DOUBLE) {
	Java8 t1;
	double d;
	d = GET_DOUBLE(t1, twoword_static_address(fb));
	fprintf(f, "#define %s\t%gD\n", name, d);
    } else if (fb->signature[0] == SIGNATURE_LONG) {
	Java8 t1;
	int64_t l;
	char buf[40];
	l = GET_INT64(t1, twoword_static_address(fb));
	ll2str(l, buf, buf + sizeof(buf));
	fprintf(f, "#define %s\t%sLL\n", name, buf);
    } else if (fb->signature[0] == SIGNATURE_FLOAT) {
	fprintf(f, "#define %s\t%gf\n", name,
		*normal_static_address(fb));
    } else {
	fprintf(f, "#define %s\t%dL\n", name,
		*normal_static_address(fb));
    }
}

static void
PrintBlockComment(FILE* f, char* format, ...)
{
    int i;
    va_list args;

    fprintf(f, "/");
    for (i = 0; i < 79; i++)
	fprintf(f, "*");
    fprintf(f, "\n * ");
    va_start(args, format);
    vfprintf(f, format, args);
    va_end(args);
    fprintf(f, "\n ");
    for (i = 0; i < 78; i++)
	fprintf(f, "*");
    fprintf(f, "/\n\n");
}

static void
GenerateFieldAccessor(FILE* f, struct fieldblock* fb, int nslots, ClassClass* cb, char* hcname)
{
    char* fs = fieldsig(fb);
    char cfname[300];
    CFieldName(cb, fb, nslots, cfname);
    if ((fb->access & ACC_STATIC) == 0) {
	char fieldType[300];
	char* suffix;
	char* unionType;
	PrintPreamble(f, fb);
	GetResultType(fs, fieldType, &suffix, &unionType);
	fprintf(f, "#define get_%s(env, obj) \\\n\t(", cfname);
	if (strcmp(suffix, "") == 0)
	    fprintf(f, "(%s)", fieldType);
	fprintf(f, "JRI_GetField%s(env, obj, fieldID_%s))\n", suffix, cfname);
	fprintf(f, "#define set_%s(env, obj, v) \\\n", cfname);
	fprintf(f, "\tJRI_SetField%s(env, obj, fieldID_%s, v)\n", suffix, cfname);
    } else if (fb->access & ACC_VALKNOWN) {
	PrintKnownValue(f, cfname, fb, hcname);
    } else {
	char fieldType[300];
	char* suffix;
	char* unionType;
	PrintPreamble(f, fb);
	GetResultType(fs, fieldType, &suffix, &unionType);
	fprintf(f, "#define get_%s(env, clazz) \\\n\t(", cfname);
	if (strcmp(suffix, "") == 0)
	    fprintf(f, "(%s)", fieldType);
	fprintf(f, "JRI_GetStaticField%s(env, clazz, fieldID_%s))\n",
		suffix, cfname);
	fprintf(f, "#define set_%s(env, clazz, v) \\\n", cfname);
	fprintf(f, "\tJRI_SetStaticField%s(env, clazz, fieldID_%s, v)\n", suffix, cfname);
    }
    fprintf(f, "\n");
}

static void
GenerateDEBUGFieldAccessor(FILE* f, struct fieldblock* fb, int nslots, ClassClass* cb, char* hcname)
{
    char* fs = fieldsig(fb);
    char cfname[300];
    CFieldName(cb, fb, nslots, cfname);
    if ((fb->access & ACC_STATIC) == 0) {
	char fieldType[300];
	char* suffix;
	char* unionType;
	PrintPreamble(f, fb);
	GetResultType(fs, fieldType, &suffix, &unionType);
	fprintf(f, "extern JRI_PUBLIC_API(%s)\nget_%s(JRIEnv* env, %s* obj);\n", 
		fieldType, cfname, hcname);
	fprintf(f, "extern JRI_PUBLIC_API(void)\nset_%s(JRIEnv* env, %s* obj, %s v);\n",
		cfname, hcname, fieldType);
    } else if (fb->access & ACC_VALKNOWN) {
	PrintKnownValue(f, cfname, fb, hcname);
    } else {
	char fieldType[300];
	char* suffix;
	char* unionType;
	PrintPreamble(f, fb);
	GetResultType(fs, fieldType, &suffix, &unionType);
	fprintf(f, "extern JRI_PUBLIC_API(%s)\nget_%s(JRIEnv* env, struct java_lang_Class* clazz);\n", 
		fieldType, cfname);
	fprintf(f, "extern JRI_PUBLIC_API(void)\nset_%s(JRIEnv* env, struct java_lang_Class* clazz, %s v);\n",
		cfname, fieldType);
    }
    fprintf(f, "\n");
}

static void
GenerateFieldAccessorExtras(FILE* f, struct fieldblock* fb, int nslots, ClassClass* cb, char* hcname)
{
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    char cfname[300];
    int known = fb->access & ACC_VALKNOWN;
    CFieldName(cb, fb, nslots, cfname);
    if (!known) {
	fprintf(f, "extern JRIFieldID FAR fieldID_%s;\n", cfname);
    }
    fprintf(f, "#define name_%s\t\"%s\"\n", cfname, fn);
    fprintf(f, "#define sig_%s \t\"%s\"\n", cfname, fs);

    if (!known) {
	fprintf(f, "#define use_%s(env, clazz)\t\\\n", cfname);
	fprintf(f, "\t(fieldID_%s =\t\\\n\t\tJRI_Get%sFieldID(env, clazz,\t\\\n\t\t\tname_%s,\t\\\n\t\t\tsig_%s))\n",
		cfname, (fb->access & ACC_STATIC ? "Static" : ""), cfname, cfname);
	
	fprintf(f, "#define unuse_%s(env, clazz)\t\\\n", cfname);
	fprintf(f, "\t\t(fieldID_%s = JRIUninitialized)\n", cfname);
    }
    fprintf(f, "\n");
}

static void
GenerateMethodAccessor(FILE* f, struct methodblock* mb, int nslots, ClassClass* cb, char* hcname)
{
    struct fieldblock* fb = &mb->fb;
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    int isStatic = fb->access & ACC_STATIC;
    char cfname[300];
    char resultType[300];
    char* suffix;
    char* unionType;

    GetResultType(fs, resultType, &suffix, &unionType);
    CMethodName(cb, fb, nslots, cfname);
    PrintPreamble(f, fb);
    if (strcmp(fn, "<init>") == 0) {
	fprintf(f, "#define %s(env, clazz", cfname);
	PrintCallArgs(f, fs);
	fprintf(f, ")\t\\\n");
	fprintf(f, "\t((struct %s*)JRI_NewObject(env)(env, JRI_NewObject_op, clazz, methodID_%s",
		hcname, cfname);
	PrintCallArgs(f, fs);
	fprintf(f, "))\n");
    }
    else {
	int isVoid = strcmp(resultType, "void") == 0;
	fprintf(f, "#define %s(env%s", cfname, (isStatic ? ", clazz" : ", obj"));
	PrintCallArgs(f, fs);
	fprintf(f, ") \\\n");
	fprintf(f, "\t(");
	if (strlen(suffix) == 0)
	    fprintf(f, "(%s)", resultType);
	fprintf(f, "JRI_Call%sMethod%s(env)(env, JRI_Call%sMethod_op, %s, methodID_%s",
		(isStatic ? "Static" : ""), 
		(isVoid ? "" : suffix),
		(isStatic ? "Static" : ""), 
		(isStatic ? "clazz" : "obj"),
		cfname);
	PrintCallArgs(f, fs);
	fprintf(f, "))\n");
    }
    fprintf(f, "\n");
}

static void
GenerateMethodAccessorSig(FILE* f, struct methodblock* mb, int nslots,
			  ClassClass* cb, char* hcname, int isNative)
{
    struct fieldblock* fb = &mb->fb;
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    int isStatic = fb->access & ACC_STATIC;
    char cfname[300];
    char resultType[300];
    char* suffix;
    char* unionType;

    GetResultType(fs, resultType, &suffix, &unionType);
    CMethodName(cb, fb, nslots, cfname);
    if (strcmp(fn, "<init>") == 0) {
	fprintf(f, "JRI_PUBLIC_API(struct %s*)\n%s%s(JRIEnv* env, struct java_lang_Class* clazz",
		hcname, (isNative ? "native_" : ""), cfname);
	if (isNative)
	    fprintf(f, ", JRIMethodID methodID");
	PrintDefArgs(f, fs);
	fprintf(f, ")");
    }
    else {
	fprintf(f, "JRI_PUBLIC_API(%s)\n%s%s(JRIEnv* env, ", resultType,
		(isNative ? "native_" : ""), cfname);
	if (isStatic)
	    fprintf(f, "struct java_lang_Class* clazz");
	else
	    fprintf(f, "struct %s* self", hcname);
	PrintDefArgs(f, fs);
	fprintf(f, ")");
    }
}

static void
GenerateExternMethodAccessor(FILE* f, struct methodblock* mb, int nslots,
			     ClassClass* cb, char* hcname, int isNative)
{
    struct fieldblock* fb = &mb->fb;
    PrintPreamble(f, fb);
    fprintf(f, "extern ");
    GenerateMethodAccessorSig(f, mb, nslots, cb, hcname, isNative);
    fprintf(f, ";\n\n");
}

static void
GenerateMethodAccessorExtras(FILE* f, struct methodblock* mb, int nslots, ClassClass* cb, char* hcname)
{
    struct fieldblock* fb = &mb->fb;
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    char cfname[300];
    char resultType[300];
    char* suffix;
    char* unionType;

    GetResultType(fs, resultType, &suffix, &unionType);
    CMethodName(cb, fb, nslots, cfname);
    PrintPreamble(f, fb);
    fprintf(f, "extern JRIMethodID FAR methodID_%s;\n", cfname);
    fprintf(f, "#define name_%s\t\"%s\"\n", cfname, fn);
    fprintf(f, "#define sig_%s \t\"%s\"\n", cfname, fs);

    fprintf(f, "#define use_%s(env, clazz)\t\\\n", cfname);
    fprintf(f, "\t(methodID_%s =\t\\\n\t\tJRI_Get%sMethodID(env, clazz,\t\\\n\t\t\tname_%s,\t\\\n\t\t\tsig_%s))\n",
	    cfname, (fb->access & ACC_STATIC ? "Static" : ""), cfname, cfname);

    fprintf(f, "#define unuse_%s(env, clazz)\t\\\n", cfname);
    fprintf(f, "\t(methodID_%s = JRIUninitialized)\n", cfname);

    fprintf(f, "\n");
}

static void
GenerateCPPFieldAccessor(FILE* f, struct fieldblock* fb, int nslots, ClassClass* cb, char* hcname)
{
    int access = fb->access;
    if ((access & ACC_STATIC) == 0) { 
	char* fs = fieldsig(fb);
	char cfname[300];
	char cppname[300];
	char fieldType[300];
	char* suffix;
	char* unionType;
	CFieldName(cb, fb, nslots, cfname);
	CPPFieldName(cb, fb, nslots, cppname);
	GetResultType(fs, fieldType, &suffix, &unionType);
	
	fprintf(f, "\n\t");
	PrintPreamble(f, fb);
	fprintf(f, "\t%s %s(JRIEnv* env) {\n",
		fieldType, cppname);
	fprintf(f, "\t\treturn get_%s(env, this);\n\t}\n", cfname);
	fprintf(f, "\tvoid %s(JRIEnv* env, %s v) {\n",
		cppname, fieldType);
	fprintf(f, "\t\tset_%s(env, this, v);\n\t}\n", cfname);
    }
}

static void
GenerateCPPMethod(FILE* f, struct methodblock* mb, int nslots, ClassClass* cb, char* hcname)
{
    struct fieldblock* fb = &mb->fb;
    char* fn = fieldname(fb);
    char* fs = fieldsig(fb);
    int isStatic = fb->access & ACC_STATIC;
    int isConstr = strcmp(fn, "<init>") == 0;
    char cfname[300];
    char cppname[300];
    char resultType[300];
    char* suffix;
    char* unionType; 
    CMethodName(cb, fb, nslots, cfname);
    CPPMethodName(cb, fb, nslots, cppname);
    GetResultType(fs, resultType, &suffix, &unionType);
    fprintf(f, "\n\t");
    PrintPreamble(f, fb);
    if (isConstr)
	fprintf(f, "\tstatic %s* %s(JRIEnv* env, struct java_lang_Class* clazz",
		hcname, cppname);
    else if (isStatic)
	fprintf(f, "\tstatic %s %s(JRIEnv* env, struct java_lang_Class* clazz",
		resultType, cppname);
    else
	fprintf(f, "\t%s %s(JRIEnv* env",
		resultType, cppname);
    PrintDefArgs(f, fs);
    fprintf(f, ") {\n");
    if (isConstr) {
	fprintf(f, "\t\treturn %s(env, clazz", cfname);
    }
    else {
	fprintf(f, "\t\t%s%s(env, ",
		(strcmp(resultType, "void") == 0 ? "" : "return "),
		cfname);
	fprintf(f, (isStatic ? "clazz" : "this"));
    }
    PrintCallArgs(f, fs);
    fprintf(f, ");\n\t}\n");
}

static int
JRIDumpClassHeader(ClassClass * cb)
{
    FILE *f;
    register struct methodblock *mb;
    register nslots;
    char hfname[300];   /* header file name */
    char hcname[300];   /* C symbol name.  */
    int needsComment = TRUE;

    currentclassname = classname(cb);
    GetFileName(currentclassname, hfname, sizeof(hfname));
    strsub(currentclassname, hcname, C_DELIM);
    if (prefixString == NULL) {
	prefixString = hcname;
    }

    if ((f = open_output()) == 0) {
	return -1;
    }

    if (verbose)
	fprintf(stderr, "=> %s\n", tempfn);
    fprintf(f, "/* Header for class %s */\n\n", currentclassname);
    fprintf(f, "#ifndef _%s_H_\n#define _%s_H_\n\n",
	    hcname, hcname);

    fprintf(f, "#ifdef __cplusplus\n");
    fprintf(f, "extern \"C\" {\n");
    fprintf(f, "#endif /* __cplusplus */\n\n");

    /* first generate forward declarations */
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if ((fb->access & ACC_STATIC) == 0) {
	    forwardDeclare(f, fb);
	}
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	forwardDeclare(f, fb);
    }
    fprintf(f, "struct java_lang_Class;\n\n", hcname, hcname);

    PrintBlockComment(f, "Class %s", currentclassname);

    fprintf(f, "typedef struct %s %s;\n\n", hcname, hcname);
    fprintf(f, "#define classname_%s\t\"%s\"\n\n", hcname, currentclassname);
    fprintf(f, "#define class_%s(env) \\\n\t((struct java_lang_Class*)JRI_FindClass(env, classname_%s))\n\n",
	    hcname, hcname);
    makeslottable(cb);

    /* generate public field accessors  */
    needsComment = TRUE;
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (fb->access & ACC_PUBLIC) {
	    if (needsComment) {
		PrintBlockComment(f, "Public Field Accessors");
		fprintf(f, "#ifdef DEBUG\n\n");
		needsComment = FALSE;
	    }
	    GenerateDEBUGFieldAccessor(f, fb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#else /* !DEBUG */\n\n");
    }
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (fb->access & ACC_PUBLIC) {
	    GenerateFieldAccessor(f, fb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#endif /* !DEBUG*/\n\n");
    }
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (fb->access & ACC_PUBLIC) {
	    GenerateFieldAccessorExtras(f, fb, nslots, cb, hcname);
	}
    }

    /* generate public methods  */
    needsComment = TRUE;
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (fb->access & ACC_PUBLIC) {
	    if (needsComment) {
		PrintBlockComment(f, "Public Methods");
		fprintf(f, "#ifdef DEBUG\n\n");
		needsComment = FALSE;
	    }
	    GenerateExternMethodAccessor(f, mb, nslots, cb, hcname, FALSE);
	}
    }
    if (!needsComment) {
	fprintf(f, "#else /* !DEBUG */\n\n");
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (fb->access & ACC_PUBLIC) {
	    GenerateMethodAccessor(f, mb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#endif /* !DEBUG*/\n\n");
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (fb->access & ACC_PUBLIC) {
	    GenerateMethodAccessorExtras(f, mb, nslots, cb, hcname);
	}
    }

    PrintBlockComment(f, "IMPLEMENTATION SECTION: \n\
 * Define the IMPLEMENT_%s symbol \n\
 * if you intend to implement the native methods of this class. This \n\
 * symbol makes the private and protected methods available. You should \n\
 * also call the register_%s routine \n\
 * to make your native methods available.", 
		      hcname, hcname);
    fprintf(f, "extern JRI_PUBLIC_API(struct java_lang_Class*)\nuse_%s(JRIEnv* env);\n\n", hcname, hcname);
    fprintf(f, "extern JRI_PUBLIC_API(void)\nunuse_%s(JRIEnv* env);\n\n", hcname, hcname);
    fprintf(f, "extern JRI_PUBLIC_API(struct java_lang_Class*)\nregister_%s(JRIEnv* env);\n\n", hcname, hcname);
    fprintf(f, "extern JRI_PUBLIC_API(void)\nunregister_%s(JRIEnv* env);\n\n", hcname, hcname);
    fprintf(f, "#ifdef IMPLEMENT_%s\n\n", hcname);

    /* generate native declarations */
    needsComment = TRUE;
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (fb->access & ACC_NATIVE) {
	    if (needsComment) {
		PrintBlockComment(f, "Native Methods: \n\
 * These are the signatures of the native methods which you must implement.");
		needsComment = FALSE;
	    }
	    GenerateExternMethodAccessor(f, mb, nslots, cb, hcname, TRUE);
	}
    }

    /* generate private/protected field accessors  */
    needsComment = TRUE;
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (!(fb->access & ACC_PUBLIC)) {
	    if (needsComment) {
		PrintBlockComment(f, "Implementation Field Accessors: \n\
 * You should only use these from within the native method definitions.");
		fprintf(f, "#ifdef DEBUG\n\n");
		needsComment = FALSE;
	    }
	    GenerateDEBUGFieldAccessor(f, fb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#else /* !DEBUG */\n\n");
    }
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (!(fb->access & ACC_PUBLIC)) {
	    GenerateFieldAccessor(f, fb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#endif /* !DEBUG*/\n\n");
    }
    for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	struct fieldblock* fb = &cb->fields[nslots];
	if (!(fb->access & ACC_PUBLIC)) {
	    GenerateFieldAccessorExtras(f, fb, nslots, cb, hcname);
	}
    }

    /* generate private/protected methods  */
    needsComment = TRUE;
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (!(fb->access & ACC_PUBLIC)) {
	    if (needsComment) {
		PrintBlockComment(f, "Implementation Methods: \n\
 * You should only use these from within the native method definitions.");
		fprintf(f, "#ifdef DEBUG\n\n");
		needsComment = FALSE;
	    }
	    GenerateExternMethodAccessor(f, mb, nslots, cb, hcname, FALSE);
	}
    }
    if (!needsComment) {
	fprintf(f, "#else /* !DEBUG */\n\n");
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (!(fb->access & ACC_PUBLIC)) {
	    GenerateMethodAccessor(f, mb, nslots, cb, hcname);
	}
    }
    if (!needsComment) {
	fprintf(f, "#endif /* !DEBUG*/\n\n");
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	if (!(fb->access & ACC_PUBLIC)) {
	    GenerateMethodAccessorExtras(f, mb, nslots, cb, hcname);
	}
    }

    fprintf(f, "#endif /* IMPLEMENT_%s */\n\n", hcname);

    /* be nice to those less fortunate */
    {
	cp_item_type *constant_pool = cb->constantpool;
	int i;
	int needsColon = 1;
	HClass* super = cbSuperclass(cb);
	char sname[300];

	fprintf(f, "#ifdef __cplusplus\n");
	fprintf(f, "} /* extern \"C\" */\n\n");

	PrintBlockComment(f, "C++ Definitions");
	for (i = 0; i < cb->implements_count; i++) {
	    char iname[300];
	    int interface_index = cb->implements[i];
	    char *interface_name = 
		GetClassConstantClassName(constant_pool, interface_index);
	    GetFileName(interface_name, iname, sizeof(iname));
	    fprintf(f, "#include \"%s.h\"\n", iname);
	}
	if (super != NULL) {
	    GetFileName(classname(unhand(super)), sname, sizeof(sname));
	    fprintf(f, "#include \"%s.h\"\n", sname);
	}
        
	fprintf(f, "\nstruct %s", hcname);
	for (i = 0; i < cb->implements_count; i++) {
	    char iname[300];
	    int interface_index = cb->implements[i];
	    char *interface_name = 
		GetClassConstantClassName(constant_pool, interface_index);
	    GetFileName(interface_name, iname, sizeof(iname));
	    fprintf(f, "%s virtual public %s", (needsColon ? " :" : ","), iname);
	    needsColon = 0;
	}
	if (super != NULL) {
	    fprintf(f, "%s virtual public %s", (needsColon ? " :" : ","), sname);
	    needsColon = 0;
	}
	fprintf(f, " {\n\n");

	fprintf(f, "\tstatic struct java_lang_Class* _use(JRIEnv* env) {\n");
	fprintf(f, "\t\treturn use_%s(env);\n\t}\n\n", hcname);
	    
	fprintf(f, "\tstatic void _unuse(JRIEnv* env) {\n");
	fprintf(f, "\t\tunuse_%s(env);\n\t}\n\n", hcname);
	    
	fprintf(f, "\tstatic struct java_lang_Class* _register(JRIEnv* env) {\n");
	fprintf(f, "\t\treturn register_%s(env);\n\t}\n\n", hcname);
	    
	fprintf(f, "\tstatic void _unregister(JRIEnv* env) {\n");
	fprintf(f, "\t\tunregister_%s(env);\n\t}\n\n", hcname);
	    
	fprintf(f, "\tstatic struct java_lang_Class* _class(JRIEnv* env) {\n");
	fprintf(f, "\t\treturn class_%s(env);\n\t}\n", hcname);
	
	needsComment = TRUE;
	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    if (fb->access & ACC_PUBLIC) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Public Field Accessors */");
		    needsComment = FALSE;
		}
		GenerateCPPFieldAccessor(f, fb, nslots, cb, hcname);
	    }
	}

	needsComment = TRUE;
	for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	    struct fieldblock* fb = &mb->fb;
	    if (fb->access & ACC_PUBLIC) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Public Methods */");
		    needsComment = FALSE;
		}
		GenerateCPPMethod(f, mb, nslots, cb, hcname);
	    }
	}

	fprintf(f, "\n#ifdef IMPLEMENT_%s\n", hcname);

	needsComment = TRUE;
	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    if (fb->access & ACC_PROTECTED) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Protected Field Accessors */");
		    needsComment = FALSE;
		}
		GenerateCPPFieldAccessor(f, fb, nslots, cb, hcname);
	    }
	}

	needsComment = TRUE;
	for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	    struct fieldblock* fb = &mb->fb;
	    if (fb->access & ACC_PROTECTED) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Protected Methods */");
		    needsComment = FALSE;
		}
		GenerateCPPMethod(f, mb, nslots, cb, hcname);
	    }
	}

	needsComment = TRUE;
	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    if (fb->access & ACC_PRIVATE) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Private Field Accessors */");
		    needsComment = FALSE;
		}
		GenerateCPPFieldAccessor(f, fb, nslots, cb, hcname);
	    }
	}

	needsComment = TRUE;
	for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	    struct fieldblock* fb = &mb->fb;
	    if (fb->access & ACC_PRIVATE) {
		if (needsComment) {
		    fprintf(f, "\n\t/* Private Methods */");
		    needsComment = FALSE;
		}
		GenerateCPPMethod(f, mb, nslots, cb, hcname);
	    }
	}

	fprintf(f, "\n#endif /* IMPLEMENT_%s */\n", hcname);

	fprintf(f, "};\n\n");

	fprintf(f, "#endif /* __cplusplus */\n\n");
    }

    fprintf(f, "#endif /* Class %s */\n", currentclassname);
    return out ? 0 : close_output();
}

static int
DumpClassHeader(ClassClass * cb)
{
    FILE *f;
    register struct fieldblock *fb;
    register struct methodblock *mb;
    register nslots;
    int offset = 0;
    char hfname[300];   /* header file name */
    char hcname[300];   /* C symbol name.  */

    currentclassname = classname(cb);
    GetFileName(currentclassname, hfname, sizeof(hfname));
    strsub(currentclassname, hcname, C_DELIM);
    if (prefixString == NULL) {
	prefixString = hcname;
    }

    if ((f = open_output()) == 0) {
	return -1;
    }

    if (verbose)
	fprintf(stderr, "=> %s\n", tempfn);
    fprintf(f, "/* Header for class %s */\n\n", hfname);
    fprintf(f, "#ifndef _Included_%s\n#define _Included_%s\n",
	    hcname, hcname);
    makeslottable(cb);
    if (strcmp(currentclassname, "java/lang/Object") != 0
	&& strcmp(currentclassname, "java/lang/Class")) {
	int NumFieldsWritten = 0;

	/* first generate forward declarations */
	for (nslots = 0; (unsigned)nslots < cbSlotTableSize(cb); nslots++) {
	    fb = (cbSlotTable(cb))[nslots];
	    if ((fb->access & ACC_STATIC) == 0) {
		forwardDeclare(f, fb);
	    }
	}

	fprintf(f, "\ntypedef struct Class%s {\n",
		hcname);
	for (nslots = 0; (unsigned)nslots < cbSlotTableSize(cb); nslots++) {
	    fb = (cbSlotTable(cb))[nslots];
	    if ((fb->access & ACC_STATIC) == 0) {
		char *fs = fieldsig(fb);
		NumFieldsWritten++;
		if (fb->u.offset != offset) {
		    fprintf(f, "    char _PAD%d_[%d];\n",
			    fb->u.offset, fb->u.offset - offset);
		    offset = fb->u.offset;
		}
		fprintf(f, "    ");
		switch (fs[0]) {
		  case SIGNATURE_ARRAY:
		    switch (fs[1]) {
		      case SIGNATURE_BYTE:
			fprintf(f, "struct HArrayOfByte *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_CHAR:
			fprintf(f, "struct HArrayOfChar *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_BOOLEAN:
			fprintf(f, "struct HArrayOfInt *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_SHORT:
			fprintf(f, "struct HArrayOfShort *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_INT:
			fprintf(f, "struct HArrayOfInt *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_LONG:
			fprintf(f, "struct HArrayOfLong *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_FLOAT:
			fprintf(f, "struct HArrayOfFloat *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_DOUBLE:
			fprintf(f, "struct HArrayOfDouble *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_ARRAY:
			fprintf(f, "struct HArrayOfArray *%s;\n", fieldname(fb));
			break;
		      case SIGNATURE_CLASS:
			fprintf(f, "struct HArrayOfObject *%s;\n", fieldname(fb));
			break;
		      default:
			fprintf(f, "void *%s;\n", fieldname(fb));
			break;
		    }
		    break;
		  case SIGNATURE_BYTE:
		  case SIGNATURE_CHAR:
		  case SIGNATURE_SHORT:
		    fprintf(f, "long %s;\n", fieldname(fb));
		    break;
		  default:
		    PrintType(f, fs, fieldname(fb));
		    fprintf(f, ";\n");
		}
		switch (fs[0]) {
		case SIGNATURE_ANY:
		    offset = fb->u.offset + sizeof(void *);
		    break;
		case SIGNATURE_BYTE:
		    offset = fb->u.offset + sizeof(/*char*/long);
		    break;
		case SIGNATURE_CHAR:
		    offset = fb->u.offset + sizeof(/*unicode*/long);
		    break;
		case SIGNATURE_DOUBLE:
		    offset = fb->u.offset + sizeof(double);
		    break;
		case SIGNATURE_ENUM:
		    offset = fb->u.offset + sizeof(/*enum*/long);
		    break;
		case SIGNATURE_FLOAT:
		    offset = fb->u.offset + sizeof(float);
		    break;
		case SIGNATURE_INT:
		    offset = fb->u.offset + sizeof(long);
		    break;
		case SIGNATURE_LONG:
		    offset = fb->u.offset + sizeof(int64_t);
		    break;
		case SIGNATURE_SHORT:
		    offset = fb->u.offset + sizeof(/*short*/long);
		    break;
		case SIGNATURE_VOID:
		    offset = fb->u.offset + sizeof(/*void*/long);
		    break;
		case SIGNATURE_BOOLEAN:
		    offset = fb->u.offset + sizeof(long);
		    break;
		default:
		    offset = fb->u.offset + sizeof(OBJECT);
		    break;
		}
            } else if (fb->access & ACC_VALKNOWN) {	
		char cfname[300];
		CFieldName(cb, fb, nslots, cfname);
		PrintKnownValue(f, cfname, fb, hcname);
	    } else {
                fprintf(f, "/* Inaccessible static: %s */\n", fieldname(fb));
	    }
	}
	if (NumFieldsWritten == 0)
	    fprintf(f, "    char PAD;\t/* ANSI C requires structures to have a least one member */\n");
	fprintf(f, "} Class%s;\n", hcname);
	fprintf(f, "HandleTo(%s);\n\n", hcname);
    }
    for (nslots = cb->methods_count, mb = cbMethods(cb); --nslots >= 0; mb++) {
	    fb = &mb->fb;
	    if (fb->access & ACC_NATIVE) {
		forwardDeclare(f, fb);
		fprintf(f, "extern ");
		PrintType(f, fieldsig(fb), fieldname(fb));
		fprintf(f, ";\n");
	    } 
    }
    fprintf(f, "#endif\n");

    return out ? 0 : close_output();
}

/*
 * Just decode those sigs that are meaningful to stubs.  We don't
 * support lots of things.
 */
static char *
SprintReverseArgs(char *sig, char *header, char *proto, char *call,
		  int argn, int *arg_size_p)
{

    int arg_size = 1;
    char *type;
    switch(*sig++) {
	case SIGNATURE_CLASS:
	    while (*sig++ != SIGNATURE_ENDCLASS);
	    type = "void *";
	    sprintf(call, ",((_P_[%d].p))", argn);
	    break;

	case SIGNATURE_BOOLEAN:
	    type = (jriMode ? "jbool" : "long");
	    sprintf(call, ",((_P_[%d].i))", argn);
	    break;

	case SIGNATURE_BYTE:
	    type = (jriMode ? "jbyte" : "long");
	    sprintf(call, ",((_P_[%d].i))", argn);
	    break;

	case SIGNATURE_SHORT:
	    type = (jriMode ? "jshort" : "long");
	    sprintf(call, ",((_P_[%d].i))", argn);
	    break;

	case SIGNATURE_CHAR:
	    type = (jriMode ? "jchar" : "long");
	    sprintf(call, ",((_P_[%d].i))", argn);
	    break;

	case SIGNATURE_INT:
	    type = (jriMode ? "jint" : "long");
	    sprintf(call, ",((_P_[%d].i))", argn);
	    break;

	case SIGNATURE_FLOAT:
	    type = (jriMode ? "jfloat" : "float");
	    sprintf(call, ",((_P_[%d].f))", argn);
	    break;

	case SIGNATURE_LONG:
	    type = (jriMode ? "jlong" : "int64_t");
	    sprintf(call, (jriMode ? ",JRI_GET_INT64(_t%d, _P_+%d)"
                           : ",GET_INT64(_t%d, _P_+%d)"), argn, argn);
	    arg_size = 2;
	    break;

	case SIGNATURE_DOUBLE:
	    type = (jriMode ? "jdouble" : "double");
	    sprintf(call, (jriMode ? ",JRI_GET_DOUBLE(_t%d, _P_+%d)"
                           : ",GET_DOUBLE(_t%d, _P_+%d)"), argn, argn);
	    arg_size = 2;
	    break;

	case SIGNATURE_VOID:
	    type = "void *";
	    sprintf(call, ",((_P_[%d].p))", argn);
	    break;

	case SIGNATURE_ARRAY:
	    for (; *sig == SIGNATURE_ARRAY ; sig++);
	    if (*sig++ == SIGNATURE_CLASS) {
		while (*sig++ != SIGNATURE_ENDCLASS);
	    }
	    type = "void *";
	    sprintf(call, ",((_P_[%d].p))", argn);
	    break;

	default:
	    fprintf(stderr, "%s: illegal signature\n", currentclassname);
	    return 0;
    }
    sprintf(proto, ", %s", type);
    if (arg_size == 2) 
	sprintf(header, (jriMode ? "\tJRI_JDK_Java8 _t%d;\n" : "\tJava8 _t%d;\n"),
                argn);
    *arg_size_p = arg_size;
    return sig;
}

static int
PrintStub(FILE *f, char *cfname, char *cname, struct methodblock *mb)
{
    struct fieldblock *fb = &mb->fb;
    char *s;
    char proto[1024], funcall[1024], header[1024];
    char *proto_p, *funcall_p, *header_p;
    int argn;
    char jriname[300];

    if (!(fb->access & ACC_NATIVE))
	return 0;
    
    mangleMethodName(mb, funcall, 1024, "_stub");
    fprintf(f, "/* SYMBOL: \"%s/%s%s\", %s */\n",
	    currentclassname, fieldname(fb), fieldsig(fb), funcall);
    if (jriMode) {
	fprintf(f, "JRI_PUBLIC_API(JRI_JDK_stack_item*)\n%s(JRI_JDK_stack_item* _P_, JRIEnv* _EE_) {\n",
		funcall);
    }
    else {
		/* We are using a JRI macro here in the non JRI case to get the
		   correct external linkage on windows.  This makes us source incompatible
		   with JDK stubs */
	fprintf(f, "JRI_PUBLIC_API(stack_item*)\n%s(stack_item* _P_, struct execenv* _EE_) {\n",
		funcall);
    }
    
    /* Generate function prototype args */
    s = fieldsig(fb) + 1;   /* first char is SIGNATURE_FUNC */

    proto_p = proto;
    header_p = header;
    *proto_p = *header_p = '\0';

    if (fb->access & ACC_STATIC) {
	argn = 0;		/* first argument is _P_[0] */
	strcpy(funcall, (jriMode ? "_EE_,NULL" : "NULL"));
    } else {
	argn = 1;
	strcpy(funcall, (jriMode ? "_EE_,_P_[0].p" : "_P_[0].p"));
    }
    funcall_p = funcall + strlen(funcall);

    while (s && *s != SIGNATURE_ENDFUNC) { 
	int argsize;
	s = SprintReverseArgs(s, header_p, proto_p, funcall_p, argn, &argsize);
	if (s == 0) return -1;
	header_p += strlen(header_p);
	proto_p += strlen(proto_p);
	funcall_p += strlen(funcall_p);
	argn += argsize;
	if (   header_p >= header + sizeof(header) || 
	       proto_p >= proto + sizeof(proto) || 
	       funcall_p >= funcall + sizeof(funcall))  { 
	    fprintf(stderr, "out of buffer space!\n");
	    return -1;
	}
    }
    if (jriMode) {
	sprintf(jriname, "native_%s", cfname);
	cfname = jriname;
    }
    switch(*++s) {
      case SIGNATURE_VOID:
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern void %s(void *%s);\n", cfname, proto);
          }
	  fprintf(f, "\t(void) %s(%s);\n", 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_;\n}\n");
	  break;


      case SIGNATURE_FLOAT:
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern float %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, "\t_P_[0].f = %s(%s);\n", 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 1;\n}\n");
	  break;

      case SIGNATURE_DOUBLE:
	  fprintf(f, (jriMode ? "\tJRI_JDK_Java8 _tval;\n" : "\tJava8 _tval;\n"));
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern double %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, (jriMode ? "\tJRI_SET_DOUBLE(_tval, _P_, %s(%s));\n"
                      : "\tSET_DOUBLE(_tval, _P_, %s(%s));\n"), 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 2;\n}\n");
	  break;

      case SIGNATURE_CLASS:
      case SIGNATURE_ARRAY:
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern void* %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, "\t_P_[0].p = %s(%s);\n", 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 1;\n}\n");
	  break;

      case SIGNATURE_BYTE:
      case SIGNATURE_SHORT:
      case SIGNATURE_CHAR:
      case SIGNATURE_INT:
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern long %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, "\t_P_[0].i = %s(%s);\n", 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 1;\n}\n");
	  break;

      case SIGNATURE_BOOLEAN:
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern long %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, "\t_P_[0].i = (%s(%s) ? 1 : 0);\n", 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 1;\n}\n");
	  break;

      case SIGNATURE_LONG:
	  fprintf(f, (jriMode ? "\tJRI_JDK_Java8 _tval;\n" : "\tJava8 _tval;\n"));
	  fprintf(f, "%s", header);
          if (!jriMode) {
              fprintf(f, "\textern int64_t %s(void *%s);\n",
                      cfname, proto);
          }
	  fprintf(f, (jriMode ? "\tJRI_SET_INT64(_tval, _P_, %s(%s));\n"
                      : "\tSET_INT64(_tval, _P_, %s(%s));\n"), 
		  cfname, funcall);
	  fprintf(f, "\treturn _P_ + 2;\n}\n");
	  break;

      default:
	  fprintf(stderr, "%s: unsupported function return type: %c\n",
		  currentclassname, *s);
	  return -1;
    }
    return 0;
}

int
DumpClassStub(ClassClass * cb)
{
    FILE *f;
    register struct methodblock *mb;
    register nslots;
    char fname[300];   /* stub file name */
    char cname[300];   /* C symbol name.  */

    currentclassname = classname(cb);
    GetFileName(currentclassname, fname, sizeof(fname));
    strsub(currentclassname, cname, C_DELIM);
    if (prefixString == NULL) {
	prefixString = cname;
    }

    if ((f = open_output()) == 0) {
	return -1;
    }
    if (verbose)
	fprintf(stderr, "=> %s\n", tempfn);

    fprintf(f, "/* Stubs for class %s */\n\n", currentclassname);
    makeslottable(cb);
    if (jriMode) {
	fprintf(f, "#ifdef IMPLEMENT_%s\n", cname);
	fprintf(f, "#define _implementing_%s\n", cname);
	fprintf(f, "#endif /* IMPLEMENT_%s */\n", cname);
	fprintf(f, "#define IMPLEMENT_%s\n", cname);
	fprintf(f, "#include \"%s.h\"\n\n", fname);

	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    int isStatic = (fb->access & ACC_STATIC);
	    char fieldType[300];
	    char* suffix;
	    char* unionType;
	    char cfname[300];
	    CFieldName(cb, fb, nslots, cfname);
	    GetResultType(fb->signature, fieldType, &suffix, &unionType);
	    if (fb->access & ACC_VALKNOWN) continue;

	    fprintf(f, "#ifndef UNUSED_%s\n", cfname);

	    fprintf(f, "JRIFieldID FAR fieldID_%s = JRIUninitialized;\n", cfname)
;
	    fprintf(f, "#ifdef DEBUG\n");
	    forwardDeclare(f, fb);
	    if (isStatic) {
		fprintf(f, "JRI_PUBLIC_API(%s)\nget_%s(JRIEnv* env, struct java_lang_Class* clazz) {\n", fieldType, cfname);
		fprintf(f, "\tif (fieldID_%s == JRIUninitialized) {\n", cfname);
		fprintf(f, "\t\tassert(!\"Forgot to call use_%s(env) before accessing field %s %s\");\n\t}\n",
			cname, fb->name, fb->signature);
		fprintf(f, "\treturn ");
		if (strcmp(suffix, "") == 0)
		    fprintf(f, "(%s)\n\t\t", fieldType);
		fprintf(f, "JRI_GetStaticField%s(env, clazz, fieldID_%s);\n}\n", suffix, cfname);

		fprintf(f, "JRI_PUBLIC_API(void)\nset_%s(JRIEnv* env, struct java_lang_Class* clazz, %s v) {\n",
			cfname, fieldType);
		fprintf(f, "\tif (fieldID_%s == JRIUninitialized) {\n", cfname);
		fprintf(f, "\t\tassert(!\"Forgot to call use_%s(env) before accessing field %s %s\");\n\t}\n",
			cname, fb->name, fb->signature);
		fprintf(f, "\tJRI_SetStaticField%s(env, clazz, fieldID_%s, v);\n}\n", suffix, cfname);
	    } else {
		fprintf(f, "JRI_PUBLIC_API(%s)\nget_%s(JRIEnv* env, struct %s* obj) {\n", fieldType, cfname, cname);
		fprintf(f, "\tif (fieldID_%s == JRIUninitialized) {\n", cfname);
		fprintf(f, "\t\tassert(!\"Forgot to call use_%s(env) before accessing field %s %s\");\n\t}\n",
			cname, fb->name, fb->signature);
		fprintf(f, "\treturn ");
		if (strcmp(suffix, "") == 0)
		    fprintf(f, "(%s)\n\t\t", fieldType);
		fprintf(f, "JRI_GetField%s(env, obj, fieldID_%s);\n}\n", suffix, cfname);

		fprintf(f, "JRI_PUBLIC_API(void)\nset_%s(JRIEnv* env, struct %s* obj, %s v) {\n",
			cfname, cname, fieldType);
		fprintf(f, "\tif (fieldID_%s == JRIUninitialized) {\n", cfname);
		fprintf(f, "\t\tassert(!\"Forgot to call use_%s(env) before accessing field %s %s\");\n\t}\n",
			cname, fb->name, fb->signature);
		fprintf(f, "\tJRI_SetField%s(env, obj, fieldID_%s, v);\n}\n", suffix, cfname);
	    }
	    fprintf(f, "#endif /* DEBUG */\n");
	    fprintf(f, "#endif /* UNUSED_%s */\n\n", cfname);
        }

        for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
            struct fieldblock* fb = &mb->fb;
	    char* fn = fieldname(fb);
	    char* fs = fieldsig(fb);
	    int isStatic = fb->access & ACC_STATIC;
	    int isConstr = strcmp(fn, "<init>") == 0;
	    char cfname[300];
	    char resultType[300];
	    char* suffix;
	    char* unionType; 
	    CMethodName(cb, fb, nslots, cfname);
	    GetResultType(fs, resultType, &suffix, &unionType);
		
	    fprintf(f, "#ifndef UNUSED_%s\n", cfname);
	    
	    fprintf(f, "JRIMethodID FAR methodID_%s = JRIUninitialized;\n", cfname);

	    fprintf(f, "#ifdef DEBUG\n");
	    GenerateMethodAccessorSig(f, mb, nslots, cb, cname, FALSE);
	    fprintf(f, " {\n");
	    fprintf(f, "\tif (methodID_%s == JRIUninitialized) {\n", cfname);
	    fprintf(f, "\t\tassert(!\"Forgot to call use_%s(env) before calling method %s %s\");\n\t}\n",
		    cname, fb->name, fb->signature);
	    if (isConstr) {
		fprintf(f, "\treturn (struct %s*)JRI_NewObject(env)(env, JRI_NewObject_op, clazz, methodID_%s",
			cname, cfname);
		PrintCallArgs(f, fs);
		fprintf(f, ");\n}\n");
	    }
	    else {
		int isVoid = strcmp(resultType, "void") == 0;
		fprintf(f, "\t%s", (isVoid ? "" : "return "));
		if (strlen(suffix) == 0)
		    fprintf(f, "(%s)", resultType);
		fprintf(f, "JRI_Call%sMethod%s(env)(env, JRI_Call%sMethod_op, %s, methodID_%s",
			(isStatic ? "Static" : ""), 
			(isVoid ? "" : suffix),
			(isStatic ? "Static" : ""), 
			(isStatic ? "clazz" : "self"),
			cfname);
		PrintCallArgs(f, fs);
		fprintf(f, ");\n}\n");
	    }
	    fprintf(f, "#endif /* DEBUG */\n");
	    fprintf(f, "#endif /* UNUSED_%s */\n\n", cfname);
        }

        fprintf(f, "#ifndef UNUSED_use_%s\n\n", cname);

	fprintf(f, "static jglobal _globalclass_%s = NULL;\n\n", cname);

	/************************************************************/
        /* Generate the class initializer */
        fprintf(f, "JRI_PUBLIC_API(struct java_lang_Class*)\nuse_%s(JRIEnv* env)\n{\n", cname);

        fprintf(f, "\tif (_globalclass_%s == NULL) {\n", cname);
        fprintf(f, "\t\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_%s);\n", 
                cname);
        fprintf(f, "\t\tif (clazz == NULL) {\n");
	fprintf(f, "\t\t\tJRI_ThrowNew(env, JRI_FindClass(env, \"java/lang/ClassNotFoundException\"), classname_%s);\n",
		cname);
	fprintf(f, "\t\t\treturn NULL;\n");
	fprintf(f, "\t\t}\n");
	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    char cfname[300];
	    CFieldName(cb, fb, nslots, cfname);
	    if (!(fb->access & ACC_VALKNOWN)) {
		fprintf(f, "\t\tuse_%s(env, clazz);\n", cfname);
	    }
        }
        for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
            struct fieldblock* fb = &mb->fb;
            char cfname[300];
            CMethodName(cb, fb, nslots, cfname);
	    fprintf(f, "\t\tuse_%s(env, clazz);\n", cfname);
        }
        fprintf(f, "\t\t_globalclass_%s = JRI_NewGlobalRef(env, clazz);\n", cname);
        fprintf(f, "\t\treturn clazz;\n");
        fprintf(f, "\t}\n\telse {\n");
        fprintf(f, "\t\treturn (struct java_lang_Class*)JRI_GetGlobalRef(env, _globalclass_%s);\n", cname);
        fprintf(f, "\t}\n");
        fprintf(f, "}\n\n");

	/************************************************************/
        /* Generate the class finalizer */
        fprintf(f, "JRI_PUBLIC_API(void)\nunuse_%s(JRIEnv* env)\n{\n", cname);
        fprintf(f, "\tif (_globalclass_%s != NULL) {\n", cname);
        fprintf(f, "\t\tstruct java_lang_Class* clazz = (struct java_lang_Class*)JRI_GetGlobalRef(env, _globalclass_%s);\n", 
                cname, cname);
	for (nslots = 0; (unsigned)nslots < cb->fields_count; nslots++) {
	    struct fieldblock* fb = &cb->fields[nslots];
	    char cfname[300];
	    CFieldName(cb, fb, nslots, cfname);
	    if (!(fb->access & ACC_VALKNOWN)) {
		fprintf(f, "\t\tunuse_%s(env, clazz);\n", cfname);
	    }
        }
        for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
            struct fieldblock* fb = &mb->fb;
            char cfname[300];
            CMethodName(cb, fb, nslots, cfname);
	    fprintf(f, "\t\tunuse_%s(env, clazz);\n", cfname);
        }
        fprintf(f, "\t\tJRI_DisposeGlobalRef(env, _globalclass_%s);\n", cname);
        fprintf(f, "\t\t_globalclass_%s = NULL;\n", cname);
        fprintf(f, "\t\tclazz = NULL;	/* prevent unused variable 'clazz' warning */\n", cname);
        fprintf(f, "\t}\n");
        fprintf(f, "}\n\n");

        fprintf(f, "#endif /* UNUSED_use_%s */\n\n", cname);

	/************************************************************/
        /* Generate the function to register natives */
        fprintf(f, "#ifdef _implementing_%s\n\n", cname);

        fprintf(f, "JRI_PUBLIC_API(struct java_lang_Class*)\nregister_%s(JRIEnv* env)\n{\n", cname);
        fprintf(f, "\tchar* nativeNamesAndSigs[] = {\n");
        for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
            struct fieldblock* fb = &mb->fb;
            char cfname[300];
            CMethodName(cb, fb, nslots, cfname);
            if (fb->access & ACC_NATIVE) {
                fprintf(f, "\t\t\"%s%s\",\n", fieldname(fb), fieldsig(fb));
            }
        }
        fprintf(f, "\t\tNULL\n");   /* trailing terminator */
        fprintf(f, "\t};\n");

        fprintf(f, "\tvoid* nativeProcs[] = {\n");
        for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
            struct fieldblock* fb = &mb->fb;
            char cfname[300];
            CMethodName(cb, fb, nslots, cfname);
            if (fb->access & ACC_NATIVE) {
                fprintf(f, "\t\t(void*)native_%s,\n", cfname);
            }
        }
        fprintf(f, "\t\tNULL\n");   /* trailing terminator */
        fprintf(f, "\t};\n");

        fprintf(f, "\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_%s);\n", 
                cname);
        fprintf(f, "\tif (clazz == NULL) {\n");
	fprintf(f, "\t\tJRI_ThrowNew(env, JRI_FindClass(env, \"java/lang/ClassNotFoundException\"), classname_%s);\n",
		cname);
	fprintf(f, "\t\treturn NULL;\n");
	fprintf(f, "\t}\n");

        fprintf(f, "\tJRI_RegisterNatives(env, clazz, nativeNamesAndSigs, nativeProcs);\n");
        fprintf(f, "\tuse_%s(env);\n", cname);
        fprintf(f, "\treturn clazz;\n");
        fprintf(f, "}\n\n");

	/************************************************************/
        /* Generate the function to unregister natives */
        fprintf(f, "JRI_PUBLIC_API(void)\nunregister_%s(JRIEnv* env)\n{\n", cname);
        fprintf(f, "\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_%s);\n", 
                cname);
        fprintf(f, "\tJRI_UnregisterNatives(env, clazz);\n");
        fprintf(f, "\tunuse_%s(env);\n", cname);
        fprintf(f, "}\n\n");

        fprintf(f, "#endif /* _implementing_%s */\n\n", cname);

	/************************************************************/
        fprintf(f, "/* These stub routines are generated for compatibility with the JDK: */\n\n");
        fprintf(f, "#ifndef NO_JDK\n\n");
    }
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
        char cfname[300];
        if (jriMode)
            CMethodName(cb, &mb->fb, nslots, cfname);
        else
            sprintf(cfname, "%s_%s", cname, fieldname(&mb->fb));
	if (mb->code == 0) {
	    if (PrintStub(f, cfname, cname, mb)) {
		fclose(f);
		unlink(tempfn);
		sysExit(-1);
	    }
	    fprintf(f, "\n");
	}
    }
    if (jriMode)
        fprintf(f, "#endif /* NO_JDK */\n\n");
    return out ? 0 : close_output();
}

int
DumpComponentHeader(ClassClass * cb)
{
    FILE *f;
    register struct methodblock *mb;
    register nslots;
    char fname[300];   /* stub file name */
    char cname[300];   /* C symbol name.  */

    currentclassname = classname(cb);
    GetFileName(currentclassname, fname, sizeof(fname));
    strsub(currentclassname, cname, C_DELIM);
    if (prefixString == NULL) {
	prefixString = cname;
    }

    if ((f = open_output()) == 0) {
	return -1;
    }
    if (verbose)
	fprintf(stderr, "=> %s\n", tempfn);

    makeslottable(cb);

    fprintf(f, "/* Component interface for %s */\n\n", currentclassname);
    fprintf(f, "#ifndef _Component_%s_\n#define _Component_%s_\n\n",
	    cname, cname);

    fprintf(f, "#ifdef __cplusplus\n");
    fprintf(f, "extern \"C\" {\n");
    fprintf(f, "#endif /* __cplusplus */\n\n");

    PrintBlockComment(f, "Component Types");
    fprintf(f, "typedef struct Interface_%s\n\tInterface_%s;\n\n",
	    cname, cname);
    fprintf(f, "typedef const Interface_%s*\n\tComponent_%s;\n\n",
	    cname, cname);

    PrintBlockComment(f, "Component Methods");
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	char* fn = fieldname(fb);
	char* fs = fieldsig(fb);
	int isStatic = fb->access & ACC_STATIC;
	int isConstr = strcmp(fn, "<init>") == 0;
	if (fb->access & ACC_PUBLIC && !isStatic && !isConstr) {
	    char cfname[300];
	    char resultType[300];
	    char* suffix;
	    char* unionType; 
	    CMethodName(cb, fb, nslots, cfname);
	    GetResultType(fs, resultType, &suffix, &unionType);
	    fprintf(f, "#define %s(comp", cfname);
	    PrintCallArgs(f, fs);
	    fprintf(f, ")\t\\\n");
	    fprintf(f, "\t((*(comp))->%s(comp", fn);
	    PrintCallArgs(f, fs);
	    fprintf(f, "))\n\n");
	}
    } 

    PrintBlockComment(f, "Component Interface Definition");
    fprintf(f, "struct Interface_%s {\n", cname);
    fprintf(f, "\tint (*getComponent)(Component_%s* comp, ComponentID* id, void** result);\n", cname);
    fprintf(f, "\tvoid*\treserved1;\n");
    fprintf(f, "\tvoid*\treserved2;\n");
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	char* fn = fieldname(fb);
	char* fs = fieldsig(fb);
	int isStatic = fb->access & ACC_STATIC;
	int isConstr = strcmp(fn, "<init>") == 0;
	if (fb->access & ACC_PUBLIC && !isStatic && !isConstr) {
	    char cfname[300];
	    char resultType[300];
	    char* suffix;
	    char* unionType; 
	    CMethodName(cb, fb, nslots, cfname);
	    GetResultType(fs, resultType, &suffix, &unionType);
	    fprintf(f, "\t%s\t(*%s)(Component_%s* comp", 
		    resultType, fn, cname);
	    PrintDefArgs(f, fs);
	    fprintf(f, ");\n");
	}
    } 
    fprintf(f, "};\n\n");

    fprintf(f, "#ifdef __cplusplus\n");
    fprintf(f, "} /* extern \"C\" */\n");
    fprintf(f, "#endif /* __cplusplus */\n\n");

    fprintf(f, "#endif /* _Component_%s_ */\n", cname);
    return out ? 0 : close_output();
}

int
DumpComponentStub(ClassClass * cb)
{
    FILE *f;
    register struct methodblock *mb;
    register nslots;
    char fname[300];   /* stub file name */
    char cname[300];   /* C symbol name */

    currentclassname = classname(cb);
    GetFileName(currentclassname, fname, sizeof(fname));
    strsub(currentclassname, cname, C_DELIM);
    if (prefixString == NULL) {
	prefixString = cname;
    }

    if ((f = open_output()) == 0) {
	return -1;
    }
    if (verbose)
	fprintf(stderr, "=> %s\n", tempfn);

    fprintf(f, "/* Component Java stubs for %s */\n\n", currentclassname);
    makeslottable(cb);

    fprintf(f, "#include \"%s.h\"\n\n", fname);

    PrintBlockComment(f, "Component Types");
    fprintf(f, "typedef struct JavaComponent_%s {\n", cname);
    fprintf(f, "\tInterface_%s*\tinterface;\n", cname);
    fprintf(f, "\tJRIEnv*\tenv;\n");
    fprintf(f, "\tjref\tobj;\n");
    fprintf(f, "} JavaComponent_%s;\n\n", cname);

    PrintBlockComment(f, "Component Methods");
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	char* fn = fieldname(fb);
	char* fs = fieldsig(fb);
	int isStatic = fb->access & ACC_STATIC;
	int isConstr = strcmp(fn, "<init>") == 0;
	if (fb->access & ACC_PUBLIC && !isStatic && !isConstr) {
	    char cfname[300];
	    char resultType[300];
	    char* suffix;
	    char* unionType; 
	    int isVoid;
	    CMethodName(cb, fb, nslots, cfname);
	    GetResultType(fs, resultType, &suffix, &unionType);
	    isVoid = strcmp(resultType, "void") == 0;
	    fprintf(f, "%s\nmethod_%s(JavaComponent_%s* comp", 
		    resultType, cfname, cname);
	    PrintDefArgs(f, fs);
	    fprintf(f, ") {\n");
	    fprintf(f, "\t%s", (isVoid ? "" : "return "));
	    if (strlen(suffix) == 0)
		fprintf(f, "(%s)", resultType);
	    fprintf(f, "JRI_CallMethod(env)(comp->env, comp->obj, methodID_%s", cfname);
	    PrintCallArgs(f, fs);
	    fprintf(f, ")%s;\n", unionType);
	    fprintf(f, "}\n\n");
	}
    }

    fprintf(f, "int\nmethod_%s_getComponent(JavaComponent_%s* comp, ComponentID* id, void** result) {\n", cname, cname);
    fprintf(f, "\treturn 0;\n");
    fprintf(f, "}\n\n");
    
    PrintBlockComment(f, "Component Interface Definition");
    fprintf(f, "const Interface_%s interface_%s = {\n", cname, cname);
    fprintf(f, "\tmethod_%s_getComponent,\n", cname);
    fprintf(f, "\tNULL,\n");
    fprintf(f, "\tNULL");
    for (nslots = 0, mb = cbMethods(cb); nslots < cb->methods_count; nslots++, mb++) {
	struct fieldblock* fb = &mb->fb;
	char* fn = fieldname(fb);
	int isStatic = fb->access & ACC_STATIC;
	int isConstr = strcmp(fn, "<init>") == 0;
	if (fb->access & ACC_PUBLIC && !isStatic && !isConstr) {
	    char cfname[300];
	    CMethodName(cb, fb, nslots, cfname);
	    fprintf(f, ",\n\tmethod_%s", cfname);
	}
    } 
    fprintf(f, "\n};\n\n");

    PrintBlockComment(f, "Component Constructor");
    fprintf(f, "Component_%s*\nmake_%s(JRIEnv* env, jref obj) {\n", cname, cname);
    fprintf(f, "\tJavaComponent_%s* comp = (JavaComponent_%s)\n\t\tmalloc(sizeof(JavaComponent_%s));\n",
	    cname, cname, cname);
    fprintf(f, "\tif (comp == NULL)\n\t\treturn NULL;\n");
    fprintf(f, "\tcomp->interface = interface_%s;\n", cname);
    fprintf(f, "\tcomp->env = env;\n");
    fprintf(f, "\tcomp->obj = obj;\n");
    fprintf(f, "\treturn comp;\n");
    fprintf(f, "};");

    return out ? 0 : close_output();
}

int DumpNatives(ClassClass *cb)
{
    struct methodblock *mb;
    int nslots;

    for (nslots = cb->methods_count, mb = cbMethods(cb); --nslots >= 0; mb++) {
	if (mb->fb.access & ACC_NATIVE) {
	    char funcall[1024];
	    mangleMethodName(mb, funcall, sizeof(funcall), "_stub");
	    fprintf(stdout, "%s\n", funcall);
	}
    }
    return 0;
}

static void
InitializeClassPath(int argc, char **argv)
{
    int i;
    const char *cp = getenv("CLASSPATH");
    if (cp) cp = strdup(cp);

    for (i = 1; i < argc; i++) {
	if (argv[i] && strcmp(argv[i], "-classpath") == 0) {
	    if (i+1 == argc || argv[i+1] == 0) {
		fprintf(stderr,
			"Missing destination directory name after "
			"'-classpath'\n");
		sysExit(1);
	    }
	    if (cp) free((char*)cp);
	    cp = strdup(argv[i+1]);
	}
    }
    setCLASSPATH(cp);
    return;
}

#include <path_md.h>		/* For LOCAL_DIR_SEPARATOR */

int
main(int argc, char **argv)
{
    int retcode = 0;
    int donesomething = 0;
    int natives = 0;
    SkipSourceChecks = 1;

    if ((progname = strrchr(argv[0], LOCAL_DIR_SEPARATOR)) != 0) {
        progname++;
    } else {
        progname = argv[0];
    }

    InhibitExecute = 1;

    PR_Init("javah", 16, 0, 0);
    InitializeClassPath(argc, argv);
    if (!DoImport("java/lang/Object", 0)) {
	fprintf(stderr, "java.lang.Object not found: aborting\n");
	sysExit(1);
    }
    while (--argc > 0) {
	if ((++argv)[0][0] == '-') {
	    if ((strcmp(*argv, "-d") == 0) && (argc > 1)) {
		dir = *++argv;
	        argc--;
	    } else if ((strcmp(*argv, "-o") == 0) && (argc > 1)) {
		out = *++argv;
		argc--;
	    } else if ((strcmp(*argv, "-td") == 0) && (argc > 1)) {
		tempdir = *++argv;
		argc--;
	    } else if (strcmp(*argv, "-stubs") == 0) {
		stubmode++;
	    } else if (strcmp(*argv, "-v") == 0) {
		verbose++;
	    } else if (strcmp(*argv, "-classpath") == 0) {
		argc--;
		argv++;
	    } else if (strcmp(*argv, "-version") == 0) {
                fprintf(stderr, "%s version \"%s\"\n", progname, RELEASE);
                donesomething++;
	    } else if (strcmp(*argv, "-natives") == 0) {
		natives++;
	    } else if (strcmp(*argv, "-jri") == 0) {
		jriMode = 1;
	    } else if (strcmp(*argv, "-component") == 0) {
		componentMode = 1;
		jriMode = 1;
	    } else if (strcmp(*argv, "-mac") == 0) {
		macMode = 1;
	    } else if (strcmp(*argv, "-prefix") == 0) {
		prefixString = *++argv;
		argc--;
	    } else{
		fprintf(stderr, "%s: illegal argument\n", *argv);
		close_output();
		return 1;
	    }
	} else if (strchr(*argv, '/')) {
	    fprintf(stderr, "Invalid class name: %s\n", *argv);
	    close_output();
	    return 1;
	} else {
	    ClassClass *cb;
	    char *classcopy = strdup(*argv), *p;

	    /* Convert all periods in the classname to slashes */
	    for (p = classcopy; ((p = strchr(p, '.')) != 0); *p++ = '/');

	    cb = FindClass(0, classcopy, TRUE);
	    donesomething++;
	    if (cb == 0) {
		retcode = 1;
		fprintf(stderr, "%s: no such class\n", classcopy);
		continue;
	    }
	    if (natives) {
		if (DumpNatives(cb) < 0) {
		    retcode = 1;
		}
	    } else if (componentMode && stubmode) {
		if (DumpComponentStub(cb) < 0) {
		    retcode = 1;
		}
	    } else if (componentMode) {
		if (DumpComponentHeader(cb) < 0) {
		    retcode = 1;
		}
	    } else if (stubmode) {
		if (DumpClassStub(cb) < 0) {
		    retcode = 1;
		}
	    } else if (jriMode) {
		if (JRIDumpClassHeader(cb) < 0) {
		    retcode = 1;
		}
	    } else {
		if (DumpClassHeader(cb) < 0) {
		    retcode = 1;
		}
	    }
	    prefixString = NULL;	/* reset it */
	}
    }
    if (!donesomething) {
	retcode = 1;
	fprintf(stderr, 
            "Usage: %s [-v] [-version] [-l filename] classes...\n", progname);
    }
    if (close_output() < 0) {
	retcode = 1;
    }
    return retcode;
}

int
OpenCode(char *fn, char *sfn, char *dir, struct stat * st)
{
    long codefd;
    if (fn == 0 || (codefd = sysOpen(fn, 0, 0400)) < 0
	    || stat(fn, st) < 0)
	return -2;
    return codefd;
}

HObject *
AllocHandle(struct methodtable *mptr, ClassObject *p)
{
    JHandle *h = malloc(sizeof(JHandle));

    h->methods = mptr;
    h->obj = (ClassObject *) p;
    return (HObject *) h;
}

ClassClass *AllocClass(void)
{
    ClassClass	*cb = NULL;
    cb = (ClassClass*) calloc(sizeof(ClassClass), 1);
    if (cb != NULL) {
	cb->classStorageArena = (ClassArena*) calloc(sizeof(ClassArena), 1);
	PR_InitArenaPool(&(cb->classStorageArena->pool), "class pool", 2 * 1024, 4);
    }

    return cb;
}


/* Dummies */
#undef DumpThreads

void
DumpThreads()
{
}

char *
vramalloc(int n)
{
    return malloc(n);
}


long
CallInterpreted(struct methodblock *mb, void *obj, ...) {
    return 0;
}

/* ResolveClassStringConstant is called by the classloader to resolve the
 * constant pool entry, before assigning a value to a final [i.e. constant]
 * String.
 *
 * For javah, we don't care.
 */

bool_t
ResolveClassStringConstant(ClassClass *cb, cp_index_type index, struct execenv *ee)
{
    return TRUE;
}