package overload::eval;
use strict;
use warnings;
use 5.009_004;
use feature ':5.10';
use XSLoader;
our $GLOBAL = 0;
sub import {
my ( undef, $callback ) = @_;
$callback //= 'eval';
given ($callback) {
when (/^-p(?:rint)?\z/) {
$^H{'overload::eval'} = 'overload::eval::_print';
_global();
}
when (/^-p(?:e|rint-eval)\z/) {
$^H{'overload::eval'} = 'overload::eval::_print_eval';
_global();
}
default { $^H{'overload::eval'} = "$callback" };
}
return;
}
sub unimport {
delete $^H{'overload::eval'};
return;
}
sub _print {
print @_ or die "Can't print: $!";
exit;
}
sub _print_eval {
print @_ or die "Can't print: $!";
return eval "@_";
}
sub _global {
$GLOBAL = 1;
}
our $init_done;
sub _install_eval; # Provided by eval.xs
our $VERSION = '0.10';
XSLoader::load( 'overload::eval', $VERSION );
_install_eval();
q[With great powers come laser eyebeams.];
__END__
=head1 NAME
overload::eval - Hooks the native string eval() function
=head1 SYNOPSIS
As a command line tool:
uneval obfuscated.pl
As a module:
use overload::eval 'my_callback';
sub my_callback { print and eval for $_[0] }
sub rot13 {
local $_ = shift;
tr[A-Za-z][N-ZA-Mn-za-m];
return $_;
}
eval(rot13());
=head1 DESCRIPTION
This module hooks the native eval() function and sends it to your
function instead. The eval() function operates normally within your
function.
This module requires user pragmas which are a feature present only in
5.9.4+.
Using this module is simplicity itself. If you've declared the hook,
any uses of string eval in that lexical scope are going to be
redirected to the function you named.
{
use overload::eval;
eval '...';
}
sub eval {
# eval goes here
}
If you declare a hook name, execution is redirected to that named
function instead of C<eval>.
{
use overload::eval 'hook';
eval '...';
}
sub hook {
# eval goes here because we declared 'hook'
}
=head1 BUILTIN-HOOKS
There are some built-in hooks. They are accessed by importing them by
name. This can also be done on the command line.
=over
=item -p
=item -print
The C<-print> option prints the source code of the eval() and then
exits the program. I expect this option is most useful when untangling
obfuscated programs. Use of this option changes the pragma so it
operates globally. B<All> evals are now hooked.
C<-p> is a synonym for C<-print>.
The program:
perl -Moverload::eval=-p obfuscated.pl
when run on:
$_='cevag "Uryyb jbeyq!\a"';tr/A-Za-z/N-ZA-Mn-za-m/;eval;
prints the following and exits:
print "Hello world!\n"
=item -pe
=item -print-eval
The C<-print-eval> option prints the source code of the eval() before
running it. Use of this option changes the pragma so it operates globally. B<All> evals are now hooked.
C<-pe> is a synonym for C<-print-eval>.
The program:
perl -Moverload::eval=-print-eval obfuscated.pl
when run on:
$_='cevag "Uryyb jbeyq!\a"';tr/A-Za-z/N-ZA-Mn-za-m/;eval;
prints the following:
print "Hello world!\n"
and then runs the code which prints:
Hello world!
=back
=head1 DISPELLING MAGIC
This module overloads eval() only with the lexical scope you've
requested. To avoid triggering this module, either create a new
lexical scope or just disable the overloading.
{
use overload::eval;
eval '...'; # Overloaded;
}
eval '...'; # NOT overloaded
Or...
use overload::eval;
eval '...'; # Overloaded;
no overload::eval;
eval '...'; # NOT overloaded.
=head1 CAVEATS
This module does not overload the block form of eval. Sorry. That's an
entirely different kind of technology.
eval { ... };
=head1 AUTHOR
Josh Jore - jjore@cpan.org
=head1 LICENSE
This module is available under the same licences as perl, the Artistic license and the GPL.