C-DynaLib
view release on metacpan or search on metacpan
lib/C/DynaLib.pm view on Meta::CPAN
# We eval $obj->isa and $obj->can for 5.003 compatibility.
local ($@);
my $self = shift;
# Calling as a method is equivalent to supplying the "libref" named arg.
my $is_method;
$is_method = ref($self) && eval { $self->isa("C::DynaLib") };
$@ and $is_method = (ref($self) eq 'C::DynaLib');
my $first = ($is_method ? shift : $self);
my ($libref, $name, $ptr, @arg_type);
my ($convention, $ret_type) = ($is_method ? $self->LibDecl : $DefConv, '');
if (ref($first) eq 'HASH') {
# Using named parameters.
! @_ && (($ptr = $first->{'ptr'}) || defined ($name = $first->{'name'}))
or croak 'Usage: $lib->DeclareSub('.
'{ "name" => $func_name [, "return" => $ret_type] [,'.
' "args" => \@arg_types] [, "decl" => $decl] })';
$libref = $first->{'libref'};
$convention = $first->{'decl'} || $convention;
$ret_type = $first->{'return'} || $ret_type;
@arg_type = @{ $first->{'args'} || [] };
} else {
# Using positional parameters.
($is_method ? $name : $ptr) = $first
or croak 'Usage: $lib->DeclareSub( $func_name [, $return_type [, \@arg_types]] )';
$ret_type = shift || $ret_type;
@arg_type = @_;
}
unless ($ptr) {
# No pointer, so we're looking up the function in a library...
$libref ||= $is_method && $self->LibRef()
or croak 'C::DynaLib::DeclareSub: non-method form requires a "ptr" or "libref"';
$ptr = eval { DynaLoader::dl_find_symbol($libref, $name) };
if ($@ || ! $ptr) {
return undef;
}
}
$ret_type =~ /^$GoodRet$/o
or croak "Invalid return type: '$ret_type'";
my $glue_sub_name = $convention . '_call_packed';
my $glue_sub = ($is_method && eval { $self->can($glue_sub_name) })
|| (defined(&{"$glue_sub_name"}) && \&{"$glue_sub_name"});
if (! $glue_sub) {
carp "Unsupported calling convention: decl => '$convention'"
if $^W;
return undef;
}
my @pre_args = ($ptr, $ret_type, $libref);
my $pkg = caller();
# This 'inner' closure must be an eval-string in order to compile the
# function call in our caller's package.
my $proc = eval q/ sub {
package /.$pkg.q/;
&$glue_sub(@pre_args, map { pack($_, shift) } @arg_type);
}/;
return sub {
if ($^W) {
if ($#_ < $#arg_type) {
carp 'Missing arguments supplied as undef';
} elsif ($#_ > $#arg_type) {
carp 'Extra arguments ignored';
}
}
local $SIG{'__WARN__'} = \&my_carp;
local $SIG{'__DIE__'} = \&my_croak;
&$proc;
};
}
sub Parse {
my $self = shift;
my $is_method = ref($self) && eval { $self->isa("C::DynaLib") };
$@ and $is_method = (ref($self) eq 'C::DynaLib');
my $first = ($is_method ? shift : $self);
my ($code,$cc,$inc,$filter);
if (ref($first) eq 'HASH') {
$code = $first->{code} or die "code missing\n";
$cc = $first->{cc} || "gcc";
$inc = $first->{inc};
$filter = $first->{filter};
$cc = "$cc -I$inc" if $inc;
} else {
$code = $first;
$cc = shift;
$filter = shift;
}
require C::DynaLib::Parse;
C::DynaLib::Parse->import (qw(declare_func declare_struct
pack_types process_struct process_func));
my $node = C::DynaLib::Parse::GCC_prepare($code, $cc);
while ($node) {
if ($node->isa('GCC::Node::function_decl')
and ($filter ? $node->name->identifier =~ /$filter/
: $node->name->identifier !~ /^_/))
{
declare_func process_func($node);
}
if ($node->isa('GCC::Node::record_type')
and ($filter ? $node->name->identifier =~ /$filter/
: $node->name->identifier !~ /^_/))
{
declare_struct process_struct($node);
}
} continue {
$node = $node->chain;
}
POST:
( run in 1.443 second using v1.01-cache-2.11-cpan-99c4e6809bf )