I need to use sys/ioctl.ph and it's not included in the perl version (5.12.3) shipped with my slackware distribution.
I did the following:
cd /usr/include
h2ph sys/ioctl.ph
cd /usr/lib64/perl5/site_perl/5.12.3/x86_64-linux-thread-multi/
mkdir sys
mv ioctl.ph sys
Now the perl interpreter doesn't complain about the sys/ioctl.ph, but this is the error I get:
Illegal declaration of subroutine Functions::ServerSocket::__INT16_C at /usr/lib64/perl5/site_perl/5.12.3/x86_64-linux-thread-multi/_h2ph_pre.ph line 164.
This is what there's in the file that causes the error at line 164:
unless (defined &__INT16_C(c)) { sub __INT16_C(c)() { &c } }
I don't know where to start. Functions::ServerSocket is one of my module, but I don't have any function like that in my file.
The __INT16_C macro on your platform is probably simple, e.g.,
#define __INT16_C(c) c
Replace the code on line 164 with
eval 'sub __INT16_C {
my($c) = #_;
eval q($c);
}' unless defined (&__INT16_C);
which is what other versions of h2ph generate.
Related
Whenever I start the perl debugger from a script with a -d option, the session starts with emacs command line editing. I then type ESC ctrl J to enable vi editing. I want to enable vi from the get-go.
I tried using the following .perldb:
&parse_options("HistFile=.perlDebugHist");
sub afterinit { push #DB::typeahead, ("o inhibit_exit", chr(27).chr(10)) }
but when the session starts, it says
auto(-2) DB<62> o inhibit_exit
inhibit_exit = '1'
auto(-1) DB<63>
Unrecognized character \x1B; marked by <-- HERE after :db_stop;
<-- HERE near column 96 at (eval 9)[/usr/share/perl/5.22/perl5db.pl:737] line 2.
at (eval 9)[/usr/share/perl/5.22/perl5db.pl:737] line 2.
eval 'no strict; ($#, $!, $^E, $,, $/, $\\, $^W) = #DB::saved;package main; $^D = $^D | $DB::db_stop;
;
' called at /usr/share/perl/5.22/perl5db.pl line 737
DB::eval called at /usr/share/perl/5.22/perl5db.pl line 3110
DB::DB called at ~/bin/debug.pl line 61
Here is a possible workaround that assumes you use the gnu readline library:
Create a file called perldb_inputrc in the current directory with content:
set editing-mode vi
Then change the afterinit() sub to:
sub afterinit {
if (!$DB::term) {
DB::setterm();
}
$DB::term->read_init_file('perldb_inputrc');
push #DB::typeahead, "o inhibit_exit";
}
See perldoc perl5db for more information.
Update:
A simpler approach is to the readline init file. You can use a global file ~/.inputrc or a use a local one for the current debugging session only by setting the environment variable INPUTRC. For example, using the above perldb_inputrc file as an example, you could use (in your .perldb init file):
sub afterinit { push #DB::typeahead, "o inhibit_exit" }
and then run the Perl script like this:
INPUTRC=./perldb_inputrc perl -d myscript.pl
According to perldoc, String Eval should be performed in the current scope. But the following simple test seems to contradict this.
We need the following two simple files to set up the test. Please put them under the same folder.
test_eval_scope.pm
package test_eval_scope;
use strict;
use warnings;
my %h = (a=>'b');
sub f1 {
eval 'print %h, "\n"';
# print %h, "\n"; # this would work
# my $dummy = \%h; # adding this would also work
}
1
test_eval_scope.pl
#!/usr/bin/perl
use File::Basename;
use lib dirname (__FILE__);
use test_eval_scope;
test_eval_scope::f1();
When I run the program, I got the following error
$ test_eval_scope.pl
Variable "%h" is not available at (eval 1) line 1.
My question is why the variable %h is out of scope.
I have done some modification, and found the following:
If I run without eval(), as in the above comment, it will work.
meaning that %h should be in the scope.
If I just add a seemingly useless mentioning in the code, as in the above
comment, eval() will work too.
If I combine pl and pm file into one file, eval() will work too.
If I declare %h with 'our' instead of 'my', eval() will work too.
I encountered this question when I was writing a big program which parsed user-provided code during run time. I don't need solutions as I have plenty workarounds above. But I cannot explain why the above code doesn't work. This affects my perl pride.
My perl version is v5.26.1 on linux.
Thank you for your help!
Subs only capture variables they use. Since f1 doesn't use %h, it doesn't capture it, and %h becomes inaccessible to f1 after it goes out of scope when the module finishes executing.
Any reference to the var, including one that's optimized away, causes the sub to capture the variable. As such, the following does work:
sub f1 {
%h if 0;
eval 'print %h, "\n"';
}
Demo:
$ perl -M5.010 -we'
{
my $x = "x";
sub f { eval q{$x} }
sub g { $x if 0; eval q{$x} }
}
say "f: ", f();
say "g: ", g();
'
Variable "$x" is not available at (eval 1) line 1.
Use of uninitialized value in say at -e line 8.
f:
g: x
I want to call "env.sh " from "my_perl.pl" without forking a subshell. I tried with backtics and system like this --> system (. env.sh) [dot space env.sh] , however wont work.
Child environments cannot change parent environments. Your best bet is to parse env.sh from inside the Perl code and set the variables in %ENV:
#!/usr/bin/perl
use strict;
use warnings;
sub source {
my $name = shift;
open my $fh, "<", $name
or die "could not open $name: $!";
while (<$fh>) {
chomp;
my ($k, $v) = split /=/, $_, 2;
$v =~ s/^(['"])(.*)\1/$2/; #' fix highlighter
$v =~ s/\$([a-zA-Z]\w*)/$ENV{$1}/g;
$v =~ s/`(.*?)`/`$1`/ge; #dangerous
$ENV{$k} = $v;
}
}
source "env.sh";
for my $k (qw/foo bar baz quux/) {
print "$k => $ENV{$k}\n";
}
Given
foo=5
bar=10
baz="$foo$bar"
quux=`date +%Y%m%d`
it prints
foo => 5
bar => 10
baz => 510
quux => 20110726
The code can only handle simple files (for instance, it doesn't handle if statements or foo=$(date)). If you need something more complex, then writing a wrapper for your Perl script that sources env.sh first is the right way to go (it is also probably the right way to go in the first place).
Another reason to source env.sh before executing the Perl script is that setting the environment variables in Perl may happen too late for modules that are expecting to see them.
In the file foo:
#!/bin/bash
source env.sh
exec foo.real
where foo.real is your Perl script.
You can use arbitrarily complex shell scripts by executing them with the relevant shell, dumping their environment to standard output in the same process, and parsing that in perl. Feeding the output into something other than %ENV or filtering for specific values of interest is prudent so you don't change things like PATH that may have interesting side effects elsewhere. I've discarded standard output and error from the spawned shell script although they could be redirected to temporary files and used for diagnostic output in the perl script.
foo.pl:
#!/usr/bin/perl
open SOURCE, "bash -c '. foo.sh >& /dev/null; env'|" or
die "Can't fork: $!";
while(<SOURCE>) {
if (/^(BAR|BAZ)=(.*)/) {
$ENV{$1} = ${2} ;
}
}
close SOURCE;
print $ENV{'BAR'} . "\n";
foo.sh:
export BAR=baz
Try this (unix code sample):
cd /tmp
vi s
#!/bin/bash
export blah=test
vi t
#!/usr/bin/perl
if ($ARGV[0]) {
print "ENV second call is : $ENV{blah}\n";
} else {
print "ENV first call is : $ENV{blah}\n";
exec(". /tmp/s; /tmp/t 1");
}
chmod 777 s t
./t
ENV first call is :
ENV second call is : test
The trick is using the exec to source your bash script first and then calling your perl script again with an argument so u know that you are being called for a second time.
I use a Perl(loader.vim) script to load VIM modules: (.vimrc) source /whatever/loader.vim
loader.vim:
function! LoadBundles()
perl HERE
while(</root/.vim/bundle/*/plugin/*>) {
my ($path, $fname) =($_ =~ m|^(.+/)(.+?)$|);
#VIM::Msg("$path $fname\n");
VIM::DoCommand("set runtimepath=$path");
VIM::DoCommand("runtime! $fname");
}
HERE
endfunction
call LoadBundles()
I'd like to do something like LoadBundles('/path/to/bundledir') but to do this I need to be able to read a variable from within Perl eg:
function! LoadBundles(path)
let var = a:path
perl HERE
print "$var\n";
How do I do this???
I'd also like to save the runtimepath within perl HERE and then restore it. How do I read runtimepath from within perl HERE?
Here's how you can get at the "runtimepath" option from embedded Perl:
perl VIM::Msg( VIM::Eval('&runtimepath') )
Do the following to get more from the docs:
:help if_perl.txt
Then search for "VIM::Eval". So try:
function! AnExample(arg)
perl << EOF
VIM::Msg( VIM::Eval('a:arg') )
EOF
endfunction
And then to test:
:so %
:call AnExample("hello")
Perl code is looks like --
sub report_generation($)
{
Shell_sh $ARGV[0] $conn_string $pm_dir/$FILE
}
$ARGV[0] -- > command line argument of perl script
$conn_string --> used in perl script value define in perl script
my $USR=$ARGV[1];
my $PSS=$ARGV[2];
my $INS=$ARGV[3];
my $conn_string=$USR."/".$PSS."\#".$INS;
$pm_dir/$FILE --> want to give file name with file path "$pm_dir/$FILE"
my $pm_dir="$ENV{'ABP_PM_ROOT'}/interfaces/output/report/$date";
my $FILE= 'FILE_NAME_'.$ARGV[0].'_'.get_timestamp().'.dat';
my $db_conn =DBI->connect( 'dbi:Oracle:'. $INS, $USR, $PSS, {AutoCommit => 0 })|| ExitProcess4 (1,$Function_Name ,$DBI::err, $DBI::errstr );
report_generation($db_conn);
See system() or ``
Use an array to hold the arguments, and then:
system #array;
There are a number of advantages to that mechanism - notably that you do not have to escape everything to prevent the shell interpreting the arguments before you call it.