1 /* Program to write C++-suitable header files from a Java(TM) .class
2 file. This is similar to SUN's javah.
4 Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
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)
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.
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.
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. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
30 #include "java-opcodes.h"
33 /* The output file. */
36 /* Nonzero on failure. */
37 static int found_error
= 0;
39 /* Directory to place resulting files in. Set by -d option. */
40 const char *output_directory
= "";
42 /* Directory to place temporary file. Set by -td option. Currently unused. */
43 const char *temp_directory
= "/tmp";
45 /* Number of friend functions we have to declare. */
46 static int friend_count
;
48 /* A class can optionally have a `friend' function declared. If
49 non-NULL, this is that function. */
50 static char **friend_specs
= NULL
;
52 /* Number of lines we are prepending before the class. */
53 static int prepend_count
;
55 /* We can prepend extra lines before the class's start. */
56 static char **prepend_specs
= NULL
;
58 /* Number of lines we are appending at the end of the class. */
61 /* We can append extra lines just before the class's end. */
62 static char **add_specs
= NULL
;
64 /* Number of lines we are appending after the class. */
65 static int append_count
;
67 /* We can append extra lines after the class's end. */
68 static char **append_specs
= NULL
;
74 struct JCF
*current_jcf
;
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
;
82 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
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)))
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. */
95 struct method_name
*next
;
98 /* List of method names we've seen. */
99 static struct method_name
*method_name_list
;
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
));
107 JCF_u2 current_field_name
;
108 JCF_u2 current_field_value
;
109 JCF_u2 current_field_signature
;
110 JCF_u2 current_field_flags
;
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)
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
123 static int method_pass
;
125 #define HANDLE_END_FIELD() \
129 print_field_info (out, jcf, current_field_name, \
130 current_field_signature, \
131 current_field_flags); \
134 add_class_decl (out, jcf, current_field_signature);
136 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
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) \
144 decompiled = 0; method_printed = 0; \
146 print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS); \
149 add_class_decl (out, jcf, SIGNATURE);
151 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
152 if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
154 static int decompiled
= 0;
155 #define HANDLE_END_METHOD() \
156 if (out && method_printed) fputs (decompiled ? "\n" : ";\n", out);
158 #include "jcf-reader.c"
160 /* Some useful constants. */
161 #define F_NAN_MASK 0x7f800000
162 #define D_NAN_MASK 0x7ff0000000000000LL
164 /* Return 1 if F is not Inf or NaN. */
166 java_float_finite (f
)
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
;
181 /* Return 1 if D is not Inf or NaN. */
183 java_double_finite (d
)
192 /* Now check for all NaNs. */
193 return (u
.i
& D_NAN_MASK
) != D_NAN_MASK
;
197 DEFUN(print_name
, (stream
, jcf
, name_index
),
198 FILE* stream AND JCF
* jcf AND
int name_index
)
200 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
201 fprintf (stream
, "<not a UTF8 constant>");
203 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
, name_index
),
204 JPOOL_UTF_LENGTH (jcf
, name_index
));
207 /* Print base name of class. The base name is everything after the
211 print_base_classname (stream
, jcf
, index
)
216 int name_index
= JPOOL_USHORT1 (jcf
, index
);
218 unsigned char *s
, *p
, *limit
;
220 s
= JPOOL_UTF_DATA (jcf
, name_index
);
221 len
= JPOOL_UTF_LENGTH (jcf
, name_index
);
226 int c
= UTF8_GET (s
, limit
);
233 int ch
= UTF8_GET (p
, limit
);
235 fputs ("::", stream
);
237 jcf_print_char (stream
, ch
);
241 /* Return 0 if NAME is equal to STR, nonzero otherwise. */
244 utf8_cmp (str
, length
, name
)
249 unsigned char *limit
= str
+ length
;
252 for (i
= 0; name
[i
]; ++i
)
254 int ch
= UTF8_GET (str
, limit
);
262 /* Generate an access control keyword based on FLAGS. Returns 0 if
263 FLAGS matches the saved access information, nonzero otherwise. */
266 generate_access (stream
, flags
)
270 if ((flags
& ACC_VISIBILITY
) == last_access
)
272 last_access
= (flags
& ACC_VISIBILITY
);
277 fputs ("public: // actually package-private\n", stream
);
280 fputs ("public:\n", stream
);
283 fputs ("private:\n", stream
);
286 fputs ("public: // actually protected\n", stream
);
290 fprintf (stream
, "#error unrecognized visibility %d\n",
291 (flags
& ACC_VISIBILITY
));
296 /* See if NAME is already the name of a method. */
298 name_is_method_p (name
, length
)
302 struct method_name
*p
;
304 for (p
= method_name_list
; p
!= NULL
; p
= p
->next
)
306 if (p
->length
== length
&& ! memcmp (p
->name
, name
, length
))
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
)
317 char *override
= NULL
;
319 if (flags
& ACC_FINAL
)
321 if (current_field_value
> 0)
325 generate_access (stream
, flags
);
326 switch (JPOOL_TAG (jcf
, current_field_value
))
328 case CONSTANT_Integer
:
331 int most_negative
= 0;
332 fputs (" static const jint ", out
);
333 print_name (out
, jcf
, name_index
);
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)
343 format_int (buffer
, (jlong
) num
, 10);
344 fprintf (out
, "%sL%s;\n", buffer
, most_negative
? " - 1" : "");
350 int most_negative
= 0;
351 fputs (" static const jlong ", out
);
352 print_name (out
, jcf
, name_index
);
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
)
362 format_int (buffer
, num
, 10);
363 fprintf (out
, "%sLL%s;\n", buffer
, most_negative
? " - 1" :"");
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
))
374 fprintf (out
, " = %.10g;\n", fnum
);
377 case CONSTANT_Double
:
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
))
385 fprintf (out
, " = %.17g;\n", dnum
);
389 fprintf(out
, " <<inappropriate constant type>>\n");
396 generate_access (stream
, flags
);
398 if ((flags
& ACC_STATIC
))
399 fputs ("static ", out
);
401 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
403 fprintf (stream
, "<not a UTF8 constant>");
408 unsigned char *name
= JPOOL_UTF_DATA (jcf
, name_index
);
409 int length
= JPOOL_UTF_LENGTH (jcf
, name_index
);
411 if (name_is_method_p (name
, length
))
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
))
419 fprintf (stderr
, "static field has same name as method\n");
423 override
= (char *) malloc (length
+ 3);
424 memcpy (override
, name
, length
);
425 strcpy (override
+ length
, "__");
429 print_c_decl (out
, jcf
, name_index
, sig_index
, flags
, 0, override
);
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
)
442 int length
, is_init
= 0;
443 const char *override
= NULL
;
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] == '$')
453 /* Ignore internally generated methods like <clinit> and
454 $finit$. However, treat <init> as a constructor. */
455 if (! utf8_cmp (str
, length
, "<init>"))
457 else if (! METHOD_IS_FINAL (jcf
->access_flags
, flags
)
458 && ! (flags
& ACC_STATIC
))
460 /* FIXME: i18n bug here. Order of prints should not be
462 fprintf (stderr
, "ignored method `");
463 jcf_print_utf8 (stderr
, str
, length
);
464 fprintf (stderr
, "' marked virtual\n");
473 struct method_name
*nn
;
475 nn
= (struct method_name
*) malloc (sizeof (struct method_name
));
476 nn
->name
= (char *) malloc (length
);
477 memcpy (nn
->name
, str
, length
);
479 nn
->next
= method_name_list
;
480 method_name_list
= nn
;
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"))
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
))
497 override
= "__dummy_delete";
501 generate_access (stream
, flags
);
504 if ((flags
& ACC_STATIC
))
505 fputs ("static ", out
);
506 else if (! METHOD_IS_FINAL (jcf
->access_flags
, flags
))
508 /* Don't print `virtual' if we have a constructor. */
510 fputs ("virtual ", out
);
512 print_c_decl (out
, jcf
, name_index
, sig_index
, flags
, is_init
, override
);
514 if ((flags
& ACC_ABSTRACT
))
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. */
523 decompile_method (out
, jcf
, code_len
)
528 unsigned char *codes
= jcf
->read_ptr
;
530 uint16 name_and_type
, name
;
532 /* If the method is synchronized, don't touch it. */
533 if ((method_access
& ACC_SYNCHRONIZED
))
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
))
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
);
557 else if (code_len
== 2
558 && codes
[0] == OPCODE_aload_0
559 && codes
[1] == OPCODE_areturn
)
561 /* Found `return this'. */
562 fputs (" { return this; }", out
);
565 else if (code_len
== 1 && codes
[0] == OPCODE_return
)
567 /* Found plain `return'. */
571 else if (code_len
== 2
572 && codes
[0] == OPCODE_aconst_null
573 && codes
[1] == OPCODE_areturn
)
575 /* Found `return null'. We don't want to depend on NULL being
577 fputs (" { return 0; }", out
);
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
)
587 unsigned char *signature
, *limit
;
592 switch (signature
[0])
595 for (signature
++; (signature
< limit
597 && *signature
<= '9'); signature
++)
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
;
611 /* We have to generate a reference to JArray here,
612 so that our output matches what the compiler
615 fputs ("JArray<", stream
);
616 while (signature
< limit
&& *signature
!= ';')
618 int ch
= UTF8_GET (signature
, limit
);
620 fputs ("::", stream
);
622 jcf_print_char (stream
, ch
);
624 fputs (" *> *", stream
);
629 /* Unparseable signature. */
636 /* This shouldn't happen. */
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
;
650 while (*signature
&& *signature
!= ';')
652 int ch
= UTF8_GET (signature
, limit
);
653 /* `$' is the separator for an inner class. */
654 if (ch
== '/' || ch
== '$')
655 fputs ("::", stream
);
657 jcf_print_char (stream
, ch
);
659 fputs (" *", stream
);
660 if (*signature
== ';')
666 jcf_print_char (stream
, *signature
++);
671 fputs (ctype
, stream
);
679 DEFUN(print_c_decl
, (stream
, jcf
, name_index
, signature_index
, flags
, is_init
,
681 FILE* stream AND JCF
* jcf
682 AND
int name_index AND
int signature_index AND JCF_u2 flags
683 AND
int is_init AND
const char *name_override
)
685 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
687 fprintf (stream
, "<not a UTF8 constant>");
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
;
697 int is_method
= str
[0] == '(';
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
703 if (is_method
&& ! is_init
)
713 /* If printing a field or an ordinary method, then print the
714 "return value" now. */
715 if (! is_method
|| ! is_init
)
717 next
= decode_signature_piece (stream
, str
, limit
, &need_space
);
720 fprintf (stderr
, "unparseable signature: `%s'\n", str0
);
726 /* Now print the name of the thing. */
730 fputs (name_override
, stream
);
733 /* Declare constructors specially. */
735 print_base_classname (stream
, jcf
, jcf
->this_class
);
737 print_name (stream
, jcf
, name_index
);
742 /* Have a method or a constructor. Print signature pieces
744 fputs (" (", stream
);
746 while (str
< limit
&& *str
!= ')')
748 next
= decode_signature_piece (stream
, str
, limit
, &need_space
);
751 fprintf (stderr
, "unparseable signature: `%s'\n", str0
);
756 if (next
< limit
&& *next
!= ')')
757 fputs (", ", stream
);
767 DEFUN(print_mangled_classname
, (stream
, jcf
, prefix
, index
),
768 FILE *stream AND JCF
*jcf AND
const char *prefix AND
int index
)
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
),
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. */
782 print_cxx_classname (stream
, prefix
, jcf
, index
)
788 int name_index
= JPOOL_USHORT1 (jcf
, index
);
790 unsigned char *s
, *p
, *limit
;
792 s
= JPOOL_UTF_DATA (jcf
, name_index
);
793 len
= JPOOL_UTF_LENGTH (jcf
, name_index
);
796 /* Explicitly omit arrays here. */
798 c
= UTF8_GET (p
, limit
);
802 fputs (prefix
, stream
);
805 c
= UTF8_GET (s
, limit
);
807 fputs ("::", stream
);
809 jcf_print_char (stream
, c
);
815 int written_class_count
= 0;
817 /* Return name of superclass. If LEN is not NULL, fill it with length
819 static unsigned char *
820 super_class_name (derived_jcf
, len
)
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
);
829 *len
= supername_length
;
836 /* We keep track of all the `#include's we generate, so we can avoid
841 struct include
*next
;
844 /* List of all includes. */
845 static struct include
*all_includes
= NULL
;
847 /* Generate a #include. */
849 print_include (out
, utf8
, len
)
854 struct include
*incl
;
862 for (incl
= all_includes
; incl
; incl
= incl
->next
)
864 if (! strncmp (incl
->name
, utf8
, len
))
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
;
875 fputs ("#include <", out
);
876 jcf_print_utf8 (out
, utf8
, len
);
877 fputs (".h>\n", out
);
882 /* This is used to represent part of a package or class name. */
885 /* The text of this part of the name. */
887 /* True if this represents a 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
;
895 /* The special root namelet. */
896 static struct namelet root
=
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
908 add_namelet (name
, name_limit
, parent
)
909 unsigned char *name
, *name_limit
;
910 struct namelet
*parent
;
913 struct namelet
*n
= NULL
, *np
;
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'. */
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)))
932 for (p
= name
; p
< name_limit
&& *p
!= '/' && *p
!= '$'; ++p
)
935 /* Search for this name beneath the PARENT node. */
936 for (np
= parent
->subnamelets
; np
!= NULL
; np
= np
->next
)
938 if (! strncmp (name
, np
->name
, p
- name
))
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
;
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
);
963 /* Print a single namelet. Destroys namelets while printing. */
965 print_namelet (out
, name
, depth
)
967 struct namelet
*name
;
975 for (i
= 0; i
< depth
; ++i
)
977 fprintf (out
, "%s %s", name
->is_class
? "class" : "namespace",
979 if (name
->is_class
&& name
->subnamelets
== NULL
)
985 for (i
= 0; i
< depth
; ++i
)
991 c
= name
->subnamelets
;
994 struct namelet
*next
= c
->next
;
995 print_namelet (out
, c
, depth
+ 2);
1003 for (i
= 0; i
< depth
; ++i
)
1005 fputs ("};\n", out
);
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
1017 add_class_decl (out
, jcf
, signature
)
1022 unsigned char *s
= JPOOL_UTF_DATA (jcf
, signature
);
1023 int len
= JPOOL_UTF_LENGTH (jcf
, signature
);
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
);
1030 for (i
= 0; i
< len
; ++i
)
1032 int start
, saw_dollar
;
1034 /* If we see an array, then we include the array header. */
1037 print_include (out
, "java-array", -1);
1041 /* We're looking for `L<stuff>;' -- everything else is
1047 for (start
= ++i
; i
< len
&& s
[i
] != ';'; ++i
)
1049 if (! saw_dollar
&& s
[i
] == '$' && out
)
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
);
1062 /* If we saw an inner class, then the generated #include will
1063 declare the class. So in this case we needn't bother. */
1065 add_namelet (&s
[start
], &s
[i
], &root
);
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. */
1074 print_class_decls (out
, jcf
, self
)
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
);
1085 s
= JPOOL_UTF_DATA (jcf
, name_index
);
1086 len
= JPOOL_UTF_LENGTH (jcf
, name_index
);
1087 add_namelet (s
, s
+ len
, &root
);
1089 if (root
.subnamelets
)
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
);
1102 DEFUN(process_file
, (jcf
, out
),
1103 JCF
*jcf AND
FILE *out
)
1106 uint32 field_start
, method_end
, method_start
;
1108 current_jcf
= main_jcf
= jcf
;
1112 if (jcf_parse_preamble (jcf
) != 0)
1114 fprintf (stderr
, "Not a valid Java .class file.\n");
1119 /* Parse and possibly print constant pool */
1120 code
= jcf_parse_constant_pool (jcf
);
1123 fprintf (stderr
, "error while parsing constant pool\n");
1127 code
= verify_constant_pool (jcf
);
1130 fprintf (stderr
, "error in constant pool entry #%d\n", code
);
1135 jcf_parse_class (jcf
);
1137 if (written_class_count
++ == 0 && out
)
1138 fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
1143 print_mangled_classname (out
, jcf
, "#ifndef __", jcf
->this_class
);
1144 fprintf (out
, "__\n");
1146 print_mangled_classname (out
, jcf
, "#define __", jcf
->this_class
);
1147 fprintf (out
, "__\n\n");
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");
1155 if (jcf
->super_class
&& out
)
1158 unsigned char *supername
= super_class_name (jcf
, &super_length
);
1161 print_include (out
, supername
, super_length
);
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. */
1170 field_start
= JCF_TELL (jcf
);
1171 jcf_parse_fields (jcf
);
1173 method_start
= JCF_TELL (jcf
);
1175 jcf_parse_methods (jcf
);
1180 print_class_decls (out
, jcf
, jcf
->this_class
);
1182 for (i
= 0; i
< prepend_count
; ++i
)
1183 fprintf (out
, "%s\n", prepend_specs
[i
]);
1184 if (prepend_count
> 0)
1188 if (out
&& ! print_cxx_classname (out
, "class ", jcf
, jcf
->this_class
))
1190 fprintf (stderr
, "class is of array type\n");
1194 if (out
&& jcf
->super_class
)
1196 if (! print_cxx_classname (out
, " : public ", jcf
, jcf
->super_class
))
1198 fprintf (stderr
, "base class is of array type\n");
1204 fputs ("\n{\n", out
);
1206 /* Now go back for second pass over methods and fields. */
1207 JCF_SEEK (jcf
, method_start
);
1209 jcf_parse_methods (jcf
);
1210 method_end
= JCF_TELL (jcf
);
1213 JCF_SEEK (jcf
, field_start
);
1214 jcf_parse_fields (jcf
);
1215 JCF_SEEK (jcf
, method_end
);
1217 jcf_parse_final_attributes (jcf
);
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
]);
1225 /* Generate extra declarations. */
1228 for (i
= 0; i
< add_count
; ++i
)
1229 fprintf (out
, " %s\n", add_specs
[i
]);
1231 fputs ("};\n", out
);
1233 if (append_count
> 0)
1235 for (i
= 0; i
< append_count
; ++i
)
1236 fprintf (out
, "%s\n", append_specs
[i
]);
1238 print_mangled_classname (out
, jcf
, "\n#endif /* __", jcf
->this_class
);
1239 fprintf (out
, "__ */\n");
1246 fprintf (stderr
, "gcjh: no classes specified\n");
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. */
1269 java_no_argument (opt
)
1272 fprintf (stderr
, "gcjh: no argument given for option `%s'\n", opt
);
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");
1288 DEFUN(main
, (argc
, argv
),
1289 int argc AND
char** argv
)
1293 char *output_file
= NULL
;
1294 int emit_dependencies
= 0, suppress_output
= 0;
1301 for (argi
= 1; argi
< argc
; argi
++)
1303 char *arg
= argv
[argi
];
1305 if (arg
[0] != '-' || ! strcmp (arg
, "--"))
1308 /* Just let all arguments be given in either "-" or "--" form. */
1312 if (strcmp (arg
, "-o") == 0)
1314 if (argi
+ 1 < argc
)
1315 output_file
= argv
[++argi
];
1317 java_no_argument (argv
[argi
]);
1319 else if (strcmp (arg
, "-d") == 0)
1321 if (argi
+ 1 < argc
)
1322 output_directory
= argv
[++argi
];
1324 java_no_argument (argv
[argi
]);
1326 else if (strcmp (arg
, "-td") == 0)
1328 if (argi
+ 1 < argc
)
1329 temp_directory
= argv
[++argi
];
1331 java_no_argument (argv
[argi
]);
1333 else if (strcmp (arg
, "-prepend") == 0)
1335 if (argi
+ 1 < argc
)
1337 if (prepend_count
== 0)
1338 prepend_specs
= (char**) ALLOC ((argc
-argi
) * sizeof (char*));
1339 prepend_specs
[prepend_count
++] = argv
[++argi
];
1342 java_no_argument (argv
[argi
]);
1344 else if (strcmp (arg
, "-friend") == 0)
1346 if (argi
+ 1 < argc
)
1348 if (friend_count
== 0)
1349 friend_specs
= (char**) ALLOC ((argc
-argi
) * sizeof (char*));
1350 friend_specs
[friend_count
++] = argv
[++argi
];
1353 java_no_argument (argv
[argi
]);
1355 else if (strcmp (arg
, "-add") == 0)
1357 if (argi
+ 1 < argc
)
1360 add_specs
= (char**) ALLOC ((argc
-argi
) * sizeof (char*));
1361 add_specs
[add_count
++] = argv
[++argi
];
1364 java_no_argument (argv
[argi
]);
1366 else if (strcmp (arg
, "-append") == 0)
1368 if (argi
+ 1 < argc
)
1370 if (append_count
== 0)
1371 append_specs
= (char**) ALLOC ((argc
-argi
) * sizeof (char*));
1372 append_specs
[append_count
++] = argv
[++argi
];
1375 java_no_argument (argv
[argi
]);
1377 else if (strcmp (arg
, "-classpath") == 0)
1379 if (argi
+ 1 < argc
)
1380 jcf_path_classpath_arg (argv
[++argi
]);
1382 java_no_argument (argv
[argi
]);
1384 else if (strcmp (arg
, "-CLASSPATH") == 0)
1386 if (argi
+ 1 < argc
)
1387 jcf_path_CLASSPATH_arg (argv
[++argi
]);
1389 java_no_argument (argv
[argi
]);
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)
1395 else if (strcmp (arg
, "-stubs") == 0)
1397 else if (strcmp (arg
, "-help") == 0)
1399 else if (strcmp (arg
, "-version") == 0)
1401 else if (strcmp (arg
, "-M") == 0)
1403 emit_dependencies
= 1;
1404 suppress_output
= 1;
1405 jcf_dependency_init (1);
1407 else if (strcmp (arg
, "-MM") == 0)
1409 emit_dependencies
= 1;
1410 suppress_output
= 1;
1411 jcf_dependency_init (0);
1413 else if (strcmp (arg
, "-MG") == 0)
1415 fprintf (stderr
, "gcjh: `%s' option is unimplemented\n", argv
[argi
]);
1418 else if (strcmp (arg
, "-MD") == 0)
1420 emit_dependencies
= 1;
1421 jcf_dependency_init (1);
1423 else if (strcmp (arg
, "-MMD") == 0)
1425 emit_dependencies
= 1;
1426 jcf_dependency_init (0);
1430 fprintf (stderr
, "%s: illegal argument\n", argv
[argi
]);
1440 if (output_file
&& emit_dependencies
)
1442 fprintf (stderr
, "gcjh: can't specify both -o and -MD\n");
1446 for (; argi
< argc
; argi
++)
1448 char *classname
= argv
[argi
];
1449 char *classfile_name
, *current_output_file
;
1452 fprintf (stderr
, "Processing %s\n", classname
);
1454 jcf_dependency_reset ();
1455 classfile_name
= find_class (classname
, strlen (classname
), &jcf
, 0);
1456 if (classfile_name
== NULL
)
1458 fprintf (stderr
, "%s: no such class\n", classname
);
1462 fprintf (stderr
, "Found in %s\n", classfile_name
);
1465 if (strcmp (output_file
, "-") == 0)
1467 else if (out
== NULL
)
1469 out
= fopen (output_file
, "w");
1473 perror (output_file
);
1476 current_output_file
= output_file
;
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
++)
1488 char ch
= classname
[i
];
1491 current_output_file
[dir_len
++] = ch
;
1493 if (emit_dependencies
)
1495 if (suppress_output
)
1497 jcf_dependency_set_dep_file ("-");
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
);
1508 strcpy (current_output_file
+ dir_len
, ".h");
1509 jcf_dependency_set_target (current_output_file
);
1510 if (! suppress_output
)
1512 out
= fopen (current_output_file
, "w");
1515 perror (current_output_file
);
1520 process_file (&jcf
, out
);
1522 if (current_output_file
!= output_file
)
1523 free (current_output_file
);
1524 jcf_dependency_write ();
1527 if (out
!= NULL
&& out
!= stdout
)
1535 * Do whatever the javah -stubs flag does.
1537 * Emit "structure forward declarations" when needed.
1539 * Generate C headers, like javah