Filename | /usr/share/perl5/Locale/Maketext/Lexicon.pm |
Statements | Executed 14 statements in 1.94ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 16µs | 16µs | BEGIN@3 | Locale::Maketext::Lexicon::
1 | 1 | 1 | 9µs | 18µs | BEGIN@205 | Locale::Maketext::Lexicon::
1 | 1 | 1 | 7µs | 17µs | BEGIN@128 | Locale::Maketext::Lexicon::
1 | 1 | 1 | 7µs | 15µs | BEGIN@264 | Locale::Maketext::Lexicon::
1 | 1 | 1 | 6µs | 17µs | BEGIN@4 | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | CLEAR | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | DELETE | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | EXISTS | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | FETCH | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | FIRSTKEY | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | NEXTKEY | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | SCALAR | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | STORE | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | TIEHASH | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | __ANON__[:176] | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | __ANON__[:195] | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | _force | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | _style_gettext | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | encoding | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | import | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_find | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get_ | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get_array | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get_glob | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get_hash | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | lexicon_get_scalar | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | option | Locale::Maketext::Lexicon::
0 | 0 | 0 | 0s | 0s | set_option | Locale::Maketext::Lexicon::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Locale::Maketext::Lexicon; | ||||
2 | 1 | 400ns | $Locale::Maketext::Lexicon::VERSION = '1.00'; | ||
3 | 2 | 41µs | 1 | 16µs | # spent 16µs within Locale::Maketext::Lexicon::BEGIN@3 which was called:
# once (16µs+0s) by Locale::Maketext::Simple::load_loc at line 3 # spent 16µs making 1 call to Locale::Maketext::Lexicon::BEGIN@3 |
4 | 2 | 708µs | 2 | 28µs | # spent 17µs (6+11) within Locale::Maketext::Lexicon::BEGIN@4 which was called:
# once (6µs+11µs) by Locale::Maketext::Simple::load_loc at line 4 # spent 17µs making 1 call to Locale::Maketext::Lexicon::BEGIN@4
# spent 11µs making 1 call to strict::import |
5 | |||||
6 | # ABSTRACT: Use other catalog formats in Maketext | ||||
7 | |||||
8 | |||||
9 | 1 | 200ns | our %Opts; | ||
10 | sub option { shift if ref( $_[0] ); $Opts{ lc $_[0] } } | ||||
11 | sub set_option { shift if ref( $_[0] ); $Opts{ lc $_[0] } = $_[1] } | ||||
12 | |||||
13 | sub encoding { | ||||
14 | my $encoding = option( @_, 'encoding' ) or return; | ||||
15 | return $encoding unless lc($encoding) eq 'locale'; | ||||
16 | |||||
17 | local $^W; # no warnings 'uninitialized', really. | ||||
18 | my ( $country_language, $locale_encoding ); | ||||
19 | |||||
20 | local $@; | ||||
21 | eval { | ||||
22 | require I18N::Langinfo; | ||||
23 | $locale_encoding | ||||
24 | = I18N::Langinfo::langinfo( I18N::Langinfo::CODESET() ); | ||||
25 | } or eval { | ||||
26 | require Win32::Console; | ||||
27 | $locale_encoding = 'cp' . Win32::Console::OutputCP(); | ||||
28 | }; | ||||
29 | if ( !$locale_encoding ) { | ||||
30 | foreach my $key (qw( LANGUAGE LC_ALL LC_MESSAGES LANG )) { | ||||
31 | $ENV{$key} =~ /^([^.]+)\.([^.:]+)/ or next; | ||||
32 | ( $country_language, $locale_encoding ) = ( $1, $2 ); | ||||
33 | last; | ||||
34 | } | ||||
35 | } | ||||
36 | if ( defined $locale_encoding | ||||
37 | && lc($locale_encoding) eq 'euc' | ||||
38 | && defined $country_language ) | ||||
39 | { | ||||
40 | if ( $country_language =~ /^ja_JP|japan(?:ese)?$/i ) { | ||||
41 | $locale_encoding = 'euc-jp'; | ||||
42 | } | ||||
43 | elsif ( $country_language =~ /^ko_KR|korean?$/i ) { | ||||
44 | $locale_encoding = 'euc-kr'; | ||||
45 | } | ||||
46 | elsif ( $country_language =~ /^zh_CN|chin(?:a|ese)?$/i ) { | ||||
47 | $locale_encoding = 'euc-cn'; | ||||
48 | } | ||||
49 | elsif ( $country_language =~ /^zh_TW|taiwan(?:ese)?$/i ) { | ||||
50 | $locale_encoding = 'euc-tw'; | ||||
51 | } | ||||
52 | } | ||||
53 | |||||
54 | return $locale_encoding; | ||||
55 | } | ||||
56 | |||||
57 | sub import { | ||||
58 | my $class = shift; | ||||
59 | return unless @_; | ||||
60 | |||||
61 | my %entries; | ||||
62 | if ( UNIVERSAL::isa( $_[0], 'HASH' ) ) { | ||||
63 | |||||
64 | # a hashref with $lang as keys, [$format, $src ...] as values | ||||
65 | %entries = %{ $_[0] }; | ||||
66 | } | ||||
67 | elsif ( @_ % 2 == 0 ) { | ||||
68 | %entries = ( '' => [ splice @_, 0, 2 ], @_ ); | ||||
69 | } | ||||
70 | |||||
71 | # expand the wildcard entry | ||||
72 | if ( my $wild_entry = delete $entries{'*'} ) { | ||||
73 | while ( my ( $format, $src ) = splice( @$wild_entry, 0, 2 ) ) { | ||||
74 | next if ref($src); # XXX: implement globbing for the 'Tie' backend | ||||
75 | |||||
76 | my $pattern = quotemeta($src); | ||||
77 | $pattern =~ s/\\\*(?=[^*]+$)/\([-\\w]+\)/g or next; | ||||
78 | $pattern =~ s/\\\*/.*?/g; | ||||
79 | $pattern =~ s/\\\?/./g; | ||||
80 | $pattern =~ s/\\\[/[/g; | ||||
81 | $pattern =~ s/\\\]/]/g; | ||||
82 | $pattern =~ s[\\\{(.*?)\\\\}][ | ||||
83 | '(?:'.join('|', split(/,/, $1)).')' | ||||
84 | ]eg; | ||||
85 | |||||
86 | require File::Glob; | ||||
87 | foreach my $file ( File::Glob::bsd_glob($src) ) { | ||||
88 | $file =~ /$pattern/ or next; | ||||
89 | push @{ $entries{$1} }, ( $format => $file ) if $1; | ||||
90 | } | ||||
91 | delete $entries{$1} | ||||
92 | unless !defined($1) | ||||
93 | or exists $entries{$1} and @{ $entries{$1} }; | ||||
94 | } | ||||
95 | } | ||||
96 | |||||
97 | %Opts = (); | ||||
98 | foreach my $key ( grep /^_/, keys %entries ) { | ||||
99 | set_option( lc( substr( $key, 1 ) ) => delete( $entries{$key} ) ); | ||||
100 | } | ||||
101 | my $OptsRef = {%Opts}; | ||||
102 | |||||
103 | while ( my ( $lang, $entry ) = each %entries ) { | ||||
104 | my $export = caller; | ||||
105 | |||||
106 | if ( length $lang ) { | ||||
107 | |||||
108 | # normalize language tag to Maketext's subclass convention | ||||
109 | $lang = lc($lang); | ||||
110 | $lang =~ s/-/_/g; | ||||
111 | $export .= "::$lang"; | ||||
112 | } | ||||
113 | |||||
114 | my @pairs = @{ $entry || [] } or die "no format specified"; | ||||
115 | |||||
116 | while ( my ( $format, $src ) = splice( @pairs, 0, 2 ) ) { | ||||
117 | if ( defined($src) and !ref($src) and $src =~ /\*/ ) { | ||||
118 | unshift( @pairs, $format => $_ ) | ||||
119 | for File::Glob::bsd_glob($src); | ||||
120 | next; | ||||
121 | } | ||||
122 | |||||
123 | my @content | ||||
124 | = eval { $class->lexicon_get( $src, scalar caller(1), $lang ); }; | ||||
125 | next if $@ and $@ =~ /^next\b/; | ||||
126 | die $@ if $@; | ||||
127 | |||||
128 | 2 | 397µs | 2 | 26µs | # spent 17µs (7+10) within Locale::Maketext::Lexicon::BEGIN@128 which was called:
# once (7µs+10µs) by Locale::Maketext::Simple::load_loc at line 128 # spent 17µs making 1 call to Locale::Maketext::Lexicon::BEGIN@128
# spent 10µs making 1 call to strict::unimport |
129 | eval "use $class\::$format; 1" or die $@; | ||||
130 | |||||
131 | if ( %{"$export\::Lexicon"} ) { | ||||
132 | my $lexicon = \%{"$export\::Lexicon"}; | ||||
133 | if ( my $obj = tied %$lexicon ) { | ||||
134 | |||||
135 | # if it's our tied hash then force loading | ||||
136 | # otherwise late load will rewrite | ||||
137 | $obj->_force if $obj->isa(__PACKAGE__); | ||||
138 | } | ||||
139 | |||||
140 | # clear the memoized cache for old entries: | ||||
141 | Locale::Maketext->clear_isa_scan; | ||||
142 | |||||
143 | my $new = "$class\::$format"->parse(@content); | ||||
144 | |||||
145 | # avoid hash rebuild, on big sets | ||||
146 | @{$lexicon}{ keys %$new } = values %$new; | ||||
147 | } | ||||
148 | else { | ||||
149 | local $^W if $] >= 5.009; # no warnings 'once', really. | ||||
150 | tie %{"$export\::Lexicon"}, __PACKAGE__, | ||||
151 | { | ||||
152 | Opts => $OptsRef, | ||||
153 | Export => "$export\::Lexicon", | ||||
154 | Class => "$class\::$format", | ||||
155 | Content => \@content, | ||||
156 | }; | ||||
157 | tied( %{"$export\::Lexicon"} )->_force | ||||
158 | if $OptsRef->{'preload'}; | ||||
159 | } | ||||
160 | |||||
161 | length $lang or next; | ||||
162 | |||||
163 | # Avoid re-entry | ||||
164 | my $caller = caller(); | ||||
165 | next if $export->isa($caller); | ||||
166 | |||||
167 | push( @{"$export\::ISA"}, scalar caller ); | ||||
168 | |||||
169 | if ( my $style = option('style') ) { | ||||
170 | my $cref | ||||
171 | = $class->can( lc("_style_$style") ) | ||||
172 | ->( $class, $export->can('maketext') ) | ||||
173 | or die "Unknown style: $style"; | ||||
174 | |||||
175 | # Avoid redefinition warnings | ||||
176 | local $SIG{__WARN__} = sub {1}; | ||||
177 | *{"$export\::maketext"} = $cref; | ||||
178 | } | ||||
179 | } | ||||
180 | } | ||||
181 | } | ||||
182 | |||||
183 | sub _style_gettext { | ||||
184 | my ( $self, $orig ) = @_; | ||||
185 | |||||
186 | require Locale::Maketext::Lexicon::Gettext; | ||||
187 | |||||
188 | sub { | ||||
189 | my $lh = shift; | ||||
190 | my $str = shift; | ||||
191 | return $orig->( | ||||
192 | $lh, | ||||
193 | Locale::Maketext::Lexicon::Gettext::_gettext_to_maketext($str), @_ | ||||
194 | ); | ||||
195 | } | ||||
196 | } | ||||
197 | |||||
198 | sub TIEHASH { | ||||
199 | my ( $class, $args ) = @_; | ||||
200 | return bless( $args, $class ); | ||||
201 | |||||
202 | } | ||||
203 | |||||
204 | { | ||||
205 | 3 | 406µs | 2 | 27µs | # spent 18µs (9+9) within Locale::Maketext::Lexicon::BEGIN@205 which was called:
# once (9µs+9µs) by Locale::Maketext::Simple::load_loc at line 205 # spent 18µs making 1 call to Locale::Maketext::Lexicon::BEGIN@205
# spent 9µs making 1 call to strict::unimport |
206 | |||||
207 | sub _force { | ||||
208 | my $args = shift; | ||||
209 | unless ( $args->{'Done'} ) { | ||||
210 | $args->{'Done'} = 1; | ||||
211 | local *Opts = $args->{Opts}; | ||||
212 | *{ $args->{Export} } | ||||
213 | = $args->{Class}->parse( @{ $args->{Content} } ); | ||||
214 | $args->{'Export'}{'_AUTO'} = 1 | ||||
215 | if option('auto'); | ||||
216 | } | ||||
217 | return $args->{'Export'}; | ||||
218 | } | ||||
219 | sub FETCH { _force( $_[0] )->{ $_[1] } } | ||||
220 | sub EXISTS { _force( $_[0] )->{ $_[1] } } | ||||
221 | sub DELETE { delete _force( $_[0] )->{ $_[1] } } | ||||
222 | sub SCALAR { scalar %{ _force( $_[0] ) } } | ||||
223 | sub STORE { _force( $_[0] )->{ $_[1] } = $_[2] } | ||||
224 | sub CLEAR { %{ _force( $_[0] )->{ $_[1] } } = () } | ||||
225 | sub NEXTKEY { each %{ _force( $_[0] ) } } | ||||
226 | |||||
227 | sub FIRSTKEY { | ||||
228 | my $hash = _force( $_[0] ); | ||||
229 | my $a = scalar keys %$hash; | ||||
230 | each %$hash; | ||||
231 | } | ||||
232 | } | ||||
233 | |||||
234 | sub lexicon_get { | ||||
235 | my ( $class, $src, $caller, $lang ) = @_; | ||||
236 | return unless defined $src; | ||||
237 | |||||
238 | foreach my $type ( qw(ARRAY HASH SCALAR GLOB), ref($src) ) { | ||||
239 | next unless UNIVERSAL::isa( $src, $type ); | ||||
240 | |||||
241 | my $method = 'lexicon_get_' . lc($type); | ||||
242 | die "cannot handle source $type for $src: no $method defined" | ||||
243 | unless $class->can($method); | ||||
244 | |||||
245 | return $class->$method( $src, $caller, $lang ); | ||||
246 | } | ||||
247 | |||||
248 | # default handler | ||||
249 | return $class->lexicon_get_( $src, $caller, $lang ); | ||||
250 | } | ||||
251 | |||||
252 | # for scalarrefs and arrayrefs we just dereference the $src | ||||
253 | sub lexicon_get_scalar { ${ $_[1] } } | ||||
254 | sub lexicon_get_array { @{ $_[1] } } | ||||
255 | |||||
256 | sub lexicon_get_hash { | ||||
257 | my ( $class, $src, $caller, $lang ) = @_; | ||||
258 | return map { $_ => $src->{$_} } sort keys %$src; | ||||
259 | } | ||||
260 | |||||
261 | sub lexicon_get_glob { | ||||
262 | my ( $class, $src, $caller, $lang ) = @_; | ||||
263 | |||||
264 | 2 | 387µs | 2 | 24µs | # spent 15µs (7+8) within Locale::Maketext::Lexicon::BEGIN@264 which was called:
# once (7µs+8µs) by Locale::Maketext::Simple::load_loc at line 264 # spent 15µs making 1 call to Locale::Maketext::Lexicon::BEGIN@264
# spent 8µs making 1 call to strict::unimport |
265 | local $^W if $] >= 5.009; # no warnings 'once', really. | ||||
266 | |||||
267 | # be extra magical and check for DATA section | ||||
268 | if ( eof($src) and $src eq \*{"$caller\::DATA"} | ||||
269 | or $src eq \*{"main\::DATA"} ) | ||||
270 | { | ||||
271 | |||||
272 | # okay, the *DATA isn't initiated yet. let's read. | ||||
273 | # | ||||
274 | require FileHandle; | ||||
275 | my $fh = FileHandle->new; | ||||
276 | my $package = ( ( $src eq \*{"main\::DATA"} ) ? 'main' : $caller ); | ||||
277 | |||||
278 | if ( $package eq 'main' and -e $0 ) { | ||||
279 | $fh->open($0) or die "Can't open $0: $!"; | ||||
280 | } | ||||
281 | else { | ||||
282 | my $level = 1; | ||||
283 | while ( my ( $pkg, $filename ) = caller( $level++ ) ) { | ||||
284 | next unless $pkg eq $package; | ||||
285 | next unless -e $filename; | ||||
286 | next; | ||||
287 | |||||
288 | $fh->open($filename) or die "Can't open $filename: $!"; | ||||
289 | last; | ||||
290 | } | ||||
291 | } | ||||
292 | |||||
293 | while (<$fh>) { | ||||
294 | |||||
295 | # okay, this isn't foolproof, but good enough | ||||
296 | last if /^__DATA__$/; | ||||
297 | } | ||||
298 | |||||
299 | return <$fh>; | ||||
300 | } | ||||
301 | |||||
302 | # fh containing the lines | ||||
303 | my $pos = tell($src); | ||||
304 | my @lines = <$src>; | ||||
305 | seek( $src, $pos, 0 ); | ||||
306 | return @lines; | ||||
307 | } | ||||
308 | |||||
309 | # assume filename - search path, open and return its contents | ||||
310 | sub lexicon_get_ { | ||||
311 | my ( $class, $src, $caller, $lang ) = @_; | ||||
312 | $src = $class->lexicon_find( $src, $caller, $lang ); | ||||
313 | defined $src or die 'next'; | ||||
314 | |||||
315 | require FileHandle; | ||||
316 | my $fh = FileHandle->new; | ||||
317 | $fh->open($src) or die "Cannot read $src (called by $caller): $!"; | ||||
318 | binmode($fh); | ||||
319 | return <$fh>; | ||||
320 | } | ||||
321 | |||||
322 | sub lexicon_find { | ||||
323 | my ( $class, $src, $caller, $lang ) = @_; | ||||
324 | return $src if -e $src; | ||||
325 | |||||
326 | require File::Spec; | ||||
327 | |||||
328 | my @path = split '::', $caller; | ||||
329 | push @path, $lang if length $lang; | ||||
330 | |||||
331 | while (@path) { | ||||
332 | foreach (@INC) { | ||||
333 | my $file = File::Spec->catfile( $_, @path, $src ); | ||||
334 | return $file if -e $file; | ||||
335 | } | ||||
336 | pop @path; | ||||
337 | } | ||||
338 | |||||
339 | return undef; | ||||
340 | } | ||||
341 | |||||
342 | 1 | 2µs | 1; | ||
343 | |||||
344 | __END__ |