Commit de380723 by Tom Tromey Committed by Tom Tromey

gjavah.c (options): Added `jni' entry.

	* gjavah.c (options): Added `jni' entry.
	(help): Document -jni.
	(flag_jni): New global.
	(process_file): Handle JNI output.  Don't print text from
	-prepend, -add, etc, when generating stubs.  Only remove `.class'
	suffix if it actually exists.
	(main): Create a `.c' file when run with `--jni --stubs'.  Create
	correct output file name with `--jni'.
	(print_include): Mangle header name differently in JNI case.
	(HANDLE_METHOD): In JNI mode, call print_method_info to generate
	method list.
	(print_method_info): Handle JNI case.  Put signature info into
	method name.  Handle case when STREAM is NULL.
	(print_name_for_stub_or_jni): New function.
	(print_stub_or_jni): Renamed from `print_stub'.  Handle JNI.
	(print_cxx_classname): Handle JNI.
	(print_full_cxx_name): Likewise.
	(decode_signature_piece): Likewise.
	(overloaded_jni_method_exists_p): New function.
	(struct method_name): Added `signature' and `sig_length' fields.
	(HANDLE_END_FIELD): Do nothing in JNI mode.

From-SVN: r31767
parent cf8e13bb
2000-02-02 Tom Tromey <tromey@cygnus.com> 2000-02-02 Tom Tromey <tromey@cygnus.com>
* gjavah.c (options): Added `jni' entry.
(help): Document -jni.
(flag_jni): New global.
(process_file): Handle JNI output. Don't print text from
-prepend, -add, etc, when generating stubs. Only remove `.class'
suffix if it actually exists.
(main): Create a `.c' file when run with `--jni --stubs'. Create
correct output file name with `--jni'.
(print_include): Mangle header name differently in JNI case.
(HANDLE_METHOD): In JNI mode, call print_method_info to generate
method list.
(print_method_info): Handle JNI case. Put signature info into
method name. Handle case when STREAM is NULL.
(print_name_for_stub_or_jni): New function.
(print_stub_or_jni): Renamed from `print_stub'. Handle JNI.
(print_cxx_classname): Handle JNI.
(print_full_cxx_name): Likewise.
(decode_signature_piece): Likewise.
(overloaded_jni_method_exists_p): New function.
(struct method_name): Added `signature' and `sig_length' fields.
(HANDLE_END_FIELD): Do nothing in JNI mode.
2000-02-02 Tom Tromey <tromey@cygnus.com>
* jv-scan.c: Include version.c, <getopt.h>. * jv-scan.c: Include version.c, <getopt.h>.
(LONG_OPT, OPT_HELP, OPT_VERSION): New macros. (LONG_OPT, OPT_HELP, OPT_VERSION): New macros.
(options): New array. (options): New array.
......
...@@ -45,6 +45,9 @@ FILE *out = NULL; ...@@ -45,6 +45,9 @@ FILE *out = NULL;
/* Nonzero on failure. */ /* Nonzero on failure. */
static int found_error = 0; 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. */ /* Directory to place resulting files in. Set by -d option. */
const char *output_directory = ""; const char *output_directory = "";
...@@ -105,6 +108,8 @@ struct method_name ...@@ -105,6 +108,8 @@ struct method_name
{ {
unsigned char *name; unsigned char *name;
int length; int length;
unsigned char *signature;
int sig_length;
struct method_name *next; struct method_name *next;
}; };
...@@ -115,9 +120,12 @@ static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2)); ...@@ -115,9 +120,12 @@ static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int)); static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int));
static int print_cxx_classname PARAMS ((FILE*, const char*, JCF*, 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_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *)); static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *,
static void print_stub PARAMS ((FILE*, JCF*, int, int, int, const char *)); int));
static void print_full_cxx_name PARAMS ((FILE*, JCF*, int, int, int, const char *)); 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 decompile_method PARAMS ((FILE*, JCF*, int));
static void add_class_decl PARAMS ((FILE*, JCF*, JCF_u2)); static void add_class_decl PARAMS ((FILE*, JCF*, JCF_u2));
...@@ -161,13 +169,13 @@ static int method_pass; ...@@ -161,13 +169,13 @@ static int method_pass;
#define HANDLE_END_FIELD() \ #define HANDLE_END_FIELD() \
if (field_pass) \ if (field_pass) \
{ \ { \
if (out && ! stubs) \ if (out && ! stubs && ! flag_jni) \
print_field_info (out, jcf, current_field_name, \ print_field_info (out, jcf, current_field_name, \
current_field_signature, \ current_field_signature, \
current_field_flags); \ current_field_flags); \
} \ } \
else \ else if (! stubs && ! flag_jni) \
if (! stubs) add_class_decl (out, jcf, current_field_signature); add_class_decl (out, jcf, current_field_signature);
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX) #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
...@@ -181,8 +189,9 @@ static int method_printed = 0; ...@@ -181,8 +189,9 @@ static int method_printed = 0;
if (out) \ if (out) \
print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \ print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
} \ } \
else \ else if (flag_jni) \
if (! stubs) add_class_decl (out, jcf, SIGNATURE); print_method_info (NULL, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
else if (! stubs) add_class_decl (out, jcf, SIGNATURE);
#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH); if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
...@@ -312,8 +321,7 @@ cxx_keyword_subst (str, length) ...@@ -312,8 +321,7 @@ cxx_keyword_subst (str, length)
return NULL; return NULL;
} }
/* Generate an access control keyword based on FLAGS. Returns 0 if /* Generate an access control keyword based on FLAGS. */
FLAGS matches the saved access information, nonzero otherwise. */
static void static void
generate_access (stream, flags) generate_access (stream, flags)
...@@ -362,6 +370,28 @@ name_is_method_p (name, length) ...@@ -362,6 +370,28 @@ name_is_method_p (name, length)
return 0; 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. */ /* Get name of a field. This handles renamings due to C++ clash. */
static char * static char *
get_field_name (jcf, name_index, flags) get_field_name (jcf, name_index, flags)
...@@ -525,7 +555,7 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags), ...@@ -525,7 +555,7 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
} }
override = get_field_name (jcf, name_index, flags); override = get_field_name (jcf, name_index, flags);
print_c_decl (out, jcf, name_index, sig_index, 0, override); print_c_decl (out, jcf, name_index, sig_index, 0, override, flags);
fputs (";\n", out); fputs (";\n", out);
if (override) if (override)
...@@ -543,7 +573,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -543,7 +573,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
method_declared = 0; method_declared = 0;
method_access = flags; 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>"); fprintf (stream, "<not a UTF8 constant>");
str = JPOOL_UTF_DATA (jcf, name_index); str = JPOOL_UTF_DATA (jcf, name_index);
length = JPOOL_UTF_LENGTH (jcf, name_index); length = JPOOL_UTF_LENGTH (jcf, name_index);
...@@ -576,9 +606,19 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -576,9 +606,19 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
memcpy (nn->name, str, length); memcpy (nn->name, str, length);
nn->length = length; nn->length = length;
nn->next = method_name_list; 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; method_name_list = nn;
} }
/* If we're not printing, then the rest of this function doesn't
matter. This happens during the first method pass in JNI mode.
Eww. */
if (! stream)
return;
/* We can't generate a method whose name is a C++ reserved word. We /* 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 can't just ignore the function, because that will cause incorrect
code to be generated if the function is virtual (not only for code to be generated if the function is virtual (not only for
...@@ -595,7 +635,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -595,7 +635,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
return; return;
} }
if (! stubs) if (! stubs && ! flag_jni)
{ {
method_printed = 1; method_printed = 1;
...@@ -610,7 +650,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -610,7 +650,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
if (! is_init) if (! is_init)
fputs ("virtual ", out); fputs ("virtual ", out);
} }
print_c_decl (out, jcf, name_index, sig_index, is_init, override); print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
if ((flags & ACC_ABSTRACT)) if ((flags & ACC_ABSTRACT))
fputs (" = 0", out); fputs (" = 0", out);
...@@ -619,10 +659,11 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), ...@@ -619,10 +659,11 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
} }
else else
{ {
if (METHOD_IS_NATIVE(flags)) if (METHOD_IS_NATIVE (flags))
{ {
method_printed = 1; method_printed = 1;
print_stub (out, jcf, name_index, sig_index, is_init, override); print_stub_or_jni (out, jcf, name_index, sig_index,
is_init, override, flags);
} }
} }
} }
...@@ -704,6 +745,7 @@ decode_signature_piece (stream, signature, limit, need_space) ...@@ -704,6 +745,7 @@ decode_signature_piece (stream, signature, limit, need_space)
{ {
case '[': case '[':
/* More spaghetti. */ /* More spaghetti. */
array_loop: array_loop:
for (signature++; (signature < limit for (signature++; (signature < limit
&& *signature >= '0' && *signature >= '0'
...@@ -711,18 +753,35 @@ decode_signature_piece (stream, signature, limit, need_space) ...@@ -711,18 +753,35 @@ decode_signature_piece (stream, signature, limit, need_space)
; ;
switch (*signature) switch (*signature)
{ {
case 'B': ctype = "jbyteArray"; goto printit; case 'B':
case 'C': ctype = "jcharArray"; goto printit; ctype = "jbyteArray";
case 'D': ctype = "jdoubleArray"; goto printit; break;
case 'F': ctype = "jfloatArray"; goto printit; case 'C':
case 'I': ctype = "jintArray"; goto printit; ctype = "jcharArray";
case 'S': ctype = "jshortArray"; goto printit; break;
case 'J': ctype = "jlongArray"; goto printit; case 'D':
case 'Z': ctype = "jbooleanArray"; goto printit; 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 '[': case '[':
/* We have a nested array. */ /* We have a nested array. */
++array_depth; ++array_depth;
fputs ("JArray<", stream); if (! flag_jni)
fputs ("JArray<", stream);
goto array_loop; goto array_loop;
case 'L': case 'L':
...@@ -730,23 +789,42 @@ decode_signature_piece (stream, signature, limit, need_space) ...@@ -730,23 +789,42 @@ decode_signature_piece (stream, signature, limit, need_space)
our output matches what the compiler does. */ our output matches what the compiler does. */
++signature; ++signature;
/* Space between `<' and `:' to avoid C++ digraphs. */ /* Space between `<' and `:' to avoid C++ digraphs. */
fputs ("JArray< ::", stream); if (! flag_jni)
fputs ("JArray< ::", stream);
while (signature < limit && *signature != ';') while (signature < limit && *signature != ';')
{ {
int ch = UTF8_GET (signature, limit); int ch = UTF8_GET (signature, limit);
if (ch == '/') if (! flag_jni)
fputs ("::", stream); {
else if (ch == '/')
jcf_print_char (stream, ch); fputs ("::", stream);
else
jcf_print_char (stream, ch);
}
} }
fputs (" *> *", stream); if (! flag_jni)
fputs (" *> *", stream);
*need_space = 0; *need_space = 0;
++signature; ctype = NULL;
break; break;
default: default:
/* Unparseable signature. */ /* Unparseable signature. */
return NULL; 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; break;
case '(': case '(':
...@@ -764,6 +842,34 @@ decode_signature_piece (stream, signature, limit, need_space) ...@@ -764,6 +842,34 @@ decode_signature_piece (stream, signature, limit, need_space)
case 'Z': ctype = "jboolean"; goto printit; case 'Z': ctype = "jboolean"; goto printit;
case 'V': ctype = "void"; goto printit; case 'V': ctype = "void"; goto printit;
case 'L': 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. */ /* Print a leading "::" so we look in the right namespace. */
fputs ("::", stream); fputs ("::", stream);
++signature; ++signature;
...@@ -792,18 +898,21 @@ decode_signature_piece (stream, signature, limit, need_space) ...@@ -792,18 +898,21 @@ decode_signature_piece (stream, signature, limit, need_space)
break; break;
} }
while (array_depth-- > 0) if (! flag_jni)
fputs ("> *", stream); {
while (array_depth-- > 0)
fputs ("> *", stream);
}
return signature; return signature;
} }
static void static void
DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init, DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
name_override), name_override, flags),
FILE* stream AND JCF* jcf FILE* stream AND JCF* jcf
AND int name_index AND int signature_index AND int name_index AND int signature_index
AND int is_init AND const char *name_override) AND int is_init AND const char *name_override AND int flags)
{ {
if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
{ {
...@@ -850,16 +959,18 @@ DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init, ...@@ -850,16 +959,18 @@ DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
if (need_space) if (need_space)
fputs (" ", stream); fputs (" ", stream);
print_full_cxx_name (stream, jcf, name_index, print_full_cxx_name (stream, jcf, name_index,
signature_index, is_init, name_override); signature_index, is_init, name_override,
flags);
} }
} }
/* Print the unqualified method name followed by the signature. */ /* Print the unqualified method name followed by the signature. */
static void static void
DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, name_override), DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index,
is_init, name_override, flags),
FILE* stream AND JCF* jcf FILE* stream AND JCF* jcf
AND int name_index AND int signature_index AND int is_init AND int name_index AND int signature_index AND int is_init
AND const char *name_override) AND const char *name_override AND int flags)
{ {
int length = JPOOL_UTF_LENGTH (jcf, signature_index); int length = JPOOL_UTF_LENGTH (jcf, signature_index);
const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index); const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
...@@ -879,13 +990,75 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, n ...@@ -879,13 +990,75 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, n
else else
print_name (stream, jcf, name_index); 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))
{
/* 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)
{
int ch = UTF8_GET (signature, limit);
if (ch == '(')
{
/* Ignore. */
}
else if (ch == ')')
{
/* Done. */
break;
}
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. FIXME: upper or lower case
letters? */
fprintf (stream, "_0%04x", ch);
}
}
}
}
if (is_method) if (is_method)
{ {
/* Have a method or a constructor. Print signature pieces /* Have a method or a constructor. Print signature pieces
until done. */ until done. */
fputs (" (", stream); fputs (" (", stream);
str = str0 + 1; str = str0 + 1;
/* 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 != ')') while (str < limit && *str != ')')
{ {
next = decode_signature_piece (stream, str, limit, &need_space); next = decode_signature_piece (stream, str, limit, &need_space);
...@@ -905,12 +1078,28 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, n ...@@ -905,12 +1078,28 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, n
} }
} }
/* This is a helper for print_stub_or_jni. */
static void static void
DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init, DEFUN (print_name_for_stub_or_jni, (stream, jcf, name_index, signature_index,
name_override), 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)
{
char *prefix = flag_jni ? "Java_" : "\n";
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 FILE* stream AND JCF* jcf
AND int name_index AND int signature_index AND int name_index AND int signature_index
AND int is_init AND const char *name_override) AND int is_init AND const char *name_override AND int flags)
{ {
if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
{ {
...@@ -927,6 +1116,13 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init, ...@@ -927,6 +1116,13 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init,
int is_method = str[0] == '('; int is_method = str[0] == '(';
const unsigned char *next; 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 /* If printing a method, skip to the return signature and print
that first. However, there is no return value if this is a that first. However, there is no return value if this is a
constructor. */ constructor. */
...@@ -941,7 +1137,8 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init, ...@@ -941,7 +1137,8 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init,
} }
/* If printing a field or an ordinary method, then print the /* If printing a field or an ordinary method, then print the
"return value" now. */ "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) if (! is_method || ! is_init)
{ {
next = decode_signature_piece (stream, str, limit, &need_space); next = decode_signature_piece (stream, str, limit, &need_space);
...@@ -953,17 +1150,29 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init, ...@@ -953,17 +1150,29 @@ DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init,
} }
} }
/* When printing a JNI header we need to respect the space. In
other cases we're just going to insert a newline anyway. */
if (flag_jni)
fputs (need_space && ! stubs ? " " : "\n", stream);
/* Now print the name of the thing. */ /* Now print the name of the thing. */
print_cxx_classname (stream, "\n", jcf, jcf->this_class); print_name_for_stub_or_jni (stream, jcf, name_index,
fputs ("::", stream); signature_index, is_init, name_override,
print_full_cxx_name (stream, jcf, name_index, flags);
signature_index, is_init, name_override);
fputs ("\n{\n JvFail (\"", stream); /* Print the body. */
print_cxx_classname (stream, "", jcf, jcf->this_class); if (stubs)
fputs ("::", stream); {
print_full_cxx_name (stream, jcf, name_index, if (flag_jni)
signature_index, is_init, name_override); fputs ("\n{\n (*env)->FatalError (\"", stream);
fputs (" not implemented\");\n}\n\n", 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);
}
} }
} }
...@@ -1006,13 +1215,14 @@ print_cxx_classname (stream, prefix, jcf, index) ...@@ -1006,13 +1215,14 @@ print_cxx_classname (stream, prefix, jcf, index)
fputs (prefix, stream); fputs (prefix, stream);
/* Print a leading "::" so we look in the right namespace. */ /* Print a leading "::" so we look in the right namespace. */
fputs ("::", stream); if (! flag_jni)
fputs ("::", stream);
while (s < limit) while (s < limit)
{ {
c = UTF8_GET (s, limit); c = UTF8_GET (s, limit);
if (c == '/') if (c == '/')
fputs ("::", stream); fputs (flag_jni ? "_" : "::", stream);
else else
jcf_print_char (stream, c); jcf_print_char (stream, c);
} }
...@@ -1084,7 +1294,9 @@ print_include (out, utf8, len) ...@@ -1084,7 +1294,9 @@ print_include (out, utf8, len)
all_includes = incl; all_includes = incl;
fputs ("#include <", out); fputs ("#include <", out);
jcf_print_utf8 (out, utf8, len); jcf_print_utf8_replace (out, utf8, len,
'/',
flag_jni ? '_' : '/');
fputs (".h>\n", out); fputs (".h>\n", out);
} }
...@@ -1356,17 +1568,46 @@ DEFUN(process_file, (jcf, out), ...@@ -1356,17 +1568,46 @@ DEFUN(process_file, (jcf, out),
if (written_class_count++ == 0 && out) if (written_class_count++ == 0 && out)
{ {
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) if (! stubs)
fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n", fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
out); cstart, mode, cend);
else else
{ {
fputs ("// This file was created by `gcjh -stubs'. It is -*- c++ -*-.\n\ fprintf (out, "%s This file was created by `gcjh -stubs%s'.%s\n\
//\n\ %s\n\
// This file is intended to give you a head start on implementing native\n\ %s This file is intended to give you a head start on implementing native\n\
// methods using CNI.\n\ %s methods using %s.\n\
// Be aware: running `gcjh -stubs' once more for this class may overwrite any\n\ %s Be aware: running `gcjh -stubs %s' once more for this class may\n\
// edits you have made to this file.\n\n", out); %s overwrite any edits you have made to this file.%s\n\n",
cstart, jflag, mode,
cstart2,
cstart2,
cstart2,
what,
cstart2,
jflag,
cstart2,
cend);
} }
} }
...@@ -1376,30 +1617,44 @@ DEFUN(process_file, (jcf, out), ...@@ -1376,30 +1617,44 @@ DEFUN(process_file, (jcf, out),
{ {
print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class); print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
fprintf (out, "__\n"); fprintf (out, "__\n");
print_mangled_classname (out, jcf, "#define __", jcf->this_class); print_mangled_classname (out, jcf, "#define __", jcf->this_class);
fprintf (out, "__\n\n"); fprintf (out, "__\n\n");
/* We do this to ensure that inline methods won't be `outlined' if (flag_jni)
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)
{ {
int super_length; fprintf (out, "#include <jni.h>\n\n");
const unsigned char *supername = fprintf (out, "#ifdef __cplusplus\n");
super_class_name (jcf, &super_length); fprintf (out, "extern \"C\"\n");
fprintf (out, "{\n");
fputs ("\n", out); fprintf (out, "#endif\n");
print_include (out, supername, super_length); }
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)
{
int super_length;
const unsigned char *supername =
super_class_name (jcf, &super_length);
fputs ("\n", out);
print_include (out, supername, super_length);
}
} }
} }
else else
{ {
/* Strip off the ".class" portion of the name when printing /* Strip off the ".class" portion of the name when printing
the include file name. */ the include file name. */
print_include (out, jcf->classname, strlen (jcf->classname) - 6); int len = strlen (jcf->classname);
if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
len -= 6;
print_include (out, jcf->classname, len);
} }
} }
...@@ -1417,9 +1672,10 @@ DEFUN(process_file, (jcf, out), ...@@ -1417,9 +1672,10 @@ DEFUN(process_file, (jcf, out),
jcf_parse_methods (jcf); jcf_parse_methods (jcf);
if (out) if (out)
{ fputs ("\n", out);
fputs ("\n", out);
if (out && ! flag_jni)
{
if (! stubs) if (! stubs)
print_class_decls (out, jcf, jcf->this_class); print_class_decls (out, jcf, jcf->this_class);
...@@ -1427,7 +1683,7 @@ DEFUN(process_file, (jcf, out), ...@@ -1427,7 +1683,7 @@ DEFUN(process_file, (jcf, out),
fprintf (out, "%s\n", prepend_specs[i]); fprintf (out, "%s\n", prepend_specs[i]);
if (prepend_count > 0) if (prepend_count > 0)
fputc ('\n', out); fputc ('\n', out);
if (! stubs) if (! stubs)
{ {
if (! print_cxx_classname (out, "class ", jcf, jcf->this_class)) if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
...@@ -1464,32 +1720,38 @@ DEFUN(process_file, (jcf, out), ...@@ -1464,32 +1720,38 @@ DEFUN(process_file, (jcf, out),
jcf_parse_final_attributes (jcf); jcf_parse_final_attributes (jcf);
if (out) if (out && ! stubs)
{ {
/* Generate friend decl if we still must. */ if (flag_jni)
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]);
if (!stubs)
{ {
print_mangled_classname (out, jcf, fprintf (out, "\n#ifdef __cplusplus\n");
"\n#endif /* __", jcf->this_class); fprintf (out, "}\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);
fprintf (out, "__ */\n");
} }
} }
...@@ -1531,6 +1793,7 @@ static struct option options[] = ...@@ -1531,6 +1793,7 @@ static struct option options[] =
{ "MG", no_argument, NULL, OPT_MG }, { "MG", no_argument, NULL, OPT_MG },
{ "MD", no_argument, NULL, OPT_MD }, { "MD", no_argument, NULL, OPT_MD },
{ "MMD", no_argument, NULL, OPT_MMD }, { "MMD", no_argument, NULL, OPT_MMD },
{ "jni", no_argument, &flag_jni, 1 },
{ NULL, no_argument, NULL, 0 } { NULL, no_argument, NULL, 0 }
}; };
...@@ -1547,6 +1810,7 @@ help () ...@@ -1547,6 +1810,7 @@ help ()
printf ("Usage: gcjh [OPTION]... CLASS...\n\n"); printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
printf ("Generate C++ header files from .class files\n\n"); printf ("Generate C++ header files from .class files\n\n");
printf (" -stubs Generate an implementation stub file\n"); printf (" -stubs Generate an implementation stub file\n");
printf (" -jni Generate a JNI header or stub\n");
printf ("\n"); printf ("\n");
printf (" -add TEXT Insert TEXT into class body\n"); printf (" -add TEXT Insert TEXT into class body\n");
printf (" -append TEXT Insert TEXT after class declaration\n"); printf (" -append TEXT Insert TEXT after class declaration\n");
...@@ -1767,6 +2031,8 @@ DEFUN(main, (argc, argv), ...@@ -1767,6 +2031,8 @@ DEFUN(main, (argc, argv),
char ch = classname[i]; char ch = classname[i];
if (ch == '.') if (ch == '.')
ch = '/'; ch = '/';
if (flag_jni && ch == '/')
ch = '_';
current_output_file[dir_len++] = ch; current_output_file[dir_len++] = ch;
} }
if (emit_dependencies) if (emit_dependencies)
...@@ -1785,7 +2051,7 @@ DEFUN(main, (argc, argv), ...@@ -1785,7 +2051,7 @@ DEFUN(main, (argc, argv),
} }
} }
strcpy (current_output_file + dir_len, strcpy (current_output_file + dir_len,
stubs ? ".cc" : ".h"); stubs ? (flag_jni ? ".c" : ".cc") : ".h");
jcf_dependency_set_target (current_output_file); jcf_dependency_set_target (current_output_file);
if (! suppress_output) if (! suppress_output)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment