OSDN Git Service

Warning fixes:
[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, 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 == (jint) 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 == (jlong) 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, 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, 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           /* `$' is the separator for an inner class.  */
654           if (ch == '/' || ch == '$')
655             fputs ("::", stream);
656           else
657             jcf_print_char (stream, ch);
658         }
659       fputs (" *", stream);
660       if (*signature == ';')
661         signature++;
662       *need_space = 0;
663       break;
664     default:
665       *need_space = 1;
666       jcf_print_char (stream, *signature++);
667       break;
668     printit:
669       signature++;
670       *need_space = 1;
671       fputs (ctype, stream);
672       break;
673     }
674
675   return signature;
676 }
677
678 static void
679 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
680                      name_override),
681       FILE* stream AND JCF* jcf
682       AND int name_index AND int signature_index
683       AND int is_init AND const char *name_override)
684 {
685   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
686     {
687       fprintf (stream, "<not a UTF8 constant>");
688       found_error = 1;
689     }
690   else
691     {
692       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
693       unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
694       register  unsigned char *str = str0;
695       unsigned char *limit = str + length;
696       int need_space = 0;
697       int is_method = str[0] == '(';
698       unsigned char *next;
699
700       /* If printing a method, skip to the return signature and print
701          that first.  However, there is no return value if this is a
702          constructor.  */
703       if (is_method && ! is_init)
704         {
705           while (str < limit)
706             {
707               int ch = *str++;
708               if (ch == ')')
709                 break;
710             }
711         }
712
713       /* If printing a field or an ordinary method, then print the
714          "return value" now.  */
715       if (! is_method || ! is_init)
716         {
717           next = decode_signature_piece (stream, str, limit, &need_space);
718           if (! next)
719             {
720               fprintf (stderr, "unparseable signature: `%s'\n", str0);
721               found_error = 1;
722               return;
723             }
724         }
725
726       /* Now print the name of the thing.  */
727       if (need_space)
728         fputs (" ", stream);
729       if (name_override)
730         fputs (name_override, stream);
731       else if (name_index)
732         {
733           /* Declare constructors specially.  */
734           if (is_init)
735             print_base_classname (stream, jcf, jcf->this_class);
736           else
737             print_name (stream, jcf, name_index);
738         }
739
740       if (is_method)
741         {
742           /* Have a method or a constructor.  Print signature pieces
743              until done.  */
744           fputs (" (", stream);
745           str = str0 + 1;
746           while (str < limit && *str != ')')
747             {
748               next = decode_signature_piece (stream, str, limit, &need_space);
749               if (! next)
750                 {
751                   fprintf (stderr, "unparseable signature: `%s'\n", str0);
752                   found_error = 1;
753                   return;
754                 }
755
756               if (next < limit && *next != ')')
757                 fputs (", ", stream);
758               str = next;
759             }
760
761           fputs (")", stream);
762         }
763     }
764 }
765
766 void
767 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
768       FILE *stream AND JCF *jcf AND const char *prefix AND int index)
769 {
770   int name_index = JPOOL_USHORT1 (jcf, index);
771   fputs (prefix, stream);
772   jcf_print_utf8_replace (out,
773                           JPOOL_UTF_DATA (jcf, name_index),
774                           JPOOL_UTF_LENGTH (jcf, name_index),
775                           '/', '_');
776 }
777
778 /* Print PREFIX, then a class name in C++ format.  If the name refers
779    to an array, ignore it and don't print PREFIX.  Returns 1 if
780    something was printed, 0 otherwise.  */
781 static int
782 print_cxx_classname (stream, prefix, jcf, index)
783      FILE *stream;
784      char *prefix;
785      JCF *jcf;
786      int index;
787 {
788   int name_index = JPOOL_USHORT1 (jcf, index);
789   int len, c;
790   unsigned char *s, *p, *limit;
791
792   s = JPOOL_UTF_DATA (jcf, name_index);
793   len = JPOOL_UTF_LENGTH (jcf, name_index);
794   limit = s + len;
795
796   /* Explicitly omit arrays here.  */
797   p = s;
798   c = UTF8_GET (p, limit);
799   if (c == '[')
800     return 0;
801
802   fputs (prefix, stream);
803   while (s < limit)
804     {
805       c = UTF8_GET (s, limit);
806       if (c == '/')
807         fputs ("::", stream);
808       else
809         jcf_print_char (stream, c);
810     }
811
812   return 1;
813 }
814
815 int written_class_count = 0;
816
817 /* Return name of superclass.  If LEN is not NULL, fill it with length
818    of name.  */
819 static unsigned char *
820 super_class_name (derived_jcf, len)
821      JCF *derived_jcf;
822      int *len;
823 {
824   int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
825   int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
826   unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index);
827
828   if (len)
829     *len = supername_length;
830
831   return supername;
832 }
833
834 \f
835
836 /* We keep track of all the `#include's we generate, so we can avoid
837    duplicates.  */
838 struct include
839 {
840   char *name;
841   struct include *next;
842 };
843
844 /* List of all includes.  */
845 static struct include *all_includes = NULL;
846
847 /* Generate a #include.  */
848 static void
849 print_include (out, utf8, len)
850      FILE *out;
851      unsigned char *utf8;
852      int len;
853 {
854   struct include *incl;
855
856   if (! out)
857     return;
858
859   if (len == -1)
860     len = strlen (utf8);
861
862   for (incl = all_includes; incl; incl = incl->next)
863     {
864       if (! strncmp (incl->name, utf8, len))
865         return;
866     }
867
868   incl = (struct include *) malloc (sizeof (struct include));
869   incl->name = malloc (len + 1);
870   strncpy (incl->name, utf8, len);
871   incl->name[len] = '\0';
872   incl->next = all_includes;
873   all_includes = incl;
874
875   fputs ("#include <", out);
876   jcf_print_utf8 (out, utf8, len);
877   fputs (".h>\n", out);
878 }
879
880 \f
881
882 /* This is used to represent part of a package or class name.  */
883 struct namelet
884 {
885   /* The text of this part of the name.  */
886   char *name;
887   /* True if this represents a class.  */
888   int is_class;
889   /* Linked list of all classes and packages inside this one.  */
890   struct namelet *subnamelets;
891   /* Pointer to next sibling.  */
892   struct namelet *next;
893 };
894
895 /* The special root namelet.  */
896 static struct namelet root =
897 {
898   NULL,
899   0,
900   NULL,
901   NULL
902 };
903
904 /* This extracts the next name segment from the full UTF-8 encoded
905    package or class name and links it into the tree.  It does this
906    recursively.  */
907 static void
908 add_namelet (name, name_limit, parent)
909      unsigned char *name, *name_limit;
910      struct namelet *parent;
911 {
912   unsigned char *p;
913   struct namelet *n = NULL, *np;
914
915   /* We want to skip the standard namespaces that we assume the
916      runtime already knows about.  We only do this at the top level,
917      though, hence the check for `root'.  */
918   if (parent == &root)
919     {
920 #define JAVALANG "java/lang/"
921 #define JAVAIO "java/io/"
922 #define JAVAUTIL "java/util/"
923       if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
924            && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
925           || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
926               && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
927           || (name_limit - name >= (int) sizeof (JAVAIO) - 1
928               && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
929         return;
930     }
931
932   for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p)
933     ;
934
935   /* Search for this name beneath the PARENT node.  */
936   for (np = parent->subnamelets; np != NULL; np = np->next)
937     {
938       if (! strncmp (name, np->name, p - name))
939         {
940           n = np;
941           break;
942         }
943     }
944
945   if (n == NULL)
946     {
947       n = (struct namelet *) malloc (sizeof (struct namelet));
948       n->name = malloc (p - name + 1);
949       strncpy (n->name, name, p - name);
950       n->name[p - name] = '\0';
951       n->is_class = (p == name_limit || *p == '$');
952       n->subnamelets = NULL;
953       n->next = parent->subnamelets;
954       parent->subnamelets = n;
955     }
956
957   /* We recurse if there is more text, and if the trailing piece does
958      not represent an inner class. */
959   if (p < name_limit && *p != '$')
960     add_namelet (p + 1, name_limit, n);
961 }
962
963 /* Print a single namelet.  Destroys namelets while printing.  */
964 static void
965 print_namelet (out, name, depth)
966      FILE *out;
967      struct namelet *name;
968      int depth;
969 {
970   int i, term = 0;
971   struct namelet *c;
972
973   if (name->name)
974     {
975       for (i = 0; i < depth; ++i)
976         fputc (' ', out);
977       fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
978                name->name);
979       if (name->is_class && name->subnamelets == NULL)
980         fputs (";\n", out);
981       else
982         {
983           term = 1;
984           fputs ("\n", out);
985           for (i = 0; i < depth; ++i)
986             fputc (' ', out);
987           fputs ("{\n", out);
988         }
989     }
990
991   c = name->subnamelets;
992   while (c != NULL)
993     {
994       struct namelet *next = c->next;
995       print_namelet (out, c, depth + 2);
996       c = next;
997     }
998
999   if (name->name)
1000     {
1001       if (term)
1002         {
1003           for (i = 0; i < depth; ++i)
1004             fputc (' ', out);
1005           fputs ("};\n", out);
1006         }
1007
1008       free (name->name);
1009       free (name);
1010     }
1011 }
1012
1013 /* This is called to add some classes to the list of classes for which
1014    we need decls.  The signature argument can be a function
1015    signature.  */
1016 static void
1017 add_class_decl (out, jcf, signature)
1018      FILE *out;
1019      JCF *jcf;
1020      JCF_u2 signature;
1021 {
1022   unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
1023   int len = JPOOL_UTF_LENGTH (jcf, signature);
1024   int i;
1025   /* Name of class we are processing.  */
1026   int name_index = JPOOL_USHORT1 (jcf, jcf->this_class);
1027   int tlen = JPOOL_UTF_LENGTH (jcf, name_index);
1028   char *tname = JPOOL_UTF_DATA (jcf, name_index);
1029
1030   for (i = 0; i < len; ++i)
1031     {
1032       int start, saw_dollar;
1033
1034       /* If we see an array, then we include the array header.  */
1035       if (s[i] == '[')
1036         {
1037           print_include (out, "java-array", -1);
1038           continue;
1039         }
1040
1041       /* We're looking for `L<stuff>;' -- everything else is
1042          ignorable.  */
1043       if (s[i] != 'L')
1044         continue;
1045
1046       saw_dollar = 0;
1047       for (start = ++i; i < len && s[i] != ';'; ++i)
1048         {
1049           if (! saw_dollar && s[i] == '$' && out)
1050             {
1051               saw_dollar = 1;
1052               /* If this class represents an inner class, then
1053                  generate a `#include' for the outer class.  However,
1054                  don't generate the include if the outer class is the
1055                  class we are processing.  */
1056               if (i - start < tlen || strncmp (&s[start], tname, i - start))
1057                 print_include (out, &s[start], i - start);
1058               break;
1059             }
1060         }
1061
1062       /* If we saw an inner class, then the generated #include will
1063          declare the class.  So in this case we needn't bother.  */
1064       if (! saw_dollar)
1065         add_namelet (&s[start], &s[i], &root);
1066     }
1067 }
1068
1069 /* Print declarations for all classes required by this class.  Any
1070    class or package in the `java' package is assumed to be handled
1071    statically in libjava; we don't generate declarations for these.
1072    This makes the generated headers a bit easier to read.  */
1073 static void
1074 print_class_decls (out, jcf, self)
1075      FILE *out;
1076      JCF *jcf;
1077      int self;
1078 {
1079   /* Make sure to always add the current class to the list of things
1080      that should be declared.  */
1081   int name_index = JPOOL_USHORT1 (jcf, self);
1082   int len;
1083   unsigned char *s;
1084
1085   s = JPOOL_UTF_DATA (jcf, name_index);
1086   len = JPOOL_UTF_LENGTH (jcf, name_index);
1087   add_namelet (s, s + len, &root);
1088
1089   if (root.subnamelets)
1090     {
1091       fputs ("extern \"Java\"\n{\n", out);
1092       /* We use an initial offset of 0 because the root namelet
1093          doesn't cause anything to print.  */
1094       print_namelet (out, &root, 0);
1095       fputs ("};\n\n", out);
1096     }
1097 }
1098
1099 \f
1100
1101 static void
1102 DEFUN(process_file, (jcf, out),
1103       JCF *jcf AND FILE *out)
1104 {
1105   int code, i;
1106   uint32 field_start, method_end, method_start;
1107
1108   current_jcf = main_jcf = jcf;
1109
1110   last_access = -1;
1111
1112   if (jcf_parse_preamble (jcf) != 0)
1113     {
1114       fprintf (stderr, "Not a valid Java .class file.\n");
1115       found_error = 1;
1116       return;
1117     }
1118
1119   /* Parse and possibly print constant pool */
1120   code = jcf_parse_constant_pool (jcf);
1121   if (code != 0)
1122     {
1123       fprintf (stderr, "error while parsing constant pool\n");
1124       found_error = 1;
1125       return;
1126     }
1127   code = verify_constant_pool (jcf);
1128   if (code > 0)
1129     {
1130       fprintf (stderr, "error in constant pool entry #%d\n", code);
1131       found_error = 1;
1132       return;
1133     }
1134
1135   jcf_parse_class (jcf);
1136
1137   if (written_class_count++ == 0 && out)
1138     fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
1139            out);
1140
1141   if (out)
1142     {
1143       print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
1144       fprintf (out, "__\n");
1145
1146       print_mangled_classname (out, jcf, "#define __", jcf->this_class);
1147       fprintf (out, "__\n\n");
1148
1149       /* We do this to ensure that inline methods won't be `outlined'
1150          by g++.  This works as long as method and fields are not
1151          added by the user.  */
1152       fprintf (out, "#pragma interface\n");
1153     }
1154
1155   if (jcf->super_class && out)
1156     {
1157       int super_length;
1158       unsigned char *supername = super_class_name (jcf, &super_length);
1159
1160       fputs ("\n", out);
1161       print_include (out, supername, super_length);
1162     }
1163
1164   /* We want to parse the methods first.  But we need to find where
1165      they start.  So first we skip the fields, then parse the methods.
1166      Then we parse the fields and skip the methods.  This is ugly, but
1167      not too bad since we need two full passes to get class decl
1168      information anyway.  */
1169   field_pass = 0;
1170   field_start = JCF_TELL (jcf);
1171   jcf_parse_fields (jcf);
1172
1173   method_start = JCF_TELL (jcf);
1174   method_pass = 0;
1175   jcf_parse_methods (jcf);
1176
1177   if (out)
1178     {
1179       fputs ("\n", out);
1180       print_class_decls (out, jcf, jcf->this_class);
1181
1182       for (i = 0; i < prepend_count; ++i)
1183         fprintf (out, "%s\n", prepend_specs[i]);
1184       if (prepend_count > 0)
1185         fputc ('\n', out);
1186     }
1187
1188   if (out && ! print_cxx_classname (out, "class ", jcf, jcf->this_class))
1189     {
1190       fprintf (stderr, "class is of array type\n");
1191       found_error = 1;
1192       return;
1193     }
1194   if (out && jcf->super_class)
1195     {
1196       if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class))
1197         {
1198           fprintf (stderr, "base class is of array type\n");
1199           found_error = 1;
1200           return;
1201         }
1202     }
1203   if (out)
1204     fputs ("\n{\n", out);
1205
1206   /* Now go back for second pass over methods and fields.  */
1207   JCF_SEEK (jcf, method_start);
1208   method_pass = 1;
1209   jcf_parse_methods (jcf);
1210   method_end = JCF_TELL (jcf);
1211
1212   field_pass = 1;
1213   JCF_SEEK (jcf, field_start);
1214   jcf_parse_fields (jcf);
1215   JCF_SEEK (jcf, method_end);
1216
1217   jcf_parse_final_attributes (jcf);
1218
1219   if (out)
1220     {
1221       /* Generate friend decl if we still must.  */
1222       for (i = 0; i < friend_count; ++i)
1223         fprintf (out, "  friend %s\n", friend_specs[i]);
1224
1225       /* Generate extra declarations.  */
1226       if (add_count > 0)
1227         fputc ('\n', out);
1228       for (i = 0; i < add_count; ++i)
1229         fprintf (out, "  %s\n", add_specs[i]);
1230
1231       fputs ("};\n", out);
1232
1233       if (append_count > 0)
1234         fputc ('\n', out);
1235       for (i = 0; i < append_count; ++i)
1236         fprintf (out, "%s\n", append_specs[i]);
1237
1238       print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class);
1239       fprintf (out, "__ */\n");
1240     }
1241 }
1242
1243 static void
1244 usage ()
1245 {
1246   fprintf (stderr, "gcjh: no classes specified\n");
1247   exit (1);
1248 }
1249
1250 static void
1251 help ()
1252 {
1253   printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
1254   printf ("Generate C++ header files from .class files\n\n");
1255   printf ("  --classpath PATH        Set path to find .class files\n");
1256   printf ("  --CLASSPATH PATH        Set path to find .class files\n");
1257   printf ("  -IDIR                   Append directory to class path\n");
1258   printf ("  -d DIRECTORY            Set output directory name\n");
1259   printf ("  --help                  Print this help, then exit\n");
1260   printf ("  -o FILE                 Set output file name\n");
1261   printf ("  -td DIRECTORY           Set temporary directory name\n");
1262   printf ("  -v, --verbose           Print extra information while running\n");
1263   printf ("  --version               Print version number, then exit\n");
1264   /* FIXME: print bug-report information.  */
1265   exit (0);
1266 }
1267
1268 static void
1269 java_no_argument (opt)
1270      char *opt;
1271 {
1272   fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
1273   exit (1);
1274 }
1275
1276 static void
1277 version ()
1278 {
1279   /* FIXME: use version.c?  */
1280   printf ("gcjh (GNU gcc) 0.0\n\n");
1281   printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n");
1282   printf ("This is free software; see the source for copying conditions.  There is NO\n");
1283   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
1284   exit (0);
1285 }
1286
1287 int
1288 DEFUN(main, (argc, argv),
1289       int argc AND char** argv)
1290 {
1291   JCF jcf;
1292   int argi;
1293   char *output_file = NULL;
1294   int emit_dependencies = 0, suppress_output = 0;
1295
1296   if (argc <= 1)
1297     usage ();
1298
1299   jcf_path_init ();
1300
1301   for (argi = 1; argi < argc; argi++)
1302     {
1303       char *arg = argv[argi];
1304
1305       if (arg[0] != '-' || ! strcmp (arg, "--"))
1306         break;
1307
1308       /* Just let all arguments be given in either "-" or "--" form.  */
1309       if (arg[1] == '-')
1310         ++arg;
1311
1312       if (strcmp (arg, "-o") == 0)
1313         {
1314           if (argi + 1 < argc)
1315             output_file = argv[++argi];
1316           else
1317             java_no_argument (argv[argi]);
1318         }
1319       else if (strcmp (arg, "-d") == 0)
1320         {
1321           if (argi + 1 < argc)
1322             output_directory = argv[++argi];
1323           else
1324             java_no_argument (argv[argi]);
1325         }
1326       else if (strcmp (arg, "-td") == 0)
1327         {
1328           if (argi + 1 < argc)
1329             temp_directory = argv[++argi];
1330           else
1331             java_no_argument (argv[argi]);
1332         }
1333       else if (strcmp (arg, "-prepend") == 0)
1334         {
1335           if (argi + 1 < argc)
1336             {
1337               if (prepend_count == 0)
1338                 prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1339               prepend_specs[prepend_count++] = argv[++argi];
1340             }
1341           else
1342             java_no_argument (argv[argi]);
1343         }
1344       else if (strcmp (arg, "-friend") == 0)
1345         {
1346           if (argi + 1 < argc)
1347             {
1348               if (friend_count == 0)
1349                 friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1350               friend_specs[friend_count++] = argv[++argi];
1351             }
1352           else
1353             java_no_argument (argv[argi]);
1354         }
1355       else if (strcmp (arg, "-add") == 0)
1356         {
1357           if (argi + 1 < argc)
1358             {
1359               if (add_count == 0)
1360                 add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1361               add_specs[add_count++] = argv[++argi];
1362             }
1363           else
1364             java_no_argument (argv[argi]);
1365         }
1366       else if (strcmp (arg, "-append") == 0)
1367         {
1368           if (argi + 1 < argc)
1369             {
1370               if (append_count == 0)
1371                 append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1372               append_specs[append_count++] = argv[++argi];
1373             }
1374           else
1375             java_no_argument (argv[argi]);
1376         }
1377       else if (strcmp (arg, "-classpath") == 0)
1378         {
1379           if (argi + 1 < argc)
1380             jcf_path_classpath_arg (argv[++argi]);
1381           else
1382             java_no_argument (argv[argi]);
1383         }
1384       else if (strcmp (arg, "-CLASSPATH") == 0)
1385         {
1386           if (argi + 1 < argc)
1387             jcf_path_CLASSPATH_arg (argv[++argi]);
1388           else
1389             java_no_argument (argv[argi]);
1390         }
1391       else if (strncmp (arg, "-I", 2) == 0)
1392         jcf_path_include_arg (arg + 2);
1393       else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
1394         verbose++;
1395       else if (strcmp (arg, "-stubs") == 0)
1396         stubs++;
1397       else if (strcmp (arg, "-help") == 0)
1398         help ();
1399       else if (strcmp (arg, "-version") == 0)
1400         version ();
1401       else if (strcmp (arg, "-M") == 0)
1402         {
1403           emit_dependencies = 1;
1404           suppress_output = 1;
1405           jcf_dependency_init (1);
1406         }
1407       else if (strcmp (arg, "-MM") == 0)
1408         {
1409           emit_dependencies = 1;
1410           suppress_output = 1;
1411           jcf_dependency_init (0);
1412         }
1413       else if (strcmp (arg, "-MG") == 0)
1414         {
1415           fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
1416           exit (1);
1417         }
1418       else if (strcmp (arg, "-MD") == 0)
1419         {
1420           emit_dependencies = 1;
1421           jcf_dependency_init (1);
1422         }
1423       else if (strcmp (arg, "-MMD") == 0)
1424         {
1425           emit_dependencies = 1;
1426           jcf_dependency_init (0);
1427         }
1428       else
1429         {
1430           fprintf (stderr, "%s: illegal argument\n", argv[argi]);
1431           exit (1);
1432         }
1433     }
1434
1435   if (argi == argc)
1436     usage ();
1437
1438   jcf_path_seal ();
1439
1440   if (output_file && emit_dependencies)
1441     {
1442       fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
1443       exit (1);
1444     }
1445
1446   for (; argi < argc; argi++)
1447     {
1448       char *classname = argv[argi];
1449       char *classfile_name, *current_output_file;
1450
1451       if (verbose)
1452         fprintf (stderr, "Processing %s\n", classname);
1453       if (! output_file)
1454         jcf_dependency_reset ();
1455       classfile_name = find_class (classname, strlen (classname), &jcf, 0);
1456       if (classfile_name == NULL)
1457         {
1458           fprintf (stderr, "%s: no such class\n", classname);
1459           exit (1);
1460         }
1461       if (verbose)
1462         fprintf (stderr, "Found in %s\n", classfile_name);
1463       if (output_file)
1464         {
1465           if (strcmp (output_file, "-") == 0)
1466             out = stdout;
1467           else if (out == NULL)
1468             {
1469               out = fopen (output_file, "w");
1470             }
1471           if (out == NULL)
1472             {
1473               perror (output_file);
1474               exit (1);
1475             }
1476           current_output_file = output_file;
1477         }
1478       else
1479         {
1480           int dir_len = strlen (output_directory);
1481           int i, classname_length = strlen (classname);
1482           current_output_file = (char*) ALLOC (dir_len + classname_length + 4);
1483           strcpy (current_output_file, output_directory);
1484           if (dir_len > 0 && output_directory[dir_len-1] != '/')
1485             current_output_file[dir_len++] = '/';
1486           for (i = 0; classname[i] != '\0'; i++)
1487             {
1488               char ch = classname[i];
1489               if (ch == '.')
1490                 ch = '/';
1491               current_output_file[dir_len++] = ch;
1492             }
1493           if (emit_dependencies)
1494             {
1495               if (suppress_output)
1496                 {
1497                   jcf_dependency_set_dep_file ("-");
1498                   out = NULL;
1499                 }
1500               else
1501                 {
1502                   /* We use `.hd' and not `.d' to avoid clashes with
1503                      dependency tracking from straight compilation.  */
1504                   strcpy (current_output_file + dir_len, ".hd");
1505                   jcf_dependency_set_dep_file (current_output_file);
1506                 }
1507             }
1508           strcpy (current_output_file + dir_len, ".h");
1509           jcf_dependency_set_target (current_output_file);
1510           if (! suppress_output)
1511             {
1512               out = fopen (current_output_file, "w");
1513               if (out == NULL)
1514                 {
1515                   perror (current_output_file);
1516                   exit (1);
1517                 }
1518             }
1519         }
1520       process_file (&jcf, out);
1521       JCF_FINISH (&jcf);
1522       if (current_output_file != output_file)
1523         free (current_output_file);
1524       jcf_dependency_write ();
1525     }
1526
1527   if (out != NULL && out != stdout)
1528     fclose (out);
1529
1530   return found_error;
1531 }
1532
1533 /* TODO:
1534
1535  * Do whatever the javah -stubs flag does.
1536
1537  * Emit "structure forward declarations" when needed.
1538
1539  * Generate C headers, like javah
1540
1541  */