home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl560.zip / jpl / JPL / Compile.pm < prev    next >
Text File  |  1999-09-14  |  17KB  |  770 lines

  1. #!/usr/bin/perl -w
  2.  
  3. # Copyright 1997, O'Reilly & Associate, Inc.
  4. #
  5. # This package may be copied under the same terms as Perl itself.
  6.  
  7. package JPL::Compile;
  8. use Exporter ();
  9. @ISA = qw(Exporter);
  10. @EXPORT = qw(files file);
  11.  
  12. use strict;
  13.  
  14.  
  15. warn "You don't have a recent JDK kit your PATH, so this may fail.\n"
  16.     unless $ENV{PATH} =~ /(java|jdk1.[1-9])/;
  17.  
  18. sub emit;
  19.  
  20. my $PERL = "";
  21. my $LASTCLASS = "";
  22. my $PERLLINE = 0;
  23. my $PROTO;
  24.  
  25. my @protos;
  26.  
  27. my $plfile;
  28. my $jpfile;
  29. my $hfile;
  30. my $h_file;
  31. my $cfile;
  32. my $jfile;
  33. my $classfile;
  34.  
  35. my $DEBUG = $ENV{JPLDEBUG};
  36.  
  37. my %ptype = qw(
  38.     Z boolean
  39.     B byte
  40.     C char
  41.     S short
  42.     I int
  43.     J long
  44.     F float
  45.     D double
  46. );
  47.  
  48. $ENV{CLASSPATH} =~ s/^/.:/ unless $ENV{CLASSPATH} =~ /^\.(?::|$)/;
  49.  
  50. unless (caller) {
  51.     files(@ARGV);
  52. }
  53.  
  54. #######################################################################
  55.  
  56. sub files {
  57.     foreach my $jpfile (@_) {
  58.     file($jpfile);
  59.     }
  60.     print "make\n";
  61.     system "make";
  62. }
  63.  
  64. sub file {
  65.     my $jpfile = shift;
  66.     my $JAVA = "";
  67.     my $lastpos = 0;
  68.     my $linenum = 2;
  69.     my %classseen;
  70.     my %fieldsig;
  71.     my %staticfield;
  72.  
  73.     (my $file = $jpfile) =~ s/\.jpl$//;
  74.     $jpfile = "$file.jpl";
  75.     $jfile = "$file.java";
  76.     $hfile = "$file.h";
  77.     $cfile = "$file.c";
  78.     $plfile = "$file.pl";
  79.     $classfile = "$file.class";
  80.  
  81.     ($h_file = $hfile) =~ s/_/_0005f/g;
  82.  
  83.     emit_c_header();
  84.  
  85.     # Extract out arg names from .java file, since .class doesn't have 'em.
  86.  
  87.     open(JPFILE, $jpfile) or die "Can't open $jpfile: $!\n";
  88.     undef $/;
  89.     $_ = <JPFILE>;
  90.     close JPFILE;
  91.  
  92.     die "$jpfile doesn't seem to define class $file!\n"
  93.     unless /class\s+\b$file\b[\w\s.,]*{/;
  94.  
  95.     @protos = ();
  96.     open(JFILE, ">$jfile") or die "Can't create $jfile: $!\n";
  97.  
  98.     while (m/\bperl\b([^\n]*?\b(\w+)\s*\(\s*(.*?)\s*\)[\s\w.,]*)\{\{(.*?)\}\}/sg) {
  99.     $JAVA = substr($`, $lastpos);
  100.     $lastpos = pos $_;
  101.     $JAVA .= "native";
  102.     $JAVA .= $1;
  103.  
  104.     my $method = $2;
  105.  
  106.     my $proto = $3;
  107.  
  108.     my $perl = $4;
  109.     (my $repl = $4) =~ tr/\n//cd;
  110.     $JAVA .= ';';
  111.     $linenum += $JAVA =~ tr/\n/\n/;
  112.     $JAVA .= $repl;
  113.     print JFILE $JAVA;
  114.  
  115.     $proto =~ s/\s+/ /g;
  116.     $perl =~ s/^[ \t]+\Z//m;
  117.     $perl =~ s/^[ \t]*\n//;
  118.     push(@protos, [$method, $proto, $perl, $linenum]);
  119.  
  120.     $linenum += $repl =~ tr/\n/\n/;
  121.     }
  122.  
  123.     print JFILE <<"END";
  124.     static {
  125.     System.loadLibrary("$file");
  126.         PerlInterpreter pi = new PerlInterpreter().fetch();
  127.         // pi.eval("\$JPL::DEBUG = \$ENV{JPLDEBUG};");
  128.     pi.eval("warn qq{loading $file\\n} if \$JPL::DEBUG");
  129.     pi.eval("eval {require '$plfile'}; print \$@ if \$@;");
  130.     }
  131. END
  132.  
  133.     print JFILE substr($_, $lastpos);
  134.  
  135.     close JFILE;
  136.  
  137.     # Produce the corresponding .h file.  Should really use make...
  138.  
  139.     if (not -s $hfile or -M $hfile > -M $jfile) {
  140.     if (not -s $classfile or -M $classfile > -M $jfile) {
  141.         unlink $classfile;
  142.         print  "javac $jfile\n";
  143.         system "javac $jfile" and die "Couldn't run javac: exit $?\n";
  144.         if (not -s $classfile or -M $classfile > -M $jfile) {
  145.         die "Couldn't produce $classfile from $jfile!";
  146.         }
  147.     }
  148.     unlink $hfile;
  149.     print  "javah -jni $file\n";
  150.     system "javah -jni $file" and die "Couldn't run javah: exit $?\n";
  151.     if (not -s $hfile and -s $h_file) {
  152.         rename $h_file, $hfile;
  153.     }
  154.     if (not -s $hfile or -M $hfile > -M $jfile) {
  155.         die "Couldn't produce $hfile from $classfile!";
  156.     }
  157.     }
  158.  
  159.     # Easiest place to get fields is from javap.
  160.  
  161.     print  "javap -s $file\n";
  162.     open(JP, "javap -s $file|");
  163.     $/ = "\n";
  164.     while (<JP>) {
  165.     if (/^\s+([A-Za-z_].*) (\w+)[\[\d\]]*;/) {
  166.         my $jtype = $1;
  167.         my $name = $2;
  168.         $_ = <JP>;
  169.         s!^\s*/\*\s*!!;
  170.         s!\s*\*/\s*!!;
  171.         print "Field $jtype $name $_\n" if $DEBUG;
  172.         $fieldsig{$name} = $_;
  173.         $staticfield{$name} = $jtype =~ /\bstatic\b/;
  174.     }
  175.     while (m/L([^;]*);/g) {
  176.         my $pclass = j2p_class($1);
  177.         $classseen{$pclass}++;
  178.     }
  179.     }
  180.     close JP;
  181.  
  182.     open(HFILE, $hfile) or die "Couldn't open $hfile: $!\n";
  183.     undef $/;
  184.     $_ = <HFILE>;
  185.     close HFILE;
  186.  
  187.     die "panic: native method mismatch" if @protos != s/^JNIEXPORT/JNIEXPORT/gm;
  188.  
  189.     $PROTO = 0;
  190.     while (m{
  191.     \*\s*Class:\s*(\w+)\s*
  192.     \*\s*Method:\s*(\w+)\s*
  193.     \*\s*Signature:\s*(\S+)\s*\*/\s*
  194.     JNIEXPORT\s*(.*?)\s*JNICALL\s*(\w+)\s*\((.*?)\)
  195.     }gx) {
  196.     my $class = $1;
  197.     my $method = $2;
  198.     my $signature = $3;
  199.     my $rettype = $4;
  200.     my $cname = $5;
  201.     my $ctypes = $6;
  202.     $class =~ s/_0005f/_/g;
  203.     if ($method ne $protos[$PROTO][0]) {
  204.         die "Method name mismatch: $method vs $protos[$PROTO][0]\n";
  205.     }
  206.     print "$class.$method($protos[$PROTO][1]) =>
  207.     $signature
  208.     $rettype $cname($ctypes)\n" if $DEBUG;
  209.  
  210.     # Insert argument names into parameter list.
  211.  
  212.     my $env = "env";
  213.     my $obj = "obj";
  214.     my @jargs = split(/\s*,\s*/, $protos[$PROTO][1]);
  215.     foreach my $arg (@jargs) {
  216.         $arg =~ s/^.*\b(\w+).*$/${1}/;
  217.     }
  218.     my @tmpargs = @jargs;
  219.     unshift(@tmpargs, $env, $obj);
  220.     print "\t@tmpargs\n" if $DEBUG;
  221.     $ctypes .= ",";
  222.     $ctypes =~ s/,/' ' . shift(@tmpargs) . '_,'/eg;
  223.     $ctypes =~ s/,$//;
  224.     $ctypes =~ s/env_/env/;
  225.     $ctypes =~ s/obj_/obj/;
  226.     print "\t$ctypes\n" if $DEBUG;
  227.  
  228.     my $jlen = @jargs + 1;
  229.  
  230.     (my $mangclass = $class) =~ s/_/_1/g;
  231.     (my $mangmethod = $method) =~ s/_/_1/g;
  232.     my $plname = $cname;
  233.     $plname =~ s/^Java_${mangclass}_${mangmethod}/JPL::${class}::${method}/;
  234.     $plname =~ s/Ljava_lang_String_2/s/g;
  235.  
  236.     # Make glue code for each argument.
  237.  
  238.     (my $sig = $signature) =~ s/^\(//;
  239.  
  240.     my $decls = "";
  241.     my $glue = "";
  242.  
  243.     foreach my $jarg (@jargs) {
  244.         if ($sig =~ s/^[ZBCSI]//) {
  245.         $glue .= <<"";
  246. !    /* $jarg */
  247. !    PUSHs(sv_2mortal(newSViv(${jarg}_)));
  248. !
  249.  
  250.         }
  251.         elsif ($sig =~ s/^[JFD]//) {
  252.         $glue .= <<"";
  253. !    /* $jarg */
  254. !    PUSHs(sv_2mortal(newSVnv(${jarg}_)));
  255. !
  256.  
  257.         }
  258.         elsif ($sig =~ s#^Ljava/lang/String;##) {
  259.         $glue .= <<"";
  260. !    /* $jarg */
  261. !    tmpjb = (jbyte*)(*env)->GetStringUTFChars(env,${jarg}_,0);
  262. !    PUSHs(sv_2mortal(newSVpv((char*)tmpjb,0)));
  263. !    (*env)->ReleaseStringUTFChars(env,${jarg}_,tmpjb);
  264. !
  265.  
  266.         }
  267.         elsif ($sig =~ s/^L([^;]*);//) {
  268.         my $pclass = j2p_class($1);
  269.         $classseen{$pclass}++;
  270.         $glue .= <<"";
  271. !    /* $jarg */
  272. !    if (!${jarg}_stashhv_)
  273. !    ${jarg}_stashhv_ = gv_stashpv("$pclass", TRUE);
  274. !    PUSHs(sv_bless(
  275. !    sv_setref_iv(sv_newmortal(), Nullch, (IV)(void*)${jarg}_),
  276. !    ${jarg}_stashhv_));
  277. !    if (jpldebug)
  278. !    fprintf(stderr, "Done with $jarg\\n");
  279. !
  280.  
  281.         $decls .= <<"";
  282. !    static HV* ${jarg}_stashhv_ = 0;
  283.  
  284.  
  285.         }
  286.         elsif ($sig =~ s/^\[+([ZBCSIJFD]|L[^;]*;)//) {
  287.         my $pclass = "jarray";
  288.         $classseen{$pclass}++;
  289.         $glue .= <<"";
  290. !    /* $jarg */
  291. !    if (!${jarg}_stashhv_)
  292. !    ${jarg}_stashhv_ = gv_stashpv("$pclass", TRUE);
  293. !    PUSHs(sv_bless(
  294. !    sv_setref_iv(sv_newmortal(), Nullch, (IV)(void*)${jarg}_),
  295. !    ${jarg}_stashhv_));
  296. !    if (jpldebug)
  297. !    fprintf(stderr, "Done with $jarg\\n");
  298. !
  299.  
  300.         $decls .= <<"";
  301. !    static HV* ${jarg}_stashhv_ = 0;
  302.  
  303.         }
  304.         else {
  305.         die "Short signature: $signature\n" if $sig eq "";
  306.         die "Unrecognized letter '" . substr($sig, 0, 1) . "' in signature $signature\n";
  307.         }
  308.     }
  309.  
  310.     $sig =~ s/^\)// or die "Argument mismatch in signature: $method$signature\n";
  311.  
  312.     my $void = $signature =~ /\)V$/;
  313.  
  314.     $decls .= <<"" if $signature =~ m#java/lang/String#;
  315. !    jbyte* tmpjb;
  316.  
  317.     $decls .= <<"" unless $void;
  318. !    SV* retsv;
  319. !    $rettype retval;
  320. !
  321. !    if (jpldebug)
  322. !    fprintf(stderr, "Got to $cname\\n");
  323. !    ENTER;
  324. !    SAVETMPS;
  325.  
  326.     emit <<"";
  327. !JNIEXPORT $rettype JNICALL
  328. !$cname($ctypes)
  329. !{
  330. !    static SV* methodsv = 0;
  331. !    static HV* stashhv = 0;
  332. !    dSP;
  333. $decls
  334. !    PUSHMARK(sp);
  335. !    EXTEND(sp,$jlen);
  336. !
  337. !    sv_setiv(perl_get_sv("JPL::_env_", 1), (IV)(void*)env);
  338. !    jplcurenv = env;
  339. !
  340. !    if (jpldebug)
  341. !    fprintf(stderr, "env = %lx\\n", (long)$env);
  342. !
  343. !    if (!methodsv)
  344. !    methodsv = (SV*)perl_get_cv("$plname", TRUE);
  345. !    if (!stashhv)
  346. !    stashhv = gv_stashpv("JPL::$class", TRUE);
  347. !    if (jpldebug)
  348. !    fprintf(stderr, "blessing obj = %lx\\n", obj);
  349. !    PUSHs(sv_bless(
  350. !    sv_setref_iv(sv_newmortal(), Nullch, (IV)(void*)obj),
  351. !    stashhv));
  352. !
  353. $glue
  354.  
  355.     # Finally, call the subroutine.
  356.  
  357.     my $mod;
  358.     $mod = "|G_DISCARD" if $void;
  359.  
  360.     if ($void) {
  361.         emit <<"";
  362. !    PUTBACK;
  363. !    perl_call_sv(methodsv, G_EVAL|G_KEEPERR|G_DISCARD);
  364. !
  365.  
  366.     }
  367.     else {
  368.         emit <<"";
  369. !    PUTBACK;
  370. !    if (perl_call_sv(methodsv, G_EVAL|G_KEEPERR))
  371. !    retsv = *PL_stack_sp--;
  372. !    else
  373. !    retsv = &PL_sv_undef;
  374. !
  375.  
  376.     }
  377.  
  378.     emit <<"";
  379. !    if (SvTRUE(ERRSV)) {
  380. !    jthrowable newExcCls;
  381. !
  382. !    (*env)->ExceptionDescribe(env);
  383. !    (*env)->ExceptionClear(env);
  384. !
  385. !    newExcCls = (*env)->FindClass(env, "java/lang/RuntimeException");
  386. !    if (newExcCls)
  387. !        (*env)->ThrowNew(env, newExcCls, SvPV(ERRSV,PL_na));
  388. !    }
  389. !
  390.  
  391.     # Fix up the return value, if any.
  392.  
  393.     if ($sig =~ s/^V//) {
  394.         emit <<"";
  395. !    return;
  396.  
  397.     }
  398.     elsif ($sig =~ s/^[ZBCSI]//) {
  399.         emit <<"";
  400. !    retval = ($rettype)SvIV(retsv);
  401. !    FREETMPS;
  402. !    LEAVE;
  403. !    return retval;
  404.  
  405.     }
  406.     elsif ($sig =~ s/^[JFD]//) {
  407.         emit <<"";
  408. !    retval = ($rettype)SvNV(retsv);
  409. !    FREETMPS;
  410. !    LEAVE;
  411. !    return retval;
  412.  
  413.     }
  414.     elsif ($sig =~ s#^Ljava/lang/String;##) {
  415.         emit <<"";
  416. !    retval = (*env)->NewStringUTF(env, SvPV(retsv,PL_na));
  417. !    FREETMPS;
  418. !    LEAVE;
  419. !    return retval;
  420.  
  421.     }
  422.     elsif ($sig =~ s/^L[^;]*;//) {
  423.         emit <<"";
  424. !    if (SvROK(retsv)) {
  425. !    SV* rv = (SV*)SvRV(retsv);
  426. !    if (SvOBJECT(rv))
  427. !        retval = ($rettype)(void*)SvIV(rv);
  428. !    else
  429. !        retval = ($rettype)(void*)0;
  430. !    }
  431. !    else
  432. !    retval = ($rettype)(void*)0;
  433. !    FREETMPS;
  434. !    LEAVE;
  435. !    return retval;
  436.  
  437.     }
  438.     elsif ($sig =~ s/^\[([ZBCSIJFD])//) {
  439.         my $elemtype = $1;
  440.         my $ptype = "\u$ptype{$elemtype}";
  441.         my $ntype = "j$ptype{$elemtype}";
  442.         my $in = $elemtype =~ /^[JFD]/ ? "N" : "I";
  443.         emit <<"";
  444. !    if (SvROK(retsv)) {
  445. !    SV* rv = (SV*)SvRV(retsv);
  446. !    if (SvOBJECT(rv))
  447. !        retval = ($rettype)(void*)SvIV(rv);
  448. !    else if (SvTYPE(rv) == SVt_PVAV) {
  449. !        jsize len = av_len((AV*)rv) + 1;
  450. !        $ntype* buf = ($ntype*)malloc(len * sizeof($ntype));
  451. !        int i;
  452. !        SV** esv;
  453. !
  454. !        ${ntype}Array ja = (*env)->New${ptype}Array(env, len);
  455. !        for (esv = AvARRAY((AV*)rv), i = 0; i < len; esv++, i++)
  456. !        buf[i] = ($ntype)Sv${in}V(*esv);
  457. !        (*env)->Set${ptype}ArrayRegion(env, ja, 0, len, buf);
  458. !        free((void*)buf);
  459. !        retval = ($rettype)ja;
  460. !    }
  461. !    else
  462. !        retval = ($rettype)(void*)0;
  463. !    }
  464. !    else if (SvPOK(retsv)) {
  465. !    jsize len = sv_len(retsv) / sizeof($ntype);
  466. !
  467. !    ${ntype}Array ja = (*env)->New${ptype}Array(env, len);
  468. !    (*env)->Set${ptype}ArrayRegion(env, ja, 0, len, ($ntype*)SvPV(retsv,PL_na));
  469. !    retval = ($rettype)ja;
  470. !    }
  471. !    else
  472. !    retval = ($rettype)(void*)0;
  473. !    FREETMPS;
  474. !    LEAVE;
  475. !    return retval;
  476.  
  477.     }
  478.     elsif ($sig =~ s!^\[Ljava/lang/String;!!) {
  479.         emit <<"";
  480. !    if (SvROK(retsv)) {
  481. !    SV* rv = (SV*)SvRV(retsv);
  482. !    if (SvOBJECT(rv))
  483. !        retval = ($rettype)(void*)SvIV(rv);
  484. !    else if (SvTYPE(rv) == SVt_PVAV) {
  485. !        jsize len = av_len((AV*)rv) + 1;
  486. !        int i;
  487. !        SV** esv;
  488. !           static jclass jcl = 0;
  489. !        jarray ja;
  490. !
  491. !        if (!jcl)
  492. !        jcl = (*env)->FindClass(env, "java/lang/String");
  493. !        ja = (*env)->NewObjectArray(env, len, jcl, 0);
  494. !        for (esv = AvARRAY((AV*)rv), i = 0; i < len; esv++, i++) {
  495. !        jobject str = (jobject)(*env)->NewStringUTF(env, SvPV(*esv,PL_na));
  496. !        (*env)->SetObjectArrayElement(env, ja, i, str);
  497. !        }
  498. !        retval = ($rettype)ja;
  499. !    }
  500. !    else
  501. !        retval = ($rettype)(void*)0;
  502. !    }
  503. !    else
  504. !    retval = ($rettype)(void*)0;
  505. !    FREETMPS;
  506. !    LEAVE;
  507. !    return retval;
  508.  
  509.     }
  510.     elsif ($sig =~ s/^(\[+)([ZBCSIJFD]|L[^;]*;)//) {
  511.         my $arity = length $1;
  512.         my $elemtype = $2;
  513.         emit <<"";
  514. !    if (SvROK(retsv)) {
  515. !    SV* rv = (SV*)SvRV(retsv);
  516. !    if (SvOBJECT(rv))
  517. !        retval = ($rettype)(void*)SvIV(rv);
  518. !    else if (SvTYPE(rv) == SVt_PVAV) {
  519. !        jsize len = av_len((AV*)rv) + 1;
  520. !        int i;
  521. !        SV** esv;
  522. !           static jclass jcl = 0;
  523. !        jarray ja;
  524. !
  525. !        if (!jcl)
  526. !        jcl = (*env)->FindClass(env, "java/lang/Object");
  527. !        ja = (*env)->NewObjectArray(env, len, jcl, 0);
  528. !        for (esv = AvARRAY((AV*)rv), i = 0; i < len; esv++, i++) {
  529. !        if (SvROK(*esv) && (rv = SvRV(*esv)) && SvOBJECT(rv)) {
  530. !            (*env)->SetObjectArrayElement(env, ja, i,
  531. !            (jobject)(void*)SvIV(rv));
  532. !        }
  533. !        else {
  534. !            jobject str = (jobject)(*env)->NewStringUTF(env,
  535. !            SvPV(*esv,PL_na));
  536. !            (*env)->SetObjectArrayElement(env, ja, i, str);
  537. !        }
  538. !        }
  539. !        retval = ($rettype)ja;
  540. !    }
  541. !    else
  542. !        retval = ($rettype)(void*)0;
  543. !    }
  544. !    else
  545. !    retval = ($rettype)(void*)0;
  546. !    FREETMPS;
  547. !    LEAVE;
  548. !    return retval;
  549.  
  550.     }
  551.     else {
  552.         die "No return type: $signature\n" if $sig eq "";
  553.         die "Unrecognized return type '" . substr($sig, 0, 1) . "' in signature $signature\n";
  554.     }
  555.  
  556.     emit <<"";
  557. !}
  558. !
  559.  
  560.     my $perl = "";
  561.  
  562.     if ($class ne $LASTCLASS) {
  563.         $LASTCLASS = $class;
  564.         $perl .= <<"";
  565. package JPL::${class};
  566. use JNI;
  567. use JPL::AutoLoader;
  568. \@ISA = qw(jobject);
  569. \$clazz = JNI::FindClass("$file");\n
  570.  
  571.         foreach my $field (sort keys %fieldsig) {
  572.         my $sig = $fieldsig{$field};
  573.         my $ptype = $ptype{$sig};
  574.         if ($ptype) {
  575.             $ptype = "\u$ptype";
  576.             if ($staticfield{$field}) {
  577.             $perl .= <<"";
  578. \$${field}_FieldID = JNI::GetStaticFieldID(\$clazz, "$field", "$sig");
  579. sub $field (\$;\$) {
  580.     my \$self = shift;
  581.     if (\@_) {
  582.     JNI::SetStatic${ptype}Field(\$clazz, \$${field}_FieldID, \$_[0]);
  583.     }
  584.     else {
  585.     JNI::GetStatic${ptype}Field(\$clazz, \$${field}_FieldID);
  586.     }
  587. }\n
  588.  
  589.             }
  590.             else {
  591.             $perl .= <<"";
  592. \$${field}_FieldID = JNI::GetFieldID(\$clazz, "$field", "$sig");
  593. sub $field (\$;\$) {
  594.     my \$self = shift;
  595.     if (\@_) {
  596.     JNI::Set${ptype}Field(\$self, \$${field}_FieldID, \$_[0]);
  597.     }
  598.     else {
  599.     JNI::Get${ptype}Field(\$self, \$${field}_FieldID);
  600.     }
  601. }\n
  602.  
  603.             }
  604.         }
  605.         else {
  606.             my $pltype = $sig;
  607.             if ($pltype =~ s/^L(.*);/$1/) {
  608.             $pltype =~ s!/!::!g;
  609.             }
  610.             else {
  611.             $pltype = 'jarray';
  612.             }
  613.             if ($pltype eq "java::lang::String") {
  614.             if ($staticfield{$field}) {
  615.                 $perl .= <<"";
  616. \$${field}_FieldID = JNI::GetStaticFieldID(\$clazz, "$field", "$sig");
  617. sub $field (\$;\$) {
  618.     my \$self = shift;
  619.     if (\@_) {
  620.     JNI::SetStaticObjectField(\$clazz, \$${field}_FieldID,
  621.         ref \$_[0] ? \$_[0] : JNI::NewStringUTF(\$_[0]));
  622.     }
  623.     else {
  624.     JNI::GetStringUTFChars(JNI::GetStaticObjectField(\$clazz, \$${field}_FieldID));
  625.     }
  626. }\n
  627.  
  628.             }
  629.             else {
  630.                 $perl .= <<"";
  631. \$${field}_FieldID = JNI::GetFieldID(\$clazz, "$field", "$sig");
  632. sub $field (\$;\$) {
  633.     my \$self = shift;
  634.     if (\@_) {
  635.     JNI::SetObjectField(\$self, \$${field}_FieldID,
  636.         ref \$_[0] ? \$_[0] : JNI::NewStringUTF(\$_[0]));
  637.     }
  638.     else {
  639.     JNI::GetStringUTFChars(JNI::GetObjectField(\$self, \$${field}_FieldID));
  640.     }
  641. }\n
  642.  
  643.             }
  644.             }
  645.             else {
  646.             if ($staticfield{$field}) {
  647.                 $perl .= <<"";
  648. \$${field}_FieldID = JNI::GetStaticFieldID(\$clazz, "$field", "$sig");
  649. sub $field (\$;\$) {
  650.     my \$self = shift;
  651.     if (\@_) {
  652.     JNI::SetStaticObjectField(\$clazz, \$${field}_FieldID, \$_[0]);
  653.     }
  654.     else {
  655.     bless JNI::GetStaticObjectField(\$clazz, \$${field}_FieldID), "$pltype";
  656.     }
  657. }\n
  658.  
  659.             }
  660.             else {
  661.                 $perl .= <<"";
  662. \$${field}_FieldID = JNI::GetFieldID(\$clazz, "$field", "$sig");
  663. sub $field (\$;\$) {
  664.     my \$self = shift;
  665.     if (\@_) {
  666.     JNI::SetObjectField(\$self, \$${field}_FieldID, \$_[0]);
  667.     }
  668.     else {
  669.     bless JNI::GetObjectField(\$self, \$${field}_FieldID), "$pltype";
  670.     }
  671. }\n
  672.  
  673.             }
  674.             }
  675.         }
  676.         }
  677.     }
  678.  
  679.     $plname =~ s/^JPL::${class}:://;
  680.  
  681.     my $proto = '$' x (@jargs + 1);
  682.     $perl .= "sub $plname ($proto) {\n";
  683.     $perl .= '    my ($self, ';
  684.     foreach my $jarg (@jargs) {
  685.         $perl .= "\$$jarg, ";
  686.     }
  687.     $perl =~ s/, $/) = \@_;\n/;
  688.     $perl .= <<"END";
  689.     warn "JPL::${class}::$plname(\@_)\\n" if \$JPL::DEBUG;
  690. #line $protos[$PROTO][3] "$jpfile"
  691. $protos[$PROTO][2]}
  692.  
  693. END
  694.  
  695.     $PERLLINE += $perl =~ tr/\n/\n/ + 2;
  696.     $perl .= <<"END";
  697. #line $PERLLINE ""
  698. END
  699.     $PERLLINE--;
  700.  
  701.     $PERL .= $perl;
  702.     }
  703.     continue {
  704.     $PROTO++;
  705.     print "\n" if $DEBUG;
  706.     }
  707.  
  708.     emit_c_footer();
  709.  
  710.     rename $cfile, "$cfile.old";
  711.     rename "$cfile.new", $cfile;
  712.  
  713.     open(PLFILE, ">$plfile") or die "Can't create $plfile: $!\n";
  714.     print PLFILE "BEGIN { \$JPL::_env_ ||= 1; }    # suppress bogus embedding\n\n";
  715.     if (%classseen) {
  716.     my @classes = sort keys %classseen;
  717.     print PLFILE "use JPL::Class qw(@classes);\n\n";
  718.     }
  719.     print PLFILE $PERL;
  720.     print PLFILE "1;\n";
  721.     close PLFILE;
  722.  
  723.     print "perl -c $plfile\n";
  724.     system "perl -c $plfile" and die "jpl stopped\n";
  725. }
  726.  
  727. sub emit_c_header {
  728.     open(CFILE, ">$cfile.new") or die "Can't create $cfile.new: $!\n";
  729.     emit <<"";
  730. !/* This file is automatically generated.  Do not modify! */
  731. !
  732. !#include "$hfile"
  733. !#include "EXTERN.h"
  734. !#include "perl.h"
  735. !#ifndef EXTERN_C
  736. !#  ifdef __cplusplus
  737. !#    define EXTERN_C extern "C"
  738. !#  else
  739. !#    define EXTERN_C extern
  740. !#  endif
  741. !#endif
  742. !
  743. !extern int jpldebug;
  744. !extern JNIEnv* jplcurenv;
  745. !
  746.  
  747. }
  748.  
  749.  
  750. sub emit_c_footer {
  751.     close CFILE;
  752. }
  753.  
  754. sub emit {
  755.     my $string = shift;
  756.     $string =~ s/^!//mg;
  757.     print CFILE $string;
  758. }
  759.  
  760. sub j2p_class {
  761.     my $jclass = shift;
  762.     $jclass =~ s#/#::#g;
  763.     $jclass;
  764. }
  765.