File Coverage

blib/lib/File/Which.pm
Criterion Covered Total %
statement 52 56 92.8
branch 12 18 66.6
condition 6 14 42.8
subroutine 11 11 100.0
pod 2 2 100.0
total 83 101 82.1


line stmt bran cond sub pod time code
1             package File::Which;
2              
3 2     2   87894 use strict;
  2         13  
  2         66  
4 2     2   10 use warnings;
  2         5  
  2         70  
5 2     2   10 use base qw( Exporter );
  2         4  
  2         317  
6 2     2   15 use File::Spec ();
  2         3  
  2         189  
7              
8             # ABSTRACT: Perl implementation of the which utility as an API
9             our $VERSION = '1.27'; # VERSION
10              
11              
12             our @EXPORT = 'which';
13             our @EXPORT_OK = 'where';
14              
15 2     2   15 use constant IS_VMS => ($^O eq 'VMS');
  2         4  
  2         233  
16 2     2   15 use constant IS_MAC => ($^O eq 'MacOS');
  2         4  
  2         155  
17 2   33 2   12 use constant IS_WIN => ($^O eq 'MSWin32' or $^O eq 'dos' or $^O eq 'os2');
  2         4  
  2         145  
18 2     2   14 use constant IS_DOS => IS_WIN();
  2         3  
  2         153  
19 2   33 2   14 use constant IS_CYG => ($^O eq 'cygwin' || $^O eq 'msys');
  2         5  
  2         1510  
20              
21             our $IMPLICIT_CURRENT_DIR = IS_WIN || IS_VMS || IS_MAC;
22              
23             # For Win32 systems, stores the extensions used for
24             # executable files
25             # For others, the empty string is used
26             # because 'perl' . '' eq 'perl' => easier
27             my @PATHEXT = ('');
28             if ( IS_WIN ) {
29             # WinNT. PATHEXT might be set on Cygwin, but not used.
30             if ( $ENV{PATHEXT} ) {
31             push @PATHEXT, split /;/, $ENV{PATHEXT};
32             } else {
33             # Win9X or other: doesn't have PATHEXT, so needs hardcoded.
34             push @PATHEXT, qw{.com .exe .bat};
35             }
36             } elsif ( IS_VMS ) {
37             push @PATHEXT, qw{.exe .com};
38             } elsif ( IS_CYG ) {
39             # See this for more info
40             # http://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-exe
41             push @PATHEXT, qw{.exe .com};
42             }
43              
44              
45             sub which {
46 8     8 1 5149 my ($exec) = @_;
47              
48 8 50       26 return undef unless defined $exec;
49 8 100       31 return undef if $exec eq '';
50              
51 6         13 my $all = wantarray; ## no critic (Freenode::Wantarray)
52 6         12 my @results = ();
53              
54             # check for aliases first
55 6         10 if ( IS_VMS ) {
56             my $symbol = `SHOW SYMBOL $exec`;
57             chomp($symbol);
58             unless ( $? ) {
59             return $symbol unless $all;
60             push @results, $symbol;
61             }
62             }
63 6         8 if ( IS_MAC ) {
64             my @aliases = split /\,/, $ENV{Aliases};
65             foreach my $alias ( @aliases ) {
66             # This has not been tested!!
67             # PPT which says MPW-Perl cannot resolve `Alias $alias`,
68             # let's just hope it's fixed
69             if ( lc($alias) eq lc($exec) ) {
70             chomp(my $file = `Alias $alias`);
71             last unless $file; # if it failed, just go on the normal way
72             return $file unless $all;
73             push @results, $file;
74             # we can stop this loop as if it finds more aliases matching,
75             # it'll just be the same result anyway
76             last;
77             }
78             }
79             }
80              
81 6 0 33     29 return $exec ## no critic (ValuesAndExpressions::ProhibitMixedBooleanOperators)
      33        
82             if !IS_VMS and !IS_MAC and !IS_WIN and $exec =~ /\// and -f $exec and -x $exec;
83              
84 6         9 my @path;
85 6 50       27 if($^O eq 'MSWin32') {
86             # File::Spec (at least recent versions)
87             # add the implicit . for you on MSWin32,
88             # but we may or may not want to include
89             # that.
90 0         0 @path = split /;/, $ENV{PATH};
91 0         0 s/"//g for @path;
92 0         0 @path = grep length, @path;
93             } else {
94 6         84 @path = File::Spec->path;
95             }
96 6 50       60 if ( $IMPLICIT_CURRENT_DIR ) {
97 0         0 unshift @path, File::Spec->curdir;
98             }
99              
100 6         18 foreach my $base ( map { File::Spec->catfile($_, $exec) } @path ) {
  23         409  
101 17         39 for my $ext ( @PATHEXT ) {
102 17         32 my $file = $base.$ext;
103              
104             # We don't want dirs (as they are -x)
105 17 50       322 next if -d $file;
106              
107 17 100 100     108 if (
108             # Executable, normal case
109             -x _
110             or (
111             # MacOS doesn't mark as executable so we check -e
112             IS_MAC ## no critic (ValuesAndExpressions::ProhibitMixedBooleanOperators)
113             ||
114             (
115             ( IS_WIN or IS_CYG )
116             and
117             grep { ## no critic (BuiltinFunctions::ProhibitBooleanGrep)
118             $file =~ /$_\z/i
119             } @PATHEXT[1..$#PATHEXT]
120             )
121             # DOSish systems don't pass -x on
122             # non-exe/bat/com files. so we check -e.
123             # However, we don't want to pass -e on files
124             # that aren't in PATHEXT, like README.
125             and -e _
126             )
127             ) {
128 5 100       37 return $file unless $all;
129 2         10 push @results, $file;
130             }
131             }
132             }
133              
134 3 100       13 if ( $all ) {
135 2         10 return @results;
136             } else {
137 1         8 return undef;
138             }
139             }
140              
141              
142             sub where {
143             # force wantarray
144 1     1 1 987 my @res = which($_[0]);
145 1         7 return @res;
146             }
147              
148             1;
149              
150             __END__