* jcf-io.c (find_class): Use saw_java_source to determine when to
[official-gcc.git] / gcc / java / gjavah.c
blobc8a9facb19caff70be358acb2786c278281c1d2d
1 /* Program to write C++-suitable header files from a Java(TM) .class
2 file. This is similar to SUN's javah.
4 Copyright (C) 1996, 1998 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
27 #include <stdio.h>
28 #include "jcf.h"
29 #ifdef __STDC__
30 #include <stdlib.h>
31 #endif
32 #include <math.h>
34 #include <string.h>
36 /* The output file. */
37 FILE *out = NULL;
39 /* Nonzero on failure. */
40 static int found_error = 0;
42 /* Directory to place resulting files in. Set by -d option. */
43 char *output_directory = "";
45 /* Directory to place temporary file. Set by -td option. Currently unused. */
46 char *temp_directory = "/tmp";
48 /* Number of friend functions we have to declare. */
49 static int friend_count;
51 /* A class can optionally have a `friend' function declared. If
52 non-NULL, this is that function. */
53 static char **friend_specs = NULL;
55 /* Number of lines we are prepending before the class. */
56 static int prepend_count;
58 /* We can prepend extra lines before the class's start. */
59 static char **prepend_specs = NULL;
61 /* Number of lines we are appending at the end of the class. */
62 static int add_count;
64 /* We can append extra lines just before the class's end. */
65 static char **add_specs = NULL;
67 /* Number of lines we are appending after the class. */
68 static int append_count;
70 /* We can append extra lines after the class's end. */
71 static char **append_specs = NULL;
73 int verbose = 0;
75 int stubs = 0;
77 struct JCF *current_jcf;
78 struct JCF *main_jcf;
80 /* This holds access information for the last field we examined. They
81 let us generate "private:", "public:", and "protected:" properly.
82 If 0 then we haven't previously examined any field. */
83 static JCF_u2 last_access;
85 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
87 /* We keep a linked list of all method names we have seen. This lets
88 us determine if a method name and a field name are in conflict. */
89 struct method_name
91 unsigned char *name;
92 int length;
93 struct method_name *next;
96 /* List of method names we've seen. */
97 static struct method_name *method_name_list;
99 static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
100 static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2));
101 static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int, char *));
103 JCF_u2 current_field_name;
104 JCF_u2 current_field_value;
105 JCF_u2 current_field_signature;
106 JCF_u2 current_field_flags;
108 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
109 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
110 current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
112 /* We pass over fields twice. The first time we just note the start
113 of the methods. Then we go back and parse the fields for real.
114 This is ugly. */
115 static int field_pass;
117 #define HANDLE_END_FIELD() \
118 if (out && field_pass) print_field_info (out, jcf, current_field_name, \
119 current_field_signature, \
120 current_field_flags);
122 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
124 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
125 if (out) print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS)
127 #include "jcf-reader.c"
129 /* Some useful constants. */
130 #define F_NAN_MASK 0x7f800000
131 #define D_NAN_MASK 0x7ff0000000000000LL
133 /* Return 1 if F is not Inf or NaN. */
134 static int
135 java_float_finite (f)
136 jfloat f;
138 int32 *ip = (int32 *) &f;
140 /* We happen to know that F_NAN_MASK will match all NaN values, and
141 also positive and negative infinity. That's why we only need one
142 test here. See The Java Language Specification, section 20.9. */
143 return (*ip & F_NAN_MASK) != F_NAN_MASK;
146 /* Return 1 if D is not Inf or NaN. */
147 static int
148 java_double_finite (d)
149 jdouble d;
151 int64 *ip = (int64 *) &d;
153 /* Now check for all NaNs. */
154 return (*ip & D_NAN_MASK) != D_NAN_MASK;
157 void
158 DEFUN(print_name, (stream, jcf, name_index),
159 FILE* stream AND JCF* jcf AND int name_index)
161 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
162 fprintf (stream, "<not a UTF8 constant>");
163 else
164 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
165 JPOOL_UTF_LENGTH (jcf, name_index));
168 /* Print base name of class. The base name is everything after the
169 final separator. */
171 static void
172 print_base_classname (stream, jcf, index)
173 FILE *stream;
174 JCF *jcf;
175 int index;
177 int name_index = JPOOL_USHORT1 (jcf, index);
178 int len;
179 unsigned char *s, *p, *limit;
181 s = JPOOL_UTF_DATA (jcf, name_index);
182 len = JPOOL_UTF_LENGTH (jcf, name_index);
183 limit = s + len;
184 p = s;
185 while (s < limit)
187 int c = UTF8_GET (s, limit);
188 if (c == '/')
189 p = s;
192 while (p < limit)
194 int ch = UTF8_GET (p, limit);
195 if (ch == '/')
196 fputs ("::", stream);
197 else
198 jcf_print_char (stream, ch);
202 /* Return 0 if NAME is equal to STR, nonzero otherwise. */
204 static int
205 utf8_cmp (str, length, name)
206 unsigned char *str;
207 int length;
208 char *name;
210 unsigned char *limit = str + length;
211 int i;
213 for (i = 0; name[i]; ++i)
215 int ch = UTF8_GET (str, limit);
216 if (ch != name[i])
217 return 1;
220 return str != limit;
223 /* Generate an access control keyword based on FLAGS. Returns 0 if
224 FLAGS matches the saved access information, nonzero otherwise. */
226 static void
227 generate_access (stream, flags)
228 FILE *stream;
229 JCF_u2 flags;
231 /* FIXME: Java's "protected" and "no access specifier" modes don't
232 actually map to C++ "protected". That's how we map them for now,
233 though. */
235 if (! (flags & ACC_VISIBILITY))
236 flags = ACC_PROTECTED;
238 if ((flags & ACC_VISIBILITY) == last_access)
239 return;
240 last_access = (flags & ACC_VISIBILITY);
242 switch (last_access)
244 case ACC_PUBLIC:
245 fputs ("public:\n", stream);
246 break;
247 case ACC_PRIVATE:
248 fputs ("private:\n", stream);
249 break;
250 case ACC_PROTECTED:
251 fputs ("protected:\n", stream);
252 break;
253 default:
254 found_error = 1;
255 fprintf (stream, "#error unrecognized visibility %d\n",
256 (flags & ACC_VISIBILITY));
257 break;
261 /* See if NAME is already the name of a method. */
262 static int
263 name_is_method_p (name, length)
264 unsigned char *name;
265 int length;
267 struct method_name *p;
269 for (p = method_name_list; p != NULL; p = p->next)
271 if (p->length == length && ! memcmp (p->name, name, length))
272 return 1;
274 return 0;
277 static void
278 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
279 FILE *stream AND JCF* jcf
280 AND int name_index AND int sig_index AND JCF_u2 flags)
282 char *override = NULL;
284 if (flags & ACC_FINAL)
286 if (current_field_value > 0)
288 jlong num;
289 char buffer[25];
291 generate_access (stream, flags);
292 switch (JPOOL_TAG (jcf, current_field_value))
294 case CONSTANT_Integer:
295 fputs (" static const jint ", out);
296 print_name (out, jcf, name_index);
297 fputs (" = ", out);
298 num = JPOOL_INT (jcf, current_field_value);
299 format_int (buffer, num, 10);
300 fprintf (out, "%sL;\n", buffer);
301 break;
302 case CONSTANT_Long:
303 fputs (" static const jlong ", out);
304 print_name (out, jcf, name_index);
305 fputs (" = ", out);
306 num = JPOOL_LONG (jcf, current_field_value);
307 format_int (buffer, num, 10);
308 fprintf (out, "%sLL;\n", buffer);
309 break;
310 case CONSTANT_Float:
312 jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
313 fputs (" static const jfloat ", out);
314 print_name (out, jcf, name_index);
315 if (! java_float_finite (fnum))
316 fputs (";\n", out);
317 else
318 fprintf (out, " = %.10g;\n", fnum);
320 break;
321 case CONSTANT_Double:
323 jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
324 fputs (" static const jdouble ", out);
325 print_name (out, jcf, name_index);
326 if (! java_double_finite (dnum))
327 fputs (";\n", out);
328 else
329 fprintf (out, " = %.17g;\n", dnum);
331 break;
332 default:
333 fprintf(out, " <<inappropriate constant type>>\n");
336 return;
340 generate_access (stream, flags);
341 fputs (" ", out);
342 if ((flags & ACC_STATIC))
343 fputs ("static ", out);
345 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
347 fprintf (stream, "<not a UTF8 constant>");
348 found_error = 1;
350 else
352 unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
353 int length = JPOOL_UTF_LENGTH (jcf, name_index);
355 if (name_is_method_p (name, length))
357 /* This field name matches a method. So override the name
358 with a dummy name. This is yucky, but it isn't clear
359 what else to do. FIXME: if the field is static, then
360 we'll be in real trouble. */
361 if ((flags & ACC_STATIC))
363 fprintf (stderr, "static field has same name as method\n");
364 found_error = 1;
367 override = (char *) malloc (length + 3);
368 memcpy (override, name, length);
369 strcpy (override + length, "__");
373 print_c_decl (out, jcf, name_index, sig_index, flags, 0, override);
374 fputs (";\n", out);
376 if (override)
377 free (override);
380 static void
381 DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
382 FILE *stream AND JCF* jcf
383 AND int name_index AND int sig_index AND JCF_u2 flags)
385 unsigned char *str;
386 int length, is_init = 0;
387 char *override = NULL;
389 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
390 fprintf (stream, "<not a UTF8 constant>");
391 str = JPOOL_UTF_DATA (jcf, name_index);
392 length = JPOOL_UTF_LENGTH (jcf, name_index);
393 if (str[0] == '<')
395 /* Ignore internally generated methods like <clinit>. However,
396 treat <init> as a constructor. */
397 if (! utf8_cmp (str, length, "<init>"))
398 is_init = 1;
399 else
400 return;
402 else
404 struct method_name *nn;
406 nn = (struct method_name *) malloc (sizeof (struct method_name));
407 nn->name = (char *) malloc (length);
408 memcpy (nn->name, str, length);
409 nn->length = length;
410 nn->next = method_name_list;
411 method_name_list = nn;
414 /* We can't generate a method whose name is a C++ reserved word.
415 For now the only problem has been `delete'; add more here as
416 required. We can't just ignore the function, because that will
417 cause incorrect code to be generated if the function is virtual
418 (not only for calls to this function for for other functions
419 after it in the vtbl). So we give it a dummy name instead. */
420 if (! utf8_cmp (str, length, "delete"))
422 /* If the method is static, we can safely skip it. If we don't
423 skip it then we'll have problems since the mangling will be
424 wrong. FIXME. */
425 if ((flags & ACC_STATIC))
426 return;
427 override = "__dummy_delete";
430 generate_access (stream, flags);
432 fputs (" ", out);
433 if ((flags & ACC_STATIC))
434 fputs ("static ", out);
435 else if (! (flags & ACC_FINAL) && ! (jcf->access_flags & ACC_FINAL))
437 /* Don't print `virtual' if we have a constructor. */
438 if (! is_init)
439 fputs ("virtual ", out);
441 print_c_decl (out, jcf, name_index, sig_index, flags, is_init, override);
443 /* FIXME: it would be nice to decompile small methods here. That
444 would allow for inlining. */
446 fprintf(out, ";\n");
449 /* Print one piece of a signature. Returns pointer to next parseable
450 character on success, NULL on error. */
451 static unsigned char *
452 decode_signature_piece (stream, signature, limit, need_space)
453 FILE *stream;
454 unsigned char *signature, *limit;
455 int *need_space;
457 char *ctype;
459 switch (signature[0])
461 case '[':
462 for (signature++; (signature < limit
463 && *signature >= '0'
464 && *signature <= '9'); signature++)
466 switch (*signature)
468 case 'B': ctype = "jbyteArray"; goto printit;
469 case 'C': ctype = "jcharArray"; goto printit;
470 case 'D': ctype = "jdoubleArray"; goto printit;
471 case 'F': ctype = "jfloatArray"; goto printit;
472 case 'I': ctype = "jintArray"; goto printit;
473 case 'S': ctype = "jshortArray"; goto printit;
474 case 'J': ctype = "jlongArray"; goto printit;
475 case 'Z': ctype = "jbooleanArray"; goto printit;
476 case '[': ctype = "jobjectArray"; goto printit;
477 case 'L':
478 /* We have to generate a reference to JArray here,
479 so that our output matches what the compiler
480 does. */
481 ++signature;
482 fputs ("JArray<", stream);
483 while (signature < limit && *signature != ';')
485 int ch = UTF8_GET (signature, limit);
486 if (ch == '/')
487 fputs ("::", stream);
488 else
489 jcf_print_char (stream, ch);
491 fputs (" *> *", stream);
492 *need_space = 0;
493 ++signature;
494 break;
495 default:
496 /* Unparseable signature. */
497 return NULL;
499 break;
501 case '(':
502 case ')':
503 /* This shouldn't happen. */
504 return NULL;
506 case 'B': ctype = "jbyte"; goto printit;
507 case 'C': ctype = "jchar"; goto printit;
508 case 'D': ctype = "jdouble"; goto printit;
509 case 'F': ctype = "jfloat"; goto printit;
510 case 'I': ctype = "jint"; goto printit;
511 case 'J': ctype = "jlong"; goto printit;
512 case 'S': ctype = "jshort"; goto printit;
513 case 'Z': ctype = "jboolean"; goto printit;
514 case 'V': ctype = "void"; goto printit;
515 case 'L':
516 ++signature;
517 while (*signature && *signature != ';')
519 int ch = UTF8_GET (signature, limit);
520 if (ch == '/')
521 fputs ("::", stream);
522 else
523 jcf_print_char (stream, ch);
525 fputs (" *", stream);
526 if (*signature == ';')
527 signature++;
528 *need_space = 0;
529 break;
530 default:
531 *need_space = 1;
532 jcf_print_char (stream, *signature++);
533 break;
534 printit:
535 signature++;
536 *need_space = 1;
537 fputs (ctype, stream);
538 break;
541 return signature;
544 static void
545 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init,
546 name_override),
547 FILE* stream AND JCF* jcf
548 AND int name_index AND int signature_index AND JCF_u2 flags
549 AND int is_init AND char *name_override)
551 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
553 fprintf (stream, "<not a UTF8 constant>");
554 found_error = 1;
556 else
558 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
559 unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
560 register unsigned char *str = str0;
561 unsigned char *limit = str + length;
562 int need_space = 0;
563 int is_method = str[0] == '(';
564 unsigned char *next;
566 /* If printing a method, skip to the return signature and print
567 that first. However, there is no return value if this is a
568 constructor. */
569 if (is_method && ! is_init)
571 while (str < limit)
573 int ch = *str++;
574 if (ch == ')')
575 break;
579 /* If printing a field or an ordinary method, then print the
580 "return value" now. */
581 if (! is_method || ! is_init)
583 next = decode_signature_piece (stream, str, limit, &need_space);
584 if (! next)
586 fprintf (stderr, "unparseable signature: `%s'\n", str0);
587 found_error = 1;
588 return;
592 /* Now print the name of the thing. */
593 if (need_space)
594 fputs (" ", stream);
595 if (name_override)
596 fputs (name_override, stream);
597 else if (name_index)
599 /* Declare constructors specially. */
600 if (is_init)
601 print_base_classname (stream, jcf, jcf->this_class);
602 else
603 print_name (stream, jcf, name_index);
606 if (is_method)
608 /* Have a method or a constructor. Print signature pieces
609 until done. */
610 fputs (" (", stream);
611 str = str0 + 1;
612 while (str < limit && *str != ')')
614 next = decode_signature_piece (stream, str, limit, &need_space);
615 if (! next)
617 fprintf (stderr, "unparseable signature: `%s'\n", str0);
618 found_error = 1;
619 return;
622 if (next < limit && *next != ')')
623 fputs (", ", stream);
624 str = next;
627 fputs (")", stream);
632 void
633 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
634 FILE *stream AND JCF *jcf AND char *prefix AND int index)
636 int name_index = JPOOL_USHORT1 (jcf, index);
637 fputs (prefix, stream);
638 jcf_print_utf8_replace (out,
639 JPOOL_UTF_DATA (jcf, name_index),
640 JPOOL_UTF_LENGTH (jcf, name_index),
641 '/', '_');
644 /* Print PREFIX, then a class name in C++ format. If the name refers
645 to an array, ignore it and don't print PREFIX. Returns 1 if
646 something was printed, 0 otherwise. */
647 static int
648 print_cxx_classname (stream, prefix, jcf, index)
649 FILE *stream;
650 char *prefix;
651 JCF *jcf;
652 int index;
654 int name_index = JPOOL_USHORT1 (jcf, index);
655 int len, c;
656 unsigned char *s, *p, *limit;
658 s = JPOOL_UTF_DATA (jcf, name_index);
659 len = JPOOL_UTF_LENGTH (jcf, name_index);
660 limit = s + len;
662 /* Explicitly omit arrays here. */
663 p = s;
664 c = UTF8_GET (p, limit);
665 if (c == '[')
666 return 0;
668 fputs (prefix, stream);
669 while (s < limit)
671 c = UTF8_GET (s, limit);
672 if (c == '/')
673 fputs ("::", stream);
674 else
675 jcf_print_char (stream, c);
678 return 1;
681 int written_class_count = 0;
683 /* Return name of superclass. If LEN is not NULL, fill it with length
684 of name. */
685 static unsigned char *
686 super_class_name (derived_jcf, len)
687 JCF *derived_jcf;
688 int *len;
690 int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
691 int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
692 unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index);
694 if (len)
695 *len = supername_length;
697 return supername;
700 /* Print declarations for all classes required by this class. FIXME:
701 the current implementation just prints every class name from the
702 constant pool. This is too much. We really only need to print a
703 declaration for each class which is the type of a return value, a
704 field, or an argument. */
705 static void
706 print_class_decls (out, jcf)
707 FILE *out;
708 JCF *jcf;
710 int i, seen_one = 0;
712 for (i = 1; i < JPOOL_SIZE (jcf); ++i)
714 int kind = JPOOL_TAG (jcf, i);
715 if (kind == CONSTANT_Class)
717 if (print_cxx_classname (out, "class ", jcf, i))
718 fputs (";\n", out);
719 seen_one = 1;
723 if (seen_one)
724 fputs ("\n", out);
727 static void
728 DEFUN(process_file, (jcf, out),
729 JCF *jcf AND FILE *out)
731 int code, i;
732 uint32 field_start, method_end;
734 current_jcf = main_jcf = jcf;
736 last_access = 0;
738 if (jcf_parse_preamble (jcf) != 0)
740 fprintf (stderr, "Not a valid Java .class file.\n");
741 found_error = 1;
742 return;
745 /* Parse and possibly print constant pool */
746 code = jcf_parse_constant_pool (jcf);
747 if (code != 0)
749 fprintf (stderr, "error while parsing constant pool\n");
750 found_error = 1;
751 return;
753 code = verify_constant_pool (jcf);
754 if (code > 0)
756 fprintf (stderr, "error in constant pool entry #%d\n", code);
757 found_error = 1;
758 return;
761 jcf_parse_class (jcf);
763 if (written_class_count++ == 0 && out)
764 fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
765 out);
767 if (out)
769 print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
770 fprintf (out, "__\n");
772 print_mangled_classname (out, jcf, "#define __", jcf->this_class);
773 fprintf (out, "__\n\n");
776 if (jcf->super_class && out)
778 int super_length;
779 unsigned char *supername = super_class_name (jcf, &super_length);
781 fputs ("#include <", out);
782 jcf_print_utf8 (out, supername, super_length);
783 fputs (".h>\n", out);
785 /* FIXME: If our superclass is Object, then we include
786 java-array.h. The right thing to do here is look at all the
787 methods and fields and see if an array is in use. Only then
788 would we need to include java-array.h. */
789 if (! utf8_cmp (supername, super_length, "java/lang/Object"))
790 fputs ("#include <java-array.h>\n", out);
792 fputs ("\n", out);
795 if (out)
797 print_class_decls (out, jcf);
799 for (i = 0; i < prepend_count; ++i)
800 fprintf (out, "%s\n", prepend_specs[i]);
801 if (prepend_count > 0)
802 fputc ('\n', out);
805 if (out && ! print_cxx_classname (out, "class ", jcf, jcf->this_class))
807 fprintf (stderr, "class is of array type\n");
808 found_error = 1;
809 return;
811 if (out && jcf->super_class)
813 if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class))
815 fprintf (stderr, "base class is of array type\n");
816 found_error = 1;
817 return;
820 if (out)
821 fputs ("\n{\n", out);
823 /* We make a single pass over the file, printing methods and fields
824 as we see them. We have to list the methods in the same order
825 that they appear in the class file, so that the Java and C++
826 vtables have the same layout. */
827 /* We want to parse the methods first. But we need to find where
828 they start. So first we skip the fields, then parse the
829 methods. Then we parse the fields and skip the methods. FIXME:
830 this is ugly. */
831 field_pass = 0;
832 field_start = JCF_TELL (jcf);
833 jcf_parse_fields (jcf);
835 jcf_parse_methods (jcf);
836 method_end = JCF_TELL (jcf);
838 field_pass = 1;
839 JCF_SEEK (jcf, field_start);
840 jcf_parse_fields (jcf);
841 JCF_SEEK (jcf, method_end);
843 jcf_parse_final_attributes (jcf);
845 if (out)
847 /* Generate friend decl if we still must. */
848 for (i = 0; i < friend_count; ++i)
849 fprintf (out, " friend %s\n", friend_specs[i]);
851 /* Generate extra declarations. */
852 if (add_count > 0)
853 fputc ('\n', out);
854 for (i = 0; i < add_count; ++i)
855 fprintf (out, " %s\n", add_specs[i]);
857 fputs ("};\n", out);
859 if (append_count > 0)
860 fputc ('\n', out);
861 for (i = 0; i < append_count; ++i)
862 fprintf (out, "%s\n", append_specs[i]);
864 print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class);
865 fprintf (out, "__ */\n");
869 static void
870 usage ()
872 fprintf (stderr, "gcjh: no classes specified\n");
873 exit (1);
876 static void
877 help ()
879 printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
880 printf ("Generate C++ header files from .class files\n\n");
881 printf (" --classpath PATH Set path to find .class files\n");
882 printf (" --CLASSPATH PATH Set path to find .class files\n");
883 printf (" -IDIR Append directory to class path\n");
884 printf (" -d DIRECTORY Set output directory name\n");
885 printf (" --help Print this help, then exit\n");
886 printf (" -o FILE Set output file name\n");
887 printf (" -td DIRECTORY Set temporary directory name\n");
888 printf (" -v, --verbose Print extra information while running\n");
889 printf (" --version Print version number, then exit\n");
890 /* FIXME: print bug-report information. */
891 exit (0);
894 static void
895 java_no_argument (opt)
896 char *opt;
898 fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
899 exit (1);
902 static void
903 version ()
905 /* FIXME: use version.c? */
906 printf ("gcjh (GNU gcc) 0.0\n\n");
907 printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n");
908 printf ("This is free software; see the source for copying conditions. There is NO\n");
909 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
910 exit (0);
914 DEFUN(main, (argc, argv),
915 int argc AND char** argv)
917 JCF jcf;
918 int argi;
919 char *output_file = NULL;
920 int emit_dependencies = 0, suppress_output = 0;
922 if (argc <= 1)
923 usage ();
925 jcf_path_init ();
927 for (argi = 1; argi < argc; argi++)
929 char *arg = argv[argi];
931 if (arg[0] != '-' || ! strcmp (arg, "--"))
932 break;
934 /* Just let all arguments be given in either "-" or "--" form. */
935 if (arg[1] == '-')
936 ++arg;
938 if (strcmp (arg, "-o") == 0)
940 if (argi + 1 < argc)
941 output_file = argv[++argi];
942 else
943 java_no_argument (argv[argi]);
945 else if (strcmp (arg, "-d") == 0)
947 if (argi + 1 < argc)
948 output_directory = argv[++argi];
949 else
950 java_no_argument (argv[argi]);
952 else if (strcmp (arg, "-td") == 0)
954 if (argi + 1 < argc)
955 temp_directory = argv[++argi];
956 else
957 java_no_argument (argv[argi]);
959 else if (strcmp (arg, "-prepend") == 0)
961 if (argi + 1 < argc)
963 if (prepend_count == 0)
964 prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
965 prepend_specs[prepend_count++] = argv[++argi];
967 else
968 java_no_argument (argv[argi]);
970 else if (strcmp (arg, "-friend") == 0)
972 if (argi + 1 < argc)
974 if (friend_count == 0)
975 friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
976 friend_specs[friend_count++] = argv[++argi];
978 else
979 java_no_argument (argv[argi]);
981 else if (strcmp (arg, "-add") == 0)
983 if (argi + 1 < argc)
985 if (add_count == 0)
986 add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
987 add_specs[add_count++] = argv[++argi];
989 else
990 java_no_argument (argv[argi]);
992 else if (strcmp (arg, "-append") == 0)
994 if (argi + 1 < argc)
996 if (append_count == 0)
997 append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
998 append_specs[append_count++] = argv[++argi];
1000 else
1001 java_no_argument (argv[argi]);
1003 else if (strcmp (arg, "-classpath") == 0)
1005 if (argi + 1 < argc)
1006 jcf_path_classpath_arg (argv[++argi]);
1007 else
1008 java_no_argument (argv[argi]);
1010 else if (strcmp (arg, "-CLASSPATH") == 0)
1012 if (argi + 1 < argc)
1013 jcf_path_CLASSPATH_arg (argv[++argi]);
1014 else
1015 java_no_argument (argv[argi]);
1017 else if (strncmp (arg, "-I", 2) == 0)
1018 jcf_path_include_arg (arg + 2);
1019 else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
1020 verbose++;
1021 else if (strcmp (arg, "-stubs") == 0)
1022 stubs++;
1023 else if (strcmp (arg, "-help") == 0)
1024 help ();
1025 else if (strcmp (arg, "-version") == 0)
1026 version ();
1027 else if (strcmp (arg, "-M") == 0)
1029 emit_dependencies = 1;
1030 suppress_output = 1;
1031 jcf_dependency_init (1);
1033 else if (strcmp (arg, "-MM") == 0)
1035 emit_dependencies = 1;
1036 suppress_output = 1;
1037 jcf_dependency_init (0);
1039 else if (strcmp (arg, "-MG") == 0)
1041 fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
1042 exit (1);
1044 else if (strcmp (arg, "-MD") == 0)
1046 emit_dependencies = 1;
1047 jcf_dependency_init (1);
1049 else if (strcmp (arg, "-MMD") == 0)
1051 emit_dependencies = 1;
1052 jcf_dependency_init (0);
1054 else
1056 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
1057 exit (1);
1061 if (argi == argc)
1062 usage ();
1064 jcf_path_seal ();
1066 if (output_file && emit_dependencies)
1068 fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
1069 exit (1);
1072 for (; argi < argc; argi++)
1074 char *classname = argv[argi];
1075 char *classfile_name, *current_output_file;
1077 if (verbose)
1078 fprintf (stderr, "Processing %s\n", classname);
1079 if (! output_file)
1080 jcf_dependency_reset ();
1081 classfile_name = find_class (classname, strlen (classname), &jcf, 1);
1082 if (classfile_name == NULL)
1084 fprintf (stderr, "%s: no such class\n", classname);
1085 exit (1);
1087 if (verbose)
1088 fprintf (stderr, "Found in %s\n", classfile_name);
1089 if (output_file)
1091 if (strcmp (output_file, "-") == 0)
1092 out = stdout;
1093 else if (out == NULL)
1095 out = fopen (output_file, "w");
1097 if (out == NULL)
1099 perror (output_file);
1100 exit (1);
1102 current_output_file = output_file;
1104 else
1106 int dir_len = strlen (output_directory);
1107 int i, classname_length = strlen (classname);
1108 current_output_file = (char*) ALLOC (dir_len + classname_length + 4);
1109 strcpy (current_output_file, output_directory);
1110 if (dir_len > 0 && output_directory[dir_len-1] != '/')
1111 current_output_file[dir_len++] = '/';
1112 for (i = 0; classname[i] != '\0'; i++)
1114 char ch = classname[i];
1115 if (ch == '.')
1116 ch = '/';
1117 current_output_file[dir_len++] = ch;
1119 if (emit_dependencies)
1121 if (suppress_output)
1123 jcf_dependency_set_dep_file ("-");
1124 out = NULL;
1126 else
1128 /* We use `.hd' and not `.d' to avoid clashes with
1129 dependency tracking from straight compilation. */
1130 strcpy (current_output_file + dir_len, ".hd");
1131 jcf_dependency_set_dep_file (current_output_file);
1134 strcpy (current_output_file + dir_len, ".h");
1135 jcf_dependency_set_target (current_output_file);
1136 if (! suppress_output)
1138 out = fopen (current_output_file, "w");
1139 if (out == NULL)
1141 perror (current_output_file);
1142 exit (1);
1146 process_file (&jcf, out);
1147 JCF_FINISH (&jcf);
1148 if (current_output_file != output_file)
1149 free (current_output_file);
1150 jcf_dependency_write ();
1153 if (out != NULL && out != stdout)
1154 fclose (out);
1156 return found_error;
1159 /* TODO:
1161 * Do whatever the javah -stubs flag does.
1163 * Emit "structure forward declarations" when needed.
1165 * Generate C headers, like javah