File Coverage

blib/lib/File/Next.pm
Criterion Covered Total %
statement 142 150 94.6
branch 61 70 87.1
condition 22 39 56.4
subroutine 18 18 100.0
pod 7 7 100.0
total 250 284 88.0


line stmt bran cond sub pod time code
1             package File::Next;
2              
3 13     13   724605 use strict;
  13         118  
  13         312  
4 13     13   71 use warnings;
  13         21  
  13         722  
5              
6             =head1 NAME
7              
8             File::Next - File-finding iterator
9              
10             =head1 VERSION
11              
12             Version 1.18
13              
14             =cut
15              
16             our $VERSION = '1.18';
17              
18             =head1 SYNOPSIS
19              
20             File::Next is a lightweight, taint-safe file-finding module.
21             It has no non-core prerequisites.
22              
23             use File::Next;
24              
25             my $files = File::Next::files( '/tmp' );
26              
27             while ( defined ( my $file = $files->() ) ) {
28             # do something...
29             }
30              
31             =head1 OPERATIONAL THEORY
32              
33             The two major functions, I and I, return an iterator
34             that will walk through a directory tree. The simplest use case is:
35              
36             use File::Next;
37              
38             my $iter = File::Next::files( '/tmp' );
39              
40             while ( defined ( my $file = $iter->() ) ) {
41             print $file, "\n";
42             }
43              
44             # Prints...
45             /tmp/foo.txt
46             /tmp/bar.pl
47             /tmp/baz/1
48             /tmp/baz/2.txt
49             /tmp/baz/wango/tango/purple.txt
50              
51             Note that only files are returned by C's iterator.
52             Directories are ignored.
53              
54             In list context, the iterator returns a list containing I<$dir>,
55             I<$file> and I<$fullpath>, where I<$fullpath> is what would get
56             returned in scalar context.
57              
58             The first parameter to any of the iterator factory functions may
59             be a hashref of options.
60              
61             =head1 ITERATORS
62              
63             For the three iterators, the \%options are optional.
64              
65             =head2 files( [ \%options, ] @starting_points )
66              
67             Returns an iterator that walks directories starting with the items
68             in I<@starting_points>. Each call to the iterator returns another
69             regular file.
70              
71             =head2 dirs( [ \%options, ] @starting_points )
72              
73             Returns an iterator that walks directories starting with the items
74             in I<@starting_points>. Each call to the iterator returns another
75             directory.
76              
77             =head2 everything( [ \%options, ] @starting_points )
78              
79             Returns an iterator that walks directories starting with the items
80             in I<@starting_points>. Each call to the iterator returns another
81             file, whether it's a regular file, directory, symlink, socket, or
82             whatever.
83              
84             =head2 from_file( [ \%options, ] $filename )
85              
86             Returns an iterator that iterates over each of the files specified
87             in I<$filename>. If I<$filename> is C<->, then the files are read
88             from STDIN.
89              
90             The files are assumed to be in the file one filename per line. If
91             I<$nul_separated> is passed, then the files are assumed to be
92             NUL-separated, as by C.
93              
94             If there are blank lines or empty filenames in the input stream,
95             they are ignored.
96              
97             Each filename is checked to see that it is a regular file or a named
98             pipe. If the file does not exists or is a directory, then a warning
99             is thrown to I, and the file is skipped.
100              
101             The following options have no effect in C: I,
102             I, I.
103              
104             =head1 SUPPORT FUNCTIONS
105              
106             =head2 sort_standard( $a, $b )
107              
108             A sort function for passing as a C option:
109              
110             my $iter = File::Next::files( {
111             sort_files => \&File::Next::sort_standard,
112             }, 't/swamp' );
113              
114             This function is the default, so the code above is identical to:
115              
116             my $iter = File::Next::files( {
117             sort_files => 1,
118             }, 't/swamp' );
119              
120             =head2 sort_reverse( $a, $b )
121              
122             Same as C, but in reverse.
123              
124             =head2 reslash( $path )
125              
126             Takes a path with all forward slashes and rebuilds it with whatever
127             is appropriate for the platform. For example 'foo/bar/bat' will
128             become 'foo\bar\bat' on Windows.
129              
130             This is really just a convenience function. I'd make it private,
131             but F wants it, too.
132              
133             =cut
134              
135             =head1 CONSTRUCTOR PARAMETERS
136              
137             =head2 file_filter -> \&file_filter
138              
139             The file_filter lets you check to see if it's really a file you
140             want to get back. If the file_filter returns a true value, the
141             file will be returned; if false, it will be skipped.
142              
143             The file_filter function takes no arguments but rather does its work through
144             a collection of variables.
145              
146             =over 4
147              
148             =item * C<$_> is the current filename within that directory
149              
150             =item * C<$File::Next::dir> is the current directory name
151              
152             =item * C<$File::Next::name> is the complete pathname to the file
153              
154             =back
155              
156             These are analogous to the same variables in L.
157              
158             my $iter = File::Next::files( { file_filter => sub { /\.txt$/ } }, '/tmp' );
159              
160             By default, the I is C, or "all files".
161              
162             This filter has no effect if your iterator is only returning directories.
163              
164             =head2 descend_filter => \&descend_filter
165              
166             The descend_filter lets you check to see if the iterator should
167             descend into a given directory. Maybe you want to skip F and
168             F<.svn> directories.
169              
170             my $descend_filter = sub { $_ ne "CVS" && $_ ne ".svn" }
171              
172             The descend_filter function takes no arguments but rather does its work through
173             a collection of variables.
174              
175             =over 4
176              
177             =item * C<$_> is the current filename of the directory
178              
179             =item * C<$File::Next::dir> is the complete directory name
180              
181             =back
182              
183             The descend filter is NOT applied to any directory names specified
184             as I<@starting_points> in the constructor. For example,
185              
186             my $iter = File::Next::files( { descend_filter => sub{0} }, '/tmp' );
187              
188             always descends into I, as you would expect.
189              
190             By default, the I is C, or "always descend".
191              
192             =head2 error_handler => \&error_handler
193              
194             If I is set, then any errors will be sent through
195             it. If the error is OS-related (ex. file not found, not permissions), the
196             native error code is passed as a second argument. By default, this value is
197             C. This function must NOT return.
198              
199             =head2 warning_handler => \&warning_handler
200              
201             If I is set, then any errors will be sent through
202             it. By default, this value is C. Unlike the
203             I, this function must return.
204              
205             =head2 sort_files => [ 0 | 1 | \&sort_sub]
206              
207             If you want files sorted, pass in some true value, as in
208             C<< sort_files => 1 >>.
209              
210             If you want a special sort order, pass in a sort function like
211             C<< sort_files => sub { $a->[1] cmp $b->[1] } >>.
212             Note that the parms passed in to the sub are arrayrefs, where $a->[0]
213             is the directory name, $a->[1] is the file name and $a->[2] is the
214             full path. Typically you're going to be sorting on $a->[2].
215              
216             =head2 follow_symlinks => [ 0 | 1 ]
217              
218             If set to false, the iterator will ignore any files and directories
219             that are actually symlinks. This has no effect on non-Unixy systems
220             such as Windows. By default, this is true.
221              
222             Note that this filter does not apply to any of the I<@starting_points>
223             passed in to the constructor.
224              
225             You should not set C<< follow_symlinks => 0 >> unless you specifically
226             need that behavior. Setting C<< follow_symlinks => 0 >> can be a
227             speed hit, because File::Next must check to see if the file or
228             directory you're about to follow is actually a symlink.
229              
230             =head2 nul_separated => [ 0 | 1 ]
231              
232             Used by the C iterator. Specifies that the files
233             listed in the input file are separated by NUL characters, as from
234             the C command with the C<-print0> argument.
235              
236             =cut
237              
238 13     13   60 use File::Spec ();
  13         21  
  13         1634  
239              
240             our $name; # name of the current file
241             our $dir; # dir of the current file
242              
243             our %files_defaults;
244             our %skip_dirs;
245              
246             BEGIN {
247             %files_defaults = (
248             file_filter => undef,
249             descend_filter => undef,
250 3         25 error_handler => sub { CORE::die $_[0] },
251 1         14 warning_handler => sub { CORE::warn @_ },
252 13     13   141 sort_files => undef,
253             follow_symlinks => 1,
254             nul_separated => 0,
255             );
256 13         157 %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir);
  26         18834  
257             }
258              
259              
260             sub files {
261 19 100 33 19 1 11920 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
      66        
262              
263 17         60 my ($parms,@queue) = _setup( \%files_defaults, @_ );
264              
265 17         39 my $filter = $parms->{file_filter};
266             return sub {
267 210     210   7766 while ( my $entry = shift @queue ) {
268 249         302 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
  249         570  
269 249 100 66     476 if ( $is_file || $is_fifo ) {
270 205 100       279 if ( $filter ) {
271 20         32 local $_ = $file;
272 20         25 local $File::Next::dir = $dirname;
273 20         31 local $File::Next::name = $fullpath;
274 20 100       31 next if not $filter->();
275             }
276 196 100       1653 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
277             }
278 44 50       78 if ( $is_dir ) {
279 44         96 unshift( @queue, _candidate_files( $parms, $fullpath ) );
280             }
281             } # while
282              
283 14         26 return;
284 17         111 }; # iterator
285             }
286              
287              
288             sub dirs {
289 5 100 33 5 1 2433 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
      66        
290              
291 3         15 my ($parms,@queue) = _setup( \%files_defaults, @_ );
292              
293             return sub {
294 6     6   560 while ( my $entry = shift @queue ) {
295 44         42 my ( undef, undef, $fullpath, $is_dir, undef, undef ) = @{$entry};
  44         71  
296 44 100       99 if ( $is_dir ) {
297 5         10 unshift( @queue, _candidate_files( $parms, $fullpath ) );
298 5         24 return $fullpath;
299             }
300             } # while
301              
302 1         2 return;
303 2         13 }; # iterator
304             }
305              
306              
307             sub everything {
308 5 100 33 5 1 2559 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
      66        
309              
310 3         14 my ($parms,@queue) = _setup( \%files_defaults, @_ );
311              
312 3         6 my $filter = $parms->{file_filter};
313             return sub {
314 55     55   1149 while ( my $entry = shift @queue ) {
315 88         333 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
  88         185  
316 88 100       127 if ( $is_dir ) {
317 10         19 unshift( @queue, _candidate_files( $parms, $fullpath ) );
318             }
319 88 100       143 if ( $filter ) {
320 44         104 local $_ = $file;
321 44         57 local $File::Next::dir = $dirname;
322 44         91 local $File::Next::name = $fullpath;
323 44 100       72 next if not $filter->();
324             }
325 53 50       243 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
326             } # while
327              
328 2         20 return;
329 3         29 }; # iterator
330             }
331              
332             sub from_file {
333 8 50 66 8 1 9085 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
      66        
334              
335 8         21 my ($parms,@queue) = _setup( \%files_defaults, @_ );
336 8         13 my $err = $parms->{error_handler};
337 8         9 my $warn = $parms->{warning_handler};
338              
339 8         13 my $filename = $queue[0]->[1];
340              
341 8 100       14 if ( !defined($filename) ) {
342 1         4 $err->( 'Must pass a filename to from_file()' );
343 0         0 return undef;
344             }
345              
346 7         8 my $fh;
347 7 50       15 if ( $filename eq '-' ) {
348 0         0 $fh = \*STDIN;
349             }
350             else {
351 7 100       164 if ( !open( $fh, '<', $filename ) ) {
352 2         20 $err->( "Unable to open $filename: $!", $! + 0 );
353 1         8 return undef;
354             }
355             }
356              
357 5         12 my $filter = $parms->{file_filter};
358             return sub {
359 85 100   85   2251 local $/ = $parms->{nul_separated} ? "\x00" : $/;
360 85         358 while ( my $fullpath = <$fh> ) {
361 84         135 chomp $fullpath;
362 84 100       210 next unless $fullpath =~ /./;
363 83 100 66     907 if ( not ( -f $fullpath || -p _ ) ) {
364 3         18 $warn->( "$fullpath: No such file" );
365 3         36 next;
366             }
367              
368 80         752 my ($volume,$dirname,$file) = File::Spec->splitpath( $fullpath );
369 80 50       153 if ( $filter ) {
370 0         0 local $_ = $file;
371 0         0 local $File::Next::dir = $dirname;
372 0         0 local $File::Next::name = $fullpath;
373 0 0       0 next if not $filter->();
374             }
375 80 50       334 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
376             } # while
377 5         39 close $fh;
378              
379 5         19 return;
380 5         35 }; # iterator
381             }
382              
383             sub _bad_invocation {
384 6     6   66 my $good = (caller(1))[3];
385 6         12 my $bad = $good;
386 6         65 $bad =~ s/(.+)::/$1->/;
387 6         51 return "$good must not be invoked as $bad";
388             }
389              
390 82     82 1 138 sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] } ## no critic (ProhibitSubroutinePrototypes)
391 83     83 1 131 sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] } ## no critic (ProhibitSubroutinePrototypes)
392              
393             sub reslash {
394 729     729 1 48536 my $path = shift;
395              
396 729         1532 my @parts = split( /\//, $path );
397              
398 729 100       1373 return $path if @parts < 2;
399              
400 646         4162 return File::Spec->catfile( @parts );
401             }
402              
403              
404             =head1 PRIVATE FUNCTIONS
405              
406             =head2 _setup( $default_parms, @whatever_was_passed_to_files() )
407              
408             Handles all the scut-work for setting up the parms passed in.
409              
410             Returns a hashref of operational options, combined between
411             I<$passed_parms> and I<$defaults>, plus the queue.
412              
413             The queue prep stuff takes the strings in I<@starting_points> and
414             puts them in the format that queue needs.
415              
416             The C<@queue> that gets passed around is an array, with each entry an
417             arrayref of $dir, $file and $fullpath.
418              
419             =cut
420              
421             sub _setup {
422 31     31   52 my $defaults = shift;
423 31 100       99 my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash
  16         51  
424              
425 31         57 my %passed_parms = %{$passed_parms};
  31         95  
426              
427 31         51 my $parms = {};
428 31         40 for my $key ( keys %{$defaults} ) {
  31         119  
429             $parms->{$key} =
430             exists $passed_parms{$key}
431             ? delete $passed_parms{$key}
432 217 100       386 : $defaults->{$key};
433             }
434              
435             # Any leftover keys are bogus
436 31         89 for my $badkey ( sort keys %passed_parms ) {
437 2         12 my $sub = (caller(1))[3];
438 2         9 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
439             }
440              
441             # If it's not a code ref, assume standard sort
442 30 100 100     90 if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) {
443 1         2 $parms->{sort_files} = \&sort_standard;
444             }
445 30         74 my @queue;
446              
447 30         55 for ( @_ ) {
448 31         63 my $start = reslash( $_ );
449 31         455 my $is_dir = -d $start;
450 31         125 my $is_file = -f _;
451 31   33     143 my $is_fifo = (-p _) || ($start =~ m{^/dev/fd});
452 31 100       154 push @queue,
453             $is_dir
454             ? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
455             : [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
456             }
457              
458 30         145 return ($parms,@queue);
459             }
460              
461             =head2 _candidate_files( $parms, $dir )
462              
463             Pulls out the files/dirs that might be worth looking into in I<$dir>.
464             If I<$dir> is the empty string, then search the current directory.
465              
466             I<$parms> is the hashref of parms passed into File::Next constructor.
467              
468             =cut
469              
470             sub _candidate_files {
471 59     59   83 my $parms = shift;
472 59         77 my $dirname = shift;
473              
474 59         73 my $dh;
475 59 50       1576 if ( !opendir $dh, $dirname ) {
476 0         0 $parms->{error_handler}->( "$dirname: $!", $! + 0 );
477 0         0 return;
478             }
479              
480 59         142 my @newfiles;
481 59         101 my $descend_filter = $parms->{descend_filter};
482 59         72 my $follow_symlinks = $parms->{follow_symlinks};
483              
484 59         1266 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
  497         915  
485 379         2348 my $fullpath = File::Spec->catdir( $dirname, $file );
486 379 100       918 if ( !$follow_symlinks ) {
487 12 100       120 next if -l $fullpath;
488             }
489             else {
490 367         3529 stat($fullpath);
491             }
492 377         924 my $is_dir = -d _;
493 377         447 my $is_file = -f _;
494 377   33     1079 my $is_fifo = (-p _) || ($fullpath =~ m{^/dev/fd});
495              
496             # Only do directory checking if we have a descend_filter
497 377 100       565 if ( $descend_filter ) {
498 36 100       56 if ( $is_dir ) {
499 6         13 local $File::Next::dir = $fullpath;
500 6         9 local $_ = $file;
501 6 100       15 next if not $descend_filter->();
502             }
503             }
504 374         3750 push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
505             }
506 59         607 closedir $dh;
507              
508 59         149 my $sort_sub = $parms->{sort_files};
509 59 100       108 if ( $sort_sub ) {
510 13         38 @newfiles = sort $sort_sub @newfiles;
511             }
512              
513 59         383 return @newfiles;
514             }
515              
516              
517             =head1 DIAGNOSTICS
518              
519             =over
520              
521             =item C<< File::Next::files must not be invoked as File::Next->files >>
522              
523             =item C<< File::Next::dirs must not be invoked as File::Next->dirs >>
524              
525             =item C<< File::Next::everything must not be invoked as File::Next->everything >>
526              
527             =back
528              
529             The interface functions do not allow for the method invocation syntax and
530             throw errors with the messages above. You can work around this limitation
531             with L.
532              
533             for my $file_system_feature (qw(dirs files)) {
534             my $iterator = File::Next->can($file_system_feature)->($options, $target_directory);
535             while (defined(my $name = $iterator->())) {
536             # ...
537             }
538             }
539              
540             =head1 SPEED TWEAKS
541              
542             =over 4
543              
544             =item * Don't set C<< follow_symlinks => 0 >> unless you need it.
545              
546             =back
547              
548             =head1 AUTHOR
549              
550             Andy Lester, C<< >>
551              
552             =head1 BUGS
553              
554             Please report any bugs or feature requests to
555             L.
556              
557             Note that File::Next does NOT use L for bug tracking.
558              
559             =head1 SUPPORT
560              
561             You can find documentation for this module with the perldoc command.
562              
563             perldoc File::Next
564              
565             You can also look for information at:
566              
567             =over 4
568              
569             =item * File::Next's bug queue
570              
571             L
572              
573             =item * CPAN Ratings
574              
575             L
576              
577             =item * Search CPAN
578              
579             L
580              
581             =item * Source code repository
582              
583             L
584              
585             =back
586              
587             =head1 ACKNOWLEDGEMENTS
588              
589             All file-finding in this module is adapted from Mark Jason Dominus'
590             marvelous I, page 126.
591              
592             Thanks to these fine contributors:
593             Varadinsky,
594             Paulo Custodio,
595             Gerhard Poul,
596             Brian Fraser,
597             Todd Rinaldo,
598             Bruce Woodward,
599             Christopher J. Madsen,
600             Bernhard Fisseni
601             and Rob Hoelz.
602              
603             =head1 COPYRIGHT & LICENSE
604              
605             Copyright 2005-2017 Andy Lester.
606              
607             This program is free software; you can redistribute it and/or modify
608             it under the terms of the Artistic License version 2.0.
609              
610             =cut
611              
612             1; # End of File::Next