Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added initial work to support Crypt::GCrypt::MPI

git-svn-id: svn://localhost/Crypt-GCrypt/trunk@76 c2f821fb-fd85-dc11-8383-000bcdcb7a8f
  • Loading branch information...
commit fe4665a3bccda2d1486478188ff7b07d2eb801d1 1 parent fb19500
dkg authored
View
4 Changelog
@@ -1,3 +1,7 @@
+version 1.24_01 (2010/01/??):
+
+ - added multi-precision integers as Crypt::GCrypt::MPI (dkg)
+
version 1.23_04 (2009/12/18):
- Makefile.PL now requires libgcrypt being not older than 1.3.0
View
281 GCrypt.xs
@@ -69,6 +69,9 @@ struct Crypt_GCrypt_s {
};
typedef struct Crypt_GCrypt_s *Crypt_GCrypt;
+/* a Crypt_GCrypt_MPI need only be a pointer to a gcrypt MPI object */
+typedef gcry_mpi_t Crypt_GCrypt_MPI;
+
/* return the offset of padding or -1 if none */
int find_padding (Crypt_GCrypt gcr, unsigned char *string, size_t string_len) {
unsigned char last_char = string[string_len-1];
@@ -794,3 +797,281 @@ cg_DESTROY(gcr)
Safefree(gcr->buffer);
Safefree(gcr);
+MODULE = Crypt::GCrypt PACKAGE = Crypt::GCrypt::MPI PREFIX = cgm_
+
+BOOT:
+ { /* found this method of storing constants in
+ http://blogs.sun.com/akolb/entry/pitfals_of_the_perl_xs */
+ HV *stash;
+
+ stash = gv_stashpv("Crypt::GCrypt::MPI", TRUE);
+ newCONSTSUB(stash, "FMT_STD", newSViv(GCRYMPI_FMT_STD));
+ newCONSTSUB(stash, "FMT_PGP", newSViv(GCRYMPI_FMT_PGP));
+ newCONSTSUB(stash, "FMT_SSH", newSViv(GCRYMPI_FMT_SSH));
+ newCONSTSUB(stash, "FMT_HEX", newSViv(GCRYMPI_FMT_HEX));
+ newCONSTSUB(stash, "FMT_USG", newSViv(GCRYMPI_FMT_USG));
+ }
+
+Crypt_GCrypt_MPI
+cgm_new(...)
+ PROTOTYPE: @
+ PREINIT:
+ char *s;
+ int i, valix, secure, set, format;
+ Crypt_GCrypt_MPI src;
+ size_t len;
+ gcry_error_t err;
+ CODE:
+ RETVAL = NULL;
+ secure = 0;
+ valix = -1;
+ format = GCRYMPI_FMT_STD;
+ set = 0;
+ s = SvPV_nolen(ST(0));
+ if (strcmp(s, "Crypt::GCrypt::MPI") == 0) {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ if ((items-i > 1) && ((items-i % 2) == 1))
+ croak("Wrong number of arguments for Crypt::GCrypt::MPI->new()");
+ if (items-i == 1) {
+ /* this is the value */
+ valix = i;
+ } else {
+ /* this is a parameterized list */
+ while (i < items) {
+ s = SvPV_nolen(ST(i));
+
+ if (strcmp(s, "secure") == 0)
+ if (SvTRUE(ST(i+1)))
+ secure = 1;
+ if (strcmp(s, "format") == 0)
+ format = SvIV(ST((i+1)));
+ if (strcmp(s, "value") == 0)
+ valix = i + 1;
+ i += 2;
+ }
+ }
+
+ /* we're copying an mpi: */
+ if ((valix >= 0) && sv_derived_from(ST(valix), "Crypt::GCrypt::MPI")) {
+ IV tmp = SvIV((SV*)SvRV(ST(valix))); /* found this incantation at */
+ src = INT2PTR(Crypt_GCrypt_MPI,tmp); /* http://cpansearch.perl.org/src/DSTH/Math-GSL-Linalg-SVD-0.0.2/SVD.c */
+ if (secure && ! gcry_mpi_get_flag(src, GCRYMPI_FLAG_SECURE)) {
+ /* we were asked for a secure MPI, but we were given an insecure one to copy */
+ RETVAL=gcry_mpi_snew(gcry_mpi_get_nbits(src));
+ if (RETVAL == NULL) XSRETURN_UNDEF;
+ gcry_mpi_set(RETVAL, src);
+ } else {
+ /* this will give us a secure MPI if a secure MPI was passed in, even if we
+ also got secure => 0 ; a bit weird, but on the safe side. */
+ RETVAL=gcry_mpi_copy(src);
+ }
+ } else {
+ if (secure) {
+ RETVAL=gcry_mpi_snew(0);
+ } else {
+ RETVAL=gcry_mpi_new(0);
+ }
+ if (RETVAL == NULL) XSRETURN_UNDEF;
+
+ /* do something with the info at valix */
+ if (valix >= 0) {
+ switch(SvTYPE(ST(valix))) {
+ case SVt_PVIV:
+ /* if negative value, we have to jump through some hoops: */
+ if (SvIV(ST(valix)) < 0) {
+ RETVAL=gcry_mpi_set_ui(NULL, 0);
+ gcry_mpi_sub_ui(RETVAL, RETVAL, -1*(SvIV(ST(valix))));
+ } else {
+ /* this can be dealt with by regular unsigned ints */
+ gcry_mpi_set_ui(RETVAL, SvIV(ST(valix)));
+ }
+ break;
+ case SVt_PV:
+ /* handle bytestrings
+ */
+ s = SvPV(ST(valix), len);
+ src = NULL;
+ err = gcry_mpi_scan(&src, format, s, ((format == GCRYMPI_FMT_HEX) ? 0 : len), NULL);
+ if (err != 0) croak("Crypt::GCrypt::MPI::new (from string, with format %d) libgcrypt internal failure %s", format, gcry_strerror(err));
+ /* FIXME: can we "eat" the head of the the input string if format is FMT_PGP or FMT_SSH ? */
+ /* avoid memory leak: */
+ if (secure) {
+ gcry_mpi_set(RETVAL, src);
+ gcry_mpi_release(src);
+ } else {
+ gcry_mpi_release(RETVAL);
+ RETVAL = src;
+ }
+ break;
+ default:
+ croak("value argument for Crypt::GCrypt::MPI->new() must currently be either an int or another Crypt::GCrypt::MPI (%d, %d, %d)", SvTYPE(ST(valix)), valix, format);
+ break;
+ }
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+void
+cgm_swap(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_swap(gcma, gcmb);
+
+void
+cgm_set(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_set(gcma, gcmb);
+
+int
+cgm_is_secure(gcm)
+ Crypt_GCrypt_MPI gcm;
+ CODE:
+ RETVAL=gcry_mpi_get_flag(gcm, GCRYMPI_FLAG_SECURE);
+ OUTPUT:
+ RETVAL
+
+int
+cgm_cmp(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ RETVAL=gcry_mpi_cmp(gcma, gcmb);
+ OUTPUT:
+ RETVAL
+
+void
+cgm_add(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_add(gcma, gcma, gcmb);
+
+void
+cgm_addm(gcma, gcmb, gcmm)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ Crypt_GCrypt_MPI gcmm;
+ CODE:
+ gcry_mpi_addm(gcma, gcma, gcmb, gcmm);
+
+void
+cgm_sub(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_sub(gcma, gcma, gcmb);
+
+void
+cgm_subm(gcma, gcmb, gcmm)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ Crypt_GCrypt_MPI gcmm;
+ CODE:
+ gcry_mpi_subm(gcma, gcma, gcmb, gcmm);
+
+void
+cgm_mul(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_mul(gcma, gcma, gcmb);
+
+void
+cgm_mulm(gcma, gcmb, gcmm)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ Crypt_GCrypt_MPI gcmm;
+ CODE:
+ gcry_mpi_mulm(gcma, gcma, gcmb, gcmm);
+
+void
+cgm_mul_2exp(gcm, e)
+ Crypt_GCrypt_MPI gcm;
+ int e;
+ CODE:
+ if (e >= 0) {
+ /* this can be dealt with by regular unsigned ints */
+ gcry_mpi_mul_2exp(gcm, gcm, e);
+ } else {
+ croak("exponent argument for Crypt::GCrypt::MPI::mul_2exp() must be an unsigned integer");
+ }
+
+void
+cgm_div(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ /* FIXME: should we return the modulus as well, if called in a list context? */
+ gcry_mpi_div(gcma, NULL, gcma, gcmb, 0);
+
+void
+cgm_mod(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ gcry_mpi_mod(gcma, gcma, gcmb);
+
+void
+cgm_powm(gcma, gcme, gcmm)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcme;
+ Crypt_GCrypt_MPI gcmm;
+ CODE:
+ gcry_mpi_powm(gcma, gcma, gcme, gcmm);
+
+void
+cgm_invm(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ /* FIXME: should we do anything with the return value (1 if invm actually exists)? */
+ gcry_mpi_invm(gcma, gcma, gcmb);
+
+void
+cgm_gcd(gcma, gcmb)
+ Crypt_GCrypt_MPI gcma;
+ Crypt_GCrypt_MPI gcmb;
+ CODE:
+ /* FIXME: should we do anything with the return value (1 if gcd == 1)? */
+ gcry_mpi_gcd(gcma, gcma, gcmb);
+
+void
+cgm_dump(gcm)
+ Crypt_GCrypt_MPI gcm;
+ CODE:
+ gcry_mpi_dump(gcm);
+
+SV *
+cgm_print(gcm, format)
+ Crypt_GCrypt_MPI gcm;
+ int format;
+ PREINIT:
+ size_t size;
+ char* buf;
+ gcry_error_t err;
+ CODE:
+ /* FIXME: make format default to FMT_STD somehow (how do we not require a parameter?) */
+ err = gcry_mpi_print(format, NULL, 0, &size, gcm);
+ if (err != 0) croak("GCrypt::MPI::print start: %s", gcry_strerror(err));
+ /* FMT_HEX asks for an extra byte for the null char, but perl allocates that
+ already, so we treat that case special */
+ RETVAL = newSVpv("", ((format == GCRYMPI_FMT_HEX) ? size-1 : size));
+ buf = SvPV_nolen(RETVAL);
+ err = gcry_mpi_print(format, buf, size, &size, gcm);
+ if (err != 0) croak("GCrypt::MPI::print finish: %s", gcry_strerror(err));
+ OUTPUT:
+ RETVAL
+
+void
+cgm_DESTROY(gmpi)
+ Crypt_GCrypt_MPI gmpi;
+ CODE:
+ gcry_mpi_release(gmpi);
+ gmpi = NULL;
View
2  MANIFEST
@@ -2,6 +2,7 @@ Changelog
GCrypt.xs
inc/Devel/CheckLib.pm
lib/Crypt/GCrypt.pm
+lib/Crypt/GCrypt/MPI.pm
Makefile.PL
MANIFEST This list of files
MANIFEST.SKIP
@@ -18,4 +19,5 @@ t/07-thread.t
t/08-digest.t
t/09-clone-digest.t
t/10-versions.t
+t/20-mpi.t
typemap
View
232 lib/Crypt/GCrypt/MPI.pm
@@ -0,0 +1,232 @@
+# ===========================================================================
+# Crypt::GCrypt:MPI
+#
+# Perl interface to multi-precision integers from the GNU Cryptographic library
+#
+# Author: Daniel Kahn Gillmor E<lt>dkg@fifthhorseman.netE<gt>,
+# Alessandro Ranellucci E<lt>aar@cpan.orgE<gt>
+# Copyright © 2009.
+#
+# Use this software AT YOUR OWN RISK.
+# See below for documentation.
+#
+
+package Crypt::GCrypt::MPI;
+
+use strict;
+use warnings;
+
+our $VERSION = '1.23';
+
+require XSLoader;
+XSLoader::load('Crypt::GCrypt', $VERSION);
+
+1;
+__END__
+
+=head1 NAME
+
+Crypt::GCrypt::MPI - Perl interface to multi-precision integers from the GNU Cryptographic library
+
+=head1 SYNOPSIS
+
+ use Crypt::GCrypt::MPI;
+
+ my $mpi = Crypt::GCrypt::MPI->new();
+
+=head1 ABSTRACT
+
+Crypt::GCrypt::MPI provides an object interface to multi-precision
+integers from the C libgcrypt library.
+
+=head1 BASIC OPERATIONS
+
+=head2 new()
+
+Create a new multi-precision integer.
+
+ my $mpi = Crypt::GCrypt::MPI::new(
+ secure => 1,
+ value => 20,
+ );
+
+No parameters are required. If only one parameter is given, it is
+treated as the "value" parameter. Available parameters:
+
+=over 4
+
+=item value
+
+The initial value of the MPI. This can be an integer, a string, or
+another Crypt::GCrypt::MPI. (It would also be nice to be able to
+initialize it with a Math::Int).
+
+=item secure
+
+If this parameter evaluates to non-zero, initialize the MPI using
+secure memory, if possible.
+
+=item format
+
+If the value is a string, the format parameter suggests how to convert
+the string. See CONVERSION FORMATS for the available formats.
+Defaults to Crypt::GCrypt::MPI::FMT_STD.
+
+=back
+
+=head2 set()
+
+Copies the value of the other Crypt::GCrypt::MPI object.
+
+ $mpi->set($othermpi);
+
+=head2 swap()
+
+Exchanges the value with the value of another Crypt::GCrpyt::MPI
+object:
+
+ $mpi->swap($othermpi);
+
+=head2 is_secure()
+
+Returns true if the Crypt::GCrypt::MPI uses secure memory, where
+possible.
+
+=head2 cmp($other)
+
+Compares this object against another Crypt::GCrypt::MPI object,
+returning 0 if the two values are equal, positive if this value is
+greater, negative if $other is greater.
+
+=head1 CALCULATIONS
+
+=head2 add($other)
+
+Adds the value of $other to this MPI.
+
+=head2 addm($other, $modulus)
+
+Adds the value of $other to this MPI, modulo the value of $modulus.
+
+=head2 sub($other)
+
+Subtracts the value of $other from this MPI.
+
+=head2 subm($other, $modulus)
+
+Subtracts the value of $other from this MPI, modulo the value of $modulus.
+
+=head2 mul($other)
+
+Multiply this MPI by the value of $other.
+
+=head2 mulm($other, $modulus)
+
+Multiply this MPI by the value of $other, modulo the value of $modulus.
+
+=head2 mul_2exp($e)
+
+Multiply this MPI by 2 raised to the power of $e (this is a leftward
+bitshift)
+
+=head2 div($other)
+
+Divide this MPI by the value of $other, leaving the integer quotient.
+(This is integer division)
+
+=head2 mod($other)
+
+Divide this MPI by the value of $other, leaving the integer remainder.
+(This is the modulus operation)
+
+=head2 powm($other, $modulus)
+
+Raise this MPI to the power of $other, modulo the value of $modulus.
+
+=head2 invm($modulus)
+
+Find the multiplicative inverse of this MPI, modulo $modulus.
+
+=head2 gcd($other)
+
+Find the greatest common divisor of this MPI.
+
+=head1 OUTPUT AND DEBUGGING
+
+=head2 dump()
+
+Send the MPI to the libgcrypt debugging stream.
+
+=head2 print($format)
+
+Return a string with the data of this MPI, in a given format. See
+CONVERSION FORMATS for the available formats.
+
+=head1 CONVERSION FORMATS
+
+The available printing and scanning formats are all in the
+Crypt::GCrypt::MPI namespace, and have the same meanings as in gcrypt.
+
+=head2 FMT_STD
+
+Two's complement representation.
+
+=head2 FMT_PGP
+
+Same as FMT_STD, but with two-byte length header, as used in OpenPGP.
+(Only works for non-negative values)
+
+=head2 FMT_SSH
+
+Same as FMT_STD, but with four-byte length header, as used by OpenSSH.
+
+=head2 FMT_HEX
+
+Hexadecimal string in ASCII.
+
+=head2 FMT_USG
+
+Simple unsigned integer.
+
+=head1 BUGS AND FEEDBACK
+
+Crypt::GCrypt::MPI does not currently auto-convert to and from
+Math::BigInt objects, even though it should.
+
+Other than that, here are no known bugs. You are very welcome to write
+mail to the author (aar@cpan.org) with your contributions, comments,
+suggestions, bug reports or complaints.
+
+=head1 AUTHORS AND CONTRIBUTORS
+
+Daniel Kahn Gillmor E<lt>dkg@fifthhorseman.net<gt>
+
+Alessandro Ranellucci E<lt>aar@cpan.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright © Daniel Kahn Gillmor.
+Crypt::GCrypt::MPI is free software, you may redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 ACKNOWLEDGEMENTS
+
+This module was initially inspired by the GCrypt.pm bindings made by
+Robert Bihlmeyer in 2002. Thanks to users who give feedback and submit
+patches (see Changelog).
+
+=head1 DISCLAIMER
+
+This software is provided by the copyright holders and contributors ``as
+is'' and any express or implied warranties, including, but not limited to,
+the implied warranties of merchantability and fitness for a particular
+purpose are disclaimed. In no event shall the regents or contributors be
+liable for any direct, indirect, incidental, special, exemplary, or
+consequential damages (including, but not limited to, procurement of
+substitute goods or services; loss of use, data, or profits; or business
+interruption) however caused and on any theory of liability, whether in
+contract, strict liability, or tort (including negligence or otherwise)
+arising in any way out of the use of this software, even if advised of the
+possibility of such damage.
+
+=cut
View
101 t/20-mpi.t
@@ -0,0 +1,101 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl 20-mpi.t'
+
+#########################
+
+use Test;
+BEGIN { plan tests => 32 }; # <--- number of tests
+use ExtUtils::testlib;
+use Crypt::GCrypt::MPI;
+
+#########################
+
+
+my $empty = Crypt::GCrypt::MPI->new(); # make simple MPI (defaults to zero?)
+ok(defined $empty);
+my $thirtysix = Crypt::GCrypt::MPI->new(36); # make simple MPI with integer assignment
+ok(defined $thirtysix);
+my $minusforty = Crypt::GCrypt::MPI->new(-40); # make simple MPI with negative integer assignment
+ok(defined $minusforty);
+my $zero = Crypt::GCrypt::MPI->new(0);
+ok(defined $zero);
+$empty->set($zero);
+ok($zero->cmp($empty) == 0);
+ok($zero->cmp($thirtysix) < 0);
+ok($thirtysix->cmp($zero) > 0);
+
+ok($zero->cmp($minusforty) > 0);
+ok($minusforty->cmp($zero) < 0);
+
+ok($thirtysix->cmp($minusforty) > 0);
+ok($minusforty->cmp($thirtysix) < 0);
+
+ok(!$zero->is_secure());
+
+# basic test calculations:
+my $x = Crypt::GCrypt::MPI->new(29);
+$x->add(Crypt::GCrypt::MPI->new(7));
+ok(0 == $x->cmp($thirtysix));
+$x->mul(Crypt::GCrypt::MPI->new(-1));
+$x->sub(Crypt::GCrypt::MPI->new(4));
+ok(0 == $x->cmp($minusforty));
+
+# modulo calculations:
+$x = Crypt::GCrypt::MPI->new(29);
+$x->addm(Crypt::GCrypt::MPI->new(12), $thirtysix);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(5)));
+$x->subm(Crypt::GCrypt::MPI->new(60), $thirtysix);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(17)));
+$x->mulm(Crypt::GCrypt::MPI->new(25), $thirtysix);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(29)));
+
+$x->mul_2exp(6);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(1856)));
+
+my $twentysix = Crypt::GCrypt::MPI->new(26);
+my $y = Crypt::GCrypt::MPI->new(1856);
+
+$x->mod($twentysix);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(10)));
+
+$y->div($twentysix);
+ok(0 == $y->cmp(Crypt::GCrypt::MPI->new(71)));
+
+
+# powm, invm, gcd:
+$x = Crypt::GCrypt::MPI->new(84);
+$y = Crypt::GCrypt::MPI->new(24);
+$y->gcd($x);
+ok(0 == $y->cmp(Crypt::GCrypt::MPI->new(12)));
+
+$x = Crypt::GCrypt::MPI->new(17);
+my $z = Crypt::GCrypt::MPI->new(7);
+$y->powm($z, $x);
+ok(0 == $y->cmp(Crypt::GCrypt::MPI->new(7)));
+
+$x = Crypt::GCrypt::MPI->new(12);
+$y = Crypt::GCrypt::MPI->new(17);
+$x->invm($y);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(10)));
+
+ok("0a" eq unpack('H*', $x->print(Crypt::GCrypt::MPI::FMT_STD)));
+ok("0A" eq $x->print(Crypt::GCrypt::MPI::FMT_HEX));
+ok("0a" eq unpack('H*', $x->print(Crypt::GCrypt::MPI::FMT_USG)));
+
+$x = Crypt::GCrypt::MPI->new(pack('H*', '0a0a'));
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(2570)));
+
+$x = Crypt::GCrypt::MPI->new(value => pack('H*', '00000003010002'),
+ format => Crypt::GCrypt::MPI::FMT_SSH);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(65538)));
+
+$x = Crypt::GCrypt::MPI->new(value => pack('H*', '0011010001'),
+ format => Crypt::GCrypt::MPI::FMT_PGP);
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(65537)));
+
+# test copy constructor:
+$y = Crypt::GCrypt::MPI->new($x);
+ok(0 == $y->cmp($x));
+$y->sub($thirtysix);
+ok(0 == $y->cmp(Crypt::GCrypt::MPI->new(65501)));
+ok(0 == $x->cmp(Crypt::GCrypt::MPI->new(65537)));
View
9 typemap
@@ -1,15 +1,16 @@
TYPEMAP
Crypt_GCrypt T_PTROBJ_SPECIAL
+Crypt_GCrypt_MPI T_PTROBJ_SPECIAL
INPUT
T_PTROBJ_SPECIAL
- if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/;\$ntt}\")) {
+ if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")) {
IV tmp = SvIV((SV*)SvRV($arg));
$var = ($type) tmp;
} else
- croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/;\$ntt}\");
+ croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\");
OUTPUT
T_PTROBJ_SPECIAL
- sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/;\$ntt}\",
- (void *)$var);
+ sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
+ (void *)$var);
Please sign in to comment.
Something went wrong with that request. Please try again.