flobo flobo - 4 months ago 22
Perl Question

Sgf2dg and Perl: Use of uninitialized value $_ in pattern match (m//)

As the title of my question suggests, I encountered the following problem:


Use of uninitialized value $_ in pattern match (m//)


in line 1416 of Sgf2Dg.pm
of the sgf2dg package.
There it says:

} elsif (($arg eq '-break') or ($arg eq '-breakList')) {
my $breaks = '';
while (@ARGV and
$ARGV[0] =! m/[\d,]*/) {
$breaks .= shift @ARGV;
}
@{$option{breakList}} = sort {$a <=> $b} split(/,/, $breaks);


Therefore I suppose the problem has something to do with the pattern match
=! m/[\d,]*/
, but I don't know enough
perl
to deal with this myself, nor enough to present you with a simple MWE :(




I have installed sgf2dg and it runs without a problem. I can use all the options except for the
-break
one, but that's the one I want. On Linux terminal:


sgf2dg -break 0 test.sgf


where
test.sgf
is a typical smart game format file. Without the
-break 0
option it runs without any problem.

For your convenience I attach an sgf file here:

(;GM[1]FF[4]CA[UTF-8]AP[CGoban:3]ST[2]
RU[Japanese]SZ[19]KM[0.00]
AW[qm][oo][po][qo][ro][op][mq][oq][or]AB[pp][qp][rp][pq][pr]PL[W]
;W[rr]
;B[rs]
;W[rq]
;B[sp]
;W[ps]
;B[qs]
;W[os]
;B[qr]
;W[sq]
;B[sr]
;W[ss])

Answer

That's a bug in the code.

$ARGV[0] =! m/[\d,]*/ really means $ARGV[0] = (! m/[\d,]*/), i.e. assign the negated result of m/[\d,]*/ to $ARGV[0]. And m/[\d,]*/ matches against $_ by default, but $_ isn't set at that point.

The less-incorrect code would be $ARGV[0] =~ m/[\d,]*/ (a match of [\d,]* against $ARGV[0]), but that's semantically wrong: [\d,]* always matches, so that condition would be always true.

It looks like it's supposed to check that the argument consists of digits and commas only, for which the correct code would be $ARGV[0] =~ m/\A[\d,]+\z/.


However, according to the documentation, -break only accepts one argument, so that whole block could be replaced by:

} elsif (($arg eq '-break') or ($arg eq '-breakList')) {
    my $breaks = shift @ARGV;
    @{$option{breakList}} = sort {$a <=> $b} split(/,/, $breaks);