/* Program to write C++-suitable header files from a Java(TM) .class
file. This is similar to SUN's javah.
-Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
+Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "config.h"
#include "system.h"
+#include <math.h>
+
#include "jcf.h"
+#include "tree.h"
+#include "javaop.h"
+#include "java-tree.h"
#include "java-opcodes.h"
-#include <math.h>
+
+#include <getopt.h>
+
+\f
/* The output file. */
FILE *out = NULL;
/* Nonzero on failure. */
static int found_error = 0;
+/* Nonzero if we're generating JNI output. */
+static int flag_jni = 0;
+
/* Directory to place resulting files in. Set by -d option. */
const char *output_directory = "";
int stubs = 0;
struct JCF *current_jcf;
-struct JCF *main_jcf;
/* This holds access information for the last field we examined. They
let us generate "private:", "public:", and "protected:" properly.
If 0 then we haven't previously examined any field. */
static JCF_u2 last_access;
-#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
-
/* Pass this macro the flags for a class and for a method. It will
return true if the method should be considered `final'. */
#define METHOD_IS_FINAL(Class, Method) \
(((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
+/* Pass this macro the flags for a method. It will return true if the
+ method is native. */
+#define METHOD_IS_NATIVE(Method) \
+ ((Method) & ACC_NATIVE)
+
/* We keep a linked list of all method names we have seen. This lets
us determine if a method name and a field name are in conflict. */
struct method_name
{
unsigned char *name;
int length;
+ unsigned char *signature;
+ int sig_length;
struct method_name *next;
};
/* List of method names we've seen. */
static struct method_name *method_name_list;
-static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
-static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
-static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int, const char *));
-static void decompile_method PROTO ((FILE *, JCF *, int));
-static void add_class_decl PROTO ((FILE *, JCF *, JCF_u2));
+static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
+static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int));
+static int print_cxx_classname PARAMS ((FILE*, const char*, JCF*, int));
+static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
+static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *,
+ int));
+static void print_stub_or_jni PARAMS ((FILE*, JCF*, int, int, int,
+ const char *, int));
+static void print_full_cxx_name PARAMS ((FILE*, JCF*, int, int, int,
+ const char *, int));
+static void decompile_method PARAMS ((FILE*, JCF*, int));
+static void add_class_decl PARAMS ((FILE*, JCF*, JCF_u2));
+
+static int java_float_finite PARAMS ((jfloat));
+static int java_double_finite PARAMS ((jdouble));
+static void print_name PARAMS ((FILE *, JCF *, int));
+static void print_base_classname PARAMS ((FILE *, JCF *, int));
+static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
+static char *cxx_keyword_subst PARAMS ((const unsigned char *, int));
+static void generate_access PARAMS ((FILE *, JCF_u2));
+static int name_is_method_p PARAMS ((const unsigned char *, int));
+static char *get_field_name PARAMS ((JCF *, int, JCF_u2));
+static void print_field_name PARAMS ((FILE *, JCF *, int, JCF_u2));
+static const unsigned char *super_class_name PARAMS ((JCF *, int *));
+static void print_include PARAMS ((FILE *, const unsigned char *, int));
+static const unsigned char *decode_signature_piece
+ PARAMS ((FILE *, const unsigned char *, const unsigned char *, int *));
+static void print_class_decls PARAMS ((FILE *, JCF *, int));
+static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
+static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
+static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
+static int overloaded_jni_method_exists_p PARAMS ((const unsigned char *, int,
+ const char *, int));
+static void jni_print_char PARAMS ((FILE *, int));
JCF_u2 current_field_name;
JCF_u2 current_field_value;
#define HANDLE_END_FIELD() \
if (field_pass) \
{ \
- if (out) \
+ if (out && ! stubs && ! flag_jni) \
print_field_info (out, jcf, current_field_name, \
current_field_signature, \
- current_field_flags); \
+ current_field_flags); \
} \
- else \
+ else if (! stubs && ! flag_jni) \
add_class_decl (out, jcf, current_field_signature);
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
if (out) \
print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
} \
- else \
- add_class_decl (out, jcf, SIGNATURE);
+ else \
+ { \
+ print_method_info (NULL, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
+ if (! stubs && ! flag_jni) \
+ add_class_decl (out, jcf, SIGNATURE); \
+ }
#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
static int decompiled = 0;
#define HANDLE_END_METHOD() \
- if (out && method_printed) fputs (decompiled ? "\n" : ";\n", out);
+ if (out && method_printed) fputs (decompiled || stubs ? "\n" : ";\n", out);
#include "jcf-reader.c"
/* Some useful constants. */
#define F_NAN_MASK 0x7f800000
+#if (1 == HOST_FLOAT_WORDS_BIG_ENDIAN) && ! defined (HOST_WORDS_BIG_ENDIAN)
+#define D_NAN_MASK 0x000000007ff00000LL
+#else
#define D_NAN_MASK 0x7ff0000000000000LL
+#endif
/* Return 1 if F is not Inf or NaN. */
static int
java_float_finite (f)
jfloat f;
{
- union {
- jfloat f;
- int32 i;
- } u;
+ union Word u;
u.f = f;
/* We happen to know that F_NAN_MASK will match all NaN values, and
java_double_finite (d)
jdouble d;
{
- union {
- jdouble d;
- int64 i;
- } u;
+ union DWord u;
u.d = d;
/* Now check for all NaNs. */
- return (u.i & D_NAN_MASK) != D_NAN_MASK;
+ return (u.l & D_NAN_MASK) != D_NAN_MASK;
+}
+
+/* Print a character, appropriately mangled for JNI. */
+
+static void
+jni_print_char (stream, ch)
+ FILE *stream;
+ int ch;
+{
+ if (! flag_jni)
+ jcf_print_char (stream, ch);
+ else if (ch == '(' || ch == ')')
+ {
+ /* Ignore. */
+ }
+ else if (ch == '_')
+ fputs ("_1", stream);
+ else if (ch == ';')
+ fputs ("_2", stream);
+ else if (ch == '[')
+ fputs ("_3", stream);
+ else if (ch == '/')
+ fputs ("_", stream);
+ else if ((ch >= '0' && ch <= '9')
+ || (ch >= 'a' && ch <= 'z')
+ || (ch >= 'A' && ch <= 'Z'))
+ fputc (ch, stream);
+ else
+ {
+ /* "Unicode" character. */
+ fprintf (stream, "_0%04x", ch);
+ }
}
-void
+/* Print a name from the class data. If the index does not point to a
+ string, an error results. */
+
+static void
DEFUN(print_name, (stream, jcf, name_index),
FILE* stream AND JCF* jcf AND int name_index)
{
if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
- fprintf (stream, "<not a UTF8 constant>");
- else
+ {
+ fprintf (stream, "<not a UTF8 constant>");
+ found_error = 1;
+ }
+ else if (! flag_jni)
jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
JPOOL_UTF_LENGTH (jcf, name_index));
+ else
+ {
+ /* For JNI we must correctly quote each character. */
+ const unsigned char *str = JPOOL_UTF_DATA (jcf, name_index);
+ int length = JPOOL_UTF_LENGTH (jcf, name_index);
+ const unsigned char *limit = str + length;
+ while (str < limit)
+ {
+ int ch = UTF8_GET (str, limit);
+ if (ch < 0)
+ {
+ fprintf (stream, "\\<invalid>");
+ return;
+ }
+ jni_print_char (stream, ch);
+ }
+ }
}
/* Print base name of class. The base name is everything after the
{
int name_index = JPOOL_USHORT1 (jcf, index);
int len;
- unsigned char *s, *p, *limit;
+ const unsigned char *s, *p, *limit;
s = JPOOL_UTF_DATA (jcf, name_index);
len = JPOOL_UTF_LENGTH (jcf, name_index);
}
}
-/* Return 0 if NAME is equal to STR, nonzero otherwise. */
+/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
+ and 1 if STR is "greater" than NAME. */
static int
utf8_cmp (str, length, name)
- unsigned char *str;
+ const unsigned char *str;
int length;
- char *name;
+ const char *name;
{
- unsigned char *limit = str + length;
+ const unsigned char *limit = str + length;
int i;
for (i = 0; name[i]; ++i)
{
int ch = UTF8_GET (str, limit);
if (ch != name[i])
- return 1;
+ return ch - name[i];
}
- return str != limit;
+ return str == limit ? 0 : 1;
+}
+
+/* This is a sorted list of all C++ keywords. */
+
+static const char *cxx_keywords[] =
+{
+ "asm",
+ "auto",
+ "bool",
+ "const_cast",
+ "delete",
+ "dynamic_cast",
+ "enum",
+ "explicit",
+ "extern",
+ "friend",
+ "inline",
+ "mutable",
+ "namespace",
+ "overload",
+ "register",
+ "reinterpret_cast",
+ "signed",
+ "sizeof",
+ "static_cast",
+ "struct",
+ "template",
+ "typedef",
+ "typeid",
+ "typename",
+ "typenameopt",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "volatile",
+ "wchar_t"
+};
+
+
+/* If NAME is the name of a C++ keyword, then return an override name.
+ This is a name that can be used in place of the keyword.
+ Otherwise, return NULL. The return value is malloc()d. */
+
+static char *
+cxx_keyword_subst (str, length)
+ const unsigned char *str;
+ int length;
+{
+ int last = sizeof (cxx_keywords) / sizeof (const char *);
+ int first = 0;
+ int mid = (last + first) / 2;
+ int old = -1;
+
+ for (mid = (last + first) / 2;
+ mid != old;
+ old = mid, mid = (last + first) / 2)
+ {
+ int r = utf8_cmp (str, length, cxx_keywords[mid]);
+
+ if (r == 0)
+ {
+ char *str = xmalloc (9 + strlen (cxx_keywords[mid]));
+ strcpy (str, "__dummy_");
+ strcat (str, cxx_keywords[mid]);
+ return str;
+ }
+ else if (r < 0)
+ last = mid;
+ else
+ first = mid;
+ }
+ return NULL;
}
-/* Generate an access control keyword based on FLAGS. Returns 0 if
- FLAGS matches the saved access information, nonzero otherwise. */
+/* Generate an access control keyword based on FLAGS. */
static void
generate_access (stream, flags)
/* See if NAME is already the name of a method. */
static int
name_is_method_p (name, length)
- unsigned char *name;
+ const unsigned char *name;
int length;
{
struct method_name *p;
return 0;
}
+/* If there is already a method named NAME, whose signature is not
+ SIGNATURE, then return true. Otherwise return false. */
+static int
+overloaded_jni_method_exists_p (name, length, signature, sig_length)
+ const unsigned char *name;
+ int length;
+ const char *signature;
+ int sig_length;
+{
+ struct method_name *p;
+
+ for (p = method_name_list; p != NULL; p = p->next)
+ {
+ if (p->length == length
+ && ! memcmp (p->name, name, length)
+ && (p->sig_length != sig_length
+ || memcmp (p->signature, signature, sig_length)))
+ return 1;
+ }
+ return 0;
+}
+
+/* Get name of a field. This handles renamings due to C++ clash. */
+static char *
+get_field_name (jcf, name_index, flags)
+ JCF *jcf;
+ int name_index;
+ JCF_u2 flags;
+{
+ unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
+ int length = JPOOL_UTF_LENGTH (jcf, name_index);
+ char *override;
+
+ if (name_is_method_p (name, length))
+ {
+ /* This field name matches a method. So override the name with
+ a dummy name. This is yucky, but it isn't clear what else to
+ do. FIXME: if the field is static, then we'll be in real
+ trouble. */
+ if ((flags & ACC_STATIC))
+ {
+ fprintf (stderr, "static field has same name as method\n");
+ found_error = 1;
+ return NULL;
+ }
+
+ override = xmalloc (length + 3);
+ memcpy (override, name, length);
+ strcpy (override + length, "__");
+ }
+ else
+ override = cxx_keyword_subst (name, length);
+
+ return override;
+}
+
+/* Print a field name. Convenience function for use with
+ get_field_name. */
+static void
+print_field_name (stream, jcf, name_index, flags)
+ FILE *stream;
+ JCF *jcf;
+ int name_index;
+ JCF_u2 flags;
+{
+ char *override = get_field_name (jcf, name_index, flags);
+
+ if (override)
+ {
+ fputs (override, stream);
+ free (override);
+ }
+ else
+ jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
+ JPOOL_UTF_LENGTH (jcf, name_index));
+}
+
static void
DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
FILE *stream AND JCF* jcf
{
char *override = NULL;
- if (flags & ACC_FINAL)
+ generate_access (stream, flags);
+ if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
+ {
+ fprintf (stream, "<not a UTF8 constant>");
+ found_error = 1;
+ return;
+ }
+
+ fputs (" ", out);
+ if ((flags & ACC_STATIC))
+ fputs ("static ", out);
+
+ if ((flags & ACC_FINAL))
{
if (current_field_value > 0)
{
char buffer[25];
+ int done = 1;
- generate_access (stream, flags);
switch (JPOOL_TAG (jcf, current_field_value))
{
case CONSTANT_Integer:
{
jint num;
int most_negative = 0;
- fputs (" static const jint ", out);
- print_name (out, jcf, name_index);
+ fputs ("const jint ", out);
+ print_field_name (out, jcf, name_index, 0);
fputs (" = ", out);
num = JPOOL_INT (jcf, current_field_value);
/* We single out the most negative number to print
specially. This avoids later warnings from g++. */
- if (num == 0x80000000)
+ if (num == (jint) 0x80000000)
{
most_negative = 1;
++num;
{
jlong num;
int most_negative = 0;
- fputs (" static const jlong ", out);
- print_name (out, jcf, name_index);
+ fputs ("const jlong ", out);
+ print_field_name (out, jcf, name_index, 0);
fputs (" = ", out);
num = JPOOL_LONG (jcf, current_field_value);
/* We single out the most negative number to print
specially.. This avoids later warnings from g++. */
- if (num == 0x8000000000000000LL)
+ if (num == (jlong) 0x8000000000000000LL)
{
most_negative = 1;
++num;
case CONSTANT_Float:
{
jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
- fputs (" static const jfloat ", out);
- print_name (out, jcf, name_index);
+ fputs ("const jfloat ", out);
+ print_field_name (out, jcf, name_index, 0);
if (! java_float_finite (fnum))
fputs (";\n", out);
else
case CONSTANT_Double:
{
jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
- fputs (" static const jdouble ", out);
- print_name (out, jcf, name_index);
+ fputs ("const jdouble ", out);
+ print_field_name (out, jcf, name_index, 0);
if (! java_double_finite (dnum))
fputs (";\n", out);
else
}
break;
default:
- fprintf(out, " <<inappropriate constant type>>\n");
- }
-
- return;
- }
- }
-
- generate_access (stream, flags);
- fputs (" ", out);
- if ((flags & ACC_STATIC))
- fputs ("static ", out);
-
- if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
- {
- fprintf (stream, "<not a UTF8 constant>");
- found_error = 1;
- }
- else
- {
- unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
- int length = JPOOL_UTF_LENGTH (jcf, name_index);
-
- if (name_is_method_p (name, length))
- {
- /* This field name matches a method. So override the name
- with a dummy name. This is yucky, but it isn't clear
- what else to do. FIXME: if the field is static, then
- we'll be in real trouble. */
- if ((flags & ACC_STATIC))
- {
- fprintf (stderr, "static field has same name as method\n");
- found_error = 1;
+ /* We can't print this as a constant, but we can still
+ print something sensible. */
+ done = 0;
+ break;
}
- override = (char *) malloc (length + 3);
- memcpy (override, name, length);
- strcpy (override + length, "__");
+ if (done)
+ return;
}
}
- print_c_decl (out, jcf, name_index, sig_index, flags, 0, override);
+ override = get_field_name (jcf, name_index, flags);
+ print_c_decl (out, jcf, name_index, sig_index, 0, override, flags);
fputs (";\n", out);
if (override)
free (override);
}
+
static void
DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
FILE *stream AND JCF* jcf
AND int name_index AND int sig_index AND JCF_u2 flags)
{
- unsigned char *str;
+ const unsigned char *str;
int length, is_init = 0;
- const char *override = NULL;
+ char *override = NULL;
method_declared = 0;
method_access = flags;
- if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
+ if (stream && JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
fprintf (stream, "<not a UTF8 constant>");
str = JPOOL_UTF_DATA (jcf, name_index);
length = JPOOL_UTF_LENGTH (jcf, name_index);
else
return;
}
- else
+
+ /* During the first method pass, build a list of method names. This will
+ be used to determine if field names conflict with method names. */
+ if (! stream)
{
struct method_name *nn;
- nn = (struct method_name *) malloc (sizeof (struct method_name));
- nn->name = (char *) malloc (length);
+ nn = (struct method_name *) xmalloc (sizeof (struct method_name));
+ nn->name = (char *) xmalloc (length);
memcpy (nn->name, str, length);
nn->length = length;
nn->next = method_name_list;
+ nn->sig_length = JPOOL_UTF_LENGTH (jcf, sig_index);
+ nn->signature = (char *) xmalloc (nn->sig_length);
+ memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index),
+ nn->sig_length);
method_name_list = nn;
+
+ /* The rest of this function doesn't matter. */
+ return;
}
- /* We can't generate a method whose name is a C++ reserved word.
- For now the only problem has been `delete'; add more here as
- required. We can't just ignore the function, because that will
- cause incorrect code to be generated if the function is virtual
- (not only for calls to this function for for other functions
- after it in the vtbl). So we give it a dummy name instead. */
- if (! utf8_cmp (str, length, "delete"))
+ /* We don't worry about overrides in JNI mode. */
+ if (! flag_jni)
{
- /* If the method is static or final, we can safely skip it. If
- we don't skip it then we'll have problems since the mangling
- will be wrong. FIXME. */
- if (METHOD_IS_FINAL (jcf->access_flags, flags)
- || (flags & ACC_STATIC))
- return;
- override = "__dummy_delete";
+ /* We can't generate a method whose name is a C++ reserved word.
+ We can't just ignore the function, because that will cause
+ incorrect code to be generated if the function is virtual
+ (not only for calls to this function for for other functions
+ after it in the vtbl). So we give it a dummy name instead. */
+ override = cxx_keyword_subst (str, length);
+ if (override)
+ {
+ /* If the method is static or final, we can safely skip it.
+ If we don't skip it then we'll have problems since the
+ mangling will be wrong. FIXME. */
+ if (METHOD_IS_FINAL (jcf->access_flags, flags)
+ || (flags & ACC_STATIC))
+ {
+ free (override);
+ return;
+ }
+ }
}
- method_printed = 1;
- generate_access (stream, flags);
-
- fputs (" ", out);
- if ((flags & ACC_STATIC))
- fputs ("static ", out);
- else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
+ if (! stubs && ! flag_jni)
{
- /* Don't print `virtual' if we have a constructor. */
- if (! is_init)
- fputs ("virtual ", out);
+ method_printed = 1;
+
+ generate_access (stream, flags);
+
+ fputs (" ", out);
+ if ((flags & ACC_STATIC))
+ fputs ("static ", out);
+ else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
+ {
+ /* Don't print `virtual' if we have a constructor. */
+ if (! is_init)
+ fputs ("virtual ", out);
+ }
+ print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
+
+ if ((flags & ACC_ABSTRACT))
+ fputs (" = 0", out);
+ else
+ method_declared = 1;
}
- print_c_decl (out, jcf, name_index, sig_index, flags, is_init, override);
-
- if ((flags & ACC_ABSTRACT))
- fputs (" = 0", out);
else
- method_declared = 1;
+ {
+ if (METHOD_IS_NATIVE (flags))
+ {
+ method_printed = 1;
+ print_stub_or_jni (out, jcf, name_index, sig_index,
+ is_init, override, flags);
+ }
+ }
+
+ if (override)
+ free (override);
}
/* Try to decompile a method body. Right now we just try to handle a
JCF *jcf;
int code_len;
{
- unsigned char *codes = jcf->read_ptr;
+ const unsigned char *codes = jcf->read_ptr;
int index;
uint16 name_and_type, name;
name_and_type = JPOOL_USHORT2 (jcf, index);
/* FIXME: ensure that tag is CONSTANT_NameAndType. */
name = JPOOL_USHORT1 (jcf, name_and_type);
- print_name (out, jcf, name);
+ /* FIXME: flags. */
+ print_field_name (out, jcf, name, 0);
fputs ("; }", out);
decompiled = 1;
}
/* Print one piece of a signature. Returns pointer to next parseable
character on success, NULL on error. */
-static unsigned char *
+static const unsigned char *
decode_signature_piece (stream, signature, limit, need_space)
FILE *stream;
- unsigned char *signature, *limit;
+ const unsigned char *signature, *limit;
int *need_space;
{
const char *ctype;
+ int array_depth = 0;
switch (signature[0])
{
case '[':
+ /* More spaghetti. */
+
+ array_loop:
for (signature++; (signature < limit
&& *signature >= '0'
&& *signature <= '9'); signature++)
;
switch (*signature)
{
- case 'B': ctype = "jbyteArray"; goto printit;
- case 'C': ctype = "jcharArray"; goto printit;
- case 'D': ctype = "jdoubleArray"; goto printit;
- case 'F': ctype = "jfloatArray"; goto printit;
- case 'I': ctype = "jintArray"; goto printit;
- case 'S': ctype = "jshortArray"; goto printit;
- case 'J': ctype = "jlongArray"; goto printit;
- case 'Z': ctype = "jbooleanArray"; goto printit;
- case '[': ctype = "jobjectArray"; goto printit;
+ case 'B':
+ ctype = "jbyteArray";
+ break;
+ case 'C':
+ ctype = "jcharArray";
+ break;
+ case 'D':
+ ctype = "jdoubleArray";
+ break;
+ case 'F':
+ ctype = "jfloatArray";
+ break;
+ case 'I':
+ ctype = "jintArray";
+ break;
+ case 'S':
+ ctype = "jshortArray";
+ break;
+ case 'J':
+ ctype = "jlongArray";
+ break;
+ case 'Z':
+ ctype = "jbooleanArray";
+ break;
+ case '[':
+ /* We have a nested array. */
+ ++array_depth;
+ if (! flag_jni)
+ fputs ("JArray<", stream);
+ goto array_loop;
+
case 'L':
- /* We have to generate a reference to JArray here,
- so that our output matches what the compiler
- does. */
+ /* We have to generate a reference to JArray here, so that
+ our output matches what the compiler does. */
++signature;
- fputs ("JArray<", stream);
+ /* Space between `<' and `:' to avoid C++ digraphs. */
+ if (! flag_jni)
+ fputs ("JArray< ::", stream);
while (signature < limit && *signature != ';')
{
int ch = UTF8_GET (signature, limit);
- if (ch == '/')
- fputs ("::", stream);
- else
- jcf_print_char (stream, ch);
+ if (! flag_jni)
+ {
+ if (ch == '/')
+ fputs ("::", stream);
+ else
+ jcf_print_char (stream, ch);
+ }
}
- fputs (" *> *", stream);
+ if (! flag_jni)
+ fputs (" *> *", stream);
*need_space = 0;
- ++signature;
+ ctype = NULL;
break;
default:
/* Unparseable signature. */
return NULL;
}
+
+ /* If the previous iterations left us with something to print,
+ print it. For JNI, we always print `jobjectArray' in the
+ nested cases. */
+ if (flag_jni && ctype == NULL)
+ {
+ ctype = "jobjectArray";
+ *need_space = 1;
+ }
+ /* The `printit' case will advance SIGNATURE for us. If we
+ don't go there, we must advance past the `;' ourselves. */
+ if (ctype != NULL)
+ goto printit;
+ ++signature;
break;
case '(':
case 'Z': ctype = "jboolean"; goto printit;
case 'V': ctype = "void"; goto printit;
case 'L':
+ if (flag_jni)
+ {
+ /* We know about certain types and special-case their
+ names.
+ FIXME: something like java.lang.Exception should be
+ printed as `jthrowable', because it is a subclass. This
+ means that gcjh must read the entire hierarchy and
+ comprehend it. */
+ if (! strncmp (signature, "Ljava/lang/String;",
+ sizeof ("Ljava/lang/String;") -1))
+ ctype = "jstring";
+ else if (! strncmp (signature, "Ljava/lang/Class;",
+ sizeof ("Ljava/lang/Class;") - 1))
+ ctype = "jclass";
+ else if (! strncmp (signature, "Ljava/lang/Throwable;",
+ sizeof ("Ljava/lang/Throwable;") - 1))
+ ctype = "jthrowable";
+ else if (! strncmp (signature, "Ljava/lang/ref/WeakReference;",
+ sizeof ("Ljava/lang/ref/WeakReference;") - 1))
+ ctype = "jweak";
+ else
+ ctype = "jobject";
+
+ while (*signature && *signature != ';')
+ ++signature;
+
+ goto printit;
+ }
+ /* Print a leading "::" so we look in the right namespace. */
+ fputs ("::", stream);
++signature;
while (*signature && *signature != ';')
{
int ch = UTF8_GET (signature, limit);
- /* `$' is the separator for an inner class. */
- if (ch == '/' || ch == '$')
+ if (ch == '/')
fputs ("::", stream);
else
jcf_print_char (stream, ch);
break;
default:
*need_space = 1;
- jcf_print_char (stream, *signature++);
+ jni_print_char (stream, *signature++);
break;
printit:
signature++;
break;
}
+ if (! flag_jni)
+ {
+ while (array_depth-- > 0)
+ fputs ("> *", stream);
+ }
+
return signature;
}
static void
-DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init,
- name_override),
+DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
+ name_override, flags),
FILE* stream AND JCF* jcf
- AND int name_index AND int signature_index AND JCF_u2 flags
- AND int is_init AND const char *name_override)
+ AND int name_index AND int signature_index
+ AND int is_init AND const char *name_override AND int flags)
{
if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
{
else
{
int length = JPOOL_UTF_LENGTH (jcf, signature_index);
- unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
- register unsigned char *str = str0;
- unsigned char *limit = str + length;
+ const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
+ register const unsigned char *str = str0;
+ const unsigned char *limit = str + length;
int need_space = 0;
int is_method = str[0] == '(';
- unsigned char *next;
+ const unsigned char *next;
/* If printing a method, skip to the return signature and print
that first. However, there is no return value if this is a
/* Now print the name of the thing. */
if (need_space)
fputs (" ", stream);
- if (name_override)
- fputs (name_override, stream);
- else if (name_index)
- {
- /* Declare constructors specially. */
- if (is_init)
- print_base_classname (stream, jcf, jcf->this_class);
- else
- print_name (stream, jcf, name_index);
- }
+ print_full_cxx_name (stream, jcf, name_index,
+ signature_index, is_init, name_override,
+ flags);
+ }
+}
- if (is_method)
+/* Print the unqualified method name followed by the signature. */
+static void
+DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index,
+ is_init, name_override, flags),
+ FILE* stream AND JCF* jcf
+ AND int name_index AND int signature_index AND int is_init
+ AND const char *name_override AND int flags)
+{
+ int length = JPOOL_UTF_LENGTH (jcf, signature_index);
+ const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
+ register const unsigned char *str = str0;
+ const unsigned char *limit = str + length;
+ int need_space = 0;
+ int is_method = str[0] == '(';
+ const unsigned char *next;
+
+ if (name_override)
+ fputs (name_override, stream);
+ else if (name_index)
+ {
+ /* Declare constructors specially. */
+ if (is_init)
+ print_base_classname (stream, jcf, jcf->this_class);
+ else
+ print_name (stream, jcf, name_index);
+ }
+
+ if (flag_jni)
+ {
+ unsigned char *signature = JPOOL_UTF_DATA (jcf, signature_index);
+ int sig_len = JPOOL_UTF_LENGTH (jcf, signature_index);
+ if (overloaded_jni_method_exists_p (JPOOL_UTF_DATA (jcf, name_index),
+ JPOOL_UTF_LENGTH (jcf, name_index),
+ signature, sig_len))
{
- /* Have a method or a constructor. Print signature pieces
- until done. */
- fputs (" (", stream);
- str = str0 + 1;
- while (str < limit && *str != ')')
+ /* If this method is overloaded by another native method,
+ then include the argument information in the mangled
+ name. */
+ unsigned char *limit = signature + sig_len;
+ fputs ("__", stream);
+ while (signature < limit)
{
- next = decode_signature_piece (stream, str, limit, &need_space);
- if (! next)
+ int ch = UTF8_GET (signature, limit);
+ jni_print_char (stream, ch);
+ if (ch == ')')
{
- fprintf (stderr, "unparseable signature: `%s'\n", str0);
- found_error = 1;
- return;
+ /* Done. */
+ break;
}
+ }
+ }
+ }
+
+ if (is_method)
+ {
+ /* Have a method or a constructor. Print signature pieces
+ until done. */
+ fputs (" (", stream);
+
+ str = str0 + 1;
- if (next < limit && *next != ')')
- fputs (", ", stream);
- str = next;
+ /* In JNI mode, add extra arguments. */
+ if (flag_jni)
+ {
+ /* FIXME: it would be nice to know if we are printing a decl
+ or a definition, and only print `env' for the latter. */
+ fputs ("JNIEnv *env", stream);
+
+ fputs ((flags & ACC_STATIC) ? ", jclass" : ", jobject", stream);
+
+ if (*str != ')')
+ fputs (", ", stream);
+ }
+
+ while (str < limit && *str != ')')
+ {
+ next = decode_signature_piece (stream, str, limit, &need_space);
+ if (! next)
+ {
+ fprintf (stderr, "unparseable signature: `%s'\n", str0);
+ found_error = 1;
+ return;
}
+
+ if (next < limit && *next != ')')
+ fputs (", ", stream);
+ str = next;
+ }
+
+ fputs (")", stream);
+ }
+}
+
+/* This is a helper for print_stub_or_jni. */
+static void
+DEFUN (print_name_for_stub_or_jni, (stream, jcf, name_index, signature_index,
+ is_init, name_override, flags),
+ FILE *stream AND JCF *jcf
+ AND int name_index AND int signature_index
+ AND int is_init AND const char *name_override AND int flags)
+{
+ const char *const prefix = flag_jni ? "Java_" : "";
+ print_cxx_classname (stream, prefix, jcf, jcf->this_class);
+ fputs (flag_jni ? "_" : "::", stream);
+ print_full_cxx_name (stream, jcf, name_index,
+ signature_index, is_init, name_override,
+ flags);
+}
+
+static void
+DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init,
+ name_override, flags),
+ FILE* stream AND JCF* jcf
+ AND int name_index AND int signature_index
+ AND int is_init AND const char *name_override AND int flags)
+{
+ if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
+ {
+ fprintf (stream, "<not a UTF8 constant>");
+ found_error = 1;
+ }
+ else
+ {
+ int length = JPOOL_UTF_LENGTH (jcf, signature_index);
+ const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
+ register const unsigned char *str = str0;
+ const unsigned char *limit = str + length;
+ int need_space = 0;
+ int is_method = str[0] == '(';
+ const unsigned char *next;
+
+ /* Don't print fields in the JNI case. */
+ if (! is_method && flag_jni)
+ return;
+
+ if (flag_jni && ! stubs)
+ fputs ("extern ", stream);
+
+ /* If printing a method, skip to the return signature and print
+ that first. However, there is no return value if this is a
+ constructor. */
+ if (is_method && ! is_init)
+ {
+ while (str < limit)
+ {
+ int ch = *str++;
+ if (ch == ')')
+ break;
+ }
+ }
+
+ /* If printing a field or an ordinary method, then print the
+ "return value" now. Note that a constructor can't be native,
+ so we don't bother checking this in the JNI case. */
+ if (! is_method || ! is_init)
+ {
+ next = decode_signature_piece (stream, str, limit, &need_space);
+ if (! next)
+ {
+ fprintf (stderr, "unparseable signature: `%s'\n", str0);
+ found_error = 1;
+ return;
+ }
+ }
+
+ /* When printing a JNI header we need to respect the space. In
+ other cases we're just going to insert a newline anyway. */
+ fputs (need_space && ! stubs ? " " : "\n", stream);
+
+ /* Now print the name of the thing. */
+ print_name_for_stub_or_jni (stream, jcf, name_index,
+ signature_index, is_init, name_override,
+ flags);
- fputs (")", stream);
+ /* Print the body. */
+ if (stubs)
+ {
+ if (flag_jni)
+ fputs ("\n{\n (*env)->FatalError (\"", stream);
+ else
+ fputs ("\n{\n JvFail (\"", stream);
+ print_name_for_stub_or_jni (stream, jcf, name_index,
+ signature_index, is_init,
+ name_override,
+ flags);
+ fputs (" not implemented\");\n}\n\n", stream);
}
}
}
-void
+static void
DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
FILE *stream AND JCF *jcf AND const char *prefix AND int index)
{
static int
print_cxx_classname (stream, prefix, jcf, index)
FILE *stream;
- char *prefix;
+ const char *prefix;
JCF *jcf;
int index;
{
int name_index = JPOOL_USHORT1 (jcf, index);
int len, c;
- unsigned char *s, *p, *limit;
+ const unsigned char *s, *p, *limit;
s = JPOOL_UTF_DATA (jcf, name_index);
len = JPOOL_UTF_LENGTH (jcf, name_index);
return 0;
fputs (prefix, stream);
+
+ /* Print a leading "::" so we look in the right namespace. */
+ if (! flag_jni && ! stubs)
+ fputs ("::", stream);
+
while (s < limit)
{
c = UTF8_GET (s, limit);
if (c == '/')
- fputs ("::", stream);
+ fputs (flag_jni ? "_" : "::", stream);
else
- jcf_print_char (stream, c);
+ jni_print_char (stream, c);
}
return 1;
/* Return name of superclass. If LEN is not NULL, fill it with length
of name. */
-static unsigned char *
+static const unsigned char *
super_class_name (derived_jcf, len)
JCF *derived_jcf;
int *len;
{
int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
- unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index);
+ const unsigned char *supername =
+ JPOOL_UTF_DATA (derived_jcf, supername_index);
if (len)
*len = supername_length;
static void
print_include (out, utf8, len)
FILE *out;
- unsigned char *utf8;
+ const unsigned char *utf8;
int len;
{
struct include *incl;
for (incl = all_includes; incl; incl = incl->next)
{
- if (! strncmp (incl->name, utf8, len))
+ /* We check the length because we might have a proper prefix. */
+ if (len == (int) strlen (incl->name)
+ && ! strncmp (incl->name, utf8, len))
return;
}
- incl = (struct include *) malloc (sizeof (struct include));
- incl->name = malloc (len + 1);
+ incl = (struct include *) xmalloc (sizeof (struct include));
+ incl->name = xmalloc (len + 1);
strncpy (incl->name, utf8, len);
incl->name[len] = '\0';
incl->next = all_includes;
all_includes = incl;
fputs ("#include <", out);
- jcf_print_utf8 (out, utf8, len);
+ jcf_print_utf8_replace (out, utf8, len,
+ '/',
+ flag_jni ? '_' : '/');
fputs (".h>\n", out);
}
struct namelet *next;
};
+static void add_namelet PARAMS ((const unsigned char *,
+ const unsigned char *, struct namelet *));
+static void print_namelet PARAMS ((FILE *, struct namelet *, int));
+
/* The special root namelet. */
static struct namelet root =
{
recursively. */
static void
add_namelet (name, name_limit, parent)
- unsigned char *name, *name_limit;
+ const unsigned char *name, *name_limit;
struct namelet *parent;
{
- unsigned char *p;
+ const unsigned char *p;
struct namelet *n = NULL, *np;
/* We want to skip the standard namespaces that we assume the
#define JAVALANG "java/lang/"
#define JAVAIO "java/io/"
#define JAVAUTIL "java/util/"
- if ((name_limit - name >= sizeof (JAVALANG) - 1
+ if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
&& ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
- || (name_limit - name >= sizeof (JAVAUTIL) - 1
+ || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
&& ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
- || (name_limit - name >= sizeof (JAVAIO) - 1
+ || (name_limit - name >= (int) sizeof (JAVAIO) - 1
&& ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
return;
}
/* Search for this name beneath the PARENT node. */
for (np = parent->subnamelets; np != NULL; np = np->next)
{
- if (! strncmp (name, np->name, p - name))
+ /* We check the length because we might have a proper prefix. */
+ if ((int) strlen (np->name) == p - name &&
+ ! strncmp (name, np->name, p - name))
{
n = np;
break;
if (n == NULL)
{
- n = (struct namelet *) malloc (sizeof (struct namelet));
- n->name = malloc (p - name + 1);
+ n = (struct namelet *) xmalloc (sizeof (struct namelet));
+ n->name = xmalloc (p - name + 1);
strncpy (n->name, name, p - name);
n->name[p - name] = '\0';
n->is_class = (p == name_limit || *p == '$');
{
for (i = 0; i < depth; ++i)
fputc (' ', out);
- fputs ("};\n", out);
+ fputs ("}\n", out);
+ /* Only print a `;' when printing a class. C++ is evil. */
+ if (name->is_class)
+ fputs (";", out);
}
free (name->name);
JCF *jcf;
JCF_u2 signature;
{
- unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
+ const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
int len = JPOOL_UTF_LENGTH (jcf, signature);
int i;
/* Name of class we are processing. */
int name_index = JPOOL_USHORT1 (jcf, jcf->this_class);
int tlen = JPOOL_UTF_LENGTH (jcf, name_index);
- char *tname = JPOOL_UTF_DATA (jcf, name_index);
+ const char *tname = JPOOL_UTF_DATA (jcf, name_index);
for (i = 0; i < len; ++i)
{
/* If we see an array, then we include the array header. */
if (s[i] == '[')
{
- print_include (out, "java-array", -1);
+ print_include (out, "gcj/array", -1);
continue;
}
that should be declared. */
int name_index = JPOOL_USHORT1 (jcf, self);
int len;
- unsigned char *s;
+ const unsigned char *s;
s = JPOOL_UTF_DATA (jcf, name_index);
len = JPOOL_UTF_LENGTH (jcf, name_index);
int code, i;
uint32 field_start, method_end, method_start;
- current_jcf = main_jcf = jcf;
+ current_jcf = jcf;
last_access = -1;
jcf_parse_class (jcf);
if (written_class_count++ == 0 && out)
- fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
- out);
+ {
+ const char *cstart, *cstart2, *mode, *cend, *what, *jflag;
+ if (flag_jni)
+ {
+ cstart = "/*";
+ cstart2 = " ";
+ cend = " */";
+ mode = "";
+ what = "JNI";
+ jflag = " -jni";
+ }
+ else
+ {
+ cstart = "//";
+ cstart2 = "//";
+ cend = "";
+ mode = " -*- c++ -*-";
+ what = "CNI";
+ jflag = "";
+ }
+
+ if (! stubs)
+ fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
+ cstart, mode, cend);
+ else
+ {
+ fprintf (out, "%s This file was created by `gcjh -stubs%s'.%s\n\
+%s\n\
+%s This file is intended to give you a head start on implementing native\n\
+%s methods using %s.\n\
+%s Be aware: running `gcjh -stubs %s' once more for this class may\n\
+%s overwrite any edits you have made to this file.%s\n\n",
+ cstart, jflag, mode,
+ cstart2,
+ cstart2,
+ cstart2,
+ what,
+ cstart2,
+ jflag,
+ cstart2,
+ cend);
+ }
+ }
if (out)
{
- print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
- fprintf (out, "__\n");
+ if (! stubs)
+ {
+ print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
+ fprintf (out, "__\n");
- print_mangled_classname (out, jcf, "#define __", jcf->this_class);
- fprintf (out, "__\n\n");
+ print_mangled_classname (out, jcf, "#define __", jcf->this_class);
+ fprintf (out, "__\n\n");
- /* We do this to ensure that inline methods won't be `outlined'
- by g++. This works as long as method and fields are not
- added by the user. */
- fprintf (out, "#pragma interface\n");
- }
+ if (flag_jni)
+ {
+ fprintf (out, "#include <jni.h>\n\n");
+ fprintf (out, "#ifdef __cplusplus\n");
+ fprintf (out, "extern \"C\"\n");
+ fprintf (out, "{\n");
+ fprintf (out, "#endif\n");
+ }
+ else
+ {
+ /* We do this to ensure that inline methods won't be
+ `outlined' by g++. This works as long as method and
+ fields are not added by the user. */
+ fprintf (out, "#pragma interface\n");
- if (jcf->super_class && out)
- {
- int super_length;
- unsigned char *supername = super_class_name (jcf, &super_length);
+ if (jcf->super_class)
+ {
+ int super_length;
+ const unsigned char *supername =
+ super_class_name (jcf, &super_length);
- fputs ("\n", out);
- print_include (out, supername, super_length);
+ fputs ("\n", out);
+ print_include (out, supername, super_length);
+ }
+ }
+ }
+ else
+ {
+ /* Strip off the ".class" portion of the name when printing
+ the include file name. */
+ int len = strlen (jcf->classname);
+ if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
+ len -= 6;
+ print_include (out, jcf->classname, len);
+ print_include (out, "gcj/cni", -1);
+ }
}
/* We want to parse the methods first. But we need to find where
jcf_parse_methods (jcf);
if (out)
+ fputs ("\n", out);
+
+ if (out && ! flag_jni)
{
- fputs ("\n", out);
- print_class_decls (out, jcf, jcf->this_class);
+ if (! stubs)
+ print_class_decls (out, jcf, jcf->this_class);
for (i = 0; i < prepend_count; ++i)
fprintf (out, "%s\n", prepend_specs[i]);
if (prepend_count > 0)
fputc ('\n', out);
- }
- if (out && ! print_cxx_classname (out, "class ", jcf, jcf->this_class))
- {
- fprintf (stderr, "class is of array type\n");
- found_error = 1;
- return;
- }
- if (out && jcf->super_class)
- {
- if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class))
+ if (! stubs)
{
- fprintf (stderr, "base class is of array type\n");
- found_error = 1;
- return;
+ if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
+ {
+ fprintf (stderr, "class is of array type\n");
+ found_error = 1;
+ return;
+ }
+ if (jcf->super_class)
+ {
+ if (! print_cxx_classname (out, " : public ",
+ jcf, jcf->super_class))
+ {
+ fprintf (stderr, "base class is of array type\n");
+ found_error = 1;
+ return;
+ }
+ }
+
+ fputs ("\n{\n", out);
}
}
- if (out)
- fputs ("\n{\n", out);
/* Now go back for second pass over methods and fields. */
JCF_SEEK (jcf, method_start);
jcf_parse_final_attributes (jcf);
- if (out)
+ if (out && ! stubs)
{
- /* Generate friend decl if we still must. */
- for (i = 0; i < friend_count; ++i)
- fprintf (out, " friend %s\n", friend_specs[i]);
-
- /* Generate extra declarations. */
- if (add_count > 0)
- fputc ('\n', out);
- for (i = 0; i < add_count; ++i)
- fprintf (out, " %s\n", add_specs[i]);
-
- fputs ("};\n", out);
-
- if (append_count > 0)
- fputc ('\n', out);
- for (i = 0; i < append_count; ++i)
- fprintf (out, "%s\n", append_specs[i]);
+ if (flag_jni)
+ {
+ fprintf (out, "\n#ifdef __cplusplus\n");
+ fprintf (out, "}\n");
+ fprintf (out, "#endif\n");
+ }
+ else
+ {
+ /* Generate friend decl if we still must. */
+ for (i = 0; i < friend_count; ++i)
+ fprintf (out, " friend %s\n", friend_specs[i]);
+
+ /* Generate extra declarations. */
+ if (add_count > 0)
+ fputc ('\n', out);
+ for (i = 0; i < add_count; ++i)
+ fprintf (out, " %s\n", add_specs[i]);
+
+ if (! stubs)
+ fputs ("};\n", out);
+
+ if (append_count > 0)
+ fputc ('\n', out);
+ for (i = 0; i < append_count; ++i)
+ fprintf (out, "%s\n", append_specs[i]);
+ }
- print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class);
+ print_mangled_classname (out, jcf,
+ "\n#endif /* __", jcf->this_class);
fprintf (out, "__ */\n");
}
}
+\f
+
+/* This is used to mark options with no short value. */
+#define LONG_OPT(Num) ((Num) + 128)
+
+#define OPT_classpath LONG_OPT (0)
+#define OPT_CLASSPATH LONG_OPT (1)
+#define OPT_HELP LONG_OPT (2)
+#define OPT_TEMP LONG_OPT (3)
+#define OPT_VERSION LONG_OPT (4)
+#define OPT_PREPEND LONG_OPT (5)
+#define OPT_FRIEND LONG_OPT (6)
+#define OPT_ADD LONG_OPT (7)
+#define OPT_APPEND LONG_OPT (8)
+#define OPT_M LONG_OPT (9)
+#define OPT_MM LONG_OPT (10)
+#define OPT_MG LONG_OPT (11)
+#define OPT_MD LONG_OPT (12)
+#define OPT_MMD LONG_OPT (13)
+
+static struct option options[] =
+{
+ { "classpath", required_argument, NULL, OPT_classpath },
+ { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
+ { "help", no_argument, NULL, OPT_HELP },
+ { "stubs", no_argument, &stubs, 1 },
+ { "td", required_argument, NULL, OPT_TEMP },
+ { "verbose", no_argument, NULL, 'v' },
+ { "version", no_argument, NULL, OPT_VERSION },
+ { "prepend", required_argument, NULL, OPT_PREPEND },
+ { "friend", required_argument, NULL, OPT_FRIEND },
+ { "add", required_argument, NULL, OPT_ADD },
+ { "append", required_argument, NULL, OPT_APPEND },
+ { "M", no_argument, NULL, OPT_M },
+ { "MM", no_argument, NULL, OPT_MM },
+ { "MG", no_argument, NULL, OPT_MG },
+ { "MD", no_argument, NULL, OPT_MD },
+ { "MMD", no_argument, NULL, OPT_MMD },
+ { "jni", no_argument, &flag_jni, 1 },
+ { NULL, no_argument, NULL, 0 }
+};
+
static void
usage ()
{
- fprintf (stderr, "gcjh: no classes specified\n");
+ fprintf (stderr, "Try `gcjh --help' for more information.\n");
exit (1);
}
{
printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
printf ("Generate C++ header files from .class files\n\n");
+ printf (" -stubs Generate an implementation stub file\n");
+ printf (" -jni Generate a JNI header or stub\n");
+ printf ("\n");
+ printf (" -add TEXT Insert TEXT into class body\n");
+ printf (" -append TEXT Insert TEXT after class declaration\n");
+ printf (" -friend TEXT Insert TEXT as `friend' declaration\n");
+ printf (" -prepend TEXT Insert TEXT before start of class\n");
+ printf ("\n");
printf (" --classpath PATH Set path to find .class files\n");
printf (" --CLASSPATH PATH Set path to find .class files\n");
printf (" -IDIR Append directory to class path\n");
printf (" -d DIRECTORY Set output directory name\n");
- printf (" --help Print this help, then exit\n");
printf (" -o FILE Set output file name\n");
printf (" -td DIRECTORY Set temporary directory name\n");
- printf (" -v, --verbose Print extra information while running\n");
+ printf ("\n");
+ printf (" --help Print this help, then exit\n");
printf (" --version Print version number, then exit\n");
- /* FIXME: print bug-report information. */
+ printf (" -v, --verbose Print extra information while running\n");
+ printf ("\n");
+ printf (" -M Print all dependencies to stdout;\n");
+ printf (" suppress ordinary output\n");
+ printf (" -MM Print non-system dependencies to stdout;\n");
+ printf (" suppress ordinary output\n");
+ printf (" -MD Print all dependencies to stdout\n");
+ printf (" -MMD Print non-system dependencies to stdout\n");
+ /* We omit -MG until it is implemented. */
+ printf ("\n");
+ printf ("For bug reporting instructions, please see:\n");
+ printf ("%s.\n", GCCBUGURL);
exit (0);
}
static void
-java_no_argument (opt)
- char *opt;
-{
- fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
- exit (1);
-}
-
-static void
version ()
{
- /* FIXME: use version.c? */
- printf ("gcjh (GNU gcc) 0.0\n\n");
- printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n");
+ printf ("gcjh (%s)\n\n", version_string);
+ printf ("Copyright (C) 1998, 1999 Free Software Foundation, Inc.\n");
printf ("This is free software; see the source for copying conditions. There is NO\n");
printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
exit (0);
int argi;
char *output_file = NULL;
int emit_dependencies = 0, suppress_output = 0;
+ int opt;
if (argc <= 1)
- usage ();
+ {
+ fprintf (stderr, "gcjh: no classes specified\n");
+ usage ();
+ }
jcf_path_init ();
- for (argi = 1; argi < argc; argi++)
+ /* We use getopt_long_only to allow single `-' long options. For
+ some of our options this is more natural. */
+ while ((opt = getopt_long_only (argc, argv, "I:d:o:v", options, NULL)) != -1)
{
- char *arg = argv[argi];
+ switch (opt)
+ {
+ case 0:
+ /* Already handled. */
+ break;
- if (arg[0] != '-' || ! strcmp (arg, "--"))
- break;
+ case 'o':
+ output_file = optarg;
+ break;
- /* Just let all arguments be given in either "-" or "--" form. */
- if (arg[1] == '-')
- ++arg;
+ case 'd':
+ output_directory = optarg;
+ break;
- if (strcmp (arg, "-o") == 0)
- {
- if (argi + 1 < argc)
- output_file = argv[++argi];
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-d") == 0)
- {
- if (argi + 1 < argc)
- output_directory = argv[++argi];
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-td") == 0)
- {
- if (argi + 1 < argc)
- temp_directory = argv[++argi];
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-prepend") == 0)
- {
- if (argi + 1 < argc)
- {
- if (prepend_count == 0)
- prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
- prepend_specs[prepend_count++] = argv[++argi];
- }
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-friend") == 0)
- {
- if (argi + 1 < argc)
- {
- if (friend_count == 0)
- friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
- friend_specs[friend_count++] = argv[++argi];
- }
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-add") == 0)
- {
- if (argi + 1 < argc)
- {
- if (add_count == 0)
- add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
- add_specs[add_count++] = argv[++argi];
- }
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-append") == 0)
- {
- if (argi + 1 < argc)
- {
- if (append_count == 0)
- append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
- append_specs[append_count++] = argv[++argi];
- }
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-classpath") == 0)
- {
- if (argi + 1 < argc)
- jcf_path_classpath_arg (argv[++argi]);
- else
- java_no_argument (argv[argi]);
- }
- else if (strcmp (arg, "-CLASSPATH") == 0)
- {
- if (argi + 1 < argc)
- jcf_path_CLASSPATH_arg (argv[++argi]);
- else
- java_no_argument (argv[argi]);
- }
- else if (strncmp (arg, "-I", 2) == 0)
- jcf_path_include_arg (arg + 2);
- else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
- verbose++;
- else if (strcmp (arg, "-stubs") == 0)
- stubs++;
- else if (strcmp (arg, "-help") == 0)
- help ();
- else if (strcmp (arg, "-version") == 0)
- version ();
- else if (strcmp (arg, "-M") == 0)
- {
+ case 'I':
+ jcf_path_include_arg (optarg);
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+
+ case OPT_classpath:
+ jcf_path_classpath_arg (optarg);
+ break;
+
+ case OPT_CLASSPATH:
+ jcf_path_CLASSPATH_arg (optarg);
+ break;
+
+ case OPT_HELP:
+ help ();
+ break;
+
+ case OPT_TEMP:
+ temp_directory = optarg;
+ break;
+
+ case OPT_VERSION:
+ version ();
+ break;
+
+ case OPT_PREPEND:
+ if (prepend_count == 0)
+ prepend_specs = (char**) ALLOC (argc * sizeof (char*));
+ prepend_specs[prepend_count++] = optarg;
+ break;
+
+ case OPT_FRIEND:
+ if (friend_count == 0)
+ friend_specs = (char**) ALLOC (argc * sizeof (char*));
+ friend_specs[friend_count++] = optarg;
+ break;
+
+ case OPT_ADD:
+ if (add_count == 0)
+ add_specs = (char**) ALLOC (argc * sizeof (char*));
+ add_specs[add_count++] = optarg;
+ break;
+
+ case OPT_APPEND:
+ if (append_count == 0)
+ append_specs = (char**) ALLOC (argc * sizeof (char*));
+ append_specs[append_count++] = optarg;
+ break;
+
+ case OPT_M:
emit_dependencies = 1;
suppress_output = 1;
jcf_dependency_init (1);
- }
- else if (strcmp (arg, "-MM") == 0)
- {
+ break;
+
+ case OPT_MM:
emit_dependencies = 1;
suppress_output = 1;
jcf_dependency_init (0);
- }
- else if (strcmp (arg, "-MG") == 0)
- {
- fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
+ break;
+
+ case OPT_MG:
+ fprintf (stderr, "gcjh: `-MG' option is unimplemented\n");
exit (1);
- }
- else if (strcmp (arg, "-MD") == 0)
- {
+
+ case OPT_MD:
emit_dependencies = 1;
jcf_dependency_init (1);
- }
- else if (strcmp (arg, "-MMD") == 0)
- {
+ break;
+
+ case OPT_MMD:
emit_dependencies = 1;
jcf_dependency_init (0);
- }
- else
- {
- fprintf (stderr, "%s: illegal argument\n", argv[argi]);
- exit (1);
+ break;
+
+ default:
+ usage ();
+ break;
}
}
- if (argi == argc)
- usage ();
+ if (optind == argc)
+ {
+ fprintf (stderr, "gcjh: no classes specified\n");
+ usage ();
+ }
jcf_path_seal ();
exit (1);
}
- for (; argi < argc; argi++)
+ for (argi = optind; argi < argc; argi++)
{
char *classname = argv[argi];
- char *classfile_name, *current_output_file;
+ char *current_output_file;
+ const char *classfile_name;
if (verbose)
fprintf (stderr, "Processing %s\n", classname);
{
int dir_len = strlen (output_directory);
int i, classname_length = strlen (classname);
- current_output_file = (char*) ALLOC (dir_len + classname_length + 4);
+ current_output_file = (char*) ALLOC (dir_len + classname_length + 5);
strcpy (current_output_file, output_directory);
if (dir_len > 0 && output_directory[dir_len-1] != '/')
current_output_file[dir_len++] = '/';
char ch = classname[i];
if (ch == '.')
ch = '/';
+ if (flag_jni && ch == '/')
+ ch = '_';
current_output_file[dir_len++] = ch;
}
if (emit_dependencies)
jcf_dependency_set_dep_file (current_output_file);
}
}
- strcpy (current_output_file + dir_len, ".h");
+ strcpy (current_output_file + dir_len,
+ stubs ? (flag_jni ? ".c" : ".cc") : ".h");
jcf_dependency_set_target (current_output_file);
if (! suppress_output)
{
return found_error;
}
-
-/* TODO:
-
- * Do whatever the javah -stubs flag does.
-
- * Emit "structure forward declarations" when needed.
-
- * Generate C headers, like javah
-
- */