File Coverage

lib/Games/Checkers/PDNParser.pm
Criterion Covered Total %
statement 12 57 21.0
branch 0 28 0.0
condition 0 12 0.0
subroutine 4 7 57.1
pod 0 3 0.0
total 16 107 14.9


line stmt bran cond sub pod time code
1             # Games::Checkers, Copyright (C) 1996-2012 Mikhael Goikhman, migo@cpan.org
2             #
3             # This program is free software: you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation, either version 3 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program. If not, see .
15              
16 1     1   1589 use strict;
  1         3  
  1         32  
17 1     1   5 use warnings;
  1         3  
  1         33  
18              
19             package Games::Checkers::PDNParser;
20              
21 1     1   6 use Games::Checkers::LocationConversions;
  1         2  
  1         78  
22 1     1   909 use IO::File;
  1         12092  
  1         1214  
23              
24             sub new ($$) {
25 0     0 0   my $class = shift;
26 0           my $filename = shift;
27              
28             -r "$filename.$_" and $filename .= ".$_"
29 0   0       for qw(pdn.gz pdn.xz pdn.bz2 pdn gz xz bz2);
30 0 0         my $file_to_open =
    0          
    0          
31             $filename =~ /\.gz$/ ? "zcat $filename |" :
32             $filename =~ /\.xz$/ ? "xzcat $filename |" :
33             $filename =~ /\.bz2$/ ? "bzcat $filename |" :
34             $filename;
35 0           my $fd = new IO::File $file_to_open;
36 0 0         die "Can't open PDN for reading ($filename)\n" unless $fd;
37              
38 0           my $self = { fn => $filename, fd => $fd, lineno => 0 };
39 0           bless $self, $class;
40 0           return $self;
41             }
42              
43             sub error_prefix {
44 0     0 0   my $self = shift;
45 0           "Error parsing $self->{fn}, line $self->{lineno}, corrupted record:\n";
46             }
47              
48             sub next_record ($) {
49 0     0 0   my $self = shift;
50              
51 0           my $record_values = {};
52              
53 0           my $line;
54 0           my $not_end = 0;
55 0           while ($line = $self->{fd}->getline) {
56 0           $self->{lineno}++;
57 0 0         next if $line =~ /^\s*(([#;]|{.*}|\(.*\))\s*)?$/;
58 0           $not_end = 1;
59 0 0         if ($line =~ /\[(\w+)\s+"?(.*?)"?\]/) {
60 0           $record_values->{$1} = $2;
61 0           next;
62             }
63 0           last;
64             }
65 0 0         return undef unless $not_end;
66              
67 0           my $result = $record_values->{Result};
68 0 0         die $self->error_prefix . "\tNon empty named value 'Result' is missing\n"
69             unless $result;
70 0           my $lineno = $self->{lineno};
71              
72 0           my $move_string = "";
73 0   0       while (!$move_string || ($line = $self->{fd}->getline) && $self->{lineno}++) {
      0        
74 0           $line =~ s/[\r\n]+$/ /;
75 0           $move_string .= $line;
76 0 0         last if $line =~ /$result/;
77              
78             # tolerate some broken PDNs without trailing result separator
79 0           my $next_char = $self->{fd}->getc;
80 0           $self->{fd}->ungetc(ord($next_char));
81 0 0         last if $next_char eq "[";
82             }
83              
84             # tolerate some broken PDNs without result separator
85             # die $self->error_prefix . "\tSeparator ($result) is not found from line $lineno\n"
86             # unless $line;
87              
88 0           $move_string =~ s/\b$result\b.*//;
89 0           $move_string =~ s/{[^}]*}//g; # remove comments
90 0           $move_string =~ s/\([^\)]*(\)[^(]*)?\)//g; # remove comments
91 0           $move_string =~ s/([x:*-])\s+(\d|\w)/$1$2/gi; # remove alignment spaces
92 0           my @move_verge_strings = split(/(?:\s+|\d+\.\s*)+/, $move_string);
93 0   0       shift @move_verge_strings while @move_verge_strings && !$move_verge_strings[0];
94              
95 0 0         my @move_verge_trios = map {
96 0           /^((\d+)|\w\d)([x:*-])((\d+)|\w\d)$/i
97             || die $self->error_prefix . "\tIncorrect move notation ($_)\n";
98             [
99 0 0         $3 eq "-" ? 0 : 1,
    0          
    0          
100             defined $2 ? num_to_location($1) : str_to_location($1),
101             defined $5 ? num_to_location($4) : str_to_location($4),
102             ]
103             } @move_verge_strings;
104              
105 0           return [ \@move_verge_trios, $record_values ];
106             }
107              
108             1;