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