OSDN Git Service

* gjavah.c (print_name, print_base_classname, utf8_cmp,
[pf3gnuchains/gcc-fork.git] / gcc / java / gjavah.c
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 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 "java-tree.h"
34 #include "java-opcodes.h"
35
36 #include "version.c"
37
38 /* The output file.  */
39 FILE *out = NULL;
40
41 /* Nonzero on failure.  */
42 static int found_error = 0;
43
44 /* Directory to place resulting files in. Set by -d option. */
45 const char *output_directory = "";
46
47 /* Directory to place temporary file.  Set by -td option.  Currently unused. */
48 const char *temp_directory = "/tmp";
49
50 /* Number of friend functions we have to declare.  */
51 static int friend_count;
52
53 /* A class can optionally have a `friend' function declared.  If
54    non-NULL, this is that function.  */
55 static char **friend_specs = NULL;
56
57 /* Number of lines we are prepending before the class.  */
58 static int prepend_count;
59
60 /* We can prepend extra lines before the class's start. */
61 static char **prepend_specs = NULL;
62
63 /* Number of lines we are appending at the end of the class.  */
64 static int add_count;
65
66 /* We can append extra lines just before the class's end. */
67 static char **add_specs = NULL;
68
69 /* Number of lines we are appending after the class.  */
70 static int append_count;
71
72 /* We can append extra lines after the class's end. */
73 static char **append_specs = NULL;
74
75 int verbose = 0;
76
77 int stubs = 0;
78
79 struct JCF *current_jcf;
80
81 /* This holds access information for the last field we examined.  They
82    let us generate "private:", "public:", and "protected:" properly.
83    If 0 then we haven't previously examined any field.  */
84 static JCF_u2 last_access;
85
86 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
87
88 /* Pass this macro the flags for a class and for a method.  It will
89    return true if the method should be considered `final'.  */
90 #define METHOD_IS_FINAL(Class, Method) \
91    (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
92
93 /* Pass this macro the flags for a method.  It will return true if the
94    method is native.  */
95 #define METHOD_IS_NATIVE(Method) \
96    ((Method) & ACC_NATIVE)
97
98 /* We keep a linked list of all method names we have seen.  This lets
99    us determine if a method name and a field name are in conflict.  */
100 struct method_name
101 {
102   unsigned char *name;
103   int length;
104   struct method_name *next;
105 };
106
107 /* List of method names we've seen.  */
108 static struct method_name *method_name_list;
109
110 static void print_field_info PROTO ((FILE*, JCF*, int, int, JCF_u2));
111 static void print_mangled_classname PROTO ((FILE*, JCF*, const char*, int));
112 static int  print_cxx_classname PROTO ((FILE*, const char*, JCF*, int));
113 static void print_method_info PROTO ((FILE*, JCF*, int, int, JCF_u2));
114 static void print_c_decl PROTO ((FILE*, JCF*, int, int, int, const char *));
115 static void print_stub PROTO ((FILE*, JCF*, int, int, int, const char *));
116 static void print_full_cxx_name PROTO ((FILE*, JCF*, int, int, int, const char *));
117 static void decompile_method PROTO ((FILE*, JCF*, int));
118 static void add_class_decl PROTO ((FILE*, JCF*, JCF_u2));
119
120 static int java_float_finite PROTO ((jfloat));
121 static int java_double_finite PROTO ((jdouble));
122 static void print_name PROTO ((FILE *, JCF *, int));
123 static void print_base_classname PROTO ((FILE *, JCF *, int));
124 static int utf8_cmp PROTO ((const unsigned char *, int, const char *));
125 static const char *cxx_keyword_subst PROTO ((const unsigned char *, int));
126 static void generate_access PROTO ((FILE *, JCF_u2));
127 static int name_is_method_p PROTO ((const unsigned char *, int));
128 static char *get_field_name PROTO ((JCF *, int, JCF_u2));
129 static void print_field_name PROTO ((FILE *, JCF *, int, JCF_u2));
130 static const unsigned char *super_class_name PROTO ((JCF *, int *));
131 static void print_include PROTO ((FILE *, const unsigned char *, int));
132 static const unsigned char *decode_signature_piece
133   PROTO ((FILE *, const unsigned char *, const unsigned char *, int *));
134 static void print_class_decls PROTO ((FILE *, JCF *, int));
135 static void usage PROTO ((void)) ATTRIBUTE_NORETURN;
136 static void help PROTO ((void)) ATTRIBUTE_NORETURN;
137 static void java_no_argument PROTO ((const char *)) ATTRIBUTE_NORETURN;
138 static void version PROTO ((void)) ATTRIBUTE_NORETURN;
139
140 JCF_u2 current_field_name;
141 JCF_u2 current_field_value;
142 JCF_u2 current_field_signature;
143 JCF_u2 current_field_flags;
144
145 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
146 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
147   current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
148
149 /* We pass over fields twice.  The first time we just note the types
150    of the fields and then the start of the methods.  Then we go back
151    and parse the fields for real.  This is ugly.  */
152 static int field_pass;
153 /* Likewise we pass over methods twice.  The first time we generate
154    class decl information; the second time we generate actual method
155    decls.  */
156 static int method_pass;
157
158 #define HANDLE_END_FIELD()                                                    \
159   if (field_pass)                                                             \
160     {                                                                         \
161       if (out && ! stubs)                                                     \
162         print_field_info (out, jcf, current_field_name,                       \
163                           current_field_signature,                            \
164                           current_field_flags);                               \
165     }                                                                         \
166   else                                                                        \
167     if (! stubs) add_class_decl (out, jcf, current_field_signature);
168
169 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
170
171 static int method_declared = 0;
172 static int method_access = 0;
173 static int method_printed = 0;
174 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)         \
175   if (method_pass)                                                            \
176     {                                                                         \
177       decompiled = 0; method_printed = 0;                                     \
178       if (out)                                                                \
179         print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS);          \
180     }                                                                         \
181   else                                                                        \
182     if (! stubs) add_class_decl (out, jcf, SIGNATURE);
183
184 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
185   if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
186
187 static int decompiled = 0;
188 #define HANDLE_END_METHOD() \
189   if (out && method_printed) fputs (decompiled || stubs ? "\n" : ";\n", out);
190
191 #include "jcf-reader.c"
192
193 /* Some useful constants.  */
194 #define F_NAN_MASK 0x7f800000
195 #define D_NAN_MASK 0x7ff0000000000000LL
196
197 /* Return 1 if F is not Inf or NaN.  */
198 static int
199 java_float_finite (f)
200      jfloat f;
201 {
202   union {
203     jfloat f;
204     int32 i;
205   } u;
206   u.f = f;
207
208   /* We happen to know that F_NAN_MASK will match all NaN values, and
209      also positive and negative infinity.  That's why we only need one
210      test here.  See The Java Language Specification, section 20.9.  */
211   return (u.i & F_NAN_MASK) != F_NAN_MASK;
212 }
213
214 /* Return 1 if D is not Inf or NaN.  */
215 static int
216 java_double_finite (d)
217      jdouble d;
218 {
219   union {
220     jdouble d;
221     int64 i;
222   } u;
223   u.d = d;
224
225   /* Now check for all NaNs.  */
226   return (u.i & D_NAN_MASK) != D_NAN_MASK;
227 }
228
229 static void
230 DEFUN(print_name, (stream, jcf, name_index),
231       FILE* stream AND JCF* jcf AND int name_index)
232 {
233   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
234     fprintf (stream, "<not a UTF8 constant>");
235   else
236     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
237                     JPOOL_UTF_LENGTH (jcf, name_index));
238 }
239
240 /* Print base name of class.  The base name is everything after the
241    final separator.  */
242
243 static void
244 print_base_classname (stream, jcf, index)
245      FILE *stream;
246      JCF *jcf;
247      int index;
248 {
249   int name_index = JPOOL_USHORT1 (jcf, index);
250   int len;
251   const unsigned char *s, *p, *limit;
252
253   s = JPOOL_UTF_DATA (jcf, name_index);
254   len = JPOOL_UTF_LENGTH (jcf, name_index);
255   limit = s + len;
256   p = s;
257   while (s < limit)
258     {
259       int c = UTF8_GET (s, limit);
260       if (c == '/')
261         p = s;
262     }
263
264   while (p < limit)
265     {
266       int ch = UTF8_GET (p, limit);
267       if (ch == '/')
268         fputs ("::", stream);
269       else
270         jcf_print_char (stream, ch);
271     }
272 }
273
274 /* Return 0 if NAME is equal to STR, nonzero otherwise.  */
275
276 static int
277 utf8_cmp (str, length, name)
278      const unsigned char *str;
279      int length;
280      const char *name;
281 {
282   const unsigned char *limit = str + length;
283   int i;
284
285   for (i = 0; name[i]; ++i)
286     {
287       int ch = UTF8_GET (str, limit);
288       if (ch != name[i])
289         return 1;
290     }
291
292   return str != limit;
293 }
294
295 /* If NAME is the name of a C++ keyword, then return an override name.
296    This is a name that can be used in place of the keyword.
297    Otherwise, return NULL.  FIXME: for now, we only handle those
298    keywords we know to be a problem for libgcj.  */
299
300 static const char *
301 cxx_keyword_subst (str, length)
302      const unsigned char *str;
303      int length;
304 {
305   if (! utf8_cmp (str, length, "delete"))
306     return "__dummy_delete";
307   else if (! utf8_cmp (str, length, "enum"))
308     return "__dummy_enum";
309   return NULL;
310 }
311
312 /* Generate an access control keyword based on FLAGS.  Returns 0 if
313    FLAGS matches the saved access information, nonzero otherwise.  */
314
315 static void
316 generate_access (stream, flags)
317      FILE *stream;
318      JCF_u2 flags;
319 {
320   if ((flags & ACC_VISIBILITY) == last_access)
321     return;
322   last_access = (flags & ACC_VISIBILITY);
323
324   switch (last_access)
325     {
326     case 0:
327       fputs ("public: // actually package-private\n", stream);
328       break;
329     case ACC_PUBLIC:
330       fputs ("public:\n", stream);
331       break;
332     case ACC_PRIVATE:
333       fputs ("private:\n", stream);
334       break;
335     case ACC_PROTECTED:
336       fputs ("public:  // actually protected\n", stream);
337       break;
338     default:
339       found_error = 1;
340       fprintf (stream, "#error unrecognized visibility %d\n",
341                (flags & ACC_VISIBILITY));
342       break;
343     }
344 }
345
346 /* See if NAME is already the name of a method.  */
347 static int
348 name_is_method_p (name, length)
349      const unsigned char *name;
350      int length;
351 {
352   struct method_name *p;
353
354   for (p = method_name_list; p != NULL; p = p->next)
355     {
356       if (p->length == length && ! memcmp (p->name, name, length))
357         return 1;
358     }
359   return 0;
360 }
361
362 /* Get name of a field.  This handles renamings due to C++ clash.  */
363 static char *
364 get_field_name (jcf, name_index, flags)
365      JCF *jcf;
366      int name_index;
367      JCF_u2 flags;
368 {
369   unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
370   int length = JPOOL_UTF_LENGTH (jcf, name_index);
371   char *override;
372   const char *tmpconstptr;
373
374
375   if (name_is_method_p (name, length))
376     {
377       /* This field name matches a method.  So override the name with
378          a dummy name.  This is yucky, but it isn't clear what else to
379          do.  FIXME: if the field is static, then we'll be in real
380          trouble.  */
381       if ((flags & ACC_STATIC))
382         {
383           fprintf (stderr, "static field has same name as method\n");
384           found_error = 1;
385           return NULL;
386         }
387
388       override = (char *) malloc (length + 3);
389       memcpy (override, name, length);
390       strcpy (override + length, "__");
391     }
392   else if ((tmpconstptr = cxx_keyword_subst (name, length)) != NULL)
393     {
394       /* Must malloc OVERRIDE.  */
395       override = xstrdup (tmpconstptr);
396     }
397   else
398     override = NULL;
399   
400   return override;
401 }
402
403 /* Print a field name.  Convenience function for use with
404    get_field_name.  */
405 static void
406 print_field_name (stream, jcf, name_index, flags)
407      FILE *stream;
408      JCF *jcf;
409      int name_index;
410      JCF_u2 flags;
411 {
412   char *override = get_field_name (jcf, name_index, flags);
413
414   if (override)
415     {
416       fputs (override, stream);
417       free (override);
418     }
419   else
420     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
421                     JPOOL_UTF_LENGTH (jcf, name_index));
422 }
423
424 static void
425 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
426       FILE *stream AND JCF* jcf
427       AND int name_index AND int sig_index AND JCF_u2 flags)
428 {
429   char *override = NULL;
430
431   generate_access (stream, flags);
432   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
433     {
434       fprintf (stream, "<not a UTF8 constant>");
435       found_error = 1;
436       return;
437     }
438
439   if (flags & ACC_FINAL)
440     {
441       if (current_field_value > 0)
442         {
443           char buffer[25];
444           int done = 1;
445
446           switch (JPOOL_TAG (jcf, current_field_value))
447             {
448             case CONSTANT_Integer:
449               {
450                 jint num;
451                 int most_negative = 0;
452                 fputs ("  static const jint ", out);
453                 print_field_name (out, jcf, name_index, 0);
454                 fputs (" = ", out);
455                 num = JPOOL_INT (jcf, current_field_value);
456                 /* We single out the most negative number to print
457                    specially.  This avoids later warnings from g++.  */
458                 if (num == (jint) 0x80000000)
459                   {
460                     most_negative = 1;
461                     ++num;
462                   }
463                 format_int (buffer, (jlong) num, 10);
464                 fprintf (out, "%sL%s;\n", buffer, most_negative ? " - 1" : "");
465               }
466               break;
467             case CONSTANT_Long:
468               {
469                 jlong num;
470                 int most_negative = 0;
471                 fputs ("  static const jlong ", out);
472                 print_field_name (out, jcf, name_index, 0);
473                 fputs (" = ", out);
474                 num = JPOOL_LONG (jcf, current_field_value);
475                 /* We single out the most negative number to print
476                    specially..  This avoids later warnings from g++.  */
477                 if (num == (jlong) 0x8000000000000000LL)
478                   {
479                     most_negative = 1;
480                     ++num;
481                   }
482                 format_int (buffer, num, 10);
483                 fprintf (out, "%sLL%s;\n", buffer, most_negative ? " - 1" :"");
484               }
485               break;
486             case CONSTANT_Float:
487               {
488                 jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
489                 fputs ("  static const jfloat ", out);
490                 print_field_name (out, jcf, name_index, 0);
491                 if (! java_float_finite (fnum))
492                   fputs (";\n", out);
493                 else
494                   fprintf (out, " = %.10g;\n",  fnum);
495               }
496               break;
497             case CONSTANT_Double:
498               {
499                 jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
500                 fputs ("  static const jdouble ", out);
501                 print_field_name (out, jcf, name_index, 0);
502                 if (! java_double_finite (dnum))
503                   fputs (";\n", out);
504                 else
505                   fprintf (out, " = %.17g;\n",  dnum);
506               }
507               break;
508             default:
509               /* We can't print this as a constant, but we can still
510                  print something sensible.  */
511               done = 0;
512               break;
513             }
514
515           if (done)
516             return;
517         }
518     }
519
520   fputs ("  ", out);
521   if ((flags & ACC_STATIC))
522     fputs ("static ", out);
523
524   override = get_field_name (jcf, name_index, flags);
525   print_c_decl (out, jcf, name_index, sig_index, 0, override);
526   fputs (";\n", out);
527
528   if (override)
529     free (override);
530 }
531
532 static void
533 DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
534       FILE *stream AND JCF* jcf
535       AND int name_index AND int sig_index AND JCF_u2 flags)
536 {
537   const unsigned char *str;
538   int length, is_init = 0;
539   const char *override = NULL;
540
541   method_declared = 0;
542   method_access = flags;
543   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
544     fprintf (stream, "<not a UTF8 constant>");
545   str = JPOOL_UTF_DATA (jcf, name_index);
546   length = JPOOL_UTF_LENGTH (jcf, name_index);
547   if (str[0] == '<' || str[0] == '$')
548     {
549       /* Ignore internally generated methods like <clinit> and
550          $finit$.  However, treat <init> as a constructor.  */
551       if (! utf8_cmp (str, length, "<init>"))
552         is_init = 1;
553       else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
554                && ! (flags & ACC_STATIC))
555         {
556           /* FIXME: i18n bug here.  Order of prints should not be
557              fixed.  */
558           fprintf (stderr, "ignored method `");
559           jcf_print_utf8 (stderr, str, length);
560           fprintf (stderr, "' marked virtual\n");
561           found_error = 1;
562           return;
563         }
564       else
565         return;
566     }
567   else
568     {
569       struct method_name *nn;
570
571       nn = (struct method_name *) malloc (sizeof (struct method_name));
572       nn->name = (char *) malloc (length);
573       memcpy (nn->name, str, length);
574       nn->length = length;
575       nn->next = method_name_list;
576       method_name_list = nn;
577     }
578
579   /* We can't generate a method whose name is a C++ reserved word.  We
580      can't just ignore the function, because that will cause incorrect
581      code to be generated if the function is virtual (not only for
582      calls to this function for for other functions after it in the
583      vtbl).  So we give it a dummy name instead.  */
584   override = cxx_keyword_subst (str, length);
585   if (override)
586     {
587       /* If the method is static or final, we can safely skip it.  If
588          we don't skip it then we'll have problems since the mangling
589          will be wrong.  FIXME.  */
590       if (METHOD_IS_FINAL (jcf->access_flags, flags)
591           || (flags & ACC_STATIC))
592         return;
593     }
594
595   if (! stubs)
596     {
597       method_printed = 1;
598
599       generate_access (stream, flags);
600       
601       fputs ("  ", out);
602       if ((flags & ACC_STATIC))
603         fputs ("static ", out);
604       else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
605         {
606           /* Don't print `virtual' if we have a constructor.  */
607           if (! is_init)
608             fputs ("virtual ", out);
609         }
610       print_c_decl (out, jcf, name_index, sig_index, is_init, override);
611       
612       if ((flags & ACC_ABSTRACT))
613         fputs (" = 0", out);
614       else
615         method_declared = 1;
616     }
617   else
618     {
619       if (METHOD_IS_NATIVE(flags)) 
620         {
621           method_printed = 1;
622           print_stub (out, jcf, name_index, sig_index, is_init, override);
623         }
624     }
625 }
626
627 /* Try to decompile a method body.  Right now we just try to handle a
628    simple case that we can do.  Expand as desired.  */
629 static void
630 decompile_method (out, jcf, code_len)
631      FILE *out;
632      JCF *jcf;
633      int code_len;
634 {
635   const unsigned char *codes = jcf->read_ptr;
636   int index;
637   uint16 name_and_type, name;
638
639   /* If the method is synchronized, don't touch it.  */
640   if ((method_access & ACC_SYNCHRONIZED))
641     return;
642
643   if (code_len == 5
644       && codes[0] == OPCODE_aload_0
645       && codes[1] == OPCODE_getfield
646       && (codes[4] == OPCODE_areturn
647           || codes[4] == OPCODE_dreturn
648           || codes[4] == OPCODE_freturn
649           || codes[4] == OPCODE_ireturn
650           || codes[4] == OPCODE_lreturn))
651     {
652       /* Found code like `return FIELD'.  */
653       fputs (" { return ", out);
654       index = (codes[2] << 8) | codes[3];
655       /* FIXME: ensure that tag is CONSTANT_Fieldref.  */
656       /* FIXME: ensure that the field's class is this class.  */
657       name_and_type = JPOOL_USHORT2 (jcf, index);
658       /* FIXME: ensure that tag is CONSTANT_NameAndType.  */
659       name = JPOOL_USHORT1 (jcf, name_and_type);
660       print_name (out, jcf, name);
661       fputs ("; }", out);
662       decompiled = 1;
663     }
664   else if (code_len == 2
665            && codes[0] == OPCODE_aload_0
666            && codes[1] == OPCODE_areturn)
667     {
668       /* Found `return this'.  */
669       fputs (" { return this; }", out);
670       decompiled = 1;
671     }
672   else if (code_len == 1 && codes[0] == OPCODE_return)
673     {
674       /* Found plain `return'.  */
675       fputs (" { }", out);
676       decompiled = 1;
677     }
678   else if (code_len == 2
679            && codes[0] == OPCODE_aconst_null
680            && codes[1] == OPCODE_areturn)
681     {
682       /* Found `return null'.  We don't want to depend on NULL being
683          defined.  */
684       fputs (" { return 0; }", out);
685       decompiled = 1;
686     }
687 }
688
689 /* Print one piece of a signature.  Returns pointer to next parseable
690    character on success, NULL on error.  */
691 static const unsigned char *
692 decode_signature_piece (stream, signature, limit, need_space)
693      FILE *stream;
694      const unsigned char *signature, *limit;
695      int *need_space;
696 {
697   const char *ctype;
698
699   switch (signature[0])
700     {
701     case '[':
702       for (signature++; (signature < limit
703                          && *signature >= '0'
704                          && *signature <= '9'); signature++)
705         ;
706       switch (*signature)
707         {
708         case 'B': ctype = "jbyteArray";  goto printit;
709         case 'C': ctype = "jcharArray";  goto printit;
710         case 'D': ctype = "jdoubleArray";  goto printit;
711         case 'F': ctype = "jfloatArray";  goto printit;
712         case 'I': ctype = "jintArray";  goto printit;
713         case 'S': ctype = "jshortArray";  goto printit;
714         case 'J': ctype = "jlongArray";  goto printit;
715         case 'Z': ctype = "jbooleanArray";  goto printit;
716         case '[': ctype = "jobjectArray"; goto printit;
717         case 'L':
718           /* We have to generate a reference to JArray here,
719              so that our output matches what the compiler
720              does.  */
721           ++signature;
722           fputs ("JArray<", stream);
723           while (signature < limit && *signature != ';')
724             {
725               int ch = UTF8_GET (signature, limit);
726               if (ch == '/')
727                 fputs ("::", stream);
728               else
729                 jcf_print_char (stream, ch);
730             }
731           fputs (" *> *", stream);
732           *need_space = 0;
733           ++signature;
734           break;
735         default:
736           /* Unparseable signature.  */
737           return NULL;
738         }
739       break;
740
741     case '(':
742     case ')':
743       /* This shouldn't happen.  */
744       return NULL;
745
746     case 'B': ctype = "jbyte";  goto printit;
747     case 'C': ctype = "jchar";  goto printit;
748     case 'D': ctype = "jdouble";  goto printit;
749     case 'F': ctype = "jfloat";  goto printit;
750     case 'I': ctype = "jint";  goto printit;
751     case 'J': ctype = "jlong";  goto printit;
752     case 'S': ctype = "jshort";  goto printit;
753     case 'Z': ctype = "jboolean";  goto printit;
754     case 'V': ctype = "void";  goto printit;
755     case 'L':
756       ++signature;
757       while (*signature && *signature != ';')
758         {
759           int ch = UTF8_GET (signature, limit);
760           /* `$' is the separator for an inner class.  */
761           if (ch == '/' || ch == '$')
762             fputs ("::", stream);
763           else
764             jcf_print_char (stream, ch);
765         }
766       fputs (" *", stream);
767       if (*signature == ';')
768         signature++;
769       *need_space = 0;
770       break;
771     default:
772       *need_space = 1;
773       jcf_print_char (stream, *signature++);
774       break;
775     printit:
776       signature++;
777       *need_space = 1;
778       fputs (ctype, stream);
779       break;
780     }
781
782   return signature;
783 }
784
785 static void
786 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
787                      name_override),
788       FILE* stream AND JCF* jcf
789       AND int name_index AND int signature_index
790       AND int is_init AND const char *name_override)
791 {
792   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
793     {
794       fprintf (stream, "<not a UTF8 constant>");
795       found_error = 1;
796     }
797   else
798     {
799       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
800       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
801       register const  unsigned char *str = str0;
802       const unsigned char *limit = str + length;
803       int need_space = 0;
804       int is_method = str[0] == '(';
805       const unsigned char *next;
806
807       /* If printing a method, skip to the return signature and print
808          that first.  However, there is no return value if this is a
809          constructor.  */
810       if (is_method && ! is_init)
811         {
812           while (str < limit)
813             {
814               int ch = *str++;
815               if (ch == ')')
816                 break;
817             }
818         }
819
820       /* If printing a field or an ordinary method, then print the
821          "return value" now.  */
822       if (! is_method || ! is_init)
823         {
824           next = decode_signature_piece (stream, str, limit, &need_space);
825           if (! next)
826             {
827               fprintf (stderr, "unparseable signature: `%s'\n", str0);
828               found_error = 1;
829               return;
830             }
831         }
832
833       /* Now print the name of the thing.  */
834       if (need_space)
835         fputs (" ", stream);
836       print_full_cxx_name (stream, jcf, name_index, 
837                            signature_index, is_init, name_override);
838     }
839 }
840
841 // Print the unqualified method name followed by the signature.
842 static void
843 DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, name_override),
844       FILE* stream AND JCF* jcf
845       AND int name_index AND int signature_index AND int is_init 
846       AND const char *name_override)
847 {
848   int length = JPOOL_UTF_LENGTH (jcf, signature_index);
849   const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
850   register const unsigned char *str = str0;
851   const unsigned char *limit = str + length;
852   int need_space = 0;
853   int is_method = str[0] == '(';
854   const unsigned char *next;
855
856   if (name_override)
857     fputs (name_override, stream);
858   else if (name_index)
859     {
860       /* Declare constructors specially.  */
861       if (is_init)
862         print_base_classname (stream, jcf, jcf->this_class);
863       else
864         print_name (stream, jcf, name_index);
865     }
866   
867   if (is_method)
868     {
869       /* Have a method or a constructor.  Print signature pieces
870          until done.  */
871       fputs (" (", stream);
872       str = str0 + 1;
873       while (str < limit && *str != ')')
874         {
875           next = decode_signature_piece (stream, str, limit, &need_space);
876           if (! next)
877             {
878               fprintf (stderr, "unparseable signature: `%s'\n", str0);
879               found_error = 1;
880               return;
881             }
882           
883           if (next < limit && *next != ')')
884             fputs (", ", stream);
885           str = next;
886         }
887       
888       fputs (")", stream);
889     }
890 }
891       
892 static void
893 DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init,
894                      name_override),
895       FILE* stream AND JCF* jcf
896       AND int name_index AND int signature_index
897       AND int is_init AND const char *name_override)
898 {
899   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
900     {
901       fprintf (stream, "<not a UTF8 constant>");
902       found_error = 1;
903     }
904   else
905     {
906       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
907       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
908       register const unsigned char *str = str0;
909       const unsigned char *limit = str + length;
910       int need_space = 0;
911       int is_method = str[0] == '(';
912       const unsigned char *next;
913
914       /* If printing a method, skip to the return signature and print
915          that first.  However, there is no return value if this is a
916          constructor.  */
917       if (is_method && ! is_init)
918         {
919           while (str < limit)
920             {
921               int ch = *str++;
922               if (ch == ')')
923                 break;
924             }
925         }
926
927       /* If printing a field or an ordinary method, then print the
928          "return value" now.  */
929       if (! is_method || ! is_init)
930         {
931           next = decode_signature_piece (stream, str, limit, &need_space);
932           if (! next)
933             {
934               fprintf (stderr, "unparseable signature: `%s'\n", str0);
935               found_error = 1;
936               return;
937             }
938         }
939
940       /* Now print the name of the thing.  */
941       print_cxx_classname (stream, "\n", jcf, jcf->this_class);
942       fputs ("::", stream);
943       print_full_cxx_name (stream, jcf, name_index, 
944                            signature_index, is_init, name_override);
945       fputs ("\n{\n  JvFail (\"", stream);
946       print_cxx_classname (stream, "", jcf, jcf->this_class);
947       fputs ("::", stream);
948       print_full_cxx_name (stream, jcf, name_index, 
949                            signature_index, is_init, name_override);
950       fputs (" not implemented\");\n}\n\n", stream);
951     }
952 }
953
954 static void
955 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
956       FILE *stream AND JCF *jcf AND const char *prefix AND int index)
957 {
958   int name_index = JPOOL_USHORT1 (jcf, index);
959   fputs (prefix, stream);
960   jcf_print_utf8_replace (out,
961                           JPOOL_UTF_DATA (jcf, name_index),
962                           JPOOL_UTF_LENGTH (jcf, name_index),
963                           '/', '_');
964 }
965
966 /* Print PREFIX, then a class name in C++ format.  If the name refers
967    to an array, ignore it and don't print PREFIX.  Returns 1 if
968    something was printed, 0 otherwise.  */
969 static int
970 print_cxx_classname (stream, prefix, jcf, index)
971      FILE *stream;
972      const char *prefix;
973      JCF *jcf;
974      int index;
975 {
976   int name_index = JPOOL_USHORT1 (jcf, index);
977   int len, c;
978   const unsigned char *s, *p, *limit;
979
980   s = JPOOL_UTF_DATA (jcf, name_index);
981   len = JPOOL_UTF_LENGTH (jcf, name_index);
982   limit = s + len;
983
984   /* Explicitly omit arrays here.  */
985   p = s;
986   c = UTF8_GET (p, limit);
987   if (c == '[')
988     return 0;
989
990   fputs (prefix, stream);
991   while (s < limit)
992     {
993       c = UTF8_GET (s, limit);
994       if (c == '/')
995         fputs ("::", stream);
996       else
997         jcf_print_char (stream, c);
998     }
999
1000   return 1;
1001 }
1002
1003 int written_class_count = 0;
1004
1005 /* Return name of superclass.  If LEN is not NULL, fill it with length
1006    of name.  */
1007 static const unsigned char *
1008 super_class_name (derived_jcf, len)
1009      JCF *derived_jcf;
1010      int *len;
1011 {
1012   int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
1013   int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
1014   const unsigned char *supername =
1015     JPOOL_UTF_DATA (derived_jcf, supername_index);
1016
1017   if (len)
1018     *len = supername_length;
1019
1020   return supername;
1021 }
1022
1023 \f
1024
1025 /* We keep track of all the `#include's we generate, so we can avoid
1026    duplicates.  */
1027 struct include
1028 {
1029   char *name;
1030   struct include *next;
1031 };
1032
1033 /* List of all includes.  */
1034 static struct include *all_includes = NULL;
1035
1036 /* Generate a #include.  */
1037 static void
1038 print_include (out, utf8, len)
1039      FILE *out;
1040      const unsigned char *utf8;
1041      int len;
1042 {
1043   struct include *incl;
1044
1045   if (! out)
1046     return;
1047
1048   if (len == -1)
1049     len = strlen (utf8);
1050
1051   for (incl = all_includes; incl; incl = incl->next)
1052     {
1053       /* We check the length because we might have a proper prefix.  */
1054       if (len == (int) strlen (incl->name)
1055           && ! strncmp (incl->name, utf8, len))
1056         return;
1057     }
1058
1059   incl = (struct include *) malloc (sizeof (struct include));
1060   incl->name = malloc (len + 1);
1061   strncpy (incl->name, utf8, len);
1062   incl->name[len] = '\0';
1063   incl->next = all_includes;
1064   all_includes = incl;
1065
1066   fputs ("#include <", out);
1067   jcf_print_utf8 (out, utf8, len);
1068   fputs (".h>\n", out);
1069 }
1070
1071 \f
1072
1073 /* This is used to represent part of a package or class name.  */
1074 struct namelet
1075 {
1076   /* The text of this part of the name.  */
1077   char *name;
1078   /* True if this represents a class.  */
1079   int is_class;
1080   /* Linked list of all classes and packages inside this one.  */
1081   struct namelet *subnamelets;
1082   /* Pointer to next sibling.  */
1083   struct namelet *next;
1084 };
1085
1086 static void add_namelet PROTO ((const unsigned char *,
1087                                 const unsigned char *, struct namelet *));
1088 static void print_namelet PROTO ((FILE *, struct namelet *, int));
1089
1090 /* The special root namelet.  */
1091 static struct namelet root =
1092 {
1093   NULL,
1094   0,
1095   NULL,
1096   NULL
1097 };
1098
1099 /* This extracts the next name segment from the full UTF-8 encoded
1100    package or class name and links it into the tree.  It does this
1101    recursively.  */
1102 static void
1103 add_namelet (name, name_limit, parent)
1104      const unsigned char *name, *name_limit;
1105      struct namelet *parent;
1106 {
1107   const unsigned char *p;
1108   struct namelet *n = NULL, *np;
1109
1110   /* We want to skip the standard namespaces that we assume the
1111      runtime already knows about.  We only do this at the top level,
1112      though, hence the check for `root'.  */
1113   if (parent == &root)
1114     {
1115 #define JAVALANG "java/lang/"
1116 #define JAVAIO "java/io/"
1117 #define JAVAUTIL "java/util/"
1118       if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
1119            && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
1120           || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
1121               && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
1122           || (name_limit - name >= (int) sizeof (JAVAIO) - 1
1123               && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
1124         return;
1125     }
1126
1127   for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p)
1128     ;
1129
1130   /* Search for this name beneath the PARENT node.  */
1131   for (np = parent->subnamelets; np != NULL; np = np->next)
1132     {
1133       /* We check the length because we might have a proper prefix.  */
1134       if ((int) strlen (np->name) == p - name &&
1135           ! strncmp (name, np->name, p - name))
1136         {
1137           n = np;
1138           break;
1139         }
1140     }
1141
1142   if (n == NULL)
1143     {
1144       n = (struct namelet *) malloc (sizeof (struct namelet));
1145       n->name = malloc (p - name + 1);
1146       strncpy (n->name, name, p - name);
1147       n->name[p - name] = '\0';
1148       n->is_class = (p == name_limit || *p == '$');
1149       n->subnamelets = NULL;
1150       n->next = parent->subnamelets;
1151       parent->subnamelets = n;
1152     }
1153
1154   /* We recurse if there is more text, and if the trailing piece does
1155      not represent an inner class. */
1156   if (p < name_limit && *p != '$')
1157     add_namelet (p + 1, name_limit, n);
1158 }
1159
1160 /* Print a single namelet.  Destroys namelets while printing.  */
1161 static void
1162 print_namelet (out, name, depth)
1163      FILE *out;
1164      struct namelet *name;
1165      int depth;
1166 {
1167   int i, term = 0;
1168   struct namelet *c;
1169
1170   if (name->name)
1171     {
1172       for (i = 0; i < depth; ++i)
1173         fputc (' ', out);
1174       fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
1175                name->name);
1176       if (name->is_class && name->subnamelets == NULL)
1177         fputs (";\n", out);
1178       else
1179         {
1180           term = 1;
1181           fputs ("\n", out);
1182           for (i = 0; i < depth; ++i)
1183             fputc (' ', out);
1184           fputs ("{\n", out);
1185         }
1186     }
1187
1188   c = name->subnamelets;
1189   while (c != NULL)
1190     {
1191       struct namelet *next = c->next;
1192       print_namelet (out, c, depth + 2);
1193       c = next;
1194     }
1195
1196   if (name->name)
1197     {
1198       if (term)
1199         {
1200           for (i = 0; i < depth; ++i)
1201             fputc (' ', out);
1202           fputs ("};\n", out);
1203         }
1204
1205       free (name->name);
1206       free (name);
1207     }
1208 }
1209
1210 /* This is called to add some classes to the list of classes for which
1211    we need decls.  The signature argument can be a function
1212    signature.  */
1213 static void
1214 add_class_decl (out, jcf, signature)
1215      FILE *out;
1216      JCF *jcf;
1217      JCF_u2 signature;
1218 {
1219   const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
1220   int len = JPOOL_UTF_LENGTH (jcf, signature);
1221   int i;
1222   /* Name of class we are processing.  */
1223   int name_index = JPOOL_USHORT1 (jcf, jcf->this_class);
1224   int tlen = JPOOL_UTF_LENGTH (jcf, name_index);
1225   const char *tname = JPOOL_UTF_DATA (jcf, name_index);
1226
1227   for (i = 0; i < len; ++i)
1228     {
1229       int start, saw_dollar;
1230
1231       /* If we see an array, then we include the array header.  */
1232       if (s[i] == '[')
1233         {
1234           print_include (out, "java-array", -1);
1235           continue;
1236         }
1237
1238       /* We're looking for `L<stuff>;' -- everything else is
1239          ignorable.  */
1240       if (s[i] != 'L')
1241         continue;
1242
1243       saw_dollar = 0;
1244       for (start = ++i; i < len && s[i] != ';'; ++i)
1245         {
1246           if (! saw_dollar && s[i] == '$' && out)
1247             {
1248               saw_dollar = 1;
1249               /* If this class represents an inner class, then
1250                  generate a `#include' for the outer class.  However,
1251                  don't generate the include if the outer class is the
1252                  class we are processing.  */
1253               if (i - start < tlen || strncmp (&s[start], tname, i - start))
1254                 print_include (out, &s[start], i - start);
1255               break;
1256             }
1257         }
1258
1259       /* If we saw an inner class, then the generated #include will
1260          declare the class.  So in this case we needn't bother.  */
1261       if (! saw_dollar)
1262         add_namelet (&s[start], &s[i], &root);
1263     }
1264 }
1265
1266 /* Print declarations for all classes required by this class.  Any
1267    class or package in the `java' package is assumed to be handled
1268    statically in libjava; we don't generate declarations for these.
1269    This makes the generated headers a bit easier to read.  */
1270 static void
1271 print_class_decls (out, jcf, self)
1272      FILE *out;
1273      JCF *jcf;
1274      int self;
1275 {
1276   /* Make sure to always add the current class to the list of things
1277      that should be declared.  */
1278   int name_index = JPOOL_USHORT1 (jcf, self);
1279   int len;
1280   const unsigned char *s;
1281
1282   s = JPOOL_UTF_DATA (jcf, name_index);
1283   len = JPOOL_UTF_LENGTH (jcf, name_index);
1284   add_namelet (s, s + len, &root);
1285
1286   if (root.subnamelets)
1287     {
1288       fputs ("extern \"Java\"\n{\n", out);
1289       /* We use an initial offset of 0 because the root namelet
1290          doesn't cause anything to print.  */
1291       print_namelet (out, &root, 0);
1292       fputs ("};\n\n", out);
1293     }
1294 }
1295
1296 \f
1297
1298 static void
1299 DEFUN(process_file, (jcf, out),
1300       JCF *jcf AND FILE *out)
1301 {
1302   int code, i;
1303   uint32 field_start, method_end, method_start;
1304
1305   current_jcf = jcf;
1306
1307   last_access = -1;
1308
1309   if (jcf_parse_preamble (jcf) != 0)
1310     {
1311       fprintf (stderr, "Not a valid Java .class file.\n");
1312       found_error = 1;
1313       return;
1314     }
1315
1316   /* Parse and possibly print constant pool */
1317   code = jcf_parse_constant_pool (jcf);
1318   if (code != 0)
1319     {
1320       fprintf (stderr, "error while parsing constant pool\n");
1321       found_error = 1;
1322       return;
1323     }
1324   code = verify_constant_pool (jcf);
1325   if (code > 0)
1326     {
1327       fprintf (stderr, "error in constant pool entry #%d\n", code);
1328       found_error = 1;
1329       return;
1330     }
1331
1332   jcf_parse_class (jcf);
1333
1334   if (written_class_count++ == 0 && out)
1335     {
1336       if (! stubs)
1337         fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
1338                out);
1339       else
1340         {
1341           fputs ("// This file was created by `gcjh -stubs'.  It is -*- c++ -*-.
1342 //
1343 // This file is intended to give you a head start on implementing native 
1344 // methods using CNI.  
1345 // Be aware: running `gcjh -stubs' once more for this class may overwrite any 
1346 // edits you have made to this file.\n\n", out);
1347         }
1348     }
1349
1350   if (out)
1351     {
1352       if (! stubs)
1353         {
1354           print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
1355           fprintf (out, "__\n");
1356           
1357           print_mangled_classname (out, jcf, "#define __", jcf->this_class);
1358           fprintf (out, "__\n\n");
1359           
1360           /* We do this to ensure that inline methods won't be `outlined'
1361              by g++.  This works as long as method and fields are not
1362              added by the user.  */
1363           fprintf (out, "#pragma interface\n");
1364           
1365           if (jcf->super_class)
1366             {
1367               int super_length;
1368               const unsigned char *supername =
1369                 super_class_name (jcf, &super_length);
1370               
1371               fputs ("\n", out);
1372               print_include (out, supername, super_length);
1373             }
1374         }
1375       else
1376         {
1377           /* Strip off the ".class" portion of the name when printing
1378              the include file name.  */
1379           print_include (out, jcf->classname, strlen (jcf->classname) - 6);
1380         }
1381     }
1382
1383   /* We want to parse the methods first.  But we need to find where
1384      they start.  So first we skip the fields, then parse the methods.
1385      Then we parse the fields and skip the methods.  This is ugly, but
1386      not too bad since we need two full passes to get class decl
1387      information anyway.  */
1388   field_pass = 0;
1389   field_start = JCF_TELL (jcf);
1390   jcf_parse_fields (jcf);
1391
1392   method_start = JCF_TELL (jcf);
1393   method_pass = 0;
1394   jcf_parse_methods (jcf);
1395
1396   if (out)
1397     {
1398       fputs ("\n", out);
1399
1400       if (! stubs)
1401         print_class_decls (out, jcf, jcf->this_class);
1402
1403       for (i = 0; i < prepend_count; ++i)
1404         fprintf (out, "%s\n", prepend_specs[i]);
1405       if (prepend_count > 0)
1406         fputc ('\n', out);
1407       
1408       if (! stubs)
1409         {
1410           if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
1411             {
1412               fprintf (stderr, "class is of array type\n");
1413               found_error = 1;
1414               return;
1415             }
1416           if (jcf->super_class)
1417             {
1418               if (! print_cxx_classname (out, " : public ", 
1419                                          jcf, jcf->super_class))
1420                 {
1421                   fprintf (stderr, "base class is of array type\n");
1422                   found_error = 1;
1423                   return;
1424                 }
1425             }
1426
1427           fputs ("\n{\n", out);
1428         }
1429     }
1430
1431   /* Now go back for second pass over methods and fields.  */
1432   JCF_SEEK (jcf, method_start);
1433   method_pass = 1;
1434   jcf_parse_methods (jcf);
1435   method_end = JCF_TELL (jcf);
1436
1437   field_pass = 1;
1438   JCF_SEEK (jcf, field_start);
1439   jcf_parse_fields (jcf);
1440   JCF_SEEK (jcf, method_end);
1441
1442   jcf_parse_final_attributes (jcf);
1443
1444   if (out)
1445     {
1446       /* Generate friend decl if we still must.  */
1447       for (i = 0; i < friend_count; ++i)
1448         fprintf (out, "  friend %s\n", friend_specs[i]);
1449
1450       /* Generate extra declarations.  */
1451       if (add_count > 0)
1452         fputc ('\n', out);
1453       for (i = 0; i < add_count; ++i)
1454         fprintf (out, "  %s\n", add_specs[i]);
1455
1456       if (! stubs)
1457         fputs ("};\n", out);
1458
1459       if (append_count > 0)
1460         fputc ('\n', out);
1461       for (i = 0; i < append_count; ++i)
1462         fprintf (out, "%s\n", append_specs[i]);
1463
1464       if (!stubs)
1465         {
1466           print_mangled_classname (out, jcf, 
1467                                    "\n#endif /* __", jcf->this_class);
1468           fprintf (out, "__ */\n");
1469         }
1470     }
1471 }
1472
1473 static void
1474 usage ()
1475 {
1476   fprintf (stderr, "gcjh: no classes specified\n");
1477   exit (1);
1478 }
1479
1480 static void
1481 help ()
1482 {
1483   printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
1484   printf ("Generate C++ header files from .class files\n\n");
1485   printf ("  --classpath PATH        Set path to find .class files\n");
1486   printf ("  --CLASSPATH PATH        Set path to find .class files\n");
1487   printf ("  -IDIR                   Append directory to class path\n");
1488   printf ("  -d DIRECTORY            Set output directory name\n");
1489   printf ("  --help                  Print this help, then exit\n");
1490   printf ("  -o FILE                 Set output file name\n");
1491   printf ("  -stubs                  Generate a C++ implementation stub file\n");
1492   printf ("  -td DIRECTORY           Set temporary directory name\n");
1493   printf ("  -v, --verbose           Print extra information while running\n");
1494   printf ("  --version               Print version number, then exit\n");
1495   /* FIXME: print bug-report information.  */
1496   exit (0);
1497 }
1498
1499 static void
1500 java_no_argument (opt)
1501      const char *opt;
1502 {
1503   fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
1504   exit (1);
1505 }
1506
1507 static void
1508 version ()
1509 {
1510   /* FIXME: use version.c?  */
1511   printf ("gcjh (%s)\n\n", version_string);
1512   printf ("Copyright (C) 1998, 1999 Free Software Foundation, Inc.\n");
1513   printf ("This is free software; see the source for copying conditions.  There is NO\n");
1514   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
1515   exit (0);
1516 }
1517
1518 int
1519 DEFUN(main, (argc, argv),
1520       int argc AND char** argv)
1521 {
1522   JCF jcf;
1523   int argi;
1524   char *output_file = NULL;
1525   int emit_dependencies = 0, suppress_output = 0;
1526
1527   if (argc <= 1)
1528     usage ();
1529
1530   jcf_path_init ();
1531
1532   for (argi = 1; argi < argc; argi++)
1533     {
1534       char *arg = argv[argi];
1535
1536       if (arg[0] != '-' || ! strcmp (arg, "--"))
1537         break;
1538
1539       /* Just let all arguments be given in either "-" or "--" form.  */
1540       if (arg[1] == '-')
1541         ++arg;
1542
1543       if (strcmp (arg, "-o") == 0)
1544         {
1545           if (argi + 1 < argc)
1546             output_file = argv[++argi];
1547           else
1548             java_no_argument (argv[argi]);
1549         }
1550       else if (strcmp (arg, "-d") == 0)
1551         {
1552           if (argi + 1 < argc)
1553             output_directory = argv[++argi];
1554           else
1555             java_no_argument (argv[argi]);
1556         }
1557       else if (strcmp (arg, "-td") == 0)
1558         {
1559           if (argi + 1 < argc)
1560             temp_directory = argv[++argi];
1561           else
1562             java_no_argument (argv[argi]);
1563         }
1564       else if (strcmp (arg, "-prepend") == 0)
1565         {
1566           if (argi + 1 < argc)
1567             {
1568               if (prepend_count == 0)
1569                 prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1570               prepend_specs[prepend_count++] = argv[++argi];
1571             }
1572           else
1573             java_no_argument (argv[argi]);
1574         }
1575       else if (strcmp (arg, "-friend") == 0)
1576         {
1577           if (argi + 1 < argc)
1578             {
1579               if (friend_count == 0)
1580                 friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1581               friend_specs[friend_count++] = argv[++argi];
1582             }
1583           else
1584             java_no_argument (argv[argi]);
1585         }
1586       else if (strcmp (arg, "-add") == 0)
1587         {
1588           if (argi + 1 < argc)
1589             {
1590               if (add_count == 0)
1591                 add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1592               add_specs[add_count++] = argv[++argi];
1593             }
1594           else
1595             java_no_argument (argv[argi]);
1596         }
1597       else if (strcmp (arg, "-append") == 0)
1598         {
1599           if (argi + 1 < argc)
1600             {
1601               if (append_count == 0)
1602                 append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1603               append_specs[append_count++] = argv[++argi];
1604             }
1605           else
1606             java_no_argument (argv[argi]);
1607         }
1608       else if (strcmp (arg, "-classpath") == 0)
1609         {
1610           if (argi + 1 < argc)
1611             jcf_path_classpath_arg (argv[++argi]);
1612           else
1613             java_no_argument (argv[argi]);
1614         }
1615       else if (strcmp (arg, "-CLASSPATH") == 0)
1616         {
1617           if (argi + 1 < argc)
1618             jcf_path_CLASSPATH_arg (argv[++argi]);
1619           else
1620             java_no_argument (argv[argi]);
1621         }
1622       else if (strncmp (arg, "-I", 2) == 0)
1623         jcf_path_include_arg (arg + 2);
1624       else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
1625         verbose++;
1626       else if (strcmp (arg, "-stubs") == 0)
1627         stubs++;
1628       else if (strcmp (arg, "-help") == 0)
1629         help ();
1630       else if (strcmp (arg, "-version") == 0)
1631         version ();
1632       else if (strcmp (arg, "-M") == 0)
1633         {
1634           emit_dependencies = 1;
1635           suppress_output = 1;
1636           jcf_dependency_init (1);
1637         }
1638       else if (strcmp (arg, "-MM") == 0)
1639         {
1640           emit_dependencies = 1;
1641           suppress_output = 1;
1642           jcf_dependency_init (0);
1643         }
1644       else if (strcmp (arg, "-MG") == 0)
1645         {
1646           fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
1647           exit (1);
1648         }
1649       else if (strcmp (arg, "-MD") == 0)
1650         {
1651           emit_dependencies = 1;
1652           jcf_dependency_init (1);
1653         }
1654       else if (strcmp (arg, "-MMD") == 0)
1655         {
1656           emit_dependencies = 1;
1657           jcf_dependency_init (0);
1658         }
1659       else
1660         {
1661           fprintf (stderr, "%s: illegal argument\n", argv[argi]);
1662           exit (1);
1663         }
1664     }
1665
1666   if (argi == argc)
1667     usage ();
1668
1669   jcf_path_seal ();
1670
1671   if (output_file && emit_dependencies)
1672     {
1673       fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
1674       exit (1);
1675     }
1676
1677   for (; argi < argc; argi++)
1678     {
1679       char *classname = argv[argi];
1680       char *current_output_file;
1681       const char *classfile_name;
1682
1683       if (verbose)
1684         fprintf (stderr, "Processing %s\n", classname);
1685       if (! output_file)
1686         jcf_dependency_reset ();
1687       classfile_name = find_class (classname, strlen (classname), &jcf, 0);
1688       if (classfile_name == NULL)
1689         {
1690           fprintf (stderr, "%s: no such class\n", classname);
1691           exit (1);
1692         }
1693       if (verbose)
1694         fprintf (stderr, "Found in %s\n", classfile_name);
1695       if (output_file)
1696         {
1697           if (strcmp (output_file, "-") == 0)
1698             out = stdout;
1699           else if (out == NULL)
1700             {
1701               out = fopen (output_file, "w");
1702             }
1703           if (out == NULL)
1704             {
1705               perror (output_file);
1706               exit (1);
1707             }
1708           current_output_file = output_file;
1709         }
1710       else
1711         {
1712           int dir_len = strlen (output_directory);
1713           int i, classname_length = strlen (classname);
1714           current_output_file = (char*) ALLOC (dir_len + classname_length + 5);
1715           strcpy (current_output_file, output_directory);
1716           if (dir_len > 0 && output_directory[dir_len-1] != '/')
1717             current_output_file[dir_len++] = '/';
1718           for (i = 0; classname[i] != '\0'; i++)
1719             {
1720               char ch = classname[i];
1721               if (ch == '.')
1722                 ch = '/';
1723               current_output_file[dir_len++] = ch;
1724             }
1725           if (emit_dependencies)
1726             {
1727               if (suppress_output)
1728                 {
1729                   jcf_dependency_set_dep_file ("-");
1730                   out = NULL;
1731                 }
1732               else
1733                 {
1734                   /* We use `.hd' and not `.d' to avoid clashes with
1735                      dependency tracking from straight compilation.  */
1736                   strcpy (current_output_file + dir_len, ".hd");
1737                   jcf_dependency_set_dep_file (current_output_file);
1738                 }
1739             }
1740           strcpy (current_output_file + dir_len, 
1741                   stubs ? ".cc" : ".h");
1742           jcf_dependency_set_target (current_output_file);
1743           if (! suppress_output)
1744             {
1745               out = fopen (current_output_file, "w");
1746               if (out == NULL)
1747                 {
1748                   perror (current_output_file);
1749                   exit (1);
1750                 }
1751             }
1752         }
1753       process_file (&jcf, out);
1754       JCF_FINISH (&jcf);
1755       if (current_output_file != output_file)
1756         free (current_output_file);
1757       jcf_dependency_write ();
1758     }
1759
1760   if (out != NULL && out != stdout)
1761     fclose (out);
1762
1763   return found_error;
1764 }
1765
1766 /* TODO:
1767
1768  * Emit "structure forward declarations" when needed.
1769
1770  * Generate C headers, like javah
1771
1772  */
1773