I realize similar questions have been asked. However, in this case I wish to use this open source perl script:
https://github.com/bAndie91/tools/blob/master/usr/bin/indent2tree
This line is producing the error Experimental push on scalar is now forbidden at /usr/local/bin/indent2tree line 43, near "};"
push $ForkPoint->{subtree}, {data=>$data, parent=>$ForkPoint, subtree=>[]};
I am not very familiar with Perl. I did check several questions on this topic and I tried to fix the issue a few different ways without success.
For example:
push #ForkPoint->{subtree}, {data=>$data, parent=>$ForkPoint, subtree=>[]};
That still produces the error.
Since my goal here is to just use the tool, maybe someone who is familiar with Perl can share the solution. I opened a bug at the project issue page.
You need
push #{ $ForkPoint->{subtree} }, ...
Whenever you can use the name of a variable, you can use a block that evaluates to a reference instead. That means the following are valid syntax for specifying an array:
#NAME # If you have the name
#BLOCK # If you have a reference
That means that the following two snippets are equivalent:
push #arary, ...
my $ref = \#array;
push #{ $ref }, ...
While not relevant in this case, you can omit the curlies when the only thing in the block is a simple scalar ($NAME or $BLOCK).
push #$ref, ...
See Perl Dereferencing Syntax.
Related
To enforce clean and explicit code, I customarily
use strict;
when programming Perl.
I would like to keep this habit in perltex, too.
So where should I put this use strict; statement so that it governs all successive \perldo, \perlnewcommand, \perlnewenvironment, \perlrenewcommand and \perlrenewenvironment invocations in the perltex input file?
The following perltex example file runs without raising an error:
\documentclass[12pt]{article}
\usepackage{perltex}
\perldo{
my $scalar = "ok";
our #array = qw( array is fine );
%HASH = (
subject => "hash",
result => "perfect"
);
use strict;
}
\perlnewcommand\printscalar{
return $scalar;
}
\perlnewcommand\printarray{
return join ", ", #array;
}
\perlnewcommand\printhash{
return join ", ", map { sprintf "%s = %s", $_, $HASH{$_} } keys %HASH;
}
\begin{document}
Scalar: \printscalar
Array: \printarray
Hash: \printhash
\end{document}
It produces something similar to
That no error is raised shows that use strict; in the top \perldo argument is disregarded in the definition of \printscalar. The result also shows that the setting of $scalar was not known there any more because of the my. To avoid such mistakes, I would wish to receive an error
Global symbol "$scalar" requires explicit package name
whenever I forget to specify my or our when introducing a new variable.
A workaround to my problem is to include the statement
use strict;
in all \perldo, ... commands, and this can be done using macros. Nevertheless I wonder whether there is no possibility to avoid such re-statements.
The perltex CTAN documentation gives in section 3.2.3 a list of the loaded modules and pragmas. These include use strict;.
The docs are a little unclear on when this is the default, but it appears to be under --nosafe. Then this option should be the way to toggle it and get those defaults loaded.
Did you try setting it only in the first command used (like \perldo)? That may well be enough.
The --permit option allows "features" described in Opcode module to be specified, what is done using the module Safe. While I don't see how to directly make use of this, the discussion under Safe::reval method may be helpful.
I don't have the module installed here and can't try. I hope that this is of some use.
As the final resort, why not contact the author? You may have revealed a bug (in documentation), since the observed behavior seems to conflict the docs. Also, this may well be feasible to add.
I am calling a perl subroutine
&ProcessInput($line, \%txcountershash, \%txhash);
I have this definition:
sub ProcessInput() {
my $word;
my $counterkey;
my $line = $_[0];
my $countershash = $_[1];
my $outputhash = $_[2];
# remove all the blanks from the line
$line =~ s/\s+//g;
my ($port,$counter,$value,$datetime) = split('\|',$line,4);
my $counterdesc = $countershash{$counter};
the line that causes the problem is the last line. It says that global symbol %countershash requires explicit package name. I'm not sure why it's giving me the error. There aren't any problems otherwise, if I comment that line out the script runs. The hash is set up as an error code for a key and a description that is the value. I'm trying to get the value at a particular key in $countershash so I can add the error description to the output hash.
The problem is dereferencing. you should dereference the hash inside the subroutine
my $counterdesc = $countershash->{$counter};
-> this is called arrow operator which is used to deference the array and hashes.
The code $counterhash{$counter} means "look up the key $counter in the hash %counterhash". You don't have a hash called %counterhash, you have a hash reference in a scalar variable called $counterhash. %counterhash and $counterhash are two completely different variables.
In order to look up an element in a hash reference, you need to use different syntax.
my $counterdesc = $countershash->{$counter};
Please don't use the $$countershash{$counter} syntax (previously) used in another answer. That will only confuse whoever needs to maintain your code in six months time (which might well be you).
File::Find and the wanted subroutine
This question is much simpler than the original title ("prototypes and forward declaration of subroutines"!) lets on. I'm hoping the answer, however simple, will help me understand subroutines/functions, prototypes and scoping and the File::Find module.
With Perl, subroutines can appear pretty much anywhere and you normally don't need to make forward declarations (except if the sub declares a prototype, which I'm not sure how to do in a "standard" way in Perl). For what I usually do with Perl there's little difference between these different ways of running somefunction:
sub somefunction; # Forward declares the function
&somefunction;
somefunction();
somefunction; # Bare word warning under `strict subs`
I often use find2perl to generate code which I crib/hack into parts of scripts. This could well be bad style and now my dirty laundry is public, but so be it :-) For File::Find the wanted function is a required subroutine - find2perl creates it and adds sub wanted; to the resulting script it creates. Sometimes, when I edit the script I'll remove the "sub" from sub wanted and it ends up as &wanted; or wanted();. But without the sub wanted; forward declaration form I get this warning:
Use of uninitialized value $_ in lstat at findscript.pl line 29
My question is: why does this happen and is it a real problem? It is "just a warning", but I want to understand it better.
The documentation and code say $_ is localized inside of sub wanted {}. Why would it be undefined if I use wanted(); instead of sub wanted;?
Is wanted using prototypes somewhere? Am I missing something obvious in Find/File.pm?
Is it because wanted returns a code reference? (???)
My guess is that the forward declaration form "initializes" wanted in some way so that the first use doesn't have an empty default variable. I guess this would be how prototypes - even Perl prototypes, such as they exist - would work as well. I tried grepping through the Perl source code to get a sense of what sub is doing when a function is called using sub function instead of function(), but that may be beyond me at this point.
Any help deepening (and speeding up) my understanding of this is much appreciated.
EDIT: Here's a recent example script here on Stack Overflow that I created using find2perl's output. If you remove the sub from sub wanted; you should get the same error.
EDIT: As I noted in a comment below (but I'll flag it here too): for several months I've been using Path::Iterator::Rule instead of File::Find. It requires perl >5.10, but I never have to deploy production code at sites with odd, "never upgrade", 5.8.* only policies so Path::Iterator::Rule has become one of those modules I never want to do with out. Also useful is Path::Class. Cheers.
I'm not a big fan of File::Find. It just doesn't work right. The find command doesn't return a list of files, so you either have to use a non-local array variable in your find to capture your list of files you've found (not good), or place your entire program in your wanted subroutine (even worse). Plus, the separate subroutine means that your logic is separate from your find command. It's just ugly.
What I do is inline my wanted subroutine inside my find command. Subroutine stays with the find. Plus, my non-local array variable is now just part of my find command and doesn't look so bad
Here's how I handle the File::Find -- assuming I want files that have a .pl suffix:
my #file_list;
find ( sub {
return unless -f; #Must be a file
return unless /\.pl$/; #Must end with `.pl` suffix
push #file_list, $File::Find::name;
}, $directory );
# At this point, #file_list contains all of the files I found.
This is exactly the same as:
my #file_list;
find ( \&wanted, $directory );
sub wanted {
return unless -f;
return unless /\.pl$/;
push #file_list, $File::Find::name;
}
# At this point, #file_list contains all of the files I found.
In lining just looks nicer. And, it keep my code together. Plus, my non-local array variable doesn't look so freaky.
I also like taking advantage of the shorter syntax in this particular way. Normally, I don't like using the inferred $_, but in this case, it makes the code much easier to read. My original Wanted is the same as this:
sub wanted {
my $file_name = $_;
if ( -f $file_name and $file_name =~ /\.pl$/ ) {
push #file_list, $File::Find::name;
}
}
File::Find isn't that tricky to use. You just have to remember:
When you find a file you don't want, you use return to go to the next file.
$_ contains the file name without the directory, and you can use that for testing the file.
The file's full name is $File::Find::name.
The file's directory is $File::Find::dir.
And, the easiest way is to push the files you want into an array, and then use that array later in your program.
Removing the sub from sub wanted; just makes it a call to the wanted function, not a forward declaration.
However, the wanted function hasn't been designed to be called directly from your code - it's been designed to be called by File::Find. File::Find does useful stuff like populating$_ before calling it.
There's no need to forward-declare wanted here, but if you want to remove the forward declaration, remove the whole sub wanted; line - not just the word sub.
Instead of File::Find, I would recommend using the find_wanted function from File::Find::Wanted.
find_wanted takes two arguments:
a subroutine that returns true for any filename that you would want.
a list of the files you are searching for.
find_wanted returns an array containing the list of filenames that it found.
I used code like the following to find all the JPEG files in certain directories on a computer:
my #files = find_wanted( sub { -f && /\.jpg$/i }, #dirs );
Explanation of some of the syntax, for those that might need it:
sub {...} is an anonymous subroutine, where ... is replaced with the code of the subroutine.
-f checks that a filename refers to a "plain file"
&& is boolean and
/\.jpg$/i is a regular expression that checks that a filename ends in .jpg (case insensitively).
#dirs is an array containing the directory names to be searched. A single directory could be searched as well, in which case a scalar works too (e.g. $dir).
Why not use open and invoke the shell find? The user can edit $findcommand (below) to be anything they want, or can define it in real time based on arguments and options passed to a script.
#!/usr/bin/perl
use strict; use warnings;
my $findcommand='find . -type f -mtime 0';
open(FILELIST,"$findcommand |")||die("can't open $findcommand |");
my #filelist=<FILELIST>;
close FILELIST;
my $Nfilelist = scalar(#filelist);
print "Number of files is $Nfilelist \n";
I've following two statements written in perl :
#m1 = ( [1,2,3],[4,5,6],[7,8,9] ); # It is an array of references.
$mr = [ [1,2,3],[4,5,6],[7,8,9] ]; # It is an anonymous array. $mr holds reference.
When I try to print:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr->[0][1]\n"; #this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
I feel second and third print statements are same. However, I didn't any output with third print statement.
Can anyone let me know what is wrong with third print statement?
This is simple. $mr is a reference. So you use the Arrow Operator to dereference.
Also, if you would use use warnings; use strict;, you would have received a somewhat obvious error message:
Global symbol "#mr" requires explicit package name
$mr is a scalar variable whose value is a reference to a list. It is not a list, and it can't be used as if it was a list. The arrow is needed to access the list it refers to.
But hold on, $m1[0] is also not a list, but a reference to one. You may be wondering why you don't have to write an arrow between the indexes, like $m1[0]->[1]. There's a special rule that says you can omit the arrow when accessing list or hash elements in a list or hash of references, so you can write $mr->[0][1] instead of $mr->[0]->[1] and $m1[0][1] instead of $m1[0]->[1].
$mr holds a reference (conceptually similar to the address of a variable in compiled languages). thus you have an extra level of indirection. replace $mrwith $$mr and you'll be fine.
btw, you can easily check questions like these by browsing for tutorials on perldoc.
You said:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
Notice how you used the same syntax both times.
As you've established by this first line, this syntax accesses the array named: #m1 and #mr. You have no variable named #mr, so you get undef for $mr[0][1].
Maybe you don't realizes that scalar $mr and array #mr have no relation to each other.
Please use use strict; use warnings; to avoid these and many other errors.
I'm hitting a bug in the SVN perl module when using git:
Bizarre copy of UNKNOWN in subroutine entry at
/usr/lib/perl5/vendor_perl/SVN/Base.pm line 80.
And I'm not quite sure if this is a perl bug or a subversion bug. This is the relevant part:
# insert the accessor
if (m/(.*)_get$/) {
my $member = $1;
*{"${caller}::$1"} = sub {
&{"SVN::_${pkg}::${prefix}${member}_". # <<<< line 80
(#_ > 1 ? 'set' : 'get')} (#_)
}
}
(full source)
What is a "Bizarre copy"? And whose fault is it?
Edit: software versions
subversion 1.6.15-1
perl 5.14.0-1
Resolution: This happens when you compile with incompatible flags:
https://groups.google.com/d/msg/subversion_users/EOru50ml6sk/5xrbu3luPk4J
That perldoc gives you the short answer, but a brief STFW session yields a little more detail. This is basically evidence of a smashed stack in Perl.
Trivial example:
#!/usr/bin/perl
my #A = 1..5;
sub blowUp {
undef #A;
my $throwAway = {};
print for #_; # <== line 6
}
blowUp(#A);
__END__
bash$ ./blowitup
Bizarre copy of HASH in print at ./blowitup line 6.
And to make it that much more entertaining, without the $throwAway assignment, it's an invisible error (though under 'use warnings' it will at least still tell you that you're trying to access an uninitialized value). It's just when you make a new assignment that you see the strange behavior.
Since #_ is essentially lexically scoped to the subroutine, and arguments are passed by reference, that little subroutine basically pulls the rug out from under itself by undef'ing the thing that #_ was pointing to (you get the same behavior if you change the undef to an assignment, fwiw). I've found a number of postings on perl5-porters that mention this as an artifact of the fact that items on the stack are not reference counted and therefore not cleanly freed.
So while I haven't looked through all of the code in your full source in depth, I'll go ahead and guess that something in there is messing with something that was passed in on #_ ; then when #_ is referenced again, Perl is telling you that something's rotten in Denmark.
The immediate problem is a bug in the script/module, iow. The deeper issue of Perl not reference counting these items is also there, but I suspect you'll have better luck fixing the module in the short term. :-)
HTH-
Brian
A "Bizarre copy" occurs when Perl's stack is corrupted or contains non-scalars. It occurs as the result of bugs in Perl itself or in XS modules. (Brian Gerard's example exercises one of a long list of known bugs related to the stack not being ref-counted.)
You could isolate the problem by adding the following to the anon sub:
warn("Calling SVN::_${pkg}::${prefix}${member}_".(#_ > 1 ? 'set' : 'get')."...");
You might even want to emit a stack trace, but you might have to build it yourself using caller to avoid triggering the panic when building the stack trace.
Probably a perl bug. SVN::Base has XS components, but the error is occurring in pure-perl code and it's my opinion that perl should never allow it to happen. However, it's possible that there's some weird XS in SVN::Base that's tweaking it.
Best idea: file it against Subversion subcomponent bindings_swig_perl and perlbug both.