OSDN Git Service

* boehm.c (set_bit): Improve type safety wrt unsignedness.
[pf3gnuchains/gcc-fork.git] / gcc / java / gjavah.c
index 595e1da..8f53df1 100644 (file)
@@ -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,13 +29,19 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include <math.h>
 
 #include "jcf.h"
 #include "tree.h"
+#include "version.h"
 #include "javaop.h"
 #include "java-tree.h"
 #include "java-opcodes.h"
+#include "ggc.h"
+#include "hashtab.h"
+#include "intl.h"
 
 #include <getopt.h>
 
@@ -45,7 +54,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 = "";
@@ -107,45 +120,51 @@ struct method_name
   int length;
   unsigned char *signature;
   int sig_length;
+  int is_native;
   struct method_name *next;
 };
 
 /* 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));
-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 const 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 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;
@@ -181,77 +200,130 @@ static int method_pass;
 static int method_declared = 0;
 static int method_access = 0;
 static int method_printed = 0;
-#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)        \
-  if (method_pass)                                                           \
-    {                                                                        \
-      decompiled = 0; method_printed = 0;                                    \
-      if (out)                                                               \
-        print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS);         \
-    }                                                                        \
-  else if (flag_jni)                                                         \
-    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) \
+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);        \
+    /* If a synthetic methods have been declared, its attribute aren't \
+       worth reading (and triggering side-effects). We skip them an    \
+       set ATTRIBUTE_COUNT to zero so that they'll be skipped in       \
+       jcf_parse_one_method.  */                                       \
+    if (method_synthetic)                                              \
+      {                                                                        \
+       skip_attribute (jcf, ATTRIBUTE_COUNT);                          \
+       ATTRIBUTE_COUNT = 0;                                            \
+      }                                                                \
+    if (method_pass && !method_synthetic)                              \
+      {                                                                        \
+       if (out)                                                        \
+         print_method_info (out, jcf, NAME, SIGNATURE,                 \
+                            ACCESS_FLAGS);                             \
+      }                                                                        \
+    else if (!method_synthetic)                                                \
+      {                                                                        \
+       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 || stubs ? "\n" : ";\n", out);
+#define HANDLE_END_METHOD()                            \
+  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)
-#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;
+
+  va_start (ap, msgid);
 
-  /* 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;
+  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;
-
-  /* Now check for all NaNs.  */
-  return (u.l & D_NAN_MASK) != D_NAN_MASK;
+  /* 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);
 }
 
+/* Print a double-precision float, suitable for parsing by g++.  */
 static void
-DEFUN(print_name, (stream, jcf, name_index),
-      FILE* stream AND JCF* jcf AND int name_index)
+jni_print_double (FILE *stream, jdouble f)
 {
-  if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
-    fprintf (stream, "<not a UTF8 constant>");
-  else
-    jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
-                   JPOOL_UTF_LENGTH (jcf, name_index));
+  /* 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);
@@ -267,9 +339,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
     {
@@ -278,14 +348,44 @@ jni_print_char (stream, ch)
     }
 }
 
+/* Print a name from the class data.  If the index does not point to a
+   string, an error results.  */
+
+static void
+print_name (FILE* stream, JCF* jcf, int name_index)
+{
+  if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
+    {
+      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
    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;
@@ -312,13 +412,11 @@ print_base_classname (stream, jcf, 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)
-     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;
@@ -327,35 +425,176 @@ utf8_cmp (str, length, name)
     {
       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 *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",
+  "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",
+  "typeof",
+  "union",
+  "unsigned",
+  "using",
+  "virtual",
+  "void",
+  "volatile",
+  "wchar_t",
+  "while",
+  "xor",
+  "xor_eq"
+};
+
+
 /* 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.  FIXME: for now, we only handle those
-   keywords we know to be a problem for libgcj.  */
+   Otherwise, return NULL.  The return value is malloc()d.  */
 
-static const char *
-cxx_keyword_subst (str, length)
-     const unsigned char *str;
-     int length;
+static char *
+cxx_keyword_subst (const unsigned char *str, int length)
 {
-  if (! utf8_cmp (str, length, "delete"))
-    return "__dummy_delete";
-  else if (! utf8_cmp (str, length, "enum"))
-    return "__dummy_enum";
+  int last = ARRAY_SIZE (cxx_keywords);
+  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 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)
+       {
+         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;
+       }
+       
+      if (r < 0)
+       last = mid;
+      else
+       first = mid;
+    }
   return NULL;
 }
 
 /* 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;
@@ -385,9 +624,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;
 
@@ -399,20 +636,18 @@ name_is_method_p (name, length)
   return 0;
 }
 
-/* If there is already a method named NAME, whose signature is not
+/* If there is already a native 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;
 
   for (p = method_name_list; p != NULL; p = p->next)
     {
-      if (p->length == length
+      if (p->is_native
+          && p->length == length
          && ! memcmp (p->name, name, length)
          && (p->sig_length != sig_length
              || memcmp (p->signature, signature, sig_length)))
@@ -423,16 +658,11 @@ 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);
   char *override;
-  const char *tmpconstptr;
-
 
   if (name_is_method_p (name, length))
     {
@@ -442,8 +672,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;
        }
 
@@ -451,25 +680,16 @@ get_field_name (jcf, name_index, flags)
       memcpy (override, name, length);
       strcpy (override + length, "__");
     }
-  else if ((tmpconstptr = cxx_keyword_subst (name, length)) != NULL)
-    {
-      /* Must malloc OVERRIDE.  */
-      override = xstrdup (tmpconstptr);
-    }
   else
-    override = NULL;
-  
+    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;
+print_field_name (FILE *stream, JCF *jcf, int name_index, JCF_u2 flags)
 {
   char *override = get_field_name (jcf, name_index, flags);
 
@@ -484,9 +704,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;
 
@@ -500,11 +719,10 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
 
   fputs ("  ", out);
   if ((flags & ACC_STATIC))
-    fputs ("static ", out);
-
-  if ((flags & ACC_FINAL))
     {
-      if (current_field_value > 0)
+      fputs ("static ", out);
+
+      if ((flags & ACC_FINAL) && current_field_value > 0)
        {
          char buffer[25];
          int done = 1;
@@ -554,10 +772,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:
@@ -565,10 +780,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:
@@ -591,14 +803,14 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
     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)
+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;
-  const char *override = NULL;
+  char *override = NULL;
 
   method_declared = 0;
   method_access = flags;
@@ -606,10 +818,11 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
     fprintf (stream, "<not a UTF8 constant>");
   str = JPOOL_UTF_DATA (jcf, name_index);
   length = JPOOL_UTF_LENGTH (jcf, name_index);
-  if (str[0] == '<' || str[0] == '$')
+
+  if (str[0] == '<')
     {
-      /* Ignore internally generated methods like <clinit> and
-        $finit$.  However, treat <init> as a constructor.  */
+      /* Ignore the internally generated method <clinit>. However,
+         treat <init> as a constructor.  */
       if (! utf8_cmp (str, length, "<init>"))
        is_init = 1;
       else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
@@ -617,51 +830,47 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
        {
          /* 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;
        }
       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 *) 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);
+      nn->is_native = METHOD_IS_NATIVE (flags);
       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;
     }
 
-  /* 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
-     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)
+  /* 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;
+      /* 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 (! stubs && ! flag_jni)
@@ -695,15 +904,140 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
                             is_init, override, flags);
        }
     }
+
+  if (override)
+    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;
@@ -723,23 +1057,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);
-      print_name (out, jcf, name);
-      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)
@@ -759,13 +1102,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 = (unsigned char *) xstrdup ("java.lang.Throwable");
+      slot = htab_find_slot (throw_hash, str, INSERT);
+      *slot = str;
+
+      str = (unsigned char *) 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 ((char *) current, strlen ((const char *) 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;
@@ -777,8 +1225,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)
        {
@@ -844,7 +1291,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;
@@ -873,24 +1320,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.  */
-         if (! strncmp (signature, "Ljava/lang/String;",
+         /* We know about certain types and special-case their names.  */
+         if (! strncmp ((const char *) signature, "Ljava/lang/String;",
                         sizeof ("Ljava/lang/String;") -1))
            ctype = "jstring";
-         else if (! strncmp (signature, "Ljava/lang/Class;",
+         else if (! strncmp ((const char *) 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";
 
@@ -905,8 +1344,7 @@ decode_signature_piece (stream, signature, limit, need_space)
       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);
@@ -937,11 +1375,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)
     {
@@ -952,7 +1387,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] == '(';
@@ -978,12 +1413,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 alignment 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);
@@ -995,15 +1440,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] == '(';
@@ -1026,7 +1469,7 @@ DEFUN(print_full_cxx_name, (stream, jcf, name_index, 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))
+                                         (const char *) signature, sig_len))
        {
          /* If this method is overloaded by another native method,
             then include the argument information in the mangled
@@ -1072,8 +1515,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;
            }
          
@@ -1088,14 +1530,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_" : "\n";
-  print_cxx_classname (stream, prefix, jcf, jcf->this_class);
+  const char *const prefix = flag_jni ? "Java_" : "";
+  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,
@@ -1103,11 +1543,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)
     {
@@ -1118,7 +1556,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] == '(';
@@ -1129,7 +1567,7 @@ DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init,
        return;
 
       if (flag_jni && ! stubs)
-       fputs ("extern ", stream);
+       fputs ("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
@@ -1152,17 +1590,18 @@ 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;
            }
        }
 
       /* 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);
+      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,
                                  signature_index, is_init, name_override,
@@ -1172,21 +1611,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);
@@ -1200,11 +1639,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;
@@ -1223,7 +1659,7 @@ print_cxx_classname (stream, prefix, jcf, index)
   fputs (prefix, stream);
 
   /* Print a leading "::" so we look in the right namespace.  */
-  if (! flag_jni)
+  if (! flag_jni && ! stubs && add_scope)
     fputs ("::", stream);
 
   while (s < limit)
@@ -1243,9 +1679,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);
@@ -1258,6 +1692,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");
+       }
+    }
+}
+
 \f
 
 /* We keep track of all the `#include's we generate, so we can avoid
@@ -1273,10 +1735,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;
 
@@ -1284,19 +1743,19 @@ print_include (out, utf8, len)
     return;
 
   if (len == -1)
-    len = strlen (utf8);
+    len = strlen ((const char *) utf8);
 
   for (incl = all_includes; incl; incl = incl->next)
     {
       /* We check the length because we might have a proper prefix.  */
       if (len == (int) strlen (incl->name)
-         && ! strncmp (incl->name, utf8, len))
+         && ! strncmp (incl->name, (const char *) 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);
+  strncpy (incl->name, (const char *) utf8, len);
   incl->name[len] = '\0';
   incl->next = all_includes;
   all_includes = incl;
@@ -1323,9 +1782,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 =
@@ -1340,9 +1799,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;
@@ -1356,15 +1814,15 @@ add_namelet (name, name_limit, parent)
 #define JAVAIO "java/io/"
 #define JAVAUTIL "java/util/"
       if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
-          && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
+          && ! strncmp ((const char *) name, JAVALANG, sizeof (JAVALANG) - 1))
          || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
-             && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
+             && ! strncmp ((const char *) name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
          || (name_limit - name >= (int) sizeof (JAVAIO) - 1
-             && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
+             && ! strncmp ((const char *) name, JAVAIO, sizeof (JAVAIO) - 1)))
        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.  */
@@ -1372,7 +1830,7 @@ add_namelet (name, name_limit, parent)
     {
       /* We check the length because we might have a proper prefix.  */
       if ((int) strlen (np->name) == p - name &&
-         ! strncmp (name, np->name, p - name))
+         ! strncmp ((const char *) name, np->name, p - name))
        {
          n = np;
          break;
@@ -1381,11 +1839,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);
+      strncpy (n->name, (const char *) 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;
@@ -1393,16 +1851,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;
@@ -1432,6 +1887,7 @@ print_namelet (out, name, depth)
       print_namelet (out, c, depth + 2);
       c = next;
     }
+  name->subnamelets = NULL;
 
   if (name->name)
     {
@@ -1454,27 +1910,20 @@ 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] == '[')
        {
-         print_include (out, "gcj/array", -1);
+         print_include (out, (const unsigned char *) "gcj/array", -1);
          continue;
        }
 
@@ -1483,26 +1932,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);
     }
 }
 
@@ -1511,10 +1944,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.  */
@@ -1532,15 +1962,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);
     }
 }
 
 \f
 
 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;
@@ -1551,8 +1980,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;
     }
 
@@ -1560,15 +1988,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;
     }
 
@@ -1659,10 +2085,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);
+         /* 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, (const unsigned char *) name, len);
+         free (name);
+
+         if (! flag_jni)
+           {
+             print_include (out, (const unsigned char *) "gcj/cni", -1);
+             print_include (out, (const unsigned char *) "java/lang/UnsupportedOperationException",
+                            -1);
+           }
        }
     }
 
@@ -1694,19 +2134,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;
                }
            }
@@ -1716,6 +2155,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);
@@ -1732,9 +2173,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
        {
@@ -1748,8 +2189,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);
@@ -1768,100 +2217,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 ("<URL:http://www.gnu.org/software/gcc/faq.html#bugreport>.\n");
+  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;
@@ -1869,9 +2322,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 ();
     }
 
@@ -1907,8 +2362,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:
@@ -1925,25 +2384,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;
 
@@ -1960,7 +2419,7 @@ DEFUN(main, (argc, argv),
          break;
 
        case OPT_MG:
-         fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
+         error ("`-MG' option is unimplemented");
          exit (1);
 
        case OPT_MD:
@@ -1981,15 +2440,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);
     }
 
@@ -2000,17 +2459,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)
@@ -2030,7 +2489,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++] = '/';