OSDN Git Service

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