.pm file that's loaded on every invocation of the perl interpreter? - perl

I thought I remember reading somewhere about where perl can be configured to automatically load a certain .pm file on start up.
I know about PERL5OPT, but to my recollection, this was a specific file that would be loaded if it exists.
Is it a compile option that can be set (i.e. via Configure)?

Reading through perldoc perlrun it looks like you are looking for what is talked about in the -f option:
-f
Disable executing $Config{sitelib}/sitecustomize.pl at startup.
Perl can be built so that it by default will try to execute
$Config{sitelib}/sitecustomize.pl at startup (in a BEGIN block). This
is a hook that allows the sysadmin to customize how Perl behaves. It
can for instance be used to add entries to the #INC array to make Perl
find modules in non-standard locations.
Perl actually inserts the following code:
BEGIN {
do { local $!; -f "$Config{sitelib}/sitecustomize.pl"; }
&& do "$Config{sitelib}/sitecustomize.pl";
}
Since it is an actual do (not a require), sitecustomize.pl doesn't
need to return a true value. The code is run in package main , in its
own lexical scope. However, if the script dies, $# will not be set.
The value of $Config{sitelib} is also determined in C code and not
read from Config.pm , which is not loaded.
The code is executed very early. For example, any changes made to #INC
will show up in the output of perl -V. Of course, END blocks will be
likewise executed very late.
To determine at runtime if this capability has been compiled in your
perl, you can check the value of $Config{usesitecustomize} .
I've never done this, but it looks like if you put what you want in $Config{sitelib}/sitecustomize.pl you'll get what you are looking for.
See:
http://perldoc.perl.org/perlrun.html
http://www.nntp.perl.org/group/perl.perl5.porters/2007/10/msg129926.html

I'm confused by what you mean by "on start up". If you mean when a script / CGI / whatever is "started", then just use the module in the script:
use Data::Dumper;
Or do you mean something else?

Related

How do I make a perl script run another perl script?

I am writing a large Perl script, which needs to utilize other existing Perl scripts. The problem is the main script needs to reference many different scripts from different folders. For example the main script would be contained in:
/perl/programs/io
It may need to run a script which is stored in:
/perl/programs/tools
Note that there are other orthogonal folders besides tools so I need to be able to access any of them on the fly.
Currently this is what I got:
my $mynumber = '../tools/convert.pl bin2dec 1011';
In theory it should move back from the io directory then enter the appropriate tool directory and call the convert.pl script while passing it the parameters.
All this does is store the string in the single quotes to $myNumber.
I like to assign the output of a command to an array so I can loop through the array to find error or other messages. For example if I'm making a zip file to email to someone I want to check to see if the zip program had any errors before I continue to make and send the email.
#msgs = `zip -f myfile.zip *.pl`; # Use backticks
You can also assign the output to a scalar:
$msg = `ls -al *.pl`; # Use backticks
To run any system command or script all you have to do is use `backticks`. From observing another programer's perl code, I misread these strange quotes for 'single quotes'.
backticks are also nice because they return the text in STDOUT to your perl script so that the output can be assigned to a variable, something I have found impossible if using system("");
The similar question answer does not work with my version of perl. The line
use IPC::System::Simple qw(system capture);
throws some errors. However just using system works, like this:
my $mynumber = system($^X, "../tools/convert.pl", 'bin2dec', '1011');
I can use the above without setting equal to something to execute scripts which return no value and are only sent arguments.
This seems to be the easiest way to do what I need to and the entire programs folder can be moved anywhere and it will still work as no parent directories above programs are used.

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?

Calling an application from a perl script

I would like to call an application from a perl script using the 'system' command. However, the application is placed in a separate directory. How can I call the application from that directory in my perl script. Can I use "require"?
You can just change directory if you want to run the application in the directory where the application resides. See the chdir command in perlfunc.
Otherwise, just add the path like this:
system('/path/to/the/application');
No, require doesn't work -- require is used to pull in other perl files, once. If, of course, the file you'd like to call to is a perl program ... well, it's probably better to factor out the parts you'd like to be shared between the two programs, rather than requireing it, or to simply treat it as a black box anyway if you don't want to do that.
To call an executable which is neither in the search path -- simply being in the same directory is not sufficient! -- supply the full path to, e.g. system, exec, &c.. For system, the preferred forms would be:
system { '/path/to/executable' } 'argument 0 (i.e. $0) supplied to program', 'argument 1 (equivalent to $ARGV[0])', ...;
or
# $path = ...
system $path 'arg 0', 'arg 1', ...;
or
# $path = ...
system $path #args;
Of course, it is good form to check the result of each system call in case of errors.
Note the use of indirect-object (i.e. with an argument passed without comma, like the fh for a print or such) system in every case! Unless you know very well what you're doing and why, it's hard to recommend risk using the one-argument form of system, because it subjects your input to the whims of shell preprocessing.
Consult perldoc -fsystem and perldoc -fexec for more detail.

Why doesn't "use lib" take effect in this way?

In my app, I put all the modules in one directory , let's just call it libx.
Since it's up to the user to choose where to deploy the app, I don't want to hardcode the lib path.
So at the beginning of myapp.pl, I wrote the following lines of code.
#! /usr/bin/perl -w
use strict;
my $curr_dir = $0;
my $curr_lib = $curr_dir;
$curr_lib =~ s/myapp\.pl/libx/;
use $curr_lib ;
Instead of getting what I'm expecting, I got compiling errors!
So what's wrong with my code? I don't want to hardcode the lib path when using use lib, how should I do this?
Sorry I forgot to mention that when the app is deployed, myapp.pl and libx are in the same directory.
use happens at compile-time, not run-time, so your variable hasn't been set yet.
You can do:
my $curr_lib;
BEGIN {
$curr_lib = $0;
$curr_lib =~ s/myapp\.pl/libx/;
}
use lib $curr_lib;
or you could:
use FindBin;
use lib "$FindBin::Bin/libx";
I had trouble with this before too. What's happening is that Perl makes two passes over your code: once to compile it, and the second time to run it. In you example, lines 4,5, and 6 don't execute until run time, but use takes effect during compile time.
One possibility is to put it all inside a BEGIN{} block, which will make the code execute at compile time. I've done this, but it's messy/ugly. (BTW, instead of $0, you need to use $ARGV[0] in Perl).
The best way to tell Perl where to pick up libraries is to use the -I flag. You can put it on the #! line, or if you are starting the script from another script, you can start it as
perl -I/your/directory/libx your_script.pl
You can use relative paths, so maybe
perl -I./libx script.pl
would work for you.
use xxx is a compile-time directive, not a run-time instruction. You cannot set it programmatically within the script you are running.
You may need to try require rather than use
If you need use, you need to set your $PERL5LIB environment variable to ensure your modules are correctly located and used, or change your shebang line to read #! /usr/local/perl -w -I/path/to/libx. There are other methods (local::lib etc.), but from your question it seems your control over installation is a bit limited for that sort of approach.

How can I determine if a script was called from the command line or as a cgi script?

I have a script that I wrote that can either be used on the command line or as a CGI script, and need to determine how the script was called so I can output a content-type header for web requests (and maybe some anti-cache headers too). My first thought is to check for the existance of http environment variables:
my $js = build_javascript();
if ( exists $ENV{HTTP_HOST} ) {
print "Content-type: text/javascript\n\n";
}
print $js;
Is there a better way?
According to the CGI specification in RFC3875 (section 4.1.4.), the GATEWAY_INTERFACE environment variable would be the authoritative thing to check whether you are running in a CGI context:
4.1.4. GATEWAY_INTERFACE
The GATEWAY_INTERFACE variable MUST be set to the dialect of CGI
being used by the server to communicate with the script.
There's really no way good way to tell if your script was started by a web server or from the command line. Any of the environment variables can be set in both situations. I often run CGI programs straight from the command line to test them, for instance.
Knowing that, if you want to pick one environment variable to use, it just has to be one that you won't set in the other situation, or one that you set in both but give different values to. In that case, choose any environment variable that you like.
If you want to get more sophisicated, you can use something like IO::Interactive to determine if you're connected to a terminal. If you aren't, the filehanandle that is_interactive returns is a null filehandle and the output goes nowhere:
print { is_interactive() } $http_header;
If you don't like how IO::Interactive decides, you can reimplement is_interactive. It's a very short piece of code and the higher-level interface is very nice.
I usually do a little trick at the beginning of my module:
exit run(#ARGV) unless caller(); # run directly if called from command line
sub run
{
process_options(#_);
...
}
sub process_options {
#ARGV = #_;
my %opts;
GetOptions(\%opts,
...
}
The module does not have to be named "run".