OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [java/] [gjavah.c] - Blame information for rev 20

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 jlechner
/* 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, 2000, 2001, 2002, 2003, 2004, 2005, 2006
5
Free Software Foundation, Inc.
6
 
7
This file is part of GCC.
8
 
9
GCC is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2, or (at your option)
12
any later version.
13
 
14
GCC is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
GNU General Public License for more details.
18
 
19
You should have received a copy of the GNU General Public License
20
along with GCC; see the file COPYING.  If not, write to
21
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22
Boston, MA 02110-1301, USA.
23
 
24
Java and all Java-based marks are trademarks or registered trademarks
25
of Sun Microsystems, Inc. in the United States and other countries.
26
The Free Software Foundation is independent of Sun Microsystems, Inc.  */
27
 
28
/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
29
 
30
#include "config.h"
31
#include "system.h"
32
#include "coretypes.h"
33
#include "tm.h"
34
#include <math.h>
35
 
36
#include "jcf.h"
37
#include "tree.h"
38
#include "version.h"
39
#include "javaop.h"
40
#include "java-tree.h"
41
#include "java-opcodes.h"
42
#include "ggc.h"
43
#include "hashtab.h"
44
#include "intl.h"
45
 
46
#include <getopt.h>
47
 
48
 
49
 
50
/* The output file.  */
51
FILE *out = NULL;
52
 
53
/* Nonzero on failure.  */
54
static int found_error = 0;
55
 
56
#ifdef JNI_DEFAULT
57
#define TOOLNAME "gjnih"
58
 
59
/* Nonzero if we're generating JNI output.  */
60
int flag_jni = 1;
61
#else
62
#define TOOLNAME "gcjh"
63
 
64
int flag_jni = 0;
65
#endif
66
 
67
/* When nonzero, warn when source file is newer than matching class
68
   file.  */
69
int flag_newer = 1;
70
 
71
/* Directory to place resulting files in. Set by -d option. */
72
static const char *output_directory = "";
73
 
74
/* Directory to place temporary file.  Set by -td option.  Currently unused. */
75
static const char *temp_directory = "/tmp";
76
 
77
/* Number of friend functions we have to declare.  */
78
static int friend_count;
79
 
80
/* A class can optionally have a `friend' function declared.  If
81
   non-NULL, this is that function.  */
82
static char **friend_specs = NULL;
83
 
84
/* Number of lines we are prepending before the class.  */
85
static int prepend_count;
86
 
87
/* We can prepend extra lines before the class's start. */
88
static char **prepend_specs = NULL;
89
 
90
/* Number of lines we are appending at the end of the class.  */
91
static int add_count;
92
 
93
/* We can append extra lines just before the class's end. */
94
static char **add_specs = NULL;
95
 
96
/* Number of lines we are appending after the class.  */
97
static int append_count;
98
 
99
/* We can append extra lines after the class's end. */
100
static char **append_specs = NULL;
101
 
102
int verbose = 0;
103
 
104
int stubs = 0;
105
 
106
struct JCF *current_jcf;
107
 
108
/* This holds access information for the last field we examined.  They
109
   let us generate "private:", "public:", and "protected:" properly.
110
   If 0 then we haven't previously examined any field.  */
111
static JCF_u2 last_access;
112
 
113
/* Pass this macro the flags for a class and for a method.  It will
114
   return true if the method should be considered `final'.  */
115
#define METHOD_IS_FINAL(Class, Method) \
116
   (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
117
 
118
/* Pass this macro the flags for a method.  It will return true if the
119
   method is native.  */
120
#define METHOD_IS_NATIVE(Method) \
121
   ((Method) & ACC_NATIVE)
122
 
123
#define METHOD_IS_PRIVATE(Class, Method) \
124
  (((Method) & ACC_PRIVATE) != 0)
125
 
126
/* We keep a linked list of all method names we have seen.  This lets
127
   us determine if a method name and a field name are in conflict.  */
128
struct method_name
129
{
130
  unsigned char *name;
131
  int length;
132
  unsigned char *signature;
133
  int sig_length;
134
  int is_native;
135
  struct method_name *next;
136
};
137
 
138
/* List of method names we've seen.  */
139
static struct method_name *method_name_list;
140
 
141
static void print_field_info (FILE*, JCF*, int, int, JCF_u2);
142
static void print_mangled_classname (FILE*, JCF*, const char*, int);
143
static int  print_cxx_classname (FILE*, const char*, JCF*, int, int);
144
static void print_method_info (FILE*, JCF*, int, int, JCF_u2);
145
static void print_c_decl (FILE*, JCF*, int, int, int, const char *, int);
146
static void print_stub_or_jni (FILE*, JCF*, int, int, int, const char *, int);
147
static void print_full_cxx_name (FILE*, JCF*, int, int, int, const char *, int);
148
static void decompile_method (FILE*, JCF*, int) ATTRIBUTE_UNUSED;
149
static void add_class_decl (FILE*, JCF*, JCF_u2);
150
 
151
static void print_name (FILE *, JCF *, int);
152
static void print_base_classname (FILE *, JCF *, int);
153
static int utf8_cmp (const unsigned char *, int, const char *);
154
static char *cxx_keyword_subst (const unsigned char *, int);
155
static void generate_access (FILE *, JCF_u2);
156
static int name_is_method_p (const unsigned char *, int);
157
static char *get_field_name (JCF *, int, JCF_u2);
158
static void print_field_name (FILE *, JCF *, int, JCF_u2);
159
static const unsigned char *super_class_name (JCF *, int *);
160
static void print_include (FILE *, const unsigned char *, int);
161
static int gcjh_streq (const void *p1, const void *p2);
162
static int throwable_p (const unsigned char *signature);
163
static const unsigned char *
164
  decode_signature_piece (FILE *, const unsigned char *,
165
                          const unsigned char *, int *);
166
static void print_class_decls (FILE *, JCF *, int);
167
static void error (const char *gmsgid, ...) ATTRIBUTE_PRINTF_1;
168
static void usage (void) ATTRIBUTE_NORETURN;
169
static void help (void) ATTRIBUTE_NORETURN;
170
static void version (void) ATTRIBUTE_NORETURN;
171
static int overloaded_jni_method_exists_p (const unsigned char *, int,
172
                                           const char *, int);
173
static void jni_print_char (FILE *, int);
174
static void jni_print_float (FILE *, jfloat);
175
static void jni_print_double (FILE *, jdouble);
176
static void decompile_return_statement (FILE *, JCF *, int, int, int);
177
 
178
static void handle_inner_classes (int);
179
 
180
JCF_u2 current_field_name;
181
JCF_u2 current_field_value;
182
JCF_u2 current_field_signature;
183
JCF_u2 current_field_flags;
184
 
185
#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
186
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
187
  current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
188
 
189
/* We pass over fields twice.  The first time we just note the types
190
   of the fields and then the start of the methods.  Then we go back
191
   and parse the fields for real.  This is ugly.  */
192
static int field_pass;
193
/* Likewise we pass over methods twice.  The first time we generate
194
   class decl information; the second time we generate actual method
195
   decls.  */
196
static int method_pass;
197
 
198
#define HANDLE_END_FIELD()                                                    \
199
  if (field_pass)                                                             \
200
    {                                                                         \
201
      if (out && ! stubs)                                                     \
202
        print_field_info (out, jcf, current_field_name,                       \
203
                          current_field_signature,                            \
204
                          current_field_flags);                               \
205
    }                                                                         \
206
  else if (! stubs && ! flag_jni)                                             \
207
    add_class_decl (out, jcf, current_field_signature);
208
 
209
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
210
 
211
static int method_declared = 0;
212
static int method_access = 0;
213
static int method_printed = 0;
214
static int method_synthetic = 0;
215
static int method_signature = 0;
216
 
217
/* Set to 1 while the very first data member of a class is being handled.  */
218
static int is_first_data_member = 0;
219
 
220
#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)   \
221
  {                                                                     \
222
    method_synthetic = 0;                                                \
223
    method_printed = 0;                                                  \
224
    decompiled = 0;                                                      \
225
    method_signature = SIGNATURE;                                       \
226
    if (ATTRIBUTE_COUNT)                                                \
227
      method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT,          \
228
                                  (const char *)"Synthetic", 9);        \
229
    /* If a synthetic methods have been declared, its attribute aren't  \
230
       worth reading (and triggering side-effects). We skip them an     \
231
       set ATTRIBUTE_COUNT to zero so that they'll be skipped in        \
232
       jcf_parse_one_method.  */                                        \
233
    if (method_synthetic)                                               \
234
      {                                                                 \
235
        skip_attribute (jcf, ATTRIBUTE_COUNT);                          \
236
        ATTRIBUTE_COUNT = 0;                                             \
237
      }                                                                 \
238
    if (method_pass && !method_synthetic)                               \
239
      {                                                                 \
240
        if (out)                                                        \
241
          print_method_info (out, jcf, NAME, SIGNATURE,                 \
242
                             ACCESS_FLAGS);                             \
243
      }                                                                 \
244
    else if (!method_synthetic)                                         \
245
      {                                                                 \
246
        print_method_info (NULL, jcf, NAME, SIGNATURE,                  \
247
                           ACCESS_FLAGS);                               \
248
        if (! stubs && ! flag_jni)                                      \
249
          add_class_decl (out, jcf, SIGNATURE);                         \
250
      }                                                                 \
251
  }
252
 
253
/* Only include byte-code decompilation optimizations for ELF targets
254
   since the generated headers are only known to work with ELF weak
255
   symbol semnatics. Specifically, these optimizations are known to
256
   not work on PE-COFF and possibly others.  */
257
#ifdef OBJECT_FORMAT_ELF
258
#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH)       \
259
  if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
260
#endif
261
 
262
static int decompiled = 0;
263
#define HANDLE_END_METHOD()                             \
264
  if (out && method_printed && !method_synthetic)       \
265
    fputs (decompiled || stubs ? "\n" : ";\n", out);
266
 
267
#define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) handle_inner_classes (COUNT)
268
 
269
/* We're going to need {peek,skip}_attribute, enable their definition.   */
270
#define NEED_PEEK_ATTRIBUTE
271
#define NEED_SKIP_ATTRIBUTE
272
 
273
#include "jcf-reader.c"
274
 
275
/* Print an error message and set found_error.
276
   Not really gcc-internal-format message, but as error elsewhere
277
   uses it, assume all users will use intersection between
278
   c-format and gcc-internal-format.  */
279
static void
280
error (const char *gmsgid, ...)
281
{
282
  va_list ap;
283
 
284
  va_start (ap, gmsgid);
285
 
286
  fprintf (stderr, TOOLNAME ": ");
287
  vfprintf (stderr, _(gmsgid), ap);
288
  va_end (ap);
289
  fprintf (stderr, "\n");
290
  found_error = 1;
291
}
292
 
293
/* Print a single-precision float, suitable for parsing by g++.  */
294
static void
295
jni_print_float (FILE *stream, jfloat f)
296
{
297
  /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
298
     work in data initializers.  FIXME.  */
299
  if (JFLOAT_FINITE (f))
300
    {
301
      if (flag_jni)
302
        {
303
          fputs (" ", out);
304
          if (f.negative)
305
            putc ('-', stream);
306
          if (f.exponent)
307
            fprintf (stream, "0x1.%.6xp%+df",
308
                     ((unsigned int)f.mantissa) << 1,
309
                     f.exponent - JFLOAT_EXP_BIAS);
310
          else
311
            /* Exponent of 0x01 is -125; exponent of 0x00 is *also* -125,
312
               because the implicit leading 1 bit is no longer present.  */
313
            fprintf (stream, "0x0.%.6xp%+df",
314
                     ((unsigned int)f.mantissa) << 1,
315
                     f.exponent + 1 - JFLOAT_EXP_BIAS);
316
        }
317
    }
318
  if (! flag_jni)
319
    fputs (";\n", stream);
320
}
321
 
322
/* Print a double-precision float, suitable for parsing by g++.  */
323
static void
324
jni_print_double (FILE *stream, jdouble f)
325
{
326
  /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
327
     work in data initializers.  FIXME.  */
328
  if (JDOUBLE_FINITE (f))
329
    {
330
      if (flag_jni)
331
        {
332
          fputs (" ", out);
333
          if (f.negative)
334
            putc ('-', stream);
335
          if (f.exponent)
336
            fprintf (stream, "0x1.%.5x%.8xp%+d",
337
                     f.mantissa0, f.mantissa1,
338
                     f.exponent - JDOUBLE_EXP_BIAS);
339
          else
340
            /* Exponent of 0x001 is -1022; exponent of 0x000 is *also* -1022,
341
               because the implicit leading 1 bit is no longer present.  */
342
            fprintf (stream, "0x0.%.5x%.8xp%+d",
343
                     f.mantissa0, f.mantissa1,
344
                     f.exponent + 1 - JDOUBLE_EXP_BIAS);
345
        }
346
    }
347
  fputs (flag_jni ? "\n" : ";\n", stream);
348
}
349
 
350
/* Print a character, appropriately mangled for JNI.  */
351
 
352
static void
353
jni_print_char (FILE *stream, int ch)
354
{
355
  if (! flag_jni)
356
    jcf_print_char (stream, ch);
357
  else if (ch == '(' || ch == ')')
358
    {
359
      /* Ignore.  */
360
    }
361
  else if (ch == '_')
362
    fputs ("_1", stream);
363
  else if (ch == ';')
364
    fputs ("_2", stream);
365
  else if (ch == '[')
366
    fputs ("_3", stream);
367
  else if (ch == '/')
368
    fputs ("_", stream);
369
  else if (ISALNUM (ch))
370
    fputc (ch, stream);
371
  else
372
    {
373
      /* "Unicode" character.  */
374
      fprintf (stream, "_0%04x", ch);
375
    }
376
}
377
 
378
/* Print a name from the class data.  If the index does not point to a
379
   string, an error results.  */
380
 
381
static void
382
print_name (FILE* stream, JCF* jcf, int name_index)
383
{
384
  if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
385
    {
386
      fprintf (stream, "<not a UTF8 constant>");
387
      found_error = 1;
388
    }
389
  else if (! flag_jni)
390
    jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
391
                    JPOOL_UTF_LENGTH (jcf, name_index));
392
  else
393
    {
394
      /* For JNI we must correctly quote each character.  */
395
      const unsigned char *str = JPOOL_UTF_DATA (jcf, name_index);
396
      int length = JPOOL_UTF_LENGTH (jcf, name_index);
397
      const unsigned char *limit = str + length;
398
      while (str < limit)
399
        {
400
          int ch = UTF8_GET (str, limit);
401
          if (ch < 0)
402
            {
403
              fprintf (stream, "\\<invalid>");
404
              return;
405
            }
406
          jni_print_char (stream, ch);
407
        }
408
    }
409
}
410
 
411
/* Print base name of class.  The base name is everything after the
412
   final separator.  */
413
 
414
static void
415
print_base_classname (FILE *stream, JCF *jcf, int index)
416
{
417
  int name_index = JPOOL_USHORT1 (jcf, index);
418
  int len;
419
  const unsigned char *s, *p, *limit;
420
 
421
  s = JPOOL_UTF_DATA (jcf, name_index);
422
  len = JPOOL_UTF_LENGTH (jcf, name_index);
423
  limit = s + len;
424
  p = s;
425
  while (s < limit)
426
    {
427
      int c = UTF8_GET (s, limit);
428
      if (c == '/')
429
        p = s;
430
    }
431
 
432
  while (p < limit)
433
    {
434
      int ch = UTF8_GET (p, limit);
435
      if (ch == '/')
436
        fputs ("::", stream);
437
      else
438
        jcf_print_char (stream, ch);
439
    }
440
}
441
 
442
/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
443
   and 1 if STR is "greater" than NAME.  */
444
 
445
static int
446
utf8_cmp (const unsigned char *str, int length, const char *name)
447
{
448
  const unsigned char *limit = str + length;
449
  int i;
450
 
451
  for (i = 0; name[i]; ++i)
452
    {
453
      int ch = UTF8_GET (str, limit);
454
      if (ch != name[i])
455
        return ch - name[i];
456
    }
457
 
458
  return str == limit ? 0 : 1;
459
}
460
 
461
/* This is a sorted list of all C++ keywords.  */
462
 
463
static const char *const cxx_keywords[] =
464
{
465
  "_Complex",
466
  "__alignof",
467
  "__alignof__",
468
  "__asm",
469
  "__asm__",
470
  "__attribute",
471
  "__attribute__",
472
  "__builtin_va_arg",
473
  "__complex",
474
  "__complex__",
475
  "__const",
476
  "__const__",
477
  "__extension__",
478
  "__imag",
479
  "__imag__",
480
  "__inline",
481
  "__inline__",
482
  "__label__",
483
  "__null",
484
  "__real",
485
  "__real__",
486
  "__restrict",
487
  "__restrict__",
488
  "__signed",
489
  "__signed__",
490
  "__typeof",
491
  "__typeof__",
492
  "__volatile",
493
  "__volatile__",
494
  "and",
495
  "and_eq",
496
  "asm",
497
  "auto",
498
  "bitand",
499
  "bitor",
500
  "bool",
501
  "break",
502
  "case",
503
  "catch",
504
  "char",
505
  "class",
506
  "compl",
507
  "const",
508
  "const_cast",
509
  "continue",
510
  "default",
511
  "delete",
512
  "do",
513
  "double",
514
  "dynamic_cast",
515
  "else",
516
  "enum",
517
  "explicit",
518
  "export",
519
  "extern",
520
  "false",
521
  "float",
522
  "for",
523
  "friend",
524
  "goto",
525
  "if",
526
  "inline",
527
  "int",
528
  "long",
529
  "mutable",
530
  "namespace",
531
  "new",
532
  "not",
533
  "not_eq",
534
  "operator",
535
  "or",
536
  "or_eq",
537
  "private",
538
  "protected",
539
  "public",
540
  "register",
541
  "reinterpret_cast",
542
  "return",
543
  "short",
544
  "signed",
545
  "sizeof",
546
  "static",
547
  "static_cast",
548
  "struct",
549
  "switch",
550
  "template",
551
  "this",
552
  "throw",
553
  "true",
554
  "try",
555
  "typedef",
556
  "typeid",
557
  "typename",
558
  "typeof",
559
  "union",
560
  "unsigned",
561
  "using",
562
  "virtual",
563
  "void",
564
  "volatile",
565
  "wchar_t",
566
  "while",
567
  "xor",
568
  "xor_eq"
569
};
570
 
571
 
572
/* If NAME is the name of a C++ keyword, then return an override name.
573
   This is a name that can be used in place of the keyword.
574
   Otherwise, return NULL.  The return value is malloc()d.  */
575
 
576
static char *
577
cxx_keyword_subst (const unsigned char *str, int length)
578
{
579
  int last = ARRAY_SIZE (cxx_keywords);
580
  int first = 0;
581
  int mid = (last + first) / 2;
582
  int old = -1;
583
 
584
  for (mid = (last + first) / 2;
585
       mid != old;
586
       old = mid, mid = (last + first) / 2)
587
    {
588
      int kwl = strlen (cxx_keywords[mid]);
589
      int min_length = kwl > length ? length : kwl;
590
      int r = utf8_cmp (str, min_length, cxx_keywords[mid]);
591
 
592
      if (r == 0)
593
        {
594
          int i;
595
 
596
          /* Skip all trailing `$'.  */
597
          for (i = min_length; i < length && str[i] == '$'; ++i)
598
            ;
599
          /* We've only found a match if all the remaining characters
600
             are `$'.  */
601
          if (i == length)
602
            {
603
              char *dup = xmalloc (2 + length - min_length + kwl);
604
              strcpy (dup, cxx_keywords[mid]);
605
              for (i = kwl; i < length + 1; ++i)
606
                dup[i] = '$';
607
              dup[i] = '\0';
608
              return dup;
609
            }
610
          r = 1;
611
        }
612
 
613
      if (r < 0)
614
        last = mid;
615
      else
616
        first = mid;
617
    }
618
  return NULL;
619
}
620
 
621
/* Generate an access control keyword based on FLAGS.  */
622
 
623
static void
624
generate_access (FILE *stream, JCF_u2 flags)
625
{
626
  if ((flags & ACC_VISIBILITY) == last_access)
627
    return;
628
  last_access = (flags & ACC_VISIBILITY);
629
 
630
  switch (last_access)
631
    {
632
    case 0:
633
      fputs ("public: // actually package-private\n", stream);
634
      break;
635
    case ACC_PUBLIC:
636
      fputs ("public:\n", stream);
637
      break;
638
    case ACC_PRIVATE:
639
      fputs ("private:\n", stream);
640
      break;
641
    case ACC_PROTECTED:
642
      fputs ("public:  // actually protected\n", stream);
643
      break;
644
    default:
645
      found_error = 1;
646
      fprintf (stream, "#error unrecognized visibility %d\n",
647
               (flags & ACC_VISIBILITY));
648
      break;
649
    }
650
}
651
 
652
/* See if NAME is already the name of a method.  */
653
static int
654
name_is_method_p (const unsigned char *name, int length)
655
{
656
  struct method_name *p;
657
 
658
  for (p = method_name_list; p != NULL; p = p->next)
659
    {
660
      if (p->length == length && ! memcmp (p->name, name, length))
661
        return 1;
662
    }
663
  return 0;
664
}
665
 
666
/* Free the method name list.  */
667
static void
668
free_method_name_list (void)
669
{
670
  struct method_name *p = method_name_list;
671
  while (p != NULL)
672
    {
673
      struct method_name *next = p->next;
674
      free (p->name);
675
      free (p->signature);
676
      free (p);
677
      p = next;
678
    }
679
  method_name_list = NULL;
680
}
681
 
682
/* If there is already a native method named NAME, whose signature is not
683
   SIGNATURE, then return true.  Otherwise return false.  */
684
static int
685
overloaded_jni_method_exists_p (const unsigned char *name, int length,
686
                                const char *signature, int sig_length)
687
{
688
  struct method_name *p;
689
 
690
  for (p = method_name_list; p != NULL; p = p->next)
691
    {
692
      if (p->is_native
693
          && p->length == length
694
          && ! memcmp (p->name, name, length)
695
          && (p->sig_length != sig_length
696
              || memcmp (p->signature, signature, sig_length)))
697
        return 1;
698
    }
699
  return 0;
700
}
701
 
702
/* Get name of a field.  This handles renamings due to C++ clash.  */
703
static char *
704
get_field_name (JCF *jcf, int name_index, JCF_u2 flags)
705
{
706
  unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
707
  int length = JPOOL_UTF_LENGTH (jcf, name_index);
708
  char *override;
709
 
710
  if (name_is_method_p (name, length))
711
    {
712
      /* This field name matches a method.  So override the name with
713
         a dummy name.  This is yucky, but it isn't clear what else to
714
         do.  FIXME: if the field is static, then we'll be in real
715
         trouble.  */
716
      if ((flags & ACC_STATIC))
717
        {
718
          error ("static field has same name as method");
719
          return NULL;
720
        }
721
 
722
      override = xmalloc (length + 3);
723
      memcpy (override, name, length);
724
      strcpy (override + length, "__");
725
    }
726
  else if (flag_jni)
727
    override = NULL;
728
  else
729
    override = cxx_keyword_subst (name, length);
730
 
731
  return override;
732
}
733
 
734
/* Print a field name.  Convenience function for use with
735
   get_field_name.  */
736
static void
737
print_field_name (FILE *stream, JCF *jcf, int name_index, JCF_u2 flags)
738
{
739
  char *override = get_field_name (jcf, name_index, flags);
740
 
741
  if (override)
742
    {
743
      fputs (override, stream);
744
      free (override);
745
    }
746
  else
747
    jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
748
                    JPOOL_UTF_LENGTH (jcf, name_index));
749
}
750
 
751
static void
752
print_field_info (FILE *stream, JCF* jcf, int name_index, int sig_index,
753
                  JCF_u2 flags)
754
{
755
  char *override = NULL;
756
 
757
  if (! flag_jni)
758
    generate_access (stream, flags);
759
  if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
760
    {
761
      fprintf (stream, "<not a UTF8 constant>");
762
      found_error = 1;
763
      return;
764
    }
765
 
766
  if (flag_jni)
767
    {
768
      /* For JNI we only want to print real constants.  */
769
      int val;
770
      if (! (flags & ACC_STATIC)
771
          || ! (flags & ACC_FINAL)
772
          || current_field_value <= 0)
773
        return;
774
      val = JPOOL_TAG (jcf, current_field_value);
775
      if (val != CONSTANT_Integer && val != CONSTANT_Long
776
          && val != CONSTANT_Float && val != CONSTANT_Double)
777
        return;
778
    }
779
  else
780
    {
781
      /* Initial indentation.  */
782
      fputs ("  ", stream);
783
    }
784
 
785
  if ((flags & ACC_STATIC))
786
    {
787
      if (flag_jni)
788
        {
789
          print_cxx_classname (stream, "#undef ", jcf, jcf->this_class, 1);
790
          fputs ("_", stream);
791
          print_field_name (stream, jcf, name_index, 0);
792
          fputs ("\n", stream);
793
          print_cxx_classname (stream, "#define ", jcf, jcf->this_class, 1);
794
          fputs ("_", stream);
795
        }
796
      else
797
        fputs ("static ", stream);
798
 
799
      if ((flags & ACC_FINAL) && current_field_value > 0)
800
        {
801
          char buffer[25];
802
          int done = 1;
803
 
804
          switch (JPOOL_TAG (jcf, current_field_value))
805
            {
806
            case CONSTANT_Integer:
807
              {
808
                jint num;
809
                int most_negative = 0;
810
                if (! flag_jni)
811
                  fputs ("const jint ", stream);
812
                print_field_name (stream, jcf, name_index, 0);
813
                fputs (flag_jni ? " " : " = ", stream);
814
                num = JPOOL_INT (jcf, current_field_value);
815
                /* We single out the most negative number to print
816
                   specially.  This avoids later warnings from g++.  */
817
                if (num == (jint) 0x80000000)
818
                  {
819
                    most_negative = 1;
820
                    ++num;
821
                  }
822
                format_int (buffer, (jlong) num, 10);
823
                fprintf (stream, "%sL%s%s\n", buffer,
824
                         most_negative ? " - 1" : "",
825
                         flag_jni ? "" : ";");
826
              }
827
              break;
828
            case CONSTANT_Long:
829
              {
830
                jlong num;
831
                int most_negative = 0;
832
                if (! flag_jni)
833
                  fputs ("const jlong ", stream);
834
                print_field_name (stream, jcf, name_index, 0);
835
                fputs (flag_jni ? " " : " = ", stream);
836
                num = JPOOL_LONG (jcf, current_field_value);
837
                /* We single out the most negative number to print
838
                   specially..  This avoids later warnings from g++.  */
839
                if (num == (jlong) 0x8000000000000000LL)
840
                  {
841
                    most_negative = 1;
842
                    ++num;
843
                  }
844
                format_int (buffer, num, 10);
845
                fprintf (stream, "%sLL%s%s\n", buffer,
846
                         most_negative ? " - 1" :"",
847
                         flag_jni ? "" : ";");
848
              }
849
              break;
850
            case CONSTANT_Float:
851
              {
852
                jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
853
                if (! flag_jni)
854
                  fputs ("const jfloat ", stream);
855
                print_field_name (stream, jcf, name_index, 0);
856
                jni_print_float (stream, fnum);
857
              }
858
              break;
859
            case CONSTANT_Double:
860
              {
861
                jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
862
                if (! flag_jni)
863
                  fputs ("const jdouble ", stream);
864
                print_field_name (stream, jcf, name_index, 0);
865
                jni_print_double (stream, dnum);
866
              }
867
              break;
868
            default:
869
              /* We can't print this as a constant, but we can still
870
                 print something sensible.  */
871
              done = 0;
872
              break;
873
            }
874
 
875
          if (done)
876
            return;
877
        }
878
    }
879
 
880
  /* assert (! flag_jni);  */
881
  override = get_field_name (jcf, name_index, flags);
882
  print_c_decl (stream, jcf, name_index, sig_index, 0, override, flags);
883
  fputs (";\n", stream);
884
 
885
  if (override)
886
    free (override);
887
}
888
 
889
 
890
static void
891
print_method_info (FILE *stream, JCF* jcf, int name_index, int sig_index,
892
                   JCF_u2 flags)
893
{
894
  const unsigned char *str;
895
  int length, is_init = 0;
896
  char *override = NULL;
897
 
898
  method_declared = 0;
899
  method_access = flags;
900
  if (stream && JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
901
    fprintf (stream, "<not a UTF8 constant>");
902
  str = JPOOL_UTF_DATA (jcf, name_index);
903
  length = JPOOL_UTF_LENGTH (jcf, name_index);
904
 
905
  if (str[0] == '<')
906
    {
907
      /* Ignore the internally generated method <clinit>. However,
908
         treat <init> as a constructor.  */
909
      if (! utf8_cmp (str, length, "<init>"))
910
        is_init = 1;
911
      else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
912
               && ! (flags & ACC_STATIC))
913
        {
914
          /* FIXME: i18n bug here.  Order of prints should not be
915
             fixed.  */
916
          fprintf (stderr, _("ignored method '"));
917
          jcf_print_utf8 (stderr, str, length);
918
          fprintf (stderr, _("' marked virtual\n"));
919
          found_error = 1;
920
          return;
921
        }
922
      else
923
        return;
924
    }
925
 
926
  /* During the first method pass, build a list of method names. This will
927
  be used to determine if field names conflict with method names. */
928
  if (! stream)
929
    {
930
      struct method_name *nn;
931
 
932
      nn = xmalloc (sizeof (struct method_name));
933
      nn->name = xmalloc (length);
934
      memcpy (nn->name, str, length);
935
      nn->length = length;
936
      nn->next = method_name_list;
937
      nn->sig_length = JPOOL_UTF_LENGTH (jcf, sig_index);
938
      nn->signature = xmalloc (nn->sig_length);
939
      nn->is_native = METHOD_IS_NATIVE (flags);
940
      memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index),
941
              nn->sig_length);
942
      method_name_list = nn;
943
 
944
      /* The rest of this function doesn't matter. */
945
      return;
946
    }
947
 
948
  /* We don't worry about overrides in JNI mode.  */
949
  if (! flag_jni)
950
    {
951
      /* We can't generate a method whose name is a C++ reserved word.
952
         We can't just ignore the function, because that will cause
953
         incorrect code to be generated if the function is virtual
954
         (not only for calls to this function for for other functions
955
         after it in the vtbl).  So we give it a dummy name instead.  */
956
      override = cxx_keyword_subst (str, length);
957
    }
958
 
959
  if (! stubs && ! flag_jni)
960
    {
961
      method_printed = 1;
962
 
963
      generate_access (stream, flags);
964
 
965
      fputs ("  ", out);
966
      if ((flags & ACC_STATIC))
967
        fputs ("static ", out);
968
      else if (! METHOD_IS_PRIVATE (jcf->access_flags, flags))
969
        {
970
          /* Don't print `virtual' if we have a constructor.  */
971
          if (! is_init)
972
            fputs ("virtual ", out);
973
        }
974
      print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
975
 
976
      if ((flags & ACC_ABSTRACT))
977
        fputs (" = 0", out);
978
      else
979
        method_declared = 1;
980
    }
981
  else
982
    {
983
      if (METHOD_IS_NATIVE (flags))
984
        {
985
          method_printed = 1;
986
          print_stub_or_jni (out, jcf, name_index, sig_index,
987
                             is_init, override, flags);
988
        }
989
    }
990
 
991
  if (override)
992
    free (override);
993
}
994
 
995
/* A helper for the decompiler which prints a `return' statement where
996
   the type is a reference type.  If METHODTYPE and OBJECTTYPE are not
997
   identical, we emit a cast.  We do this because the C++ compiler
998
   doesn't know that a reference can be cast to the type of an
999
   interface it implements.  METHODTYPE is the index of the method's
1000
   signature.  NAMEINDEX is the index of the field name; -1 for
1001
   `this'.  OBJECTTYPE is the index of the object's type.  */
1002
static void
1003
decompile_return_statement (FILE *out, JCF *jcf, int methodtype,
1004
                            int nameindex, int objecttype)
1005
{
1006
  int cast = 0;
1007
  int obj_name_len, method_name_len;
1008
  const unsigned char *obj_data, *method_data;
1009
 
1010
  obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype);
1011
  obj_data = JPOOL_UTF_DATA (jcf, objecttype);
1012
 
1013
  method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype);
1014
  method_data = JPOOL_UTF_DATA (jcf, methodtype);
1015
 
1016
  /* Skip forward to return type part of method.  */
1017
  while (*method_data != ')')
1018
    {
1019
      ++method_data;
1020
      --method_name_len;
1021
    }
1022
  /* Skip past `)'.  */
1023
  ++method_data;
1024
  --method_name_len;
1025
 
1026
  /* If we see an `L', skip it and the trailing `;'.  */
1027
  if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';')
1028
    {
1029
      ++method_data;
1030
      method_name_len -= 2;
1031
    }
1032
  if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';')
1033
    {
1034
      ++obj_data;
1035
      obj_name_len -= 2;
1036
    }
1037
 
1038
  /* FIXME: if METHODTYPE is a superclass of OBJECTTYPE then we don't
1039
     need a cast.  Right now there is no way to determine if this is
1040
     the case.  */
1041
  if (method_name_len != obj_name_len)
1042
    cast = 1;
1043
  else
1044
    {
1045
      int i;
1046
      for (i = 0; i < method_name_len; ++i)
1047
        {
1048
          if (method_data[i] != obj_data[i])
1049
            {
1050
              cast = 1;
1051
              break;
1052
            }
1053
        }
1054
    }
1055
 
1056
  fputs (" { return ", out);
1057
 
1058
  if (cast)
1059
    {
1060
      int array_depth = 0;
1061
      const unsigned char *limit;
1062
 
1063
      fputs ("reinterpret_cast<", out);
1064
 
1065
      while (*method_data == '[')
1066
        {
1067
          ++method_data;
1068
          ++array_depth;
1069
          --method_name_len;
1070
          fputs ("JArray<", out);
1071
        }
1072
 
1073
      /* Leading space to avoid C++ digraphs.  */
1074
      fputs (" ::", out);
1075
 
1076
      /* If we see an `L', skip it and the trailing `;'.  Only do this
1077
         if we've seen an array specification.  If we don't have an
1078
         array then the `L' was stripped earlier.  */
1079
      if (array_depth && method_data[0] == 'L'
1080
          && method_data[method_name_len - 1] == ';')
1081
        {
1082
          ++method_data;
1083
          method_name_len -= 2;
1084
        }
1085
 
1086
      limit = method_data + method_name_len;
1087
      while (method_data < limit)
1088
        {
1089
          int ch = UTF8_GET (method_data, limit);
1090
          if (ch == '/')
1091
            fputs ("::", out);
1092
          else
1093
            jcf_print_char (out, ch);
1094
        }
1095
      fputs (" *", out);
1096
 
1097
      /* Close each array.  */
1098
      while (array_depth > 0)
1099
        {
1100
          fputs ("> *", out);
1101
          --array_depth;
1102
        }
1103
 
1104
      /* Close the cast.  */
1105
      fputs ("> (", out);
1106
    }
1107
 
1108
  if (nameindex == -1)
1109
    fputs ("this", out);
1110
  else
1111
    print_field_name (out, jcf, nameindex, 0);
1112
 
1113
  if (cast)
1114
    fputs (")", out);
1115
 
1116
  fputs ("; }", out);
1117
}
1118
 
1119
 
1120
/* Try to decompile a method body.  Right now we just try to handle a
1121
   simple case that we can do.  Expand as desired.  */
1122
static void
1123
decompile_method (FILE *out, JCF *jcf, int code_len)
1124
{
1125
  const unsigned char *codes = jcf->read_ptr;
1126
  int index;
1127
  uint16 name_and_type, name;
1128
 
1129
  /* If the method is synchronized, don't touch it.  */
1130
  if ((method_access & ACC_SYNCHRONIZED))
1131
    return;
1132
 
1133
  if (code_len == 5
1134
      && codes[0] == OPCODE_aload_0
1135
      && codes[1] == OPCODE_getfield
1136
      && (codes[4] == OPCODE_areturn
1137
          || codes[4] == OPCODE_dreturn
1138
          || codes[4] == OPCODE_freturn
1139
          || codes[4] == OPCODE_ireturn
1140
          || codes[4] == OPCODE_lreturn))
1141
    {
1142
      /* Found code like `return FIELD'.  */
1143
      index = (codes[2] << 8) | codes[3];
1144
      /* FIXME: ensure that tag is CONSTANT_Fieldref.  */
1145
      name_and_type = JPOOL_USHORT2 (jcf, index);
1146
      /* FIXME: ensure that tag is CONSTANT_NameAndType.  */
1147
      name = JPOOL_USHORT1 (jcf, name_and_type);
1148
      if (codes[4] == OPCODE_areturn)
1149
        decompile_return_statement (out, jcf, method_signature,
1150
                                    name, JPOOL_USHORT2 (jcf, name_and_type));
1151
      else
1152
        {
1153
          fputs (" { return ", out);
1154
          /* FIXME: flags.  */
1155
          print_field_name (out, jcf, name, 0);
1156
          fputs ("; }", out);
1157
        }
1158
      decompiled = 1;
1159
    }
1160
  else if (code_len == 2
1161
           && codes[0] == OPCODE_aload_0
1162
           && codes[1] == OPCODE_areturn
1163
           /* We're going to generate `return this'.  This only makes
1164
              sense for non-static methods.  */
1165
           && ! (method_access & ACC_STATIC))
1166
    {
1167
      decompile_return_statement (out, jcf, method_signature, -1,
1168
                                  JPOOL_USHORT1 (jcf, jcf->this_class));
1169
      decompiled = 1;
1170
    }
1171
  else if (code_len == 1 && codes[0] == OPCODE_return)
1172
    {
1173
      /* Found plain `return'.  */
1174
      fputs (" { }", out);
1175
      decompiled = 1;
1176
    }
1177
  else if (code_len == 2
1178
           && codes[0] == OPCODE_aconst_null
1179
           && codes[1] == OPCODE_areturn)
1180
    {
1181
      /* Found `return null'.  We don't want to depend on NULL being
1182
         defined.  */
1183
      fputs (" { return 0; }", out);
1184
      decompiled = 1;
1185
    }
1186
}
1187
 
1188
/* Like strcmp, but invert the return result for the hash table.  This
1189
   should probably be in hashtab.c to complement the existing string
1190
   hash function.  */
1191
static int
1192
gcjh_streq (const void *p1, const void *p2)
1193
{
1194
  return ! strcmp ((char *) p1, (char *) p2);
1195
}
1196
 
1197
/* Return 1 if the initial part of CLNAME names a subclass of throwable,
1198
   or 0 if not.  CLNAME may be extracted from a signature, and can be
1199
   terminated with either `;' or NULL.  */
1200
static int
1201
throwable_p (const unsigned char *clname)
1202
{
1203
  int length;
1204
  unsigned char *current;
1205
  int i;
1206
  int result = 0;
1207
 
1208
  /* We keep two hash tables of class names.  In one we list all the
1209
     classes which are subclasses of Throwable.  In the other we will
1210
     all other classes.  We keep two tables to make the code a bit
1211
     simpler; we don't have to have a structure mapping class name to
1212
     a `throwable?' bit.  */
1213
  static htab_t throw_hash;
1214
  static htab_t non_throw_hash;
1215
  static int init_done = 0;
1216
 
1217
  if (! init_done)
1218
    {
1219
      void **slot;
1220
      unsigned char *str;
1221
 
1222
      /* Self-initializing.  The cost of this really doesn't matter.
1223
         We also don't care about freeing these, either.  */
1224
      throw_hash = htab_create (10, htab_hash_string, gcjh_streq,
1225
                                (htab_del) free);
1226
      non_throw_hash = htab_create (10, htab_hash_string, gcjh_streq,
1227
                                    (htab_del) free);
1228
 
1229
      /* Make sure the root classes show up in the tables.  */
1230
      str = (unsigned char *) xstrdup ("java.lang.Throwable");
1231
      slot = htab_find_slot (throw_hash, str, INSERT);
1232
      *slot = str;
1233
 
1234
      str = (unsigned char *) xstrdup ("java.lang.Object");
1235
      slot = htab_find_slot (non_throw_hash, str, INSERT);
1236
      *slot = str;
1237
 
1238
      init_done = 1;
1239
    }
1240
 
1241
  for (length = 0; clname[length] != ';' && clname[length] != '\0'; ++length)
1242
    ;
1243
  current = ALLOC (length + 1);
1244
  for (i = 0; i < length; ++i)
1245
    current[i] = clname[i] == '/' ? '.' : clname[i];
1246
  current[length] = '\0';
1247
 
1248
  /* We don't compute the hash slot here because the table might be
1249
     modified by the recursion.  In that case the slot could be
1250
     invalidated.  */
1251
  if (htab_find (throw_hash, current))
1252
    result = 1;
1253
  else if (htab_find (non_throw_hash, current))
1254
    result = 0;
1255
  else
1256
    {
1257
      JCF jcf;
1258
      void **slot;
1259
      unsigned char *super, *tmp;
1260
      int super_length = -1;
1261
      const char *classfile_name = find_class ((char *) current, strlen ((const char *) current),
1262
                                               &jcf, 0);
1263
 
1264
      if (! classfile_name)
1265
        {
1266
          error ("couldn't find class %s", current);
1267
          return 0;
1268
        }
1269
      if (jcf_parse_preamble (&jcf) != 0
1270
          || jcf_parse_constant_pool (&jcf) != 0
1271
          || verify_constant_pool (&jcf) > 0)
1272
        {
1273
          error ("parse error while reading %s", classfile_name);
1274
          return 0;
1275
        }
1276
      jcf_parse_class (&jcf);
1277
 
1278
      tmp = (unsigned char *) super_class_name (&jcf, &super_length);
1279
      super = ALLOC (super_length + 1);
1280
      memcpy (super, tmp, super_length);
1281
      super[super_length] = '\0';
1282
 
1283
      result = throwable_p (super);
1284
      slot = htab_find_slot (result ? throw_hash : non_throw_hash,
1285
                             current, INSERT);
1286
      *slot = current;
1287
      current = NULL;
1288
 
1289
      JCF_FINISH (&jcf);
1290
    }
1291
 
1292
  return result;
1293
}
1294
 
1295
/* Print one piece of a signature.  Returns pointer to next parseable
1296
   character on success, NULL on error.  */
1297
static const unsigned char *
1298
decode_signature_piece (FILE *stream, const unsigned char *signature,
1299
                        const unsigned char *limit, int *need_space)
1300
{
1301
  const char *ctype;
1302
  int array_depth = 0;
1303
 
1304
  switch (signature[0])
1305
    {
1306
    case '[':
1307
      /* More spaghetti.  */
1308
 
1309
    array_loop:
1310
      for (signature++; (signature < limit
1311
                         && ISDIGIT (*signature)); signature++)
1312
        ;
1313
      switch (*signature)
1314
        {
1315
        case 'B':
1316
          ctype = "jbyteArray";
1317
          break;
1318
        case 'C':
1319
          ctype = "jcharArray";
1320
          break;
1321
        case 'D':
1322
          ctype = "jdoubleArray";
1323
          break;
1324
        case 'F':
1325
          ctype = "jfloatArray";
1326
          break;
1327
        case 'I':
1328
          ctype = "jintArray";
1329
          break;
1330
        case 'S':
1331
          ctype = "jshortArray";
1332
          break;
1333
        case 'J':
1334
          ctype = "jlongArray";
1335
          break;
1336
        case 'Z':
1337
          ctype = "jbooleanArray";
1338
          break;
1339
        case '[':
1340
          /* We have a nested array.  */
1341
          ++array_depth;
1342
          if (! flag_jni)
1343
            fputs ("JArray<", stream);
1344
          goto array_loop;
1345
 
1346
        case 'L':
1347
          /* We have to generate a reference to JArray here, so that
1348
             our output matches what the compiler does.  */
1349
          ++signature;
1350
          /* Space between `<' and `:' to avoid C++ digraphs.  */
1351
          if (! flag_jni)
1352
            fputs ("JArray< ::", stream);
1353
          while (signature < limit && *signature != ';')
1354
            {
1355
              int ch = UTF8_GET (signature, limit);
1356
              if (! flag_jni)
1357
                {
1358
                  if (ch == '/')
1359
                    fputs ("::", stream);
1360
                  else
1361
                    jcf_print_char (stream, ch);
1362
                }
1363
            }
1364
          if (! flag_jni)
1365
            fputs (" *> *", stream);
1366
          *need_space = 0;
1367
          ctype = NULL;
1368
          break;
1369
        default:
1370
          /* Unparseable signature.  */
1371
          return NULL;
1372
        }
1373
 
1374
      /* If the previous iterations left us with something to print,
1375
         print it.  For JNI, we always print `jobjectArray' in the
1376
         nested cases.  */
1377
      if (flag_jni && (ctype == NULL || array_depth > 0))
1378
        {
1379
          ctype = "jobjectArray";
1380
          *need_space = 1;
1381
        }
1382
      /* The `printit' case will advance SIGNATURE for us.  If we
1383
         don't go there, we must advance past the `;' ourselves.  */
1384
      if (ctype != NULL)
1385
        goto printit;
1386
      ++signature;
1387
      break;
1388
 
1389
    case '(':
1390
    case ')':
1391
      /* This shouldn't happen.  */
1392
      return NULL;
1393
 
1394
    case 'B': ctype = "jbyte";  goto printit;
1395
    case 'C': ctype = "jchar";  goto printit;
1396
    case 'D': ctype = "jdouble";  goto printit;
1397
    case 'F': ctype = "jfloat";  goto printit;
1398
    case 'I': ctype = "jint";  goto printit;
1399
    case 'J': ctype = "jlong";  goto printit;
1400
    case 'S': ctype = "jshort";  goto printit;
1401
    case 'Z': ctype = "jboolean";  goto printit;
1402
    case 'V': ctype = "void";  goto printit;
1403
    case 'L':
1404
      if (flag_jni)
1405
        {
1406
          /* We know about certain types and special-case their names.  */
1407
          if (! strncmp ((const char *) signature, "Ljava/lang/String;",
1408
                         sizeof ("Ljava/lang/String;") -1))
1409
            ctype = "jstring";
1410
          else if (! strncmp ((const char *) signature, "Ljava/lang/Class;",
1411
                              sizeof ("Ljava/lang/Class;") - 1))
1412
            ctype = "jclass";
1413
          /* Skip leading 'L' for throwable_p call.  */
1414
          else if (throwable_p (signature + 1))
1415
            ctype = "jthrowable";
1416
          else
1417
            ctype = "jobject";
1418
 
1419
          while (*signature && *signature != ';')
1420
            ++signature;
1421
 
1422
          goto printit;
1423
        }
1424
      /* Print a leading "::" so we look in the right namespace.  */
1425
      fputs ("::", stream);
1426
      ++signature;
1427
      while (*signature && *signature != ';')
1428
        {
1429
          int ch = UTF8_GET (signature, limit);
1430
          if (ch == '/')
1431
            fputs ("::", stream);
1432
          else
1433
            jcf_print_char (stream, ch);
1434
        }
1435
      fputs (" *", stream);
1436
      if (*signature == ';')
1437
        signature++;
1438
      *need_space = 0;
1439
      break;
1440
    default:
1441
      *need_space = 1;
1442
      jni_print_char (stream, *signature++);
1443
      break;
1444
    printit:
1445
      signature++;
1446
      *need_space = 1;
1447
      fputs (ctype, stream);
1448
      break;
1449
    }
1450
 
1451
  if (! flag_jni)
1452
    {
1453
      while (array_depth-- > 0)
1454
        fputs ("> *", stream);
1455
    }
1456
 
1457
  return signature;
1458
}
1459
 
1460
static void
1461
print_c_decl (FILE* stream, JCF* jcf, int name_index, int signature_index,
1462
              int is_init, const char *name_override, int flags)
1463
{
1464
  if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1465
    {
1466
      fprintf (stream, "<not a UTF8 constant>");
1467
      found_error = 1;
1468
    }
1469
  else
1470
    {
1471
      int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1472
      const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1473
      const unsigned char *str = str0;
1474
      const unsigned char *limit = str + length;
1475
      int need_space = 0;
1476
      int is_method = str[0] == '(';
1477
      const unsigned char *next;
1478
 
1479
      /* If printing a method, skip to the return signature and print
1480
         that first.  However, there is no return value if this is a
1481
         constructor.  */
1482
      if (is_method && ! is_init)
1483
        {
1484
          while (str < limit)
1485
            {
1486
              int ch = *str++;
1487
              if (ch == ')')
1488
                break;
1489
            }
1490
        }
1491
 
1492
      /* If printing a field or an ordinary method, then print the
1493
         "return value" now.  */
1494
      if (! is_method || ! is_init)
1495
        {
1496
          next = decode_signature_piece (stream, str, limit, &need_space);
1497
          if (! next)
1498
            {
1499
              error ("unparseable signature: '%s'", str0);
1500
              return;
1501
            }
1502
        }
1503
 
1504
      /* Force the alignment of the first data member.  This is
1505
         because the "new" C++ ABI changed the alignment of non-POD
1506
         classes.  gcj, however, still uses the "old" alignment.  */
1507
      if (is_first_data_member && ! (flags & ACC_STATIC) && ! is_method)
1508
        {
1509
          is_first_data_member = 0;
1510
          print_cxx_classname (out, " __attribute__((aligned(__alignof__( ",
1511
                               jcf, jcf->super_class, 1);
1512
          fputs (" )))) ", stream);
1513
        }
1514
 
1515
      /* Now print the name of the thing.  */
1516
      if (need_space)
1517
        fputs (" ", stream);
1518
      print_full_cxx_name (stream, jcf, name_index,
1519
                           signature_index, is_init, name_override,
1520
                           flags);
1521
    }
1522
}
1523
 
1524
/* Print the unqualified method name followed by the signature. */
1525
static void
1526
print_full_cxx_name (FILE* stream, JCF* jcf, int name_index,
1527
                     int signature_index, int is_init,
1528
                     const char *name_override, int flags)
1529
{
1530
  int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1531
  const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1532
  const unsigned char *str = str0;
1533
  const unsigned char *limit = str + length;
1534
  int need_space = 0;
1535
  int is_method = str[0] == '(';
1536
  const unsigned char *next;
1537
 
1538
  if (name_override)
1539
    fputs (name_override, stream);
1540
  else if (name_index)
1541
    {
1542
      /* Declare constructors specially.  */
1543
      if (is_init)
1544
        print_base_classname (stream, jcf, jcf->this_class);
1545
      else
1546
        print_name (stream, jcf, name_index);
1547
    }
1548
 
1549
  if (flag_jni)
1550
    {
1551
      unsigned char *signature = JPOOL_UTF_DATA (jcf, signature_index);
1552
      int sig_len = JPOOL_UTF_LENGTH (jcf, signature_index);
1553
      if (overloaded_jni_method_exists_p (JPOOL_UTF_DATA (jcf, name_index),
1554
                                          JPOOL_UTF_LENGTH (jcf, name_index),
1555
                                          (const char *) signature, sig_len))
1556
        {
1557
          /* If this method is overloaded by another native method,
1558
             then include the argument information in the mangled
1559
             name.  */
1560
          unsigned char *limit = signature + sig_len;
1561
          fputs ("__", stream);
1562
          while (signature < limit)
1563
            {
1564
              int ch = UTF8_GET (signature, limit);
1565
              jni_print_char (stream, ch);
1566
              if (ch == ')')
1567
                {
1568
                  /* Done.  */
1569
                  break;
1570
                }
1571
            }
1572
        }
1573
    }
1574
 
1575
  if (is_method)
1576
    {
1577
      /* Have a method or a constructor.  Print signature pieces
1578
         until done.  */
1579
      fputs (" (", stream);
1580
 
1581
      str = str0 + 1;
1582
 
1583
      /* In JNI mode, add extra arguments.  */
1584
      if (flag_jni)
1585
        {
1586
          /* FIXME: it would be nice to know if we are printing a decl
1587
             or a definition, and only print `env' for the latter.  */
1588
          fputs ("JNIEnv *env", stream);
1589
 
1590
          fputs ((flags & ACC_STATIC) ? ", jclass" : ", jobject", stream);
1591
 
1592
          if (*str != ')')
1593
            fputs (", ", stream);
1594
        }
1595
 
1596
      while (str < limit && *str != ')')
1597
        {
1598
          next = decode_signature_piece (stream, str, limit, &need_space);
1599
          if (! next)
1600
            {
1601
              error ("unparseable signature: '%s'", str0);
1602
              return;
1603
            }
1604
 
1605
          if (next < limit && *next != ')')
1606
            fputs (", ", stream);
1607
          str = next;
1608
        }
1609
 
1610
      fputs (")", stream);
1611
    }
1612
}
1613
 
1614
/* This is a helper for print_stub_or_jni.  */
1615
static void
1616
print_name_for_stub_or_jni (FILE *stream, JCF *jcf, int name_index,
1617
                            int signature_index, int is_init,
1618
                            const char *name_override, int flags)
1619
{
1620
  const char *const prefix = flag_jni ? "Java_" : "";
1621
  print_cxx_classname (stream, prefix, jcf, jcf->this_class, 1);
1622
  fputs (flag_jni ? "_" : "::", stream);
1623
  print_full_cxx_name (stream, jcf, name_index,
1624
                       signature_index, is_init, name_override,
1625
                       flags);
1626
}
1627
 
1628
static void
1629
print_stub_or_jni (FILE* stream, JCF* jcf, int name_index,
1630
                   int signature_index, int is_init,
1631
                   const char *name_override, int flags)
1632
{
1633
  if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1634
    {
1635
      fprintf (stream, "<not a UTF8 constant>");
1636
      found_error = 1;
1637
    }
1638
  else
1639
    {
1640
      int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1641
      const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
1642
      const unsigned char *str = str0;
1643
      const unsigned char *limit = str + length;
1644
      int need_space = 0;
1645
      int is_method = str[0] == '(';
1646
      const unsigned char *next;
1647
 
1648
      /* Don't print fields in the JNI case.  */
1649
      if (! is_method && flag_jni)
1650
        return;
1651
 
1652
      if (flag_jni && ! stubs)
1653
        fputs ("JNIEXPORT ", stream);
1654
 
1655
      /* If printing a method, skip to the return signature and print
1656
         that first.  However, there is no return value if this is a
1657
         constructor.  */
1658
      if (is_method && ! is_init)
1659
        {
1660
          while (str < limit)
1661
            {
1662
              int ch = *str++;
1663
              if (ch == ')')
1664
                break;
1665
            }
1666
        }
1667
 
1668
      /* If printing a field or an ordinary method, then print the
1669
         "return value" now.  Note that a constructor can't be native,
1670
         so we don't bother checking this in the JNI case.  */
1671
      if (! is_method || ! is_init)
1672
        {
1673
          next = decode_signature_piece (stream, str, limit, &need_space);
1674
          if (! next)
1675
            {
1676
              error ("unparseable signature: '%s'", str0);
1677
              return;
1678
            }
1679
        }
1680
 
1681
      /* When printing a JNI header we need to respect the space.  In
1682
         other cases we're just going to insert a newline anyway.  */
1683
      fputs (need_space && ! stubs ? " " : "\n", stream);
1684
 
1685
      if (flag_jni && ! stubs)
1686
        fputs ("JNICALL ", stream);
1687
 
1688
      /* Now print the name of the thing.  */
1689
      print_name_for_stub_or_jni (stream, jcf, name_index,
1690
                                  signature_index, is_init, name_override,
1691
                                  flags);
1692
 
1693
      /* Print the body.  */
1694
      if (stubs)
1695
        {
1696
          if (flag_jni)
1697
            fputs ("\n{\n  (*env)->FatalError (env, \"", stream);
1698
          else
1699
            fputs ("\n{\n  throw new ::java::lang::UnsupportedOperationException (JvNewStringLatin1 (\"", stream);
1700
          print_name_for_stub_or_jni (stream, jcf, name_index,
1701
                                      signature_index, is_init,
1702
                                      name_override,
1703
                                      flags);
1704
          fprintf (stream, " not implemented\")%s;\n}\n\n",
1705
                   flag_jni ? "" : ")");
1706
        }
1707
    }
1708
}
1709
 
1710
static void
1711
print_mangled_classname (FILE *stream, JCF *jcf, const char *prefix, int index)
1712
{
1713
  int name_index = JPOOL_USHORT1 (jcf, index);
1714
  fputs (prefix, stream);
1715
  jcf_print_utf8_replace (out,
1716
                          JPOOL_UTF_DATA (jcf, name_index),
1717
                          JPOOL_UTF_LENGTH (jcf, name_index),
1718
                          '/', '_');
1719
}
1720
 
1721
/* Print PREFIX, then a class name in C++ format.  If the name refers
1722
   to an array, ignore it and don't print PREFIX.  Returns 1 if
1723
   something was printed, 0 otherwise.  */
1724
static int
1725
print_cxx_classname (FILE *stream, const char *prefix,
1726
                     JCF *jcf, int index, int add_scope)
1727
{
1728
  int name_index = JPOOL_USHORT1 (jcf, index);
1729
  int len, c;
1730
  const unsigned char *s, *p, *limit;
1731
 
1732
  s = JPOOL_UTF_DATA (jcf, name_index);
1733
  len = JPOOL_UTF_LENGTH (jcf, name_index);
1734
  limit = s + len;
1735
 
1736
  /* Explicitly omit arrays here.  */
1737
  p = s;
1738
  c = UTF8_GET (p, limit);
1739
  if (c == '[')
1740
    return 0;
1741
 
1742
  fputs (prefix, stream);
1743
 
1744
  /* Print a leading "::" so we look in the right namespace.  */
1745
  if (! flag_jni && ! stubs && add_scope)
1746
    fputs ("::", stream);
1747
 
1748
  while (s < limit)
1749
    {
1750
      c = UTF8_GET (s, limit);
1751
      if (c == '/')
1752
        fputs (flag_jni ? "_" : "::", stream);
1753
      else
1754
        jni_print_char (stream, c);
1755
    }
1756
 
1757
  return 1;
1758
}
1759
 
1760
int written_class_count = 0;
1761
 
1762
/* Return name of superclass.  If LEN is not NULL, fill it with length
1763
   of name.  */
1764
static const unsigned char *
1765
super_class_name (JCF *derived_jcf, int *len)
1766
{
1767
  int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
1768
  int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
1769
  const unsigned char *supername =
1770
    JPOOL_UTF_DATA (derived_jcf, supername_index);
1771
 
1772
  if (len)
1773
    *len = supername_length;
1774
 
1775
  return supername;
1776
}
1777
 
1778
static void
1779
handle_inner_classes (int count)
1780
{
1781
  int i;
1782
 
1783
  if (out && ! flag_jni && ! stubs && count > 0)
1784
    fprintf (out, "\n");
1785
 
1786
  for (i = 0; i < count; ++i)
1787
    {
1788
      JCF_u2 inner_info_index = JCF_readu2 (current_jcf);
1789
 
1790
      /* There are a few more values here, but we don't care about
1791
         them.  The (void) cast is apparently the only way to avoid a
1792
         warning here.  */
1793
      (void) JCF_readu2 (current_jcf);
1794
      (void) JCF_readu2 (current_jcf);
1795
      (void) JCF_readu2 (current_jcf);
1796
 
1797
      if (out && ! flag_jni && ! stubs)
1798
        {
1799
          print_mangled_classname (out, current_jcf, "  friend class ",
1800
                                   inner_info_index);
1801
          fprintf (out, ";\n");
1802
        }
1803
    }
1804
}
1805
 
1806
 
1807
 
1808
/* We keep track of all the `#include's we generate, so we can avoid
1809
   duplicates.  */
1810
struct include
1811
{
1812
  char *name;
1813
  struct include *next;
1814
};
1815
 
1816
/* List of all includes.  */
1817
static struct include *all_includes = NULL;
1818
 
1819
/* Generate a #include.  */
1820
static void
1821
print_include (FILE *out, const unsigned char *utf8, int len)
1822
{
1823
  struct include *incl;
1824
 
1825
  if (! out)
1826
    return;
1827
 
1828
  if (len == -1)
1829
    len = strlen ((const char *) utf8);
1830
 
1831
  for (incl = all_includes; incl; incl = incl->next)
1832
    {
1833
      /* We check the length because we might have a proper prefix.  */
1834
      if (len == (int) strlen (incl->name)
1835
          && ! strncmp (incl->name, (const char *) utf8, len))
1836
        return;
1837
    }
1838
 
1839
  incl = xmalloc (sizeof (struct include));
1840
  incl->name = xmalloc (len + 1);
1841
  strncpy (incl->name, (const char *) utf8, len);
1842
  incl->name[len] = '\0';
1843
  incl->next = all_includes;
1844
  all_includes = incl;
1845
 
1846
  fputs ("#include <", out);
1847
  jcf_print_utf8_replace (out, utf8, len,
1848
                          '/',
1849
                          flag_jni ? '_' : '/');
1850
  fputs (".h>\n", out);
1851
}
1852
 
1853
 
1854
 
1855
/* This is used to represent part of a package or class name.  */
1856
struct namelet
1857
{
1858
  /* The text of this part of the name.  */
1859
  char *name;
1860
  /* True if this represents a class.  */
1861
  int is_class;
1862
  /* Linked list of all classes and packages inside this one.  */
1863
  struct namelet *subnamelets;
1864
  /* Pointer to next sibling.  */
1865
  struct namelet *next;
1866
};
1867
 
1868
static void add_namelet (const unsigned char *, const unsigned char *,
1869
                         struct namelet *);
1870
static void print_namelet (FILE *, struct namelet *, int);
1871
 
1872
/* The special root namelet.  */
1873
static struct namelet root =
1874
{
1875
  NULL,
1876
  0,
1877
  NULL,
1878
  NULL
1879
};
1880
 
1881
/* This extracts the next name segment from the full UTF-8 encoded
1882
   package or class name and links it into the tree.  It does this
1883
   recursively.  */
1884
static void
1885
add_namelet (const unsigned char *name, const unsigned char *name_limit,
1886
             struct namelet *parent)
1887
{
1888
  const unsigned char *p;
1889
  struct namelet *n = NULL, *np;
1890
 
1891
  /* We want to skip the standard namespaces that we assume the
1892
     runtime already knows about.  We only do this at the top level,
1893
     though, hence the check for `root'.  */
1894
  if (parent == &root)
1895
    {
1896
#define JAVALANG "java/lang/"
1897
#define JAVAIO "java/io/"
1898
#define JAVAUTIL "java/util/"
1899
      if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
1900
           && ! strncmp ((const char *) name, JAVALANG, sizeof (JAVALANG) - 1))
1901
          || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
1902
              && ! strncmp ((const char *) name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
1903
          || (name_limit - name >= (int) sizeof (JAVAIO) - 1
1904
              && ! strncmp ((const char *) name, JAVAIO, sizeof (JAVAIO) - 1)))
1905
        return;
1906
    }
1907
 
1908
  for (p = name; p < name_limit && *p != '/'; ++p)
1909
    ;
1910
 
1911
  /* Search for this name beneath the PARENT node.  */
1912
  for (np = parent->subnamelets; np != NULL; np = np->next)
1913
    {
1914
      /* We check the length because we might have a proper prefix.  */
1915
      if ((int) strlen (np->name) == p - name &&
1916
          ! strncmp ((const char *) name, np->name, p - name))
1917
        {
1918
          n = np;
1919
          break;
1920
        }
1921
    }
1922
 
1923
  if (n == NULL)
1924
    {
1925
      n = xmalloc (sizeof (struct namelet));
1926
      n->name = xmalloc (p - name + 1);
1927
      strncpy (n->name, (const char *) name, p - name);
1928
      n->name[p - name] = '\0';
1929
      n->is_class = (p == name_limit);
1930
      n->subnamelets = NULL;
1931
      n->next = parent->subnamelets;
1932
      parent->subnamelets = n;
1933
    }
1934
 
1935
  /* We recurse if there is more text, and if the trailing piece does
1936
     not represent an inner class. */
1937
  if (p < name_limit)
1938
    add_namelet (p + 1, name_limit, n);
1939
}
1940
 
1941
/* Print a single namelet.  Destroys namelets while printing.  */
1942
static void
1943
print_namelet (FILE *out, struct namelet *name, int depth)
1944
{
1945
  int i, term = 0;
1946
  struct namelet *c;
1947
 
1948
  if (name->name)
1949
    {
1950
      for (i = 0; i < depth; ++i)
1951
        fputc (' ', out);
1952
      fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
1953
               name->name);
1954
      if (name->is_class && name->subnamelets == NULL)
1955
        fputs (";\n", out);
1956
      else
1957
        {
1958
          term = 1;
1959
          fputs ("\n", out);
1960
          for (i = 0; i < depth; ++i)
1961
            fputc (' ', out);
1962
          fputs ("{\n", out);
1963
        }
1964
    }
1965
 
1966
  c = name->subnamelets;
1967
  while (c != NULL)
1968
    {
1969
      struct namelet *next = c->next;
1970
      print_namelet (out, c, depth + 2);
1971
      c = next;
1972
    }
1973
  name->subnamelets = NULL;
1974
 
1975
  if (name->name)
1976
    {
1977
      if (term)
1978
        {
1979
          for (i = 0; i < depth; ++i)
1980
            fputc (' ', out);
1981
          fputs ("}\n", out);
1982
          /* Only print a `;' when printing a class.  C++ is evil.  */
1983
          if (name->is_class)
1984
            fputs (";", out);
1985
        }
1986
 
1987
      free (name->name);
1988
      free (name);
1989
    }
1990
}
1991
 
1992
/* This is called to add some classes to the list of classes for which
1993
   we need decls.  The signature argument can be a function
1994
   signature.  */
1995
static void
1996
add_class_decl (FILE *out, JCF *jcf, JCF_u2 signature)
1997
{
1998
  const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
1999
  int len = JPOOL_UTF_LENGTH (jcf, signature);
2000
  int i;
2001
 
2002
  for (i = 0; i < len; ++i)
2003
    {
2004
      int start;
2005
 
2006
      /* If we see an array, then we include the array header.  */
2007
      if (s[i] == '[')
2008
        {
2009
          print_include (out, (const unsigned char *) "gcj/array", -1);
2010
          continue;
2011
        }
2012
 
2013
      /* We're looking for `L<stuff>;' -- everything else is
2014
         ignorable.  */
2015
      if (s[i] != 'L')
2016
        continue;
2017
 
2018
      for (start = ++i; i < len && s[i] != ';'; ++i)
2019
        ;
2020
 
2021
      add_namelet (&s[start], &s[i], &root);
2022
    }
2023
}
2024
 
2025
/* Print declarations for all classes required by this class.  Any
2026
   class or package in the `java' package is assumed to be handled
2027
   statically in libjava; we don't generate declarations for these.
2028
   This makes the generated headers a bit easier to read.  */
2029
static void
2030
print_class_decls (FILE *out, JCF *jcf, int self)
2031
{
2032
  /* Make sure to always add the current class to the list of things
2033
     that should be declared.  */
2034
  int name_index = JPOOL_USHORT1 (jcf, self);
2035
  int len;
2036
  const unsigned char *s;
2037
 
2038
  s = JPOOL_UTF_DATA (jcf, name_index);
2039
  len = JPOOL_UTF_LENGTH (jcf, name_index);
2040
  add_namelet (s, s + len, &root);
2041
 
2042
  if (root.subnamelets)
2043
    {
2044
      fputs ("extern \"Java\"\n{\n", out);
2045
      /* We use an initial offset of 0 because the root namelet
2046
         doesn't cause anything to print.  */
2047
      print_namelet (out, &root, 0);
2048
      fputs ("}\n\n", out);
2049
    }
2050
}
2051
 
2052
 
2053
 
2054
static void
2055
process_file (JCF *jcf, FILE *out)
2056
{
2057
  int code, i;
2058
  uint32 field_start, method_end, method_start;
2059
 
2060
  current_jcf = jcf;
2061
 
2062
  last_access = -1;
2063
 
2064
  if (jcf_parse_preamble (jcf) != 0)
2065
    {
2066
      error ("Not a valid Java .class file.");
2067
      return;
2068
    }
2069
 
2070
  /* Parse and possibly print constant pool */
2071
  code = jcf_parse_constant_pool (jcf);
2072
  if (code != 0)
2073
    {
2074
      error ("error while parsing constant pool");
2075
      return;
2076
    }
2077
  code = verify_constant_pool (jcf);
2078
  if (code > 0)
2079
    {
2080
      error ("error in constant pool entry #%d", code);
2081
      return;
2082
    }
2083
 
2084
  jcf_parse_class (jcf);
2085
 
2086
  if (written_class_count++ == 0 && out)
2087
    {
2088
      const char *cstart, *cstart2, *mode, *cend, *what, *jflag;
2089
      if (flag_jni)
2090
        {
2091
          cstart = "/*";
2092
          cstart2 = "  ";
2093
          cend = " */";
2094
          mode = "";
2095
          what = "JNI";
2096
          jflag = " -jni";
2097
        }
2098
      else
2099
        {
2100
          cstart = "//";
2101
          cstart2 = "//";
2102
          cend = "";
2103
          mode = " -*- c++ -*-";
2104
          what = "CNI";
2105
          jflag = "";
2106
        }
2107
 
2108
      if (! stubs)
2109
        fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
2110
                 cstart, mode, cend);
2111
      else
2112
        {
2113
          fprintf (out, "%s This file was created by `" TOOLNAME " -stubs%s'.%s\n\
2114
%s\n\
2115
%s This file is intended to give you a head start on implementing native\n\
2116
%s methods using %s.\n\
2117
%s Be aware: running `" TOOLNAME " -stubs %s' once more for this class may\n\
2118
%s overwrite any edits you have made to this file.%s\n\n",
2119
                   cstart, jflag, mode,
2120
                   cstart2,
2121
                   cstart2,
2122
                   cstart2,
2123
                   what,
2124
                   cstart2,
2125
                   jflag,
2126
                   cstart2,
2127
                   cend);
2128
        }
2129
    }
2130
 
2131
  if (out)
2132
    {
2133
      if (! stubs)
2134
        {
2135
          print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
2136
          fprintf (out, "__\n");
2137
 
2138
          print_mangled_classname (out, jcf, "#define __", jcf->this_class);
2139
          fprintf (out, "__\n\n");
2140
 
2141
          if (flag_jni)
2142
            {
2143
              fprintf (out, "#include <jni.h>\n\n");
2144
              fprintf (out, "#ifdef __cplusplus\n");
2145
              fprintf (out, "extern \"C\"\n");
2146
              fprintf (out, "{\n");
2147
              fprintf (out, "#endif\n");
2148
            }
2149
          else
2150
            {
2151
              /* We do this to ensure that inline methods won't be
2152
                 `outlined' by g++.  This works as long as method and
2153
                 fields are not added by the user.  */
2154
              fprintf (out, "#pragma interface\n");
2155
 
2156
              if (jcf->super_class)
2157
                {
2158
                  int super_length;
2159
                  const unsigned char *supername =
2160
                    super_class_name (jcf, &super_length);
2161
 
2162
                  fputs ("\n", out);
2163
                  print_include (out, supername, super_length);
2164
                }
2165
            }
2166
        }
2167
      else
2168
        {
2169
          /* Strip off the ".class" portion of the name when printing
2170
             the include file name.  */
2171
          char *name;
2172
          int i, len = strlen (jcf->classname);
2173
          if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
2174
            len -= 6;
2175
          /* Turn the class name into a file name.  */
2176
          name = xmalloc (len + 1);
2177
          for (i = 0; i < len; ++i)
2178
            name[i] = jcf->classname[i] == '.' ? '/' : jcf->classname[i];
2179
          name[i] = '\0';
2180
          print_include (out, (const unsigned char *) name, len);
2181
          free (name);
2182
 
2183
          if (! flag_jni)
2184
            {
2185
              print_include (out, (const unsigned char *) "gcj/cni", -1);
2186
              print_include (out, (const unsigned char *) "java/lang/UnsupportedOperationException",
2187
                             -1);
2188
            }
2189
        }
2190
    }
2191
 
2192
  /* We want to parse the methods first.  But we need to find where
2193
     they start.  So first we skip the fields, then parse the methods.
2194
     Then we parse the fields and skip the methods.  This is ugly, but
2195
     not too bad since we need two full passes to get class decl
2196
     information anyway.  */
2197
  field_pass = 0;
2198
  field_start = JCF_TELL (jcf);
2199
  jcf_parse_fields (jcf);
2200
 
2201
  method_start = JCF_TELL (jcf);
2202
  method_pass = 0;
2203
  jcf_parse_methods (jcf);
2204
 
2205
  if (out)
2206
    fputs ("\n", out);
2207
 
2208
  if (out && ! flag_jni)
2209
    {
2210
      if (! stubs)
2211
        print_class_decls (out, jcf, jcf->this_class);
2212
 
2213
      for (i = 0; i < prepend_count; ++i)
2214
        fprintf (out, "%s\n", prepend_specs[i]);
2215
      if (prepend_count > 0)
2216
        fputc ('\n', out);
2217
 
2218
      if (! stubs)
2219
        {
2220
          if (! print_cxx_classname (out, "class ", jcf,
2221
                                     jcf->this_class, 0))
2222
            {
2223
              error ("class is of array type\n");
2224
              return;
2225
            }
2226
          if (jcf->super_class)
2227
            {
2228
              if (! print_cxx_classname (out, " : public ",
2229
                                         jcf, jcf->super_class, 1))
2230
                {
2231
                  error ("base class is of array type");
2232
                  return;
2233
                }
2234
            }
2235
 
2236
          fputs ("\n{\n", out);
2237
        }
2238
    }
2239
 
2240
  /* Now go back for second pass over methods and fields.  */
2241
  is_first_data_member = 1;
2242
 
2243
  JCF_SEEK (jcf, method_start);
2244
  method_pass = 1;
2245
  jcf_parse_methods (jcf);
2246
  method_end = JCF_TELL (jcf);
2247
 
2248
  field_pass = 1;
2249
  JCF_SEEK (jcf, field_start);
2250
  jcf_parse_fields (jcf);
2251
  JCF_SEEK (jcf, method_end);
2252
 
2253
  jcf_parse_final_attributes (jcf);
2254
 
2255
  if (out && ! stubs)
2256
    {
2257
      if (flag_jni)
2258
        {
2259
          fprintf (out, "\n#ifdef __cplusplus\n");
2260
          fprintf (out, "}\n");
2261
          fprintf (out, "#endif\n");
2262
        }
2263
      else
2264
        {
2265
          /* Generate friend decl if we still must.  */
2266
          for (i = 0; i < friend_count; ++i)
2267
            fprintf (out, "  friend %s\n", friend_specs[i]);
2268
 
2269
          /* Generate extra declarations.  */
2270
          if (add_count > 0)
2271
            fputc ('\n', out);
2272
          for (i = 0; i < add_count; ++i)
2273
            fprintf (out, "  %s\n", add_specs[i]);
2274
 
2275
          /* Generate an entry for the class object.  */
2276
          generate_access (out, ACC_PUBLIC);
2277
          fprintf (out, "\n  static ::java::lang::Class class$;\n");
2278
 
2279
          fputs ("}", out);
2280
 
2281
          if (jcf->access_flags & ACC_INTERFACE)
2282
            fputs (" __attribute__ ((java_interface))", out);
2283
 
2284
          fputs (";\n", out);
2285
 
2286
          if (append_count > 0)
2287
            fputc ('\n', out);
2288
          for (i = 0; i < append_count; ++i)
2289
            fprintf (out, "%s\n", append_specs[i]);
2290
        }
2291
 
2292
      print_mangled_classname (out, jcf,
2293
                               "\n#endif /* __", jcf->this_class);
2294
      fprintf (out, "__ */\n");
2295
    }
2296
}
2297
 
2298
 
2299
 
2300
/* This is used to mark options with no short value.  */
2301
#define LONG_OPT(Num)  ((Num) + 128)
2302
 
2303
#define OPT_classpath     LONG_OPT (0)
2304
#define OPT_CLASSPATH     OPT_classpath
2305
#define OPT_bootclasspath LONG_OPT (1)
2306
#define OPT_extdirs       LONG_OPT (2)
2307
#define OPT_HELP          LONG_OPT (3)
2308
#define OPT_TEMP          LONG_OPT (4)
2309
#define OPT_VERSION       LONG_OPT (5)
2310
#define OPT_PREPEND       LONG_OPT (6)
2311
#define OPT_FRIEND        LONG_OPT (7)
2312
#define OPT_ADD           LONG_OPT (8)
2313
#define OPT_APPEND        LONG_OPT (9)
2314
#define OPT_M             LONG_OPT (10)
2315
#define OPT_MM            LONG_OPT (11)
2316
#define OPT_MG            LONG_OPT (12)
2317
#define OPT_MD            LONG_OPT (13)
2318
#define OPT_MMD           LONG_OPT (14)
2319
#define OPT_FORCE         LONG_OPT (15)
2320
#define OPT_OLD           LONG_OPT (16)
2321
#define OPT_TRACE         LONG_OPT (17)
2322
 
2323
static const struct option options[] =
2324
{
2325
  { "classpath",     required_argument, NULL, OPT_classpath },
2326
  { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
2327
  { "extdirs",       required_argument, NULL, OPT_extdirs },
2328
  { "CLASSPATH",     required_argument, NULL, OPT_CLASSPATH },
2329
  { "help",          no_argument,       NULL, OPT_HELP },
2330
  { "stubs",         no_argument,       &stubs, 1 },
2331
  { "td",            required_argument, NULL, OPT_TEMP },
2332
  { "verbose",       no_argument,       NULL, 'v' },
2333
  { "version",       no_argument,       NULL, OPT_VERSION },
2334
  { "prepend",       required_argument, NULL, OPT_PREPEND },
2335
  { "friend",        required_argument, NULL, OPT_FRIEND },
2336
  { "add",           required_argument, NULL, OPT_ADD },
2337
  { "append",        required_argument, NULL, OPT_APPEND },
2338
  { "M",             no_argument,       NULL, OPT_M   },
2339
  { "MM",            no_argument,       NULL, OPT_MM  },
2340
  { "MG",            no_argument,       NULL, OPT_MG  },
2341
  { "MD",            no_argument,       NULL, OPT_MD  },
2342
  { "MMD",           no_argument,       NULL, OPT_MMD },
2343
  { "jni",           no_argument,       &flag_jni, 1 },
2344
  { "force",         no_argument,       NULL, OPT_FORCE },
2345
  /* If the output file should be named "ld" then a space is needed
2346
     between -o and its argument, ld. */
2347
  { "old",           no_argument,       NULL, OPT_OLD },
2348
  { "trace",         no_argument,       NULL, OPT_TRACE },
2349
  { NULL,            required_argument, NULL, 'J' },
2350
  { NULL,            no_argument,       NULL, 0 }
2351
};
2352
 
2353
static void
2354
usage (void)
2355
{
2356
  fprintf (stderr, _("Try '" TOOLNAME " --help' for more information.\n"));
2357
  exit (1);
2358
}
2359
 
2360
static void
2361
help (void)
2362
{
2363
  printf (_("Usage: " TOOLNAME " [OPTION]... CLASS...\n\n"));
2364
  printf (_("Generate C or C++ header files from .class files\n\n"));
2365
  printf (_("  -stubs                  Generate an implementation stub file\n"));
2366
  printf (_("  -jni                    Generate a JNI header or stub\n"));
2367
  printf (_("  -force                  Always overwrite output files\n"));
2368
  printf (_("  -old                    Unused compatibility option\n"));
2369
  printf (_("  -trace                  Unused compatibility option\n"));
2370
  printf (_("  -J OPTION               Unused compatibility option\n"));
2371
  printf ("\n");
2372
  printf (_("  -add TEXT               Insert TEXT into class body\n"));
2373
  printf (_("  -append TEXT            Insert TEXT after class declaration\n"));
2374
  printf (_("  -friend TEXT            Insert TEXT as 'friend' declaration\n"));
2375
  printf (_("  -prepend TEXT           Insert TEXT before start of class\n"));
2376
  printf ("\n");
2377
  printf (_("  --classpath PATH        Set path to find .class files\n"));
2378
  printf (_("  -IDIR                   Append directory to class path\n"));
2379
  printf (_("  --bootclasspath PATH    Override built-in class path\n"));
2380
  printf (_("  --extdirs PATH          Set extensions directory path\n"));
2381
  printf (_("  -d DIRECTORY            Set output directory name\n"));
2382
  printf (_("  -o FILE                 Set output file name\n"));
2383
  printf (_("  -td DIRECTORY           Set temporary directory name\n"));
2384
  printf ("\n");
2385
  printf (_("  --help                  Print this help, then exit\n"));
2386
  printf (_("  --version               Print version number, then exit\n"));
2387
  printf (_("  -v, --verbose           Print extra information while running\n"));
2388
  printf ("\n");
2389
  printf (_("  -M                      Print all dependencies to stdout;\n"
2390
            "                             suppress ordinary output\n"));
2391
  printf (_("  -MM                     Print non-system dependencies to stdout;\n"
2392
            "                             suppress ordinary output\n"));
2393
  printf (_("  -MD                     Print all dependencies to stdout\n"));
2394
  printf (_("  -MMD                    Print non-system dependencies to stdout\n"));
2395
  /* We omit -MG until it is implemented.  */
2396
  printf ("\n");
2397
  printf (_("For bug reporting instructions, please see:\n"
2398
            "%s.\n"), bug_report_url);
2399
  exit (0);
2400
}
2401
 
2402
static void
2403
version (void)
2404
{
2405
  printf (TOOLNAME " (GCC) %s\n\n", version_string);
2406
  printf ("Copyright %s 2006 Free Software Foundation, Inc.\n", _("(C)"));
2407
  printf (_("This is free software; see the source for copying conditions.  There is NO\n"
2408
            "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
2409
  exit (0);
2410
}
2411
 
2412
int
2413
main (int argc, char** argv)
2414
{
2415
  JCF jcf;
2416
  int argi;
2417
  char *output_file = NULL;
2418
  int emit_dependencies = 0, suppress_output = 0;
2419
  int opt;
2420
  int local_found_error;
2421
 
2422
  /* Unlock the stdio streams.  */
2423
  unlock_std_streams ();
2424
 
2425
  gcc_init_libintl ();
2426
 
2427
  if (argc <= 1)
2428
    {
2429
      error ("no classes specified");
2430
      usage ();
2431
    }
2432
 
2433
  jcf_path_init ();
2434
 
2435
  /* We use getopt_long_only to allow single `-' long options.  For
2436
     some of our options this is more natural.  */
2437
  while ((opt = getopt_long_only (argc, argv, "J:I:d:o:v", options, NULL)) != -1)
2438
    {
2439
      switch (opt)
2440
        {
2441
        case 0:
2442
          /* Already handled.  */
2443
          break;
2444
 
2445
        case 'o':
2446
          output_file = optarg;
2447
          break;
2448
 
2449
        case 'd':
2450
          output_directory = optarg;
2451
          break;
2452
 
2453
        case 'I':
2454
          jcf_path_include_arg (optarg);
2455
          break;
2456
 
2457
        case 'v':
2458
          verbose++;
2459
          break;
2460
 
2461
        case OPT_classpath:
2462
          jcf_path_classpath_arg (optarg);
2463
          break;
2464
 
2465
        case OPT_bootclasspath:
2466
          jcf_path_bootclasspath_arg (optarg);
2467
          break;
2468
 
2469
        case OPT_extdirs:
2470
          jcf_path_extdirs_arg (optarg);
2471
          break;
2472
 
2473
        case OPT_HELP:
2474
          help ();
2475
          break;
2476
 
2477
        case OPT_TEMP:
2478
          temp_directory = optarg;
2479
          break;
2480
 
2481
        case OPT_VERSION:
2482
          version ();
2483
          break;
2484
 
2485
        case OPT_PREPEND:
2486
          if (prepend_count == 0)
2487
            prepend_specs = ALLOC (argc * sizeof (char*));
2488
          prepend_specs[prepend_count++] = optarg;
2489
          break;
2490
 
2491
        case OPT_FRIEND:
2492
          if (friend_count == 0)
2493
            friend_specs = ALLOC (argc * sizeof (char*));
2494
          friend_specs[friend_count++] = optarg;
2495
          break;
2496
 
2497
        case OPT_ADD:
2498
          if (add_count == 0)
2499
            add_specs = ALLOC (argc * sizeof (char*));
2500
          add_specs[add_count++] = optarg;
2501
          break;
2502
 
2503
        case OPT_APPEND:
2504
          if (append_count == 0)
2505
            append_specs = ALLOC (argc * sizeof (char*));
2506
          append_specs[append_count++] = optarg;
2507
          break;
2508
 
2509
        case OPT_M:
2510
          emit_dependencies = 1;
2511
          suppress_output = 1;
2512
          jcf_dependency_init (1);
2513
          break;
2514
 
2515
        case OPT_MM:
2516
          emit_dependencies = 1;
2517
          suppress_output = 1;
2518
          jcf_dependency_init (0);
2519
          break;
2520
 
2521
        case OPT_MG:
2522
          error ("'-MG' option is unimplemented");
2523
          exit (1);
2524
 
2525
        case OPT_MD:
2526
          emit_dependencies = 1;
2527
          jcf_dependency_init (1);
2528
          break;
2529
 
2530
        case OPT_MMD:
2531
          emit_dependencies = 1;
2532
          jcf_dependency_init (0);
2533
          break;
2534
 
2535
        case OPT_FORCE:
2536
          break;
2537
 
2538
        case OPT_OLD:
2539
          break;
2540
 
2541
        case OPT_TRACE:
2542
          break;
2543
 
2544
        case 'J':
2545
          /* Ignore -J options. */
2546
          break;
2547
 
2548
        default:
2549
          usage ();
2550
          break;
2551
        }
2552
    }
2553
 
2554
  if (optind == argc)
2555
    {
2556
      error ("no classes specified");
2557
      usage ();
2558
    }
2559
 
2560
  jcf_path_seal (verbose);
2561
 
2562
  if (output_file && emit_dependencies)
2563
    {
2564
      error ("can't specify both -o and -MD");
2565
      exit (1);
2566
    }
2567
 
2568
  local_found_error = 0;
2569
  for (argi = optind; argi < argc; argi++)
2570
    {
2571
      char *classname = argv[argi];
2572
      char *current_output_file = NULL;
2573
      const char *classfile_name;
2574
 
2575
      /* We reset the error state here so that we can detect errors
2576
         that occur when processing this file, so the output can be
2577
         unlinked if need be.  */
2578
      found_error = 0;
2579
 
2580
      if (verbose)
2581
        printf (_("Processing %s\n"), classname);
2582
      if (! output_file)
2583
        jcf_dependency_reset ();
2584
      classfile_name = find_class (classname, strlen (classname), &jcf, 0);
2585
      if (classfile_name == NULL)
2586
        {
2587
          error ("%s: no such class", classname);
2588
          exit (1);
2589
        }
2590
      if (verbose)
2591
        printf (_("Found in %s\n"), classfile_name);
2592
      if (output_file)
2593
        {
2594
          if (strcmp (output_file, "-") == 0)
2595
            out = stdout;
2596
          else if (out == NULL)
2597
            {
2598
              out = fopen (output_file, "w");
2599
            }
2600
          if (out == NULL)
2601
            {
2602
              perror (output_file);
2603
              exit (1);
2604
            }
2605
          current_output_file = output_file;
2606
        }
2607
      else
2608
        {
2609
          int dir_len = strlen (output_directory);
2610
          int i, classname_length = strlen (classname);
2611
          current_output_file = ALLOC (dir_len + classname_length + 5);
2612
          strcpy (current_output_file, output_directory);
2613
          if (dir_len > 0 && output_directory[dir_len-1] != '/')
2614
            current_output_file[dir_len++] = '/';
2615
          for (i = 0; classname[i] != '\0'; i++)
2616
            {
2617
              char ch = classname[i];
2618
              if (ch == '.')
2619
                ch = '/';
2620
              if (flag_jni && ch == '/')
2621
                ch = '_';
2622
              current_output_file[dir_len++] = ch;
2623
            }
2624
          if (emit_dependencies)
2625
            {
2626
              if (suppress_output)
2627
                {
2628
                  jcf_dependency_set_dep_file ("-");
2629
                  out = NULL;
2630
                }
2631
              else
2632
                {
2633
                  /* We use `.hd' and not `.d' to avoid clashes with
2634
                     dependency tracking from straight compilation.  */
2635
                  strcpy (current_output_file + dir_len, ".hd");
2636
                  jcf_dependency_set_dep_file (current_output_file);
2637
                }
2638
            }
2639
          strcpy (current_output_file + dir_len,
2640
                  stubs ? (flag_jni ? ".c" : ".cc") : ".h");
2641
          jcf_dependency_set_target (current_output_file);
2642
          if (! suppress_output)
2643
            {
2644
              out = fopen (current_output_file, "w");
2645
              if (out == NULL)
2646
                {
2647
                  perror (current_output_file);
2648
                  exit (1);
2649
                }
2650
            }
2651
        }
2652
      free_method_name_list ();
2653
      process_file (&jcf, out);
2654
      JCF_FINISH (&jcf);
2655
 
2656
      /* If we found an error and we're writing to a real file,
2657
         delete it.  */
2658
      if (found_error && ! suppress_output && current_output_file != NULL
2659
          && strcmp (current_output_file, "-"))
2660
        unlink (current_output_file);
2661
 
2662
      if (current_output_file != output_file)
2663
        free (current_output_file);
2664
      jcf_dependency_write ();
2665
 
2666
      local_found_error |= found_error;
2667
    }
2668
 
2669
  if (out != NULL && out != stdout)
2670
    fclose (out);
2671
 
2672
  return local_found_error;
2673
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.