How to define an environment variable before loading modules? - perl

I use the AnyEvent::DNS module.
I want to disable IPv6, so that the resolver only makes a request for A record.
AnyEvent::DNS, uses the environment variable $ENV{PERL_ANYEVENT_PROTOCOLS}
But setting the variable does not work; the resolver still sends two requests A and AAAA
Code from AnyEvent::DNS:
our %PROTOCOL; # (ipv4|ipv6) => (1|2), higher numbers are preferred
BEGIN {
...;
my $idx;
$PROTOCOL{$_} = ++$idx
for reverse split /\s*,\s*/,
$ENV{PERL_ANYEVENT_PROTOCOLS} || "ipv4,ipv6";
}
How to define an environment variable before loading modules?

Since the code that checks the environment variable is in a BEGIN block, it will be run immediately once the Perl compiler reaches it.
When Perl starts compiling your script, it checks for use statements first. So when you use AnyEvent::DNS, Perl loads that module and parses the file. BEGIN blocks are executed at that stage, while code in methods will only be compiled, not executed.
So if you have something like the following, the code you showed above will be run before you even set that variable.
use strict;
use warnings;
use AnyEvent::DNS;
$ENV{PERL_ANYEVENT_PROTOCOLS} = 'ipv4';
...
There are two ways you can circumvent that.
You can put the assignment in your own BEGIN block before you load AnyEvent::DNS. That way it will be set first.
use strict;
use warnings;
BEGIN {
$ENV{PERL_ANYEVENT_PROTOCOLS} = 'ipv4';
}
use AnyEvent::DNS;
Alternatively, you can just call your program with the environment variable set for it from the shell.
$ PERL_ANYEVENT_PROTOCOLS=ipv4 perl resolver.pl
The second one is more portable, in case you later want it to do IPv6 after all.
Read more about BEGIN in perlmod.

Related

Calling one Perl script from another, passing a CGI parameter

I have two Perl scripts. Let's call them one.pl and two.pl.
one.pl processes some data and needs to call two.pl, passing a variable.
In one.pl I can
require "two.pl"
to call the second script.
That works fine, but I want to pass a CGI variable to two.pl.
Is there any way to do this without rewriting two.pl as a Perl module?
For example what I want is:
one.pl
...
require "two.pl $number";
two.pl
use CGI;
my $cgi = new CGI;
my $number = $cgi->param('number');
...
EDIT: two.pl should only ever be called once
If one.pl is not in a CGI environment
If your one.pl is a shell script, you can set #ARGV before the call to require. This abuses CGI's mode to work with command line arguments. The arg needs to be the param name equals the value.
{
my $number = 5;
local #ARGV = ( "number=$number" );
require "two.pl";
}
The key=value format is important. The local keyword makes sure that #ARGV is only set inside the block, making sure other possible arguments to your script are not permanently lost, but rather invisible to two.pl.
If one.pl is in a CGI environment
If the param is already there, you don't have to do anything.
Else, see above.
Note that for both of these you can only ever require a script once. That's the idea of require. Perl keeps track of what it's loaded already (in %INC). If you are in an environment like mod_perl, or a modern Perl application that runs persistently, you should use do "two.pl" instead, which will execute it every time. But then that might break other things if two.pl is not designed to be ran multiple times in the same process.
Your best bet is to refactor the code inside two.pl into a module, and use that in both scripts.

BEGIN,CHECK,INIT& END blocks in Perl

As I understand these special functions inside Perl code, BEGIN and CHECK blocks run during the compilation phase while INIT and END blocks run during actual execution phase.
I can understand using these blocks inside actual Perl code (Perl libraries) but what about using them inside modules? Is that possible?
Since when we use use <Module-name> the module is compiled, so in effect BEGIN and CHECK blocks run. But how will the INIT and END blocks run since module code I don't think is run in the true sense. We only use certain functions from inside the modules.
Short The special code blocks in packages loaded via use are processed and run (or scheduled to run) as encoutered, in the same way and order as in main::, since use itself is a BEGIN block.
Excellent documentation on this can be found in perlmod. From this section
A BEGIN code block is executed as soon as possible, that is, the moment it is completely defined, even before the rest of the containing file (or string) is parsed.
Since the use statements are BEGIN blocks they run as soon as encountered. From use
It is exactly equivalent to
BEGIN { require Module; Module->import( LIST ); }
So the BEGIN blocks in a package run in-line with others, as they are encountered. The END blocks in a package are then also compiled in the same order, as well as the other special blocks. As for the order of (eventual) execution
An END code block is executed as late as possible ...
and
You may have multiple END blocks within a file--they will execute in reverse order of definition; that is: last in, first out (LIFO)
The order of compilation and execution of INIT and CHECK blocks follows suit.
Here is some code to demonstrate these special code blocks used in a package.
File PackageBlocks.pm
package PackageBlocks;
use warnings;
BEGIN { print "BEGIN block in the package\n" }
INIT { print "INIT block in the package\n" }
END { print "END block in the package\n" }
1;
The main script
use warnings;
BEGIN { print "BEGIN in main script.\n" }
print "Running in the main.\n";
INIT { print "INIT in main script.\n" }
use PackageBlocks;
END { print "END in main script.\n" }
BEGIN { print "BEGIN in main script, after package is loaded.\n" }
print "After use PackageBlocks.\n";
Output
BEGIN in main script.
BEGIN block in the package
BEGIN in main script, after package is loaded.
INIT in main script.
INIT block in the package
Running in the main.
After use PackageBlocks.
END in main script.
END block in the package
The BEGIN block in the package runs in order of appearance, in comparison with the ones in main::, and before INIT. The END block runs at end,
and the one in the package runs after the one in main::, since the use comes before it in this example.
This is very easy to test for yourself
use Module (and require EXPR and do EXPR and eval EXPR) compile the Perl code and then immediately run it
That is where the 1; at the end of most modules is picked up. If executing the module's code after compiling it doesn't return a true value then require will fail
Admittedly there usually isn't much use for an INIT or an END block, because the run-time phase is so intimately tied to the compilation, and because modules are generally about defining subroutines, but the option is there if you want it

identify a procedure and replace it with a different procedure

What I want to achieve:
###############CODE########
old_procedure(arg1, arg2);
#############CODE_END######
I have a huge code which has a old procedure in it. I want that the call to that old_procedure go to a call to a new procedure (new_procedure(arg1, arg2)) with the same arguments.
Now I know, the question seems pretty stupid but the trick is I am not allowed to change the code or the bad_function. So the only thing I can do it create a procedure externally which reads the code flow or something and then whenever it finds the bad_function, it replaces it with the new_function. They have a void type, so don't have to worry about the return values.
I am usng perl. If someone knows how to atleast start in this direction...please comment or answer. It would be nice if the new code can be done in perl or C, but other known languages are good too. C++, java.
EDIT: The code is written in shell script and perl. I cannot edit the code and I don't have location of the old_function, I mean I can find it...but its really tough. So I can use the package thing pointed out but if there is a way around it...so that I could parse the thread with that function and replace function calls. Please don't remove tags as I need suggestions from java, C++ experts also.
EDIT: #mirod
So I tried it out and your answer made a new subroutine and now there is no way of accessing the old one. I had created an variable which checks the value to decide which way to go( old_sub or new_sub)...is there a way to add the variable in the new code...which sends the control back to old_function if it is not set...
like:
use BadPackage; # sub is defined there
BEGIN
{ package BapPackage;
no warnings; # to avoid the "Subroutine bad_sub redefined" message
# check for the variable and send to old_sub if the var is not set
sub bad_sub
{ # good code
}
}
# Thanks #mirod
This is easier to do in Perl than in a lot of other languages, but that doesn't mean it's easy, and I don't know if it's what you want to hear. Here's a proof-of-concept:
Let's take some broken code:
# file name: Some/Package.pm
package Some::Package;
use base 'Exporter';
our #EXPORT = qw(forty_two nineteen);
sub forty_two { 19 }
sub nineteen { 19 }
1;
# file name: main.pl
use Some::Package;
print "forty-two plus nineteen is ", forty_two() + nineteen();
Running the program perl main.pl produces the output:
forty-two plus nineteen is 38
It is given that the files Some/Package.pm and main.pl are broken and immutable. How can we fix their behavior?
One way we can insert arbitrary code to a perl command is with the -M command-line switch. Let's make a repair module:
# file: MyRepairs.pm
CHECK {
no warnings 'redefine';
*forty_two = *Some::Package::forty_two = sub { 42 };
};
1;
Now running the program perl -MMyRepairs main.pl produces:
forty-two plus nineteen is 61
Our repair module uses a CHECK block to execute code in between the compile-time and run-time phase. We want our code to be the last code run at compile-time so it will overwrite some functions that have already been loaded. The -M command-line switch will run our code first, so the CHECK block delays execution of our repairs until all the other compile time code is run. See perlmod for more details.
This solution is fragile. It can't do much about modules loaded at run-time (with require ... or eval "use ..." (these are common) or subroutines defined in other CHECK blocks (these are rare).
If we assume the shell script that runs main.pl is also immutable (i.e., we're not allowed to change perl main.pl to perl -MMyRepairs main.pl), then we move up one level and pass the -MMyRepairs in the PERL5OPT environment variable:
PERL5OPT="-I/path/to/MyRepairs -MMyRepairs" bash the_immutable_script_that_calls_main_pl.sh
These are called automated refactoring tools and are common for other languages. For Perl though you may well be in a really bad way because parsing Perl to find all the references is going to be virtually impossible.
Where is the old procedure defined?
If it is defined in a package, you can switch to the package, after it has been used, and redefine the sub:
use BadPackage; # sub is defined there
BEGIN
{ package BapPackage;
no warnings; # to avoid the "Subroutine bad_sub redefined" message
sub bad_sub
{ # good code
}
}
If the code is in the same package but in a different file (loaded through a require), you can do the same thing without having to switch package.
if all the code is in the same file, then change it.
sed -i 's/old_procedure/new_procedure/g codefile
Is this what you mean?

Initializing global variable on Perl module (with BEGIN block) include

I'm trying to initialize a global variable from a Perl module that has a BEGIN block, but I can't manage to get it work.
This is the Perl module
Package A::B;
our $var;
BEGIN{
$var ||= "/some/default/path";
#create/access files/folders in $var
}
This is my CGI script
use A::B;
$A::B::var = "/correct/path";
But #error returned because $var is not the correct path
The BEGIN block is being executed before the correct path is assigned to $var. Is there a way to work around this without having to remove code from the BEGIN block?
BEGIN { $A::B::var = "/correct/path" }
use A::B;
This answer is unsatisfying to me, but I can't think of any other way, given how your A::B is designed. Ideally a module doesn't depend on who is using it or how often, but this module can really only be used once.

Package name in module code

Short version
Is it possible to access variables from a module declared as our using unqualified names within the BEGIN code block, but using qualified names outside? In particular, can this be done without explicitely naming the package in the module file?
Example
Let demomod.pm be
use strict;
use warnings;
package demomod;
our $foo;
BEGIN { $foo = 42; }
1;
and demoscript.pl be
#!/usr/bin/perl -Tw
use strict;
use warnings;
BEGIN { #INC = ('.', #INC); }
use demomod;
print $demomod::foo."\n";
In this case, all names agree, and everything works as it should. Is there a way to omit the line package demomod; from the demomod.pm code and still let this work?
Motivation
The reason why I'm asking is because I encountered something along these lines during a recent upgrade of Foswiki. That software has a module Foswiki.pm which does not have a package line (EDIT: seems the package line only got lost in my local copy, for reasons unknown). It declares and initializes a variable $engine like in my example. There also is a CGI script called view which sets #INC and then does use Foswiki (); followed by $Foswiki::engine->run(). This last line always fails for me due to the variable not being initialized:
Can't call method "run" on an undefined value at …/view
In the BEGIN block of the module, $engine is set correctly but $Foswiki::engine apparently is not. So it looks like there were two variables here, one qualified and a different one unqualified.
All that code apparently works for others, and a previous version used to work for me as well, without a package line either. So while I try to understand how this broke, I also try to understand how this could work before, without that line in place. Is there some mechanism that would make this work?
If you have no package statement in your code then any package variables will be declared into the main package. So no, you cannot do what you describe.
If you look at line 2 of the Foswiki code that you linked, you will see that it does have a package statement.