Manual integration error in #12235.
[p5sagit/p5-mst-13.2.git] / lib / File / Find.pm
index e2bb8ab..ae76323 100644 (file)
@@ -1,8 +1,8 @@
 package File::Find;
+use 5.006;
 use strict;
 use warnings;
-use 5.6.0;
-our $VERSION = '1.01';
+our $VERSION = '1.02';
 require Exporter;
 require Cwd;
 
@@ -63,7 +63,7 @@ The value should be a code reference. It is invoked just before leaving
 the currently processed directory. It is called in void context with no 
 arguments. The name of the current directory is in $File::Find::dir. This 
 hook is handy for summarizing a directory, such as calculating its disk 
-usage. When I<follow> or I<follow_fast> are in effect, C<preprocess> is a 
+usage. When I<follow> or I<follow_fast> are in effect, C<postprocess> is a 
 no-op.
 
 =item C<follow>
@@ -108,6 +108,13 @@ processed a second time.
 C<follow_skip==2> causes File::Find to ignore any duplicate files and
 directories but to proceed normally otherwise.
 
+=item C<dangling_symlinks>
+
+If true and a code reference, will be called with the symbolic link
+name and the directory it lives in as arguments.  Otherwise, if true
+and warnings are on, warning "symbolic_link_name is a dangling
+symbolic link\n" will be issued.  If false, the dangling symbolic link
+will be silently ignored.
 
 =item C<no_chdir>
 
@@ -128,7 +135,7 @@ not in taint-mode, C<untaint> is a no-op.
 
 See above. This should be set using the C<qr> quoting operator.
 The default is set to  C<qr|^([-+@\w./]+)$|>. 
-Note that the parantheses are vital.
+Note that the parentheses are vital.
 
 =item C<untaint_skip>
 
@@ -169,12 +176,15 @@ produces something like:
         ($File::Find::prune = 1);
     }
 
+Notice the C<_> in the above C<int(-M _)>: the C<_> is a magical
+filehandle that caches the information from the preceding
+stat(), lstat(), or filetest.
+
 Set the variable C<$File::Find::dont_use_nlink> if you're using AFS,
 since AFS cheats.
 
-
-Here's another interesting wanted function.  It will find all symlinks
-that don't resolve:
+Here's another interesting wanted function.  It will find all symbolic
+links that don't resolve:
 
     sub wanted {
          -l && !-e && print "bogus link: $File::Find::name\n";
@@ -237,7 +247,7 @@ directories (requires Mac::Files):
  use Mac::Files;
 
  # invisible() --  returns 1 if file/directory is invisible,  
- # 0 if it's visible or undef if an error occured
+ # 0 if it's visible or undef if an error occurred
 
  sub invisible($) { 
    my $file = shift;
@@ -293,7 +303,7 @@ require File::Spec;
 our %SLnkSeen;
 our ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
     $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
-    $pre_process, $post_process);
+    $pre_process, $post_process, $dangling_symlinks);
 
 sub contract_name {
     my ($cdir,$fn) = @_;
@@ -462,25 +472,26 @@ sub _find_opt {
     local %SLnkSeen;
     local ($wanted_callback, $avoid_nlink, $bydepth, $no_chdir, $follow,
        $follow_skip, $full_check, $untaint, $untaint_skip, $untaint_pat,
-       $pre_process, $post_process);
+       $pre_process, $post_process, $dangling_symlinks);
     local($dir, $name, $fullname, $prune);
 
-    my $cwd           = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::cwd();
-    my $cwd_untainted = $cwd;
-    my $check_t_cwd   = 1;
-    $wanted_callback  = $wanted->{wanted};
-    $bydepth          = $wanted->{bydepth};
-    $pre_process      = $wanted->{preprocess};
-    $post_process     = $wanted->{postprocess};
-    $no_chdir         = $wanted->{no_chdir};
-    $full_check       = $wanted->{follow};
-    $follow           = $full_check || $wanted->{follow_fast};
-    $follow_skip      = $wanted->{follow_skip};
-    $untaint          = $wanted->{untaint};
-    $untaint_pat      = $wanted->{untaint_pattern};
-    $untaint_skip     = $wanted->{untaint_skip};
-
-    # for compatability reasons (find.pl, find2perl)
+    my $cwd            = $wanted->{bydepth} ? Cwd::fastcwd() : Cwd::getcwd();
+    my $cwd_untainted  = $cwd;
+    my $check_t_cwd    = 1;
+    $wanted_callback   = $wanted->{wanted};
+    $bydepth           = $wanted->{bydepth};
+    $pre_process       = $wanted->{preprocess};
+    $post_process      = $wanted->{postprocess};
+    $no_chdir          = $wanted->{no_chdir};
+    $full_check        = $wanted->{follow};
+    $follow            = $full_check || $wanted->{follow_fast};
+    $follow_skip       = $wanted->{follow_skip};
+    $untaint           = $wanted->{untaint};
+    $untaint_pat       = $wanted->{untaint_pattern};
+    $untaint_skip      = $wanted->{untaint_skip};
+    $dangling_symlinks = $wanted->{dangling_symlinks};
+
+    # for compatibility reasons (find.pl, find2perl)
     local our ($topdir, $topdev, $topino, $topmode, $topnlink);
 
     # a symbolic link to a directory doesn't increase the link count
@@ -495,7 +506,7 @@ sub _find_opt {
        if ($Is_MacOS) {
            ($topdev,$topino,$topmode,$topnlink) = $follow ? stat $top_item : lstat $top_item;
            $top_item = ":$top_item"
-               if ( (-d _) && ($top_item =~ /^[^:]+\z/) );
+               if ( (-d _) && ( $top_item !~ /:/ ) );
        }
        else {
            $top_item =~ s|/\z|| unless $top_item eq '/';
@@ -515,7 +526,7 @@ sub _find_opt {
                else {
                    $abs_dir = contract_name_Mac($cwd, $top_item);
                    unless (defined $abs_dir) {
-                       warn "Can't determine absolute path for $top_item (No such file or directory)\n";
+                       warn "Can't determine absolute path for $top_item (No such file or directory)\n" if $^W;
                        next Proc_Top_Item;
                    }
                }
@@ -534,7 +545,13 @@ sub _find_opt {
            }
            $abs_dir= Follow_SymLink($abs_dir);
            unless (defined $abs_dir) {
-               warn "$top_item is a dangling symbolic link\n";
+               if ($dangling_symlinks) {
+                   if (ref $dangling_symlinks eq 'CODE') {
+                       $dangling_symlinks->($top_item, $cwd);
+                   } else {
+                       warn "$top_item is a dangling symbolic link\n" if $^W;
+                   }
+               }
                next Proc_Top_Item;
            }
 
@@ -546,7 +563,7 @@ sub _find_opt {
        else { # no follow
            $topdir = $top_item;
            unless (defined $topnlink) {
-               warn "Can't stat $top_item: $!\n";
+               warn "Can't stat $top_item: $!\n" if $^W;
                next Proc_Top_Item;
            }
            if (-d _) {
@@ -583,7 +600,7 @@ sub _find_opt {
            }
 
            unless ($no_chdir || chdir $abs_dir) {
-               warn "Couldn't chdir $abs_dir: $!\n";
+               warn "Couldn't chdir $abs_dir: $!\n" if $^W;
                next Proc_Top_Item;
            }
 
@@ -624,16 +641,14 @@ sub _find_dir($$$) {
     my $SE= [];
     my $dir_name= $p_dir;
     my $dir_pref;
-    my $dir_rel;
+    my $dir_rel = $File::Find::current_dir;
     my $tainted = 0;
 
     if ($Is_MacOS) {
        $dir_pref= ($p_dir =~ /:$/) ? $p_dir : "$p_dir:"; # preface
-       $dir_rel= ':'; # directory name relative to current directory
     }
     else {
        $dir_pref= ( $p_dir eq '/' ? '/' : "$p_dir/" );
-       $dir_rel= '.'; # directory name relative to current directory
     }
 
     local ($dir, $name, $prune, *DIR);
@@ -652,7 +667,7 @@ sub _find_dir($$$) {
            }
        }
        unless (chdir $udir) {
-           warn "Can't cd to $udir: $!\n";
+           warn "Can't cd to $udir: $!\n" if $^W;
            return;
        }
     }
@@ -695,10 +710,10 @@ sub _find_dir($$$) {
            }
            unless (chdir $udir) {
                if ($Is_MacOS) {
-                   warn "Can't cd to ($p_dir) $udir: $!\n";
+                   warn "Can't cd to ($p_dir) $udir: $!\n" if $^W;
                }
                else {
-                   warn "Can't cd to (" . ($p_dir ne '/' ? $p_dir : '') . "/) $udir: $!\n";
+                   warn "Can't cd to (" . ($p_dir ne '/' ? $p_dir : '') . "/) $udir: $!\n" if $^W;
                }
                next;
            }
@@ -713,7 +728,7 @@ sub _find_dir($$$) {
 
        # Get the list of files in the current directory.
        unless (opendir DIR, ($no_chdir ? $dir_name : $File::Find::current_dir)) {
-           warn "Can't opendir($dir_name): $!\n";
+           warn "Can't opendir($dir_name): $!\n" if $^W;
            next;
        }
        @filenames = readdir DIR;
@@ -792,12 +807,7 @@ sub _find_dir($$$) {
 
            if ( $nlink == -2 ) {
                $name = $dir = $p_dir; # $File::Find::name / dir
-               if ($Is_MacOS) {
-                   $_ = ':'; # $_
-               }
-               else {
-                   $_ = '.';
-               }
+                $_ = $File::Find::current_dir;
                &$post_process;         # End-of-directory processing
            }
            elsif ( $nlink < 0 ) {  # must be finddepth, report dirname now
@@ -848,7 +858,7 @@ sub _find_dir_symlnk($$$) {
     my $dir_name = $p_dir;
     my $dir_pref;
     my $loc_pref;
-    my $dir_rel;
+    my $dir_rel = $File::Find::current_dir;
     my $byd_flag; # flag for pending stack entry if $bydepth
     my $tainted = 0;
     my $ok = 1;
@@ -856,11 +866,9 @@ sub _find_dir_symlnk($$$) {
     if ($Is_MacOS) {
        $dir_pref = ($p_dir =~ /:$/) ? "$p_dir" : "$p_dir:";
        $loc_pref = ($dir_loc =~ /:$/) ? "$dir_loc" : "$dir_loc:";
-       $dir_rel  = ':'; # directory name relative to current directory
     } else {
        $dir_pref = ( $p_dir   eq '/' ? '/' : "$p_dir/" );
        $loc_pref = ( $dir_loc eq '/' ? '/' : "$dir_loc/" );
-       $dir_rel  = '.'; # directory name relative to current directory
     }
 
     local ($dir, $name, $fullname, $prune, *DIR);
@@ -883,7 +891,7 @@ sub _find_dir_symlnk($$$) {
        }
        $ok = chdir($updir_loc) unless ($p_dir eq $File::Find::current_dir);
        unless ($ok) {
-           warn "Can't cd to $updir_loc: $!\n";
+           warn "Can't cd to $updir_loc: $!\n" if $^W;
            return;
        }
     }
@@ -900,7 +908,7 @@ sub _find_dir_symlnk($$$) {
            # change (back) to parent directory (always untainted)
            unless ($no_chdir) {
                unless (chdir $updir_loc) {
-                   warn "Can't cd to $updir_loc: $!\n";
+                   warn "Can't cd to $updir_loc: $!\n" if $^W;
                    next;
                }
            }
@@ -931,7 +939,7 @@ sub _find_dir_symlnk($$$) {
                }
            }
            unless (chdir $updir_loc) {
-               warn "Can't cd to $updir_loc: $!\n";
+               warn "Can't cd to $updir_loc: $!\n" if $^W;
                next;
            }
        }
@@ -944,7 +952,7 @@ sub _find_dir_symlnk($$$) {
 
        # Get the list of files in the current directory.
        unless (opendir DIR, ($no_chdir ? $dir_loc : $File::Find::current_dir)) {
-           warn "Can't opendir($dir_loc): $!\n";
+           warn "Can't opendir($dir_loc): $!\n" if $^W;
            next;
        }
        @filenames = readdir DIR;
@@ -989,7 +997,7 @@ sub _find_dir_symlnk($$$) {
            if ( $byd_flag < 0 ) {  # must be finddepth, report dirname now
                unless ($no_chdir || ($dir_rel eq $File::Find::current_dir)) {
                    unless (chdir $updir_loc) { # $updir_loc (parent dir) is always untainted 
-                       warn "Can't cd to $updir_loc: $!\n";
+                       warn "Can't cd to $updir_loc: $!\n" if $^W;
                        next;
                    }
                }