X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fjava%2Fgjavah.c;h=4afa14959551f247ad0d3e7741464d9bf4d19a9c;hb=44b49c1594059a18beb60bdf47a8f1135d3dc1d1;hp=3dc4217888792db32764bb99e138963f1f57ce33;hpb=2ff1cdc49f3970ecd62565f6b77d36f53227a562;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c index 3dc42178887..4afa1495955 100644 --- a/gcc/java/gjavah.c +++ b/gcc/java/gjavah.c @@ -1,20 +1,23 @@ /* 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, 2000 Free Software Foundation, Inc. +Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +Free Software Foundation, Inc. -This program is free software; you can redistribute it and/or modify +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -This program is distributed in the hope that it will be useful, +GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to +along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -26,6 +29,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include #include "jcf.h" @@ -33,6 +38,9 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "javaop.h" #include "java-tree.h" #include "java-opcodes.h" +#include "ggc.h" +#include "hashtab.h" +#include "intl.h" #include @@ -45,7 +53,11 @@ FILE *out = NULL; static int found_error = 0; /* Nonzero if we're generating JNI output. */ -static int flag_jni = 0; +int flag_jni = 0; + +/* When nonzero, warn when source file is newer than matching class + file. */ +int flag_newer = 1; /* Directory to place resulting files in. Set by -d option. */ const char *output_directory = ""; @@ -113,40 +125,44 @@ struct method_name /* List of method names we've seen. */ static struct method_name *method_name_list; -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, int)); -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)); +static void print_field_info (FILE*, JCF*, int, int, JCF_u2); +static void print_mangled_classname (FILE*, JCF*, const char*, int); +static int print_cxx_classname (FILE*, const char*, JCF*, int, int); +static void print_method_info (FILE*, JCF*, int, int, JCF_u2); +static void print_c_decl (FILE*, JCF*, int, int, int, const char *, int); +static void print_stub_or_jni (FILE*, JCF*, int, int, int, const char *, int); +static void print_full_cxx_name (FILE*, JCF*, int, int, int, const char *, int); +static void decompile_method (FILE*, JCF*, int); +static void add_class_decl (FILE*, JCF*, JCF_u2); + +static void print_name (FILE *, JCF *, int); +static void print_base_classname (FILE *, JCF *, int); +static int utf8_cmp (const unsigned char *, int, const char *); +static char *cxx_keyword_subst (const unsigned char *, int); +static void generate_access (FILE *, JCF_u2); +static int name_is_method_p (const unsigned char *, int); +static char *get_field_name (JCF *, int, JCF_u2); +static void print_field_name (FILE *, JCF *, int, JCF_u2); +static const unsigned char *super_class_name (JCF *, int *); +static void print_include (FILE *, const unsigned char *, int); +static int gcjh_streq (const void *p1, const void *p2); +static int throwable_p (const unsigned char *signature); +static const unsigned char * + decode_signature_piece (FILE *, const unsigned char *, + const unsigned char *, int *); +static void print_class_decls (FILE *, JCF *, int); +static void error (const char *msgid, ...); +static void usage (void) ATTRIBUTE_NORETURN; +static void help (void) ATTRIBUTE_NORETURN; +static void version (void) ATTRIBUTE_NORETURN; +static int overloaded_jni_method_exists_p (const unsigned char *, int, + const char *, int); +static void jni_print_char (FILE *, int); +static void jni_print_float (FILE *, jfloat); +static void jni_print_double (FILE *, jdouble); +static void decompile_return_statement (FILE *, JCF *, int, int, int); + +static void handle_inner_classes (int); JCF_u2 current_field_name; JCF_u2 current_field_value; @@ -183,9 +199,17 @@ static int method_declared = 0; static int method_access = 0; static int method_printed = 0; static int method_synthetic = 0; +static int method_signature = 0; + +/* Set to 1 while the very first data member of a class is being handled. */ +static int is_first_data_member = 0; + #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ { \ method_synthetic = 0; \ + method_printed = 0; \ + decompiled = 0; \ + method_signature = SIGNATURE; \ if (ATTRIBUTE_COUNT) \ method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT, \ (const char *)"Synthetic", 9); \ @@ -200,15 +224,14 @@ static int method_synthetic = 0; } \ if (method_pass && !method_synthetic) \ { \ - decompiled = 0; method_printed = 0; \ if (out) \ print_method_info (out, jcf, NAME, SIGNATURE, \ - ACCESS_FLAGS, method_synthetic); \ + ACCESS_FLAGS); \ } \ else if (!method_synthetic) \ { \ print_method_info (NULL, jcf, NAME, SIGNATURE, \ - ACCESS_FLAGS, method_synthetic); \ + ACCESS_FLAGS); \ if (! stubs && ! flag_jni) \ add_class_decl (out, jcf, SIGNATURE); \ } \ @@ -222,48 +245,83 @@ static int decompiled = 0; if (out && method_printed && !method_synthetic) \ fputs (decompiled || stubs ? "\n" : ";\n", out); -#include "jcf-reader.c" +#define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) handle_inner_classes (COUNT) -/* 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 +/* We're going to need {peek,skip}_attribute, enable their definition. */ +#define NEED_PEEK_ATTRIBUTE +#define NEED_SKIP_ATTRIBUTE -/* Return 1 if F is not Inf or NaN. */ -static int -java_float_finite (f) - jfloat f; +#include "jcf-reader.c" + +/* Print an error message and set found_error. */ +static void +error (const char *msgid, ...) { - union Word u; - u.f = f; + va_list ap; - /* We happen to know that F_NAN_MASK will match all NaN values, and - also positive and negative infinity. That's why we only need one - test here. See The Java Language Specification, section 20.9. */ - return (u.i & F_NAN_MASK) != F_NAN_MASK; + va_start (ap, msgid); + + fprintf (stderr, "gcjh: "); + vfprintf (stderr, _(msgid), ap); + va_end (ap); + fprintf (stderr, "\n"); + found_error = 1; } -/* Return 1 if D is not Inf or NaN. */ -static int -java_double_finite (d) - jdouble d; +/* Print a single-precision float, suitable for parsing by g++. */ +static void +jni_print_float (FILE *stream, jfloat f) { - union DWord u; - u.d = d; + /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't + work in data initializers. FIXME. */ + if (JFLOAT_FINITE (f)) + { + fputs (" = ", stream); + if (f.negative) + putc ('-', stream); + if (f.exponent) + fprintf (stream, "0x1.%.6xp%+df", + ((unsigned int)f.mantissa) << 1, + f.exponent - JFLOAT_EXP_BIAS); + else + /* Exponent of 0x01 is -125; exponent of 0x00 is *also* -125, + because the implicit leading 1 bit is no longer present. */ + fprintf (stream, "0x0.%.6xp%+df", + ((unsigned int)f.mantissa) << 1, + f.exponent + 1 - JFLOAT_EXP_BIAS); + } + fputs (";\n", stream); +} - /* Now check for all NaNs. */ - return (u.l & D_NAN_MASK) != D_NAN_MASK; +/* Print a double-precision float, suitable for parsing by g++. */ +static void +jni_print_double (FILE *stream, jdouble f) +{ + /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't + work in data initializers. FIXME. */ + if (JDOUBLE_FINITE (f)) + { + fputs (" = ", stream); + if (f.negative) + putc ('-', stream); + if (f.exponent) + fprintf (stream, "0x1.%.5x%.8xp%+d", + f.mantissa0, f.mantissa1, + f.exponent - JDOUBLE_EXP_BIAS); + else + /* Exponent of 0x001 is -1022; exponent of 0x000 is *also* -1022, + because the implicit leading 1 bit is no longer present. */ + fprintf (stream, "0x0.%.5x%.8xp%+d", + f.mantissa0, f.mantissa1, + f.exponent + 1 - JDOUBLE_EXP_BIAS); + } + fputs (";\n", stream); } /* Print a character, appropriately mangled for JNI. */ static void -jni_print_char (stream, ch) - FILE *stream; - int ch; +jni_print_char (FILE *stream, int ch) { if (! flag_jni) jcf_print_char (stream, ch); @@ -279,9 +337,7 @@ jni_print_char (stream, ch) fputs ("_3", stream); else if (ch == '/') fputs ("_", stream); - else if ((ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z')) + else if (ISALNUM (ch)) fputc (ch, stream); else { @@ -294,8 +350,7 @@ jni_print_char (stream, ch) string, an error results. */ static void -DEFUN(print_name, (stream, jcf, name_index), - FILE* stream AND JCF* jcf AND int name_index) +print_name (FILE* stream, JCF* jcf, int name_index) { if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8) { @@ -328,10 +383,7 @@ DEFUN(print_name, (stream, jcf, name_index), final separator. */ static void -print_base_classname (stream, jcf, index) - FILE *stream; - JCF *jcf; - int index; +print_base_classname (FILE *stream, JCF *jcf, int index) { int name_index = JPOOL_USHORT1 (jcf, index); int len; @@ -362,10 +414,7 @@ print_base_classname (stream, jcf, index) and 1 if STR is "greater" than NAME. */ static int -utf8_cmp (str, length, name) - const unsigned char *str; - int length; - const char *name; +utf8_cmp (const unsigned char *str, int length, const char *name) { const unsigned char *limit = str + length; int i; @@ -382,39 +431,112 @@ utf8_cmp (str, length, name) /* This is a sorted list of all C++ keywords. */ -static const char *cxx_keywords[] = +static const char *const cxx_keywords[] = { + "_Complex", + "__alignof", + "__alignof__", + "__asm", + "__asm__", + "__attribute", + "__attribute__", + "__builtin_va_arg", + "__complex", + "__complex__", + "__const", + "__const__", + "__extension__", + "__imag", + "__imag__", + "__inline", + "__inline__", + "__label__", + "__null", + "__real", + "__real__", + "__restrict", + "__restrict__", + "__signed", + "__signed__", + "__typeof", + "__typeof__", + "__volatile", + "__volatile__", + "and", + "and_eq", "asm", "auto", + "bitand", + "bitor", "bool", + "break", + "case", + "catch", + "char", + "class", + "compl", + "const", "const_cast", + "continue", + "default", "delete", + "do", + "double", "dynamic_cast", + "else", "enum", "explicit", + "export", "extern", + "false", + "float", + "for", "friend", + "goto", + "if", "inline", + "int", + "long", "mutable", "namespace", - "overload", + "new", + "not", + "not_eq", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", "register", "reinterpret_cast", + "return", + "short", "signed", "sizeof", + "static", "static_cast", "struct", + "switch", "template", + "this", + "throw", + "true", + "try", "typedef", "typeid", "typename", - "typenameopt", + "typeof", "union", "unsigned", "using", "virtual", + "void", "volatile", - "wchar_t" + "wchar_t", + "while", + "xor", + "xor_eq" }; @@ -423,9 +545,7 @@ static const char *cxx_keywords[] = Otherwise, return NULL. The return value is malloc()d. */ static char * -cxx_keyword_subst (str, length) - const unsigned char *str; - int length; +cxx_keyword_subst (const unsigned char *str, int length) { int last = ARRAY_SIZE (cxx_keywords); int first = 0; @@ -436,16 +556,32 @@ cxx_keyword_subst (str, length) mid != old; old = mid, mid = (last + first) / 2) { - int r = utf8_cmp (str, length, cxx_keywords[mid]); + int kwl = strlen (cxx_keywords[mid]); + int min_length = kwl > length ? length : kwl; + int r = utf8_cmp (str, min_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; + int i; + + /* Skip all trailing `$'. */ + for (i = min_length; i < length && str[i] == '$'; ++i) + ; + /* We've only found a match if all the remaining characters + are `$'. */ + if (i == length) + { + char *dup = xmalloc (2 + length - min_length + kwl); + strcpy (dup, cxx_keywords[mid]); + for (i = kwl; i < length + 1; ++i) + dup[i] = '$'; + dup[i] = '\0'; + return dup; + } + r = 1; } - else if (r < 0) + + if (r < 0) last = mid; else first = mid; @@ -456,9 +592,7 @@ cxx_keyword_subst (str, length) /* Generate an access control keyword based on FLAGS. */ static void -generate_access (stream, flags) - FILE *stream; - JCF_u2 flags; +generate_access (FILE *stream, JCF_u2 flags) { if ((flags & ACC_VISIBILITY) == last_access) return; @@ -488,9 +622,7 @@ generate_access (stream, flags) /* See if NAME is already the name of a method. */ static int -name_is_method_p (name, length) - const unsigned char *name; - int length; +name_is_method_p (const unsigned char *name, int length) { struct method_name *p; @@ -505,11 +637,8 @@ name_is_method_p (name, length) /* 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; +overloaded_jni_method_exists_p (const unsigned char *name, int length, + const char *signature, int sig_length) { struct method_name *p; @@ -526,10 +655,7 @@ overloaded_jni_method_exists_p (name, length, signature, sig_length) /* 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; +get_field_name (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); @@ -543,8 +669,7 @@ get_field_name (jcf, name_index, flags) trouble. */ if ((flags & ACC_STATIC)) { - fprintf (stderr, "static field has same name as method\n"); - found_error = 1; + error ("static field has same name as method"); return NULL; } @@ -561,11 +686,7 @@ get_field_name (jcf, name_index, flags) /* 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; +print_field_name (FILE *stream, JCF *jcf, int name_index, JCF_u2 flags) { char *override = get_field_name (jcf, name_index, flags); @@ -580,9 +701,8 @@ print_field_name (stream, jcf, name_index, flags) } static void -DEFUN(print_field_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) +print_field_info (FILE *stream, JCF* jcf, int name_index, int sig_index, + JCF_u2 flags) { char *override = NULL; @@ -650,10 +770,7 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags), jfloat fnum = JPOOL_FLOAT (jcf, current_field_value); fputs ("const jfloat ", out); print_field_name (out, jcf, name_index, 0); - if (! java_float_finite (fnum)) - fputs (";\n", out); - else - fprintf (out, " = %.10g;\n", fnum); + jni_print_float (out, fnum); } break; case CONSTANT_Double: @@ -661,10 +778,7 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags), jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value); fputs ("const jdouble ", out); print_field_name (out, jcf, name_index, 0); - if (! java_double_finite (dnum)) - fputs (";\n", out); - else - fprintf (out, " = %.17g;\n", dnum); + jni_print_double (out, dnum); } break; default: @@ -689,9 +803,8 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags), static void -DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), - FILE *stream AND JCF* jcf - AND int name_index AND int sig_index AND JCF_u2 flags AND int synth) +print_method_info (FILE *stream, JCF* jcf, int name_index, int sig_index, + JCF_u2 flags) { const unsigned char *str; int length, is_init = 0; @@ -704,10 +817,6 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), str = JPOOL_UTF_DATA (jcf, name_index); length = JPOOL_UTF_LENGTH (jcf, name_index); - /* Ignore synthetic methods. */ - if (synth) - return; - if (str[0] == '<') { /* Ignore the internally generated method . However, @@ -719,9 +828,9 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), { /* FIXME: i18n bug here. Order of prints should not be fixed. */ - fprintf (stderr, "ignored method `"); + fprintf (stderr, _("ignored method `")); jcf_print_utf8 (stderr, str, length); - fprintf (stderr, "' marked virtual\n"); + fprintf (stderr, _("' marked virtual\n")); found_error = 1; return; } @@ -735,13 +844,13 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), { struct method_name *nn; - nn = (struct method_name *) xmalloc (sizeof (struct method_name)); - nn->name = (char *) xmalloc (length); + nn = xmalloc (sizeof (struct method_name)); + nn->name = 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); + nn->signature = xmalloc (nn->sig_length); memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index), nn->sig_length); method_name_list = nn; @@ -759,18 +868,6 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), (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; - } - } } if (! stubs && ! flag_jni) @@ -809,13 +906,135 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth), free (override); } +/* A helper for the decompiler which prints a `return' statement where + the type is a reference type. If METHODTYPE and OBJECTTYPE are not + identical, we emit a cast. We do this because the C++ compiler + doesn't know that a reference can be cast to the type of an + interface it implements. METHODTYPE is the index of the method's + signature. NAMEINDEX is the index of the field name; -1 for + `this'. OBJECTTYPE is the index of the object's type. */ +static void +decompile_return_statement (FILE *out, JCF *jcf, int methodtype, + int nameindex, int objecttype) +{ + int cast = 0; + int obj_name_len, method_name_len; + const unsigned char *obj_data, *method_data; + + obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype); + obj_data = JPOOL_UTF_DATA (jcf, objecttype); + + method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype); + method_data = JPOOL_UTF_DATA (jcf, methodtype); + + /* Skip forward to return type part of method. */ + while (*method_data != ')') + { + ++method_data; + --method_name_len; + } + /* Skip past `)'. */ + ++method_data; + --method_name_len; + + /* If we see an `L', skip it and the trailing `;'. */ + if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';') + { + ++method_data; + method_name_len -= 2; + } + if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';') + { + ++obj_data; + obj_name_len -= 2; + } + + /* FIXME: if METHODTYPE is a superclass of OBJECTTYPE then we don't + need a cast. Right now there is no way to determine if this is + the case. */ + if (method_name_len != obj_name_len) + cast = 1; + else + { + int i; + for (i = 0; i < method_name_len; ++i) + { + if (method_data[i] != obj_data[i]) + { + cast = 1; + break; + } + } + } + + fputs (" { return ", out); + + if (cast) + { + int array_depth = 0; + const unsigned char *limit; + + fputs ("reinterpret_cast<", out); + + while (*method_data == '[') + { + ++method_data; + ++array_depth; + --method_name_len; + fputs ("JArray<", out); + } + + /* Leading space to avoid C++ digraphs. */ + fputs (" ::", out); + + /* If we see an `L', skip it and the trailing `;'. Only do this + if we've seen an array specification. If we don't have an + array then the `L' was stripped earlier. */ + if (array_depth && method_data[0] == 'L' + && method_data[method_name_len - 1] == ';') + { + ++method_data; + method_name_len -= 2; + } + + limit = method_data + method_name_len; + while (method_data < limit) + { + int ch = UTF8_GET (method_data, limit); + if (ch == '/') + fputs ("::", out); + else + jcf_print_char (out, ch); + } + fputs (" *", out); + + /* Close each array. */ + while (array_depth > 0) + { + fputs ("> *", out); + --array_depth; + } + + /* Close the cast. */ + fputs ("> (", out); + } + + if (nameindex == -1) + fputs ("this", out); + else + print_field_name (out, jcf, nameindex, 0); + + if (cast) + fputs (")", out); + + fputs ("; }", out); +} + + /* Try to decompile a method body. Right now we just try to handle a simple case that we can do. Expand as desired. */ static void -decompile_method (out, jcf, code_len) - FILE *out; - JCF *jcf; - int code_len; +decompile_method (FILE *out, JCF *jcf, int code_len) { const unsigned char *codes = jcf->read_ptr; int index; @@ -835,24 +1054,32 @@ decompile_method (out, jcf, code_len) || codes[4] == OPCODE_lreturn)) { /* Found code like `return FIELD'. */ - fputs (" { return ", out); index = (codes[2] << 8) | codes[3]; /* FIXME: ensure that tag is CONSTANT_Fieldref. */ - /* FIXME: ensure that the field's class is this class. */ name_and_type = JPOOL_USHORT2 (jcf, index); /* FIXME: ensure that tag is CONSTANT_NameAndType. */ name = JPOOL_USHORT1 (jcf, name_and_type); - /* FIXME: flags. */ - print_field_name (out, jcf, name, 0); - fputs ("; }", out); + if (codes[4] == OPCODE_areturn) + decompile_return_statement (out, jcf, method_signature, + name, JPOOL_USHORT2 (jcf, name_and_type)); + else + { + fputs (" { return ", out); + /* FIXME: flags. */ + print_field_name (out, jcf, name, 0); + fputs ("; }", out); + } decompiled = 1; } else if (code_len == 2 && codes[0] == OPCODE_aload_0 - && codes[1] == OPCODE_areturn) + && codes[1] == OPCODE_areturn + /* We're going to generate `return this'. This only makes + sense for non-static methods. */ + && ! (method_access & ACC_STATIC)) { - /* Found `return this'. */ - fputs (" { return this; }", out); + decompile_return_statement (out, jcf, method_signature, -1, + JPOOL_USHORT1 (jcf, jcf->this_class)); decompiled = 1; } else if (code_len == 1 && codes[0] == OPCODE_return) @@ -872,13 +1099,118 @@ decompile_method (out, jcf, code_len) } } +/* Like strcmp, but invert the return result for the hash table. This + should probably be in hashtab.c to complement the existing string + hash function. */ +static int +gcjh_streq (const void *p1, const void *p2) +{ + return ! strcmp ((char *) p1, (char *) p2); +} + +/* Return 1 if the initial part of CLNAME names a subclass of throwable, + or 0 if not. CLNAME may be extracted from a signature, and can be + terminated with either `;' or NULL. */ +static int +throwable_p (const unsigned char *clname) +{ + int length; + unsigned char *current; + int i; + int result = 0; + + /* We keep two hash tables of class names. In one we list all the + classes which are subclasses of Throwable. In the other we will + all other classes. We keep two tables to make the code a bit + simpler; we don't have to have a structure mapping class name to + a `throwable?' bit. */ + static htab_t throw_hash; + static htab_t non_throw_hash; + static int init_done = 0; + + if (! init_done) + { + void **slot; + unsigned char *str; + + /* Self-initializing. The cost of this really doesn't matter. + We also don't care about freeing these, either. */ + throw_hash = htab_create (10, htab_hash_string, gcjh_streq, + (htab_del) free); + non_throw_hash = htab_create (10, htab_hash_string, gcjh_streq, + (htab_del) free); + + /* Make sure the root classes show up in the tables. */ + str = xstrdup ("java.lang.Throwable"); + slot = htab_find_slot (throw_hash, str, INSERT); + *slot = str; + + str = xstrdup ("java.lang.Object"); + slot = htab_find_slot (non_throw_hash, str, INSERT); + *slot = str; + + init_done = 1; + } + + for (length = 0; clname[length] != ';' && clname[length] != '\0'; ++length) + ; + current = ALLOC (length + 1); + for (i = 0; i < length; ++i) + current[i] = clname[i] == '/' ? '.' : clname[i]; + current[length] = '\0'; + + /* We don't compute the hash slot here because the table might be + modified by the recursion. In that case the slot could be + invalidated. */ + if (htab_find (throw_hash, current)) + result = 1; + else if (htab_find (non_throw_hash, current)) + result = 0; + else + { + JCF jcf; + void **slot; + unsigned char *super, *tmp; + int super_length = -1; + const char *classfile_name = find_class (current, strlen (current), + &jcf, 0); + + if (! classfile_name) + { + error ("couldn't find class %s", current); + return 0; + } + if (jcf_parse_preamble (&jcf) != 0 + || jcf_parse_constant_pool (&jcf) != 0 + || verify_constant_pool (&jcf) > 0) + { + error ("parse error while reading %s", classfile_name); + return 0; + } + jcf_parse_class (&jcf); + + tmp = (unsigned char *) super_class_name (&jcf, &super_length); + super = ALLOC (super_length + 1); + memcpy (super, tmp, super_length); + super[super_length] = '\0'; + + result = throwable_p (super); + slot = htab_find_slot (result ? throw_hash : non_throw_hash, + current, INSERT); + *slot = current; + current = NULL; + + JCF_FINISH (&jcf); + } + + return result; +} + /* Print one piece of a signature. Returns pointer to next parseable character on success, NULL on error. */ static const unsigned char * -decode_signature_piece (stream, signature, limit, need_space) - FILE *stream; - const unsigned char *signature, *limit; - int *need_space; +decode_signature_piece (FILE *stream, const unsigned char *signature, + const unsigned char *limit, int *need_space) { const char *ctype; int array_depth = 0; @@ -890,8 +1222,7 @@ decode_signature_piece (stream, signature, limit, need_space) array_loop: for (signature++; (signature < limit - && *signature >= '0' - && *signature <= '9'); signature++) + && ISDIGIT (*signature)); signature++) ; switch (*signature) { @@ -957,7 +1288,7 @@ decode_signature_piece (stream, signature, limit, need_space) /* 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) + if (flag_jni && (ctype == NULL || array_depth > 0)) { ctype = "jobjectArray"; *need_space = 1; @@ -986,24 +1317,16 @@ decode_signature_piece (stream, signature, limit, need_space) 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. */ + /* We know about certain types and special-case their names. */ 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)) + /* Skip leading 'L' for throwable_p call. */ + else if (throwable_p (signature + 1)) ctype = "jthrowable"; - else if (! strncmp (signature, "Ljava/lang/ref/WeakReference;", - sizeof ("Ljava/lang/ref/WeakReference;") - 1)) - ctype = "jweak"; else ctype = "jobject"; @@ -1049,11 +1372,8 @@ decode_signature_piece (stream, signature, limit, need_space) } static void -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 int is_init AND const char *name_override AND int flags) +print_c_decl (FILE* stream, JCF* jcf, int name_index, int signature_index, + int is_init, const char *name_override, int flags) { if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) { @@ -1064,7 +1384,7 @@ DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init, { 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 *str = str0; const unsigned char *limit = str + length; int need_space = 0; int is_method = str[0] == '('; @@ -1090,12 +1410,22 @@ DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init, next = decode_signature_piece (stream, str, limit, &need_space); if (! next) { - fprintf (stderr, "unparseable signature: `%s'\n", str0); - found_error = 1; + error ("unparseable signature: `%s'", str0); return; } } + /* Force the alignment of the first data member. This is + because the "new" C++ ABI changed the alignemnt of non-POD + classes. gcj, however, still uses the "old" alignment. */ + if (is_first_data_member && ! (flags & ACC_STATIC) && ! is_method) + { + is_first_data_member = 0; + print_cxx_classname (out, " __attribute__((aligned(__alignof__( ", + jcf, jcf->super_class, 1); + fputs (" )))) ", stream); + } + /* Now print the name of the thing. */ if (need_space) fputs (" ", stream); @@ -1107,15 +1437,13 @@ DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init, /* 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) +print_full_cxx_name (FILE* stream, JCF* jcf, int name_index, + int signature_index, int is_init, + const char *name_override, 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 *str = str0; const unsigned char *limit = str + length; int need_space = 0; int is_method = str[0] == '('; @@ -1184,8 +1512,7 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, next = decode_signature_piece (stream, str, limit, &need_space); if (! next) { - fprintf (stderr, "unparseable signature: `%s'\n", str0); - found_error = 1; + error ("unparseable signature: `%s'", str0); return; } @@ -1200,14 +1527,12 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, /* 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) +print_name_for_stub_or_jni (FILE *stream, JCF *jcf, int name_index, + int signature_index, int is_init, + const char *name_override, int flags) { const char *const prefix = flag_jni ? "Java_" : ""; - print_cxx_classname (stream, prefix, jcf, jcf->this_class); + print_cxx_classname (stream, prefix, jcf, jcf->this_class, 1); fputs (flag_jni ? "_" : "::", stream); print_full_cxx_name (stream, jcf, name_index, signature_index, is_init, name_override, @@ -1215,11 +1540,9 @@ DEFUN (print_name_for_stub_or_jni, (stream, jcf, name_index, signature_index, } 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) +print_stub_or_jni (FILE* stream, JCF* jcf, int name_index, + int signature_index, int is_init, + const char *name_override, int flags) { if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) { @@ -1230,7 +1553,7 @@ DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init, { 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 *str = str0; const unsigned char *limit = str + length; int need_space = 0; int is_method = str[0] == '('; @@ -1241,7 +1564,7 @@ DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init, return; if (flag_jni && ! stubs) - fputs ("extern ", stream); + fputs ("extern JNIEXPORT ", stream); /* If printing a method, skip to the return signature and print that first. However, there is no return value if this is a @@ -1264,8 +1587,7 @@ DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init, next = decode_signature_piece (stream, str, limit, &need_space); if (! next) { - fprintf (stderr, "unparseable signature: `%s'\n", str0); - found_error = 1; + error ("unparseable signature: `%s'", str0); return; } } @@ -1273,6 +1595,9 @@ DEFUN(print_stub_or_jni, (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. */ fputs (need_space && ! stubs ? " " : "\n", stream); + + if (flag_jni && ! stubs) + fputs ("JNICALL ", stream); /* Now print the name of the thing. */ print_name_for_stub_or_jni (stream, jcf, name_index, @@ -1283,21 +1608,21 @@ DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init, if (stubs) { if (flag_jni) - fputs ("\n{\n (*env)->FatalError (\"", stream); + fputs ("\n{\n (*env)->FatalError (env, \"", stream); else - fputs ("\n{\n JvFail (\"", stream); + fputs ("\n{\n throw new ::java::lang::UnsupportedOperationException (JvNewStringLatin1 (\"", 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); + fprintf (stream, " not implemented\")%s;\n}\n\n", + flag_jni ? "" : ")"); } } } static void -DEFUN(print_mangled_classname, (stream, jcf, prefix, index), - FILE *stream AND JCF *jcf AND const char *prefix AND int index) +print_mangled_classname (FILE *stream, JCF *jcf, const char *prefix, int index) { int name_index = JPOOL_USHORT1 (jcf, index); fputs (prefix, stream); @@ -1311,11 +1636,8 @@ DEFUN(print_mangled_classname, (stream, jcf, prefix, index), to an array, ignore it and don't print PREFIX. Returns 1 if something was printed, 0 otherwise. */ static int -print_cxx_classname (stream, prefix, jcf, index) - FILE *stream; - const char *prefix; - JCF *jcf; - int index; +print_cxx_classname (FILE *stream, const char *prefix, + JCF *jcf, int index, int add_scope) { int name_index = JPOOL_USHORT1 (jcf, index); int len, c; @@ -1334,7 +1656,7 @@ print_cxx_classname (stream, prefix, jcf, index) fputs (prefix, stream); /* Print a leading "::" so we look in the right namespace. */ - if (! flag_jni && ! stubs) + if (! flag_jni && ! stubs && add_scope) fputs ("::", stream); while (s < limit) @@ -1354,9 +1676,7 @@ int written_class_count = 0; /* Return name of superclass. If LEN is not NULL, fill it with length of name. */ static const unsigned char * -super_class_name (derived_jcf, len) - JCF *derived_jcf; - int *len; +super_class_name (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); @@ -1369,6 +1689,34 @@ super_class_name (derived_jcf, len) return supername; } +static void +handle_inner_classes (int count) +{ + int i; + + if (out && ! flag_jni && ! stubs && count > 0) + fprintf (out, "\n"); + + for (i = 0; i < count; ++i) + { + JCF_u2 inner_info_index = JCF_readu2 (current_jcf); + + /* There are a few more values here, but we don't care about + them. The (void) cast is apparently the only way to avoid a + warning here. */ + (void) JCF_readu2 (current_jcf); + (void) JCF_readu2 (current_jcf); + (void) JCF_readu2 (current_jcf); + + if (out && ! flag_jni && ! stubs) + { + print_mangled_classname (out, current_jcf, " friend class ", + inner_info_index); + fprintf (out, ";\n"); + } + } +} + /* We keep track of all the `#include's we generate, so we can avoid @@ -1384,10 +1732,7 @@ static struct include *all_includes = NULL; /* Generate a #include. */ static void -print_include (out, utf8, len) - FILE *out; - const unsigned char *utf8; - int len; +print_include (FILE *out, const unsigned char *utf8, int len) { struct include *incl; @@ -1405,7 +1750,7 @@ print_include (out, utf8, len) return; } - incl = (struct include *) xmalloc (sizeof (struct include)); + incl = xmalloc (sizeof (struct include)); incl->name = xmalloc (len + 1); strncpy (incl->name, utf8, len); incl->name[len] = '\0'; @@ -1434,9 +1779,9 @@ struct namelet 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)); +static void add_namelet (const unsigned char *, const unsigned char *, + struct namelet *); +static void print_namelet (FILE *, struct namelet *, int); /* The special root namelet. */ static struct namelet root = @@ -1451,9 +1796,8 @@ static struct namelet root = package or class name and links it into the tree. It does this recursively. */ static void -add_namelet (name, name_limit, parent) - const unsigned char *name, *name_limit; - struct namelet *parent; +add_namelet (const unsigned char *name, const unsigned char *name_limit, + struct namelet *parent) { const unsigned char *p; struct namelet *n = NULL, *np; @@ -1475,7 +1819,7 @@ add_namelet (name, name_limit, parent) return; } - for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p) + for (p = name; p < name_limit && *p != '/'; ++p) ; /* Search for this name beneath the PARENT node. */ @@ -1492,11 +1836,11 @@ add_namelet (name, name_limit, parent) if (n == NULL) { - n = (struct namelet *) xmalloc (sizeof (struct namelet)); + n = 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 == '$'); + n->is_class = (p == name_limit); n->subnamelets = NULL; n->next = parent->subnamelets; parent->subnamelets = n; @@ -1504,16 +1848,13 @@ add_namelet (name, name_limit, parent) /* We recurse if there is more text, and if the trailing piece does not represent an inner class. */ - if (p < name_limit && *p != '$') + if (p < name_limit) add_namelet (p + 1, name_limit, n); } /* Print a single namelet. Destroys namelets while printing. */ static void -print_namelet (out, name, depth) - FILE *out; - struct namelet *name; - int depth; +print_namelet (FILE *out, struct namelet *name, int depth) { int i, term = 0; struct namelet *c; @@ -1543,6 +1884,7 @@ print_namelet (out, name, depth) print_namelet (out, c, depth + 2); c = next; } + name->subnamelets = NULL; if (name->name) { @@ -1565,22 +1907,15 @@ print_namelet (out, name, depth) we need decls. The signature argument can be a function signature. */ static void -add_class_decl (out, jcf, signature) - FILE *out; - JCF *jcf; - JCF_u2 signature; +add_class_decl (FILE *out, JCF *jcf, JCF_u2 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); - const char *tname = JPOOL_UTF_DATA (jcf, name_index); for (i = 0; i < len; ++i) { - int start, saw_dollar; + int start; /* If we see an array, then we include the array header. */ if (s[i] == '[') @@ -1594,26 +1929,10 @@ add_class_decl (out, jcf, signature) if (s[i] != 'L') continue; - saw_dollar = 0; for (start = ++i; i < len && s[i] != ';'; ++i) - { - if (! saw_dollar && s[i] == '$' && out) - { - saw_dollar = 1; - /* If this class represents an inner class, then - generate a `#include' for the outer class. However, - don't generate the include if the outer class is the - class we are processing. */ - if (i - start < tlen || strncmp (&s[start], tname, i - start)) - print_include (out, &s[start], i - start); - break; - } - } + ; - /* If we saw an inner class, then the generated #include will - declare the class. So in this case we needn't bother. */ - if (! saw_dollar) - add_namelet (&s[start], &s[i], &root); + add_namelet (&s[start], &s[i], &root); } } @@ -1622,10 +1941,7 @@ add_class_decl (out, jcf, signature) statically in libjava; we don't generate declarations for these. This makes the generated headers a bit easier to read. */ static void -print_class_decls (out, jcf, self) - FILE *out; - JCF *jcf; - int self; +print_class_decls (FILE *out, JCF *jcf, int self) { /* Make sure to always add the current class to the list of things that should be declared. */ @@ -1643,15 +1959,14 @@ print_class_decls (out, jcf, self) /* We use an initial offset of 0 because the root namelet doesn't cause anything to print. */ print_namelet (out, &root, 0); - fputs ("};\n\n", out); + fputs ("}\n\n", out); } } static void -DEFUN(process_file, (jcf, out), - JCF *jcf AND FILE *out) +process_file (JCF *jcf, FILE *out) { int code, i; uint32 field_start, method_end, method_start; @@ -1662,8 +1977,7 @@ DEFUN(process_file, (jcf, out), if (jcf_parse_preamble (jcf) != 0) { - fprintf (stderr, "Not a valid Java .class file.\n"); - found_error = 1; + error ("Not a valid Java .class file."); return; } @@ -1671,15 +1985,13 @@ DEFUN(process_file, (jcf, out), code = jcf_parse_constant_pool (jcf); if (code != 0) { - fprintf (stderr, "error while parsing constant pool\n"); - found_error = 1; + error ("error while parsing constant pool"); return; } code = verify_constant_pool (jcf); if (code > 0) { - fprintf (stderr, "error in constant pool entry #%d\n", code); - found_error = 1; + error ("error in constant pool entry #%d", code); return; } @@ -1770,11 +2082,24 @@ DEFUN(process_file, (jcf, out), { /* Strip off the ".class" portion of the name when printing the include file name. */ - int len = strlen (jcf->classname); + char *name; + int i, 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); + /* Turn the class name into a file name. */ + name = xmalloc (len + 1); + for (i = 0; i < len; ++i) + name[i] = jcf->classname[i] == '.' ? '/' : jcf->classname[i]; + name[i] = '\0'; + print_include (out, name, len); + free (name); + + if (! flag_jni) + { + print_include (out, "gcj/cni", -1); + print_include (out, "java/lang/UnsupportedOperationException", + -1); + } } } @@ -1806,19 +2131,18 @@ DEFUN(process_file, (jcf, out), if (! stubs) { - if (! print_cxx_classname (out, "class ", jcf, jcf->this_class)) + if (! print_cxx_classname (out, "class ", jcf, + jcf->this_class, 0)) { - fprintf (stderr, "class is of array type\n"); - found_error = 1; + error ("class is of array type\n"); return; } if (jcf->super_class) { if (! print_cxx_classname (out, " : public ", - jcf, jcf->super_class)) + jcf, jcf->super_class, 1)) { - fprintf (stderr, "base class is of array type\n"); - found_error = 1; + error ("base class is of array type"); return; } } @@ -1828,6 +2152,8 @@ DEFUN(process_file, (jcf, out), } /* Now go back for second pass over methods and fields. */ + is_first_data_member = 1; + JCF_SEEK (jcf, method_start); method_pass = 1; jcf_parse_methods (jcf); @@ -1844,9 +2170,9 @@ DEFUN(process_file, (jcf, out), { if (flag_jni) { - fprintf (out, "\n#ifdef __cplusplus\n"); - fprintf (out, "}\n"); - fprintf (out, "#endif\n"); + fprintf (out, "\n#ifdef __cplusplus\n"); + fprintf (out, "}\n"); + fprintf (out, "#endif\n"); } else { @@ -1860,8 +2186,16 @@ DEFUN(process_file, (jcf, out), for (i = 0; i < add_count; ++i) fprintf (out, " %s\n", add_specs[i]); - if (! stubs) - fputs ("};\n", out); + /* Generate an entry for the class object. */ + generate_access (out, ACC_PUBLIC); + fprintf (out, "\n static ::java::lang::Class class$;\n"); + + fputs ("}", out); + + if (jcf->access_flags & ACC_INTERFACE) + fputs (" __attribute__ ((java_interface))", out); + + fputs (";\n", out); if (append_count > 0) fputc ('\n', out); @@ -1880,100 +2214,104 @@ DEFUN(process_file, (jcf, out), /* 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[] = +#define OPT_classpath LONG_OPT (0) +#define OPT_CLASSPATH OPT_classpath +#define OPT_bootclasspath LONG_OPT (1) +#define OPT_extdirs LONG_OPT (2) +#define OPT_HELP LONG_OPT (3) +#define OPT_TEMP LONG_OPT (4) +#define OPT_VERSION LONG_OPT (5) +#define OPT_PREPEND LONG_OPT (6) +#define OPT_FRIEND LONG_OPT (7) +#define OPT_ADD LONG_OPT (8) +#define OPT_APPEND LONG_OPT (9) +#define OPT_M LONG_OPT (10) +#define OPT_MM LONG_OPT (11) +#define OPT_MG LONG_OPT (12) +#define OPT_MD LONG_OPT (13) +#define OPT_MMD LONG_OPT (14) + +static const 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 } + { "classpath", required_argument, NULL, OPT_classpath }, + { "bootclasspath", required_argument, NULL, OPT_bootclasspath }, + { "extdirs", required_argument, NULL, OPT_extdirs }, + { "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 () +usage (void) { - fprintf (stderr, "Try `gcjh --help' for more information.\n"); + fprintf (stderr, _("Try `gcjh --help' for more information.\n")); exit (1); } static void -help () +help (void) { - 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 (_("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 (_(" -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 (" -o FILE Set output file name\n"); - printf (" -td DIRECTORY Set temporary directory name\n"); + printf (_(" --classpath PATH Set path to find .class files\n")); + printf (_(" -IDIR Append directory to class path\n")); + printf (_(" --bootclasspath PATH Override built-in class path\n")); + printf (_(" --extdirs PATH Set extensions directory path\n")); + printf (_(" -d DIRECTORY Set output directory name\n")); + printf (_(" -o FILE Set output file name\n")); + printf (_(" -td DIRECTORY Set temporary directory name\n")); printf ("\n"); - printf (" --help Print this help, then exit\n"); - printf (" --version Print version number, then exit\n"); - printf (" -v, --verbose Print extra information while running\n"); + printf (_(" --help Print this help, then exit\n")); + printf (_(" --version Print version number, then exit\n")); + 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"); + printf (_(" -M Print all dependencies to stdout;\n" + " suppress ordinary output\n")); + printf (_(" -MM Print non-system dependencies to stdout;\n" + " 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); + printf (_("For bug reporting instructions, please see:\n" + "%s.\n"), bug_report_url); exit (0); } static void -version () +version (void) { - 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"); + printf ("gcjh (GCC) %s\n\n", version_string); + printf ("Copyright %s 2004 Free Software Foundation, Inc.\n", _("(C)")); + printf (_("This is free software; see the source for copying conditions. There is NO\n" + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n")); exit (0); } int -DEFUN(main, (argc, argv), - int argc AND char** argv) +main (int argc, char** argv) { JCF jcf; int argi; @@ -1981,9 +2319,11 @@ DEFUN(main, (argc, argv), int emit_dependencies = 0, suppress_output = 0; int opt; + gcc_init_libintl (); + if (argc <= 1) { - fprintf (stderr, "gcjh: no classes specified\n"); + error ("no classes specified"); usage (); } @@ -2019,8 +2359,12 @@ DEFUN(main, (argc, argv), jcf_path_classpath_arg (optarg); break; - case OPT_CLASSPATH: - jcf_path_CLASSPATH_arg (optarg); + case OPT_bootclasspath: + jcf_path_bootclasspath_arg (optarg); + break; + + case OPT_extdirs: + jcf_path_extdirs_arg (optarg); break; case OPT_HELP: @@ -2037,25 +2381,25 @@ DEFUN(main, (argc, argv), case OPT_PREPEND: if (prepend_count == 0) - prepend_specs = (char**) ALLOC (argc * sizeof (char*)); + prepend_specs = 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 = 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 = 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 = ALLOC (argc * sizeof (char*)); append_specs[append_count++] = optarg; break; @@ -2072,7 +2416,7 @@ DEFUN(main, (argc, argv), break; case OPT_MG: - fprintf (stderr, "gcjh: `-MG' option is unimplemented\n"); + error ("`-MG' option is unimplemented"); exit (1); case OPT_MD: @@ -2093,15 +2437,15 @@ DEFUN(main, (argc, argv), if (optind == argc) { - fprintf (stderr, "gcjh: no classes specified\n"); + error ("no classes specified"); usage (); } - jcf_path_seal (); + jcf_path_seal (verbose); if (output_file && emit_dependencies) { - fprintf (stderr, "gcjh: can't specify both -o and -MD\n"); + error ("can't specify both -o and -MD"); exit (1); } @@ -2112,17 +2456,17 @@ DEFUN(main, (argc, argv), const char *classfile_name; if (verbose) - fprintf (stderr, "Processing %s\n", classname); + printf (_("Processing %s\n"), classname); if (! output_file) jcf_dependency_reset (); classfile_name = find_class (classname, strlen (classname), &jcf, 0); if (classfile_name == NULL) { - fprintf (stderr, "%s: no such class\n", classname); + error ("%s: no such class", classname); exit (1); } if (verbose) - fprintf (stderr, "Found in %s\n", classfile_name); + printf (_("Found in %s\n"), classfile_name); if (output_file) { if (strcmp (output_file, "-") == 0) @@ -2142,7 +2486,7 @@ DEFUN(main, (argc, argv), { int dir_len = strlen (output_directory); int i, classname_length = strlen (classname); - current_output_file = (char*) ALLOC (dir_len + classname_length + 5); + current_output_file = 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++] = '/';