OSDN Git Service

More for PR java/5365:
[pf3gnuchains/gcc-fork.git] / gcc / java / gjavah.c
1 /* Program to write C++-suitable header files from a Java(TM) .class
2    file.  This is similar to SUN's javah.
3
4 Copyright (C) 1996, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  
20
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
24
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
26
27 #include "config.h"
28 #include "system.h"
29 #include <math.h>
30
31 #include "jcf.h"
32 #include "tree.h"
33 #include "javaop.h"
34 #include "java-tree.h"
35 #include "java-opcodes.h"
36
37 #include <getopt.h>
38
39 \f
40
41 /* The output file.  */
42 FILE *out = NULL;
43
44 /* Nonzero on failure.  */
45 static int found_error = 0;
46
47 /* Nonzero if we're generating JNI output.  */
48 static int flag_jni = 0;
49
50 /* When non zero, warn when source file is newer than matching class
51    file.  */
52 int flag_newer = 1;
53
54 /* Directory to place resulting files in. Set by -d option. */
55 const char *output_directory = "";
56
57 /* Directory to place temporary file.  Set by -td option.  Currently unused. */
58 const char *temp_directory = "/tmp";
59
60 /* Number of friend functions we have to declare.  */
61 static int friend_count;
62
63 /* A class can optionally have a `friend' function declared.  If
64    non-NULL, this is that function.  */
65 static char **friend_specs = NULL;
66
67 /* Number of lines we are prepending before the class.  */
68 static int prepend_count;
69
70 /* We can prepend extra lines before the class's start. */
71 static char **prepend_specs = NULL;
72
73 /* Number of lines we are appending at the end of the class.  */
74 static int add_count;
75
76 /* We can append extra lines just before the class's end. */
77 static char **add_specs = NULL;
78
79 /* Number of lines we are appending after the class.  */
80 static int append_count;
81
82 /* We can append extra lines after the class's end. */
83 static char **append_specs = NULL;
84
85 int verbose = 0;
86
87 int stubs = 0;
88
89 struct JCF *current_jcf;
90
91 /* This holds access information for the last field we examined.  They
92    let us generate "private:", "public:", and "protected:" properly.
93    If 0 then we haven't previously examined any field.  */
94 static JCF_u2 last_access;
95
96 /* Pass this macro the flags for a class and for a method.  It will
97    return true if the method should be considered `final'.  */
98 #define METHOD_IS_FINAL(Class, Method) \
99    (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
100
101 /* Pass this macro the flags for a method.  It will return true if the
102    method is native.  */
103 #define METHOD_IS_NATIVE(Method) \
104    ((Method) & ACC_NATIVE)
105
106 /* We keep a linked list of all method names we have seen.  This lets
107    us determine if a method name and a field name are in conflict.  */
108 struct method_name
109 {
110   unsigned char *name;
111   int length;
112   unsigned char *signature;
113   int sig_length;
114   struct method_name *next;
115 };
116
117 /* List of method names we've seen.  */
118 static struct method_name *method_name_list;
119
120 static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
121 static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int));
122 static int  print_cxx_classname PARAMS ((FILE*, const char*, JCF*, int));
123 static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
124 static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *,
125                                   int));
126 static void print_stub_or_jni PARAMS ((FILE*, JCF*, int, int, int,
127                                        const char *, int));
128 static void print_full_cxx_name PARAMS ((FILE*, JCF*, int, int, int,
129                                          const char *, int));
130 static void decompile_method PARAMS ((FILE*, JCF*, int));
131 static void add_class_decl PARAMS ((FILE*, JCF*, JCF_u2));
132
133 static int java_float_finite PARAMS ((jfloat));
134 static int java_double_finite PARAMS ((jdouble));
135 static void print_name PARAMS ((FILE *, JCF *, int));
136 static void print_base_classname PARAMS ((FILE *, JCF *, int));
137 static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
138 static char *cxx_keyword_subst PARAMS ((const unsigned char *, int));
139 static void generate_access PARAMS ((FILE *, JCF_u2));
140 static int name_is_method_p PARAMS ((const unsigned char *, int));
141 static char *get_field_name PARAMS ((JCF *, int, JCF_u2));
142 static void print_field_name PARAMS ((FILE *, JCF *, int, JCF_u2));
143 static const unsigned char *super_class_name PARAMS ((JCF *, int *));
144 static void print_include PARAMS ((FILE *, const unsigned char *, int));
145 static const unsigned char *decode_signature_piece
146   PARAMS ((FILE *, const unsigned char *, const unsigned char *, int *));
147 static void print_class_decls PARAMS ((FILE *, JCF *, int));
148 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
149 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
150 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
151 static int overloaded_jni_method_exists_p PARAMS ((const unsigned char *, int,
152                                                    const char *, int));
153 static void jni_print_char PARAMS ((FILE *, int));
154 static void decompile_return_statement PARAMS ((FILE *, JCF *, int, int, int));
155
156 JCF_u2 current_field_name;
157 JCF_u2 current_field_value;
158 JCF_u2 current_field_signature;
159 JCF_u2 current_field_flags;
160
161 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
162 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
163   current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
164
165 /* We pass over fields twice.  The first time we just note the types
166    of the fields and then the start of the methods.  Then we go back
167    and parse the fields for real.  This is ugly.  */
168 static int field_pass;
169 /* Likewise we pass over methods twice.  The first time we generate
170    class decl information; the second time we generate actual method
171    decls.  */
172 static int method_pass;
173
174 #define HANDLE_END_FIELD()                                                    \
175   if (field_pass)                                                             \
176     {                                                                         \
177       if (out && ! stubs && ! flag_jni)                                       \
178         print_field_info (out, jcf, current_field_name,                       \
179                           current_field_signature,                            \
180                           current_field_flags);                               \
181     }                                                                         \
182   else if (! stubs && ! flag_jni)                                             \
183     add_class_decl (out, jcf, current_field_signature);
184
185 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
186
187 static int method_declared = 0;
188 static int method_access = 0;
189 static int method_printed = 0;
190 static int method_synthetic = 0;
191 static int method_signature = 0;
192
193 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)   \
194   {                                                                     \
195     method_synthetic = 0;                                               \
196     method_printed = 0;                                                 \
197     decompiled = 0;                                                     \
198     method_signature = SIGNATURE;                                       \
199     if (ATTRIBUTE_COUNT)                                                \
200       method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT,          \
201                                   (const char *)"Synthetic", 9);        \
202     /* If a synthetic methods have been declared, its attribute aren't  \
203        worth reading (and triggering side-effects). We skip them an     \
204        set ATTRIBUTE_COUNT to zero so that they'll be skipped in        \
205        jcf_parse_one_method.  */                                        \
206     if (method_synthetic)                                               \
207       {                                                                 \
208         skip_attribute (jcf, ATTRIBUTE_COUNT);                          \
209         ATTRIBUTE_COUNT = 0;                                            \
210       }                                                                 \
211     if (method_pass && !method_synthetic)                               \
212       {                                                                 \
213         if (out)                                                        \
214           print_method_info (out, jcf, NAME, SIGNATURE,                 \
215                              ACCESS_FLAGS);                             \
216       }                                                                 \
217     else if (!method_synthetic)                                         \
218       {                                                                 \
219         print_method_info (NULL, jcf, NAME, SIGNATURE,                  \
220                            ACCESS_FLAGS);                               \
221         if (! stubs && ! flag_jni)                                      \
222           add_class_decl (out, jcf, SIGNATURE);                         \
223       }                                                                 \
224   }
225
226 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH)       \
227   if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
228
229 static int decompiled = 0;
230 #define HANDLE_END_METHOD()                             \
231   if (out && method_printed && !method_synthetic)       \
232     fputs (decompiled || stubs ? "\n" : ";\n", out);
233
234 /* We're going to need {peek,skip}_attribute, enable their definition.   */
235 #define NEED_PEEK_ATTRIBUTE
236 #define NEED_SKIP_ATTRIBUTE
237
238 #include "jcf-reader.c"
239
240 /* Some useful constants.  */
241 #define F_NAN_MASK 0x7f800000
242 #if (1 == HOST_FLOAT_WORDS_BIG_ENDIAN) && ! defined (HOST_WORDS_BIG_ENDIAN)
243 #define D_NAN_MASK 0x000000007ff00000LL
244 #else
245 #define D_NAN_MASK 0x7ff0000000000000LL
246 #endif
247
248 /* Return 1 if F is not Inf or NaN.  */
249 static int
250 java_float_finite (f)
251      jfloat f;
252 {
253   union Word u;
254   u.f = f;
255
256   /* We happen to know that F_NAN_MASK will match all NaN values, and
257      also positive and negative infinity.  That's why we only need one
258      test here.  See The Java Language Specification, section 20.9.  */
259   return (u.i & F_NAN_MASK) != F_NAN_MASK;
260 }
261
262 /* Return 1 if D is not Inf or NaN.  */
263 static int
264 java_double_finite (d)
265      jdouble d;
266 {
267   union DWord u;
268   u.d = d;
269
270   /* Now check for all NaNs.  */
271   return (u.l & D_NAN_MASK) != D_NAN_MASK;
272 }
273
274 /* Print a character, appropriately mangled for JNI.  */
275
276 static void
277 jni_print_char (stream, ch)
278      FILE *stream;
279      int ch;
280 {
281   if (! flag_jni)
282     jcf_print_char (stream, ch);
283   else if (ch == '(' || ch == ')')
284     {
285       /* Ignore.  */
286     }
287   else if (ch == '_')
288     fputs ("_1", stream);
289   else if (ch == ';')
290     fputs ("_2", stream);
291   else if (ch == '[')
292     fputs ("_3", stream);
293   else if (ch == '/')
294     fputs ("_", stream);
295   else if (ISALNUM (ch))
296     fputc (ch, stream);
297   else
298     {
299       /* "Unicode" character.  */
300       fprintf (stream, "_0%04x", ch);
301     }
302 }
303
304 /* Print a name from the class data.  If the index does not point to a
305    string, an error results.  */
306
307 static void
308 DEFUN(print_name, (stream, jcf, name_index),
309       FILE* stream AND JCF* jcf AND int name_index)
310 {
311   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
312     {
313       fprintf (stream, "<not a UTF8 constant>");
314       found_error = 1;
315     }
316   else if (! flag_jni)
317     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
318                     JPOOL_UTF_LENGTH (jcf, name_index));
319   else
320     {
321       /* For JNI we must correctly quote each character.  */
322       const unsigned char *str = JPOOL_UTF_DATA (jcf, name_index);
323       int length = JPOOL_UTF_LENGTH (jcf, name_index);
324       const unsigned char *limit = str + length;
325       while (str < limit)
326         {
327           int ch = UTF8_GET (str, limit);
328           if (ch < 0)
329             {
330               fprintf (stream, "\\<invalid>");
331               return;
332             }
333           jni_print_char (stream, ch);
334         }
335     }
336 }
337
338 /* Print base name of class.  The base name is everything after the
339    final separator.  */
340
341 static void
342 print_base_classname (stream, jcf, index)
343      FILE *stream;
344      JCF *jcf;
345      int index;
346 {
347   int name_index = JPOOL_USHORT1 (jcf, index);
348   int len;
349   const unsigned char *s, *p, *limit;
350
351   s = JPOOL_UTF_DATA (jcf, name_index);
352   len = JPOOL_UTF_LENGTH (jcf, name_index);
353   limit = s + len;
354   p = s;
355   while (s < limit)
356     {
357       int c = UTF8_GET (s, limit);
358       if (c == '/')
359         p = s;
360     }
361
362   while (p < limit)
363     {
364       int ch = UTF8_GET (p, limit);
365       if (ch == '/')
366         fputs ("::", stream);
367       else
368         jcf_print_char (stream, ch);
369     }
370 }
371
372 /* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
373    and 1 if STR is "greater" than NAME.  */
374
375 static int
376 utf8_cmp (str, length, name)
377      const unsigned char *str;
378      int length;
379      const char *name;
380 {
381   const unsigned char *limit = str + length;
382   int i;
383
384   for (i = 0; name[i]; ++i)
385     {
386       int ch = UTF8_GET (str, limit);
387       if (ch != name[i])
388         return ch - name[i];
389     }
390
391   return str == limit ? 0 : 1;
392 }
393
394 /* This is a sorted list of all C++ keywords.  */
395
396 static const char *const cxx_keywords[] =
397 {
398   "_Complex",
399   "__alignof",
400   "__alignof__",
401   "__asm",
402   "__asm__",
403   "__attribute",
404   "__attribute__",
405   "__builtin_va_arg",
406   "__complex",
407   "__complex__",
408   "__const",
409   "__const__",
410   "__extension__",
411   "__imag",
412   "__imag__",
413   "__inline",
414   "__inline__",
415   "__label__",
416   "__null",
417   "__real",
418   "__real__",
419   "__restrict",
420   "__restrict__",
421   "__signed",
422   "__signed__",
423   "__typeof",
424   "__typeof__",
425   "__volatile",
426   "__volatile__",
427   "and",
428   "and_eq",
429   "asm",
430   "auto",
431   "bitand",
432   "bitor",
433   "bool",
434   "break",
435   "case",
436   "catch",
437   "char",
438   "class",
439   "compl",
440   "const",
441   "const_cast",
442   "continue",
443   "default",
444   "delete",
445   "do",
446   "double",
447   "dynamic_cast",
448   "else",
449   "enum",
450   "explicit",
451   "export",
452   "extern",
453   "false",
454   "float",
455   "for",
456   "friend",
457   "goto",
458   "if",
459   "inline",
460   "int",
461   "long",
462   "mutable",
463   "namespace",
464   "new",
465   "not",
466   "not_eq",
467   "operator",
468   "or",
469   "or_eq",
470   "private",
471   "protected",
472   "public",
473   "register",
474   "reinterpret_cast",
475   "return",
476   "short",
477   "signed",
478   "sizeof",
479   "static",
480   "static_cast",
481   "struct",
482   "switch",
483   "template",
484   "this",      
485   "throw",
486   "true",
487   "try",
488   "typedef",
489   "typeid",
490   "typename",
491   "typeof",
492   "union",
493   "unsigned",
494   "using",
495   "virtual",
496   "void",
497   "volatile",
498   "wchar_t",
499   "while",
500   "xor",
501   "xor_eq"
502 };
503
504
505 /* If NAME is the name of a C++ keyword, then return an override name.
506    This is a name that can be used in place of the keyword.
507    Otherwise, return NULL.  The return value is malloc()d.  */
508
509 static char *
510 cxx_keyword_subst (str, length)
511      const unsigned char *str;
512      int length;
513 {
514   int last = ARRAY_SIZE (cxx_keywords);
515   int first = 0;
516   int mid = (last + first) / 2;
517   int old = -1;
518
519   for (mid = (last + first) / 2;
520        mid != old;
521        old = mid, mid = (last + first) / 2)
522     {
523       int kwl = strlen (cxx_keywords[mid]);
524       int min_length = kwl > length ? length : kwl;
525       int r = utf8_cmp (str, min_length, cxx_keywords[mid]);
526
527       if (r == 0)
528         {
529           int i;
530
531           /* Skip all trailing `$'.  */
532           for (i = min_length; i < length && str[i] == '$'; ++i)
533             ;
534           /* We've only found a match if all the remaining characters
535              are `$'.  */
536           if (i == length)
537             {
538               char *dup = xmalloc (2 + length - min_length + kwl);
539               strcpy (dup, cxx_keywords[mid]);
540               for (i = kwl; i < length + 1; ++i)
541                 dup[i] = '$';
542               dup[i] = '\0';
543               return dup;
544             }
545           r = 1;
546         }
547         
548       if (r < 0)
549         last = mid;
550       else
551         first = mid;
552     }
553   return NULL;
554 }
555
556 /* Generate an access control keyword based on FLAGS.  */
557
558 static void
559 generate_access (stream, flags)
560      FILE *stream;
561      JCF_u2 flags;
562 {
563   if ((flags & ACC_VISIBILITY) == last_access)
564     return;
565   last_access = (flags & ACC_VISIBILITY);
566
567   switch (last_access)
568     {
569     case 0:
570       fputs ("public: // actually package-private\n", stream);
571       break;
572     case ACC_PUBLIC:
573       fputs ("public:\n", stream);
574       break;
575     case ACC_PRIVATE:
576       fputs ("private:\n", stream);
577       break;
578     case ACC_PROTECTED:
579       fputs ("public:  // actually protected\n", stream);
580       break;
581     default:
582       found_error = 1;
583       fprintf (stream, "#error unrecognized visibility %d\n",
584                (flags & ACC_VISIBILITY));
585       break;
586     }
587 }
588
589 /* See if NAME is already the name of a method.  */
590 static int
591 name_is_method_p (name, length)
592      const unsigned char *name;
593      int length;
594 {
595   struct method_name *p;
596
597   for (p = method_name_list; p != NULL; p = p->next)
598     {
599       if (p->length == length && ! memcmp (p->name, name, length))
600         return 1;
601     }
602   return 0;
603 }
604
605 /* If there is already a method named NAME, whose signature is not
606    SIGNATURE, then return true.  Otherwise return false.  */
607 static int
608 overloaded_jni_method_exists_p (name, length, signature, sig_length)
609      const unsigned char *name;
610      int length;
611      const char *signature;
612      int sig_length;
613 {
614   struct method_name *p;
615
616   for (p = method_name_list; p != NULL; p = p->next)
617     {
618       if (p->length == length
619           && ! memcmp (p->name, name, length)
620           && (p->sig_length != sig_length
621               || memcmp (p->signature, signature, sig_length)))
622         return 1;
623     }
624   return 0;
625 }
626
627 /* Get name of a field.  This handles renamings due to C++ clash.  */
628 static char *
629 get_field_name (jcf, name_index, flags)
630      JCF *jcf;
631      int name_index;
632      JCF_u2 flags;
633 {
634   unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
635   int length = JPOOL_UTF_LENGTH (jcf, name_index);
636   char *override;
637
638   if (name_is_method_p (name, length))
639     {
640       /* This field name matches a method.  So override the name with
641          a dummy name.  This is yucky, but it isn't clear what else to
642          do.  FIXME: if the field is static, then we'll be in real
643          trouble.  */
644       if ((flags & ACC_STATIC))
645         {
646           fprintf (stderr, "static field has same name as method\n");
647           found_error = 1;
648           return NULL;
649         }
650
651       override = xmalloc (length + 3);
652       memcpy (override, name, length);
653       strcpy (override + length, "__");
654     }
655   else
656     override = cxx_keyword_subst (name, length);
657
658   return override;
659 }
660
661 /* Print a field name.  Convenience function for use with
662    get_field_name.  */
663 static void
664 print_field_name (stream, jcf, name_index, flags)
665      FILE *stream;
666      JCF *jcf;
667      int name_index;
668      JCF_u2 flags;
669 {
670   char *override = get_field_name (jcf, name_index, flags);
671
672   if (override)
673     {
674       fputs (override, stream);
675       free (override);
676     }
677   else
678     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
679                     JPOOL_UTF_LENGTH (jcf, name_index));
680 }
681
682 static void
683 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
684       FILE *stream AND JCF* jcf
685       AND int name_index AND int sig_index AND JCF_u2 flags)
686 {
687   char *override = NULL;
688
689   generate_access (stream, flags);
690   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
691     {
692       fprintf (stream, "<not a UTF8 constant>");
693       found_error = 1;
694       return;
695     }
696
697   fputs ("  ", out);
698   if ((flags & ACC_STATIC))
699     fputs ("static ", out);
700
701   if ((flags & ACC_FINAL))
702     {
703       if (current_field_value > 0)
704         {
705           char buffer[25];
706           int done = 1;
707
708           switch (JPOOL_TAG (jcf, current_field_value))
709             {
710             case CONSTANT_Integer:
711               {
712                 jint num;
713                 int most_negative = 0;
714                 fputs ("const jint ", out);
715                 print_field_name (out, jcf, name_index, 0);
716                 fputs (" = ", out);
717                 num = JPOOL_INT (jcf, current_field_value);
718                 /* We single out the most negative number to print
719                    specially.  This avoids later warnings from g++.  */
720                 if (num == (jint) 0x80000000)
721                   {
722                     most_negative = 1;
723                     ++num;
724                   }
725                 format_int (buffer, (jlong) num, 10);
726                 fprintf (out, "%sL%s;\n", buffer, most_negative ? " - 1" : "");
727               }
728               break;
729             case CONSTANT_Long:
730               {
731                 jlong num;
732                 int most_negative = 0;
733                 fputs ("const jlong ", out);
734                 print_field_name (out, jcf, name_index, 0);
735                 fputs (" = ", out);
736                 num = JPOOL_LONG (jcf, current_field_value);
737                 /* We single out the most negative number to print
738                    specially..  This avoids later warnings from g++.  */
739                 if (num == (jlong) 0x8000000000000000LL)
740                   {
741                     most_negative = 1;
742                     ++num;
743                   }
744                 format_int (buffer, num, 10);
745                 fprintf (out, "%sLL%s;\n", buffer, most_negative ? " - 1" :"");
746               }
747               break;
748             case CONSTANT_Float:
749               {
750                 jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
751                 fputs ("const jfloat ", out);
752                 print_field_name (out, jcf, name_index, 0);
753                 if (! java_float_finite (fnum))
754                   fputs (";\n", out);
755                 else
756                   fprintf (out, " = %.10g;\n",  fnum);
757               }
758               break;
759             case CONSTANT_Double:
760               {
761                 jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
762                 fputs ("const jdouble ", out);
763                 print_field_name (out, jcf, name_index, 0);
764                 if (! java_double_finite (dnum))
765                   fputs (";\n", out);
766                 else
767                   fprintf (out, " = %.17g;\n",  dnum);
768               }
769               break;
770             default:
771               /* We can't print this as a constant, but we can still
772                  print something sensible.  */
773               done = 0;
774               break;
775             }
776
777           if (done)
778             return;
779         }
780     }
781
782   override = get_field_name (jcf, name_index, flags);
783   print_c_decl (out, jcf, name_index, sig_index, 0, override, flags);
784   fputs (";\n", out);
785
786   if (override)
787     free (override);
788 }
789
790
791 static void
792 DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
793       FILE *stream AND JCF* jcf
794       AND int name_index AND int sig_index AND JCF_u2 flags)
795 {
796   const unsigned char *str;
797   int length, is_init = 0;
798   char *override = NULL;
799
800   method_declared = 0;
801   method_access = flags;
802   if (stream && JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
803     fprintf (stream, "<not a UTF8 constant>");
804   str = JPOOL_UTF_DATA (jcf, name_index);
805   length = JPOOL_UTF_LENGTH (jcf, name_index);
806
807   if (str[0] == '<')
808     {
809       /* Ignore the internally generated method <clinit>. However,
810          treat <init> as a constructor.  */
811       if (! utf8_cmp (str, length, "<init>"))
812         is_init = 1;
813       else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
814                && ! (flags & ACC_STATIC))
815         {
816           /* FIXME: i18n bug here.  Order of prints should not be
817              fixed.  */
818           fprintf (stderr, "ignored method `");
819           jcf_print_utf8 (stderr, str, length);
820           fprintf (stderr, "' marked virtual\n");
821           found_error = 1;
822           return;
823         }
824       else
825         return;
826     }
827
828   /* During the first method pass, build a list of method names. This will
829   be used to determine if field names conflict with method names. */
830   if (! stream)
831     {
832       struct method_name *nn;
833
834       nn = (struct method_name *) xmalloc (sizeof (struct method_name));
835       nn->name = (char *) xmalloc (length);
836       memcpy (nn->name, str, length);
837       nn->length = length;
838       nn->next = method_name_list;
839       nn->sig_length = JPOOL_UTF_LENGTH (jcf, sig_index);
840       nn->signature = (char *) xmalloc (nn->sig_length);
841       memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index),
842               nn->sig_length);
843       method_name_list = nn;
844       
845       /* The rest of this function doesn't matter. */
846       return;
847     }
848
849   /* We don't worry about overrides in JNI mode.  */
850   if (! flag_jni)
851     {
852       /* We can't generate a method whose name is a C++ reserved word.
853          We can't just ignore the function, because that will cause
854          incorrect code to be generated if the function is virtual
855          (not only for calls to this function for for other functions
856          after it in the vtbl).  So we give it a dummy name instead.  */
857       override = cxx_keyword_subst (str, length);
858     }
859
860   if (! stubs && ! flag_jni)
861     {
862       method_printed = 1;
863
864       generate_access (stream, flags);
865       
866       fputs ("  ", out);
867       if ((flags & ACC_STATIC))
868         fputs ("static ", out);
869       else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
870         {
871           /* Don't print `virtual' if we have a constructor.  */
872           if (! is_init)
873             fputs ("virtual ", out);
874         }
875       print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
876       
877       if ((flags & ACC_ABSTRACT))
878         fputs (" = 0", out);
879       else
880         method_declared = 1;
881     }
882   else
883     {
884       if (METHOD_IS_NATIVE (flags)) 
885         {
886           method_printed = 1;
887           print_stub_or_jni (out, jcf, name_index, sig_index,
888                              is_init, override, flags);
889         }
890     }
891
892   if (override)
893     free (override);
894 }
895
896 /* A helper for the decompiler which prints a `return' statement where
897    the type is a reference type.  If METHODTYPE and OBJECTTYPE are not
898    identical, we emit a cast.  We do this because the C++ compiler
899    doesn't know that a reference can be cast to the type of an
900    interface it implements.  METHODTYPE is the index of the method's
901    signature.  NAMEINDEX is the index of the field name; -1 for
902    `this'.  OBJECTTYPE is the index of the object's type.  */
903 static void
904 decompile_return_statement (out, jcf, methodtype, nameindex, objecttype)
905      FILE *out;
906      JCF *jcf;
907      int methodtype, nameindex, objecttype;
908 {
909   int cast = 0;
910   int obj_name_len, method_name_len;
911   const unsigned char *obj_data, *method_data;
912
913   obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype);
914   obj_data = JPOOL_UTF_DATA (jcf, objecttype);
915
916   method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype);
917   method_data = JPOOL_UTF_DATA (jcf, methodtype);
918
919   /* Skip forward to return type part of method.  */
920   while (*method_data != ')')
921     {
922       ++method_data;
923       --method_name_len;
924     }
925   /* Skip past `)'.  */
926   ++method_data;
927   --method_name_len;
928
929   /* If we see an `L', skip it and the trailing `;'.  */
930   if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';')
931     {
932       ++method_data;
933       method_name_len -= 2;
934     }
935   if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';')
936     {
937       ++obj_data;
938       obj_name_len -= 2;
939     }
940
941   /* FIXME: if METHODTYPE is a superclass of OBJECTTYPE then we don't
942      need a cast.  Right now there is no way to determine if this is
943      the case.  */
944   if (method_name_len != obj_name_len)
945     cast = 1;
946   else
947     {
948       int i;
949       for (i = 0; i < method_name_len; ++i)
950         {
951           if (method_data[i] != obj_data[i])
952             {
953               cast = 1;
954               break;
955             }
956         }
957     }
958
959   fputs (" { return ", out);
960
961   if (cast)
962     {
963       int array_depth = 0;
964       const unsigned char *limit;
965
966       fputs ("reinterpret_cast<", out);
967
968       while (*method_data == '[')
969         {
970           ++method_data;
971           ++array_depth;
972           --method_name_len;
973           fputs ("JArray<", out);
974         }
975
976       /* Leading space to avoid C++ digraphs.  */
977       fputs (" ::", out);
978
979       /* If we see an `L', skip it and the trailing `;'.  Only do this
980          if we've seen an array specification.  If we don't have an
981          array then the `L' was stripped earlier.  */
982       if (array_depth && method_data[0] == 'L'
983           && method_data[method_name_len - 1] == ';')
984         {
985           ++method_data;
986           method_name_len -= 2;
987         }
988
989       limit = method_data + method_name_len;
990       while (method_data < limit)
991         {
992           int ch = UTF8_GET (method_data, limit);
993           if (ch == '/')
994             fputs ("::", out);
995           else
996             jcf_print_char (out, ch);
997         }
998       fputs (" *", out);
999
1000       /* Close each array.  */
1001       while (array_depth > 0)
1002         {
1003           fputs ("> *", out);
1004           --array_depth;
1005         }
1006
1007       /* Close the cast.  */
1008       fputs ("> (", out);
1009     }
1010
1011   if (nameindex == -1)
1012     fputs ("this", out);
1013   else
1014     print_field_name (out, jcf, nameindex, 0);
1015
1016   if (cast)
1017     fputs (")", out);
1018
1019   fputs ("; }", out);
1020 }
1021
1022
1023 /* Try to decompile a method body.  Right now we just try to handle a
1024    simple case that we can do.  Expand as desired.  */
1025 static void
1026 decompile_method (out, jcf, code_len)
1027      FILE *out;
1028      JCF *jcf;
1029      int code_len;
1030 {
1031   const unsigned char *codes = jcf->read_ptr;
1032   int index;
1033   uint16 name_and_type, name;
1034
1035   /* If the method is synchronized, don't touch it.  */
1036   if ((method_access & ACC_SYNCHRONIZED))
1037     return;
1038
1039   if (code_len == 5
1040       && codes[0] == OPCODE_aload_0
1041       && codes[1] == OPCODE_getfield
1042       && (codes[4] == OPCODE_areturn
1043           || codes[4] == OPCODE_dreturn
1044           || codes[4] == OPCODE_freturn
1045           || codes[4] == OPCODE_ireturn
1046           || codes[4] == OPCODE_lreturn))
1047     {
1048       /* Found code like `return FIELD'.  */
1049       index = (codes[2] << 8) | codes[3];
1050       /* FIXME: ensure that tag is CONSTANT_Fieldref.  */
1051       name_and_type = JPOOL_USHORT2 (jcf, index);
1052       /* FIXME: ensure that tag is CONSTANT_NameAndType.  */
1053       name = JPOOL_USHORT1 (jcf, name_and_type);
1054       if (codes[4] == OPCODE_areturn)
1055         decompile_return_statement (out, jcf, method_signature,
1056                                     name, JPOOL_USHORT2 (jcf, name_and_type));
1057       else
1058         {
1059           fputs (" { return ", out);
1060           /* FIXME: flags.  */
1061           print_field_name (out, jcf, name, 0);
1062           fputs ("; }", out);
1063         }
1064       decompiled = 1;
1065     }
1066   else if (code_len == 2
1067            && codes[0] == OPCODE_aload_0
1068            && codes[1] == OPCODE_areturn
1069            /* We're going to generate `return this'.  This only makes
1070               sense for non-static methods.  */
1071            && ! (method_access & ACC_STATIC))
1072     {
1073       decompile_return_statement (out, jcf, method_signature, -1,
1074                                   JPOOL_USHORT1 (jcf, jcf->this_class));
1075       decompiled = 1;
1076     }
1077   else if (code_len == 1 && codes[0] == OPCODE_return)
1078     {
1079       /* Found plain `return'.  */
1080       fputs (" { }", out);
1081       decompiled = 1;
1082     }
1083   else if (code_len == 2
1084            && codes[0] == OPCODE_aconst_null
1085            && codes[1] == OPCODE_areturn)
1086     {
1087       /* Found `return null'.  We don't want to depend on NULL being
1088          defined.  */
1089       fputs (" { return 0; }", out);
1090       decompiled = 1;
1091     }
1092 }
1093
1094 /* Print one piece of a signature.  Returns pointer to next parseable
1095    character on success, NULL on error.  */
1096 static const unsigned char *
1097 decode_signature_piece (stream, signature, limit, need_space)
1098      FILE *stream;
1099      const unsigned char *signature, *limit;
1100      int *need_space;
1101 {
1102   const char *ctype;
1103   int array_depth = 0;
1104
1105   switch (signature[0])
1106     {
1107     case '[':
1108       /* More spaghetti.  */
1109
1110     array_loop:
1111       for (signature++; (signature < limit
1112                          && ISDIGIT (*signature)); signature++)
1113         ;
1114       switch (*signature)
1115         {
1116         case 'B':
1117           ctype = "jbyteArray";
1118           break;
1119         case 'C':
1120           ctype = "jcharArray";
1121           break;
1122         case 'D':
1123           ctype = "jdoubleArray";
1124           break;
1125         case 'F':
1126           ctype = "jfloatArray";
1127           break;
1128         case 'I':
1129           ctype = "jintArray";
1130           break;
1131         case 'S':
1132           ctype = "jshortArray";
1133           break;
1134         case 'J':
1135           ctype = "jlongArray";
1136           break;
1137         case 'Z':
1138           ctype = "jbooleanArray";
1139           break;
1140         case '[':
1141           /* We have a nested array.  */
1142           ++array_depth;
1143           if (! flag_jni)
1144             fputs ("JArray<", stream);
1145           goto array_loop;
1146
1147         case 'L':
1148           /* We have to generate a reference to JArray here, so that
1149              our output matches what the compiler does.  */
1150           ++signature;
1151           /* Space between `<' and `:' to avoid C++ digraphs.  */
1152           if (! flag_jni)
1153             fputs ("JArray< ::", stream);
1154           while (signature < limit && *signature != ';')
1155             {
1156               int ch = UTF8_GET (signature, limit);
1157               if (! flag_jni)
1158                 {
1159                   if (ch == '/')
1160                     fputs ("::", stream);
1161                   else
1162                     jcf_print_char (stream, ch);
1163                 }
1164             }
1165           if (! flag_jni)
1166             fputs (" *> *", stream);
1167           *need_space = 0;
1168           ctype = NULL;
1169           break;
1170         default:
1171           /* Unparseable signature.  */
1172           return NULL;
1173         }
1174
1175       /* If the previous iterations left us with something to print,
1176          print it.  For JNI, we always print `jobjectArray' in the
1177          nested cases.  */
1178       if (flag_jni && ctype == NULL)
1179         {
1180           ctype = "jobjectArray";
1181           *need_space = 1;
1182         }
1183       /* The `printit' case will advance SIGNATURE for us.  If we
1184          don't go there, we must advance past the `;' ourselves.  */
1185       if (ctype != NULL)
1186         goto printit;
1187       ++signature;
1188       break;
1189
1190     case '(':
1191     case ')':
1192       /* This shouldn't happen.  */
1193       return NULL;
1194
1195     case 'B': ctype = "jbyte";  goto printit;
1196     case 'C': ctype = "jchar";  goto printit;
1197     case 'D': ctype = "jdouble";  goto printit;
1198     case 'F': ctype = "jfloat";  goto printit;
1199     case 'I': ctype = "jint";  goto printit;
1200     case 'J': ctype = "jlong";  goto printit;
1201     case 'S': ctype = "jshort";  goto printit;
1202     case 'Z': ctype = "jboolean";  goto printit;
1203     case 'V': ctype = "void";  goto printit;
1204     case 'L':
1205       if (flag_jni)
1206         {
1207           /* We know about certain types and special-case their
1208              names.
1209              FIXME: something like java.lang.Exception should be
1210              printed as `jthrowable', because it is a subclass.  This
1211              means that gcjh must read the entire hierarchy and
1212              comprehend it.  */
1213           if (! strncmp (signature, "Ljava/lang/String;",
1214                          sizeof ("Ljava/lang/String;") -1))
1215             ctype = "jstring";
1216           else if (! strncmp (signature, "Ljava/lang/Class;",
1217                               sizeof ("Ljava/lang/Class;") - 1))
1218             ctype = "jclass";
1219           else if (! strncmp (signature, "Ljava/lang/Throwable;",
1220                               sizeof ("Ljava/lang/Throwable;") - 1))
1221             ctype = "jthrowable";
1222           else if (! strncmp (signature, "Ljava/lang/ref/WeakReference;",
1223                               sizeof ("Ljava/lang/ref/WeakReference;") - 1))
1224             ctype = "jweak";
1225           else
1226             ctype = "jobject";
1227
1228           while (*signature && *signature != ';')
1229             ++signature;
1230
1231           goto printit;
1232         }
1233       /* Print a leading "::" so we look in the right namespace.  */
1234       fputs ("::", stream);
1235       ++signature;
1236       while (*signature && *signature != ';')
1237         {
1238           int ch = UTF8_GET (signature, limit);
1239           if (ch == '/')
1240             fputs ("::", stream);
1241           else
1242             jcf_print_char (stream, ch);
1243         }
1244       fputs (" *", stream);
1245       if (*signature == ';')
1246         signature++;
1247       *need_space = 0;
1248       break;
1249     default:
1250       *need_space = 1;
1251       jni_print_char (stream, *signature++);
1252       break;
1253     printit:
1254       signature++;
1255       *need_space = 1;
1256       fputs (ctype, stream);
1257       break;
1258     }
1259
1260   if (! flag_jni)
1261     {
1262       while (array_depth-- > 0)
1263         fputs ("> *", stream);
1264     }
1265
1266   return signature;
1267 }
1268
1269 static void
1270 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
1271                      name_override, flags),
1272       FILE* stream AND JCF* jcf
1273       AND int name_index AND int signature_index
1274       AND int is_init AND const char *name_override AND int flags)
1275 {
1276   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1277     {
1278       fprintf (stream, "<not a UTF8 constant>");
1279       found_error = 1;
1280     }
1281   else
1282     {
1283       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1284       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1285       register const  unsigned char *str = str0;
1286       const unsigned char *limit = str + length;
1287       int need_space = 0;
1288       int is_method = str[0] == '(';
1289       const unsigned char *next;
1290
1291       /* If printing a method, skip to the return signature and print
1292          that first.  However, there is no return value if this is a
1293          constructor.  */
1294       if (is_method && ! is_init)
1295         {
1296           while (str < limit)
1297             {
1298               int ch = *str++;
1299               if (ch == ')')
1300                 break;
1301             }
1302         }
1303
1304       /* If printing a field or an ordinary method, then print the
1305          "return value" now.  */
1306       if (! is_method || ! is_init)
1307         {
1308           next = decode_signature_piece (stream, str, limit, &need_space);
1309           if (! next)
1310             {
1311               fprintf (stderr, "unparseable signature: `%s'\n", str0);
1312               found_error = 1;
1313               return;
1314             }
1315         }
1316
1317       /* Now print the name of the thing.  */
1318       if (need_space)
1319         fputs (" ", stream);
1320       print_full_cxx_name (stream, jcf, name_index, 
1321                            signature_index, is_init, name_override,
1322                            flags);
1323     }
1324 }
1325
1326 /* Print the unqualified method name followed by the signature. */
1327 static void
1328 DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index,
1329                             is_init, name_override, flags),
1330       FILE* stream AND JCF* jcf
1331       AND int name_index AND int signature_index AND int is_init 
1332       AND const char *name_override AND int flags)
1333 {
1334   int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1335   const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1336   register const unsigned char *str = str0;
1337   const unsigned char *limit = str + length;
1338   int need_space = 0;
1339   int is_method = str[0] == '(';
1340   const unsigned char *next;
1341
1342   if (name_override)
1343     fputs (name_override, stream);
1344   else if (name_index)
1345     {
1346       /* Declare constructors specially.  */
1347       if (is_init)
1348         print_base_classname (stream, jcf, jcf->this_class);
1349       else
1350         print_name (stream, jcf, name_index);
1351     }
1352
1353   if (flag_jni)
1354     {
1355       unsigned char *signature = JPOOL_UTF_DATA (jcf, signature_index);
1356       int sig_len = JPOOL_UTF_LENGTH (jcf, signature_index);
1357       if (overloaded_jni_method_exists_p (JPOOL_UTF_DATA (jcf, name_index),
1358                                           JPOOL_UTF_LENGTH (jcf, name_index),
1359                                           signature, sig_len))
1360         {
1361           /* If this method is overloaded by another native method,
1362              then include the argument information in the mangled
1363              name.  */
1364           unsigned char *limit = signature + sig_len;
1365           fputs ("__", stream);
1366           while (signature < limit)
1367             {
1368               int ch = UTF8_GET (signature, limit);
1369               jni_print_char (stream, ch);
1370               if (ch == ')')
1371                 {
1372                   /* Done.  */
1373                   break;
1374                 }
1375             }
1376         }
1377     }
1378
1379   if (is_method)
1380     {
1381       /* Have a method or a constructor.  Print signature pieces
1382          until done.  */
1383       fputs (" (", stream);
1384
1385       str = str0 + 1;
1386
1387       /* In JNI mode, add extra arguments.  */
1388       if (flag_jni)
1389         {
1390           /* FIXME: it would be nice to know if we are printing a decl
1391              or a definition, and only print `env' for the latter.  */
1392           fputs ("JNIEnv *env", stream);
1393
1394           fputs ((flags & ACC_STATIC) ? ", jclass" : ", jobject", stream);
1395
1396           if (*str != ')')
1397             fputs (", ", stream);
1398         }
1399
1400       while (str < limit && *str != ')')
1401         {
1402           next = decode_signature_piece (stream, str, limit, &need_space);
1403           if (! next)
1404             {
1405               fprintf (stderr, "unparseable signature: `%s'\n", str0);
1406               found_error = 1;
1407               return;
1408             }
1409           
1410           if (next < limit && *next != ')')
1411             fputs (", ", stream);
1412           str = next;
1413         }
1414       
1415       fputs (")", stream);
1416     }
1417 }
1418
1419 /* This is a helper for print_stub_or_jni.  */
1420 static void
1421 DEFUN (print_name_for_stub_or_jni, (stream, jcf, name_index, signature_index,
1422                                     is_init, name_override, flags),
1423        FILE *stream AND JCF *jcf
1424        AND int name_index AND int signature_index
1425        AND int is_init AND const char *name_override AND int flags)
1426 {
1427   const char *const prefix = flag_jni ? "Java_" : "";
1428   print_cxx_classname (stream, prefix, jcf, jcf->this_class);
1429   fputs (flag_jni ? "_" : "::", stream);
1430   print_full_cxx_name (stream, jcf, name_index, 
1431                        signature_index, is_init, name_override,
1432                        flags);
1433 }
1434
1435 static void
1436 DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init,
1437                           name_override, flags),
1438       FILE* stream AND JCF* jcf
1439       AND int name_index AND int signature_index
1440       AND int is_init AND const char *name_override AND int flags)
1441 {
1442   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1443     {
1444       fprintf (stream, "<not a UTF8 constant>");
1445       found_error = 1;
1446     }
1447   else
1448     {
1449       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1450       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1451       register const unsigned char *str = str0;
1452       const unsigned char *limit = str + length;
1453       int need_space = 0;
1454       int is_method = str[0] == '(';
1455       const unsigned char *next;
1456
1457       /* Don't print fields in the JNI case.  */
1458       if (! is_method && flag_jni)
1459         return;
1460
1461       if (flag_jni && ! stubs)
1462         fputs ("extern ", stream);
1463
1464       /* If printing a method, skip to the return signature and print
1465          that first.  However, there is no return value if this is a
1466          constructor.  */
1467       if (is_method && ! is_init)
1468         {
1469           while (str < limit)
1470             {
1471               int ch = *str++;
1472               if (ch == ')')
1473                 break;
1474             }
1475         }
1476
1477       /* If printing a field or an ordinary method, then print the
1478          "return value" now.  Note that a constructor can't be native,
1479          so we don't bother checking this in the JNI case.  */
1480       if (! is_method || ! is_init)
1481         {
1482           next = decode_signature_piece (stream, str, limit, &need_space);
1483           if (! next)
1484             {
1485               fprintf (stderr, "unparseable signature: `%s'\n", str0);
1486               found_error = 1;
1487               return;
1488             }
1489         }
1490
1491       /* When printing a JNI header we need to respect the space.  In
1492          other cases we're just going to insert a newline anyway.  */
1493       fputs (need_space && ! stubs ? " " : "\n", stream);
1494       
1495       /* Now print the name of the thing.  */
1496       print_name_for_stub_or_jni (stream, jcf, name_index,
1497                                   signature_index, is_init, name_override,
1498                                   flags);
1499
1500       /* Print the body.  */
1501       if (stubs)
1502         {
1503           if (flag_jni)
1504             fputs ("\n{\n  (*env)->FatalError (\"", stream);
1505           else
1506             fputs ("\n{\n  throw new ::java::lang::UnsupportedOperationException (JvNewStringLatin1 (\"", stream);
1507           print_name_for_stub_or_jni (stream, jcf, name_index,
1508                                       signature_index, is_init,
1509                                       name_override,
1510                                       flags);
1511           fprintf (stream, " not implemented\")%s;\n}\n\n",
1512                    flag_jni ? "" : ")");
1513         }
1514     }
1515 }
1516
1517 static void
1518 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
1519       FILE *stream AND JCF *jcf AND const char *prefix AND int index)
1520 {
1521   int name_index = JPOOL_USHORT1 (jcf, index);
1522   fputs (prefix, stream);
1523   jcf_print_utf8_replace (out,
1524                           JPOOL_UTF_DATA (jcf, name_index),
1525                           JPOOL_UTF_LENGTH (jcf, name_index),
1526                           '/', '_');
1527 }
1528
1529 /* Print PREFIX, then a class name in C++ format.  If the name refers
1530    to an array, ignore it and don't print PREFIX.  Returns 1 if
1531    something was printed, 0 otherwise.  */
1532 static int
1533 print_cxx_classname (stream, prefix, jcf, index)
1534      FILE *stream;
1535      const char *prefix;
1536      JCF *jcf;
1537      int index;
1538 {
1539   int name_index = JPOOL_USHORT1 (jcf, index);
1540   int len, c;
1541   const unsigned char *s, *p, *limit;
1542
1543   s = JPOOL_UTF_DATA (jcf, name_index);
1544   len = JPOOL_UTF_LENGTH (jcf, name_index);
1545   limit = s + len;
1546
1547   /* Explicitly omit arrays here.  */
1548   p = s;
1549   c = UTF8_GET (p, limit);
1550   if (c == '[')
1551     return 0;
1552
1553   fputs (prefix, stream);
1554
1555   /* Print a leading "::" so we look in the right namespace.  */
1556   if (! flag_jni && ! stubs)
1557     fputs ("::", stream);
1558
1559   while (s < limit)
1560     {
1561       c = UTF8_GET (s, limit);
1562       if (c == '/')
1563         fputs (flag_jni ? "_" : "::", stream);
1564       else
1565         jni_print_char (stream, c);
1566     }
1567
1568   return 1;
1569 }
1570
1571 int written_class_count = 0;
1572
1573 /* Return name of superclass.  If LEN is not NULL, fill it with length
1574    of name.  */
1575 static const unsigned char *
1576 super_class_name (derived_jcf, len)
1577      JCF *derived_jcf;
1578      int *len;
1579 {
1580   int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
1581   int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
1582   const unsigned char *supername =
1583     JPOOL_UTF_DATA (derived_jcf, supername_index);
1584
1585   if (len)
1586     *len = supername_length;
1587
1588   return supername;
1589 }
1590
1591 \f
1592
1593 /* We keep track of all the `#include's we generate, so we can avoid
1594    duplicates.  */
1595 struct include
1596 {
1597   char *name;
1598   struct include *next;
1599 };
1600
1601 /* List of all includes.  */
1602 static struct include *all_includes = NULL;
1603
1604 /* Generate a #include.  */
1605 static void
1606 print_include (out, utf8, len)
1607      FILE *out;
1608      const unsigned char *utf8;
1609      int len;
1610 {
1611   struct include *incl;
1612
1613   if (! out)
1614     return;
1615
1616   if (len == -1)
1617     len = strlen (utf8);
1618
1619   for (incl = all_includes; incl; incl = incl->next)
1620     {
1621       /* We check the length because we might have a proper prefix.  */
1622       if (len == (int) strlen (incl->name)
1623           && ! strncmp (incl->name, utf8, len))
1624         return;
1625     }
1626
1627   incl = (struct include *) xmalloc (sizeof (struct include));
1628   incl->name = xmalloc (len + 1);
1629   strncpy (incl->name, utf8, len);
1630   incl->name[len] = '\0';
1631   incl->next = all_includes;
1632   all_includes = incl;
1633
1634   fputs ("#include <", out);
1635   jcf_print_utf8_replace (out, utf8, len,
1636                           '/',
1637                           flag_jni ? '_' : '/');
1638   fputs (".h>\n", out);
1639 }
1640
1641 \f
1642
1643 /* This is used to represent part of a package or class name.  */
1644 struct namelet
1645 {
1646   /* The text of this part of the name.  */
1647   char *name;
1648   /* True if this represents a class.  */
1649   int is_class;
1650   /* Linked list of all classes and packages inside this one.  */
1651   struct namelet *subnamelets;
1652   /* Pointer to next sibling.  */
1653   struct namelet *next;
1654 };
1655
1656 static void add_namelet PARAMS ((const unsigned char *,
1657                                 const unsigned char *, struct namelet *));
1658 static void print_namelet PARAMS ((FILE *, struct namelet *, int));
1659
1660 /* The special root namelet.  */
1661 static struct namelet root =
1662 {
1663   NULL,
1664   0,
1665   NULL,
1666   NULL
1667 };
1668
1669 /* This extracts the next name segment from the full UTF-8 encoded
1670    package or class name and links it into the tree.  It does this
1671    recursively.  */
1672 static void
1673 add_namelet (name, name_limit, parent)
1674      const unsigned char *name, *name_limit;
1675      struct namelet *parent;
1676 {
1677   const unsigned char *p;
1678   struct namelet *n = NULL, *np;
1679
1680   /* We want to skip the standard namespaces that we assume the
1681      runtime already knows about.  We only do this at the top level,
1682      though, hence the check for `root'.  */
1683   if (parent == &root)
1684     {
1685 #define JAVALANG "java/lang/"
1686 #define JAVAIO "java/io/"
1687 #define JAVAUTIL "java/util/"
1688       if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
1689            && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
1690           || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
1691               && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
1692           || (name_limit - name >= (int) sizeof (JAVAIO) - 1
1693               && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
1694         return;
1695     }
1696
1697   for (p = name; p < name_limit && *p != '/'; ++p)
1698     ;
1699
1700   /* Search for this name beneath the PARENT node.  */
1701   for (np = parent->subnamelets; np != NULL; np = np->next)
1702     {
1703       /* We check the length because we might have a proper prefix.  */
1704       if ((int) strlen (np->name) == p - name &&
1705           ! strncmp (name, np->name, p - name))
1706         {
1707           n = np;
1708           break;
1709         }
1710     }
1711
1712   if (n == NULL)
1713     {
1714       n = (struct namelet *) xmalloc (sizeof (struct namelet));
1715       n->name = xmalloc (p - name + 1);
1716       strncpy (n->name, name, p - name);
1717       n->name[p - name] = '\0';
1718       n->is_class = (p == name_limit);
1719       n->subnamelets = NULL;
1720       n->next = parent->subnamelets;
1721       parent->subnamelets = n;
1722     }
1723
1724   /* We recurse if there is more text, and if the trailing piece does
1725      not represent an inner class. */
1726   if (p < name_limit)
1727     add_namelet (p + 1, name_limit, n);
1728 }
1729
1730 /* Print a single namelet.  Destroys namelets while printing.  */
1731 static void
1732 print_namelet (out, name, depth)
1733      FILE *out;
1734      struct namelet *name;
1735      int depth;
1736 {
1737   int i, term = 0;
1738   struct namelet *c;
1739
1740   if (name->name)
1741     {
1742       for (i = 0; i < depth; ++i)
1743         fputc (' ', out);
1744       fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
1745                name->name);
1746       if (name->is_class && name->subnamelets == NULL)
1747         fputs (";\n", out);
1748       else
1749         {
1750           term = 1;
1751           fputs ("\n", out);
1752           for (i = 0; i < depth; ++i)
1753             fputc (' ', out);
1754           fputs ("{\n", out);
1755         }
1756     }
1757
1758   c = name->subnamelets;
1759   while (c != NULL)
1760     {
1761       struct namelet *next = c->next;
1762       print_namelet (out, c, depth + 2);
1763       c = next;
1764     }
1765   name->subnamelets = NULL;
1766
1767   if (name->name)
1768     {
1769       if (term)
1770         {
1771           for (i = 0; i < depth; ++i)
1772             fputc (' ', out);
1773           fputs ("}\n", out);
1774           /* Only print a `;' when printing a class.  C++ is evil.  */
1775           if (name->is_class)
1776             fputs (";", out);
1777         }
1778
1779       free (name->name);
1780       free (name);
1781     }
1782 }
1783
1784 /* This is called to add some classes to the list of classes for which
1785    we need decls.  The signature argument can be a function
1786    signature.  */
1787 static void
1788 add_class_decl (out, jcf, signature)
1789      FILE *out;
1790      JCF *jcf;
1791      JCF_u2 signature;
1792 {
1793   const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
1794   int len = JPOOL_UTF_LENGTH (jcf, signature);
1795   int i;
1796
1797   for (i = 0; i < len; ++i)
1798     {
1799       int start;
1800
1801       /* If we see an array, then we include the array header.  */
1802       if (s[i] == '[')
1803         {
1804           print_include (out, "gcj/array", -1);
1805           continue;
1806         }
1807
1808       /* We're looking for `L<stuff>;' -- everything else is
1809          ignorable.  */
1810       if (s[i] != 'L')
1811         continue;
1812
1813       for (start = ++i; i < len && s[i] != ';'; ++i)
1814         ;
1815
1816       add_namelet (&s[start], &s[i], &root);
1817     }
1818 }
1819
1820 /* Print declarations for all classes required by this class.  Any
1821    class or package in the `java' package is assumed to be handled
1822    statically in libjava; we don't generate declarations for these.
1823    This makes the generated headers a bit easier to read.  */
1824 static void
1825 print_class_decls (out, jcf, self)
1826      FILE *out;
1827      JCF *jcf;
1828      int self;
1829 {
1830   /* Make sure to always add the current class to the list of things
1831      that should be declared.  */
1832   int name_index = JPOOL_USHORT1 (jcf, self);
1833   int len;
1834   const unsigned char *s;
1835
1836   s = JPOOL_UTF_DATA (jcf, name_index);
1837   len = JPOOL_UTF_LENGTH (jcf, name_index);
1838   add_namelet (s, s + len, &root);
1839
1840   if (root.subnamelets)
1841     {
1842       fputs ("extern \"Java\"\n{\n", out);
1843       /* We use an initial offset of 0 because the root namelet
1844          doesn't cause anything to print.  */
1845       print_namelet (out, &root, 0);
1846       fputs ("};\n\n", out);
1847     }
1848 }
1849
1850 \f
1851
1852 static void
1853 DEFUN(process_file, (jcf, out),
1854       JCF *jcf AND FILE *out)
1855 {
1856   int code, i;
1857   uint32 field_start, method_end, method_start;
1858
1859   current_jcf = jcf;
1860
1861   last_access = -1;
1862
1863   if (jcf_parse_preamble (jcf) != 0)
1864     {
1865       fprintf (stderr, "Not a valid Java .class file.\n");
1866       found_error = 1;
1867       return;
1868     }
1869
1870   /* Parse and possibly print constant pool */
1871   code = jcf_parse_constant_pool (jcf);
1872   if (code != 0)
1873     {
1874       fprintf (stderr, "error while parsing constant pool\n");
1875       found_error = 1;
1876       return;
1877     }
1878   code = verify_constant_pool (jcf);
1879   if (code > 0)
1880     {
1881       fprintf (stderr, "error in constant pool entry #%d\n", code);
1882       found_error = 1;
1883       return;
1884     }
1885
1886   jcf_parse_class (jcf);
1887
1888   if (written_class_count++ == 0 && out)
1889     {
1890       const char *cstart, *cstart2, *mode, *cend, *what, *jflag;
1891       if (flag_jni)
1892         {
1893           cstart = "/*";
1894           cstart2 = "  ";
1895           cend = " */";
1896           mode = "";
1897           what = "JNI";
1898           jflag = " -jni";
1899         }
1900       else
1901         {
1902           cstart = "//";
1903           cstart2 = "//";
1904           cend = "";
1905           mode = " -*- c++ -*-";
1906           what = "CNI";
1907           jflag = "";
1908         }
1909
1910       if (! stubs)
1911         fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
1912                  cstart, mode, cend);
1913       else
1914         {
1915           fprintf (out, "%s This file was created by `gcjh -stubs%s'.%s\n\
1916 %s\n\
1917 %s This file is intended to give you a head start on implementing native\n\
1918 %s methods using %s.\n\
1919 %s Be aware: running `gcjh -stubs %s' once more for this class may\n\
1920 %s overwrite any edits you have made to this file.%s\n\n",
1921                    cstart, jflag, mode,
1922                    cstart2,
1923                    cstart2,
1924                    cstart2,
1925                    what,
1926                    cstart2,
1927                    jflag,
1928                    cstart2,
1929                    cend);
1930         }
1931     }
1932
1933   if (out)
1934     {
1935       if (! stubs)
1936         {
1937           print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
1938           fprintf (out, "__\n");
1939
1940           print_mangled_classname (out, jcf, "#define __", jcf->this_class);
1941           fprintf (out, "__\n\n");
1942
1943           if (flag_jni)
1944             {
1945               fprintf (out, "#include <jni.h>\n\n");
1946               fprintf (out, "#ifdef __cplusplus\n");
1947               fprintf (out, "extern \"C\"\n");
1948               fprintf (out, "{\n");
1949               fprintf (out, "#endif\n");
1950             }
1951           else  
1952             {
1953               /* We do this to ensure that inline methods won't be
1954                  `outlined' by g++.  This works as long as method and
1955                  fields are not added by the user.  */
1956               fprintf (out, "#pragma interface\n");
1957
1958               if (jcf->super_class)
1959                 {
1960                   int super_length;
1961                   const unsigned char *supername =
1962                     super_class_name (jcf, &super_length);
1963
1964                   fputs ("\n", out);
1965                   print_include (out, supername, super_length);
1966                 }
1967             }
1968         }
1969       else
1970         {
1971           /* Strip off the ".class" portion of the name when printing
1972              the include file name.  */
1973           char *name;
1974           int i, len = strlen (jcf->classname);
1975           if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
1976             len -= 6;
1977           /* Turn the class name into a file name.  */
1978           name = xmalloc (len + 1);
1979           for (i = 0; i < len; ++i)
1980             name[i] = jcf->classname[i] == '.' ? '/' : jcf->classname[i];
1981           name[i] = '\0';
1982           print_include (out, name, len);
1983           free (name);
1984
1985           if (! flag_jni)
1986             {
1987               print_include (out, "gcj/cni", -1);
1988               print_include (out, "java/lang/UnsupportedOperationException",
1989                              -1);
1990             }
1991         }
1992     }
1993
1994   /* We want to parse the methods first.  But we need to find where
1995      they start.  So first we skip the fields, then parse the methods.
1996      Then we parse the fields and skip the methods.  This is ugly, but
1997      not too bad since we need two full passes to get class decl
1998      information anyway.  */
1999   field_pass = 0;
2000   field_start = JCF_TELL (jcf);
2001   jcf_parse_fields (jcf);
2002
2003   method_start = JCF_TELL (jcf);
2004   method_pass = 0;
2005   jcf_parse_methods (jcf);
2006
2007   if (out)
2008     fputs ("\n", out);
2009
2010   if (out && ! flag_jni)
2011     {
2012       if (! stubs)
2013         print_class_decls (out, jcf, jcf->this_class);
2014
2015       for (i = 0; i < prepend_count; ++i)
2016         fprintf (out, "%s\n", prepend_specs[i]);
2017       if (prepend_count > 0)
2018         fputc ('\n', out);
2019
2020       if (! stubs)
2021         {
2022           if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
2023             {
2024               fprintf (stderr, "class is of array type\n");
2025               found_error = 1;
2026               return;
2027             }
2028           if (jcf->super_class)
2029             {
2030               if (! print_cxx_classname (out, " : public ", 
2031                                          jcf, jcf->super_class))
2032                 {
2033                   fprintf (stderr, "base class is of array type\n");
2034                   found_error = 1;
2035                   return;
2036                 }
2037             }
2038
2039           fputs ("\n{\n", out);
2040         }
2041     }
2042
2043   /* Now go back for second pass over methods and fields.  */
2044   JCF_SEEK (jcf, method_start);
2045   method_pass = 1;
2046   jcf_parse_methods (jcf);
2047   method_end = JCF_TELL (jcf);
2048
2049   field_pass = 1;
2050   JCF_SEEK (jcf, field_start);
2051   jcf_parse_fields (jcf);
2052   JCF_SEEK (jcf, method_end);
2053
2054   jcf_parse_final_attributes (jcf);
2055
2056   if (out && ! stubs)
2057     {
2058       if (flag_jni)
2059         {
2060           fprintf (out, "\n#ifdef __cplusplus\n");
2061           fprintf (out, "}\n");
2062           fprintf (out, "#endif\n");
2063         }
2064       else
2065         {
2066           /* Generate friend decl if we still must.  */
2067           for (i = 0; i < friend_count; ++i)
2068             fprintf (out, "  friend %s\n", friend_specs[i]);
2069
2070           /* Generate extra declarations.  */
2071           if (add_count > 0)
2072             fputc ('\n', out);
2073           for (i = 0; i < add_count; ++i)
2074             fprintf (out, "  %s\n", add_specs[i]);
2075
2076           /* Generate an entry for the class object.  */
2077           generate_access (out, ACC_PUBLIC);
2078           fprintf (out, "\n  static ::java::lang::Class class$;\n");
2079
2080           fputs ("}", out);
2081           
2082           if (jcf->access_flags & ACC_INTERFACE)
2083             fputs (" __attribute__ ((java_interface))", out);
2084
2085           fputs (";\n", out);
2086
2087           if (append_count > 0)
2088             fputc ('\n', out);
2089           for (i = 0; i < append_count; ++i)
2090             fprintf (out, "%s\n", append_specs[i]);
2091         }
2092
2093       print_mangled_classname (out, jcf, 
2094                                "\n#endif /* __", jcf->this_class);
2095       fprintf (out, "__ */\n");
2096     }
2097 }
2098
2099 \f
2100
2101 /* This is used to mark options with no short value.  */
2102 #define LONG_OPT(Num)  ((Num) + 128)
2103
2104 #define OPT_classpath LONG_OPT (0)
2105 #define OPT_CLASSPATH LONG_OPT (1)
2106 #define OPT_HELP      LONG_OPT (2)
2107 #define OPT_TEMP      LONG_OPT (3)
2108 #define OPT_VERSION   LONG_OPT (4)
2109 #define OPT_PREPEND   LONG_OPT (5)
2110 #define OPT_FRIEND    LONG_OPT (6)
2111 #define OPT_ADD       LONG_OPT (7)
2112 #define OPT_APPEND    LONG_OPT (8)
2113 #define OPT_M         LONG_OPT (9)
2114 #define OPT_MM        LONG_OPT (10)
2115 #define OPT_MG        LONG_OPT (11)
2116 #define OPT_MD        LONG_OPT (12)
2117 #define OPT_MMD       LONG_OPT (13)
2118
2119 static const struct option options[] =
2120 {
2121   { "classpath", required_argument, NULL, OPT_classpath },
2122   { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
2123   { "help",      no_argument,       NULL, OPT_HELP },
2124   { "stubs",     no_argument,       &stubs, 1 },
2125   { "td",        required_argument, NULL, OPT_TEMP },
2126   { "verbose",   no_argument,       NULL, 'v' },
2127   { "version",   no_argument,       NULL, OPT_VERSION },
2128   { "prepend",   required_argument, NULL, OPT_PREPEND },
2129   { "friend",    required_argument, NULL, OPT_FRIEND },
2130   { "add",       required_argument, NULL, OPT_ADD },
2131   { "append",    required_argument, NULL, OPT_APPEND },
2132   { "M",         no_argument,       NULL, OPT_M   },
2133   { "MM",        no_argument,       NULL, OPT_MM  },
2134   { "MG",        no_argument,       NULL, OPT_MG  },
2135   { "MD",        no_argument,       NULL, OPT_MD  },
2136   { "MMD",       no_argument,       NULL, OPT_MMD },
2137   { "jni",       no_argument,       &flag_jni, 1 },
2138   { NULL,        no_argument,       NULL, 0 }
2139 };
2140
2141 static void
2142 usage ()
2143 {
2144   fprintf (stderr, "Try `gcjh --help' for more information.\n");
2145   exit (1);
2146 }
2147
2148 static void
2149 help ()
2150 {
2151   printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
2152   printf ("Generate C++ header files from .class files\n\n");
2153   printf ("  -stubs                  Generate an implementation stub file\n");
2154   printf ("  -jni                    Generate a JNI header or stub\n");
2155   printf ("\n");
2156   printf ("  -add TEXT               Insert TEXT into class body\n");
2157   printf ("  -append TEXT            Insert TEXT after class declaration\n");
2158   printf ("  -friend TEXT            Insert TEXT as `friend' declaration\n");
2159   printf ("  -prepend TEXT           Insert TEXT before start of class\n");
2160   printf ("\n");
2161   printf ("  --classpath PATH        Set path to find .class files\n");
2162   printf ("  --CLASSPATH PATH        Set path to find .class files\n");
2163   printf ("  -IDIR                   Append directory to class path\n");
2164   printf ("  -d DIRECTORY            Set output directory name\n");
2165   printf ("  -o FILE                 Set output file name\n");
2166   printf ("  -td DIRECTORY           Set temporary directory name\n");
2167   printf ("\n");
2168   printf ("  --help                  Print this help, then exit\n");
2169   printf ("  --version               Print version number, then exit\n");
2170   printf ("  -v, --verbose           Print extra information while running\n");
2171   printf ("\n");
2172   printf ("  -M                      Print all dependencies to stdout;\n");
2173   printf ("                             suppress ordinary output\n");
2174   printf ("  -MM                     Print non-system dependencies to stdout;\n");
2175   printf ("                             suppress ordinary output\n");
2176   printf ("  -MD                     Print all dependencies to stdout\n");
2177   printf ("  -MMD                    Print non-system dependencies to stdout\n");
2178   /* We omit -MG until it is implemented.  */
2179   printf ("\n");
2180   printf ("For bug reporting instructions, please see:\n");
2181   printf ("%s.\n", GCCBUGURL);
2182   exit (0);
2183 }
2184
2185 static void
2186 version ()
2187 {
2188   printf ("gcjh (%s)\n\n", version_string);
2189   printf ("Copyright (C) 2001 Free Software Foundation, Inc.\n");
2190   printf ("This is free software; see the source for copying conditions.  There is NO\n");
2191   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
2192   exit (0);
2193 }
2194
2195 int
2196 DEFUN(main, (argc, argv),
2197       int argc AND char** argv)
2198 {
2199   JCF jcf;
2200   int argi;
2201   char *output_file = NULL;
2202   int emit_dependencies = 0, suppress_output = 0;
2203   int opt;
2204
2205   if (argc <= 1)
2206     {
2207       fprintf (stderr, "gcjh: no classes specified\n");
2208       usage ();
2209     }
2210
2211   jcf_path_init ();
2212
2213   /* We use getopt_long_only to allow single `-' long options.  For
2214      some of our options this is more natural.  */
2215   while ((opt = getopt_long_only (argc, argv, "I:d:o:v", options, NULL)) != -1)
2216     {
2217       switch (opt)
2218         {
2219         case 0:
2220           /* Already handled.  */
2221           break;
2222
2223         case 'o':
2224           output_file = optarg;
2225           break;
2226
2227         case 'd':
2228           output_directory = optarg;
2229           break;
2230
2231         case 'I':
2232           jcf_path_include_arg (optarg);
2233           break;
2234
2235         case 'v':
2236           verbose++;
2237           break;
2238
2239         case OPT_classpath:
2240           jcf_path_classpath_arg (optarg);
2241           break;
2242
2243         case OPT_CLASSPATH:
2244           jcf_path_CLASSPATH_arg (optarg);
2245           break;
2246
2247         case OPT_HELP:
2248           help ();
2249           break;
2250
2251         case OPT_TEMP:
2252           temp_directory = optarg;
2253           break;
2254
2255         case OPT_VERSION:
2256           version ();
2257           break;
2258
2259         case OPT_PREPEND:
2260           if (prepend_count == 0)
2261             prepend_specs = (char**) ALLOC (argc * sizeof (char*));
2262           prepend_specs[prepend_count++] = optarg;
2263           break;
2264
2265         case OPT_FRIEND:
2266           if (friend_count == 0)
2267             friend_specs = (char**) ALLOC (argc * sizeof (char*));
2268           friend_specs[friend_count++] = optarg;
2269           break;
2270
2271         case OPT_ADD:
2272           if (add_count == 0)
2273             add_specs = (char**) ALLOC (argc * sizeof (char*));
2274           add_specs[add_count++] = optarg;
2275           break;
2276
2277         case OPT_APPEND:
2278           if (append_count == 0)
2279             append_specs = (char**) ALLOC (argc * sizeof (char*));
2280           append_specs[append_count++] = optarg;
2281           break;
2282
2283         case OPT_M:
2284           emit_dependencies = 1;
2285           suppress_output = 1;
2286           jcf_dependency_init (1);
2287           break;
2288
2289         case OPT_MM:
2290           emit_dependencies = 1;
2291           suppress_output = 1;
2292           jcf_dependency_init (0);
2293           break;
2294
2295         case OPT_MG:
2296           fprintf (stderr, "gcjh: `-MG' option is unimplemented\n");
2297           exit (1);
2298
2299         case OPT_MD:
2300           emit_dependencies = 1;
2301           jcf_dependency_init (1);
2302           break;
2303
2304         case OPT_MMD:
2305           emit_dependencies = 1;
2306           jcf_dependency_init (0);
2307           break;
2308
2309         default:
2310           usage ();
2311           break;
2312         }
2313     }
2314
2315   if (optind == argc)
2316     {
2317       fprintf (stderr, "gcjh: no classes specified\n");
2318       usage ();
2319     }
2320
2321   jcf_path_seal (verbose);
2322
2323   if (output_file && emit_dependencies)
2324     {
2325       fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
2326       exit (1);
2327     }
2328
2329   for (argi = optind; argi < argc; argi++)
2330     {
2331       char *classname = argv[argi];
2332       char *current_output_file;
2333       const char *classfile_name;
2334
2335       if (verbose)
2336         fprintf (stderr, "Processing %s\n", classname);
2337       if (! output_file)
2338         jcf_dependency_reset ();
2339       classfile_name = find_class (classname, strlen (classname), &jcf, 0);
2340       if (classfile_name == NULL)
2341         {
2342           fprintf (stderr, "%s: no such class\n", classname);
2343           exit (1);
2344         }
2345       if (verbose)
2346         fprintf (stderr, "Found in %s\n", classfile_name);
2347       if (output_file)
2348         {
2349           if (strcmp (output_file, "-") == 0)
2350             out = stdout;
2351           else if (out == NULL)
2352             {
2353               out = fopen (output_file, "w");
2354             }
2355           if (out == NULL)
2356             {
2357               perror (output_file);
2358               exit (1);
2359             }
2360           current_output_file = output_file;
2361         }
2362       else
2363         {
2364           int dir_len = strlen (output_directory);
2365           int i, classname_length = strlen (classname);
2366           current_output_file = (char*) ALLOC (dir_len + classname_length + 5);
2367           strcpy (current_output_file, output_directory);
2368           if (dir_len > 0 && output_directory[dir_len-1] != '/')
2369             current_output_file[dir_len++] = '/';
2370           for (i = 0; classname[i] != '\0'; i++)
2371             {
2372               char ch = classname[i];
2373               if (ch == '.')
2374                 ch = '/';
2375               if (flag_jni && ch == '/')
2376                 ch = '_';
2377               current_output_file[dir_len++] = ch;
2378             }
2379           if (emit_dependencies)
2380             {
2381               if (suppress_output)
2382                 {
2383                   jcf_dependency_set_dep_file ("-");
2384                   out = NULL;
2385                 }
2386               else
2387                 {
2388                   /* We use `.hd' and not `.d' to avoid clashes with
2389                      dependency tracking from straight compilation.  */
2390                   strcpy (current_output_file + dir_len, ".hd");
2391                   jcf_dependency_set_dep_file (current_output_file);
2392                 }
2393             }
2394           strcpy (current_output_file + dir_len, 
2395                   stubs ? (flag_jni ? ".c" : ".cc") : ".h");
2396           jcf_dependency_set_target (current_output_file);
2397           if (! suppress_output)
2398             {
2399               out = fopen (current_output_file, "w");
2400               if (out == NULL)
2401                 {
2402                   perror (current_output_file);
2403                   exit (1);
2404                 }
2405             }
2406         }
2407       process_file (&jcf, out);
2408       JCF_FINISH (&jcf);
2409       if (current_output_file != output_file)
2410         free (current_output_file);
2411       jcf_dependency_write ();
2412     }
2413
2414   if (out != NULL && out != stdout)
2415     fclose (out);
2416
2417   return found_error;
2418 }