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