File Coverage

blib/lib/Code/TidyAll/Zglob.pm
Criterion Covered Total %
statement 85 140 60.7
branch 49 106 46.2
condition 34 75 45.3
subroutine 13 14 92.8
pod 0 7 0.0
total 181 342 52.9


line stmt bran cond sub pod time code
1             use strict;
2 27     27   174 use warnings 'all', FATAL => 'recursion';
  27         54  
  27         885  
3 27     27   128 use 5.008008;
  27         56  
  27         1084  
4 27     27   606 our $VERSION = '0.81';
  27         83  
5             use base qw(Exporter);
6 27     27   161  
  27         52  
  27         3648  
7             our @EXPORT = qw(zglob);
8              
9             use File::Basename;
10 27     27   221  
  27         70  
  27         47639  
11             our $SEPCHAR = '/';
12             our $NOCASE = $^O =~ /^(?:MSWin32|VMS|os2|dos|riscos|MacOS|darwin)$/ ? 1 : 0;
13             our $DIRFLAG = \"DIR?";
14             our $DEEPFLAG = \"**";
15             our $PARENTFLAG = \"..";
16             our $DEBUG = 0;
17             our $STRICT_LEADING_DOT = 1;
18             our $STRICT_WILDCARD_SLASH = 1;
19              
20             my ($pattern) = @_;
21             #dbg("FOLDING: $pattern");
22 42     42 0 341 # support ~tokuhirom/
23             if ($^O eq 'MSWin32') {
24             require Win32;
25 42 50       164 $pattern =~ s!^(\~[^$SEPCHAR]*)!Win32::GetLongPathName([glob($1)]->[0])!e;
26 0         0 } else {
27 0         0 $pattern =~ s!^(\~[^$SEPCHAR]*)![glob($1)]->[0]!e;
  0         0  
28             }
29 42         249 my ($node, $matcher) = glob_prepare_pattern($pattern);
  0         0  
30             # $node : \0 if absolute path, \1 if relative.
31 42         144  
32             #dbg("pattern: ", $node, $matcher);
33             return _rec($node, $matcher, []);
34             }
35 42         139  
36             return unless $DEBUG;
37             my ($pkg, $filename, $line, $sub) = caller(1);
38             my $i = 0;
39 384 50   384 0 670 while (caller($i++)) { 1 }
40 0         0 my $msg;
41 0         0 $msg .= ('-' x ($i-5));
42 0         0 $msg .= " [$sub] ";
  0         0  
43 0         0 for (@_) {
44 0         0 $msg .= ' ';
45 0         0 if (not defined $_) {
46 0         0 $msg .= '<<undef>>';
47 0         0 } elsif (ref $_) {
48 0 0       0 require Data::Dumper;
    0          
49 0         0 local $Data::Dumper::Terse = 1;
50             local $Data::Dumper::Indent = 0;
51 0         0 $msg .= Data::Dumper::Dumper($_);
52 0         0 } else {
53 0         0 $msg .= $_;
54 0         0 }
55             }
56 0         0 $msg .= " at $filename line $line\n";
57             print($msg);
58             }
59 0         0  
60 0         0 my ($node, $matcher) = @_;
61             #dbg("recstar: ", $node, $matcher, $seed);
62             return (
63             _rec( $node, $matcher ),
64 47     47   99 (
65             map { _recstar( $_, $matcher ) }
66             glob_fs_fold( $node, qr{^[^.].*$}, 1 )
67             )
68             );
69 47         114 }
  15         60  
70              
71             my ($node, $matcher) = @_;
72             # $matcher: ArrayRef[Any]
73              
74             my ($current, @rest) = @{$matcher};
75             if (!defined $current) {
76 177     177   326 #dbg("FINISHED");
77             return ();
78             } elsif (ref($current) eq 'SCALAR' && $current == $DEEPFLAG) {
79 177         216 #dbg("** mode");
  177         346  
80 177 50 66     882 return _recstar($node, \@rest);
    100 33        
    50          
    100          
81             } elsif (ref($current) eq 'SCALAR' && $current == $PARENTFLAG) {
82 0         0 if (ref($node) eq 'SCALAR' && $$node eq 1) { #t
83             die "You cannot get a parent directory of root dir.";
84             } elsif (ref($node) eq 'SCALAR' && $$node eq 0) { #f
85 32         133 return _rec("..", \@rest);
86             } else {
87 0 0 0     0 return _rec("$node$SEPCHAR..", \@rest);
    0 0        
88 0         0 }
89             } elsif (@rest == 0) {
90 0         0 #dbg("file name");
91             # (folder proc seed node (car matcher) #f)
92 0         0 return glob_fs_fold($node, $current, 0);
93             } else {
94             return glob_fs_fold($node, $current, 1, \@rest);
95             }
96             }
97 51         122  
98              
99 94         207 # /^home$/ のような固定の文字列の場合に高速化をはかるための最適化予定地なので、とりあえず undef をかえしておいても問題がない
100             return undef;
101             die "TBI"
102             }
103              
104             # returns arrayref of seeds.
105             my ($node, $regexp, $non_leaf_p, $rest) = @_;
106 0     0 0 0  
107 0         0 my $prefix = do {
108             if (ref $node eq 'SCALAR') {
109             if ($$node eq 1) { #t
110             $SEPCHAR
111             } elsif ($$node eq '0') { #f
112 192     192 0 394 '';
113             } else {
114 192         223 die "FATAL";
115 192 100       496 }
    50          
116 42 50       89 } elsif ($node !~ m{/$}) {
    0          
117 42         83 $node . '/';
118             } else {
119 0         0 $node;
120             }
121 0         0 };
122             dbg("prefix: $prefix");
123             dbg("regxp: ", $regexp);
124 150         294 if ($^O eq 'MSWin32' && ref $regexp eq 'SCALAR' && $$regexp =~ /^[a-zA-Z]\:$/) {
125             return _rec($$regexp . '/', $rest);
126 0         0 }
127             if (ref $regexp eq 'SCALAR' && $regexp == $DIRFLAG) {
128             if ($rest) {
129 192         480 return _rec($prefix, $rest);
130 192         374 } else {
131 192 0 33     535 return ($prefix);
      33        
132 0         0 }
133             # } elsif (my $string_portion = fixed_regexp_p($regexp)) { # /^path$/
134 192 50 33     391 # die "TBI";
135 0 0       0 # my $full = $prefix . $string_portion;
136 0         0 # if (-e $full && (!$non_leaf_p || -d $full)) {
137             # $proc->($full, $seed);
138 0         0 # } else {
139             # $proc;
140             # }
141             } else { # normal regexp
142             #dbg("normal regexp");
143             my $dir = do {
144             if (ref($node) eq 'SCALAR' && $$node eq 1) {
145             $SEPCHAR
146             } elsif (ref($node) eq 'SCALAR' && $$node eq 0) {
147             '.';
148             } else {
149             $node;
150 192         236 }
151 192 100 66     643 };
    50 33        
152 42         77 #dbg("dir: $dir");
153             opendir my $dirh, $dir or do {
154 0         0 #dbg("cannot open dir: $dir: $!");
155             return ();
156 150         248 };
157             my @ret;
158             while (defined(my $child = readdir($dirh))) {
159             next if $child eq '.' or $child eq '..';
160 192 50       4677 my $full;
161             #dbg("non-leaf: ", $non_leaf_p);
162 0         0 if (($child =~ $regexp) && ($full = $prefix . $child) && (!$non_leaf_p || -d $full)) {
163             #dbg("matched: ", $regexp, $child, $full);
164 192         516 if ($rest) {
165 192         8496 push @ret, _rec($full, $rest);
166 1779 100 100     5263 } else {
167 1395         1410 push @ret, $full;
168             }
169 1395 100 66     8389 # } else {
      100        
      100        
170             #dbg("Don't match: $child");
171 177 100       436 }
172 88         236 }
173             return @ret;
174 89         360 }
175             }
176              
177             my ($pattern) = @_;
178             my @path = split $SEPCHAR, $pattern;
179              
180 192         3301 my $is_absolute = $path[0] eq '' ? 1 : 0;
181             if ($is_absolute) {
182             shift @path;
183             }
184             if ($^O eq 'MSWin32' && $path[0] =~ /^[a-zA-Z]\:$/) {
185 42     42 0 80 $is_absolute = 1;
186 42         566 }
187              
188 42 50       140 @path = map {
189 42 50       93 if ($_ eq '**') {
190 42         72 $DEEPFLAG
191             } elsif ($_ eq '') {
192 42 50 33     121 $DIRFLAG
193 0         0 } elsif ($_ eq '.') {
194             ()
195             } elsif ($_ eq '..') {
196             $PARENTFLAG
197 42 100 33     88 } elsif ($^O eq 'MSWin32' && $_ =~ '^[a-zA-Z]\:$') {
  168 50       638  
    50          
    50          
    50          
198 32         60 \$_
199             } else {
200 0         0 glob_to_regex($_) # TODO: replace with original implementation?
201             }
202             } @path;
203 0         0  
204 0         0 return ( \$is_absolute, \@path );
205             }
206 0         0  
207             # this is not a private function. '**' was handled at glob_prepare_pattern() function.
208 136         236 my $glob = shift;
209             my $regex = glob_to_regex_string($glob);
210             return $NOCASE ? qr/^$regex$/i : qr/^$regex$/;
211             }
212 42         145  
213             my $glob = shift;
214             my ($regex, $in_curlies, $escaping);
215             local $_;
216             my $first_byte = 1;
217 136     136 0 190 for ($glob =~ m/(.)/gs) {
218 136         246 if ($first_byte) {
219 136 50       2562 if ($STRICT_LEADING_DOT) {
220             $regex .= '(?=[^\.])' unless $_ eq '.';
221             }
222             $first_byte = 0;
223 136     136 0 179 }
224 136         176 if ($_ eq '/') {
225 136         156 $first_byte = 1;
226 136         159 }
227 136         863 if ($_ eq '.' || $_ eq '(' || $_ eq ')' || $_ eq '|' ||
228 1101 100       1459 $_ eq '+' || $_ eq '^' || $_ eq '$' || $_ eq '@' || $_ eq '%' ) {
229 136 50       220 $regex .= "\\$_";
230 136 50       282 }
231             elsif ($_ eq '*') {
232 136         175 $regex .= $escaping ? "\\*" :
233             $STRICT_WILDCARD_SLASH ? "[^/]*" : ".*";
234 1101 50       1417 }
235 0         0 elsif ($_ eq '?') {
236             $regex .= $escaping ? "\\?" :
237 1101 100 66     9972 $STRICT_WILDCARD_SLASH ? "[^/]" : ".";
    100 66        
    50 33        
    50 33        
    50 33        
    50 33        
    50 33        
      33        
      33        
      33        
238             }
239 31         61 elsif ($_ eq '{') {
240             $regex .= $escaping ? "\\{" : "(";
241             ++$in_curlies unless $escaping;
242 38 50       94 }
    50          
243             elsif ($_ eq '}' && $in_curlies) {
244             $regex .= $escaping ? "}" : ")";
245             --$in_curlies unless $escaping;
246 0 0       0 }
    0          
247             elsif ($_ eq ',' && $in_curlies) {
248             $regex .= $escaping ? "," : "|";
249             }
250 0 0       0 elsif ($_ eq "\\") {
251 0 0       0 if ($escaping) {
252             $regex .= "\\\\";
253             $escaping = 0;
254 0 0       0 }
255 0 0       0 else {
256             $escaping = 1;
257             }
258 0 0       0 next;
259             }
260             else {
261 0 0       0 $regex .= $_;
262 0         0 $escaping = 0;
263 0         0 }
264             $escaping = 0;
265             }
266 0         0  
267             return $regex;
268 0         0 }
269              
270             1;
271 1032         1175  
272 1032         1061 # ABSTRACT: A borged copy of File::Zglob
273              
274 1101         1204  
275             =pod
276              
277 136         345 =encoding UTF-8
278              
279             =head1 NAME
280              
281             Code::TidyAll::Zglob - A borged copy of File::Zglob
282              
283             =head1 VERSION
284              
285             version 0.81
286              
287             =head1 DESCRIPTION
288              
289             File::Zglob has not been installable under Perl 5.26 and this has been an open
290             issue for 8+ months
291             (https://rt.cpan.org/Public/Bug/Display.html?id=120445). This module will go
292             away once File::Zglob is installable.
293              
294             =head1 LICENSE
295              
296             Copyright (C) Tokuhiro Matsuno
297              
298             This library is free software; you can redistribute it and/or modify
299             it under the same terms as Perl itself.
300              
301             =head1 SUPPORT
302              
303             Bugs may be submitted at L<https://github.com/houseabsolute/perl-code-tidyall/issues>.
304              
305             =head1 SOURCE
306              
307             The source code repository for Code-TidyAll can be found at L<https://github.com/houseabsolute/perl-code-tidyall>.
308              
309             =head1 AUTHORS
310              
311             =over 4
312              
313             =item *
314              
315             Jonathan Swartz <swartz@pobox.com>
316              
317             =item *
318              
319             Dave Rolsky <autarch@urth.org>
320              
321             =back
322              
323             =head1 COPYRIGHT AND LICENSE
324              
325             This software is copyright (c) 2011 - 2022 by Jonathan Swartz.
326              
327             This is free software; you can redistribute it and/or modify it under
328             the same terms as the Perl 5 programming language system itself.
329              
330             The full text of the license can be found in the
331             F<LICENSE> file included with this distribution.
332              
333             =cut