OSDN Git Service

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