This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Quote string argument in example -- necessary if using strict subs
[perl5.git] / lib / find.pl
1 # Usage:
2 #       require "find.pl";
3 #
4 #       &find('/foo','/bar');
5 #
6 #       sub wanted { ... }
7 #               where wanted does whatever you want.  $dir contains the
8 #               current directory name, and $_ the current filename within
9 #               that directory.  $name contains "$dir/$_".  You are cd'ed
10 #               to $dir when the function is called.  The function may
11 #               set $prune to prune the tree.
12 #
13 # This library is primarily for find2perl, which, when fed
14 #
15 #   find2perl / -name .nfs\* -mtime +7 -exec rm -f {} \; -o -fstype nfs -prune
16 #
17 # spits out something like this
18 #
19 #       sub wanted {
20 #           /^\.nfs.*$/ &&
21 #           (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
22 #           int(-M _) > 7 &&
23 #           unlink($_)
24 #           ||
25 #           ($nlink || (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_))) &&
26 #           $dev < 0 &&
27 #           ($prune = 1);
28 #       }
29 #
30 # Set the variable $dont_use_nlink if you're using AFS, since AFS cheats.
31
32 sub find {
33     chop($cwd = `pwd`);
34     foreach $topdir (@_) {
35         (($topdev,$topino,$topmode,$topnlink) = stat($topdir))
36           || (warn("Can't stat $topdir: $!\n"), next);
37         if (-d _) {
38             if (chdir($topdir)) {
39                 ($dir,$_) = ($topdir,'.');
40                 $name = $topdir;
41                 &wanted;
42                 ($fixtopdir = $topdir) =~ s,/$,, ;
43                 &finddir($fixtopdir,$topnlink);
44             }
45             else {
46                 warn "Can't cd to $topdir: $!\n";
47             }
48         }
49         else {
50             unless (($dir,$_) = $topdir =~ m#^(.*/)(.*)$#) {
51                 ($dir,$_) = ('.', $topdir);
52             }
53             $name = $topdir;
54             chdir $dir && &wanted;
55         }
56         chdir $cwd;
57     }
58 }
59
60 sub finddir {
61     local($dir,$nlink) = @_;
62     local($dev,$ino,$mode,$subcount);
63     local($name);
64
65     # Get the list of files in the current directory.
66
67     opendir(DIR,'.') || (warn "Can't open $dir: $!\n", return);
68     local(@filenames) = readdir(DIR);
69     closedir(DIR);
70
71     if ($nlink == 2 && !$dont_use_nlink) {  # This dir has no subdirectories.
72         for (@filenames) {
73             next if $_ eq '.';
74             next if $_ eq '..';
75             $name = "$dir/$_";
76             $nlink = 0;
77             &wanted;
78         }
79     }
80     else {                    # This dir has subdirectories.
81         $subcount = $nlink - 2;
82         for (@filenames) {
83             next if $_ eq '.';
84             next if $_ eq '..';
85             $nlink = $prune = 0;
86             $name = "$dir/$_";
87             &wanted;
88             if ($subcount > 0 || $dont_use_nlink) {    # Seen all the subdirs?
89
90                 # Get link count and check for directoriness.
91
92                 ($dev,$ino,$mode,$nlink) = lstat($_) unless $nlink;
93                 
94                 if (-d _) {
95
96                     # It really is a directory, so do it recursively.
97
98                     if (!$prune && chdir $_) {
99                         &finddir($name,$nlink);
100                         chdir '..';
101                     }
102                     --$subcount;
103                 }
104             }
105         }
106     }
107 }
108 1;