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