OSDN Git Service

* gjavah.c, jcf-write.c, verify.c: Do not use C++ style
[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       /* Print a leading "::" so we look in the right namespace.  */
757       fputs ("::", stream);
758       ++signature;
759       while (*signature && *signature != ';')
760         {
761           int ch = UTF8_GET (signature, limit);
762           /* `$' is the separator for an inner class.  */
763           if (ch == '/' || ch == '$')
764             fputs ("::", stream);
765           else
766             jcf_print_char (stream, ch);
767         }
768       fputs (" *", stream);
769       if (*signature == ';')
770         signature++;
771       *need_space = 0;
772       break;
773     default:
774       *need_space = 1;
775       jcf_print_char (stream, *signature++);
776       break;
777     printit:
778       signature++;
779       *need_space = 1;
780       fputs (ctype, stream);
781       break;
782     }
783
784   return signature;
785 }
786
787 static void
788 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
789                      name_override),
790       FILE* stream AND JCF* jcf
791       AND int name_index AND int signature_index
792       AND int is_init AND const char *name_override)
793 {
794   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
795     {
796       fprintf (stream, "<not a UTF8 constant>");
797       found_error = 1;
798     }
799   else
800     {
801       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
802       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
803       register const  unsigned char *str = str0;
804       const unsigned char *limit = str + length;
805       int need_space = 0;
806       int is_method = str[0] == '(';
807       const unsigned char *next;
808
809       /* If printing a method, skip to the return signature and print
810          that first.  However, there is no return value if this is a
811          constructor.  */
812       if (is_method && ! is_init)
813         {
814           while (str < limit)
815             {
816               int ch = *str++;
817               if (ch == ')')
818                 break;
819             }
820         }
821
822       /* If printing a field or an ordinary method, then print the
823          "return value" now.  */
824       if (! is_method || ! is_init)
825         {
826           next = decode_signature_piece (stream, str, limit, &need_space);
827           if (! next)
828             {
829               fprintf (stderr, "unparseable signature: `%s'\n", str0);
830               found_error = 1;
831               return;
832             }
833         }
834
835       /* Now print the name of the thing.  */
836       if (need_space)
837         fputs (" ", stream);
838       print_full_cxx_name (stream, jcf, name_index, 
839                            signature_index, is_init, name_override);
840     }
841 }
842
843 /* Print the unqualified method name followed by the signature. */
844 static void
845 DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index, is_init, name_override),
846       FILE* stream AND JCF* jcf
847       AND int name_index AND int signature_index AND int is_init 
848       AND const char *name_override)
849 {
850   int length = JPOOL_UTF_LENGTH (jcf, signature_index);
851   const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
852   register const unsigned char *str = str0;
853   const unsigned char *limit = str + length;
854   int need_space = 0;
855   int is_method = str[0] == '(';
856   const unsigned char *next;
857
858   if (name_override)
859     fputs (name_override, stream);
860   else if (name_index)
861     {
862       /* Declare constructors specially.  */
863       if (is_init)
864         print_base_classname (stream, jcf, jcf->this_class);
865       else
866         print_name (stream, jcf, name_index);
867     }
868   
869   if (is_method)
870     {
871       /* Have a method or a constructor.  Print signature pieces
872          until done.  */
873       fputs (" (", stream);
874       str = str0 + 1;
875       while (str < limit && *str != ')')
876         {
877           next = decode_signature_piece (stream, str, limit, &need_space);
878           if (! next)
879             {
880               fprintf (stderr, "unparseable signature: `%s'\n", str0);
881               found_error = 1;
882               return;
883             }
884           
885           if (next < limit && *next != ')')
886             fputs (", ", stream);
887           str = next;
888         }
889       
890       fputs (")", stream);
891     }
892 }
893       
894 static void
895 DEFUN(print_stub, (stream, jcf, name_index, signature_index, is_init,
896                      name_override),
897       FILE* stream AND JCF* jcf
898       AND int name_index AND int signature_index
899       AND int is_init AND const char *name_override)
900 {
901   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
902     {
903       fprintf (stream, "<not a UTF8 constant>");
904       found_error = 1;
905     }
906   else
907     {
908       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
909       const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
910       register const unsigned char *str = str0;
911       const unsigned char *limit = str + length;
912       int need_space = 0;
913       int is_method = str[0] == '(';
914       const unsigned char *next;
915
916       /* If printing a method, skip to the return signature and print
917          that first.  However, there is no return value if this is a
918          constructor.  */
919       if (is_method && ! is_init)
920         {
921           while (str < limit)
922             {
923               int ch = *str++;
924               if (ch == ')')
925                 break;
926             }
927         }
928
929       /* If printing a field or an ordinary method, then print the
930          "return value" now.  */
931       if (! is_method || ! is_init)
932         {
933           next = decode_signature_piece (stream, str, limit, &need_space);
934           if (! next)
935             {
936               fprintf (stderr, "unparseable signature: `%s'\n", str0);
937               found_error = 1;
938               return;
939             }
940         }
941
942       /* Now print the name of the thing.  */
943       print_cxx_classname (stream, "\n", jcf, jcf->this_class);
944       fputs ("::", stream);
945       print_full_cxx_name (stream, jcf, name_index, 
946                            signature_index, is_init, name_override);
947       fputs ("\n{\n  JvFail (\"", stream);
948       print_cxx_classname (stream, "", jcf, jcf->this_class);
949       fputs ("::", stream);
950       print_full_cxx_name (stream, jcf, name_index, 
951                            signature_index, is_init, name_override);
952       fputs (" not implemented\");\n}\n\n", stream);
953     }
954 }
955
956 static void
957 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
958       FILE *stream AND JCF *jcf AND const char *prefix AND int index)
959 {
960   int name_index = JPOOL_USHORT1 (jcf, index);
961   fputs (prefix, stream);
962   jcf_print_utf8_replace (out,
963                           JPOOL_UTF_DATA (jcf, name_index),
964                           JPOOL_UTF_LENGTH (jcf, name_index),
965                           '/', '_');
966 }
967
968 /* Print PREFIX, then a class name in C++ format.  If the name refers
969    to an array, ignore it and don't print PREFIX.  Returns 1 if
970    something was printed, 0 otherwise.  */
971 static int
972 print_cxx_classname (stream, prefix, jcf, index)
973      FILE *stream;
974      const char *prefix;
975      JCF *jcf;
976      int index;
977 {
978   int name_index = JPOOL_USHORT1 (jcf, index);
979   int len, c;
980   const unsigned char *s, *p, *limit;
981
982   s = JPOOL_UTF_DATA (jcf, name_index);
983   len = JPOOL_UTF_LENGTH (jcf, name_index);
984   limit = s + len;
985
986   /* Explicitly omit arrays here.  */
987   p = s;
988   c = UTF8_GET (p, limit);
989   if (c == '[')
990     return 0;
991
992   fputs (prefix, stream);
993
994   /* Print a leading "::" so we look in the right namespace.  */
995   fputs ("::", stream);
996
997   while (s < limit)
998     {
999       c = UTF8_GET (s, limit);
1000       if (c == '/')
1001         fputs ("::", stream);
1002       else
1003         jcf_print_char (stream, c);
1004     }
1005
1006   return 1;
1007 }
1008
1009 int written_class_count = 0;
1010
1011 /* Return name of superclass.  If LEN is not NULL, fill it with length
1012    of name.  */
1013 static const unsigned char *
1014 super_class_name (derived_jcf, len)
1015      JCF *derived_jcf;
1016      int *len;
1017 {
1018   int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
1019   int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
1020   const unsigned char *supername =
1021     JPOOL_UTF_DATA (derived_jcf, supername_index);
1022
1023   if (len)
1024     *len = supername_length;
1025
1026   return supername;
1027 }
1028
1029 \f
1030
1031 /* We keep track of all the `#include's we generate, so we can avoid
1032    duplicates.  */
1033 struct include
1034 {
1035   char *name;
1036   struct include *next;
1037 };
1038
1039 /* List of all includes.  */
1040 static struct include *all_includes = NULL;
1041
1042 /* Generate a #include.  */
1043 static void
1044 print_include (out, utf8, len)
1045      FILE *out;
1046      const unsigned char *utf8;
1047      int len;
1048 {
1049   struct include *incl;
1050
1051   if (! out)
1052     return;
1053
1054   if (len == -1)
1055     len = strlen (utf8);
1056
1057   for (incl = all_includes; incl; incl = incl->next)
1058     {
1059       /* We check the length because we might have a proper prefix.  */
1060       if (len == (int) strlen (incl->name)
1061           && ! strncmp (incl->name, utf8, len))
1062         return;
1063     }
1064
1065   incl = (struct include *) malloc (sizeof (struct include));
1066   incl->name = malloc (len + 1);
1067   strncpy (incl->name, utf8, len);
1068   incl->name[len] = '\0';
1069   incl->next = all_includes;
1070   all_includes = incl;
1071
1072   fputs ("#include <", out);
1073   jcf_print_utf8 (out, utf8, len);
1074   fputs (".h>\n", out);
1075 }
1076
1077 \f
1078
1079 /* This is used to represent part of a package or class name.  */
1080 struct namelet
1081 {
1082   /* The text of this part of the name.  */
1083   char *name;
1084   /* True if this represents a class.  */
1085   int is_class;
1086   /* Linked list of all classes and packages inside this one.  */
1087   struct namelet *subnamelets;
1088   /* Pointer to next sibling.  */
1089   struct namelet *next;
1090 };
1091
1092 static void add_namelet PROTO ((const unsigned char *,
1093                                 const unsigned char *, struct namelet *));
1094 static void print_namelet PROTO ((FILE *, struct namelet *, int));
1095
1096 /* The special root namelet.  */
1097 static struct namelet root =
1098 {
1099   NULL,
1100   0,
1101   NULL,
1102   NULL
1103 };
1104
1105 /* This extracts the next name segment from the full UTF-8 encoded
1106    package or class name and links it into the tree.  It does this
1107    recursively.  */
1108 static void
1109 add_namelet (name, name_limit, parent)
1110      const unsigned char *name, *name_limit;
1111      struct namelet *parent;
1112 {
1113   const unsigned char *p;
1114   struct namelet *n = NULL, *np;
1115
1116   /* We want to skip the standard namespaces that we assume the
1117      runtime already knows about.  We only do this at the top level,
1118      though, hence the check for `root'.  */
1119   if (parent == &root)
1120     {
1121 #define JAVALANG "java/lang/"
1122 #define JAVAIO "java/io/"
1123 #define JAVAUTIL "java/util/"
1124       if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
1125            && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
1126           || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
1127               && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
1128           || (name_limit - name >= (int) sizeof (JAVAIO) - 1
1129               && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
1130         return;
1131     }
1132
1133   for (p = name; p < name_limit && *p != '/' && *p != '$'; ++p)
1134     ;
1135
1136   /* Search for this name beneath the PARENT node.  */
1137   for (np = parent->subnamelets; np != NULL; np = np->next)
1138     {
1139       /* We check the length because we might have a proper prefix.  */
1140       if ((int) strlen (np->name) == p - name &&
1141           ! strncmp (name, np->name, p - name))
1142         {
1143           n = np;
1144           break;
1145         }
1146     }
1147
1148   if (n == NULL)
1149     {
1150       n = (struct namelet *) malloc (sizeof (struct namelet));
1151       n->name = malloc (p - name + 1);
1152       strncpy (n->name, name, p - name);
1153       n->name[p - name] = '\0';
1154       n->is_class = (p == name_limit || *p == '$');
1155       n->subnamelets = NULL;
1156       n->next = parent->subnamelets;
1157       parent->subnamelets = n;
1158     }
1159
1160   /* We recurse if there is more text, and if the trailing piece does
1161      not represent an inner class. */
1162   if (p < name_limit && *p != '$')
1163     add_namelet (p + 1, name_limit, n);
1164 }
1165
1166 /* Print a single namelet.  Destroys namelets while printing.  */
1167 static void
1168 print_namelet (out, name, depth)
1169      FILE *out;
1170      struct namelet *name;
1171      int depth;
1172 {
1173   int i, term = 0;
1174   struct namelet *c;
1175
1176   if (name->name)
1177     {
1178       for (i = 0; i < depth; ++i)
1179         fputc (' ', out);
1180       fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
1181                name->name);
1182       if (name->is_class && name->subnamelets == NULL)
1183         fputs (";\n", out);
1184       else
1185         {
1186           term = 1;
1187           fputs ("\n", out);
1188           for (i = 0; i < depth; ++i)
1189             fputc (' ', out);
1190           fputs ("{\n", out);
1191         }
1192     }
1193
1194   c = name->subnamelets;
1195   while (c != NULL)
1196     {
1197       struct namelet *next = c->next;
1198       print_namelet (out, c, depth + 2);
1199       c = next;
1200     }
1201
1202   if (name->name)
1203     {
1204       if (term)
1205         {
1206           for (i = 0; i < depth; ++i)
1207             fputc (' ', out);
1208           fputs ("};\n", out);
1209         }
1210
1211       free (name->name);
1212       free (name);
1213     }
1214 }
1215
1216 /* This is called to add some classes to the list of classes for which
1217    we need decls.  The signature argument can be a function
1218    signature.  */
1219 static void
1220 add_class_decl (out, jcf, signature)
1221      FILE *out;
1222      JCF *jcf;
1223      JCF_u2 signature;
1224 {
1225   const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
1226   int len = JPOOL_UTF_LENGTH (jcf, signature);
1227   int i;
1228   /* Name of class we are processing.  */
1229   int name_index = JPOOL_USHORT1 (jcf, jcf->this_class);
1230   int tlen = JPOOL_UTF_LENGTH (jcf, name_index);
1231   const char *tname = JPOOL_UTF_DATA (jcf, name_index);
1232
1233   for (i = 0; i < len; ++i)
1234     {
1235       int start, saw_dollar;
1236
1237       /* If we see an array, then we include the array header.  */
1238       if (s[i] == '[')
1239         {
1240           print_include (out, "java-array", -1);
1241           continue;
1242         }
1243
1244       /* We're looking for `L<stuff>;' -- everything else is
1245          ignorable.  */
1246       if (s[i] != 'L')
1247         continue;
1248
1249       saw_dollar = 0;
1250       for (start = ++i; i < len && s[i] != ';'; ++i)
1251         {
1252           if (! saw_dollar && s[i] == '$' && out)
1253             {
1254               saw_dollar = 1;
1255               /* If this class represents an inner class, then
1256                  generate a `#include' for the outer class.  However,
1257                  don't generate the include if the outer class is the
1258                  class we are processing.  */
1259               if (i - start < tlen || strncmp (&s[start], tname, i - start))
1260                 print_include (out, &s[start], i - start);
1261               break;
1262             }
1263         }
1264
1265       /* If we saw an inner class, then the generated #include will
1266          declare the class.  So in this case we needn't bother.  */
1267       if (! saw_dollar)
1268         add_namelet (&s[start], &s[i], &root);
1269     }
1270 }
1271
1272 /* Print declarations for all classes required by this class.  Any
1273    class or package in the `java' package is assumed to be handled
1274    statically in libjava; we don't generate declarations for these.
1275    This makes the generated headers a bit easier to read.  */
1276 static void
1277 print_class_decls (out, jcf, self)
1278      FILE *out;
1279      JCF *jcf;
1280      int self;
1281 {
1282   /* Make sure to always add the current class to the list of things
1283      that should be declared.  */
1284   int name_index = JPOOL_USHORT1 (jcf, self);
1285   int len;
1286   const unsigned char *s;
1287
1288   s = JPOOL_UTF_DATA (jcf, name_index);
1289   len = JPOOL_UTF_LENGTH (jcf, name_index);
1290   add_namelet (s, s + len, &root);
1291
1292   if (root.subnamelets)
1293     {
1294       fputs ("extern \"Java\"\n{\n", out);
1295       /* We use an initial offset of 0 because the root namelet
1296          doesn't cause anything to print.  */
1297       print_namelet (out, &root, 0);
1298       fputs ("};\n\n", out);
1299     }
1300 }
1301
1302 \f
1303
1304 static void
1305 DEFUN(process_file, (jcf, out),
1306       JCF *jcf AND FILE *out)
1307 {
1308   int code, i;
1309   uint32 field_start, method_end, method_start;
1310
1311   current_jcf = jcf;
1312
1313   last_access = -1;
1314
1315   if (jcf_parse_preamble (jcf) != 0)
1316     {
1317       fprintf (stderr, "Not a valid Java .class file.\n");
1318       found_error = 1;
1319       return;
1320     }
1321
1322   /* Parse and possibly print constant pool */
1323   code = jcf_parse_constant_pool (jcf);
1324   if (code != 0)
1325     {
1326       fprintf (stderr, "error while parsing constant pool\n");
1327       found_error = 1;
1328       return;
1329     }
1330   code = verify_constant_pool (jcf);
1331   if (code > 0)
1332     {
1333       fprintf (stderr, "error in constant pool entry #%d\n", code);
1334       found_error = 1;
1335       return;
1336     }
1337
1338   jcf_parse_class (jcf);
1339
1340   if (written_class_count++ == 0 && out)
1341     {
1342       if (! stubs)
1343         fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n",
1344                out);
1345       else
1346         {
1347           fputs ("// This file was created by `gcjh -stubs'.  It is -*- c++ -*-.
1348 //
1349 // This file is intended to give you a head start on implementing native 
1350 // methods using CNI.  
1351 // Be aware: running `gcjh -stubs' once more for this class may overwrite any 
1352 // edits you have made to this file.\n\n", out);
1353         }
1354     }
1355
1356   if (out)
1357     {
1358       if (! stubs)
1359         {
1360           print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
1361           fprintf (out, "__\n");
1362           
1363           print_mangled_classname (out, jcf, "#define __", jcf->this_class);
1364           fprintf (out, "__\n\n");
1365           
1366           /* We do this to ensure that inline methods won't be `outlined'
1367              by g++.  This works as long as method and fields are not
1368              added by the user.  */
1369           fprintf (out, "#pragma interface\n");
1370           
1371           if (jcf->super_class)
1372             {
1373               int super_length;
1374               const unsigned char *supername =
1375                 super_class_name (jcf, &super_length);
1376               
1377               fputs ("\n", out);
1378               print_include (out, supername, super_length);
1379             }
1380         }
1381       else
1382         {
1383           /* Strip off the ".class" portion of the name when printing
1384              the include file name.  */
1385           print_include (out, jcf->classname, strlen (jcf->classname) - 6);
1386         }
1387     }
1388
1389   /* We want to parse the methods first.  But we need to find where
1390      they start.  So first we skip the fields, then parse the methods.
1391      Then we parse the fields and skip the methods.  This is ugly, but
1392      not too bad since we need two full passes to get class decl
1393      information anyway.  */
1394   field_pass = 0;
1395   field_start = JCF_TELL (jcf);
1396   jcf_parse_fields (jcf);
1397
1398   method_start = JCF_TELL (jcf);
1399   method_pass = 0;
1400   jcf_parse_methods (jcf);
1401
1402   if (out)
1403     {
1404       fputs ("\n", out);
1405
1406       if (! stubs)
1407         print_class_decls (out, jcf, jcf->this_class);
1408
1409       for (i = 0; i < prepend_count; ++i)
1410         fprintf (out, "%s\n", prepend_specs[i]);
1411       if (prepend_count > 0)
1412         fputc ('\n', out);
1413       
1414       if (! stubs)
1415         {
1416           if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
1417             {
1418               fprintf (stderr, "class is of array type\n");
1419               found_error = 1;
1420               return;
1421             }
1422           if (jcf->super_class)
1423             {
1424               if (! print_cxx_classname (out, " : public ", 
1425                                          jcf, jcf->super_class))
1426                 {
1427                   fprintf (stderr, "base class is of array type\n");
1428                   found_error = 1;
1429                   return;
1430                 }
1431             }
1432
1433           fputs ("\n{\n", out);
1434         }
1435     }
1436
1437   /* Now go back for second pass over methods and fields.  */
1438   JCF_SEEK (jcf, method_start);
1439   method_pass = 1;
1440   jcf_parse_methods (jcf);
1441   method_end = JCF_TELL (jcf);
1442
1443   field_pass = 1;
1444   JCF_SEEK (jcf, field_start);
1445   jcf_parse_fields (jcf);
1446   JCF_SEEK (jcf, method_end);
1447
1448   jcf_parse_final_attributes (jcf);
1449
1450   if (out)
1451     {
1452       /* Generate friend decl if we still must.  */
1453       for (i = 0; i < friend_count; ++i)
1454         fprintf (out, "  friend %s\n", friend_specs[i]);
1455
1456       /* Generate extra declarations.  */
1457       if (add_count > 0)
1458         fputc ('\n', out);
1459       for (i = 0; i < add_count; ++i)
1460         fprintf (out, "  %s\n", add_specs[i]);
1461
1462       if (! stubs)
1463         fputs ("};\n", out);
1464
1465       if (append_count > 0)
1466         fputc ('\n', out);
1467       for (i = 0; i < append_count; ++i)
1468         fprintf (out, "%s\n", append_specs[i]);
1469
1470       if (!stubs)
1471         {
1472           print_mangled_classname (out, jcf, 
1473                                    "\n#endif /* __", jcf->this_class);
1474           fprintf (out, "__ */\n");
1475         }
1476     }
1477 }
1478
1479 static void
1480 usage ()
1481 {
1482   fprintf (stderr, "gcjh: no classes specified\n");
1483   exit (1);
1484 }
1485
1486 static void
1487 help ()
1488 {
1489   printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
1490   printf ("Generate C++ header files from .class files\n\n");
1491   printf ("  --classpath PATH        Set path to find .class files\n");
1492   printf ("  --CLASSPATH PATH        Set path to find .class files\n");
1493   printf ("  -IDIR                   Append directory to class path\n");
1494   printf ("  -d DIRECTORY            Set output directory name\n");
1495   printf ("  --help                  Print this help, then exit\n");
1496   printf ("  -o FILE                 Set output file name\n");
1497   printf ("  -stubs                  Generate a C++ implementation stub file\n");
1498   printf ("  -td DIRECTORY           Set temporary directory name\n");
1499   printf ("  -v, --verbose           Print extra information while running\n");
1500   printf ("  --version               Print version number, then exit\n");
1501   /* FIXME: print bug-report information.  */
1502   exit (0);
1503 }
1504
1505 static void
1506 java_no_argument (opt)
1507      const char *opt;
1508 {
1509   fprintf (stderr, "gcjh: no argument given for option `%s'\n", opt);
1510   exit (1);
1511 }
1512
1513 static void
1514 version ()
1515 {
1516   /* FIXME: use version.c?  */
1517   printf ("gcjh (%s)\n\n", version_string);
1518   printf ("Copyright (C) 1998, 1999 Free Software Foundation, Inc.\n");
1519   printf ("This is free software; see the source for copying conditions.  There is NO\n");
1520   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
1521   exit (0);
1522 }
1523
1524 int
1525 DEFUN(main, (argc, argv),
1526       int argc AND char** argv)
1527 {
1528   JCF jcf;
1529   int argi;
1530   char *output_file = NULL;
1531   int emit_dependencies = 0, suppress_output = 0;
1532
1533   if (argc <= 1)
1534     usage ();
1535
1536   jcf_path_init ();
1537
1538   for (argi = 1; argi < argc; argi++)
1539     {
1540       char *arg = argv[argi];
1541
1542       if (arg[0] != '-' || ! strcmp (arg, "--"))
1543         break;
1544
1545       /* Just let all arguments be given in either "-" or "--" form.  */
1546       if (arg[1] == '-')
1547         ++arg;
1548
1549       if (strcmp (arg, "-o") == 0)
1550         {
1551           if (argi + 1 < argc)
1552             output_file = argv[++argi];
1553           else
1554             java_no_argument (argv[argi]);
1555         }
1556       else if (strcmp (arg, "-d") == 0)
1557         {
1558           if (argi + 1 < argc)
1559             output_directory = argv[++argi];
1560           else
1561             java_no_argument (argv[argi]);
1562         }
1563       else if (strcmp (arg, "-td") == 0)
1564         {
1565           if (argi + 1 < argc)
1566             temp_directory = argv[++argi];
1567           else
1568             java_no_argument (argv[argi]);
1569         }
1570       else if (strcmp (arg, "-prepend") == 0)
1571         {
1572           if (argi + 1 < argc)
1573             {
1574               if (prepend_count == 0)
1575                 prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1576               prepend_specs[prepend_count++] = argv[++argi];
1577             }
1578           else
1579             java_no_argument (argv[argi]);
1580         }
1581       else if (strcmp (arg, "-friend") == 0)
1582         {
1583           if (argi + 1 < argc)
1584             {
1585               if (friend_count == 0)
1586                 friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1587               friend_specs[friend_count++] = argv[++argi];
1588             }
1589           else
1590             java_no_argument (argv[argi]);
1591         }
1592       else if (strcmp (arg, "-add") == 0)
1593         {
1594           if (argi + 1 < argc)
1595             {
1596               if (add_count == 0)
1597                 add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1598               add_specs[add_count++] = argv[++argi];
1599             }
1600           else
1601             java_no_argument (argv[argi]);
1602         }
1603       else if (strcmp (arg, "-append") == 0)
1604         {
1605           if (argi + 1 < argc)
1606             {
1607               if (append_count == 0)
1608                 append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*));
1609               append_specs[append_count++] = argv[++argi];
1610             }
1611           else
1612             java_no_argument (argv[argi]);
1613         }
1614       else if (strcmp (arg, "-classpath") == 0)
1615         {
1616           if (argi + 1 < argc)
1617             jcf_path_classpath_arg (argv[++argi]);
1618           else
1619             java_no_argument (argv[argi]);
1620         }
1621       else if (strcmp (arg, "-CLASSPATH") == 0)
1622         {
1623           if (argi + 1 < argc)
1624             jcf_path_CLASSPATH_arg (argv[++argi]);
1625           else
1626             java_no_argument (argv[argi]);
1627         }
1628       else if (strncmp (arg, "-I", 2) == 0)
1629         jcf_path_include_arg (arg + 2);
1630       else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0)
1631         verbose++;
1632       else if (strcmp (arg, "-stubs") == 0)
1633         stubs++;
1634       else if (strcmp (arg, "-help") == 0)
1635         help ();
1636       else if (strcmp (arg, "-version") == 0)
1637         version ();
1638       else if (strcmp (arg, "-M") == 0)
1639         {
1640           emit_dependencies = 1;
1641           suppress_output = 1;
1642           jcf_dependency_init (1);
1643         }
1644       else if (strcmp (arg, "-MM") == 0)
1645         {
1646           emit_dependencies = 1;
1647           suppress_output = 1;
1648           jcf_dependency_init (0);
1649         }
1650       else if (strcmp (arg, "-MG") == 0)
1651         {
1652           fprintf (stderr, "gcjh: `%s' option is unimplemented\n", argv[argi]);
1653           exit (1);
1654         }
1655       else if (strcmp (arg, "-MD") == 0)
1656         {
1657           emit_dependencies = 1;
1658           jcf_dependency_init (1);
1659         }
1660       else if (strcmp (arg, "-MMD") == 0)
1661         {
1662           emit_dependencies = 1;
1663           jcf_dependency_init (0);
1664         }
1665       else
1666         {
1667           fprintf (stderr, "%s: illegal argument\n", argv[argi]);
1668           exit (1);
1669         }
1670     }
1671
1672   if (argi == argc)
1673     usage ();
1674
1675   jcf_path_seal ();
1676
1677   if (output_file && emit_dependencies)
1678     {
1679       fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
1680       exit (1);
1681     }
1682
1683   for (; argi < argc; argi++)
1684     {
1685       char *classname = argv[argi];
1686       char *current_output_file;
1687       const char *classfile_name;
1688
1689       if (verbose)
1690         fprintf (stderr, "Processing %s\n", classname);
1691       if (! output_file)
1692         jcf_dependency_reset ();
1693       classfile_name = find_class (classname, strlen (classname), &jcf, 0);
1694       if (classfile_name == NULL)
1695         {
1696           fprintf (stderr, "%s: no such class\n", classname);
1697           exit (1);
1698         }
1699       if (verbose)
1700         fprintf (stderr, "Found in %s\n", classfile_name);
1701       if (output_file)
1702         {
1703           if (strcmp (output_file, "-") == 0)
1704             out = stdout;
1705           else if (out == NULL)
1706             {
1707               out = fopen (output_file, "w");
1708             }
1709           if (out == NULL)
1710             {
1711               perror (output_file);
1712               exit (1);
1713             }
1714           current_output_file = output_file;
1715         }
1716       else
1717         {
1718           int dir_len = strlen (output_directory);
1719           int i, classname_length = strlen (classname);
1720           current_output_file = (char*) ALLOC (dir_len + classname_length + 5);
1721           strcpy (current_output_file, output_directory);
1722           if (dir_len > 0 && output_directory[dir_len-1] != '/')
1723             current_output_file[dir_len++] = '/';
1724           for (i = 0; classname[i] != '\0'; i++)
1725             {
1726               char ch = classname[i];
1727               if (ch == '.')
1728                 ch = '/';
1729               current_output_file[dir_len++] = ch;
1730             }
1731           if (emit_dependencies)
1732             {
1733               if (suppress_output)
1734                 {
1735                   jcf_dependency_set_dep_file ("-");
1736                   out = NULL;
1737                 }
1738               else
1739                 {
1740                   /* We use `.hd' and not `.d' to avoid clashes with
1741                      dependency tracking from straight compilation.  */
1742                   strcpy (current_output_file + dir_len, ".hd");
1743                   jcf_dependency_set_dep_file (current_output_file);
1744                 }
1745             }
1746           strcpy (current_output_file + dir_len, 
1747                   stubs ? ".cc" : ".h");
1748           jcf_dependency_set_target (current_output_file);
1749           if (! suppress_output)
1750             {
1751               out = fopen (current_output_file, "w");
1752               if (out == NULL)
1753                 {
1754                   perror (current_output_file);
1755                   exit (1);
1756                 }
1757             }
1758         }
1759       process_file (&jcf, out);
1760       JCF_FINISH (&jcf);
1761       if (current_output_file != output_file)
1762         free (current_output_file);
1763       jcf_dependency_write ();
1764     }
1765
1766   if (out != NULL && out != stdout)
1767     fclose (out);
1768
1769   return found_error;
1770 }
1771
1772 /* TODO:
1773
1774  * Emit "structure forward declarations" when needed.
1775
1776  * Generate C headers, like javah
1777
1778  */
1779