8 | 8 |
|
9 | 9 |
=head1 VERSION
|
10 | 10 |
|
11 | |
Version 1.16
|
|
11 |
Version 1.18
|
12 | 12 |
|
13 | 13 |
=cut
|
14 | 14 |
|
15 | |
our $VERSION = '1.16';
|
|
15 |
our $VERSION = '1.18';
|
16 | 16 |
|
17 | 17 |
=head1 SYNOPSIS
|
18 | 18 |
|
19 | 19 |
File::Next is a lightweight, taint-safe file-finding module.
|
20 | |
It's lightweight and has no non-core prerequisites.
|
|
20 |
It has no non-core prerequisites.
|
21 | 21 |
|
22 | 22 |
use File::Next;
|
23 | 23 |
|
|
261 | 261 |
|
262 | 262 |
my ($parms,@queue) = _setup( \%files_defaults, @_ );
|
263 | 263 |
|
|
264 |
my $filter = $parms->{file_filter};
|
264 | 265 |
return sub {
|
265 | |
my $filter = $parms->{file_filter};
|
266 | |
while (@queue) {
|
267 | |
my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
|
268 | |
if ( -f $fullpath || -p _ || $fullpath =~ m{^/dev/fd} ) {
|
|
266 |
while ( my $entry = shift @queue ) {
|
|
267 |
my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
|
|
268 |
if ( $is_file || $is_fifo ) {
|
269 | 269 |
if ( $filter ) {
|
270 | 270 |
local $_ = $file;
|
271 | 271 |
local $File::Next::dir = $dirname;
|
|
274 | 274 |
}
|
275 | 275 |
return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
|
276 | 276 |
}
|
277 | |
if ( -d _ ) {
|
|
277 |
if ( $is_dir ) {
|
278 | 278 |
unshift( @queue, _candidate_files( $parms, $fullpath ) );
|
279 | 279 |
}
|
280 | 280 |
} # while
|
|
290 | 290 |
my ($parms,@queue) = _setup( \%files_defaults, @_ );
|
291 | 291 |
|
292 | 292 |
return sub {
|
293 | |
while (@queue) {
|
294 | |
my (undef,undef,$fullpath) = splice( @queue, 0, 3 );
|
295 | |
if ( -d $fullpath ) {
|
|
293 |
while ( my $entry = shift @queue ) {
|
|
294 |
my ( undef, undef, $fullpath, $is_dir, undef, undef ) = @{$entry};
|
|
295 |
if ( $is_dir ) {
|
296 | 296 |
unshift( @queue, _candidate_files( $parms, $fullpath ) );
|
297 | 297 |
return $fullpath;
|
298 | 298 |
}
|
|
302 | 302 |
}; # iterator
|
303 | 303 |
}
|
304 | 304 |
|
|
305 |
|
305 | 306 |
sub everything {
|
306 | 307 |
die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
|
307 | 308 |
|
308 | 309 |
my ($parms,@queue) = _setup( \%files_defaults, @_ );
|
309 | 310 |
|
|
311 |
my $filter = $parms->{file_filter};
|
310 | 312 |
return sub {
|
311 | |
my $filter = $parms->{file_filter};
|
312 | |
while (@queue) {
|
313 | |
my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
|
314 | |
if ( -d $fullpath ) {
|
|
313 |
while ( my $entry = shift @queue ) {
|
|
314 |
my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
|
|
315 |
if ( $is_dir ) {
|
315 | 316 |
unshift( @queue, _candidate_files( $parms, $fullpath ) );
|
316 | 317 |
}
|
317 | 318 |
if ( $filter ) {
|
|
334 | 335 |
my $err = $parms->{error_handler};
|
335 | 336 |
my $warn = $parms->{warning_handler};
|
336 | 337 |
|
337 | |
my $filename = $queue[1];
|
|
338 |
my $filename = $queue[0]->[1];
|
338 | 339 |
|
339 | 340 |
if ( !defined($filename) ) {
|
340 | 341 |
$err->( 'Must pass a filename to from_file()' );
|
|
352 | 353 |
}
|
353 | 354 |
}
|
354 | 355 |
|
|
356 |
my $filter = $parms->{file_filter};
|
355 | 357 |
return sub {
|
356 | |
my $filter = $parms->{file_filter};
|
357 | 358 |
local $/ = $parms->{nul_separated} ? "\x00" : $/;
|
358 | 359 |
while ( my $fullpath = <$fh> ) {
|
359 | 360 |
chomp $fullpath;
|
|
411 | 412 |
The queue prep stuff takes the strings in I<@starting_points> and
|
412 | 413 |
puts them in the format that queue needs.
|
413 | 414 |
|
414 | |
The C<@queue> that gets passed around is an array that has three
|
415 | |
elements for each of the entries in the queue: $dir, $file and
|
416 | |
$fullpath. Items must be pushed and popped off the queue three at
|
417 | |
a time (spliced, really).
|
|
415 |
The C<@queue> that gets passed around is an array, with each entry an
|
|
416 |
arrayref of $dir, $file and $fullpath.
|
418 | 417 |
|
419 | 418 |
=cut
|
420 | 419 |
|
|
433 | 432 |
}
|
434 | 433 |
|
435 | 434 |
# Any leftover keys are bogus
|
436 | |
for my $badkey ( keys %passed_parms ) {
|
|
435 |
for my $badkey ( sort keys %passed_parms ) {
|
437 | 436 |
my $sub = (caller(1))[3];
|
438 | 437 |
$parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
|
439 | 438 |
}
|
|
446 | 445 |
|
447 | 446 |
for ( @_ ) {
|
448 | 447 |
my $start = reslash( $_ );
|
449 | |
if (-d $start) {
|
450 | |
push @queue, ($start,undef,$start);
|
451 | |
}
|
452 | |
else {
|
453 | |
push @queue, (undef,$start,$start);
|
454 | |
}
|
|
448 |
my $is_dir = -d $start;
|
|
449 |
my $is_file = -f _;
|
|
450 |
my $is_fifo = (-p _) || ($start =~ m{^/dev/fd});
|
|
451 |
push @queue,
|
|
452 |
$is_dir
|
|
453 |
? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
|
|
454 |
: [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
|
455 | 455 |
}
|
456 | 456 |
|
457 | 457 |
return ($parms,@queue);
|
|
479 | 479 |
my @newfiles;
|
480 | 480 |
my $descend_filter = $parms->{descend_filter};
|
481 | 481 |
my $follow_symlinks = $parms->{follow_symlinks};
|
482 | |
my $sort_sub = $parms->{sort_files};
|
483 | 482 |
|
484 | 483 |
for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
|
485 | |
my $has_stat;
|
486 | |
|
487 | 484 |
my $fullpath = File::Spec->catdir( $dirname, $file );
|
488 | 485 |
if ( !$follow_symlinks ) {
|
489 | 486 |
next if -l $fullpath;
|
490 | |
$has_stat = 1;
|
491 | 487 |
}
|
|
488 |
else {
|
|
489 |
stat($fullpath);
|
|
490 |
}
|
|
491 |
my $is_dir = -d _;
|
|
492 |
my $is_file = -f _;
|
|
493 |
my $is_fifo = (-p _) || ($fullpath =~ m{^/dev/fd});
|
492 | 494 |
|
493 | 495 |
# Only do directory checking if we have a descend_filter
|
494 | 496 |
if ( $descend_filter ) {
|
495 | |
if ( $has_stat ? (-d _) : (-d $fullpath) ) {
|
|
497 |
if ( $is_dir ) {
|
496 | 498 |
local $File::Next::dir = $fullpath;
|
497 | 499 |
local $_ = $file;
|
498 | 500 |
next if not $descend_filter->();
|
499 | 501 |
}
|
500 | 502 |
}
|
501 | |
if ( $sort_sub ) {
|
502 | |
push( @newfiles, [ $dirname, $file, $fullpath ] );
|
503 | |
}
|
504 | |
else {
|
505 | |
push( @newfiles, $dirname, $file, $fullpath );
|
506 | |
}
|
|
503 |
push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
|
507 | 504 |
}
|
508 | 505 |
closedir $dh;
|
509 | 506 |
|
|
507 |
my $sort_sub = $parms->{sort_files};
|
510 | 508 |
if ( $sort_sub ) {
|
511 | |
return map { @{$_} } sort $sort_sub @newfiles;
|
|
509 |
@newfiles = sort $sort_sub @newfiles;
|
512 | 510 |
}
|
513 | 511 |
|
514 | 512 |
return @newfiles;
|
515 | 513 |
}
|
|
514 |
|
516 | 515 |
|
517 | 516 |
=head1 DIAGNOSTICS
|
518 | 517 |
|
|
570 | 569 |
|
571 | 570 |
L<http://github.com/petdance/file-next/issues>
|
572 | 571 |
|
573 | |
=item * AnnoCPAN: Annotated CPAN documentation
|
574 | |
|
575 | |
L<http://annocpan.org/dist/File-Next>
|
576 | |
|
577 | 572 |
=item * CPAN Ratings
|
578 | 573 |
|
579 | 574 |
L<http://cpanratings.perl.org/d/File-Next>
|
|
593 | 588 |
All file-finding in this module is adapted from Mark Jason Dominus'
|
594 | 589 |
marvelous I<Higher Order Perl>, page 126.
|
595 | 590 |
|
596 | |
Thanks also for bug fixes and typo finding to
|
|
591 |
Thanks to these fine contributors:
|
|
592 |
Varadinsky,
|
|
593 |
Paulo Custodio,
|
597 | 594 |
Gerhard Poul,
|
598 | 595 |
Brian Fraser,
|
599 | 596 |
Todd Rinaldo,
|
|
604 | 601 |
|
605 | 602 |
=head1 COPYRIGHT & LICENSE
|
606 | 603 |
|
607 | |
Copyright 2005-2016 Andy Lester.
|
|
604 |
Copyright 2005-2017 Andy Lester.
|
608 | 605 |
|
609 | 606 |
This program is free software; you can redistribute it and/or modify
|
610 | 607 |
it under the terms of the Artistic License version 2.0.
|