File Coverage

blib/lib/Log/Report/Lexicon/POTcompact.pm
Criterion Covered Total %
statement 77 82 93.9
branch 39 50 78.0
condition 11 17 64.7
subroutine 16 17 94.1
pod 5 6 83.3
total 148 172 86.0


line stmt bran cond sub pod time code
1             # Copyrights 2007-2018 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             # This code is part of distribution Log-Report-Lexicon. Meta-POD processed
6             # with OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package Log::Report::Lexicon::POTcompact;
10 6     6   541 use vars '$VERSION';
  6         11  
  6         273  
11             $VERSION = '1.11';
12              
13 6     6   27 use base 'Log::Report::Lexicon::Table';
  6         9  
  6         1575  
14              
15 6     6   32 use warnings;
  6         7  
  6         108  
16 6     6   22 use strict;
  6         9  
  6         108  
17              
18 6     6   33 use Log::Report 'log-report-lexicon';
  6         10  
  6         33  
19 6     6   1083 use Log::Report::Util qw/escape_chars unescape_chars/;
  6         10  
  6         242  
20              
21 6     6   25 use Encode qw/find_encoding/;
  6         9  
  6         5941  
22              
23             sub _unescape($$);
24             sub _escape($$);
25              
26              
27             sub read($@)
28 12     12 1 517 { my ($class, $fn, %args) = @_;
29              
30 12         19 my $self = bless {}, $class;
31              
32 12         15 my $charset = $args{charset};
33              
34             # Try to pick-up charset from the filename (which may contain a modifier)
35 12 50 66     41 $charset = $1
36             if !$charset && $fn =~ m!\.([\w-]+)(?:\@[^/\\]+)?\.po$!i;
37              
38 12         11 my $fh;
39 12 100       18 if($charset)
40 1 50   1   25 { open $fh, "<:encoding($charset):crlf", $fn
  1         5  
  1         1  
  1         5  
41             or fault __x"cannot read in {charset} from file {fn}"
42             , charset => $charset, fn => $fn;
43             }
44             else
45 11 50       409 { open $fh, '<:raw:crlf', $fn
46             or fault __x"cannot read from file {fn} (unknown charset)", fn=>$fn;
47             }
48              
49             # Speed!
50 12         969 my $msgctxt = '';
51 12         15 my ($last, $msgid, @msgstr);
52 12   50     57 my $index = $self->{index} ||= {};
53              
54             my $add = sub {
55 225 100   225   256 unless($charset)
56 11 50       13 { $msgid eq ''
57             or error __x"header not found for charset in {fn}", fn => $fn;
58 11 50       53 $charset = $msgstr[0] =~ m/^content-type:.*?charset=["']?([\w-]+)/mi
59             ? $1 : error __x"cannot detect charset in {fn}", fn => $fn;
60 11 50       25 my $enc = find_encoding($charset)
61             or error __x"unsupported charset {charset} in {fn}"
62             , charset => $charset, fn => $fn;
63              
64 11         2702 trace "auto-detected charset $charset for $fn";
65 11         222 $fh->binmode(":encoding($charset):crlf");
66              
67 11         1234 $_ = $enc->decode($_) for @msgstr, $msgctxt;
68             }
69              
70 225 100       709 $index->{"$msgid#$msgctxt"} = @msgstr > 1 ? [@msgstr] : $msgstr[0];
71 225         376 ($msgctxt, $msgid, @msgstr) = ('');
72 12         53 };
73              
74             LINE:
75 12         235 while(my $line = $fh->getline)
76 1103 100       25298 { next if substr($line, 0, 1) eq '#';
77              
78 801 100       1426 if($line =~ m/^\s*$/) # blank line starts new
79 232 100       475 { $add->() if @msgstr;
80 232         3050 next LINE;
81             }
82              
83 569 50 66     2108 if($line =~ s/^msgctxt\s+//)
    100          
    100          
    100          
    100          
84 0         0 { $msgctxt = _unescape $line, $fn;
85 0         0 $last = \$msgctxt;
86             }
87             elsif($line =~ s/^msgid\s+//)
88 225         336 { $msgid = _unescape $line, $fn;
89 225         3731 $last = \$msgid;
90             }
91             elsif($line =~ s/^msgstr\[(\d+)\]\s*//)
92 4         6 { $last = \($msgstr[$1] = _unescape $line, $fn);
93             }
94             elsif($line =~ s/^msgstr\s+//)
95 224         294 { $msgstr[0] = _unescape $line, $fn;
96 224         4209 $last = \$msgstr[0];
97             }
98             elsif($last && $line =~ m/^\s*\"/)
99 115         164 { $$last .= _unescape $line, $fn;
100             }
101             }
102 12 100       319 $add->() if @msgstr; # don't forget the last
103              
104 12 50       131 close $fh
105             or failure __x"failed reading from file {fn}", fn => $fn;
106              
107 12         29 $self->{origcharset} = $charset;
108 12         32 $self->{filename} = $fn;
109 12         43 $self->setupPluralAlgorithm;
110 12         139 $self;
111             }
112              
113             #------------------
114              
115 22     22 1 2886 sub filename() {shift->{filename}}
116 11     11 1 36 sub originalCharset() {shift->{origcharset}}
117              
118             #------------------
119              
120 0     0 0 0 sub index() {shift->{index}}
121             # The index is a HASH with "$msg#$msgctxt" keys. If there is no
122             # $msgctxt, then there still is the #
123              
124              
125 26   50 26 1 169 sub msgid($) { $_[0]->{index}{$_[1].'#'.($_[2]//'')} }
126              
127              
128             # speed!!!
129             sub msgstr($;$$)
130 13     13 1 900 { my ($self, $msgid, $count, $ctxt) = @_;
131              
132 13   50     75 $ctxt //= '';
133 13 50       35 my $po = $self->{index}{"$msgid#$ctxt"}
134             or return undef;
135              
136 13 100       31 ref $po # no plurals defined
137             or return $po;
138              
139 9 50 50     152 $po->[$self->{algo}->($count // 1)] || $po->[$self->{algo}->(1)];
140             }
141              
142             #
143             ### internal helper routines, shared with ::PO.pm and ::POT.pm
144             #
145              
146             sub _unescape($$)
147 686 50   686   1654 { unless( $_[0] =~ m/^\s*\"(.*)\"\s*$/ )
148 0         0 { warning __x"string '{text}' not between quotes at {location}"
149             , text => $_[0], location => $_[1];
150 0         0 return $_[0];
151             }
152 686         1114 unescape_chars $1;
153             }
154              
155             sub _escape($$)
156 64 100 100 64   352 { my @escaped = map { '"' . escape_chars($_) . '"' }
  100         740  
157             defined $_[0] && length $_[0] ? split(/(?<=\n)/, $_[0]) : '';
158              
159 64 100       472 unshift @escaped, '""' if @escaped > 1;
160 64         195 join $_[1], @escaped;
161             }
162              
163             1;