xref: /openbsd/gnu/usr.bin/gcc/gcc/java/gjavah.c (revision c87b03e5)
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