| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package File::Find::utf8; |
|
2
|
4
|
|
|
4
|
|
95476
|
use strict; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
132
|
|
|
3
|
4
|
|
|
4
|
|
24
|
use warnings; |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
103
|
|
|
4
|
4
|
|
|
4
|
|
92
|
use 5.010; # state |
|
|
4
|
|
|
|
|
16
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Fully UTF-8 aware File::Find |
|
7
|
|
|
|
|
|
|
our $VERSION = '0.013'; # VERSION |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#pod =begin :prelude |
|
10
|
|
|
|
|
|
|
#pod |
|
11
|
|
|
|
|
|
|
#pod =for test_synopsis |
|
12
|
|
|
|
|
|
|
#pod my @directories_to_search; |
|
13
|
|
|
|
|
|
|
#pod |
|
14
|
|
|
|
|
|
|
#pod =end :prelude |
|
15
|
|
|
|
|
|
|
#pod |
|
16
|
|
|
|
|
|
|
#pod =head1 SYNOPSIS |
|
17
|
|
|
|
|
|
|
#pod |
|
18
|
|
|
|
|
|
|
#pod # Use the utf-8 versions of find and finddepth |
|
19
|
|
|
|
|
|
|
#pod use File::Find::utf8; |
|
20
|
|
|
|
|
|
|
#pod find(\&wanted, @directories_to_search); |
|
21
|
|
|
|
|
|
|
#pod |
|
22
|
|
|
|
|
|
|
#pod # Revert back to non-utf-8 versions |
|
23
|
|
|
|
|
|
|
#pod no File::Find::utf8; |
|
24
|
|
|
|
|
|
|
#pod finddepth(\&wanted, @directories_to_search); |
|
25
|
|
|
|
|
|
|
#pod |
|
26
|
|
|
|
|
|
|
#pod # Export only the find function |
|
27
|
|
|
|
|
|
|
#pod use File::Find::utf8 qw(find); |
|
28
|
|
|
|
|
|
|
#pod find(\&wanted, @directories_to_search); |
|
29
|
|
|
|
|
|
|
#pod |
|
30
|
|
|
|
|
|
|
#pod # Export no functions |
|
31
|
|
|
|
|
|
|
#pod use File::Find::utf8 qw(:none); # NOT "use File::Find::utf8 qw();"! |
|
32
|
|
|
|
|
|
|
#pod File::Find::find(\&wanted, @directories_to_search); |
|
33
|
|
|
|
|
|
|
#pod |
|
34
|
|
|
|
|
|
|
#pod =head1 DESCRIPTION |
|
35
|
|
|
|
|
|
|
#pod |
|
36
|
|
|
|
|
|
|
#pod While the original L functions are capable of handling |
|
37
|
|
|
|
|
|
|
#pod UTF-8 quite well, they expect and return all data as bytes, not as |
|
38
|
|
|
|
|
|
|
#pod characters. |
|
39
|
|
|
|
|
|
|
#pod |
|
40
|
|
|
|
|
|
|
#pod This module replaces the L functions with fully UTF-8 |
|
41
|
|
|
|
|
|
|
#pod aware versions, both expecting and returning characters. |
|
42
|
|
|
|
|
|
|
#pod |
|
43
|
|
|
|
|
|
|
#pod B Replacement of functions is not done on DOS, Windows, and OS/2 |
|
44
|
|
|
|
|
|
|
#pod as these systems do not have full UTF-8 file system support. |
|
45
|
|
|
|
|
|
|
#pod |
|
46
|
|
|
|
|
|
|
#pod =head2 Behaviour |
|
47
|
|
|
|
|
|
|
#pod |
|
48
|
|
|
|
|
|
|
#pod The module behaves as a pragma so you can use both C |
|
49
|
|
|
|
|
|
|
#pod File::Find::utf8> and C to turn utf-8 support on |
|
50
|
|
|
|
|
|
|
#pod or off. |
|
51
|
|
|
|
|
|
|
#pod |
|
52
|
|
|
|
|
|
|
#pod By default, both find() and finddepth() are exported (as with the original |
|
53
|
|
|
|
|
|
|
#pod L), if you want to prevent this, use C |
|
54
|
|
|
|
|
|
|
#pod qw(:none)>. (As all the magic happens in the module's import function, |
|
55
|
|
|
|
|
|
|
#pod you can not simply use C |
|
56
|
|
|
|
|
|
|
#pod |
|
57
|
|
|
|
|
|
|
#pod L warning levels are properly propagated. Note though that |
|
58
|
|
|
|
|
|
|
#pod for propagation of fatal L warnings, Perl 5.12 or higher |
|
59
|
|
|
|
|
|
|
#pod is required (or the appropriate version of L). |
|
60
|
|
|
|
|
|
|
#pod |
|
61
|
|
|
|
|
|
|
#pod =head1 COMPATIBILITY |
|
62
|
|
|
|
|
|
|
#pod |
|
63
|
|
|
|
|
|
|
#pod The filesystems of Dos, Windows, and OS/2 do not (fully) support |
|
64
|
|
|
|
|
|
|
#pod UTF-8. The L function will therefore not be replaced on these |
|
65
|
|
|
|
|
|
|
#pod systems. |
|
66
|
|
|
|
|
|
|
#pod |
|
67
|
|
|
|
|
|
|
#pod =head1 SEE ALSO |
|
68
|
|
|
|
|
|
|
#pod |
|
69
|
|
|
|
|
|
|
#pod =for :list |
|
70
|
|
|
|
|
|
|
#pod * L -- The original module. |
|
71
|
|
|
|
|
|
|
#pod * L -- Fully utf-8 aware version of the L functions. |
|
72
|
|
|
|
|
|
|
#pod * L -- Turn on utf-8, all of it. |
|
73
|
|
|
|
|
|
|
#pod This was also the module I first added the utf-8 aware versions of |
|
74
|
|
|
|
|
|
|
#pod L and L to before moving them to their own package. |
|
75
|
|
|
|
|
|
|
#pod |
|
76
|
|
|
|
|
|
|
#pod =cut |
|
77
|
|
|
|
|
|
|
|
|
78
|
4
|
|
|
4
|
|
24
|
use File::Find (); |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
66
|
|
|
79
|
4
|
|
|
4
|
|
892
|
use Encode (); |
|
|
4
|
|
|
|
|
15948
|
|
|
|
4
|
|
|
|
|
655
|
|
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Holds the pointers to the original version of redefined functions |
|
82
|
|
|
|
|
|
|
state %_orig_functions; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Current (i.e., this) package |
|
85
|
|
|
|
|
|
|
my $current_package = __PACKAGE__; |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Original package (i.e., the one for which this module is replacing the functions) |
|
88
|
|
|
|
|
|
|
my $original_package = $current_package; |
|
89
|
|
|
|
|
|
|
$original_package =~ s/::utf8$//; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
require Carp; |
|
92
|
|
|
|
|
|
|
$Carp::Internal{$current_package}++; # To get warnings reported at correct caller level |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
#pod =attr $File::Find::utf8::SPECIALVARS |
|
95
|
|
|
|
|
|
|
#pod |
|
96
|
|
|
|
|
|
|
#pod By default C only decodes the I |
|
97
|
|
|
|
|
|
|
#pod L variables C<$_>, C<$File::Find::name>, |
|
98
|
|
|
|
|
|
|
#pod C<$File::Find::dir>, and (when C or C is in |
|
99
|
|
|
|
|
|
|
#pod effect) C<$File::Find::fullname> for use in the C, |
|
100
|
|
|
|
|
|
|
#pod C, and C functions. |
|
101
|
|
|
|
|
|
|
#pod |
|
102
|
|
|
|
|
|
|
#pod If for any reason (e.g., compatibility with find.pl or find2perl) you |
|
103
|
|
|
|
|
|
|
#pod also need the I variables C<$File::Find::topdir>, |
|
104
|
|
|
|
|
|
|
#pod C<$File::Find::topdev>, C<$File::Find::topino>, |
|
105
|
|
|
|
|
|
|
#pod C<$File::Find::topmode>, and C<$File::Find::topnlink> to be decoded, |
|
106
|
|
|
|
|
|
|
#pod specify C in your |
|
107
|
|
|
|
|
|
|
#pod code. The extra decoding that needs to happen will impact performance |
|
108
|
|
|
|
|
|
|
#pod though, so use only when absolutely necessary. |
|
109
|
|
|
|
|
|
|
#pod |
|
110
|
|
|
|
|
|
|
#pod =cut |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
our $SPECIALVARS = 0; |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
#pod =attr $File::Find::utf8::UTF8_CHECK |
|
115
|
|
|
|
|
|
|
#pod |
|
116
|
|
|
|
|
|
|
#pod By default C marks decoding errors as fatal (default value |
|
117
|
|
|
|
|
|
|
#pod for this setting is C). If you want, you can change this by |
|
118
|
|
|
|
|
|
|
#pod setting C. The value C reports |
|
119
|
|
|
|
|
|
|
#pod the encoding errors as warnings, and C will completely |
|
120
|
|
|
|
|
|
|
#pod ignore them. Please see L for details. Note: C is |
|
121
|
|
|
|
|
|
|
#pod I enforced. |
|
122
|
|
|
|
|
|
|
#pod =cut |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
our $UTF8_CHECK = Encode::FB_CROAK | Encode::LEAVE_SRC; # Die on encoding errors |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# UTF-8 Encoding object |
|
127
|
|
|
|
|
|
|
my $_UTF8 = Encode::find_encoding('UTF-8'); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub import { |
|
130
|
|
|
|
|
|
|
# Target package (i.e., the one loading this module) |
|
131
|
8
|
|
|
8
|
|
1155
|
my $target_package = caller; |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# If run on the dos/os2/windows platform, ignore overriding functions silently. |
|
134
|
|
|
|
|
|
|
# These platforms do not have (proper) utf-8 file system suppport... |
|
135
|
8
|
50
|
|
|
|
161
|
unless ($^O =~ /MSWin32|cygwin|dos|os2/) { |
|
136
|
4
|
|
|
4
|
|
907
|
no strict qw(refs); ## no critic (TestingAndDebugging::ProhibitNoStrict) |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
127
|
|
|
137
|
4
|
|
|
4
|
|
18
|
no warnings qw(redefine); |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
2348
|
|
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# Redefine each of the functions to their UTF-8 equivalent |
|
140
|
8
|
|
|
|
|
43
|
for my $f (@{$original_package . '::EXPORT'}, @{$original_package . '::EXPORT_OK'}) { |
|
|
8
|
|
|
|
|
32
|
|
|
|
8
|
|
|
|
|
35
|
|
|
141
|
|
|
|
|
|
|
# If we already have the _orig_function, we have redefined the function |
|
142
|
|
|
|
|
|
|
# in an earlier load of this module, so we need not do it again |
|
143
|
16
|
100
|
|
|
|
47
|
unless ($_orig_functions{$f}) { |
|
144
|
8
|
|
|
|
|
12
|
$_orig_functions{$f} = \&{$original_package . '::' . $f}; |
|
|
8
|
|
|
|
|
33
|
|
|
145
|
8
|
|
|
|
|
11
|
*{$original_package . '::' . $f} = \&{"_utf8_$f"}; |
|
|
8
|
|
|
|
|
33
|
|
|
|
8
|
|
|
|
|
18
|
|
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
} |
|
148
|
8
|
|
|
|
|
33
|
$^H{$current_package} = 1; # Set compiler hint that we should use the utf-8 version |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Determine symbols to export |
|
152
|
8
|
|
|
|
|
14
|
shift; # First argument contains the package (that's us) |
|
153
|
8
|
100
|
|
|
|
29
|
@_ = (':DEFAULT') if !@_; # If nothing provided, use default |
|
154
|
8
|
|
|
|
|
16
|
@_ = grep { $_ ne ':none' } @_; # Strip :none tag |
|
|
8
|
|
|
|
|
25
|
|
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Use exporter to export |
|
157
|
8
|
|
|
|
|
37
|
require Exporter; |
|
158
|
8
|
100
|
|
|
|
646
|
Exporter::export_to_level($original_package, 1, $target_package, @_) if (@_); |
|
159
|
|
|
|
|
|
|
|
|
160
|
7
|
|
|
|
|
1412
|
return; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub unimport { ## no critic (Subroutines::ProhibitBuiltinHomonyms) |
|
164
|
1
|
|
|
1
|
|
9
|
$^H{$current_package} = 0; # Set compiler hint that we should not use the utf-8 version |
|
165
|
1
|
|
|
|
|
1081
|
return; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub _utf8_find { |
|
169
|
15
|
|
|
15
|
|
10191
|
my $ref = shift; # This can be the wanted function or a find options hash |
|
170
|
|
|
|
|
|
|
# Make argument always into the find's options hash |
|
171
|
15
|
100
|
|
|
|
73
|
my %find_options_hash = ref($ref) eq "HASH" ? %$ref : (wanted => $ref); |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Holds the (possibly encoded) arguments |
|
174
|
15
|
|
|
|
|
45
|
my @args = @_; |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Get the hint from the caller (one level deeper if called from finddepth) |
|
177
|
15
|
100
|
50
|
|
|
86
|
my $hints = ((caller 1)[3]//'') ne 'File::Find::utf8::_utf8_finddepth' ? (caller 0)[10] : (caller 1)[10]; |
|
178
|
15
|
100
|
|
|
|
781
|
if ($hints->{$current_package}) { |
|
179
|
12
|
100
|
|
|
|
51
|
$UTF8_CHECK |= Encode::LEAVE_SRC if $UTF8_CHECK; # Enforce LEAVE_SRC |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# Save original processors |
|
182
|
12
|
|
|
|
|
22
|
my %org_proc; |
|
183
|
12
|
|
|
|
|
28
|
for my $proc ("wanted", "preprocess", "postprocess") { $org_proc{$proc} = $find_options_hash{$proc}; } |
|
|
36
|
|
|
|
|
73
|
|
|
184
|
|
|
|
|
|
|
my $follow_option = (exists $find_options_hash{follow} && $find_options_hash{follow}) |
|
185
|
12
|
|
33
|
|
|
75
|
|| (exists $find_options_hash{follow_fast} && $find_options_hash{follow_fast}); |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# Wrap processors to become utf8-aware |
|
188
|
12
|
50
|
33
|
|
|
67
|
if (defined $org_proc{wanted} && ref $org_proc{wanted}) { |
|
189
|
|
|
|
|
|
|
$find_options_hash{wanted} = sub { |
|
190
|
|
|
|
|
|
|
# Decode the file variables so they become characters |
|
191
|
15
|
50
|
|
15
|
|
356
|
local $_ = $_UTF8->decode($_, $UTF8_CHECK) if $_; |
|
192
|
15
|
50
|
|
|
|
120
|
local $File::Find::name = $_UTF8->decode($File::Find::name, $UTF8_CHECK) if $File::Find::name; |
|
193
|
15
|
50
|
|
|
|
102
|
local $File::Find::dir = $_UTF8->decode($File::Find::dir, $UTF8_CHECK) if $File::Find::dir; |
|
194
|
15
|
0
|
33
|
|
|
79
|
local $File::Find::fullname = $_UTF8->decode($File::Find::fullname, $UTF8_CHECK) if $follow_option && $File::Find::fullname; |
|
195
|
|
|
|
|
|
|
# These are only necessary for compatibility reasons (find.pl, find2perl). |
|
196
|
|
|
|
|
|
|
# If you need them, set $File::Find::utf8::SPECIALVARS |
|
197
|
15
|
0
|
33
|
|
|
32
|
local $File::Find::topdir = $_UTF8->decode($File::Find::topdir, $UTF8_CHECK) if $SPECIALVARS && $File::Find::topdir; |
|
198
|
15
|
0
|
33
|
|
|
31
|
local $File::Find::topdev = $_UTF8->decode($File::Find::topdev, $UTF8_CHECK) if $SPECIALVARS && $File::Find::topdev; |
|
199
|
15
|
0
|
33
|
|
|
37
|
local $File::Find::topino = $_UTF8->decode($File::Find::topino, $UTF8_CHECK) if $SPECIALVARS && $File::Find::topino; |
|
200
|
15
|
0
|
33
|
|
|
32
|
local $File::Find::topmode = $_UTF8->decode($File::Find::topmode, $UTF8_CHECK) if $SPECIALVARS && $File::Find::topmode; |
|
201
|
15
|
0
|
33
|
|
|
32
|
local $File::Find::topnlink = $_UTF8->decode($File::Find::topnlink, $UTF8_CHECK) if $SPECIALVARS && $File::Find::topnlink; |
|
202
|
15
|
0
|
|
|
|
41
|
return $org_proc{wanted}->(map { $_ ? $_UTF8->decode($_, $UTF8_CHECK) : $_ } @_); |
|
|
0
|
|
|
|
|
0
|
|
|
203
|
12
|
|
|
|
|
58
|
}; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
12
|
|
|
|
|
27
|
for my $proc ("preprocess", "postprocess") { |
|
206
|
24
|
100
|
66
|
|
|
76
|
if (defined $org_proc{$proc} && ref $org_proc{$proc}) { |
|
207
|
|
|
|
|
|
|
$find_options_hash{$proc} = sub { |
|
208
|
|
|
|
|
|
|
# Decode the file variables so they become characters |
|
209
|
3
|
50
|
|
3
|
|
64
|
local $File::Find::dir = $_UTF8->decode($File::Find::dir, $UTF8_CHECK) if $File::Find::dir; |
|
210
|
|
|
|
|
|
|
# Decode the arguments and encode the results |
|
211
|
3
|
0
|
|
|
|
28
|
return map { $_ ? $_UTF8->encode($_, $UTF8_CHECK) : $_ } $org_proc{$proc}->(map { $_ ? $_UTF8->decode($_, $UTF8_CHECK) : $_ } @_); |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
69
|
|
|
|
|
375
|
|
|
212
|
3
|
|
|
|
|
10
|
}; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
# Encode arguments as utf-8 so that the original File::Find receives bytes |
|
216
|
12
|
50
|
|
|
|
27
|
@args = map { $_ ? $_UTF8->encode($_, $UTF8_CHECK) : $_ } @_; |
|
|
12
|
|
|
|
|
117
|
|
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# Make sure warning level propagates to File::Find |
|
220
|
|
|
|
|
|
|
# Note: on perl prior to v5.12 warnings_fatal_enabled does not exist |
|
221
|
|
|
|
|
|
|
# so we can not use it. |
|
222
|
14
|
100
|
66
|
|
|
629
|
if (!warnings::enabled('File::Find')) { |
|
|
|
100
|
|
|
|
|
|
|
223
|
4
|
|
|
4
|
|
27
|
no warnings 'File::Find'; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
241
|
|
|
224
|
3
|
|
|
|
|
877
|
return $_orig_functions{find}->(\%find_options_hash, @args); |
|
225
|
|
|
|
|
|
|
} elsif (!exists &warnings::fatal_enabled or !warnings::fatal_enabled('File::Find')) { |
|
226
|
4
|
|
|
4
|
|
20
|
use warnings 'File::Find'; |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
213
|
|
|
227
|
10
|
|
|
|
|
2214
|
return $_orig_functions{find}->(\%find_options_hash, @args); |
|
228
|
|
|
|
|
|
|
} else { |
|
229
|
4
|
|
|
4
|
|
47
|
use warnings FATAL => qw(File::Find); |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
492
|
|
|
230
|
1
|
|
|
|
|
354
|
return $_orig_functions{find}->(\%find_options_hash, @args); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub _utf8_finddepth { |
|
235
|
4
|
|
|
4
|
|
4231
|
my $ref = shift; # This can be the wanted function or a find options hash |
|
236
|
4
|
50
|
|
|
|
27
|
return _utf8_find( { bydepth => 1, ref($ref) eq "HASH" ? %$ref : (wanted => $ref) }, @_); |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
1; |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
__END__ |