OSDN Git Service

* gjavah.c (add_namelet): Check for standard package names here.
[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 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 "jcf.h"
30 #include "java-opcodes.h"
31 #include <math.h>
32
33 /* The output file.  */
34 FILE *out = NULL;
35
36 /* Nonzero on failure.  */
37 static int found_error = 0;
38
39 /* Directory to place resulting files in. Set by -d option. */
40 const char *output_directory = "";
41
42 /* Directory to place temporary file.  Set by -td option.  Currently unused. */
43 const char *temp_directory = "/tmp";
44
45 /* Number of friend functions we have to declare.  */
46 static int friend_count;
47
48 /* A class can optionally have a `friend' function declared.  If
49    non-NULL, this is that function.  */
50 static char **friend_specs = NULL;
51
52 /* Number of lines we are prepending before the class.  */
53 static int prepend_count;
54
55 /* We can prepend extra lines before the class's start. */
56 static char **prepend_specs = NULL;
57
58 /* Number of lines we are appending at the end of the class.  */
59 static int add_count;
60
61 /* We can append extra lines just before the class's end. */
62 static char **add_specs = NULL;
63
64 /* Number of lines we are appending after the class.  */
65 static int append_count;
66
67 /* We can append extra lines after the class's end. */
68 static char **append_specs = NULL;
69
70 int verbose = 0;
71
72 int stubs = 0;
73
74 struct JCF *current_jcf;
75 struct JCF *main_jcf;
76
77 /* This holds access information for the last field we examined.  They
78    let us generate "private:", "public:", and "protected:" properly.
79    If 0 then we haven't previously examined any field.  */
80 static JCF_u2 last_access;
81
82 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
83
84 /* Pass this macro the flags for a class and for a method.  It will
85    return true if the method should be considered `final'.  */
86 #define METHOD_IS_FINAL(Class, Method) \
87    (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
88
89 /* We keep a linked list of all method names we have seen.  This lets
90    us determine if a method name and a field name are in conflict.  */
91 struct method_name
92 {
93   unsigned char *name;
94   int length;
95   struct method_name *next;
96 };
97
98 /* List of method names we've seen.  */
99 static struct method_name *method_name_list;
100
101 static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
102 static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
103 static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int, const char *));
104 static void decompile_method PROTO ((FILE *, JCF *, int));
105 static void add_class_decl PROTO ((FILE *, JCF *, JCF_u2));
106
107 JCF_u2 current_field_name;
108 JCF_u2 current_field_value;
109 JCF_u2 current_field_signature;
110 JCF_u2 current_field_flags;
111
112 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
113 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
114   current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
115
116 /* We pass over fields twice.  The first time we just note the types
117    of the fields and then the start of the methods.  Then we go back
118    and parse the fields for real.  This is ugly.  */
119 static int field_pass;
120 /* Likewise we pass over methods twice.  The first time we generate
121    class decl information; the second time we generate actual method
122    decls.  */
123 static int method_pass;
124
125 #define HANDLE_END_FIELD()                                                    \
126   if (field_pass)                                                             \
127     {                                                                         \
128       if (out)                                                                \
129         print_field_info (out, jcf, current_field_name,                       \
130                           current_field_signature,                            \
131                           current_field_flags);                               \
132     }                                                                         \
133   else                                                                        \
134     add_class_decl (out, jcf, current_field_signature);
135
136 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
137
138 static int method_declared = 0;
139 static int method_access = 0;
140 static int method_printed = 0;
141 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)         \
142   if (method_pass)                                                            \
143     {                                                                         \
144       decompiled = 0; method_printed = 0;                                     \
145       if (out)                                                                \
146         print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS);          \
147     }                                                                         \
148   else                                                                        \
149     add_class_decl (out, jcf, SIGNATURE);
150
151 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
152   if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
153
154 static int decompiled = 0;
155 #define HANDLE_END_METHOD() \
156   if (out && method_printed) fputs (decompiled ? "\n" : ";\n", out);
157
158 #include "jcf-reader.c"
159
160 /* Some useful constants.  */
161 #define F_NAN_MASK 0x7f800000
162 #define D_NAN_MASK 0x7ff0000000000000LL
163
164 /* Return 1 if F is not Inf or NaN.  */
165 static int
166 java_float_finite (f)
167      jfloat f;
168 {
169   union {
170     jfloat f;
171     int32 i;
172   } u;
173   u.f = f;
174
175   /* We happen to know that F_NAN_MASK will match all NaN values, and
176      also positive and negative infinity.  That's why we only need one
177      test here.  See The Java Language Specification, section 20.9.  */
178   return (u.i & F_NAN_MASK) != F_NAN_MASK;
179 }
180
181 /* Return 1 if D is not Inf or NaN.  */
182 static int
183 java_double_finite (d)
184      jdouble d;
185 {
186   union {
187     jdouble d;
188     int64 i;
189   } u;
190   u.d = d;
191
192   /* Now check for all NaNs.  */
193   return (u.i & D_NAN_MASK) != D_NAN_MASK;
194 }
195
196 void
197 DEFUN(print_name, (stream, jcf, name_index),
198       FILE* stream AND JCF* jcf AND int name_index)
199 {
200   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
201     fprintf (stream, "<not a UTF8 constant>");
202   else
203     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
204                     JPOOL_UTF_LENGTH (jcf, name_index));
205 }
206
207 /* Print base name of class.  The base name is everything after the
208    final separator.  */
209
210 static void
211 print_base_classname (stream, jcf, index)
212      FILE *stream;
213      JCF *jcf;
214      int index;
215 {
216   int name_index = JPOOL_USHORT1 (jcf, index);
217   int len;
218   unsigned char *s, *p, *limit;
219
220   s = JPOOL_UTF_DATA (jcf, name_index);
221   len = JPOOL_UTF_LENGTH (jcf, name_index);
222   limit = s + len;
223   p = s;
224   while (s < limit)
225     {
226       int c = UTF8_GET (s, limit);
227       if (c == '/')
228         p = s;
229     }
230
231   while (p < limit)
232     {
233       int ch = UTF8_GET (p, limit);
234       if (ch == '/')
235         fputs ("::", stream);
236       else
237         jcf_print_char (stream, ch);
238     }
239 }
240
241 /* Return 0 if NAME is equal to STR, nonzero otherwise.  */
242
243 static int
244 utf8_cmp (str, length, name)
245      unsigned char *str;
246      int length;
247      char *name;
248 {
249   unsigned char *limit = str + length;
250   int i;
251
252   for (i = 0; name[i]; ++i)
253     {
254       int ch = UTF8_GET (str, limit);
255       if (ch != name[i])
256         return 1;
257     }
258
259   return str != limit;
260 }
261
262 /* Generate an access control keyword based on FLAGS.  Returns 0 if
263    FLAGS matches the saved access information, nonzero otherwise.  */
264
265 static void
266 generate_access (stream, flags)
267      FILE *stream;
268      JCF_u2 flags;
269 {
270   if ((flags & ACC_VISIBILITY) == last_access)
271     return;
272   last_access = (flags & ACC_VISIBILITY);
273
274   switch (last_access)
275     {
276     case 0:
277       fputs ("public: // actually package-private\n", stream);
278       break;
279     case ACC_PUBLIC:
280       fputs ("public:\n", stream);
281       break;
282     case ACC_PRIVATE:
283       fputs ("private:\n", stream);
284       break;
285     case ACC_PROTECTED:
286       fputs ("public:  // actually protected\n", stream);
287       break;
288     default:
289       found_error = 1;
290       fprintf (stream, "#error unrecognized visibility %d\n",
291                (flags & ACC_VISIBILITY));
292       break;
293     }
294 }
295
296 /* See if NAME is already the name of a method.  */
297 static int
298 name_is_method_p (name, length)
299      unsigned char *name;
300      int length;
301 {
302   struct method_name *p;
303
304   for (p = method_name_list; p != NULL; p = p->next)
305     {
306       if (p->length == length && ! memcmp (p->name, name, length))
307         return 1;
308     }
309   return 0;
310 }
311
312 static void
313 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
314       FILE *stream AND JCF* jcf
315       AND int name_index AND int sig_index AND JCF_u2 flags)
316 {
317   char *override = NULL;
318
319   if (flags & ACC_FINAL)
320     {
321       if (current_field_value > 0)
322         {
323           char buffer[25];
324
325           generate_access (stream, flags);
326           switch (JPOOL_TAG (jcf, current_field_value))
327             {
328             case CONSTANT_Integer:
329               {
330                 jint num;
331                 int most_negative = 0;
332                 fputs ("  static const jint ", out);
333                 print_name (out, jcf, name_index);
334                 fputs (" = ", out);
335                 num = JPOOL_INT (jcf, current_field_value);
336                 /* We single out the most negative number to print
337                    specially.  This avoids later warnings from g++.  */
338                 if (num == 0x80000000)
339                   {
340                     most_negative = 1;
341                     ++num;
342                   }
343                 format_int (buffer, (jlong) num, 10);
344                 fprintf (out, "%sL%s;\n", buffer, most_negative ? " - 1" : "");
345               }
346               break;
347             case CONSTANT_Long:
348               {
349                 jlong num;
350                 int most_negative = 0;
351                 fputs ("  static const jlong ", out);
352                 print_name (out, jcf, name_index);
353                 fputs (" = ", out);
354                 num = JPOOL_LONG (jcf, current_field_value);
355                 /* We single out the most negative number to print
356                    specially..  This avoids later warnings from g++.  */
357                 if (num == 0x8000000000000000LL)
358                   {
359                     most_negative = 1;
360                     ++num;
361                   }
362                 format_int (buffer, num, 10);
363                 fprintf (out, "%sLL%s;\n", buffer, most_negative ? " - 1" :"");
364               }
365               break;
366             case CONSTANT_Float:
367               {
368                 jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
369                 fputs ("  static const jfloat ", out);
370                 print_name (out, jcf, name_index);
371                 if (! java_float_finite (fnum))
372                   fputs (";\n", out);
373                 else
374                   fprintf (out, " = %.10g;\n",  fnum);
375               }
376               break;
377             case CONSTANT_Double:
378               {
379                 jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
380                 fputs ("  static const jdouble ", out);
381                 print_name (out, jcf, name_index);
382                 if (! java_double_finite (dnum))
383                   fputs (";\n", out);
384                 else
385                   fprintf (out, " = %.17g;\n",  dnum);
386               }
387               break;
388             default:
389               fprintf(out, " <<inappropriate constant type>>\n");
390             }
391
392           return;
393         }
394     }
395
396   generate_access (stream, flags);
397   fputs ("  ", out);
398   if ((flags & ACC_STATIC))
399     fputs ("static ", out);
400
401   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
402     {
403       fprintf (stream, "<not a UTF8 constant>");
404       found_error = 1;
405     }
406   else
407     {
408       unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
409       int length = JPOOL_UTF_LENGTH (jcf, name_index);
410
411       if (name_is_method_p (name, length))
412         {
413           /* This field name matches a method.  So override the name
414              with a dummy name.  This is yucky, but it isn't clear
415              what else to do.  FIXME: if the field is static, then
416              we'll be in real trouble.  */
417           if ((flags & ACC_STATIC))
418             {
419               fprintf (stderr, "static field has same name as method\n");
420               found_error = 1;
421             }
422
423           override = (char *) malloc (length + 3);
424           memcpy (override, name, length);
425           strcpy (override + length, "__");
426         }
427     }
428
429   print_c_decl (out, jcf, name_index, sig_index, flags, 0, override);
430   fputs (";\n", out);
431
432   if (override)
433     free (override);
434 }
435
436 static void
437 DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
438       FILE *stream AND JCF* jcf
439       AND int name_index AND int sig_index AND JCF_u2 flags)
440 {
441   unsigned char *str;
442   int length, is_init = 0;
443   const char *override = NULL;
444
445   method_declared = 0;
446   method_access = flags;
447   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
448     fprintf (stream, "<not a UTF8 constant>");
449   str = JPOOL_UTF_DATA (jcf, name_index);
450   length = JPOOL_UTF_LENGTH (jcf, name_index);
451   if (str[0] == '<' || str[0] == '$')
452     {
453       /* Ignore internally generated methods like <clinit> and
454          $finit$.  However, treat <init> as a constructor.  */
455       if (! utf8_cmp (str, length, "<init>"))
456         is_init = 1;
457       else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
458                && ! (flags & ACC_STATIC))
459         {
460           /* FIXME: i18n bug here.  Order of prints should not be
461              fixed.  */
462           fprintf (stderr, "ignored method `");
463           jcf_print_utf8 (stderr, str, length);
464           fprintf (stderr, "' marked virtual\n");
465           found_error = 1;
466           return;
467         }
468       else
469         return;
470     }
471   else
472     {
473       struct method_name *nn;
474
475       nn = (struct method_name *) malloc (sizeof (struct method_name));
476       nn->name = (char *) malloc (length);
477       memcpy (nn->name, str, length);
478       nn->length = length;
479       nn->next = method_name_list;
480       method_name_list = nn;
481     }
482
483   /* We can't generate a method whose name is a C++ reserved word.
484      For now the only problem has been `delete'; add more here as
485      required.  We can't just ignore the function, because that will
486      cause incorrect code to be generated if the function is virtual
487      (not only for calls to this function for for other functions
488      after it in the vtbl).  So we give it a dummy name instead.  */
489   if (! utf8_cmp (str, length, "delete"))
490     {
491       /* If the method is static or final, we can safely skip it.  If
492          we don't skip it then we'll have problems since the mangling
493          will be wrong.  FIXME.  */
494       if (METHOD_IS_FINAL (jcf->access_flags, flags)
495           || (flags & ACC_STATIC))
496         return;
497       override = "__dummy_delete";
498     }
499
500   method_printed = 1;
501   generate_access (stream, flags);
502
503   fputs ("  ", out);
504   if ((flags & ACC_STATIC))
505     fputs ("static ", out);
506   else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
507     {
508       /* Don't print `virtual' if we have a constructor.  */
509       if (! is_init)
510         fputs ("virtual ", out);
511     }
512   print_c_decl (out, jcf, name_index, sig_index, flags, is_init, override);
513
514   if ((flags & ACC_ABSTRACT))
515     fputs (" = 0", out);
516   else
517     method_declared = 1;
518 }
519
520 /* Try to decompile a method body.  Right now we just try to handle a
521    simple case that we can do.  Expand as desired.  */
522 static void
523 decompile_method (out, jcf, code_len)
524      FILE *out;
525      JCF *jcf;
526      int code_len;
527 {
528   unsigned char *codes = jcf->read_ptr;
529   int index;
530   uint16 name_and_type, name;
531
532   /* If the method is synchronized, don't touch it.  */
533   if ((method_access & ACC_SYNCHRONIZED))
534     return;
535
536   if (code_len == 5
537       && codes[0] == OPCODE_aload_0
538       && codes[1] == OPCODE_getfield
539       && (codes[4] == OPCODE_areturn
540           || codes[4] == OPCODE_dreturn
541           || codes[4] == OPCODE_freturn
542           || codes[4] == OPCODE_ireturn
543           || codes[4] == OPCODE_lreturn))
544     {
545       /* Found code like `return FIELD'.  */
546       fputs (" { return ", out);
547       index = (codes[2] << 8) | codes[3];
548       /* FIXME: ensure that tag is CONSTANT_Fieldref.  */
549       /* FIXME: ensure that the field's class is this class.  */
550       name_and_type = JPOOL_USHORT2 (jcf, index);
551       /* FIXME: ensure that tag is CONSTANT_NameAndType.  */
552       name = JPOOL_USHORT1 (jcf, name_and_type);
553       print_name (out, jcf, name);
554       fputs ("; }", out);
555       decompiled = 1;
556     }
557   else if (code_len == 2
558            && codes[0] == OPCODE_aload_0
559            && codes[1] == OPCODE_areturn)
560     {
561       /* Found `return this'.  */
562       fputs (" { return this; }", out);
563       decompiled = 1;
564     }
565   else if (code_len == 1 && codes[0] == OPCODE_return)
566     {
567       /* Found plain `return'.  */
568       fputs (" { }", out);
569       decompiled = 1;
570     }
571   else if (code_len == 2
572            && codes[0] == OPCODE_aconst_null
573            && codes[1] == OPCODE_areturn)
574     {
575       /* Found `return null'.  We don't want to depend on NULL being
576          defined.  */
577       fputs (" { return 0; }", out);
578       decompiled = 1;
579     }
580 }
581
582 /* Print one piece of a signature.  Returns pointer to next parseable
583    character on success, NULL on error.  */
584 static unsigned char *
585 decode_signature_piece (stream, signature, limit, need_space)
586      FILE *stream;
587      unsigned char *signature, *limit;
588      int *need_space;
589 {
590   const char *ctype;
591
592   switch (signature[0])
593     {
594     case '[':
595       for (signature++; (signature < limit
596                          && *signature >= '0'
597                          && *signature <= '9'); signature++)
598         ;
599       switch (*signature)
600         {
601         case 'B': ctype = "jbyteArray";  goto printit;
602         case 'C': ctype = "jcharArray";  goto printit;
603         case 'D': ctype = "jdoubleArray";  goto printit;
604         case 'F': ctype = "jfloatArray";  goto printit;
605         case 'I': ctype = "jintArray";  goto printit;
606         case 'S': ctype = "jshortArray";  goto printit;
607         case 'J': ctype = "jlongArray";  goto printit;
608         case 'Z': ctype = "jbooleanArray";  goto printit;
609         case '[': ctype = "jobjectArray"; goto printit;
610         case 'L':
611           /* We have to generate a reference to JArray here,
612              so that our output matches what the compiler
613              does.  */
614           ++signature;
615           fputs ("JArray<", stream);
616           while (signature < limit && *signature != ';')
617             {
618               int ch = UTF8_GET (signature, limit);
619               if (ch == '/')
620                 fputs ("::", stream);
621               else
622                 jcf_print_char (stream, ch);
623             }
624           fputs (" *> *", stream);
625           *need_space = 0;
626           ++signature;
627           break;
628         default:
629           /* Unparseable signature.  */
630           return NULL;
631         }
632       break;
633
634     case '(':
635     case ')':
636       /* This shouldn't happen.  */
637       return NULL;
638
639     case 'B': ctype = "jbyte";  goto printit;
640     case 'C': ctype = "jchar";  goto printit;
641     case 'D': ctype = "jdouble";  goto printit;
642     case 'F': ctype = "jfloat";  goto printit;
643     case 'I': ctype = "jint";  goto printit;
644     case 'J': ctype = "jlong";  goto printit;
645     case 'S': ctype = "jshort";  goto printit;
646     case 'Z': ctype = "jboolean";  goto printit;
647     case 'V': ctype = "void";  goto printit;
648     case 'L':
649       ++signature;
650       while (*signature && *signature != ';')
651         {
652           int ch = UTF8_GET (signature, limit);
653           if (ch == '/')
654             fputs ("::", stream);
655           else
656             jcf_print_char (stream, ch);
657         }
658       fputs (" *", stream);
659       if (*signature == ';')
660         signature++;
661       *need_space = 0;
662       break;
663     default:
664       *need_space = 1;
665       jcf_print_char (stream, *signature++);
666       break;
667     printit:
668       signature++;
669       *need_space = 1;
670       fputs (ctype, stream);
671       break;
672     }
673
674   return signature;
675 }
676
677 static void
678 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init,
679                      name_override),
680       FILE* stream AND JCF* jcf
681       AND int name_index AND int signature_index AND JCF_u2 flags
682       AND int is_init AND const char *name_override)
683 {
684   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
685     {
686       fprintf (stream, "<not a UTF8 constant>");
687       found_error = 1;
688     }
689   else
690     {
691       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
692       unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
693       register  unsigned char *str = str0;
694       unsigned char *limit = str + length;
695       int need_space = 0;
696       int is_method = str[0] == '(';
697       unsigned char *next;
698
699       /* If printing a method, skip to the return signature and print
700          that first.  However, there is no return value if this is a
701          constructor.  */
702       if (is_method && ! is_init)
703         {
704           while (str < limit)
705             {
706               int ch = *str++;
707               if (ch == ')')
708                 break;
709             }
710         }
711
712       /* If printing a field or an ordinary method, then print the
713          "return value" now.  */
714       if (! is_method || ! is_init)
715         {
716           next = decode_signature_piece (stream, str, limit, &need_space);
717           if (! next)
718             {
719               fprintf (stderr, "unparseable signature: `%s'\n", str0);
720               found_error = 1;
721               return;
722             }
723         }
724
725       /* Now print the name of the thing.  */
726       if (need_space)
727         fputs (" ", stream);
728       if (name_override)
729         fputs (name_override, stream);
730       else if (name_index)
731         {
732           /* Declare constructors specially.  */
733           if (is_init)
734             print_base_classname (stream, jcf, jcf->this_class);
735           else
736             print_name (stream, jcf, name_index);
737         }
738
739       if (is_method)
740         {
741           /* Have a method or a constructor.  Print signature pieces
742              until done.  */
743           fputs (" (", stream);
744           str = str0 + 1;
745           while (str < limit && *str != ')')
746             {
747               next = decode_signature_piece (stream, str, limit, &need_space);
748               if (! next)
749                 {
750                   fprintf (stderr, "unparseable signature: `%s'\n", str0);
751                   found_error = 1;
752                   return;
753                 }
754
755               if (next < limit && *next != ')')
756                 fputs (", ", stream);
757               str = next;
758             }
759
760           fputs (")", stream);
761         }
762     }
763 }
764
765 void
766 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
767       FILE *stream AND JCF *jcf AND const char *prefix AND int index)
768 {
769   int name_index = JPOOL_USHORT1 (jcf, index);
770   fputs (prefix, stream);
771   jcf_print_utf8_replace (out,
772                           JPOOL_UTF_DATA (jcf, name_index),
773                           JPOOL_UTF_LENGTH (jcf, name_index),
774                           '/', '_');
775 }
776
777 /* Print PREFIX, then a class name in C++ format.  If the name refers
778    to an array, ignore it and don't print PREFIX.  Returns 1 if
779    something was printed, 0 otherwise.  */
780 static int
781 print_cxx_classname (stream, prefix, jcf, index)
782      FILE *stream;
783      char *prefix;
784      JCF *jcf;
785      int index;
786 {
787   int name_index = JPOOL_USHORT1 (jcf, index);
788   int len, c;
789   unsigned char *s, *p, *limit;
790
791   s = JPOOL_UTF_DATA (jcf, name_index);
792   len = JPOOL_UTF_LENGTH (jcf, name_index);
793   limit = s + len;
794
795   /* Explicitly omit arrays here.  */
796   p = s;
797   c = UTF8_GET (p, limit);
798   if (c == '[')
799     return 0;
800
801   fputs (prefix, stream);
802   while (s < limit)
803     {
804       c = UTF8_GET (s, limit);
805       if (c == '/')
806         fputs ("::", stream);
807       else
808         jcf_print_char (stream, c);
809     }
810
811   return 1;
812 }
813
814 int written_class_count = 0;
815
816 /* Return name of superclass.  If LEN is not NULL, fill it with length
817    of name.  */
818 static unsigned char *
819 super_class_name (derived_jcf, len)
820      JCF *derived_jcf;
821      int *len;
822 {
823   int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
824   int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
825   unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index);
826
827   if (len)
828     *len = supername_length;
829
830   return supername;
831 }
832
833 \f
834
835 /* This is used to represent part of a package or class name.  */
836 struct namelet
837 {
838   /* The text of this part of the name.  */
839   char *name;
840   /* True if this represents a class.  */
841   int is_class;
842   /* Linked list of all classes and packages inside this one.  */
843   struct namelet *subnamelets;
844   /* Pointer to next sibling.  */
845   struct namelet *next;
846 };
847
848 /* The special root namelet.  */
849 static struct namelet root =
850 {
851   NULL,
852   0,
853   NULL,
854   NULL
855 };
856
857 /* This extracts the next name segment from the full UTF-8 encoded
858    package or class name and links it into the tree.  It does this
859    recursively.  */
860 static void
861 add_namelet (name, name_limit, parent)
862      unsigned char *name, *name_limit;
863      struct namelet *parent;
864 {
865   unsigned char *p;
866   struct namelet *n = NULL, *np;
867
868   /* We want to skip the standard namespaces that we assume the
869      runtime already knows about.  We only do this at the top level,
870      though, hence the check for `root'.  */
871   if (parent == &root)
872     {
873 #define JAVALANG "java/lang/"
874 #define JAVAIO "java/io/"
875 #define JAVAUTIL "java/util/"
876       if ((name_limit - name >= sizeof (JAVALANG) - 1
877            && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
878           || (name_limit - name >= sizeof (JAVAUTIL) - 1
879               && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
880           || (name_limit - name >= sizeof (JAVAIO) - 1
881               && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
882         return;
883     }
884
885   for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p)
886     ;
887
888   /* Search for this name beneath the PARENT node.  */
889   for (np = parent->subnamelets; np != NULL; np = np->next)
890     {
891       if (! strncmp (name, np->name, p - name))
892         {
893           n = np;
894           break;
895         }
896     }
897
898   if (n == NULL)
899     {
900       n = (struct namelet *) malloc (sizeof (struct namelet));
901       n->name = malloc (p - name + 1);
902       strncpy (n->name, name, p - name);
903       n->name[p - name] = '\0';
904       n->is_class = (p == name_limit || *p == '$');
905       n->subnamelets = NULL;
906       n->next = parent->subnamelets;
907       parent->subnamelets = n;
908     }
909
910   /* We recurse if there is more text, and if the trailing piece does
911      not represent an inner class. */
912   if (p < name_limit && *p != '$')
913     add_namelet (p + 1, name_limit, n);
914 }
915
916 /* Print a single namelet.  Destroys namelets while printing.  */
917 static void
918 print_namelet (out, name, depth)
919      FILE *out;
920      struct namelet *name;
921      int depth;
922 {
923   int i, term = 0;
924   struct namelet *c;
925
926   if (name->name)
927     {
928       for (i = 0; i < depth; ++i)
929         fputc (' ', out);
930       fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
931                name->name);
932       if (name->is_class && name->subnamelets == NULL)
933         fputs (";\n", out);
934       else
935         {
936           term = 1;
937           fputs ("\n", out);
938           for (i = 0; i < depth; ++i)
939             fputc (' ', out);
940           fputs ("{\n", out);
941         }
942     }
943
944   c = name->subnamelets;
945   while (c != NULL)
946     {
947       struct namelet *next = c->next;
948       print_namelet (out, c, depth + 2);
949       c = next;
950     }
951
952   if (name->name)
953     {
954       if (term)
955         {
956           for (i = 0; i < depth; ++i)
957             fputc (' ', out);
958           fputs ("};\n", out);
959         }
960
961       free (name->name);
962       free (name);
963     }
964 }
965
966 /* This is called to add some classes to the list of classes for which
967    we need decls.  The signature argument can be a function
968    signature.  */
969 static void
970 add_class_decl (out, jcf, signature)
971      FILE *out;
972      JCF *jcf;
973      JCF_u2 signature;
974 {
975   unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
976   int len = JPOOL_UTF_LENGTH (jcf, signature);
977   int i;
978
979   for (i = 0; i < len; ++i)
980     {
981       int start;
982       /* We're looking for `L<stuff>;' -- everything else is
983          ignorable.  */
984       if (s[i] != 'L')
985         continue;
986       for (start = ++i; i < len && s[i] != ';'; ++i)
987         {
988           if (s[i] == '$' && out)
989             {
990               /* If this class represents an inner class, then
991                  generate a `#include' for the outer class.  */
992               fputs ("#include <", out);
993               jcf_print_utf8 (out, &s[start], i - start);
994               fputs (">\n", out);
995             }
996         }
997
998       add_namelet (&s[start], &s[i], &root);
999     }
1000 }
1001
1002 /* Print declarations for all classes required by this class.  Any
1003    class or package in the `java' package is assumed to be handled
1004    statically in libjava; we don't generate declarations for these.
1005    This makes the generated headers a bit easier to read.  */
1006 static void
1007 print_class_decls (out, jcf, self)
1008      FILE *out;
1009      JCF *jcf;
1010      int self;
1011 {
1012   /* Make sure to always add the current class to the list of things
1013      that should be declared.  */
1014   int name_index = JPOOL_USHORT1 (jcf, self);
1015   int len;
1016   unsigned char *s;
1017
1018   s = JPOOL_UTF_DATA (jcf, name_index);
1019   len = JPOOL_UTF_LENGTH (jcf, name_index);
1020   add_namelet (s, s + len, &root);
1021
1022   if (root.subnamelets)
1023     {
1024       fputs ("extern \"Java\"\n{\n", out);
1025       /* We use an initial offset of 0 because the root namelet
1026          doesn't cause anything to print.  */
1027       print_namelet (out, &root, 0);
1028       fputs ("};\n\n", out);
1029     }
1030 }
1031
1032 \f
1033
1034 static void
1035 DEFUN(process_file, (jcf, out),
1036       JCF *jcf AND FILE *out)
1037 {
1038   int code, i;
1039   uint32 field_start, method_end, method_start;
1040
1041   current_jcf = main_jcf = jcf;
1042
1043   last_access = -1;
1044
1045   if (jcf_parse_preamble (jcf) != 0)
1046     {
1047       fprintf (stderr, "Not a valid Java .class file.\n");
1048       found_error = 1;
1049       return;
1050     }
1051
1052   /* Parse and possibly print constant pool */
1053   code = jcf_parse_constant_pool (jcf);
1054   if (code != 0)
1055     {
1056       fprintf (stderr, "error while parsing constant pool\n");
1057       found_error = 1;
1058       return;
1059     }
1060   code = verify_constant_pool (jcf);
1061   if (code > 0)
1062     {
1063       fprintf (stderr, "error in constant pool entry #%d\n", code);
1064       found_error = 1;
1065       return;
1066     }
1067
1068   jcf_parse_class (jcf);
1069
1070   if (written_class_count++ == 0 && out)
1071     fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
1072            out);
1073
1074   if (out)
1075     {
1076       print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
1077       fprintf (out, "__\n");
1078
1079       print_mangled_classname (out, jcf, "#define __", jcf->this_class);
1080       fprintf (out, "__\n\n");
1081
1082       /* We do this to ensure that inline methods won't be `outlined'
1083          by g++.  This works as long as method and fields are not
1084          added by the user.  */
1085       fprintf (out, "#pragma interface\n\n");
1086     }
1087
1088   if (jcf->super_class && out)
1089     {
1090       int super_length;
1091       unsigned char *supername = super_class_name (jcf, &super_length);
1092
1093       fputs ("#include <", out);
1094       jcf_print_utf8 (out, supername, super_length);
1095       fputs (".h>\n", out);
1096
1097       /* FIXME: If our superclass is Object, then we include
1098          java-array.h.  The right thing to do here is look at all the
1099          methods and fields and see if an array is in use.  Only then
1100          would we need to include java-array.h.  */
1101       if (! utf8_cmp (supername, super_length, "java/lang/Object"))
1102         fputs ("#include <java-array.h>\n", out);
1103
1104       fputs ("\n", out);
1105     }
1106
1107   /* We want to parse the methods first.  But we need to find where
1108      they start.  So first we skip the fields, then parse the methods.
1109      Then we parse the fields and skip the methods.  This is ugly, but
1110      not too bad since we need two full passes to get class decl
1111      information anyway.  */
1112   field_pass = 0;
1113   field_start = JCF_TELL (jcf);
1114   jcf_parse_fields (jcf);
1115
1116   method_start = JCF_TELL (jcf);
1117   method_pass = 0;
1118   jcf_parse_methods (jcf);
1119
1120   if (out)
1121     {
1122       print_class_decls (out, jcf, jcf->this_class);
1123
1124       for (i = 0; i < prepend_count; ++i)
1125         fprintf (out, "%s\n", prepend_specs[i]);
1126       if (prepend_count > 0)
1127         fputc ('\n', out);
1128     }
1129
1130   if (out && ! print_cxx_classname (out, "class ", jcf, jcf->this_class))
1131     {
1132       fprintf (stderr, "class is of array type\n");
1133       found_error = 1;
1134       return;
1135     }
1136   if (out && jcf->super_class)
1137     {
1138       if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class))
1139         {
1140           fprintf (stderr, "base class is of array type\n");
1141           found_error = 1;
1142           return;
1143         }
1144     }
1145   if (out)
1146     fputs ("\n{\n", out);
1147
1148   /* Now go back for second pass over methods and fields.  */
1149   JCF_SEEK (jcf, method_start);
1150   method_pass = 1;
1151   jcf_parse_methods (jcf);
1152   method_end = JCF_TELL (jcf);
1153
1154   field_pass = 1;
1155   JCF_SEEK (jcf, field_start);
1156   jcf_parse_fields (jcf);
1157   JCF_SEEK (jcf, method_end);
1158
1159   jcf_parse_final_attributes (jcf);
1160
1161   if (out)
1162     {
1163       /* Generate friend decl if we still must.  */
1164       for (i = 0; i < friend_count; ++i)
1165         fprintf (out, "  friend %s\n", friend_specs[i]);
1166
1167       /* Generate extra declarations.  */
1168       if (add_count > 0)
1169         fputc ('\n', out);
1170       for (i = 0; i < add_count; ++i)
1171         fprintf (out, "  %s\n", add_specs[i]);
1172
1173       fputs ("};\n", out);
1174
1175       if (append_count > 0)
1176         fputc ('\n', out);
1177       for (i = 0; i < append_count; ++i)
1178         fprintf (out, "%s\n", append_specs[i]);
1179
1180       print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class);
1181       fprintf (out, "__ */\n");
1182     }
1183 }
1184
1185 static void
1186 usage ()
1187 {
1188   fprintf (stderr, "gcjh: no classes specified\n");
1189   exit (1);
1190 }
1191
1192 static void
1193 help ()
1194 {
1195   printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
1196   printf ("Generate C++ header files from .class files\n\n");
1197   printf ("  --classpath PATH        Set path to find .class files\n");
1198   printf ("  --CLASSPATH PATH        Set path to find .class files\n");
1199   printf ("  -IDIR                   Append directory to class path\n");
1200   printf ("  -d DIRECTORY            Set output directory name\n");
1201   printf ("  --help                  Print this help, then exit\n");
1202   printf ("  -o FILE                 Set output file name\n");
1203   printf ("  -td DIRECTORY           Set temporary directory name\n");
1204   printf ("  -v, --verbose           Print extra information while running\n");
1205   printf ("  --version               Print version number, then exit\n");
1206   /* FIXME: print bug-report information.  */
1207   exit (0);
1208 }
1209
1210 static void
1211 java_no_argument (opt)
1212      char *opt;
1213 {
1214   fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
1215   exit (1);
1216 }
1217
1218 static void
1219 version ()
1220 {
1221   /* FIXME: use version.c?  */
1222   printf ("gcjh (GNU gcc) 0.0\n\n");
1223   printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n");
1224   printf ("This is free software; see the source for copying conditions.  There is NO\n");
1225   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
1226   exit (0);
1227 }
1228
1229 int
1230 DEFUN(main, (argc, argv),
1231       int argc AND char** argv)
1232 {
1233   JCF jcf;
1234   int argi;
1235   char *output_file = NULL;
1236   int emit_dependencies = 0, suppress_output = 0;
1237
1238   if (argc <= 1)
1239     usage ();
1240
1241   jcf_path_init ();
1242
1243   for (argi = 1; argi < argc; argi++)
1244     {
1245       char *arg = argv[argi];
1246
1247       if (arg[0] != '-' || ! strcmp (arg, "--"))
1248         break;
1249
1250       /* Just let all arguments be given in either "-" or "--" form.  */
1251       if (arg[1] == '-')
1252         ++arg;
1253
1254       if (strcmp (arg, "-o") == 0)
1255         {
1256           if (argi + 1 < argc)
1257             output_file = argv[++argi];
1258           else
1259             java_no_argument (argv[argi]);
1260         }
1261       else if (strcmp (arg, "-d") == 0)
1262         {
1263           if (argi + 1 < argc)
1264             output_directory = argv[++argi];
1265           else
1266             java_no_argument (argv[argi]);
1267         }
1268       else if (strcmp (arg, "-td") == 0)
1269         {
1270           if (argi + 1 < argc)
1271             temp_directory = argv[++argi];
1272           else
1273             java_no_argument (argv[argi]);
1274         }
1275       else if (strcmp (arg, "-prepend") == 0)
1276         {
1277           if (argi + 1 < argc)
1278             {
1279               if (prepend_count == 0)
1280                 prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1281               prepend_specs[prepend_count++] = argv[++argi];
1282             }
1283           else
1284             java_no_argument (argv[argi]);
1285         }
1286       else if (strcmp (arg, "-friend") == 0)
1287         {
1288           if (argi + 1 < argc)
1289             {
1290               if (friend_count == 0)
1291                 friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1292               friend_specs[friend_count++] = argv[++argi];
1293             }
1294           else
1295             java_no_argument (argv[argi]);
1296         }
1297       else if (strcmp (arg, "-add") == 0)
1298         {
1299           if (argi + 1 < argc)
1300             {
1301               if (add_count == 0)
1302                 add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1303               add_specs[add_count++] = argv[++argi];
1304             }
1305           else
1306             java_no_argument (argv[argi]);
1307         }
1308       else if (strcmp (arg, "-append") == 0)
1309         {
1310           if (argi + 1 < argc)
1311             {
1312               if (append_count == 0)
1313                 append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1314               append_specs[append_count++] = argv[++argi];
1315             }
1316           else
1317             java_no_argument (argv[argi]);
1318         }
1319       else if (strcmp (arg, "-classpath") == 0)
1320         {
1321           if (argi + 1 < argc)
1322             jcf_path_classpath_arg (argv[++argi]);
1323           else
1324             java_no_argument (argv[argi]);
1325         }
1326       else if (strcmp (arg, "-CLASSPATH") == 0)
1327         {
1328           if (argi + 1 < argc)
1329             jcf_path_CLASSPATH_arg (argv[++argi]);
1330           else
1331             java_no_argument (argv[argi]);
1332         }
1333       else if (strncmp (arg, "-I", 2) == 0)
1334         jcf_path_include_arg (arg + 2);
1335       else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
1336         verbose++;
1337       else if (strcmp (arg, "-stubs") == 0)
1338         stubs++;
1339       else if (strcmp (arg, "-help") == 0)
1340         help ();
1341       else if (strcmp (arg, "-version") == 0)
1342         version ();
1343       else if (strcmp (arg, "-M") == 0)
1344         {
1345           emit_dependencies = 1;
1346           suppress_output = 1;
1347           jcf_dependency_init (1);
1348         }
1349       else if (strcmp (arg, "-MM") == 0)
1350         {
1351           emit_dependencies = 1;
1352           suppress_output = 1;
1353           jcf_dependency_init (0);
1354         }
1355       else if (strcmp (arg, "-MG") == 0)
1356         {
1357           fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
1358           exit (1);
1359         }
1360       else if (strcmp (arg, "-MD") == 0)
1361         {
1362           emit_dependencies = 1;
1363           jcf_dependency_init (1);
1364         }
1365       else if (strcmp (arg, "-MMD") == 0)
1366         {
1367           emit_dependencies = 1;
1368           jcf_dependency_init (0);
1369         }
1370       else
1371         {
1372           fprintf (stderr, "%s: illegal argument\n", argv[argi]);
1373           exit (1);
1374         }
1375     }
1376
1377   if (argi == argc)
1378     usage ();
1379
1380   jcf_path_seal ();
1381
1382   if (output_file && emit_dependencies)
1383     {
1384       fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
1385       exit (1);
1386     }
1387
1388   for (; argi < argc; argi++)
1389     {
1390       char *classname = argv[argi];
1391       char *classfile_name, *current_output_file;
1392
1393       if (verbose)
1394         fprintf (stderr, "Processing %s\n", classname);
1395       if (! output_file)
1396         jcf_dependency_reset ();
1397       classfile_name = find_class (classname, strlen (classname), &jcf, 0);
1398       if (classfile_name == NULL)
1399         {
1400           fprintf (stderr, "%s: no such class\n", classname);
1401           exit (1);
1402         }
1403       if (verbose)
1404         fprintf (stderr, "Found in %s\n", classfile_name);
1405       if (output_file)
1406         {
1407           if (strcmp (output_file, "-") == 0)
1408             out = stdout;
1409           else if (out == NULL)
1410             {
1411               out = fopen (output_file, "w");
1412             }
1413           if (out == NULL)
1414             {
1415               perror (output_file);
1416               exit (1);
1417             }
1418           current_output_file = output_file;
1419         }
1420       else
1421         {
1422           int dir_len = strlen (output_directory);
1423           int i, classname_length = strlen (classname);
1424           current_output_file = (char*) ALLOC (dir_len + classname_length + 4);
1425           strcpy (current_output_file, output_directory);
1426           if (dir_len > 0 && output_directory[dir_len-1] != '/')
1427             current_output_file[dir_len++] = '/';
1428           for (i = 0; classname[i] != '\0'; i++)
1429             {
1430               char ch = classname[i];
1431               if (ch == '.')
1432                 ch = '/';
1433               current_output_file[dir_len++] = ch;
1434             }
1435           if (emit_dependencies)
1436             {
1437               if (suppress_output)
1438                 {
1439                   jcf_dependency_set_dep_file ("-");
1440                   out = NULL;
1441                 }
1442               else
1443                 {
1444                   /* We use `.hd' and not `.d' to avoid clashes with
1445                      dependency tracking from straight compilation.  */
1446                   strcpy (current_output_file + dir_len, ".hd");
1447                   jcf_dependency_set_dep_file (current_output_file);
1448                 }
1449             }
1450           strcpy (current_output_file + dir_len, ".h");
1451           jcf_dependency_set_target (current_output_file);
1452           if (! suppress_output)
1453             {
1454               out = fopen (current_output_file, "w");
1455               if (out == NULL)
1456                 {
1457                   perror (current_output_file);
1458                   exit (1);
1459                 }
1460             }
1461         }
1462       process_file (&jcf, out);
1463       JCF_FINISH (&jcf);
1464       if (current_output_file != output_file)
1465         free (current_output_file);
1466       jcf_dependency_write ();
1467     }
1468
1469   if (out != NULL && out != stdout)
1470     fclose (out);
1471
1472   return found_error;
1473 }
1474
1475 /* TODO:
1476
1477  * Do whatever the javah -stubs flag does.
1478
1479  * Emit "structure forward declarations" when needed.
1480
1481  * Generate C headers, like javah
1482
1483  */