Initial Commit
This commit is contained in:
283
database/perl/vendor/lib/FFI/Platypus/API.pm
vendored
Normal file
283
database/perl/vendor/lib/FFI/Platypus/API.pm
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
package FFI::Platypus::API;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
|
||||
our @EXPORT = grep /^arguments_/, keys %FFI::Platypus::API::;
|
||||
|
||||
# ABSTRACT: Platypus arguments and return value API for custom types
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::API - Platypus arguments and return value API for custom types
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package FFI::Platypus::Type::MyCustomType;
|
||||
|
||||
use FFI::Platypus::API;
|
||||
|
||||
sub ffi_custom_type_api_1
|
||||
{
|
||||
{
|
||||
native_type => 'uint32',
|
||||
perl_to_native => sub {
|
||||
my($value, $i) = @_;
|
||||
# Translates ($value) passed in from Perl
|
||||
# into ($value+1, $value+2)
|
||||
arguments_set_uint32($i, $value+1);
|
||||
arguments_set_uint32($i+1, $value+2);
|
||||
},
|
||||
argument_count => 2,
|
||||
}
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<NOTE>: I added this interface early on to L<FFI::Platypus>, but haven't
|
||||
used it much, generally finding function wrappers to be a more powerful
|
||||
(although possibly not as fast) interface. It has thus not been
|
||||
tested as much as the rest of Platypus. If you feel the need to use
|
||||
this interface please coordinate with the Platypus developers.
|
||||
|
||||
The custom types API for L<FFI::Platypus> allows you to set multiple C
|
||||
arguments from a single Perl argument as a common type. This is
|
||||
sometimes useful for pointer / size pairs which are a common pattern in
|
||||
C, but are usually represented by a single value (a string scalar) in
|
||||
Perl.
|
||||
|
||||
The custom type API is somewhat experimental, and you should expect some
|
||||
changes as needs arise (I won't break compatibility lightly, however).
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
These functions are only valid within a custom type callback.
|
||||
|
||||
=head2 arguments_count
|
||||
|
||||
my $count = argument_count;
|
||||
|
||||
Returns the total number of native arguments.
|
||||
|
||||
=head2 arguments_get_sint8
|
||||
|
||||
my $sint8 = arguments_get_sint8 $i;
|
||||
|
||||
Get the 8 bit signed integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_sint8
|
||||
|
||||
arguments_set_sint8 $i, $sint8;
|
||||
|
||||
Set the 8 bit signed integer argument at position I<$i> to I<$sint8>.
|
||||
|
||||
=head2 arguments_get_uint8
|
||||
|
||||
my $uint8 = arguments_get_uint8 $i;
|
||||
|
||||
Get the 8 bit unsigned integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_uint8
|
||||
|
||||
arguments_set_uint8 $i, $uint8;
|
||||
|
||||
Set the 8 bit unsigned integer argument at position I<$i> to I<$uint8>.
|
||||
|
||||
=head2 arguments_get_sint16
|
||||
|
||||
my $sint16 = arguments_get_sint16 $i;
|
||||
|
||||
Get the 16 bit signed integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_sint16
|
||||
|
||||
arguments_set_sint16 $i, $sint16;
|
||||
|
||||
Set the 16 bit signed integer argument at position I<$i> to I<$sint16>.
|
||||
|
||||
=head2 arguments_get_uint16
|
||||
|
||||
my $uint16 = arguments_get_uint16 $i;
|
||||
|
||||
Get the 16 bit unsigned integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_uint16
|
||||
|
||||
arguments_set_uint16 $i, $uint16;
|
||||
|
||||
Set the 16 bit unsigned integer argument at position I<$i> to I<$uint16>.
|
||||
|
||||
=head2 arguments_get_sint32
|
||||
|
||||
my $sint32 = arguments_get_sint32 $i;
|
||||
|
||||
Get the 32 bit signed integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_sint32
|
||||
|
||||
arguments_set_sint32 $i, $sint32;
|
||||
|
||||
Set the 32 bit signed integer argument at position I<$i> to I<$sint32>.
|
||||
|
||||
=head2 arguments_get_uint32
|
||||
|
||||
my $uint32 = arguments_get_uint32 $i;
|
||||
|
||||
Get the 32 bit unsigned integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_uint32
|
||||
|
||||
arguments_set_uint32 $i, $uint32;
|
||||
|
||||
Set the 32 bit unsigned integer argument at position I<$i> to I<$uint32>.
|
||||
|
||||
=head2 arguments_get_sint64
|
||||
|
||||
my $sint64 = arguments_get_sint64 $i;
|
||||
|
||||
Get the 64 bit signed integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_sint64
|
||||
|
||||
arguments_set_sint64 $i, $sint64;
|
||||
|
||||
Set the 64 bit signed integer argument at position I<$i> to I<$sint64>.
|
||||
|
||||
=head2 arguments_get_uint64
|
||||
|
||||
my $uint64 = arguments_get_uint64 $i;
|
||||
|
||||
Get the 64 bit unsigned integer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_uint64
|
||||
|
||||
arguments_set_uint64 $i, $uint64;
|
||||
|
||||
Set the 64 bit unsigned integer argument at position I<$i> to I<$uint64>.
|
||||
|
||||
=head2 arguments_get_float
|
||||
|
||||
my $float = arguments_get_float $i;
|
||||
|
||||
Get the floating point argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_float
|
||||
|
||||
arguments_set_float $i, $float;
|
||||
|
||||
Set the floating point argument at position I<$i> to I<$float>
|
||||
|
||||
=head2 arguments_get_double
|
||||
|
||||
my $double = arguments_get_double $i;
|
||||
|
||||
Get the double precision floating point argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_double
|
||||
|
||||
arguments_set_double $i, $double;
|
||||
|
||||
Set the double precision floating point argument at position I<$i> to
|
||||
I<$double>
|
||||
|
||||
=head2 arguments_get_pointer
|
||||
|
||||
my $pointer = arguments_get_pointer $i;
|
||||
|
||||
Get the pointer argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_pointer
|
||||
|
||||
arguments_set_pointer $i, $pointer;
|
||||
|
||||
Set the pointer argument at position I<$i> to I<$pointer>.
|
||||
|
||||
=head2 arguments_get_string
|
||||
|
||||
my $string = arguments_get_string $i;
|
||||
|
||||
Get the string argument from position I<$i>.
|
||||
|
||||
=head2 arguments_set_string
|
||||
|
||||
arguments_set_string $i, $string;
|
||||
|
||||
Set the string argument at position I<$i> to I<$string>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
=back
|
||||
|
||||
Examples of use:
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus::Type::PointerSizeBuffer>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
356
database/perl/vendor/lib/FFI/Platypus/Buffer.pm
vendored
Normal file
356
database/perl/vendor/lib/FFI/Platypus/Buffer.pm
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
package FFI::Platypus::Buffer;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
|
||||
our @EXPORT = qw( scalar_to_buffer buffer_to_scalar );
|
||||
our @EXPORT_OK = qw ( scalar_to_pointer grow set_used_length window );
|
||||
|
||||
# ABSTRACT: Convert scalars to C buffers
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
use constant _incantation =>
|
||||
$^O eq 'MSWin32' && do { require Config; $Config::Config{archname} =~ /MSWin32-x64/ }
|
||||
? 'Q'
|
||||
: 'L!';
|
||||
|
||||
|
||||
sub scalar_to_buffer ($)
|
||||
{
|
||||
(unpack(_incantation, pack 'P', $_[0]), do { use bytes; length $_[0] });
|
||||
}
|
||||
|
||||
|
||||
sub scalar_to_pointer ($)
|
||||
{
|
||||
unpack(_incantation, pack 'P', $_[0]);
|
||||
}
|
||||
|
||||
|
||||
sub buffer_to_scalar ($$)
|
||||
{
|
||||
unpack 'P'.$_[1], pack _incantation, defined $_[0] ? $_[0] : 0;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Buffer - Convert scalars to C buffers
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus::Buffer;
|
||||
my($pointer, $size) = scalar_to_buffer $scalar;
|
||||
my $scalar2 = buffer_to_scalar $pointer, $size;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
A common pattern in C is to pass a "buffer" or region of memory into a
|
||||
function with a pair of arguments, an opaque pointer and the size of the
|
||||
memory region. In Perl the equivalent structure is a scalar containing
|
||||
a string of bytes. This module provides portable functions for
|
||||
converting a Perl string or scalar into a buffer and back.
|
||||
|
||||
These functions are implemented using L<pack and unpack|perlpacktut> and
|
||||
so they should be relatively fast.
|
||||
|
||||
Both functions are exported by default, but you can explicitly export
|
||||
one or neither if you so choose.
|
||||
|
||||
A better way to do this might be with custom types see
|
||||
L<FFI::Platypus::API> and L<FFI::Platypus::Type>. These functions were
|
||||
taken from the now obsolete L<FFI::Util> module, as they may be useful
|
||||
in some cases.
|
||||
|
||||
B<Caution>: This module provides great power in the way that you
|
||||
interact with C code, but with that power comes great responsibility.
|
||||
Since you are dealing with blocks of memory you need to take care to
|
||||
understand the underlying ownership model of these pointers.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=head2 scalar_to_buffer
|
||||
|
||||
my($pointer, $size) = scalar_to_buffer $scalar;
|
||||
|
||||
Convert a string scalar into a buffer. Returned in order are a pointer
|
||||
to the start of the string scalar's memory region and the size of the
|
||||
region.
|
||||
|
||||
You should NEVER try to free C<$pointer>.
|
||||
|
||||
When you pass this pointer and size into a C function, it has direct
|
||||
access to the data stored in your scalar, so it is important that you
|
||||
not resize or free the scalar while it is in use by the C code. Typically
|
||||
if you are passing a buffer into a C function which reads or writes to
|
||||
the buffer, but does not keep the pointer for later use you are okay.
|
||||
If the buffer is in use long term by the C code, then you should consider
|
||||
copying the buffer instead. For example:
|
||||
|
||||
use FFI::Platypus::Buffer qw( scalar_to_buffer );
|
||||
use FFI::Platypus::Memory qw( malloc memcpy free )
|
||||
|
||||
my($ptr, $size) = scalar_to_buffer $string;
|
||||
c_function_thaat_does_not_keep_ptr( $ptr, $size); # okay
|
||||
|
||||
my($ptr, $size) = scalar_to_buffer $string;
|
||||
my $ptr_copy = malloc($size);
|
||||
memcpy($ptr_copy, $ptr, $size);
|
||||
c_function_that_DOES_keep_ptr( $ptr_copy, $size); # also okay
|
||||
|
||||
...
|
||||
|
||||
# later when you know that the c code is no longer using the pointer
|
||||
# Since you allocated the copy, you are responsible for free'ing it.
|
||||
free($ptr_copy);
|
||||
|
||||
=head2 scalar_to_pointer
|
||||
|
||||
my $pointer = scalar_to_pointer $scalar;
|
||||
|
||||
Get the pointer to the scalar. (Similar to C<scalar_to_buffer> above, but
|
||||
the size of the scalar is not computed or returned).
|
||||
|
||||
Not exported by default, but may be exported on request.
|
||||
|
||||
=head2 buffer_to_scalar
|
||||
|
||||
my $scalar = buffer_to_scalar $pointer, $size;
|
||||
|
||||
Convert the buffer region defined by the pointer and size into a string
|
||||
scalar.
|
||||
|
||||
Because of the way memory management works in Perl, the buffer is copied
|
||||
from the buffer into the scalar. If this pointer was returned from C
|
||||
land, then you should only free it if you allocated it.
|
||||
|
||||
=head2 grow
|
||||
|
||||
grow $scalar, $size, \%options;
|
||||
|
||||
Ensure that the scalar can contain at least C<$size> bytes. The
|
||||
following are recognized:
|
||||
|
||||
=over
|
||||
|
||||
=item clear => I<boolean>
|
||||
|
||||
If true, C<$scalar> is cleared prior to being enlarged. This
|
||||
avoids copying the existing contents to the reallocated memory
|
||||
if they are not needed.
|
||||
|
||||
For example, after
|
||||
|
||||
$scalar = "my string";
|
||||
grow $scalar, 100, { clear => 0 };
|
||||
|
||||
C<$scalar == "my string">, while after
|
||||
|
||||
$scalar = "my string";
|
||||
grow $scalar, 100;
|
||||
|
||||
C<length($scalar) == 0>
|
||||
|
||||
It defaults to C<true>.
|
||||
|
||||
=item set_length => I<boolean>
|
||||
|
||||
If true, the length of the I<string> in the C<$scalar> is set to C<$size>.
|
||||
(See the discussion in L</set_used_length>.) This is useful if a
|
||||
foreign function writes exactly C<$size> bytes to C<$scalar>, as it avoids
|
||||
a subsequent call to C<set_used_length>. Contrast this
|
||||
|
||||
grow my $scalar, 100;
|
||||
read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) );
|
||||
@chars = unpack( 'c*', $scalar );
|
||||
|
||||
with this:
|
||||
|
||||
grow my $scalar, 100, { set_length => 0 };
|
||||
read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) );
|
||||
set_used_length( $scalar, 100 );
|
||||
@chars = unpack( 'c*', $scalar );
|
||||
|
||||
It defaults to C<true>.
|
||||
|
||||
=back
|
||||
|
||||
Any pointers obtained with C<scalar_to_pointer> or C<scalar_to_buffer>
|
||||
are no longer valid after growing the scalar.
|
||||
|
||||
Not exported by default, but may be exported on request.
|
||||
|
||||
=head2 set_used_length
|
||||
|
||||
set_used_length $scalar, $length;
|
||||
|
||||
Update Perl's notion of the length of the string in the scalar. A
|
||||
string scalar keeps track of two lengths: the number of available
|
||||
bytes and the number of used bytes. When a string scalar is
|
||||
used as a buffer by a foreign function, it is necessary to indicate
|
||||
to Perl how many bytes were actually written to it so that Perl's
|
||||
string functions (such as C<substr> or C<unpack>) will work correctly.
|
||||
|
||||
If C<$length> is larger than what the scalar can hold, it is set to the
|
||||
maximum possible size.
|
||||
|
||||
In the following example, the foreign routine C<read_doubles>
|
||||
may fill the buffer with up to a set number of doubles, returning the
|
||||
number actually written.
|
||||
|
||||
my $sizeof_double = $ffi->sizeof( 'double' );
|
||||
my $max_doubles = 100;
|
||||
my $max_length = $max_doubles * $sizeof_double;
|
||||
|
||||
my $buffer; # length($buffer) == 0
|
||||
grow $buffer, $max_length; # length($buffer) is still 0
|
||||
my $pointer = scalar_to_pointer($buffer);
|
||||
|
||||
my $num_read = read_doubles( $pointer, $max_doubles );
|
||||
# length($buffer) is still == 0
|
||||
|
||||
set_used_length $buffer, $num_read * $sizeof_double;
|
||||
# length($buffer) is finally != 0
|
||||
|
||||
# unpack the native doubles into a Perl array
|
||||
my @doubles = unpack( 'd*', $buffer ); # @doubles == $num_read
|
||||
|
||||
Not exported by default, but may be exported on request.
|
||||
|
||||
=head2 window
|
||||
|
||||
window $scalar, $pointer;
|
||||
window $scalar, $pointer, $size;
|
||||
window $scalar, $pointer, $size, $utf8;
|
||||
|
||||
This makes the scalar a read-only window into the arbitrary region of
|
||||
memory defined by C<$pointer>, pointing to the start of the region
|
||||
and C<$size>, the size of the region. If C<$size> is omitted then
|
||||
it will assume a C style string and use the C C<strlen> function to
|
||||
determine the size (the terminating C<'\0'> will not be included).
|
||||
|
||||
This can be useful if you have a C function that returns a buffer
|
||||
pair (pointer, size), and want to access it from Perl without having
|
||||
to copy the data. This can also be useful when interfacing with
|
||||
programming languages that store strings as a address/length pair
|
||||
instead of a pointer to null-terminated sequence of bytes.
|
||||
|
||||
You can specify C<$utf8> to set the UTF-8 flag on the scalar. Note
|
||||
that the behavior of setting the UTF-8 flag on a buffer that does
|
||||
not contain UTF-8 as understood by the version of Perl that you are
|
||||
running is undefined.
|
||||
|
||||
I<Hint>: If you have a buffer that needs to be free'd by C once the
|
||||
scalar falls out of scope you can use L<Variable::Magic> to apply
|
||||
magic to the scalar and free the pointer once it falls out of scope.
|
||||
|
||||
use FFI::Platypus::Buffer qw( scalar_to_pointer );
|
||||
use FFI::Platypus::Memory qw( strdup free );
|
||||
use Variable::Magic qw( wizard cast );
|
||||
|
||||
my $free_when_out_of_scope = wizard(
|
||||
free => sub {
|
||||
my $ptr = scalar_to_pointer ${$_[0]};
|
||||
free $ptr;
|
||||
}
|
||||
);
|
||||
|
||||
my $ptr = strdup "Hello Perl";
|
||||
my $scalar;
|
||||
window $scalar, $ptr, 10;
|
||||
cast $scalar, $free_when_out_of_scope;
|
||||
undef $ptr; # don't need to track the pointer anymore.
|
||||
|
||||
# we can now use scalar as a regular read-only Perl variable
|
||||
print $scalar, "\n"; # prints "Hello Perl" without the \0
|
||||
|
||||
# this will free the C pointer
|
||||
undef $scalar;
|
||||
|
||||
I<Hint>: Returning a scalar string from a Perl function actually
|
||||
copies the value. If you want to return a string without copying
|
||||
then you need to return a reference.
|
||||
|
||||
sub c_string
|
||||
{
|
||||
my $ptr = strdup "Hello Perl";
|
||||
my $scalar;
|
||||
window $scalar, $ptr, 10;
|
||||
cast $scalar, $free_when_out_of_scope;
|
||||
\$scalar;
|
||||
}
|
||||
|
||||
my $ref = c_string();
|
||||
print $$ref, "\n"; # prints "Hello Perl" without the \0
|
||||
|
||||
Not exported by default, but may be exported on request.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
Main Platypus documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
625
database/perl/vendor/lib/FFI/Platypus/Bundle.pm
vendored
Normal file
625
database/perl/vendor/lib/FFI/Platypus/Bundle.pm
vendored
Normal file
@@ -0,0 +1,625 @@
|
||||
package FFI::Platypus::Bundle;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Carp ();
|
||||
|
||||
# ABSTRACT: Bundle foreign code with your Perl module
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
package FFI::Platypus;
|
||||
|
||||
sub _bundle
|
||||
{
|
||||
my @arg_ptrs;
|
||||
|
||||
if(defined $_[-1] && ref($_[-1]) eq 'ARRAY')
|
||||
{
|
||||
@arg_ptrs = @{ pop @_ };
|
||||
}
|
||||
|
||||
push @arg_ptrs, undef;
|
||||
|
||||
my($self, $package) = @_;
|
||||
$package = caller unless defined $package;
|
||||
|
||||
require List::Util;
|
||||
|
||||
my($pm) = do {
|
||||
my $pm = "$package.pm";
|
||||
$pm =~ s{::}{/}g;
|
||||
# if the module is already loaded, we can use %INC
|
||||
# otherwise we can go through @INC and find the first .pm
|
||||
# this doesn't handle all edge cases, but probably enough
|
||||
List::Util::first(sub { (defined $_) && (-f $_) }, ($INC{$pm}, map { "$_/$pm" } @INC));
|
||||
};
|
||||
|
||||
Carp::croak "unable to find module $package" unless $pm;
|
||||
|
||||
my @parts = split /::/, $package;
|
||||
my $incroot = $pm;
|
||||
{
|
||||
my $c = @parts;
|
||||
$incroot =~ s![\\/][^\\/]+$!! while $c--;
|
||||
}
|
||||
|
||||
my $txtfn = List::Util::first(sub { -f $_ }, do {
|
||||
my $dir = join '/', @parts;
|
||||
my $file = $parts[-1] . ".txt";
|
||||
(
|
||||
"$incroot/auto/$dir/$file",
|
||||
"$incroot/../arch/auto/$dir/$file",
|
||||
);
|
||||
});
|
||||
|
||||
my $lib;
|
||||
|
||||
if($txtfn)
|
||||
{
|
||||
$lib = do {
|
||||
my $fh;
|
||||
open($fh, '<', $txtfn) or die "unable to read $txtfn $!";
|
||||
my $line = <$fh>;
|
||||
close $fh;
|
||||
$line =~ /^FFI::Build\@(.*)$/
|
||||
? "$incroot/$1"
|
||||
: Carp::croak "bad format $txtfn";
|
||||
};
|
||||
Carp::croak "bundle code is missing: $lib" unless -f $lib;
|
||||
}
|
||||
elsif(-d "$incroot/../ffi")
|
||||
{
|
||||
require FFI::Build::MM;
|
||||
require Capture::Tiny;
|
||||
require Cwd;
|
||||
require File::Spec;
|
||||
my $save = Cwd::getcwd();
|
||||
chdir "$incroot/..";
|
||||
my($output, $error) = Capture::Tiny::capture_merged(sub {
|
||||
$lib = eval {
|
||||
my $dist_name = $package;
|
||||
$dist_name =~ s/::/-/g;
|
||||
my $fbmm = FFI::Build::MM->new( save => 0 );
|
||||
$fbmm->mm_args( DISTNAME => $dist_name );
|
||||
my $build = $fbmm->load_build('ffi', undef, 'ffi/_build');
|
||||
$build->build;
|
||||
};
|
||||
$@;
|
||||
});
|
||||
if($error)
|
||||
{
|
||||
chdir $save;
|
||||
print STDERR $output;
|
||||
die $error;
|
||||
}
|
||||
else
|
||||
{
|
||||
$lib = File::Spec->rel2abs($lib);
|
||||
chdir $save;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Carp::croak "unable to find bundle code for $package";
|
||||
}
|
||||
|
||||
my $handle = FFI::Platypus::DL::dlopen($lib, FFI::Platypus::DL::RTLD_PLATYPUS_DEFAULT())
|
||||
or Carp::croak "error loading bundle code: $lib @{[ FFI::Platypus::DL::dlerror() ]}";
|
||||
|
||||
$self->{handles}->{$lib} = $handle;
|
||||
|
||||
$self->lib($lib);
|
||||
|
||||
if(my $init = eval { $self->function( 'ffi_pl_bundle_init' => [ 'string', 'sint32', 'opaque[]' ] => 'void' ) })
|
||||
{
|
||||
$init->call($package, scalar(@arg_ptrs)-1, \@arg_ptrs);
|
||||
}
|
||||
|
||||
if(my $init = eval { $self->function( 'ffi_pl_bundle_constant' => [ 'string', 'opaque' ] => 'void' ) })
|
||||
{
|
||||
require FFI::Platypus::Constant;
|
||||
my $api = FFI::Platypus::Constant->new($package);
|
||||
$init->call($package, $api->ptr);
|
||||
}
|
||||
|
||||
if(my $address = $self->find_symbol( 'ffi_pl_bundle_fini' ))
|
||||
{
|
||||
push @{ $self->{fini} }, sub {
|
||||
my $self = shift;
|
||||
$self->function( $address => [ 'string' ] => 'void' )
|
||||
->call( $package );
|
||||
};
|
||||
}
|
||||
|
||||
$self;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Bundle - Bundle foreign code with your Perl module
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
C<ffi/foo.c>:
|
||||
|
||||
#include <ffi_platypus_bundle.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int value;
|
||||
} foo_t;
|
||||
|
||||
foo_t*
|
||||
foo__new(const char *class_name, const char *name, int value)
|
||||
{
|
||||
(void)class_name;
|
||||
foo_t *self = malloc( sizeof( foo_t ) );
|
||||
self->name = strdup(name);
|
||||
self->value = value;
|
||||
return self;
|
||||
}
|
||||
|
||||
const char *
|
||||
foo__name(foo_t *self)
|
||||
{
|
||||
return self->name;
|
||||
}
|
||||
|
||||
int
|
||||
foo__value(foo_t *self)
|
||||
{
|
||||
return self->value;
|
||||
}
|
||||
|
||||
void
|
||||
foo__DESTROY(foo_t *self)
|
||||
{
|
||||
free(self->name);
|
||||
free(self);
|
||||
}
|
||||
|
||||
C<lib/Foo.pm>:
|
||||
|
||||
package Foo;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FFI::Platypus;
|
||||
|
||||
{
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
|
||||
$ffi->type('object(Foo)' => 'foo_t');
|
||||
$ffi->mangler(sub {
|
||||
my $name = shift;
|
||||
$name =~ s/^/foo__/;
|
||||
$name;
|
||||
});
|
||||
|
||||
$ffi->bundle;
|
||||
|
||||
$ffi->attach( new => [ 'string', 'string', 'int' ] => 'foo_t' );
|
||||
$ffi->attach( name => [ 'foo_t' ] => 'string' );
|
||||
$ffi->attach( value => [ 'foo_t' ] => 'int' );
|
||||
$ffi->attach( DESTROY => [ 'foo_t' ] => 'void' );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
C<t/foo.t>
|
||||
|
||||
use Test::More;
|
||||
use Foo;
|
||||
|
||||
my $foo = Foo->new("platypus", 10);
|
||||
isa_ok $foo, 'Foo';
|
||||
is $foo->name, "platypus";
|
||||
is $foo->value, 10;
|
||||
|
||||
done_testing;
|
||||
|
||||
C<Makefile.PL>:
|
||||
|
||||
use ExtUtils::MakeMaker;
|
||||
use FFI::Build::MM;
|
||||
my $fbmm = FFI::Build::MM->new;
|
||||
WriteMakefile(
|
||||
$fbmm->mm_args(
|
||||
NAME => 'Foo',
|
||||
DISTNAME => 'Foo',
|
||||
VERSION => '1.00',
|
||||
# ...
|
||||
)
|
||||
);
|
||||
|
||||
sub MY::postamble
|
||||
{
|
||||
$fbmm->mm_postamble;
|
||||
}
|
||||
|
||||
or C<dist.ini>:
|
||||
|
||||
name = Foo
|
||||
version = 0.01
|
||||
...
|
||||
|
||||
[FFI::Build]
|
||||
version = 1.04
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This document serves as a tutorial for using the new bundling interface provided
|
||||
by L<FFI::Platypus> as of api version 1. It requires L<FFI::Platypus> of at least
|
||||
1.00.
|
||||
|
||||
Sometimes when writing FFI bindings you need to include a little C code (or your
|
||||
favorite compiled language) to finish things off. Alternatively, you might just
|
||||
want to write some C code (or your favorite compiled language) to include with your
|
||||
Perl module to make a tight loop faster. The bundling interface has you covered.
|
||||
|
||||
=head2 Basic example
|
||||
|
||||
To illustrate we will go through the files in the synopsis and explain
|
||||
how and why they work. To start with we have some C code which emulates object
|
||||
oriented code using C<foo__> as a prefix. We use a C struct that we call
|
||||
C<foo_t> to store our object data. On the C level the struct acts as a class,
|
||||
when combined with its functions that act as methods. The constructor just
|
||||
allocates the memory it needs for the C<foo_t> instance, fills in the
|
||||
appropriate fields and returns the pointer:
|
||||
|
||||
foo_t*
|
||||
foo__new(const char *class_name, const char *name, int value)
|
||||
{
|
||||
(void) class_name;
|
||||
foo_t *self = malloc( sizeof( foo_t ) );
|
||||
self->name = strdup(name);
|
||||
self->value = value;
|
||||
return self;
|
||||
}
|
||||
|
||||
We include a class name as the first argument, because Perl will include that
|
||||
when calling the constructor, but we do not use it here. An exercise for the
|
||||
reader would be to add hierarchical inheritance.
|
||||
|
||||
There are also some methods which return member values. This class has only
|
||||
read only members, but you could have read/write or other methods depending
|
||||
on your needs.
|
||||
|
||||
const char *
|
||||
foo__name(foo_t *self)
|
||||
{
|
||||
return self->name;
|
||||
}
|
||||
|
||||
We also include a destructor so that the memory owned by the object can be
|
||||
freed when it is no longer needed.
|
||||
|
||||
void
|
||||
foo__DESTROY(foo_t *self)
|
||||
{
|
||||
free(self->name);
|
||||
free(self);
|
||||
}
|
||||
|
||||
This might start to look a little like a Perl module, and when we look at the Perl
|
||||
code that binds to this code, you will see why. First lets prepare the
|
||||
L<FFI::Platypus> instance and specify the correct api version:
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
|
||||
The bundle interface is only supported with api version 1, so if you try to use
|
||||
version 0 it will not work. Next we define an object type for C<foo_t> which will
|
||||
associate it with the Perl class C<Foo>.
|
||||
|
||||
$ffi->type('object(Foo)' => 'foo_t');
|
||||
|
||||
As object type is a blessed reference to an opaque (default) or integer type which
|
||||
can be used as a Perl object. Platypus does the translating of Perl object to and
|
||||
from the foo_t pointers that the C code understands. For more details on Platypus
|
||||
types see L<FFI::Platypus::Type>.
|
||||
|
||||
Next we set the mangler on the Platypus instance so that we can refer to function
|
||||
names without the C<foo__> prefix. You could just not use the prefix in your C
|
||||
code and skip this step, or you could refer to the function names in their full
|
||||
in your Perl code, however, this saves extra typing and allows you to bundle more
|
||||
than one class with your Perl code without having to worry about name conflicts.
|
||||
|
||||
$ffi->mangler(sub {
|
||||
my $name = shift;
|
||||
$name =~ s/^/foo__/;
|
||||
$name;
|
||||
});
|
||||
|
||||
Finally we let Platypus know that we will be bundling code.
|
||||
|
||||
$ffi->bundle;
|
||||
|
||||
By default, this searches for the appropriate place for your dynamic libraries using
|
||||
the current package. In some cases you may need to override this, for example if your
|
||||
dist is named C<Foo-Bar> but your specific class is named C<Foo::Bar::Baz>, you'd
|
||||
want something like this:
|
||||
|
||||
package Foo::Bar::Baz;
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->bundle('Foo::Bar');
|
||||
...
|
||||
|
||||
Now, finally we can attach the methods for our class:
|
||||
|
||||
$ffi->attach( new => [ 'string', 'int' ] => 'foo_t' );
|
||||
$ffi->attach( name => [ 'foo_t' ] => 'string' );
|
||||
$ffi->attach( value => [ 'foo_t' ] => 'int' );
|
||||
$ffi->attach( DESTROY => [ 'foo_t' ] => 'void' );
|
||||
|
||||
Note that we do not have to include the C<foo__> prefix because of the way we set up
|
||||
the mangler. If we hadn't done that then we could instead attach with the full names:
|
||||
|
||||
$ffi->attach( [ 'foo__new' => 'new' ] => [ 'string', 'int' ] => 'foo_t' );
|
||||
$ffi->attach( [ 'foo__name' => 'name' ] => [ 'foo_t' ] => 'string' );
|
||||
...
|
||||
|
||||
You're done! You can now use this class. Lets write a test to make sure it works,
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
use Foo;
|
||||
|
||||
my $foo = Foo->new("platypus", 10);
|
||||
isa_ok $foo, 'Foo';
|
||||
is $foo->name, "platypus";
|
||||
is $foo->value, 10;
|
||||
|
||||
done_testing;
|
||||
|
||||
and use C<prove> to check that it works:
|
||||
|
||||
% prove -lvm
|
||||
t/foo.t ..
|
||||
ok 1 - An object of class 'Foo' isa 'Foo'
|
||||
ok 2
|
||||
ok 3
|
||||
1..3
|
||||
ok
|
||||
All tests successful.
|
||||
Files=1, Tests=3, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.14 cusr 0.03 csys = 0.19 CPU)
|
||||
Result: PASS
|
||||
|
||||
Platypus automatically compiles and links the dynamic library for you:
|
||||
|
||||
% ls ffi/_build
|
||||
foo.c.o libFoo.so
|
||||
|
||||
The C code will be rebuilt next time if the source code is newer than the object or dynamic libraries
|
||||
files. If the source files are not changed, then it won't be rebuilt to save time. If you are using
|
||||
the code without MakeMaker, or another build system you are responsible for cleaning up these files.
|
||||
This is intended as a convenience to allow you to test your code without having to invoke MakeMaker,
|
||||
or C<dzil> or whatever build system you are using.
|
||||
|
||||
When you distribute your module though, you will want the dynamic library built just once
|
||||
at build-time and installed correctly so that it can be found at run-time. You don't need
|
||||
to make any changes to your C or Perl code, but you do need to tell MakeMaker to build and
|
||||
install the appropriate files using L<FFI::Build::MM>:
|
||||
|
||||
use ExtUtils::MakeMaker;
|
||||
use FFI::Build::MM;
|
||||
my $fbmm = FFI::Build::MM->new;
|
||||
WriteMakefile(
|
||||
$fbmm->mm_args(
|
||||
NAME => 'Foo',
|
||||
DISTNAME => 'Foo',
|
||||
VERSION => '1.00',
|
||||
# ...
|
||||
)
|
||||
);
|
||||
|
||||
sub MY::postamble
|
||||
{
|
||||
$fbmm->mm_postamble;
|
||||
}
|
||||
|
||||
And we can invoke all the normal MakeMaker style stuff and our C code will be compiled, linked
|
||||
and installed at the appropriate steps.
|
||||
|
||||
% perl Makefile.PL
|
||||
Generating a Unix-style Makefile
|
||||
Writing Makefile for Foo
|
||||
Writing MYMETA.yml and MYMETA.json
|
||||
% make
|
||||
cp lib/Foo.pm blib/lib/Foo.pm
|
||||
"/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
|
||||
CC ffi/foo.c
|
||||
LD blib/lib/auto/share/dist/Foo/lib/libFoo.dylib
|
||||
% make test
|
||||
"/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
|
||||
"/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_test
|
||||
PERL_DL_NONLAZY=1 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
|
||||
t/foo.t .. ok
|
||||
All tests successful.
|
||||
Files=1, Tests=3, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.06 cusr 0.01 csys = 0.08 CPU)
|
||||
Result: PASS
|
||||
|
||||
If the C<Makefile.PL> file above looks overly complicated, you can use the
|
||||
L<Dist::Zilla::Plugin::FFI::Build> plugin to simplify your life if you are
|
||||
using L<Dist::Zilla>:
|
||||
|
||||
[FFI::Build]
|
||||
version = 1.04
|
||||
|
||||
Specifying version 1.04 will ensure that any C<.o> or C<.so> files are pruned
|
||||
from your build tree and not distributed by mistake.
|
||||
|
||||
=head2 Initialization example
|
||||
|
||||
The bundle interface also gives you entry points which will be called automatically
|
||||
when your code is loaded and unloaded if they are found.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<ffi_pl_bundle_init>
|
||||
|
||||
void ffi_pl_bundle_init(const char *package, int argc, void *argv[]);
|
||||
|
||||
Called when the dynamic library is loaded. C<package> is the Perl package
|
||||
that called C<bundle> from Perl space. C<argc> and C<argv> represents an
|
||||
array of opaque pointers that can be passed as an array to bundle as the
|
||||
last argument. (the count C<argc> is a little redundant because C<argv>
|
||||
is also NULL terminated).
|
||||
|
||||
=item C<ffi_pl_bundle_constant>
|
||||
|
||||
void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c);
|
||||
|
||||
Called immediately after C<ffi_pl_bundle_init>, and is intended to allow
|
||||
you to set Perl constants from C space. For details on how this works
|
||||
and what methods you can call on the C<ffi_platypus_constant_t> instance,
|
||||
see L<FFI::Platypus::Constant>.
|
||||
|
||||
=item C<ffi_pl_bundle_fini>
|
||||
|
||||
void ffi_pl_bundle_fini(const char *package);
|
||||
|
||||
Called when the dynamic library is unloaded. C<package> is the Perl
|
||||
package that called C<bundle> from Perl space when the library was
|
||||
loaded. B<CAVEAT>: if you attach any functions then this will
|
||||
never be called, because attaching functions locks the Platypus
|
||||
instance into memory along with the libraries which it is using.
|
||||
|
||||
=back
|
||||
|
||||
Here is an example that passes the version and a callback back into Perl
|
||||
space that emulates the Perl 5.10 C<say> feature.
|
||||
|
||||
C<ffi/init.c>:
|
||||
|
||||
#include <ffi_platypus_bundle.h>
|
||||
|
||||
char buffer[512];
|
||||
const char *version;
|
||||
void (*say)(const char *);
|
||||
|
||||
void
|
||||
ffi_pl_bundle_init(const char *package, int argc, void *argv[])
|
||||
{
|
||||
version = argv[0];
|
||||
say = argv[1];
|
||||
|
||||
say("in init!");
|
||||
|
||||
snprintf(buffer, 512, "package = %s, version = %s", package, version);
|
||||
say(buffer);
|
||||
|
||||
snprintf(buffer, 512, "args = %d", argc);
|
||||
say(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
ffi_pl_bundle_fini(const char *package)
|
||||
{
|
||||
say("in fini!");
|
||||
}
|
||||
|
||||
C<lib/Init.pm>:
|
||||
|
||||
package Init;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FFI::Platypus;
|
||||
|
||||
our $VERSION = '1.00';
|
||||
|
||||
{
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
|
||||
my $say = $ffi->closure(sub {
|
||||
my $string = shift;
|
||||
print "$string\n";
|
||||
});
|
||||
|
||||
$ffi->bundle([
|
||||
$ffi->cast( 'string' => 'opaque', $VERSION ),
|
||||
$ffi->cast( '(string)->void' => 'opaque', $say ),
|
||||
]);
|
||||
|
||||
undef $ffi;
|
||||
undef $say;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
The deinitialization order for the C<$say> callback and the C<$ffi>
|
||||
instance is essential here, so we do it manually with C<undef>:
|
||||
|
||||
undef $ffi;
|
||||
undef $say;
|
||||
|
||||
First we deallocate C<$ffi> which calls C<ffi_pl_bundle_fini>,
|
||||
which calls C<$say>, so we want to make sure the latter is still
|
||||
allocated. Once C<ffi_pl_bundle_fini> is done, we can safely
|
||||
deallocate C<$say>.
|
||||
|
||||
If C<ffi_pl_bundle_fini> didn't call back into Perl space like
|
||||
this then we don't have to be as careful about deallocating
|
||||
things in Perl space.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
189
database/perl/vendor/lib/FFI/Platypus/Closure.pm
vendored
Normal file
189
database/perl/vendor/lib/FFI/Platypus/Closure.pm
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
package FFI::Platypus::Closure;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use Scalar::Util qw( refaddr);
|
||||
use Carp qw( croak );
|
||||
use overload '&{}' => sub {
|
||||
my $self = shift;
|
||||
sub { $self->{code}->(@_) };
|
||||
}, bool => sub { 1 }, fallback => 1;
|
||||
|
||||
# ABSTRACT: Platypus closure object
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub new
|
||||
{
|
||||
my($class, $coderef) = @_;
|
||||
croak "not a coderef" unless ref($coderef) eq 'CODE';
|
||||
my $self = bless { code => $coderef, cbdata => {}, sticky => 0 }, $class;
|
||||
$self;
|
||||
}
|
||||
|
||||
sub add_data
|
||||
{
|
||||
my($self, $payload, $type) = @_;
|
||||
$self->{cbdata}{$type} = bless \$payload, 'FFI::Platypus::ClosureData';
|
||||
}
|
||||
|
||||
sub get_data
|
||||
{
|
||||
my($self, $type) = @_;
|
||||
|
||||
if (exists $self->{cbdata}->{$type}) {
|
||||
return ${$self->{cbdata}->{$type}};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sub call
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{code}->(@_)
|
||||
}
|
||||
|
||||
|
||||
sub sticky
|
||||
{
|
||||
my($self) = @_;
|
||||
return if $self->{sticky};
|
||||
$self->{sticky} = 1;
|
||||
$self->_sticky;
|
||||
}
|
||||
|
||||
|
||||
sub unstick
|
||||
{
|
||||
my($self) = @_;
|
||||
return unless $self->{sticky};
|
||||
$self->{sticky} = 0;
|
||||
$self->_unstick;
|
||||
}
|
||||
|
||||
package FFI::Platypus::ClosureData;
|
||||
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Closure - Platypus closure object
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
create closure with OO interface
|
||||
|
||||
use FFI::Platypus::Closure;
|
||||
my $closure = FFI::Platypus::Closure->new(sub { print "hello world\n" });
|
||||
|
||||
create closure from Platypus object
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
my $closure = $ffi->closure(sub { print "hello world\n" });
|
||||
|
||||
use closure
|
||||
|
||||
$ffi->function(foo => ['()->void'] => 'void')->call($closure);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class represents a Perl code reference that can be called from compiled code.
|
||||
When you create a closure object, you can pass it into any function that expects
|
||||
a function pointer. Care needs to be taken with closures because compiled languages
|
||||
typically have a different way of handling lifetimes of objects. You have to make
|
||||
sure that if the compiled code is going to call a closure that the closure object
|
||||
is still in scope somewhere, or has been made sticky, otherwise you may get a
|
||||
segment violation or other mysterious crash.
|
||||
|
||||
=head1 CONSTRUCTOR
|
||||
|
||||
=head2 new
|
||||
|
||||
my $closure = FFI::Platypus::Closure->new($coderef);
|
||||
|
||||
Create a new closure object; C<$coderef> must be a subroutine code reference.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 call
|
||||
|
||||
$closure->call(@arguments);
|
||||
$closure->(@arguments);
|
||||
|
||||
Call the closure from Perl space. May also be invoked by treating
|
||||
the closure object as a code reference.
|
||||
|
||||
=head2 sticky
|
||||
|
||||
$closure->sticky;
|
||||
|
||||
Mark the closure sticky, meaning that it won't be free'd even if
|
||||
all the reference of the object fall out of scope.
|
||||
|
||||
=head2 unstick
|
||||
|
||||
$closure->unstick;
|
||||
|
||||
Unmark the closure as sticky.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
236
database/perl/vendor/lib/FFI/Platypus/Constant.pm
vendored
Normal file
236
database/perl/vendor/lib/FFI/Platypus/Constant.pm
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
package FFI::Platypus::Constant;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use constant 1.32 ();
|
||||
use FFI::Platypus;
|
||||
|
||||
# ABSTRACT: Define constants in C space for Perl
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
{
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->bundle;
|
||||
|
||||
$ffi->type( 'opaque' => 'ffi_platypus_constant_t' );
|
||||
$ffi->type( '(string,string)->void' => 'set_str_t' );
|
||||
$ffi->type( '(string,sint64)->void' => 'set_sint_t' );
|
||||
$ffi->type( '(string,uint64)->void' => 'set_uint_t' );
|
||||
$ffi->type( '(string,double)->void' => 'set_double_t' );
|
||||
|
||||
$ffi->mangler(sub {
|
||||
my($name) = @_;
|
||||
$name =~ s/^/ffi_platypus_constant__/;
|
||||
$name;
|
||||
});
|
||||
|
||||
$ffi->attach( new => [ 'set_str_t', 'set_sint_t', 'set_uint_t', 'set_double_t' ] => 'ffi_platypus_constant_t' => sub {
|
||||
my($xsub, $class, $default_package) = @_;
|
||||
my $f = $ffi->closure(sub {
|
||||
my($name, $value) = @_;
|
||||
if($name !~ /::/)
|
||||
{
|
||||
$name = join('::', $default_package, $name);
|
||||
}
|
||||
constant->import($name, $value);
|
||||
});
|
||||
|
||||
bless {
|
||||
ptr => $xsub->($f, $f, $f, $f),
|
||||
f => $f,
|
||||
}, $class;
|
||||
});
|
||||
|
||||
$ffi->attach( DESTROY => ['ffi_platypus_constant_t'] => 'void' => sub {
|
||||
my($xsub, $self) = @_;
|
||||
$xsub->($self->ptr);
|
||||
});
|
||||
|
||||
sub ptr { shift->{ptr} }
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Constant - Define constants in C space for Perl
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
C<ffi/foo.c>:
|
||||
|
||||
#include <ffi_platypus_bundle.h>
|
||||
|
||||
void
|
||||
ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c)
|
||||
{
|
||||
c->set_str("FOO", "BAR"); /* sets $package::FOO to "BAR" */
|
||||
c->set_str("ABC::DEF", "GHI"); /* sets ABC::DEF to GHI */
|
||||
}
|
||||
|
||||
C<lib/Foo.pm>:
|
||||
|
||||
package Foo;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
|
||||
my $ffi = FFI::Platypus->new;
|
||||
# sets constatns Foo::FOO and ABC::DEF from C
|
||||
$ffi->bundle;
|
||||
|
||||
1;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The Platypus bundle interface (see L<FFI::Platypus::Bundle>) has an entry point
|
||||
C<ffi_pl_bundle_constant> that lets you define constants in Perl space from C.
|
||||
|
||||
void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c);
|
||||
|
||||
The first argument C<package> is the name of the Perl package. The second argument
|
||||
C<c> is a struct with function pointers that lets you define constants of different
|
||||
types. The first argument for each function is the name of the constant and the
|
||||
second is the value. If C<::> is included in the constant name then it will be
|
||||
defined in that package space. If it isn't then the constant will be defined in
|
||||
whichever package called C<bundle>.
|
||||
|
||||
=over 4
|
||||
|
||||
=item set_str
|
||||
|
||||
c->set_str(name, value);
|
||||
|
||||
Sets a string constant.
|
||||
|
||||
=item set_sint
|
||||
|
||||
c->set_sint(name, value);
|
||||
|
||||
Sets a 64-bit signed integer constant.
|
||||
|
||||
=item set_uint
|
||||
|
||||
c->set_uint(name, value);
|
||||
|
||||
Sets a 64-bit unsigned integer constant.
|
||||
|
||||
=item set_double
|
||||
|
||||
c->set_double(name, value);
|
||||
|
||||
Sets a double precision floating point constant.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Example
|
||||
|
||||
Suppose you have a header file C<myheader.h>:
|
||||
|
||||
#ifndef MYHEADER_H
|
||||
#define MYHEADER_H
|
||||
|
||||
#define MYVERSION_STRING "1.2.3"
|
||||
#define MYVERSION_MAJOR 1
|
||||
#define MYVERSION_MINOR 2
|
||||
#define MYVERSION_PATCH 3
|
||||
|
||||
enum {
|
||||
MYBAD = -1,
|
||||
MYOK = 1
|
||||
};
|
||||
|
||||
#define MYPI 3.14
|
||||
|
||||
#endif
|
||||
|
||||
You can define these constants from C:
|
||||
|
||||
#include <ffi_platypus_bundle.h>
|
||||
#include "myheader.h"
|
||||
|
||||
void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c)
|
||||
{
|
||||
c->set_str("MYVERSION_STRING", MYVERSION_STRING);
|
||||
c->set_uint("MYVERSION_MAJOR", MYVERSION_MAJOR);
|
||||
c->set_uint("MYVERSION_MINOR", MYVERSION_MINOR);
|
||||
c->set_uint("MYVERSION_PATCH", MYVERSION_PATCH);
|
||||
c->set_sint("MYBAD", MYBAD);
|
||||
c->set_sint("MYOK", MYOK);
|
||||
c->set_double("MYPI", MYPI);
|
||||
}
|
||||
|
||||
Your Perl code doesn't have to do anything when calling bundle:
|
||||
|
||||
package Const;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FFI::Platypus;
|
||||
|
||||
{
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->bundle;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
221
database/perl/vendor/lib/FFI/Platypus/DL.pm
vendored
Normal file
221
database/perl/vendor/lib/FFI/Platypus/DL.pm
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
package FFI::Platypus::DL;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use base qw( Exporter );
|
||||
|
||||
require FFI::Platypus;
|
||||
our @EXPORT = qw( dlopen dlerror dlsym dlclose );
|
||||
push @EXPORT, grep /RTLD_/, keys %FFI::Platypus::DL::;
|
||||
|
||||
# ABSTRACT: Slightly non-portable interface to libdl
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::DL - Slightly non-portable interface to libdl
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
use FFI::Platypus::DL;
|
||||
|
||||
my $handle = dlopen("./libfoo.so", RTLD_PLATYPUS_DEFAULT);
|
||||
my $address = dlsym($handle, "my_function_named_foo");
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->function($address => [] => 'void')->call;
|
||||
dlclose($handle);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides an interface to libdl, the dynamic loader on UNIX. The underlying interface
|
||||
has always been used by L<FFI::Platypus>, but it wasn't a public interface until version 0.52. The
|
||||
name was changed with that version when it became a public interface, so be sure to specify that
|
||||
version if you are going to use it.
|
||||
|
||||
It is somewhat non-portable for these reasons:
|
||||
|
||||
=over 4
|
||||
|
||||
=item GNU extensions
|
||||
|
||||
It provides some GNU extensions to platforms such as Linux that support them.
|
||||
|
||||
=item Windows
|
||||
|
||||
It provides an emulation layer on Windows. The emulation layer only supports C<RTLD_PLATYPUS_DEFAULT>
|
||||
as a flag. The emulation layer emulates the convention described below of passing C<undef> as
|
||||
the dynamic library name to mean, use the currently running executable. I've used it without
|
||||
any problems for years, but Windows is not my main development platform.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=head2 dlopen
|
||||
|
||||
my $handle = dlopen($filename, $flags);
|
||||
|
||||
This opens a dynamic library in the context of the dynamic loader. C<$filename> is the full or
|
||||
relative path to a dynamic library (usually a C<.so> on Linux and some other UNIXen, a C<.dll> on
|
||||
Windows and a C<.dylib> on OS X). C<$flags> are flags that can be used to alter the behavior
|
||||
of the library and the symbols it contains. The return value is an opaque pointer or C<$handle>
|
||||
which can be used to look up symbols with C<dlsym>. The handle should be closed with C<dlclose>
|
||||
when you are done with it.
|
||||
|
||||
By convention if you pass in C<undef> for the filename, the currently loaded executable will be
|
||||
used instead of a separate dynamic library. This is the easiest and most portable way to find
|
||||
the address of symbols in the standard C library. This convention is baked into most UNIXen,
|
||||
but this capability is emulated in Windows which doesn't come with the capability out of the box.
|
||||
|
||||
If there is an error in opening the library then C<undef> will be returned and the diagnostic
|
||||
for the failure can be retrieved with C<dlerror> as described below.
|
||||
|
||||
Not all flags are supported on all platforms. You can test if a flag is available using can:
|
||||
|
||||
if(FFI::Platypus::DL->can('RTLD_LAZY'))
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
Typically where flags are not mutually exclusive, they can be or'd together:
|
||||
|
||||
my $handle = dlopen("libfoo.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
Check your operating system documentation for detailed descriptions of these flags.
|
||||
|
||||
=over 4
|
||||
|
||||
=item RTLD_PLATYPUS_DEFAULT
|
||||
|
||||
This is the L<FFI::Platypus> default for C<dlopen> (NOTE: NOT the libdl default). This is the only
|
||||
flag supported on Windows. For historical reasons, this is usually C<RTLD_LAZY> on Unix and C<0> on
|
||||
Windows.
|
||||
|
||||
=item RTLD_LAZY
|
||||
|
||||
Perform lazy binding.
|
||||
|
||||
=item RTLD_NOW
|
||||
|
||||
Resolve all symbols before returning from C<dlopen>. Error if all symbols cannot resolve.
|
||||
|
||||
=item RTLD_GLOBAL
|
||||
|
||||
Symbols are shared.
|
||||
|
||||
=item RTLD_LOCAL
|
||||
|
||||
Symbols are NOT shared.
|
||||
|
||||
=item RTLD_NODELETE
|
||||
|
||||
glibc 2.2 extension.
|
||||
|
||||
=item RTLD_NOLOAD
|
||||
|
||||
glibc 2.2 extension.
|
||||
|
||||
=item RTLD_DEEPBIND
|
||||
|
||||
glibc 2.3.4 extension.
|
||||
|
||||
=back
|
||||
|
||||
=head2 dlsym
|
||||
|
||||
my $opaque = dlsym($handle, $symbol);
|
||||
|
||||
This looks up the given C<$symbol> in the library pointed to by C<$handle>. If the symbol is found,
|
||||
the address for that symbol is returned as an opaque pointer. This pointer can be passed into
|
||||
the L<FFI::Platypus> C<function> and C<attach> methods instead of a function name.
|
||||
|
||||
If the symbol cannot be found then C<undef> will be returned and the diagnostic for the failure can
|
||||
be retrieved with C<dlerror> as described below.
|
||||
|
||||
=head2 dlclose
|
||||
|
||||
my $status = dlclose($handle);
|
||||
|
||||
On success, C<dlclose> returns 0; on error, it returns a nonzero value, and the diagnostic for the
|
||||
failure can be retrieved with C<dlerror> as described below.
|
||||
|
||||
=head2 dlerror
|
||||
|
||||
my $error_string = dlerror;
|
||||
|
||||
Returns the human readable diagnostic for the reason for the failure for the most recent C<dl>
|
||||
prefixed function call.
|
||||
|
||||
=head1 CAVEATS
|
||||
|
||||
Some flags for C<dlopen> are not portable. This module may not be supported platforms added to
|
||||
L<FFI::Platypus> in the future. It does work as far as I know on all of the currently supported
|
||||
platforms.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
219
database/perl/vendor/lib/FFI/Platypus/Function.pm
vendored
Normal file
219
database/perl/vendor/lib/FFI/Platypus/Function.pm
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package FFI::Platypus::Function;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
|
||||
# ABSTRACT: An FFI function object
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
use overload '&{}' => sub {
|
||||
my $ffi = shift;
|
||||
sub { $ffi->call(@_) };
|
||||
}, 'bool' => sub {
|
||||
my $ffi = shift;
|
||||
return $ffi;
|
||||
}, fallback => 1;
|
||||
|
||||
package FFI::Platypus::Function::Function;
|
||||
|
||||
use base qw( FFI::Platypus::Function );
|
||||
|
||||
sub attach
|
||||
{
|
||||
my($self, $perl_name, $proto) = @_;
|
||||
|
||||
my $frame = -1;
|
||||
my($caller, $filename, $line);
|
||||
|
||||
do {
|
||||
($caller, $filename, $line) = caller(++$frame);
|
||||
} while( $caller =~ /^FFI::Platypus(|::Function|::Function::Wrapper|::Declare)$/ );
|
||||
|
||||
$perl_name = join '::', $caller, $perl_name
|
||||
unless $perl_name =~ /::/;
|
||||
|
||||
$self->_attach($perl_name, "$filename:$line", $proto);
|
||||
$self;
|
||||
}
|
||||
|
||||
sub sub_ref
|
||||
{
|
||||
my($self) = @_;
|
||||
|
||||
my $frame = -1;
|
||||
my($caller, $filename, $line);
|
||||
|
||||
do {
|
||||
($caller, $filename, $line) = caller(++$frame);
|
||||
} while( $caller =~ /^FFI::Platypus(|::Function|::Function::Wrapper|::Declare)$/ );
|
||||
|
||||
$self->_sub_ref("$filename:$line");
|
||||
}
|
||||
|
||||
package FFI::Platypus::Function::Wrapper;
|
||||
|
||||
use base qw( FFI::Platypus::Function );
|
||||
|
||||
sub new
|
||||
{
|
||||
my($class, $function, $wrapper) = @_;
|
||||
bless [ $function, $wrapper ], $class;
|
||||
}
|
||||
|
||||
sub call
|
||||
{
|
||||
my($function, $wrapper) = @{ shift() };
|
||||
@_ = ($function, @_);
|
||||
goto &$wrapper;
|
||||
}
|
||||
|
||||
sub attach
|
||||
{
|
||||
my($self, $perl_name, $proto) = @_;
|
||||
my($function, $wrapper) = @{ $self };
|
||||
|
||||
unless($perl_name =~ /::/)
|
||||
{
|
||||
my $caller;
|
||||
my $frame = -1;
|
||||
do { $caller = caller(++$frame) } while( $caller =~ /^FFI::Platypus(|::Declare)$/ );
|
||||
$perl_name = join '::', $caller, $perl_name
|
||||
}
|
||||
|
||||
my $xsub = $function->sub_ref;
|
||||
|
||||
{
|
||||
my $code = sub {
|
||||
unshift @_, $xsub;
|
||||
goto &$wrapper;
|
||||
};
|
||||
if(defined $proto)
|
||||
{
|
||||
_set_prototype($proto, $code);
|
||||
}
|
||||
no strict 'refs';
|
||||
*{$perl_name} = $code;
|
||||
}
|
||||
|
||||
$self;
|
||||
}
|
||||
|
||||
sub sub_ref
|
||||
{
|
||||
my($self) = @_;
|
||||
my($function, $wrapper) = @{ $self };
|
||||
my $xsub = $function->sub_ref;
|
||||
|
||||
return sub {
|
||||
unshift @_, $xsub;
|
||||
goto &$wrapper;
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Function - An FFI function object
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
|
||||
# call directly
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
my $f = $ffi->function(puts => ['string'] => 'int');
|
||||
$f->call("hello there");
|
||||
|
||||
# attach as xsub and call (faster for repeated calls)
|
||||
$f->attach('puts');
|
||||
puts('hello there');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class represents an unattached platypus function. For more
|
||||
context and better examples see L<FFI::Platypus>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 attach
|
||||
|
||||
$f->attach($name);
|
||||
$f->attach($name, $prototype);
|
||||
|
||||
Attaches the function as an xsub (similar to calling attach directly
|
||||
from an L<FFI::Platypus> instance). You may optionally include a
|
||||
prototype.
|
||||
|
||||
=head2 call
|
||||
|
||||
my $ret = $f->call(@arguments);
|
||||
my $ret = $f->(@arguments);
|
||||
|
||||
Calls the function and returns the result. You can also use the
|
||||
function object B<like> a code reference.
|
||||
|
||||
=head2 sub_ref
|
||||
|
||||
my $code = $f->sub_ref;
|
||||
|
||||
Returns an anonymous code reference. This will usually be faster
|
||||
than using the C<call> method above.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
86
database/perl/vendor/lib/FFI/Platypus/Internal.pm
vendored
Normal file
86
database/perl/vendor/lib/FFI/Platypus/Internal.pm
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package FFI::Platypus::Internal;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
|
||||
require FFI::Platypus;
|
||||
_init();
|
||||
|
||||
our @EXPORT = grep /^FFI_PL/, keys %FFI::Platypus::Internal::;
|
||||
|
||||
# ABSTRACT: For internal use only
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Internal - For internal use only
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
perldoc FFI::Platypus
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module is for internal use only. Do not rely on it having any particular behavior, or even existing in future versions.
|
||||
You have been warned.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
93
database/perl/vendor/lib/FFI/Platypus/Lang.pm
vendored
Normal file
93
database/perl/vendor/lib/FFI/Platypus/Lang.pm
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package FFI::Platypus::Lang;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
|
||||
# ABSTRACT: Language specific customizations
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Lang - Language specific customizations
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
perldoc FFI::Platypus::Lang;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This namespace is reserved for language specific customizations of L<FFI::Platypus>.
|
||||
This usually involves providing native type maps. It can also involve computing
|
||||
mangled names. The default language is C, and is defined in L<FFI::Platypus::Lang::C>.
|
||||
|
||||
This package itself doesn't do anything, it serves only as documentation.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
=item L<FFI::Platypus::Lang::C>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
112
database/perl/vendor/lib/FFI/Platypus/Lang/ASM.pm
vendored
Normal file
112
database/perl/vendor/lib/FFI/Platypus/Lang/ASM.pm
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package FFI::Platypus::Lang::ASM;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
|
||||
# ABSTRACT: Documentation and tools for using Platypus with the Assembly
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub native_type_map
|
||||
{
|
||||
{}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Lang::ASM - Documentation and tools for using Platypus with the Assembly
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->lang('ASM');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Setting your lang to C<ASM> includes no native type aliases, so types
|
||||
like C<int> or C<unsigned long> will not work. You need to specify
|
||||
instead C<sint32> or C<sint64>. Although intended for use with Assembly
|
||||
it could also be used for other languages if you did not want to use
|
||||
the normal C aliases for native types.
|
||||
|
||||
This document will one day include information on bundling Assembly
|
||||
with your Perl / FFI / Platypus distribution. Pull requests welcome!
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 native_type_map
|
||||
|
||||
my $hashref = FFI::Platypus::Lang::ASM->native_type_map;
|
||||
|
||||
This returns an empty hash reference. For other languages it returns
|
||||
a hash reference that defines the aliases for the types normally used
|
||||
for that language.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The Core Platypus documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
109
database/perl/vendor/lib/FFI/Platypus/Lang/C.pm
vendored
Normal file
109
database/perl/vendor/lib/FFI/Platypus/Lang/C.pm
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package FFI::Platypus::Lang::C;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
|
||||
# ABSTRACT: Documentation and tools for using Platypus with the C programming language
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub native_type_map
|
||||
{
|
||||
require FFI::Platypus::ShareConfig;
|
||||
FFI::Platypus::ShareConfig->get('type_map');
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Lang::C - Documentation and tools for using Platypus with the C programming language
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->lang('C'); # the default
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides some hooks for Platypus to interact with the C
|
||||
programming language. It is generally used by default if you do not
|
||||
specify another foreign programming language with the
|
||||
L<FFI::Platypus#lang> attribute.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 native_type_map
|
||||
|
||||
my $hashref = FFI::Platypus::Lang::C->native_type_map;
|
||||
|
||||
This returns a hash reference containing the native aliases for the
|
||||
C programming languages. That is the keys are native C types and the
|
||||
values are libffi native types.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The Core Platypus documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
272
database/perl/vendor/lib/FFI/Platypus/Lang/Win32.pm
vendored
Normal file
272
database/perl/vendor/lib/FFI/Platypus/Lang/Win32.pm
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
package FFI::Platypus::Lang::Win32;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Config;
|
||||
|
||||
# ABSTRACT: Documentation and tools for using Platypus with the Windows API
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub abi
|
||||
{
|
||||
$^O =~ /^(cygwin|MSWin32|msys)$/ && $Config{ptrsize} == 4
|
||||
? 'stdcall'
|
||||
: 'default_abi';
|
||||
}
|
||||
|
||||
|
||||
my %map;
|
||||
|
||||
sub native_type_map
|
||||
{
|
||||
unless(%map)
|
||||
{
|
||||
require FFI::Platypus::ShareConfig;
|
||||
%map = %{ FFI::Platypus::ShareConfig->get('type_map') };
|
||||
|
||||
my %win32_map = qw(
|
||||
BOOL int
|
||||
BOOLEAN BYTE
|
||||
BYTE uchar
|
||||
CCHAR char
|
||||
CHAR char
|
||||
COLORREF DWORD
|
||||
DWORD uint
|
||||
DWORDLONG uint64
|
||||
DWORD_PTR ULONG_PTR
|
||||
DWORD32 uint32
|
||||
DWORD64 uint64
|
||||
FLOAT float
|
||||
HACCEL HANDLE
|
||||
HANDLE PVOID
|
||||
HBITMAP HANDLE
|
||||
HBRUSH HANDLE
|
||||
HCOLORSPACE HANDLE
|
||||
HCONV HANDLE
|
||||
HCONVLIST HANDLE
|
||||
HCURSOR HICON
|
||||
HDC HANDLE
|
||||
HDDEDATA HANDLE
|
||||
HDESK HANDLE
|
||||
HDROP HANDLE
|
||||
HDWP HANDLE
|
||||
HENHMETAFILE HANDLE
|
||||
HFILE int
|
||||
HFONT HANDLE
|
||||
HGDIOBJ HANDLE
|
||||
HGLOBAL HANDLE
|
||||
HHOOK HANDLE
|
||||
HICON HANDLE
|
||||
HINSTANCE HANDLE
|
||||
HKEY HANDLE
|
||||
HKL HANDLE
|
||||
HLOCAL HANDLE
|
||||
HMENU HANDLE
|
||||
HMETAFILE HANDLE
|
||||
HMODULE HINSTANCE
|
||||
HMONITOR HANDLE
|
||||
HPALETTE HANDLE
|
||||
HPEN HANDLE
|
||||
HRESULT LONG
|
||||
HRGN HANDLE
|
||||
HRSRC HANDLE
|
||||
HSZ HANDLE
|
||||
HWINSTA HANDLE
|
||||
HWND HANDLE
|
||||
INT int
|
||||
INT8 sint8
|
||||
INT16 sint16
|
||||
INT32 sint32
|
||||
INT64 sint64
|
||||
LANGID WORD
|
||||
LCID DWORD
|
||||
LCTYPE DWORD
|
||||
LGRPID DWORD
|
||||
LONG sint32
|
||||
LONGLONG sint64
|
||||
LONG32 sint32
|
||||
LONG64 sint64
|
||||
LPCSTR string
|
||||
LPCVOID opaque
|
||||
LPVOID opaque
|
||||
LRESULT LONG_PTR
|
||||
PSTR string
|
||||
PVOID opaque
|
||||
QWORD uint64
|
||||
SC_HANDLE HANDLE
|
||||
SC_LOCK LPVOID
|
||||
SERVICE_STATUS_HANDLE HANDLE
|
||||
SHORT sint16
|
||||
SIZE_T ULONG_PTR
|
||||
SSIZE_T LONG_PTR
|
||||
UCHAR uint8
|
||||
UINT8 uint8
|
||||
UINT16 uint16
|
||||
UINT32 uint32
|
||||
UINT64 uint64
|
||||
ULONG uint32
|
||||
ULONGLONG uint64
|
||||
ULONG32 uint32
|
||||
ULONG64 uint64
|
||||
USHORT uint16
|
||||
USN LONGLONG
|
||||
VOID void
|
||||
WORD uint16
|
||||
WPARAM UINT_PTR
|
||||
|
||||
);
|
||||
|
||||
if($Config{ptrsize} == 4)
|
||||
{
|
||||
$win32_map{HALF_PTR} = 'sint16';
|
||||
$win32_map{INT_PTR} = 'sint32';
|
||||
$win32_map{LONG_PTR} = 'sint16';
|
||||
$win32_map{UHALF_PTR} = 'uint16';
|
||||
$win32_map{UINT_PTR} = 'uint32';
|
||||
$win32_map{ULONG_PTR} = 'uint16';
|
||||
}
|
||||
elsif($Config{ptrsize} == 8)
|
||||
{
|
||||
$win32_map{HALF_PTR} = 'sint16';
|
||||
$win32_map{INT_PTR} = 'sint32';
|
||||
$win32_map{LONG_PTR} = 'sint16';
|
||||
$win32_map{UHALF_PTR} = 'uint16';
|
||||
$win32_map{UINT_PTR} = 'uint32';
|
||||
$win32_map{ULONG_PTR} = 'uint16';
|
||||
}
|
||||
else
|
||||
{
|
||||
die "interesting word size you have";
|
||||
}
|
||||
|
||||
foreach my $alias (keys %win32_map)
|
||||
{
|
||||
my $type = $alias;
|
||||
while(1)
|
||||
{
|
||||
if($type =~ /^(opaque|[us]int(8|16|32|64)|float|double|string|void)$/)
|
||||
{
|
||||
$map{$alias} = $type;
|
||||
last;
|
||||
}
|
||||
if(defined $map{$type})
|
||||
{
|
||||
$map{$alias} = $map{$type};
|
||||
last;
|
||||
}
|
||||
if(defined $win32_map{$type})
|
||||
{
|
||||
$type = $win32_map{$type};
|
||||
next;
|
||||
}
|
||||
die "unable to resolve $alias => ... => $type";
|
||||
}
|
||||
}
|
||||
|
||||
# stuff we are not yet dealing with
|
||||
# LPCTSTR is unicode string, not currently supported
|
||||
# LPWSTR 16 bit unicode string
|
||||
# TBYTE TCHAR UNICODE_STRING WCHAR
|
||||
# Not supported: POINTER_32 POINTER_64 POINTER_SIGNED POINTER_UNSIGNED
|
||||
}
|
||||
\%map;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Lang::Win32 - Documentation and tools for using Platypus with the Windows API
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->lang('Win32');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides the Windows datatypes used by the Windows API.
|
||||
This means that you can use things like C<DWORD> as an alias for
|
||||
C<uint32>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 abi
|
||||
|
||||
my $abi = FFI::Platypus::Lang::Win32->abi;
|
||||
|
||||
=head2 native_type_map
|
||||
|
||||
my $hashref = FFI::Platypus::Lang::Win32->native_type_map;
|
||||
|
||||
This returns a hash reference containing the native aliases for the
|
||||
Windows API. That is the keys are native Windows API C types and the
|
||||
values are libffi native types.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The Core Platypus documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
130
database/perl/vendor/lib/FFI/Platypus/Legacy.pm
vendored
Normal file
130
database/perl/vendor/lib/FFI/Platypus/Legacy.pm
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
package FFI::Platypus::Legacy;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
|
||||
# ABSTRACT: Legacy Platypus interfaces
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
package FFI::Platypus;
|
||||
|
||||
sub _package
|
||||
{
|
||||
my($self, $module, $modlibname) = @_;
|
||||
|
||||
($module, $modlibname) = caller unless defined $modlibname;
|
||||
my @modparts = split /::/, $module;
|
||||
my $modfname = $modparts[-1];
|
||||
my $modpname = join('/',@modparts);
|
||||
my $c = @modparts;
|
||||
$modlibname =~ s,[\\/][^\\/]+$,, while $c--; # Q&D basename
|
||||
|
||||
{
|
||||
my @maybe = (
|
||||
"$modlibname/auto/$modpname/$modfname.txt",
|
||||
"$modlibname/../arch/auto/$modpname/$modfname.txt",
|
||||
);
|
||||
foreach my $file (@maybe)
|
||||
{
|
||||
if(-f $file)
|
||||
{
|
||||
open my $fh, '<', $file;
|
||||
my $line = <$fh>;
|
||||
close $fh;
|
||||
if($line =~ /^FFI::Build\@(.*)$/)
|
||||
{
|
||||
$self->lib("$modlibname/$1");
|
||||
return $self;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require FFI::Platypus::ShareConfig;
|
||||
my @dlext = @{ FFI::Platypus::ShareConfig->get("config_dlext") };
|
||||
|
||||
foreach my $dlext (@dlext)
|
||||
{
|
||||
my $file = "$modlibname/auto/$modpname/$modfname.$dlext";
|
||||
unless(-e $file)
|
||||
{
|
||||
$modlibname =~ s,[\\/][^\\/]+$,,;
|
||||
$file = "$modlibname/arch/auto/$modpname/$modfname.$dlext";
|
||||
}
|
||||
|
||||
if(-e $file)
|
||||
{
|
||||
$self->lib($file);
|
||||
return $self;
|
||||
}
|
||||
}
|
||||
|
||||
$self;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Legacy - Legacy Platypus interfaces
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class is private to L<FFI::Platypus>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
219
database/perl/vendor/lib/FFI/Platypus/Memory.pm
vendored
Normal file
219
database/perl/vendor/lib/FFI/Platypus/Memory.pm
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package FFI::Platypus::Memory;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
|
||||
# ABSTRACT: Memory functions for FFI
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
our @EXPORT = qw( malloc free calloc realloc memcpy memset strdup strndup strcpy );
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->lib(undef);
|
||||
$ffi->bundle;
|
||||
sub _ffi { $ffi }
|
||||
|
||||
$ffi->attach(malloc => ['size_t'] => 'opaque' => '$');
|
||||
$ffi->attach(free => ['opaque'] => 'void' => '$');
|
||||
$ffi->attach(calloc => ['size_t', 'size_t'] => 'opaque' => '$$');
|
||||
$ffi->attach(realloc => ['opaque', 'size_t'] => 'opaque' => '$$');
|
||||
$ffi->attach(memcpy => ['opaque', 'opaque', 'size_t'] => 'opaque' => '$$$');
|
||||
$ffi->attach(memset => ['opaque', 'int', 'size_t'] => 'opaque' => '$$$');
|
||||
$ffi->attach(strcpy => ['opaque', 'string'] => 'opaque' => '$$');
|
||||
|
||||
my $_strdup_impl = 'not-loaded';
|
||||
sub _strdup_impl { $_strdup_impl }
|
||||
|
||||
eval {
|
||||
die "do not use c impl" if ($ENV{FFI_PLATYPUS_MEMORY_STRDUP_IMPL}||'libc') eq 'ffi';
|
||||
$ffi->attach(strdup => ['string'] => 'opaque' => '$');
|
||||
$_strdup_impl = 'libc';
|
||||
};
|
||||
if($@)
|
||||
{
|
||||
$_strdup_impl = 'ffi';
|
||||
$ffi->attach([ ffi_platypus_memory__strdup => 'strdup' ] => ['string'] => 'opaque' => '$');
|
||||
}
|
||||
|
||||
my $_strndup_impl = 'not-loaded';
|
||||
sub _strndup_impl { $_strndup_impl }
|
||||
|
||||
eval {
|
||||
die "do not use c impl" if ($ENV{FFI_PLATYPUS_MEMORY_STRDUP_IMPL}||'libc') eq 'ffi';
|
||||
$ffi->attach(strndup => ['string','size_t'] => 'opaque' => '$$');
|
||||
$_strndup_impl = 'libc';
|
||||
};
|
||||
if($@)
|
||||
{
|
||||
$_strndup_impl = 'ffi';
|
||||
$ffi->attach([ ffi_platypus_memory__strndup => 'strndup' ] => ['string','size_t'] => 'opaque' => '$$');
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Memory - Memory functions for FFI
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus::Memory;
|
||||
|
||||
# allocate 64 bytes of memory using the
|
||||
# libc malloc function.
|
||||
my $pointer = malloc 64;
|
||||
|
||||
# use that memory wisely
|
||||
...
|
||||
|
||||
# free the memory when you are done.
|
||||
free $pointer;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides an interface to common memory functions provided by
|
||||
the standard C library. They may be useful when constructing interfaces
|
||||
to C libraries with FFI. It works mostly with the C<opaque> type and it
|
||||
is worth reviewing the section on opaque pointers in L<FFI::Platypus::Type>.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=head2 calloc
|
||||
|
||||
my $pointer = calloc $count, $size;
|
||||
|
||||
The C<calloc> function contiguously allocates enough space for I<$count>
|
||||
objects that are I<$size> bytes of memory each.
|
||||
|
||||
=head2 free
|
||||
|
||||
free $pointer;
|
||||
|
||||
The C<free> function frees the memory allocated by C<malloc>, C<calloc>,
|
||||
C<realloc> or C<strdup>. It is important to only free memory that you
|
||||
yourself have allocated. A good way to crash your program is to try and
|
||||
free a pointer that some C library has returned to you.
|
||||
|
||||
=head2 malloc
|
||||
|
||||
my $pointer = malloc $size;
|
||||
|
||||
The C<malloc> function allocates I<$size> bytes of memory.
|
||||
|
||||
=head2 memcpy
|
||||
|
||||
memcpy $dst_pointer, $src_pointer, $size;
|
||||
|
||||
The C<memcpy> function copies I<$size> bytes from I<$src_pointer> to
|
||||
I<$dst_pointer>. It also returns I<$dst_pointer>.
|
||||
|
||||
=head2 memset
|
||||
|
||||
memset $buffer, $value, $length;
|
||||
|
||||
The C<memset> function writes I<$length> bytes of I<$value> to the address
|
||||
specified by I<$buffer>.
|
||||
|
||||
=head2 realloc
|
||||
|
||||
my $new_pointer = realloc $old_pointer, $size;
|
||||
|
||||
The C<realloc> function reallocates enough memory to fit I<$size> bytes.
|
||||
It copies the existing data and frees I<$old_pointer>.
|
||||
|
||||
If you pass C<undef> in as I<$old_pointer>, then it behaves exactly like
|
||||
C<malloc>:
|
||||
|
||||
my $pointer = realloc undef, 64; # same as malloc 64
|
||||
|
||||
=head2 strcpy
|
||||
|
||||
strcpy $opaque, $string;
|
||||
|
||||
Copies the string to the memory location pointed to by C<$opaque>.
|
||||
|
||||
=head2 strdup
|
||||
|
||||
my $pointer = strdup $string;
|
||||
|
||||
The C<strdup> function allocates enough memory to contain I<$string> and
|
||||
then copies it to that newly allocated memory. This version of
|
||||
C<strdup> returns an opaque pointer type, not a string type. This may
|
||||
seem a little strange, but returning a string type would not be very
|
||||
useful in Perl.
|
||||
|
||||
=head2 strndup
|
||||
|
||||
my $pointer = strndup $string, $max;
|
||||
|
||||
The same as C<strdup> above, except at most C<$max> characters will be
|
||||
copied in the new string.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
Main Platypus documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
557
database/perl/vendor/lib/FFI/Platypus/Record.pm
vendored
Normal file
557
database/perl/vendor/lib/FFI/Platypus/Record.pm
vendored
Normal file
@@ -0,0 +1,557 @@
|
||||
package FFI::Platypus::Record;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Carp qw( croak );
|
||||
use FFI::Platypus;
|
||||
use base qw( Exporter );
|
||||
use constant 1.32 ();
|
||||
|
||||
our @EXPORT = qw( record_layout record_layout_1 );
|
||||
|
||||
# ABSTRACT: FFI support for structured records data
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub record_layout_1
|
||||
{
|
||||
if(@_ % 2 == 0)
|
||||
{
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
unshift @_, $ffi;
|
||||
goto &record_layout;
|
||||
}
|
||||
elsif(defined $_[0] && ref($_[0]) eq 'ARRAY')
|
||||
{
|
||||
my @args = @{ shift @_ };
|
||||
unshift @args, api => 1;
|
||||
unshift @_, \@args;
|
||||
goto &record_layout;
|
||||
}
|
||||
elsif(defined $_[0] && eval { $_[0]->isa('FFI::Platypus') })
|
||||
{
|
||||
goto &record_layout;
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "odd number of arguments, but first argument is not either an array reference or Platypus instance";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub record_layout
|
||||
{
|
||||
my $ffi;
|
||||
|
||||
if(defined $_[0])
|
||||
{
|
||||
if(ref($_[0]) eq 'ARRAY')
|
||||
{
|
||||
my @args = @{ shift() };
|
||||
$ffi = FFI::Platypus->new(@args);
|
||||
}
|
||||
elsif(eval { $_[0]->isa('FFI::Platypus') })
|
||||
{
|
||||
$ffi = shift;
|
||||
}
|
||||
}
|
||||
|
||||
$ffi ||= FFI::Platypus->new;
|
||||
|
||||
my $offset = 0;
|
||||
my $record_align = 0;
|
||||
|
||||
croak "uneven number of arguments!" if scalar(@_) % 2;
|
||||
|
||||
my($caller, $filename, $line) = caller;
|
||||
|
||||
if($caller->can("_ffi_record_size")
|
||||
|| $caller->can("ffi_record_size"))
|
||||
{
|
||||
croak "record already defined for the class $caller";
|
||||
}
|
||||
|
||||
my @destroy;
|
||||
my @ffi_types;
|
||||
|
||||
while(@_)
|
||||
{
|
||||
my $spec = shift;
|
||||
my $name = shift;
|
||||
my $type = $ffi->{tp}->parse( $spec, { member => 1 } );
|
||||
|
||||
croak "illegal name $name"
|
||||
unless $name =~ /^[A-Za-z_][A-Za-z_0-9]*$/
|
||||
|| $name eq ':';
|
||||
croak "accessor/method $name already exists"
|
||||
if $caller->can($name);
|
||||
|
||||
my $size = $type->sizeof;
|
||||
my $align = $type->alignof;
|
||||
$record_align = $align if $align > $record_align;
|
||||
my $meta = $type->meta;
|
||||
|
||||
$offset++ while $offset % $align;
|
||||
|
||||
{
|
||||
my $count;
|
||||
my $ffi_type;
|
||||
|
||||
if($meta->{type} eq 'record') # this means fixed string atm
|
||||
{
|
||||
$ffi_type = 'sint8';
|
||||
$count = $size;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ffi_type = $meta->{ffi_type};
|
||||
$count = $meta->{element_count};
|
||||
$count = 1 unless defined $count;
|
||||
}
|
||||
push @ffi_types, $ffi_type for 1..$count;
|
||||
}
|
||||
|
||||
if($name ne ':')
|
||||
{
|
||||
|
||||
if($meta->{type} eq 'string'
|
||||
&& $meta->{access} eq 'rw')
|
||||
{
|
||||
push @destroy, eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) .qq{
|
||||
sub {
|
||||
shift->$name(undef);
|
||||
};
|
||||
};
|
||||
die $@ if $@;
|
||||
}
|
||||
|
||||
my $full_name = join '::', $caller, $name;
|
||||
my $error_str = _accessor
|
||||
$full_name,
|
||||
"$filename:$line",
|
||||
$type,
|
||||
$offset;
|
||||
croak("$error_str ($spec $name)") if $error_str;
|
||||
};
|
||||
|
||||
$offset += $size;
|
||||
}
|
||||
|
||||
my $size = $offset;
|
||||
|
||||
no strict 'refs';
|
||||
constant->import("${caller}::_ffi_record_size", $size);
|
||||
constant->import("${caller}::_ffi_record_align", $record_align);
|
||||
*{join '::', $caller, '_ffi_record_ro'} = \&_ffi_record_ro;
|
||||
*{join '::', $caller, 'new'} = sub {
|
||||
my $class = shift;
|
||||
my $args = ref($_[0]) ? [%{$_[0]}] : \@_;
|
||||
croak "uneven number of arguments to record constructor"
|
||||
if @$args % 2;
|
||||
my $record = "\0" x $class->_ffi_record_size;
|
||||
my $self = bless \$record, $class;
|
||||
|
||||
while(@$args)
|
||||
{
|
||||
my $key = shift @$args;
|
||||
my $value = shift @$args;
|
||||
$self->$key($value);
|
||||
}
|
||||
|
||||
$self;
|
||||
};
|
||||
|
||||
{
|
||||
require FFI::Platypus::Record::Meta;
|
||||
my $ffi_meta = FFI::Platypus::Record::Meta->new(
|
||||
\@ffi_types,
|
||||
);
|
||||
*{join '::', $caller, '_ffi_meta'} = sub { $ffi_meta };
|
||||
}
|
||||
|
||||
my $destroy_sub = sub {};
|
||||
|
||||
if(@destroy)
|
||||
{
|
||||
$destroy_sub = sub {
|
||||
return if _ffi_record_ro($_[0]);
|
||||
$_->($_[0]) for @destroy;
|
||||
};
|
||||
}
|
||||
do {
|
||||
no strict 'refs';
|
||||
*{"${caller}::DESTROY"} = $destroy_sub;
|
||||
};
|
||||
();
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Record - FFI support for structured records data
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
C:
|
||||
|
||||
struct my_person {
|
||||
int age;
|
||||
const char title[3];
|
||||
const char *name
|
||||
};
|
||||
|
||||
void process_person(struct my_person *person)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Perl:
|
||||
|
||||
package MyPerson;
|
||||
|
||||
use FFI::Platypus::Record;
|
||||
|
||||
record_layout_1(qw(
|
||||
int age
|
||||
string(3) title
|
||||
string_rw name
|
||||
));
|
||||
|
||||
package main;
|
||||
|
||||
use FFI::Platypus;
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->lib("myperson.so");
|
||||
$ffi->type("record(MyPerson)" => 'MyPerson');
|
||||
|
||||
my $person = MyPerson->new(
|
||||
age => 40,
|
||||
title => "Mr.",
|
||||
name => "John Smith",
|
||||
);
|
||||
|
||||
$ffi->attach( process_person => [ 'MyPerson*' ] => 'void' );
|
||||
|
||||
process_person($person);
|
||||
|
||||
$person->age($person->age + 1); # another year older
|
||||
|
||||
process_person($person);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
[version 0.21]
|
||||
|
||||
This module provides a mechanism for building classes that can be used
|
||||
to mange structured data records (known as C as "structs" and in some
|
||||
languages as "records"). A structured record is a series of bytes that
|
||||
have structure understood by the C or other foreign language library
|
||||
that you are interfacing with. It is designed for use with FFI and
|
||||
L<FFI::Platypus>, though it may have other applications.
|
||||
|
||||
Before you get to deep into using this class you should also consider
|
||||
the L<FFI::C>, which provides some overlapping functionality. Briefly,
|
||||
it comes down to this:
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus::Record>
|
||||
|
||||
Supports:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C pointers to C<struct> types
|
||||
|
||||
=item Passing C <struct>s by-value.
|
||||
|
||||
=back
|
||||
|
||||
Does not support:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C C<union> types.
|
||||
|
||||
=item C arrays of C<struct> and C<union> types.
|
||||
|
||||
=back
|
||||
|
||||
=item L<FFI::C>
|
||||
|
||||
Supports:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C C<struct> andC<union> types
|
||||
|
||||
=item C arrays of C<struct> and C<union> types.
|
||||
|
||||
=back
|
||||
|
||||
Does not support:
|
||||
|
||||
=over 4
|
||||
|
||||
=item Passing C C<struct>s by-value.
|
||||
|
||||
=back
|
||||
|
||||
String members are as of this writing a TODO for L<FFI::C>, but
|
||||
should be coming soon!
|
||||
|
||||
=back
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=head2 record_layout_1
|
||||
|
||||
record_layout_1($ffi, $type => $name, ... );
|
||||
record_layout_1(\@ffi_args, $type => $name, ... );
|
||||
record_layout_1($type => $name, ... );
|
||||
|
||||
Define the layout of the record. You may optionally provide an instance
|
||||
of L<FFI::Platypus> as the first argument in order to use its type
|
||||
aliases. Alternatively you may provide constructor arguments that will
|
||||
be passed to the internal platypus instance. Thus this is the same:
|
||||
|
||||
my $ffi = FFI::Platypus->new( lang => 'Rust', api => 1 );
|
||||
record_layout_1( $ffi, ... );
|
||||
# same as:
|
||||
record_layout_1( [ lang => 'Rust' ], ... );
|
||||
|
||||
and this is the same:
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
record_layout_1( $ffi, ... );
|
||||
# same as:
|
||||
record_layout_1( ... );
|
||||
|
||||
Then you provide members as type/name pairs.
|
||||
|
||||
For each member you declare, C<record_layout_1> will create an accessor
|
||||
which can be used to read and write its value. For example imagine a
|
||||
class C<Foo>:
|
||||
|
||||
package Foo;
|
||||
|
||||
use FFI::Platypus::Record;
|
||||
|
||||
record_layout_1(
|
||||
int => 'bar', # int bar;
|
||||
'string(10)' => 'baz', # char baz[10];
|
||||
);
|
||||
|
||||
You can get and set its fields with like named C<bar> and C<baz>
|
||||
accessors:
|
||||
|
||||
my $foo = Foo->new;
|
||||
|
||||
$foo->bar(22);
|
||||
my $value = $foo->bar;
|
||||
|
||||
$foo->baz("grimlock\0\0"); # should be 10 characters long
|
||||
my $string_value = $foo->baz; # includes the trailing \0\0
|
||||
|
||||
You can also pass initial values in to the constructor, either passing
|
||||
as a list of key value pairs or by passing a hash reference:
|
||||
|
||||
$foo = Foo->new(
|
||||
bar => 22,
|
||||
baz => "grimlock\0\0",
|
||||
);
|
||||
|
||||
# same as:
|
||||
|
||||
$foo = Foo->new( {
|
||||
bar => 22,
|
||||
baz => "grimlock\0\0",
|
||||
} );
|
||||
|
||||
If there are members of a record that you need to account for in terms
|
||||
of size and alignment, but do not want to have an accessor for, you can
|
||||
use C<:> as a place holder for its name:
|
||||
|
||||
record_layout_1(
|
||||
'int' => ':',
|
||||
'string(10)' => 'baz',
|
||||
);
|
||||
|
||||
=head3 strings
|
||||
|
||||
So far I've shown fixed length strings. These are declared with the
|
||||
word C<string> followed by the length of the string in parentheticals.
|
||||
Fixed length strings are included inside the record itself and do not
|
||||
need to be allocated or deallocated separately from the record.
|
||||
Variable length strings must be allocated on the heap, and thus require
|
||||
a sense of "ownership", that is whomever allocates variable length
|
||||
strings should be responsible for also free'ing them. To handle this,
|
||||
you can add a C<ro> or C<rw> trait to a string field. The default is
|
||||
C<ro>, means that you can get, but not set its value:
|
||||
|
||||
package Foo;
|
||||
|
||||
record_layout_1(
|
||||
'string ro' => 'bar', # same type as 'string' and 'string_ro'
|
||||
);
|
||||
|
||||
package main;
|
||||
|
||||
my $foo = Foo->new;
|
||||
|
||||
my $string = $foo->bar; # GOOD
|
||||
$foo->bar("starscream"); # BAD
|
||||
|
||||
If you specify a field is C<rw>, then you can set its value:
|
||||
|
||||
package Foo;
|
||||
|
||||
record_layout_1(
|
||||
'string rw' => 'bar', # same type as 'string_rw'
|
||||
);
|
||||
|
||||
package main;
|
||||
|
||||
my $foo = Foo->new;
|
||||
|
||||
my $string = $foo->bar; # GOOD
|
||||
$foo->bar("starscream"); # GOOD
|
||||
|
||||
Any string value that is pointed to by the record will be free'd when it
|
||||
falls out of scope, so you must be very careful that any C<string rw>
|
||||
fields are not set or modified by C code. You should also take care not
|
||||
to copy any record that has a C<rw> string in it because its values will
|
||||
be free'd twice!
|
||||
|
||||
use Clone qw( clone );
|
||||
|
||||
my $foo2 = clone $foo; # BAD bar will be free'd twice
|
||||
|
||||
=head3 arrays
|
||||
|
||||
Arrays of integer, floating points and opaque pointers are supported.
|
||||
|
||||
package Foo;
|
||||
|
||||
record_layout_1(
|
||||
'int[10]' => 'bar',
|
||||
);
|
||||
|
||||
my $foo = Foo->new;
|
||||
|
||||
$foo->bar([1,2,3,4,5,6,7,8,9,10]); # sets the values for the array
|
||||
my $list = $foo->bar; # returns a list reference
|
||||
|
||||
$foo->bar(5, -6); # sets the 5th element in the array to -6
|
||||
my $item = $foo->bar(5); gets the 5th element in the array
|
||||
|
||||
=head2 record_layout
|
||||
|
||||
record_layout($ffi, $type => $name, ... );
|
||||
record_layout(\@ffi_args, $type => $name, ... );
|
||||
record_layout($type => $name, ... );
|
||||
|
||||
This function works like C<record_layout> except that
|
||||
C<api =E<gt> 0> is used instead of C<api =E<gt> 1>.
|
||||
All new code should use C<record_layout_1> instead.
|
||||
|
||||
=head1 CAVEATS
|
||||
|
||||
These useful features (and probably more) are missing, and unlikely to be added.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Unions
|
||||
|
||||
=item Nested records
|
||||
|
||||
=back
|
||||
|
||||
If you need these features, consider using L<FFI::C> instead.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The main platypus documentation.
|
||||
|
||||
=item L<FFI::C>
|
||||
|
||||
Another interface for constructing structured data. It includes support for
|
||||
C<union> and array types (which this module does not), but lacks support for
|
||||
passing records by-value.
|
||||
|
||||
=item L<FFI::Platypus::Record::TieArray>
|
||||
|
||||
Tied array interface for record array members.
|
||||
|
||||
=item L<Convert::Binary::C>
|
||||
|
||||
Another method for constructing and dissecting structured data records.
|
||||
|
||||
=item L<pack and unpack|perlpacktut>
|
||||
|
||||
Built-in Perl functions for constructing and dissecting structured data
|
||||
records.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
136
database/perl/vendor/lib/FFI/Platypus/Record/Meta.pm
vendored
Normal file
136
database/perl/vendor/lib/FFI/Platypus/Record/Meta.pm
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package FFI::Platypus::Record::Meta;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
|
||||
# ABSTRACT: FFI support for structured records data
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
{
|
||||
require FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new(
|
||||
api => 1,
|
||||
);
|
||||
$ffi->bundle;
|
||||
$ffi->mangler(sub {
|
||||
my($name) = @_;
|
||||
$name =~ s/^/ffi_platypus_record_meta__/;
|
||||
$name;
|
||||
});
|
||||
|
||||
$ffi->type('opaque' => 'ffi_type');
|
||||
|
||||
$ffi->custom_type('meta_t' => {
|
||||
native_type => 'opaque',
|
||||
perl_to_native => sub {
|
||||
${ $_[0] };
|
||||
},
|
||||
});
|
||||
|
||||
$ffi->attach( _find_symbol => ['string'] => 'ffi_type');
|
||||
|
||||
$ffi->attach( new => ['ffi_type[]'] => 'meta_t', sub {
|
||||
my($xsub, $class, $elements) = @_;
|
||||
|
||||
if(ref($elements) ne 'ARRAY')
|
||||
{
|
||||
require Carp;
|
||||
Carp::croak("passed something other than a array ref to @{[ __PACKAGE__ ]}");
|
||||
}
|
||||
|
||||
my @element_type_pointers;
|
||||
foreach my $element_type (@$elements)
|
||||
{
|
||||
my $ptr = _find_symbol($element_type);
|
||||
if($ptr)
|
||||
{
|
||||
push @element_type_pointers, $ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
require Carp;
|
||||
Carp::croak("unknown type: $element_type");
|
||||
}
|
||||
}
|
||||
|
||||
push @element_type_pointers, undef;
|
||||
|
||||
my $ptr = $xsub->(\@element_type_pointers);
|
||||
bless \$ptr, $class;
|
||||
});
|
||||
|
||||
$ffi->attach( ffi_type => ['meta_t'] => 'ffi_type' );
|
||||
$ffi->attach( size => ['meta_t'] => 'size_t' );
|
||||
$ffi->attach( alignment => ['meta_t'] => 'ushort' );
|
||||
$ffi->attach( element_pointers => ['meta_t'] => 'ffi_type[]' );
|
||||
|
||||
$ffi->attach( DESTROY => ['meta_t'] => 'void' );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Record::Meta - FFI support for structured records data
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class is private to FFI::Platypus. See L<FFI::Platypus::Record> for
|
||||
the public interface to Platypus records.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
164
database/perl/vendor/lib/FFI/Platypus/Record/TieArray.pm
vendored
Normal file
164
database/perl/vendor/lib/FFI/Platypus/Record/TieArray.pm
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
package FFI::Platypus::Record::TieArray;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Carp qw( croak );
|
||||
|
||||
# ABSTRACT: Tied array interface for record array members
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
sub TIEARRAY
|
||||
{
|
||||
my $class = shift;
|
||||
bless [ @_ ], $class;
|
||||
}
|
||||
|
||||
sub FETCH
|
||||
{
|
||||
my($self, $key) = @_;
|
||||
my($obj, $member) = @$self;
|
||||
$obj->$member($key);
|
||||
}
|
||||
|
||||
sub STORE
|
||||
{
|
||||
my($self, $key, $value) = @_;
|
||||
my($obj, $member) = @$self;
|
||||
$obj->$member($key, $value);
|
||||
}
|
||||
|
||||
sub FETCHSIZE
|
||||
{
|
||||
my($self) = @_;
|
||||
$self->[2];
|
||||
}
|
||||
|
||||
sub CLEAR
|
||||
{
|
||||
my($self) = @_;
|
||||
my($obj, $member) = @$self;
|
||||
|
||||
$obj->$member([]);
|
||||
}
|
||||
|
||||
sub EXTEND
|
||||
{
|
||||
my($self, $count) = @_;
|
||||
croak "tried to extend a fixed length array" if $count > $self->[2];
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Record::TieArray - Tied array interface for record array members
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
|
||||
use FFI::Platypus::Record;
|
||||
use FFI::Platypus::Record::TieArray;
|
||||
|
||||
record_layout(qw(
|
||||
int[20] _bar
|
||||
));
|
||||
|
||||
sub bar
|
||||
{
|
||||
my($self, $arg) = @_;
|
||||
$self->_bar($arg) if ref($arg) eq ' ARRAY';
|
||||
tie my @list, 'FFI::Platypus::Record::TieArray',
|
||||
$self, '_bar', 20;
|
||||
}
|
||||
|
||||
package main;
|
||||
|
||||
my $foo = Foo->new;
|
||||
|
||||
my $bar5 = $foo->bar->[5]; # get the 5th element of the bar array
|
||||
$foo->bar->[5] = 10; # set the 5th element of the bar array
|
||||
@{ $foo->bar } = (); # set all elements in bar to 0
|
||||
@{ $foo->bar } = (1..5); # set the first five elements of the bar array
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<WARNING>: This module is considered EXPERIMENTAL. It may go away or
|
||||
be changed in incompatible ways, possibly without notice, but not
|
||||
without a good reason.
|
||||
|
||||
This class provides a tie interface for record array members.
|
||||
|
||||
In the future a short cut for using this with L<FFI::Platypus::Record>
|
||||
directly may be provided.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The main Platypus documentation.
|
||||
|
||||
=item L<FFI::Platypus::Record>
|
||||
|
||||
Documentation on Platypus records.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
112
database/perl/vendor/lib/FFI/Platypus/ShareConfig.pm
vendored
Normal file
112
database/perl/vendor/lib/FFI/Platypus/ShareConfig.pm
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package FFI::Platypus::ShareConfig;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use File::Spec;
|
||||
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
sub dist_dir ($)
|
||||
{
|
||||
my($dist_name) = @_;
|
||||
|
||||
my @pm = split /-/, $dist_name;
|
||||
$pm[-1] .= ".pm";
|
||||
|
||||
foreach my $inc (@INC)
|
||||
{
|
||||
if(-f File::Spec->catfile($inc, @pm))
|
||||
{
|
||||
my $share = File::Spec->catdir($inc, qw( auto share dist ), $dist_name );
|
||||
if(-d $share)
|
||||
{
|
||||
return File::Spec->rel2abs($share);
|
||||
}
|
||||
last;
|
||||
}
|
||||
}
|
||||
Carp::croak("unable to find dist share directory for $dist_name");
|
||||
}
|
||||
|
||||
sub get
|
||||
{
|
||||
my(undef, $name) = @_;
|
||||
my $config;
|
||||
|
||||
unless($config)
|
||||
{
|
||||
my $fn = File::Spec->catfile(dist_dir('FFI-Platypus'), 'config.pl');
|
||||
$fn = File::Spec->rel2abs($fn) unless File::Spec->file_name_is_absolute($fn);
|
||||
local $@;
|
||||
unless($config = do $fn)
|
||||
{
|
||||
die "couldn't parse configuration $fn $@" if $@;
|
||||
die "couldn't do $fn $!" if $!;
|
||||
die "bad or missing config file $fn";
|
||||
};
|
||||
}
|
||||
|
||||
defined $name ? $config->{$name} : $config;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::ShareConfig
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
1384
database/perl/vendor/lib/FFI/Platypus/Type.pm
vendored
Normal file
1384
database/perl/vendor/lib/FFI/Platypus/Type.pm
vendored
Normal file
File diff suppressed because it is too large
Load Diff
152
database/perl/vendor/lib/FFI/Platypus/Type/PointerSizeBuffer.pm
vendored
Normal file
152
database/perl/vendor/lib/FFI/Platypus/Type/PointerSizeBuffer.pm
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
package FFI::Platypus::Type::PointerSizeBuffer;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use FFI::Platypus::API qw(
|
||||
arguments_set_pointer
|
||||
arguments_set_uint32
|
||||
arguments_set_uint64
|
||||
);
|
||||
use FFI::Platypus::Buffer qw( scalar_to_buffer );
|
||||
use FFI::Platypus::Buffer qw( buffer_to_scalar );
|
||||
|
||||
# ABSTRACT: Convert string scalar to a buffer as a pointer / size_t combination
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
my @stack;
|
||||
|
||||
*arguments_set_size_t
|
||||
= FFI::Platypus->new( api => 1 )->sizeof('size_t') == 4
|
||||
? \&arguments_set_uint32
|
||||
: \&arguments_set_uint64;
|
||||
|
||||
sub perl_to_native
|
||||
{
|
||||
my($pointer, $size) = scalar_to_buffer($_[0]);
|
||||
push @stack, [ $pointer, $size ];
|
||||
arguments_set_pointer $_[1], $pointer;
|
||||
arguments_set_size_t($_[1]+1, $size);
|
||||
}
|
||||
|
||||
sub perl_to_native_post
|
||||
{
|
||||
my($pointer, $size) = @{ pop @stack };
|
||||
$_[0] = buffer_to_scalar($pointer, $size);
|
||||
}
|
||||
|
||||
sub ffi_custom_type_api_1
|
||||
{
|
||||
{
|
||||
native_type => 'opaque',
|
||||
perl_to_native => \&perl_to_native,
|
||||
perl_to_native_post => \&perl_to_native_post,
|
||||
argument_count => 2,
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Type::PointerSizeBuffer - Convert string scalar to a buffer as a pointer / size_t combination
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
In your C code:
|
||||
|
||||
void
|
||||
function_with_buffer(void *pointer, size_t size)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
In your Platypus::FFI code:
|
||||
|
||||
use FFI::Platypus;
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->load_custom_type('::PointerSizeBuffer' => 'buffer');
|
||||
|
||||
$ffi->attach(function_with_buffer => ['buffer'] => 'void');
|
||||
my $string = "content of buffer";
|
||||
function_with_buffer($string);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
A common pattern in C code is to pass in a region of memory as a buffer,
|
||||
consisting of a pointer and a size of the memory region. In Perl,
|
||||
string scalars also point to a contiguous series of bytes that has a
|
||||
size, so when interfacing with C libraries it is handy to be able to
|
||||
pass in a string scalar as a pointer / size buffer pair.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
Main Platypus documentation.
|
||||
|
||||
=item L<FFI::Platypus::Type>
|
||||
|
||||
Platypus types documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
262
database/perl/vendor/lib/FFI/Platypus/Type/StringArray.pm
vendored
Normal file
262
database/perl/vendor/lib/FFI/Platypus/Type/StringArray.pm
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
package FFI::Platypus::Type::StringArray;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
|
||||
# ABSTRACT: Platypus custom type for arrays of strings
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
use constant _incantation =>
|
||||
$^O eq 'MSWin32' && do { require Config; $Config::Config{archname} =~ /MSWin32-x64/ }
|
||||
? 'Q'
|
||||
: 'L!';
|
||||
use constant _size_of_pointer => FFI::Platypus->new( api => 1 )->sizeof('opaque');
|
||||
use constant _pointer_buffer => "P" . _size_of_pointer;
|
||||
|
||||
my @stack;
|
||||
|
||||
sub perl_to_native
|
||||
{
|
||||
# this is the variable length version
|
||||
# and is actually simpler than the
|
||||
# fixed length version
|
||||
my $count = scalar @{ $_[0] };
|
||||
my $pointers = pack(('P' x $count)._incantation, @{ $_[0] }, 0);
|
||||
my $array_pointer = unpack _incantation, pack 'P', $pointers;
|
||||
push @stack, [ \$_[0], \$pointers ];
|
||||
$array_pointer;
|
||||
}
|
||||
|
||||
sub perl_to_native_post
|
||||
{
|
||||
pop @stack;
|
||||
();
|
||||
}
|
||||
|
||||
sub native_to_perl
|
||||
{
|
||||
return unless defined $_[0];
|
||||
my @list;
|
||||
my $i=0;
|
||||
while(1)
|
||||
{
|
||||
my $pointer_pointer = unpack(
|
||||
_incantation,
|
||||
unpack(
|
||||
_pointer_buffer,
|
||||
pack(
|
||||
_incantation, $_[0]+_size_of_pointer*$i
|
||||
)
|
||||
)
|
||||
);
|
||||
last unless $pointer_pointer;
|
||||
push @list, unpack('p', pack(_incantation, $pointer_pointer));
|
||||
$i++;
|
||||
}
|
||||
\@list;
|
||||
}
|
||||
|
||||
sub ffi_custom_type_api_1
|
||||
{
|
||||
# arg0 = class
|
||||
# arg1 = FFI::Platypus instance
|
||||
# arg2 = array size
|
||||
# arg3 = default value
|
||||
my(undef, undef, $count, $default) = @_;
|
||||
|
||||
my $config = {
|
||||
native_type => 'opaque',
|
||||
perl_to_native => \&perl_to_native,
|
||||
perl_to_native_post => \&perl_to_native_post,
|
||||
native_to_perl => \&native_to_perl,
|
||||
};
|
||||
|
||||
if(defined $count)
|
||||
{
|
||||
my $end = $count-1;
|
||||
|
||||
$config->{perl_to_native} = sub {
|
||||
my $incantation = '';
|
||||
|
||||
my @list = ((map {
|
||||
defined $_
|
||||
? do { $incantation .= 'P'; $_ }
|
||||
: defined $default
|
||||
? do { $incantation .= 'P'; $default }
|
||||
: do { $incantation .= _incantation; 0 };
|
||||
} @{ $_[0] }[0..$end]), 0);
|
||||
|
||||
$incantation .= _incantation;
|
||||
|
||||
my $pointers = pack $incantation, @list;
|
||||
my $array_pointer = unpack _incantation, pack 'P', $pointers;
|
||||
push @stack, [ \@list, $pointers ];
|
||||
$array_pointer;
|
||||
};
|
||||
|
||||
my $pointer_buffer = "P@{[ FFI::Platypus->new( api => 1 )->sizeof('opaque') * $count ]}";
|
||||
my $incantation_count = _incantation.$count;
|
||||
|
||||
$config->{native_to_perl} = sub {
|
||||
return unless defined $_[0];
|
||||
my @pointer_pointer = unpack($incantation_count, unpack($pointer_buffer, pack(_incantation, $_[0])));
|
||||
[map { $_ ? unpack('p', pack(_incantation, $_)) : $default } @pointer_pointer];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
$config;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Type::StringArray - Platypus custom type for arrays of strings
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
In your C code:
|
||||
|
||||
void
|
||||
takes_string_array(const char **array)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
void
|
||||
takes_fixed_string_array(const char *array[5])
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
In your L<Platypus::FFI> code:
|
||||
|
||||
use FFI::Platypus;
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->load_custom_type('::StringArray' => 'string_array');
|
||||
$ffi->load_custom_type('::StringArray' => 'string_5' => 5);
|
||||
|
||||
$ffi->attach(takes_string_array => ['string_array'] => 'void');
|
||||
$ffi->attach(takes_fixed_string_array => ['string_5'] => 'void');
|
||||
|
||||
my @list = qw( foo bar baz );
|
||||
|
||||
takes_string_array(\@list);
|
||||
takes_fixed_string_array([qw( s1 s2 s3 s4 s5 )]);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<NOTE>: The primary motivation for this custom type was originally to
|
||||
fill the void left by the fact that L<FFI::Platypus> did not support arrays
|
||||
of strings by itself. Since 0.62 this support has been added, and that is
|
||||
probably what you want to use, but the semantics and feature set are
|
||||
slightly different, so there are cases where you might want to use this
|
||||
custom type.
|
||||
|
||||
This module provides a L<FFI::Platypus> custom type for arrays of
|
||||
strings. The array is always NULL terminated. Return types are supported!
|
||||
|
||||
This custom type takes two optional arguments. The first is the size of
|
||||
arrays and the second is a default value to fill in any values that
|
||||
aren't provided when the function is called. If not default is provided
|
||||
then C<NULL> will be passed in for those values.
|
||||
|
||||
=head1 SUPPORT
|
||||
|
||||
If something does not work the way you think it should, or if you have a
|
||||
feature request, please open an issue on this project's GitHub Issue
|
||||
tracker:
|
||||
|
||||
L<https://github.com/plicease/FFI-Platypus-Type-StringArray/issues>
|
||||
|
||||
=head1 CONTRIBUTING
|
||||
|
||||
If you have implemented a new feature or fixed a bug then you may make a
|
||||
pull request on this project's GitHub repository:
|
||||
|
||||
L<https://github.com/plicease/FFI-Platypus-Type-StringArray/pulls>
|
||||
|
||||
This project's GitHub issue tracker listed above is not Write-Only. If
|
||||
you want to contribute then feel free to browse through the existing
|
||||
issues and see if there is something you feel you might be good at and
|
||||
take a whack at the problem. I frequently open issues myself that I
|
||||
hope will be accomplished by someone in the future but do not have time
|
||||
to immediately implement myself.
|
||||
|
||||
Another good area to help out in is documentation. I try to make sure
|
||||
that there is good document coverage, that is there should be
|
||||
documentation describing all the public features and warnings about
|
||||
common pitfalls, but an outsider's or alternate view point on such
|
||||
things would be welcome; if you see something confusing or lacks
|
||||
sufficient detail I encourage documentation only pull requests to
|
||||
improve things.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
=item L<FFI::Platypus::Type::StringPointer>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
180
database/perl/vendor/lib/FFI/Platypus/Type/StringPointer.pm
vendored
Normal file
180
database/perl/vendor/lib/FFI/Platypus/Type/StringPointer.pm
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
package FFI::Platypus::Type::StringPointer;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use FFI::Platypus;
|
||||
use Scalar::Util qw( readonly );
|
||||
|
||||
# ABSTRACT: Convert a pointer to a string and back
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
use constant _incantation =>
|
||||
$^O eq 'MSWin32' && do { require Config; $Config::Config{archname} =~ /MSWin32-x64/ }
|
||||
? 'Q'
|
||||
: 'L!';
|
||||
use constant _pointer_buffer => "P" . FFI::Platypus->new( api => 1 )->sizeof('opaque');
|
||||
|
||||
my @stack;
|
||||
|
||||
sub perl_to_native
|
||||
{
|
||||
if(defined $_[0])
|
||||
{
|
||||
my $packed = pack 'P', ${$_[0]};
|
||||
my $pointer_pointer = pack 'P', $packed;
|
||||
my $unpacked = unpack _incantation, $pointer_pointer;
|
||||
push @stack, [ \$packed, \$pointer_pointer ];
|
||||
return $unpacked;
|
||||
}
|
||||
else
|
||||
{
|
||||
push @stack, [];
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub perl_to_native_post
|
||||
{
|
||||
my($packed) = @{ pop @stack };
|
||||
return unless defined $packed;
|
||||
unless(readonly(${$_[0]}))
|
||||
{
|
||||
${$_[0]} = unpack 'p', $$packed;
|
||||
}
|
||||
}
|
||||
|
||||
sub native_to_perl
|
||||
{
|
||||
return unless defined $_[0];
|
||||
my $pointer_pointer = unpack(_incantation, unpack(_pointer_buffer, pack(_incantation, $_[0])));
|
||||
$pointer_pointer ? \unpack('p', pack(_incantation, $pointer_pointer)) : \undef;
|
||||
}
|
||||
|
||||
sub ffi_custom_type_api_1
|
||||
{
|
||||
return {
|
||||
native_type => 'opaque',
|
||||
perl_to_native => \&perl_to_native,
|
||||
perl_to_native_post => \&perl_to_native_post,
|
||||
native_to_perl => \&native_to_perl,
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::Type::StringPointer - Convert a pointer to a string and back
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
In your C code:
|
||||
|
||||
void
|
||||
string_pointer_argument(const char **string)
|
||||
{
|
||||
...
|
||||
}
|
||||
const char **
|
||||
string_pointer_return(void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
In your Platypus::FFI code:
|
||||
|
||||
use FFI::Platypus;
|
||||
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->load_custom_type('::StringPointer' => 'string_pointer');
|
||||
|
||||
$ffi->attach(string_pointer_argument => ['string_pointer'] => 'void');
|
||||
$ffi->attach(string_pointer_return => [] => 'string_pointer');
|
||||
|
||||
my $string = "foo";
|
||||
|
||||
string_pointer_argument(\$string); # $string may be modified
|
||||
|
||||
$ref = string_pointer_return();
|
||||
|
||||
print $$ref; # print the string pointed to by $ref
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<NOTE>: As of version 0.61, this custom type is now deprecated since
|
||||
pointers to strings are supported in the L<FFI::Platypus> directly
|
||||
without custom types.
|
||||
|
||||
This module provides a L<FFI::Platypus> custom type for pointers to
|
||||
strings.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
Main Platypus documentation.
|
||||
|
||||
=item L<FFI::Platypus::Type>
|
||||
|
||||
Platypus types documentation.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
165
database/perl/vendor/lib/FFI/Platypus/TypeParser.pm
vendored
Normal file
165
database/perl/vendor/lib/FFI/Platypus/TypeParser.pm
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
package FFI::Platypus::TypeParser;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use List::Util 1.45 qw( uniqstr );
|
||||
use Carp qw( croak );
|
||||
|
||||
# ABSTRACT: FFI Type Parser
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
# The TypeParser and Type classes are used internally ONLY and
|
||||
# are not to be exposed to the user. External users should
|
||||
# not under any circumstances rely on the implementation of
|
||||
# these classes.
|
||||
|
||||
sub new
|
||||
{
|
||||
my($class) = @_;
|
||||
my $self = bless { types => {}, type_map => {} }, $class;
|
||||
$self->build;
|
||||
$self;
|
||||
}
|
||||
|
||||
sub build {}
|
||||
|
||||
our %basic_type;
|
||||
|
||||
# this just checks if the underlying libffi/platypus implementation
|
||||
# has the basic type. It is used mainly to verify that exotic types
|
||||
# like longdouble and complex_float are available before the test
|
||||
# suite tries to use them.
|
||||
sub have_type
|
||||
{
|
||||
my(undef, $name) = @_;
|
||||
!!$basic_type{$name};
|
||||
}
|
||||
|
||||
sub create_type_custom
|
||||
{
|
||||
my($self, $name, @rest) = @_;
|
||||
$name = 'opaque' unless defined $name;
|
||||
my $type = $self->parse($name);
|
||||
unless($type->is_customizable)
|
||||
{
|
||||
croak "$name is not a legal basis for a custom type"
|
||||
}
|
||||
$self->_create_type_custom($type, @rest);
|
||||
}
|
||||
|
||||
# this is the type map provided by the language plugin, if any
|
||||
# in addition to the basic types (which map to themselves).
|
||||
sub type_map
|
||||
{
|
||||
my($self, $new) = @_;
|
||||
|
||||
if(defined $new)
|
||||
{
|
||||
$self->{type_map} = $new;
|
||||
}
|
||||
|
||||
$self->{type_map};
|
||||
}
|
||||
|
||||
# this stores the types that have been mentioned so far. It also
|
||||
# usually includes aliases.
|
||||
sub types
|
||||
{
|
||||
shift->{types};
|
||||
}
|
||||
|
||||
{
|
||||
my %store;
|
||||
|
||||
foreach my $name (keys %basic_type)
|
||||
{
|
||||
my $type_code = $basic_type{$name};
|
||||
$store{basic}->{$name} = __PACKAGE__->create_type_basic($type_code);
|
||||
$store{ptr}->{$name} = __PACKAGE__->create_type_pointer($type_code);
|
||||
$store{rev}->{$type_code} = $name;
|
||||
}
|
||||
|
||||
sub global_types
|
||||
{
|
||||
\%store;
|
||||
}
|
||||
}
|
||||
|
||||
# list all the types that this type parser knows about, including
|
||||
# those provided by the language plugin (if any), those defined
|
||||
# by the user, and the basic types that everyone gets.
|
||||
sub list_types
|
||||
{
|
||||
my($self) = @_;
|
||||
uniqstr( ( keys %{ $self->type_map } ), ( keys %{ $self->types } ) );
|
||||
}
|
||||
|
||||
our @CARP_NOT = qw( FFI::Platypus );
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::TypeParser - FFI Type Parser
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This class is private to FFI::Platypus. See L<FFI::Platypus> for
|
||||
the public interface to Platypus types.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
275
database/perl/vendor/lib/FFI/Platypus/TypeParser/Version0.pm
vendored
Normal file
275
database/perl/vendor/lib/FFI/Platypus/TypeParser/Version0.pm
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
package FFI::Platypus::TypeParser::Version0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Carp qw( croak );
|
||||
use base qw( FFI::Platypus::TypeParser );
|
||||
|
||||
# ABSTRACT: FFI Type Parser Version Zero
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
our @CARP_NOT = qw( FFI::Platypus FFI::Platypus::TypeParser );
|
||||
|
||||
# The type parser is responsible for deciding if something is a legal
|
||||
# alias name. Since this needs to be checked before the type is parsed
|
||||
# it is separate from set_alias below.
|
||||
sub check_alias
|
||||
{
|
||||
my($self, $alias) = @_;
|
||||
croak "spaces not allowed in alias" if $alias =~ /\s/;
|
||||
croak "allowed characters for alias: [A-Za-z0-9_]" if $alias !~ /^[A-Za-z0-9_]+$/;
|
||||
croak "alias \"$alias\" conflicts with existing type"
|
||||
if defined $self->type_map->{$alias}
|
||||
|| $self->types->{$alias};
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub set_alias
|
||||
{
|
||||
my($self, $alias, $type) = @_;
|
||||
$self->types->{$alias} = $type;
|
||||
}
|
||||
|
||||
# This method takes a string representation of the a type and
|
||||
# returns the internal platypus type representation.
|
||||
sub parse
|
||||
{
|
||||
my($self, $name) = @_;
|
||||
|
||||
return $self->types->{$name} if defined $self->types->{$name};
|
||||
|
||||
# Darmock and Legacy Code at Tanagra
|
||||
unless($name =~ /-\>/ || $name =~ /^record\s*\([0-9A-Z:a-z_]+\)$/
|
||||
|| $name =~ /^string(_rw|_ro|\s+rw|\s+ro|\s*\([0-9]+\))$/)
|
||||
{
|
||||
my $basic = $name;
|
||||
my $extra = '';
|
||||
if($basic =~ s/\s*((\*|\[|\<).*)$//)
|
||||
{
|
||||
$extra = " $1";
|
||||
}
|
||||
if(defined $self->type_map->{$basic})
|
||||
{
|
||||
my $new_name = $self->type_map->{$basic} . $extra;
|
||||
if($new_name ne $name)
|
||||
{
|
||||
# hopefully no recursion here.
|
||||
return $self->types->{$name} = $self->parse($new_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($name =~ m/^ \( (.*) \) \s* -\> \s* (.*) \s* $/x)
|
||||
{
|
||||
my @argument_types = map { $self->parse($_) } map { my $t = $_; $t =~ s/^\s+//; $t =~ s/\s+$//; $t } split /,/, $1;
|
||||
my $return_type = $self->parse($2);
|
||||
return $self->types->{$name} = $self->create_type_closure($return_type, @argument_types);
|
||||
}
|
||||
|
||||
if($name =~ /^ string \s* \( ([0-9]+) \) $/x)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
0,
|
||||
$1, # size
|
||||
);
|
||||
}
|
||||
|
||||
if($name =~ /^ string ( _rw | _ro | \s+ro | \s+rw | ) $/x)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_string(
|
||||
defined $1 && $1 =~ /rw/ ? 1 : 0, # rw
|
||||
);
|
||||
}
|
||||
|
||||
if($name =~ /^ record \s* \( ([0-9]+) \) $/x)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
0,
|
||||
$1, # size
|
||||
);
|
||||
}
|
||||
|
||||
if($name =~ /^ record \s* \( ([0-9:A-Za-z_]+) \) $/x)
|
||||
{
|
||||
my $size;
|
||||
my $classname = $1;
|
||||
unless($classname->can('ffi_record_size') || $classname->can('_ffi_record_size'))
|
||||
{
|
||||
my $pm = "$classname.pm";
|
||||
$pm =~ s/\//::/g;
|
||||
require $pm;
|
||||
}
|
||||
if($classname->can('ffi_record_size'))
|
||||
{
|
||||
$size = $classname->ffi_record_size;
|
||||
}
|
||||
elsif($classname->can('_ffi_record_size'))
|
||||
{
|
||||
$size = $classname->_ffi_record_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "$classname has not ffi_record_size or _ffi_record_size method";
|
||||
}
|
||||
return $self->global_types->{record}->{$classname} ||= $self->create_type_record(
|
||||
0,
|
||||
$size, # size
|
||||
$classname, # record_class
|
||||
);
|
||||
}
|
||||
|
||||
# array types
|
||||
if($name =~ /^([\S]+)\s+ \[ ([0-9]*) \] $/x)
|
||||
{
|
||||
my $size = $2 || '';
|
||||
my $basic = $self->global_types->{basic}->{$1} || croak("unknown ffi/platypus type $name [$size]");
|
||||
if($size)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_array(
|
||||
$basic->type_code,
|
||||
$size,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->global_types->{array}->{$name} ||= $self->create_type_array(
|
||||
$basic->type_code,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# pointer types
|
||||
if($name =~ s/\s+\*$//)
|
||||
{
|
||||
return $self->global_types->{ptr}->{$name} || croak("unknown ffi/platypus type $name *");
|
||||
}
|
||||
|
||||
# basic types
|
||||
return $self->global_types->{basic}->{$name} || croak("unknown ffi/platypus type $name");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::TypeParser::Version0 - FFI Type Parser Version Zero
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 0 );
|
||||
$ffi->type('record(Foo::Bar)' => 'foo_bar_t');
|
||||
$ffi->type('opaque' => 'baz_t');
|
||||
$ffi->type('opaque*' => 'baz_ptr');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This documents the original L<FFI::Platypus> type parser. It was the default and only
|
||||
type parser used by L<FFI::Platypus> starting with version C<0.02>. Starting with
|
||||
version C<1.00> L<FFI::Platypus> comes with a new type parser with design fixes that
|
||||
are not backward compatibility.
|
||||
|
||||
=head2 Interface differences
|
||||
|
||||
=over
|
||||
|
||||
=item Pass-by-value records are not allowed
|
||||
|
||||
Originally L<FFI::Platypus> only supported passing records as a pointer. The type
|
||||
C<record(Foo::Bar)> actually passes a pointer to the record. In the version 1.00 parser
|
||||
allows C<record(Foo::Bar)> which is pass-by-value (the contents of the record is copied
|
||||
onto the stack) and C<record(Foo::Bar)*> which is pass-by-reference or pointer (a pointer
|
||||
to the record is passed to the callee so that it can make modifications to the record).
|
||||
|
||||
TL;DR C<record(Foo::Bar)> in version 0 is equivalent to C<record(Foo::Bar)*> in the
|
||||
version 1 API. There is no equivalent to C<record(Foo::Bar)*> in the version 0 API.
|
||||
|
||||
=item decorate aliases of basic types
|
||||
|
||||
This is not allowed in the version 0 API:
|
||||
|
||||
$ffi->type('opaque' => 'foo_t'); # ok!
|
||||
$ffi->type('foo_t*' => 'foo_ptr'); # not ok! in version 0, ok! in version 1
|
||||
|
||||
Instead you need to use the basic type in the second type definition:
|
||||
|
||||
$ffi->type('opaque' => 'foo_t'); # ok!
|
||||
$ffi->type('opaque*' => 'foo_ptr'); # ok!
|
||||
|
||||
=item object types are not allowed
|
||||
|
||||
$ffi->type('object(Foo::Bar)'); # not ok! in version 0, ok! in version 1
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The core L<FFI::Platypus> documentation.
|
||||
|
||||
=item L<FFI::Platypus::TypeParser::Version1>
|
||||
|
||||
The API C<1.00> type parser.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
371
database/perl/vendor/lib/FFI/Platypus/TypeParser/Version1.pm
vendored
Normal file
371
database/perl/vendor/lib/FFI/Platypus/TypeParser/Version1.pm
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
package FFI::Platypus::TypeParser::Version1;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.008004;
|
||||
use Carp qw( croak );
|
||||
use base qw( FFI::Platypus::TypeParser );
|
||||
|
||||
# ABSTRACT: FFI Type Parser Version One
|
||||
our $VERSION = '1.34'; # VERSION
|
||||
|
||||
|
||||
our @CARP_NOT = qw( FFI::Platypus FFI::Platypus::TypeParser );
|
||||
|
||||
my %reserved = map { $_ => 1 } qw(
|
||||
string
|
||||
object
|
||||
type
|
||||
role
|
||||
union
|
||||
class
|
||||
struct
|
||||
record
|
||||
array
|
||||
senum
|
||||
enum
|
||||
);
|
||||
|
||||
# The type parser is responsible for deciding if something is a legal
|
||||
# alias name. Since this needs to be checked before the type is parsed
|
||||
# it is separate from set_alias below.
|
||||
sub check_alias
|
||||
{
|
||||
my($self, $alias) = @_;
|
||||
croak "spaces not allowed in alias" if $alias =~ /\s/;
|
||||
croak "allowed characters for alias: [A-Za-z0-9_]" if $alias !~ /^[A-Za-z0-9_]+$/;
|
||||
croak "reserved world \"$alias\" cannot be used as an alias"
|
||||
if $reserved{$alias};
|
||||
croak "alias \"$alias\" conflicts with existing type"
|
||||
if defined $self->type_map->{$alias}
|
||||
|| $self->types->{$alias}
|
||||
|| $self->global_types->{basic}->{$alias};
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub set_alias
|
||||
{
|
||||
my($self, $alias, $type) = @_;
|
||||
$self->types->{$alias} = $type;
|
||||
}
|
||||
|
||||
use constant type_regex =>
|
||||
|
||||
qr/^ #
|
||||
#
|
||||
\s* # prefix white space
|
||||
#
|
||||
(?: #
|
||||
#
|
||||
\( ([^)]*) \) -> (.*) # closure $1 argument types, $2 return type
|
||||
| #
|
||||
(?: string | record ) \s* \( \s* ([0-9]+) \s* \) (?: \s* (\*) | ) # fixed record, fixed string $3, ponter $4
|
||||
| #
|
||||
record \s* \( ( \s* (?: [A-Za-z_] [A-Za-z_0-9]* :: )* [A-Za-z_] [A-Za-z_0-9]* ) \s* \) (?: \s* (\*) | ) # record class $5, pointer $6
|
||||
| #
|
||||
( (?: [A-Za-z_] [A-Za-z_0-9]* \s+ )* [A-Za-z_] [A-Za-z_0-9]* ) \s* # unit type name $7
|
||||
#
|
||||
(?: (\*) | \[ ([0-9]*) \] | ) # pointer $8, array $9
|
||||
| #
|
||||
object \s* \( \s* ( (?: [A-Za-z_] [A-Za-z_0-9]* :: )* [A-Za-z_] [A-Za-z_0-9]* ) # object class $10
|
||||
(?: \s*,\s* ( (?: [A-Za-z_] [A-Za-z_0-9]* \s+ )* [A-Za-z_] [A-Za-z_0-9]* ) )? # type $11
|
||||
\s* \) #
|
||||
) #
|
||||
#
|
||||
\s* # trailing white space
|
||||
#
|
||||
$/x; #
|
||||
|
||||
sub parse
|
||||
{
|
||||
my($self, $name, $opt) = @_;
|
||||
|
||||
$opt ||= {};
|
||||
|
||||
return $self->types->{$name} if $self->types->{$name};
|
||||
|
||||
$name =~ type_regex or croak "bad type name: $name";
|
||||
|
||||
if(defined (my $at = $1)) # closure
|
||||
{
|
||||
my $rt = $2;
|
||||
return $self->types->{$name} = $self->create_type_closure(
|
||||
$self->parse($rt, $opt),
|
||||
map { $self->parse($_, $opt) } map { my $t = $_; $t =~ s/^\s+//; $t =~ s/\s+$//; $t } split /,/, $at,
|
||||
);
|
||||
}
|
||||
|
||||
if(defined (my $size = $3)) # fixed record / fixed string
|
||||
{
|
||||
croak "fixed record / fixed string size must be larger than 0"
|
||||
unless $size > 0;
|
||||
|
||||
if(my $pointer = $4)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
0,
|
||||
$size,
|
||||
);
|
||||
}
|
||||
elsif($opt->{member})
|
||||
{
|
||||
return $self->types->{"$name *"} = $self->create_type_record(
|
||||
0,
|
||||
$size,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "fixed string / classless record not allowed as value type";
|
||||
}
|
||||
}
|
||||
|
||||
if(defined (my $class = $5)) # class record
|
||||
{
|
||||
my $size_method = $class->can('ffi_record_size') || $class->can('_ffi_record_size') || croak "$class has no ffi_record_size or _ffi_record_size method";
|
||||
if(my $pointer = $6)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
0,
|
||||
$class->$size_method,
|
||||
$class,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
1,
|
||||
$class->$size_method,
|
||||
$class,
|
||||
$class->_ffi_meta->ffi_type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(defined (my $unit_name = $7)) # basic type
|
||||
{
|
||||
if($self->global_types->{basic}->{$unit_name})
|
||||
{
|
||||
if(my $pointer = $8)
|
||||
{
|
||||
croak "void pointer not allowed" if $unit_name eq 'void';
|
||||
return $self->types->{$name} = $self->global_types->{ptr}->{$unit_name};
|
||||
}
|
||||
|
||||
if(defined (my $size = $9)) # array
|
||||
{
|
||||
croak "void array not allowed" if $unit_name eq 'void';
|
||||
if($size ne '')
|
||||
{
|
||||
croak "array size must be larger than 0" if $size < 1;
|
||||
return $self->types->{$name} = $self->create_type_array(
|
||||
$self->global_types->{basic}->{$unit_name}->type_code,
|
||||
$size,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->global_types->{array}->{$unit_name} ||= $self->create_type_array(
|
||||
$self->global_types->{basic}->{$unit_name}->type_code,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# basic type with no decorations
|
||||
return $self->global_types->{basic}->{$unit_name};
|
||||
}
|
||||
|
||||
if(my $map_name = $self->type_map->{$unit_name})
|
||||
{
|
||||
if(my $pointer = $8)
|
||||
{
|
||||
return $self->types->{$name} = $self->parse("$map_name *", $opt);
|
||||
}
|
||||
if(defined (my $size = $9))
|
||||
{
|
||||
if($size ne '')
|
||||
{
|
||||
croak "array size must be larger than 0" if $size < 1;
|
||||
return $self->types->{$name} = $self->parse("$map_name [$size]", $opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->types->{$name} = $self->parse("$map_name []", $opt);
|
||||
}
|
||||
}
|
||||
|
||||
return $self->types->{$name} = $self->parse("$map_name", $opt);
|
||||
}
|
||||
|
||||
if(my $pointer = $8)
|
||||
{
|
||||
my $unit_type = $self->parse($unit_name, $opt);
|
||||
|
||||
if($unit_type->is_record_value)
|
||||
{
|
||||
my $meta = $unit_type->meta;
|
||||
return $self->types->{$name} = $self->create_type_record(
|
||||
0,
|
||||
$meta->{size},
|
||||
$meta->{class},
|
||||
);
|
||||
}
|
||||
|
||||
my $basic_name = $self->global_types->{rev}->{$unit_type->type_code};
|
||||
if($basic_name)
|
||||
{
|
||||
return $self->types->{$name} = $self->parse("$basic_name *", $opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "cannot make a pointer to $unit_name";
|
||||
}
|
||||
}
|
||||
|
||||
if(defined (my $size = $9))
|
||||
{
|
||||
my $unit_type = $self->parse($unit_name, $opt);
|
||||
my $basic_name = $self->global_types->{rev}->{$unit_type->type_code};
|
||||
if($basic_name)
|
||||
{
|
||||
if($size ne '')
|
||||
{
|
||||
croak "array size must be larger than 0" if $size < 1;
|
||||
return $self->types->{$name} = $self->parse("$basic_name [$size]", $opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->types->{$name} = $self->parse("$basic_name []", $opt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "cannot make an array of $unit_name";
|
||||
}
|
||||
}
|
||||
|
||||
if($name eq 'string ro')
|
||||
{
|
||||
return $self->global_types->{basic}->{string};
|
||||
}
|
||||
elsif($name eq 'string rw')
|
||||
{
|
||||
return $self->global_types->{v2}->{string_rw} ||= $self->create_type_string(1);
|
||||
}
|
||||
|
||||
return $self->types->{$name} || croak "unknown type: $unit_name";
|
||||
}
|
||||
|
||||
if(defined (my $class = $10)) # object type
|
||||
{
|
||||
my $basic_name = $11 || 'opaque';
|
||||
my $basic_type = $self->parse($basic_name);
|
||||
if($basic_type->is_object_ok)
|
||||
{
|
||||
return $self->types->{$name} = $self->create_type_object(
|
||||
$basic_type->type_code,
|
||||
$class,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "cannot make an object of $basic_name";
|
||||
}
|
||||
}
|
||||
|
||||
croak "internal error parsing: $name";
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
FFI::Platypus::TypeParser::Version1 - FFI Type Parser Version One
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.34
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use FFI::Platypus;
|
||||
my $ffi = FFI::Platypus->new( api => 1 );
|
||||
$ffi->type('record(Foo::Bar)' => 'foo_bar_t');
|
||||
$ffi->type('record(Foo::Bar)*' => 'foo_bar_ptr');
|
||||
$ffi->type('opaque' => 'baz_t');
|
||||
$ffi->type('bar_t*' => 'baz_ptr');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This documents the second (version 1) type parser for L<FFI::Platypus>.
|
||||
This type parser was included with L<FFI::Platypus> starting with version
|
||||
C<0.91> in an experimental capability, and C<1.00> as a stable interface.
|
||||
Starting with version C<1.00> the main L<FFI::Platypus> documentation
|
||||
describes the version 1 API and you can refer to
|
||||
L<FFI::Platypus::TypeParser::Version0> for details on the version0 API.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<FFI::Platypus>
|
||||
|
||||
The core L<FFI::Platypus> documentation.
|
||||
|
||||
=item L<FFI::Platypus::TypeParser::Version0>
|
||||
|
||||
The API C<0.02> type parser.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Bakkiaraj Murugesan (bakkiaraj)
|
||||
|
||||
Dylan Cali (calid)
|
||||
|
||||
pipcet
|
||||
|
||||
Zaki Mughal (zmughal)
|
||||
|
||||
Fitz Elliott (felliott)
|
||||
|
||||
Vickenty Fesunov (vyf)
|
||||
|
||||
Gregor Herrmann (gregoa)
|
||||
|
||||
Shlomi Fish (shlomif)
|
||||
|
||||
Damyan Ivanov
|
||||
|
||||
Ilya Pavlov (Ilya33)
|
||||
|
||||
Petr Pisar (ppisar)
|
||||
|
||||
Mohammad S Anwar (MANWAR)
|
||||
|
||||
Håkon Hægland (hakonhagland, HAKONH)
|
||||
|
||||
Meredith (merrilymeredith, MHOWARD)
|
||||
|
||||
Diab Jerius (DJERIUS)
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user