This patch implements prototypes for Inline::C.  It starts by intuiting
prototypes from argument types (AV*, HV*, CV* and GV*), as originally
proposed by Brian:

    http:[EMAIL PROTECTED]/msg00546.html

This idea is expanded to pseudo-types SCALAR, LIST and PAIRS which are
typedefs of SV*, AV* and HV* with $, @ and % prototypes.

To handle optional prototypes, I implemented C++ style default parameters.
And since I was mucking around Inline::C::grammar, I added support for
functions with zero or more arguments as well.

BTW, I don't like the patch to Inline::C::grammar.  It was the result of
blind trial and error.  Someone with more knowledge of Parse::RecDescent
should apply some logic to it before applying the patch.


--- Inline-0.43/C/C.pod.orig    Fri Jul 20 03:28:43 2001
+++ Inline-0.43/C/C.pod Thu Mar 28 16:31:24 2002
@@ -22,19 +22,22 @@

 The Inline grammar for C recognizes certain function definitions (or signatures) in 
your C code. If a signature is recognized by Inline, then it will be available in 
Perl-space. That is, Inline will generate the "glue" necessary to call that function 
as if it were a Perl subroutine. If the signature is not recognized, Inline will 
simply ignore it, with no complaints. It will not be available from Perl-space, 
although it I<will> be available from C-space.

-Inline looks for ANSI/prototype style function definitions. They must be of the form:
+Inline looks for ANSI/prototype style function definitions. C++ style default 
+parameters may also be used, and an explicit Perl L<prototype|/Perl Prototypes> may 
+follow the argument list. Function definitions must be of the form:

     return-type function-name ( type-name-pairs ) { ... }
+    return-type function-name ( type-name-pairs ) ( prototype ) { ... }

-The most common types are: C<int>, C<long>, C<double>, C<char*>, and C<SV*>. But you 
can use any type for which Inline can find a typemap. Inline uses the C<typemap> file 
distributed with Perl as the default. You can specify more typemaps with the TYPEMAPS 
configuration option.
+The most common types are: C<int>, C<long>, C<double>, C<char*>, and C<SV*>. But you 
+can use any type for which Inline can find a typemap. Inline uses the C<typemap> file 
+distributed with Perl and one of its own as the defaults. You can specify more 
+typemaps with the TYPEMAPS configuration option.

 A return type of C<void> may also be used. The following are examples of valid 
function definitions.

     int Foo(double num, char* str) {
     void Foo(double num, char* str) {
     SV* Foo() {
+    void Foo(...) {
     void Foo(SV*, ...) {
-    long Foo(int i, int j, ...) {
+    long Foo(int i = 1, int j = 2, ...) {
+    int Foo(AV* aref, int i) ($$) {

 The following definitions would not be recognized:

@@ -149,6 +152,8 @@

 Inline uses the default Perl typemap file for its default types. This file is called 
C</usr/local/lib/perl5/5.6.1/ExtUtils/typemap>, or something similar, depending on 
your Perl installation. It has definitions for over 40 types, which are automatically 
used by Inline. (You should probably browse this file at least once, just to get an 
idea of the possibilities.)

+In addition to the Perl typemap file, Inline also uses its own typemap file 
+C<$lib/Inline/C/typemap> to better handle implicit L<prototypes|/Perl Prototypes>.  
+It redefines mappings for the C<AV*>, C<HV*>, C<CV*>, and C<GV*> types and defines 
+new mappings for C<SCALAR>, C<LIST>, and C<PAIRS> pseudo-types.
+
 Inline parses your code for these types and generates the XS code to map them. The 
most commonly used types are:

  - int
@@ -162,9 +167,72 @@

 A return type of C<void> has a special meaning to Inline. It means that you plan to 
push the values back onto the B<Stack> yourself. This is what you need to do to return 
a list of values. If you really don't want to return anything (the traditional meaning 
of C<void>) then simply don't push anything back.

-If ellipsis or C<...> is used at the end of an argument list, it means that any 
number of C<SV*>s may follow. Again you will need to pop the values off of the 
C<Stack> yourself.
+If ellipsis or C<...> is used at the end of an argument list, it means that any 
+number of C<SV*>s may follow. If C<...> is used as the only thing in an argument 
+list, it means that there are any number of C<SV*>s in the list. Again you will need 
+to pop the values off of the C<Stack> yourself.

 See L<"Examples"> below.
+
+=head1 Perl Prototypes
+
+Inline can "glue" a C function to a L<prototyped|perlsub/Prototypes> Perl subroutine. 
+ Prototypes are implicitly generated if a C function argument list includes one of 
+the following types:
+
+    C Type    Perl Prototype
+    --------  --------------
+    AV*       \@
+    HV*       \%
+    CV*        &
+    GV*        *
+    SCALAR     $
+    LIST       @
+    PAIRS      %
+
+All other types are mapped to C<$>.  If the argument list ends with C<...>, then an 
+C<@> is appended to the prototype.  For example:
+
+    C Function                            Perl Subroutine
+    ------------------------------------  --------------------
+    int  mypush (AV* array, ...)          sub mypush (\@@)
+    void mykeys (HV* hash)                sub mykeys (\%)
+    void mygrep (CV* code, ...)           sub mygrep (&@)
+    bool mypipe (GV* read, GV* write)     sub mypipe (**)
+    void mylock (SCALAR thing)            sub mylock ($)
+    void mykill (LIST list)               sub mykill (@)
+    int  mynew  (PAIRS named_params)      sub mynew  (%)
+
+Inline I<typedefs> the C<SCALAR>, C<LIST>, and C<PAIRS> types to C<SV*>, C<AV*>, and 
+C<HV*>, respectively. A C<SCALAR> type argument forces scalar context. A C<LIST> type 
+argument forces list context and slurps up all remaining arguments from the B<Stack>. 
+And a C<PAIRS> type argument slurps up all remaining arguments as key-value pairs (an 
+odd number of remaining arguments is fatal).
+
+For optional prototypes, use C++ style default parameters:
+
+    C Function                                       Perl Subroutine
+    -----------------------------------------------  ------------------
+    double myrand  (double num = 1.0)                sub myrand  (;$)
+    int    myint   (double num = SvNV(DEFSV))        sub myint   (;$)
+    bool   mymkdir (char* dir, int mask = 0777)      sub mymkdir ($;$)
+    bool   myopen  (GV* io, char* file = "")         sub myopen  (*;$)
+
+Functions that take no arguments get an empty prototype, and functions that take a 
+variable number of arguments get an C<@> prototype:
+
+    C Function               Perl Subroutine
+    -----------------------  --------------------
+    int mytime  ()           sub mytime  ()
+    int myutime (...)        sub myutime (@)
+
+You may also explicitly set a prototype.
+
+    int myadd (int i, int j) ($$) {...}    # No implicit prototype
+    SV* mypop (AV* array) (@) {...}        # Override implicit \@
+
+Note that prototyped Perl subroutines must be visible at compile time, but the 
+C<DATA> filehandle can't be read until runtime. This means that when using 
+prototypes, do B<not> put your C code after the C<__END__> or C<__DATA__> tokens of 
+your program. Instead, use either the C<FILE> keyword:
+
+    use Inline::Files;
+    use Inline C => 'FILE';
+
+    __C__
+    /* Put your C code here */
+
+Or place your code in a string:
+
+    use Inline C => <<'CODE';
+    /* Put your C code here */
+    CODE

 =head1 The Inline Stack Macros


--- Inline-0.43/C/C.pm.orig     Sun Jul 22 08:09:35 2001
+++ Inline-0.43/C/C.pm  Thu Mar 28 16:31:37 2002
@@ -7,6 +7,7 @@
 use Data::Dumper;
 use Carp;
 use Cwd qw(cwd abs_path);
+use File::Spec;

 $Inline::C::VERSION = '0.43';
 @Inline::C::ISA = qw(Inline);
@@ -277,8 +278,10 @@
     my $parser = $o->{ILSM}{parser} = $o->get_parser;

     Inline::Struct::parse($o) if $o->{STRUCT}{'.any'};
-    $parser->code($o->{ILSM}{code})
+
+    my $code = $parser->code($o->{ILSM}{code})
       or croak "Bad $o->{API}{language} code passed to Inline at @{[caller(2)]}\n";
+    $o->{ILSM}{code} = $code unless $code eq '1';
 }

 # Create and initialize a parser
@@ -300,6 +303,11 @@
 sub get_maps {
     my $o = shift;

+    my ($vol, $dir, $file) = File::Spec->splitpath($INC{'Inline/C/grammar.pm'});
+    my $path = File::Spec->rel2abs(File::Spec->catpath($vol, $dir, 'typemap'));
+    ($path) = $path =~ /(.*)/ if $o->UNTAINT;
+    unshift(@{$o->{ILSM}{MAKEFILE}{TYPEMAPS}}, $path) if -f $path;
+
     my $typemap = '';
     $typemap = "$Config::Config{installprivlib}/ExtUtils/typemap"
       if -f "$Config::Config{installprivlib}/ExtUtils/typemap";
@@ -515,18 +523,69 @@
         "Check your C function definition(s) for Inline compatibility\n\n")
       if ((not defined$data->{functions}) and ($^W));

+    my %type2proto = (
+       'AV *'   => '\@',
+       'HV *'   => '\%',
+       'CV *'   => '&',
+       'GV *'   => '*',
+       'SCALAR' => '$',
+       'LIST'   => '@',
+       'PAIRS'  => '%',
+       '...'    => '@',
+    );
+
+    my %type2default = (
+       'LIST'   => 'newAV()',
+       'PAIRS'  => 'newHV()',
+    );
+
     for my $function (@{$data->{functions}}) {
-       my $return_type = $data->{function}->{$function}->{return_type};
-       my @arg_names = @{$data->{function}->{$function}->{arg_names}};
-       my @arg_types = @{$data->{function}->{$function}->{arg_types}};
-
-       $XS .= join '', ("\n$return_type\n$function (",
-                 join(', ', @arg_names), ")\n");
-
-       for my $arg_name (@arg_names) {
-           my $arg_type = shift @arg_types;
-           last if $arg_type eq '...';
-           $XS .= "\t$arg_type\t$arg_name\n";
+       my $return_type  = $data->{function}->{$function}->{return_type};
+       my $prototype    = $data->{function}->{$function}->{prototype};
+       my @arg_names    = @{$data->{function}->{$function}->{arg_names}};
+       my @arg_types    = @{$data->{function}->{$function}->{arg_types}};
+       my @arg_defaults = @{$data->{function}->{$function}->{arg_defaults}}
+           if ref $data->{function}->{$function}->{arg_defaults};
+
+       my $proto = join '', map $type2proto{$_} || '-', @arg_types;
+
+       if (@arg_types and $type2default{$arg_types[-1]}) {
+           push @arg_types, '...';
+           push @arg_names, '...';
+       }
+
+       my $semicolon;
+
+       my $arg_names = join ', ', map {
+           if (defined $arg_defaults[$_]) {
+               $semicolon = $_ unless defined $semicolon;
+               "$arg_names[$_] = $arg_defaults[$_]";
+           } else {
+               $arg_names[$_];
+           }
+       } 0..$#arg_names;
+
+       substr $arg_names, -5, 0, "=$type2default{$arg_types[-2]}"
+           if @arg_types > 1
+           && $arg_types[-1] eq '...'
+           && $type2default{$arg_types[-2]};
+
+       $XS .= "\n$return_type\n$function ($arg_names)\n";
+
+       for (0..$#arg_names) {
+           last if $arg_types[$_] eq '...';
+           $XS .= "\t$arg_types[$_]\t$arg_names[$_]\n";
+       }
+
+       if ($prototype) {
+           $XS .= "\tPROTOTYPE: $prototype\n";
+       } elsif (defined $semicolon) {
+           substr $proto, $semicolon, 0, ';';
+           $proto =~ tr/-/$/;
+           $XS .= "\tPROTOTYPE: $proto\n";
+       } elsif ($proto !~ /^-+\@?$/) {
+           $proto =~ tr/-/$/;
+           $XS .= "\tPROTOTYPE: $proto\n";
        }

        my $listargs = '';
@@ -603,6 +662,10 @@
 #define inline_stack_done      Inline_Stack_Done
 #define inline_stack_return(x) Inline_Stack_Return(x)
 #define inline_stack_void      Inline_Stack_Void
+
+typedef SV* SCALAR;
+typedef AV* LIST;
+typedef HV* PAIRS;
 END

     close HEADER;


--- Inline-0.43/C/grammar/grammar.pm.orig       Fri Jul 20 18:03:10 2001
+++ Inline-0.43/C/grammar/grammar.pm    Thu Mar 28 16:32:31 2002
@@ -7,13 +7,17 @@
 sub grammar {
     <<'END';

-code:  part(s) {1}
+code:  part(s) { join "\n", @{$item[1]} }

 part:    comment
        | function_definition
        {
         my $function = $item[1][0];
-         $return = 1, last if $thisparser->{data}{done}{$function}++;
+        $return = "$item[1][1] $function(" . join(
+            ', ' => map {ref $_ ? "$_->[0] $_->[1]" : '...'} @{$item[1][2]}
+        ) . ") {";
+        $return =~ s/\Q(...) {\E$/(   ) {/;
+         last if $thisparser->{data}{done}{$function}++;
         push @{$thisparser->{data}{functions}}, $function;
         $thisparser->{data}{function}{$function}{return_type} =
              $item[1][1];
@@ -21,12 +25,21 @@
              [map {ref $_ ? $_->[0] : '...'} @{$item[1][2]}];
         $thisparser->{data}{function}{$function}{arg_names} =
              [map {ref $_ ? $_->[1] : '...'} @{$item[1][2]}];
+        $thisparser->{data}{function}{$function}{arg_defaults} =
+             [map {ref $_ ? $_->[2] : undef} @{$item[1][2]}];
+        $thisparser->{data}{function}{$function}{prototype} =
+             $item[1][3];
+        1;
        }
        | function_declaration
        {
-         $return = 1, last unless $thisparser->{data}{AUTOWRAP};
+        $return = "$item[1][1] $item[1][0](" . join(
+            ', ' => map {ref $_ ? "$_->[0] $_->[1]" : '...'} @{$item[1][2]}
+        ) . ");";
+        $return =~ s/\Q(...);\E$/(   );/;
+         last unless $thisparser->{data}{AUTOWRAP};
         my $function = $item[1][0];
-         $return = 1, last if $thisparser->{data}{done}{$function}++;
+         last if $thisparser->{data}{done}{$function}++;
          my $dummy = 'arg1';
         push @{$thisparser->{data}{functions}}, $function;
         $thisparser->{data}{function}{$function}{return_type} =
@@ -35,19 +48,25 @@
              [map {ref $_ ? $_->[0] : '...'} @{$item[1][2]}];
         $thisparser->{data}{function}{$function}{arg_names} =
              [map {ref $_ ? ($_->[1] || $dummy++) : '...'} @{$item[1][2]}];
+        $thisparser->{data}{function}{$function}{arg_defaults} =
+             [map {ref $_ ? $_->[2] : undef} @{$item[1][2]}];
+        $thisparser->{data}{function}{$function}{prototype} =
+             $item[1][3];
+        1;
        }
-       | anything_else
+       | anything_else {$item[1]}

 comment:  m{\s* // [^\n]* \n }x
        | m{\s* /\* (?:[^*]+|\*(?!/))* \*/  ([ \t]*)? }x

 function_definition:
-       rtype IDENTIFIER '(' <leftop: arg ',' arg>(s?) ')' '{'
-       {[@item[2,1], $item[4]]}
+       rtype IDENTIFIER '(' <leftop: arg ',' arg>(s?) ')' prototype(?) '{'
+       {[@item[2,1], $item[4], $item[6][0]]}

 function_declaration:
-       rtype IDENTIFIER '(' <leftop: arg_decl ',' arg_decl>(s?) ')' ';'
-       {[@item[2,1], $item[4]]}
+       rtype IDENTIFIER '(' <leftop: arg_decl ',' arg_decl>(s?) ')' prototype(?) ';'
+       {[@item[2,1], $item[4], $item[6][0]]}
+#      {[@item[2,1,4,6]]}

 rtype:  TYPE star(s?)
         {
@@ -64,11 +83,34 @@
          return undef unless (defined 
$thisparser->{data}{typeconv}{valid_rtypes}{$return});
        }

-arg:     type IDENTIFIER {[@item[1,2]]}
+arg:     type IDENTIFIER default(?) {[@item[1,2], $item[3][0]]}
        | '...'

-arg_decl: type IDENTIFIER(s?) {[$item[1], $item[2][0] || '']}
+arg_decl: type IDENTIFIER(s?) default(?)
+          {[ $item[1], $item[2][0] || '', $item[3][0] ]}
        | '...'
+
+default: '=' expression
+
+expression: outer_chunk(s) { join '', @{$item[1]} }
+
+outer_chunk: string | character | parenthesis | outer_continuation
+
+inner_chunk: string | character | parenthesis | inner_continuation
+
+parenthesis: '(' inner_chunk(s?) ')' { join '', '(', @{$item[2]} , ')' }
+
+string: /"(?:[^"\\]+|\\.)*"/
+
+character: /'\\?.'/
+
+outer_continuation: /[^'"(),]+/
+
+inner_continuation: /[^'"()]+/
+
+prototype: '(' proto ')' {$item[2]}
+
+proto: /[\$\@%&*\\;]+/

 type:   TYPE star(s?)
         {

--- /dev/null   Wed Dec 31 16:00:00 1969
+++ Inline-0.43/C/typemap       Thu Mar 28 16:32:05 2002
@@ -0,0 +1,81 @@
+TYPEMAP
+
+AV *   IC_ARRAY
+HV *   IC_HASH
+CV *   IC_CODE
+GV *   IC_GLOB
+SCALAR IC_SCALAR
+LIST   IC_LIST
+PAIRS  IC_PAIRS
+
+INPUT
+
+IC_ARRAY
+    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV)
+        $var = (AV*) SvRV($arg);
+    else
+        croak(\"$var is not an ARRAY reference\")
+IC_HASH
+    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV)
+        $var = (HV*) SvRV($arg);
+    else
+        croak(\"$var is not a HASH reference\")
+IC_CODE
+    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVCV)
+        $var = (CV*) SvRV($arg);
+    else
+        croak(\"$var is not a CODE reference\")
+IC_GLOB
+    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVGV)
+        $var = (GV*) SvRV($arg);
+    else
+        $var = (GV*) SvRV(eval_pv(SvPV_nolen(newSVpvf(
+            \"use Symbol; qualify_to_ref('%s', caller)\",
+            SvPV_nolen($arg)
+        )), TRUE));
+IC_SCALAR
+    $var = $arg
+IC_LIST
+    {
+        int i;
+        $var = newAV();
+        for (i = $argoff; i < items; i++)
+            av_push($var, ST(i));
+    }
+IC_PAIRS
+    {
+        SV** store;
+        int i;
+        char* key;
+        STRLEN len;
+        $var = newHV();
+        if ((items - $argoff) % 2)
+            croak(\"Odd number of elements in hash prototype\");
+        for (i = $argoff + 1; i < items; i += 2) {
+            key = SvPV(ST(i - 1), len);
+            store = hv_store($var, key, len, ST(i), 0);
+        }
+    }
+
+OUTPUT
+
+IC_ARRAY
+    $arg = newRV((SV*) $var);
+IC_HASH
+    $arg = newRV((SV*) $var);
+IC_CODE
+    $arg = newRV((SV*) $var);
+IC_GLOB
+    $arg = newRV((SV*) $var);
+IC_LIST
+    {
+        int i;
+        int len = av_len($var) + 1;
+        XSprePUSH;
+        for (i = 0; i < len; i++)
+            PUSHs(sv_mortalcopy(av_shift($var)));
+        XSRETURN(len);
+    }
+
+
+

--- /dev/null   Wed Dec 31 16:00:00 1969
+++ Inline-0.43/C/t/06grammar.t Thu Mar 28 16:34:48 2002
@@ -0,0 +1,65 @@
+use lib qw(../blib/lib ./blib/lib);
+use strict;
+use Test;
+use diagnostics;
+use Inline Config => DIRECTORY => './_Inline_test';
+
+BEGIN {
+    plan(tests => 11,
+        todo => [],
+        onfail => sub {},
+       );
+}
+
+use Inline C => <<'END_OF_C_CODE';
+
+int integer(double num) {
+    return (int) num;
+}
+
+int power(int x, int y = 2) {
+    return pow(x, y);
+}
+
+int negate(int i = SvIV(DEFSV)) {
+    return -i;
+}
+
+int count(int i) ($) {
+    return i;
+}
+
+int sum(...) {
+    INLINE_STACK_VARS;
+    int tot = 0;
+    int i;
+    for (i = 0; i < INLINE_STACK_ITEMS; i++)
+        tot += SvIV(INLINE_STACK_ITEM(i));
+    return tot;
+}
+
+END_OF_C_CODE
+
+# test 1 - Check ANSI/prototypes still work
+my $i = integer(21.2);
+ok($i == 21);
+
+# test 2..5 - Check C++ style default parameters
+ok(power(2, 3) == 2**3);
+ok(power(2) == 2**2);
+ok(negate(10) == -10);
+$_ = 8;
+ok(negate == -8);
+
+# test 6..7 - Check explicit prototype
+ok(count(5) == 5);
+my @a = 'a'..'z';
+ok(count(@a) == @a);
+
+# test 8..11 - Check variable argument list
+ok(sum == 0);
+ok(sum(100) == 100);
+ok(sum(100, 10) == 110);
+ok(sum(100, 10, 1) == 111);
+
+__END__


--- /dev/null   Wed Dec 31 16:00:00 1969
+++ Inline-0.43/C/t/07prototypes.t      Thu Mar 28 16:35:07 2002
@@ -0,0 +1,145 @@
+use lib qw(../blib/lib ./blib/lib);
+use strict;
+use Test;
+use diagnostics;
+use Inline Config => DIRECTORY => './_Inline_test';
+
+BEGIN {
+    plan(tests => 24,
+        todo => [],
+        onfail => sub {},
+       );
+}
+
+use Inline C => <<'END_OF_C_CODE';
+
+int array_length(AV* av) {
+    return av_len(av) + 1;
+}
+
+int hash_keys(HV* hv) {
+    return HvKEYS(hv);
+}
+
+void code_repeat(CV* cv, int iter) {
+    int i;
+    dSP;
+    PUSHMARK(SP);
+    for (i = 0; i < iter; i++)
+        call_sv((SV*) cv, G_DISCARD|G_NOARGS);
+}
+
+char* glob_string(GV* gv) {
+    return SvPV_nolen(GvSV(gv));
+}
+
+SV* scalar_value(SCALAR sv) {
+    return newSVsv(sv);
+}
+
+int list_sum(LIST av) {
+    int tot = 0;
+    SV* sv;
+    while ((sv = av_pop(av)) != &PL_sv_undef)
+        tot += SvNV(sv);
+    return tot;
+}
+
+int pairs_area(PAIRS hv) {
+    SV** fetch;
+    int width, height;
+    fetch = hv_fetch(hv, "width", 5, FALSE);
+    width = fetch == NULL ? 0 : SvIV(*fetch);
+    fetch = hv_fetch(hv, "height", 6, FALSE);
+    height = fetch == NULL ? 0 : SvIV(*fetch);
+    return width * height;
+}
+
+char opt_letter(char* str, int index = 0) {
+    return str[index];
+}
+
+void empty() {
+    return;
+}
+
+void variable(...) {
+    return;
+}
+
+void explicit(AV* av) ($) {
+    return;
+}
+
+END_OF_C_CODE
+
+# test 1..11 - Check prototypes
+ok(prototype \&array_length eq '\@');
+ok(prototype \&hash_keys    eq '\%');
+ok(prototype \&code_repeat  eq '&$');
+ok(prototype \&glob_string  eq '*');
+ok(prototype \&scalar_value eq '$');
+ok(prototype \&list_sum     eq '@');
+ok(prototype \&pairs_area   eq '%');
+ok(prototype \&opt_letter   eq '$;$');
+ok(prototype \&variable     eq '@');
+ok(prototype \&explicit     eq '$');
+my $empty = prototype \&empty;
+ok(defined $empty and $empty eq "");
+
+# test 12 - Check AV* binding
+my @a = 'a'..'z';
+my $len = eval 'array_length @a';
+ok(!$@ and $len == @a);
+
+# test 13 - Check HV* binding
+my %h;
+@h{@a} = ();
+$len = eval 'hash_keys %h';
+ok(!$@ and $len == keys %h);
+
+# test 14 - Check CV* binding
+my $x = 10;
+eval 'code_repeat { $x++ } 4';
+ok(!$@ and $x == 14);
+
+# test 15..16 - Check GV* binding
+our $str = 'Just another Inline hacker';
+my $ret = eval 'glob_string *str';
+ok(!$@ and $ret eq $str);
+$str = uc $str;
+$ret = eval 'glob_string str';
+ok(!$@ and $ret eq $str);
+
+# test 17 - Check SCALAR binding
+$len = eval 'scalar_value @a';
+ok(!$@ and $len == @a);
+
+# test 18..20 - Check LIST binding
+my $sum = eval 'list_sum 1..4';
+ok(!$@ and $sum == 1 + 2 + 3 + 4);
+$sum = eval 'list_sum 8';
+ok(!$@ and $sum == 8);
+$sum = eval 'list_sum';
+ok(!$@ and $sum == 0);
+
+# test 21..22 - Check PAIRS binding.
+my $area = eval 'pairs_area width => 10, height => 20';
+ok(!$@ and $area == 10 * 20);
+my $warn;
+$area = eval q{
+    local $SIG{__WARN__} = sub {
+        $warn++ if $_[0] =~ /^Odd number of elements in hash prototype/;
+    };
+    pairs_area width => 4, height => 8, 1;
+};
+ok(!$@ and $warn and $area == 4 * 8);
+
+# test 23..24 - Check optional prototypes
+my $letter = eval 'opt_letter "perl", 2';
+ok(!$@ and $letter eq 'r');
+$letter = eval 'opt_letter "perl"';
+ok(!$@ and $letter eq 'p');
+
+__END__
+



-- 
Tim Gim Yee
[EMAIL PROTECTED]



Reply via email to