https://www.youtube.com/watch?v=-XITNDvqoTo
Have you ever wanted to learn the secrets of the dark masters of Perl? Ever been curious about what an *SV is? Maybe you just want to make a subroutine really, really fast, but you're terrified of this thing called XS that stands in your way. This talk presents the Perl API for beginners from the ground up, explaining everything you need to know to get started hacking Perl in C. XS is not required, as the examples use the much smarter Inline module to get right at the core API with nothing in the way.
17. What is XS?
perldoc perlxs:
XS is an interface description file format used to create an
extension interface between Perl and C code (or a C library)
which one wishes to use with Perl. The XS interface is
combined with the library to create a new library which can
then be either dynamically loaded or statically linked into
perl. The XS interface description is written in the XS
language and is the core component of the Perl extension
interface.
18.
19. XS is a specialized templating
language for C.
74. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
75. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
76. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
77. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
78. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
79. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
int add( int a, int b ) {
return a + b;
}
89. •SvIOK Is it a SvIV?
•SvNOK Is it a SvNV?
•SvIV Get the C int value from SV
90. •SvIOK Is it a SvIV?
•SvNOK Is it a SvNV?
•SvIV Get the C int value from SV
•SvNV Get the C float value from SV
91. •SvIOK Is it a SvIV?
•SvNOK Is it a SvNV?
•SvIV Get the C int value from SV
•SvNV Get the C float value from SV
•newSViv Make a new integer SV
92. •SvIOK Is it a SvIV?
•SvNOK Is it a SvNV?
•SvIV Get the C int value from SV
•SvNV Get the C float value from SV
•newSViv Make a new integer SV
•newSVnv Make a new float SV
93. use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
$num_a += 0; $num_b += 0;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
SV *add( SV *a, SV *b ) {
if ( SvIOK( a ) && SvIOK( b ) ) {
return newSViv( SvIV( a ) + SvIV( b ) );
} else if ( SvNOK( a ) && SvNOK( b ) ) {
return newSVnv( SvNV( a ) + SvNV( b ) );
} else {
croak( "I don't know what to do!" );
}
}
94. use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
$num_a += 0; $num_b += 0; # coerce
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
SV *add( SV *a, SV *b ) {
if ( SvIOK( a ) && SvIOK( b ) ) {
return newSViv( SvIV( a ) + SvIV( b ) );
} else if ( SvNOK( a ) && SvNOK( b ) ) {
return newSVnv( SvNV( a ) + SvNV( b ) );
} else {
croak( "I don't know what to do!" );
}
}
95. use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
$num_a += 0; $num_b += 0;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
SV *add( SV *a, SV *b ) {
if ( SvIOK( a ) && SvIOK( b ) ) {
return newSViv( SvIV( a ) + SvIV( b ) );
} else if ( SvNOK( a ) && SvNOK( b ) ) {
return newSVnv( SvNV( a ) + SvNV( b ) );
} else {
croak( "I don't know what to do!" );
}
}
96. use Inline 'C';
print 'Give me a number: ';
my $num_a = <STDIN>;
print 'Give me another number: ';
my $num_b = <STDIN>;
$num_a += 0; $num_b += 0;
printf "The sum is: %sn", add( $num_a, $num_b );
__END__
__C__
SV *add( SV *a, SV *b ) {
if ( SvIOK( a ) && SvIOK( b ) ) {
return newSViv( SvIV( a ) + SvIV( b ) );
} else if ( SvNOK( a ) && SvNOK( b ) ) {
return newSVnv( SvNV( a ) + SvNV( b ) );
} else {
croak( "I don't know what to do!" );
}
}
97. bash-3.2$ perl cexp2.pl
Give me a number: 42
Give me another number: 11
The sum is: 53
bash-3.2$ perl cexp2.pl
Run it!
98. bash-3.2$ perl cexp2.pl
Give me a number: 42
Give me another number: 11
The sum is: 53
bash-3.2$ perl cexp2.pl
Run it!
bash-3.2$ perl cexp2.pl
Give me a number: 53.4
Give me another number: 6.54
The sum is: 59.94
99. bash-3.2$ perl cexp2.pl
Give me a number: 42
Give me another number: 11
The sum is: 53
bash-3.2$ perl cexp2.pl
Run it!
bash-3.2$ perl cexp2.pl
Give me a number: 53.4
Give me another number: 6.54
The sum is: 59.94
Give me a number: 42
Give me another number: 6.54
I don't know what to do! at
cexp2.pl line 16, <STDIN>
line 2.
100. Once you get this far,
everything you need
is in perlapi.
108. •SvRV Get SV from reference
•newAV Make a new array AV
109. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
110. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
•AvFILL Get size of array
111. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
112. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvIOK Is it an int?
113. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvIOK Is it an int?
•SvIV Get C int from SV
114. •SvRV Get SV from reference
•newAV Make a new array AV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvIOK Is it an int?
•SvIV Get C int from SV
•av_push Obvs.
115. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print "Give me some numbers: ";
my @numbers = map { $_ += 0 }
split /,/, <STDIN>;
my $result = squares( @numbers );
printf "The squares are: %sn",
join ", ", @$result;
__END__
116. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print "Give me some numbers: ";
my @numbers = map { $_ += 0 }
split /,/, <STDIN>;
my $result = squares( @numbers );
printf "The squares are: %sn",
join ", ", @$result;
__END__
117. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
118. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
119. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
120. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
121. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
122. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV_inc( (SV *)return_array );
}
123. SV *squares( SV *numbers ) {
AV *array = (AV *)SvRV( numbers );
AV *return_array = newAV();
SV **tmp;
int len = AvFILL( array );
int i, val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvIOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvIV( *tmp );
val = val * val;
av_push( return_array, newSViv( val ) );
}
return newRV( (SV *)return_array );
}
132. •SvRV Get SV from reference
•newHV Make a new hash HV
133. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
134. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
•AvFILL Get size of array
135. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
136. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvPOK Is it a string?
137. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvPOK Is it a string?
•SvPV Get C string from SV
138. •SvRV Get SV from reference
•newHV Make a new hash HV
•newRV Make a new reference
•AvFILL Get size of array
•av_fetch Get an element from array
•SvPOK Is it a string?
•SvPV Get C string from SV
•hv_store Obvs.
139. #!/usr/bin/env perl
use strict;
use warnings;
use Inline 'C';
print "Give me some words: ";
my @words = split /,/, <STDIN>;
chomp @words;
my $result = uniques( @words );
printf "The uniques are: %sn",
join ", ", %$result;
__END__
140. __C__
SV *uniques( SV *words ) {
AV *array = (AV *)SvRV( words );
HV *result = newHV();
SV **tmp;
int len = AvFILL( array );
int i;
char *val;
for( i = 0; i <= len; i++ ) {
tmp = av_fetch( array, i, 1 );
if( !SvPOK( *tmp ) ) {
croak( "Can't handle this value!" );
}
val = SvPV_nolen( *tmp );
hv_store( result, val, strlen( val ), newSV(0), 0 );
}
return newRV( (SV *)result );
}
141. bash-3.2$ perl cexp4.pl
Give me some words: foo,bar,baz,baz,foo,quux,narf,poit
The uniques are: bar, narf, baz, poit, quux, foo
Run it!
144. Magic is a linked list of function pointers
attached to a *SV.
145. Magic is a linked list of function pointers
attached to a *SV.
The functions implement custom read/write
behavior.
146. Magic is a linked list of function pointers
attached to a *SV.
The functions implement custom read/write
behavior.
Special vars like %ENV are implemented via
Magic.