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