line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Locale::MakePhrase::BackingStore::File; |
2
|
|
|
|
|
|
|
our $VERSION = 0.3; |
3
|
|
|
|
|
|
|
our $DEBUG = 0; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
Locale::MakePhrase::BackingStore::File - Retrieve language |
8
|
|
|
|
|
|
|
translations for all supported languages, from a single file. |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 DESCRIPTION |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
This backing store is capable of loading language rules from a |
13
|
|
|
|
|
|
|
single translation file. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
The file must be formatted as shown in the B file (which |
16
|
|
|
|
|
|
|
can be located in the same directories that these modules are are |
17
|
|
|
|
|
|
|
installed in). The important points to note are that the file is |
18
|
|
|
|
|
|
|
broken into groups containing: |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=over 2 |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=item B |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=item B |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=item B |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=item B |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=item B |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Where expression & priority are optional. However, if you specify the |
33
|
|
|
|
|
|
|
priority and/or expression, make sure the translation key is the last |
34
|
|
|
|
|
|
|
entry in the group - this is necessary, as we dont know when the |
35
|
|
|
|
|
|
|
the block is finished. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=back |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 API |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
The following methods are implemented: |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
44
|
|
|
|
|
|
|
|
45
|
6
|
|
|
6
|
|
14317
|
use strict; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
278
|
|
46
|
6
|
|
|
6
|
|
41
|
use warnings; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
314
|
|
47
|
6
|
|
|
6
|
|
37
|
use utf8; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
78
|
|
48
|
6
|
|
|
6
|
|
165
|
use Data::Dumper; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
505
|
|
49
|
6
|
|
|
6
|
|
56
|
use base qw(Locale::MakePhrase::BackingStore); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
687
|
|
50
|
6
|
|
|
6
|
|
1718
|
use I18N::LangTags; |
|
6
|
|
|
|
|
8428
|
|
|
6
|
|
|
|
|
305
|
|
51
|
6
|
|
|
6
|
|
80
|
use Locale::MakePhrase::Utils qw(die_from_caller alltrim); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
11967
|
|
52
|
|
|
|
|
|
|
our $implicit_data_structure = [ "key","language","expression","priority","translation" ]; |
53
|
|
|
|
|
|
|
our $default_encoding = 'utf-8'; |
54
|
|
|
|
|
|
|
local $Data::Dumper::Indent = 1 if $DEBUG; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head2 $self new([...]) |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
We support loading text/translations (from the translation file) which |
61
|
|
|
|
|
|
|
may be encoded using any character encoding. Since we need to know |
62
|
|
|
|
|
|
|
something about the file we are trying to load, we expect this object |
63
|
|
|
|
|
|
|
to be constructed with the following options: |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=over 2 |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item C |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
The full path to the file containing the translations. eg: |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
/usr/local/myapp/translations.mpt |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Default: none; you must specify a filename |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item C |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
We can load translations from any enocding supported by the L |
78
|
|
|
|
|
|
|
module. Upon load, this module will convert the translations from |
79
|
|
|
|
|
|
|
the specified encoding, into the interal encoding of UTF-8. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Default: load UTF-8 encoded text translations. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item C |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
It is handy for the language module to be able to dynamically reload |
86
|
|
|
|
|
|
|
its known translations, if the file gets updated. You can set this |
87
|
|
|
|
|
|
|
to avoid reloading the file if it changes. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Default: reload if file changes |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=back |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub new { |
96
|
5
|
|
|
5
|
1
|
2100
|
my $proto = shift; |
97
|
5
|
|
33
|
|
|
42
|
my $class = ref($proto) || $proto; |
98
|
5
|
|
|
|
|
27
|
my $self = bless {}, $class; |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# get options |
101
|
5
|
|
|
|
|
13
|
my %options; |
102
|
5
|
50
|
33
|
|
|
65
|
if (@_ > 1 and not(@_ % 2)) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
103
|
5
|
|
|
|
|
22
|
%options = @_; |
104
|
|
|
|
|
|
|
} elsif (@_ == 1 and ref($_[0]) eq 'HASH') { |
105
|
0
|
|
|
|
|
0
|
%options = %{$_[0]}; |
|
0
|
|
|
|
|
0
|
|
106
|
|
|
|
|
|
|
} elsif (@_ == 1) { |
107
|
0
|
|
|
|
|
0
|
$options{file} = shift; |
108
|
|
|
|
|
|
|
} |
109
|
5
|
50
|
|
|
|
22
|
print STDERR "Arguments to ". ref($self) .": ". Dumper(\%options) if $DEBUG > 5; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# allow sub-class to control construction |
112
|
5
|
|
|
|
|
71
|
$self = $self->init(); |
113
|
5
|
50
|
|
|
|
47
|
return undef unless $self; |
114
|
|
|
|
|
|
|
|
115
|
5
|
50
|
|
|
|
27
|
$self->{file} = (exists $options{file}) ? $options{file} : $self->{file}; |
116
|
5
|
50
|
|
|
|
36
|
$self->{encoding} = (exists $options{encoding}) ? $options{encoding} : (exists $self->{encoding}) ? $self->{encoding} : $default_encoding; |
|
|
50
|
|
|
|
|
|
117
|
5
|
0
|
|
|
|
45
|
$self->{reload} = (exists $options{reload}) ? ($options{reload} ? 1 : 0) : (exists $self->{reload}) ? ($self->{reload} ? 1 : 0) : 1; |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
118
|
5
|
|
|
|
|
13
|
$self->{rules} = {}; |
119
|
5
|
|
|
|
|
16
|
$self->{mtime} = 0; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# make sure file exists |
122
|
5
|
50
|
|
|
|
19
|
die_from_caller("Missing 'file' definition") unless (defined $self->{file}); |
123
|
5
|
50
|
|
|
|
161
|
die_from_caller("No such translation file:",$self->{file}) unless (-e $self->{file}); |
124
|
5
|
50
|
|
|
|
21
|
die_from_caller("Invalid encoding specified") unless $self->{encoding}; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Pre-load all available languages |
127
|
5
|
|
|
|
|
25
|
$self->_load_file(); |
128
|
|
|
|
|
|
|
|
129
|
5
|
|
|
|
|
34
|
return $self; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 \@rule_objs get_rules($context,$key,\@languages) |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Retrieve the translations (that have been previously loaded), using the |
137
|
|
|
|
|
|
|
selected languages. This implementation will reload the language file |
138
|
|
|
|
|
|
|
if it changes (unless it has been told not to). |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub get_rules { |
143
|
23
|
|
|
23
|
1
|
37
|
my ($self,$context,$key,$languages) = @_; |
144
|
23
|
|
|
|
|
28
|
my @translations; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# make sure languages are loaded |
147
|
23
|
50
|
|
|
|
84
|
$self->_load_file() unless $self->{dont_reload}; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# look for rules for each language in the current key |
150
|
23
|
|
|
|
|
27
|
my @langs; |
151
|
23
|
|
|
|
|
35
|
my $rules = $self->{rules}; |
152
|
23
|
|
|
|
|
42
|
foreach my $language (@$languages) { |
153
|
46
|
50
|
|
|
|
107
|
next unless (exists $rules->{$language}); |
154
|
46
|
|
|
|
|
99
|
push @langs, $rules->{$language}; |
155
|
|
|
|
|
|
|
} |
156
|
23
|
50
|
|
|
|
58
|
return undef unless @langs; |
157
|
23
|
|
|
|
|
35
|
$rules = undef; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Only use rules which match this context, if we are using a context |
160
|
23
|
50
|
|
|
|
42
|
if ($context) { |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# look for rules that match the key |
163
|
0
|
|
|
|
|
0
|
foreach my $language (@langs) { |
164
|
0
|
|
|
|
|
0
|
my $keys = $language->{$key}; |
165
|
0
|
0
|
0
|
|
|
0
|
next unless ($keys or ref($keys) ne 'HASH'); |
166
|
0
|
|
|
|
|
0
|
$keys = $keys->{$context}; |
167
|
0
|
0
|
|
|
|
0
|
next unless $keys; |
168
|
0
|
|
|
|
|
0
|
foreach my $ky (@$keys) { |
169
|
0
|
|
|
|
|
0
|
push @translations, $ky; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
} else { |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# look for rules that match the key |
176
|
23
|
|
|
|
|
32
|
foreach my $language (@langs) { |
177
|
46
|
|
|
|
|
76
|
my $keys = $language->{$key}; |
178
|
46
|
100
|
|
|
|
114
|
next unless $keys; |
179
|
14
|
|
|
|
|
21
|
$keys = $keys->{_}; |
180
|
14
|
|
|
|
|
23
|
foreach my $ky (@$keys) { |
181
|
28
|
|
|
|
|
70
|
push @translations, $ky; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
23
|
50
|
|
|
|
100
|
print STDERR "Found translations:\n", Dumper(@translations) if $DEBUG; |
188
|
23
|
|
|
|
|
90
|
return \@translations; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
192
|
|
|
|
|
|
|
# The following methods are not part of the API - they are private. |
193
|
|
|
|
|
|
|
# |
194
|
|
|
|
|
|
|
# This means that everything above this code-break is allowed/designed |
195
|
|
|
|
|
|
|
# to be overloaded. |
196
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
199
|
|
|
|
|
|
|
# |
200
|
|
|
|
|
|
|
# If the file hasn't yet been loaded or its mtime has changed, load it into the cache. |
201
|
|
|
|
|
|
|
# |
202
|
|
|
|
|
|
|
sub _load_file { |
203
|
28
|
|
|
28
|
|
41
|
my ($self) = @_; |
204
|
28
|
|
|
|
|
45
|
my $file = $self->{file}; |
205
|
28
|
50
|
33
|
|
|
945
|
die_from_caller("Incorrect permissions on translation file:",$file) unless ((-f $file || -l $file) and -r $file); |
|
|
|
33
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# if mtime is same as previous, do nothing |
208
|
28
|
|
|
|
|
397
|
my $mtime = (stat($file))[9]; |
209
|
28
|
100
|
|
|
|
121
|
return if ($mtime == $self->{mtime}); |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# ... mtime has changed -> reload the file |
212
|
5
|
|
|
|
|
18
|
$self->{mtime} = $mtime; |
213
|
5
|
|
|
|
|
14
|
$self->{rules} = undef; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Load the translations from the file (skip empty lines, or comments) |
216
|
5
|
|
|
|
|
13
|
my $rules = {}; |
217
|
5
|
|
|
|
|
11
|
my ($key,$language,$expression,$priority,$translation,$context); |
218
|
5
|
|
|
|
|
9
|
my $in_group = 0; |
219
|
5
|
|
|
|
|
11
|
my $line = 0; |
220
|
5
|
|
|
|
|
10
|
my $encoding = $self->{encoding}; |
221
|
5
|
|
|
|
|
10
|
my $fh; |
222
|
5
|
50
|
|
5
|
|
242
|
open ($fh, "<:encoding($encoding)", "$file") || die_from_caller("Failed to open translation file:",$file); |
|
5
|
|
|
|
|
5790
|
|
|
5
|
|
|
|
|
61
|
|
|
5
|
|
|
|
|
28
|
|
223
|
|
|
|
|
|
|
|
224
|
5
|
|
|
|
|
8196
|
while (<$fh>) { |
225
|
355
|
|
|
|
|
757
|
chomp; |
226
|
355
|
|
|
|
|
524
|
s/
//; |
227
|
355
|
|
|
|
|
351
|
$line++; |
228
|
355
|
|
|
|
|
824
|
$_ = alltrim($_); |
229
|
355
|
100
|
66
|
|
|
2563
|
next if (not defined or length == 0 or /^#/); |
|
|
|
100
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# search for group entries |
232
|
210
|
|
|
|
|
634
|
/^ |
233
|
|
|
|
|
|
|
([^=]*)=(.*) |
234
|
|
|
|
|
|
|
| |
235
|
|
|
|
|
|
|
(.*) |
236
|
|
|
|
|
|
|
$/sx; |
237
|
210
|
50
|
|
|
|
560
|
next unless ($1); |
238
|
210
|
|
|
|
|
513
|
my $lhs = alltrim($1); |
239
|
210
|
|
|
|
|
496
|
my $rhs = alltrim($2); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# process group entries |
242
|
210
|
100
|
66
|
|
|
1287
|
if ($lhs eq 'key') { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
243
|
50
|
50
|
|
|
|
117
|
die_from_caller("Found another group while processing previous group, file '$file' line '$line'") if ($in_group); |
244
|
50
|
|
|
|
|
53
|
$in_group++; |
245
|
50
|
|
|
|
|
68
|
$key = $rhs; |
246
|
50
|
50
|
|
|
|
104
|
die_from_caller("Key must have some length, file '$file' line '$line'") unless (length $key); |
247
|
|
|
|
|
|
|
# $line += _read_lines($fh,\$key); |
248
|
50
|
|
|
|
|
306
|
next; |
249
|
|
|
|
|
|
|
} elsif ($lhs eq 'language' and not defined $language) { |
250
|
50
|
|
|
|
|
78
|
$language = $rhs; |
251
|
50
|
|
|
|
|
87
|
$language =~ tr<_A-Z><-a-z>; # support the variations case/hyphenation for language/locale |
252
|
50
|
50
|
|
|
|
108
|
die_from_caller("Language must have some length, file '$file' line '$line'") unless (length $language); |
253
|
50
|
50
|
|
|
|
149
|
die_from_caller("Must be valid language tag, file '$file' line '$line'") unless (I18N::LangTags::is_language_tag($language)); |
254
|
50
|
|
|
|
|
550
|
$language =~ tr<-><_>; |
255
|
|
|
|
|
|
|
} elsif ($lhs eq 'expression' and not defined $expression) { |
256
|
30
|
|
|
|
|
44
|
$expression = $rhs; |
257
|
|
|
|
|
|
|
} elsif ($lhs eq 'priority' and not defined $priority) { |
258
|
30
|
|
|
|
|
46
|
$priority = $rhs; |
259
|
30
|
|
|
|
|
58
|
$priority = int($priority); # must be a valid number |
260
|
|
|
|
|
|
|
} elsif ($lhs eq 'translation' and not defined $translation) { |
261
|
50
|
|
|
|
|
70
|
$translation = $rhs; |
262
|
50
|
50
|
|
|
|
118
|
die_from_caller("Translation must have some length, file '$file' line '$line'") unless (length $translation); |
263
|
|
|
|
|
|
|
# $line += _read_lines($fh,\$translation); |
264
|
|
|
|
|
|
|
} elsif ($lhs eq 'context' and not defined $context) { |
265
|
0
|
|
|
|
|
0
|
$context = $rhs; |
266
|
|
|
|
|
|
|
} else { |
267
|
0
|
|
|
|
|
0
|
die_from_caller("Syntax error in translation file '$file', line '$line'"); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Have we enough info to make a linguistic rule? |
271
|
160
|
100
|
66
|
|
|
902
|
next unless (defined $language and $translation); |
272
|
50
|
100
|
|
|
|
106
|
$expression = "" unless $expression; |
273
|
50
|
100
|
|
|
|
87
|
$priority = 0 unless $priority; |
274
|
50
|
50
|
|
|
|
91
|
$context = "" unless $context; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# Make this linguistic rule, and add it to any others that may exist for this language/key |
277
|
50
|
|
|
|
|
55
|
$in_group--; |
278
|
50
|
|
|
|
|
48
|
my $entries; |
279
|
50
|
50
|
|
|
|
90
|
if ($context) { |
280
|
0
|
|
|
|
|
0
|
$entries = $rules->{$language}{$key}{$context}; |
281
|
0
|
0
|
|
|
|
0
|
unless ($entries) { |
282
|
0
|
0
|
|
|
|
0
|
$entries = [] unless $entries; |
283
|
0
|
|
|
|
|
0
|
$rules->{$language}{$key}{$context} = $entries; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} else { |
286
|
50
|
|
|
|
|
182
|
$entries = $rules->{$language}{$key}{_}; |
287
|
50
|
100
|
|
|
|
110
|
unless ($entries) { |
288
|
30
|
50
|
|
|
|
108
|
$entries = [] unless $entries; |
289
|
30
|
|
|
|
|
99
|
$rules->{$language}{$key}{_} = $entries; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} |
292
|
50
|
|
|
|
|
227
|
push @$entries, $self->make_rule( |
293
|
|
|
|
|
|
|
key => $key, |
294
|
|
|
|
|
|
|
language => $language, |
295
|
|
|
|
|
|
|
expression => $expression, |
296
|
|
|
|
|
|
|
priority => $priority, |
297
|
|
|
|
|
|
|
translation => $translation, |
298
|
|
|
|
|
|
|
); |
299
|
|
|
|
|
|
|
|
300
|
50
|
|
|
|
|
278
|
$key = $language = $expression = $priority = $translation = $context = undef; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
5
|
|
|
|
|
173
|
close $fh; |
304
|
5
|
|
|
|
|
57
|
$self->{rules} = $rules; |
305
|
5
|
50
|
|
|
|
53
|
print STDERR "Loaded the following languages rules:\n", Dumper($rules) if $DEBUG > 7; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
#-------------------------------------------------------------------------- |
309
|
|
|
|
|
|
|
# |
310
|
|
|
|
|
|
|
# Helper routine for reading multiple lines for a given key |
311
|
|
|
|
|
|
|
# |
312
|
|
|
|
|
|
|
sub _read_lines { |
313
|
0
|
|
|
0
|
|
0
|
my ($fh,$s_ref); |
314
|
0
|
|
|
|
|
0
|
my $line = 0; |
315
|
0
|
0
|
|
|
|
0
|
if ($$s_ref =~ /\/$/) { |
316
|
0
|
|
|
|
|
0
|
while (<$fh>) { |
317
|
0
|
|
|
|
|
0
|
chomp; |
318
|
0
|
|
|
|
|
0
|
s/^M$//; |
319
|
0
|
|
|
|
|
0
|
$line++; |
320
|
0
|
|
|
|
|
0
|
$_ = alltrim($_); |
321
|
0
|
0
|
|
|
|
0
|
if (/\.\s*\\$/) { |
322
|
0
|
|
|
|
|
0
|
$$s_ref =~ s/\s*\/$/\n/; |
323
|
|
|
|
|
|
|
} else { |
324
|
0
|
|
|
|
|
0
|
$$s_ref =~ s/\s*\/$/ /; |
325
|
|
|
|
|
|
|
} |
326
|
0
|
|
|
|
|
0
|
$$s_ref .= $_; |
327
|
0
|
0
|
|
|
|
0
|
last unless ($$s_ref =~ /\/$/); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} |
330
|
0
|
|
|
|
|
0
|
return $line; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
1; |
334
|
|
|
|
|
|
|
__END__ |