File Coverage

inc/FindBin/libs.pm
Criterion Covered Total %
statement 58 72 80.5
branch 12 28 42.8
condition 11 21 52.3
subroutine 11 11 100.0
pod 0 1 0.0
total 92 133 69.1


line stmt bran cond sub pod time code
1             #line 1
2             ########################################################################
3             # FindBin::libs
4             #
5             # use $FindBin::Bin to search for 'lib' directories and use them.
6             #
7             # default action is to look for dir's named "lib" and silently use
8             # the lib's without exporting anything. print turns on a short
9             # message with the abs_path results, export pushes out a variable
10             # (default name is the base value), verbose turns on decision output
11             # and print. export takes an optional argument with the name of a
12             # variable to export.
13             #
14             # Copyright (C) 2003, Steven Lembark, Workhorse Computing.
15             # This code is released under the same terms as Perl-5.6.1
16             # or any later version of Perl.
17             #
18             ########################################################################
19              
20             ########################################################################
21             # housekeeping
22             ########################################################################
23              
24             package FindBin::libs;
25 1     1   836  
  1         2  
  1         36  
26             use 5.00601;
27 1     1   4  
  1         2  
  1         32  
28             use strict;
29 1     1   4  
  1         1  
  1         103  
30             use Carp qw( &croak );
31 1     1   807  
  1         1093  
  1         40  
32             use FindBin;
33 1     1   6  
  1         1  
  1         52  
34             use Symbol;
35              
36             # both of these are in the standard distro and
37             # should be available.
38 1     1   4  
  1         2  
  1         52  
39             use File::Basename;
40              
41             use File::Spec::Functions
42 1         133 qw
43             (
44             &splitpath
45             &splitdir
46             &catpath
47 1     1   819 &catdir
  1         785  
48             );
49              
50             BEGIN
51             {
52             # however... there have been complaints of
53             # places where abs_path does not work.
54             #
55             # if abs_path fails on the working directory
56             # then replace it with rel2abs and live with
57             # possibly slower, redundant directories.
58             #
59             # the abs_path '//' hack allows for testing
60             # broken abs_path on primitive systems that
61             # cannot handle the rooted system being linked
62             # back to itself.
63 1     1   5  
  1         2  
  1         152  
64             use Cwd qw( &abs_path &cwd );
65 1 50   1   1  
  1         4  
  1         7004  
66             unless( eval {abs_path '//'; abs_path cwd } )
67             {
68             # abs_path seems to be having problems,
69             # fix is to stub it out. ref and sub are
70             # syntatic sugar, but do you really want
71             # to see it all on one line???
72             #
73             # undef avoids re-defining subroutine nastygram.
74 0         0  
75             my $ref = qualify_to_ref 'abs_path', __PACKAGE__;
76 0         0  
77             my $sub = File::Spec::Functions->can( 'rel2abs' );
78 0         0  
  0         0  
79             undef &{ $ref };
80 0         0  
81             *$ref = $sub
82             };
83             }
84              
85             ########################################################################
86             # package variables
87             ########################################################################
88              
89             our $VERSION = '1.40';
90              
91             my %defaultz =
92             (
93             Bin => $FindBin::Bin,
94             base => 'lib',
95             use => 1,
96              
97             subdir => '', # add this subdir also if found.
98             subonly => undef, # leave out lib's, use only subdir.
99             export => undef, # push variable into caller's space.
100             verbose => undef, # boolean: print inputs, results.
101             debug => undef, # boolean: set internal breakpoints.
102              
103             print => undef, # display the results
104              
105             p5lib => undef, # prefix PERL5LIB with the results
106              
107             ignore => '/,/usr', # dir's to skip looking for ./lib
108             );
109              
110             # only new directories are used, ignore pre-loads
111             # this with unwanted values.
112              
113             my %found = ();
114              
115             # saves passing this between import and $handle_args.
116              
117             my %argz = ();
118              
119             my $verbose = '';
120              
121             my $empty = q{};
122              
123             ########################################################################
124             # subroutines
125             ########################################################################
126              
127             # HAK ALERT: $Bin is an absolute path, there are cases
128             # where splitdir does not add the leading '' onto the
129             # directory path for it on VMS. Fix is to unshift a leading
130             # '' into @dirpath where the leading entry is true.
131              
132             sub find_libs
133 1   33 1 0 90 {
134             my $base = basename ( shift || $argz{ base } );
135 1   50     8  
136             my $subdir = $argz{ subdir } || '';
137 1         2  
138             my $subonly = defined $argz{ subonly };
139              
140             # for some reason, RH Enterprise V/4 has a
141             # trailing '/'; I havn't seen another copy of
142             # FindBin that does this. fix is quick enough:
143             # strip the trailing '/'.
144             #
145             # using a regex to extract the value untaints it.
146             # after that split path can grab the directory
147             # portion for future use.
148 1         3  
149             my ( $Bin ) = $argz{ Bin } =~ m{^ (.+) }xs;
150 1 50       3  
151             print STDERR "\nSearching $Bin for '$base'...\n"
152             if $verbose;
153 1         7  
154             my( $vol, $dir ) = splitpath $Bin, 1;
155 1         27  
156             my @dirpath = splitdir $dir;
157              
158             # fix for File::Spec::VMS missing the leading empty
159             # string on a split. this can be removed once File::Spec
160             # is fixed.
161 1 50       10  
162             unshift @dirpath, '' if $dirpath[ 0 ];
163 1         1  
164             my @libz = ();
165 1         3  
166             for( 1 .. @dirpath )
167             {
168             # note that catpath is extraneous on *NIX; the
169             # volume only means something on DOS- & VMS-based
170             # filesystems, and adding an empty basename on
171             # *nix is unnecessary.
172             #
173             # HAK ALERT: the poor slobs stuck on windog have an
174             # abs_path that croaks on missing directories. have
175             # to eval the check for subdir's.
176              
177 5   50     6 my $abs
178             = eval { abs_path catpath $vol, ( catdir @dirpath, $base ), $empty }
179             || '';
180              
181             my $sub
182 5 50 0     217 = $subdir
183             ? eval { abs_path ( catpath '', $abs, $subdir ) } || ''
184             : ''
185             ;
186 5 50       13  
187             my @search = $subonly ? ( $sub ) : ( $abs, $sub );
188 5         6  
189             for my $dir ( @search )
190 10 100 100     101 {
      100        
191             if( $dir && -d $dir && ! exists $found{ $dir } )
192 1         2 {
193             $found{ $dir } = 1;
194 1         2  
195             push @libz, $dir;
196             }
197             }
198              
199 5         11 pop @dirpath
200             }
201              
202             # caller gets back the existing lib paths
203             # (including volume) walking up the path
204             # from $FindBin::Bin -> root.
205             #
206             # passing it back as a list isn't all that
207             # painful for a few paths.
208 1 50       5  
209             wantarray ? @libz : \@libz
210             };
211              
212             # break out the messy part into a separate block.
213              
214             my $handle_args
215             = sub
216             {
217             # discard the module, rest are arguments.
218              
219             shift;
220              
221             # anything after the module are options with arguments
222             # assigned via '='.
223              
224             %argz
225             = map
226             {
227             my ( $k, $v ) = split '=', $_, 2;
228              
229             if( $k =~ s{^(?:!|no)}{} )
230             {
231             $k => undef
232             }
233             else
234             {
235             $k => ( $v || '' )
236             }
237             }
238             @_;
239              
240             # stuff "debug=1" into your arguments and perl -d will stop here.
241              
242             $DB::single = 1 if $argz{debug};
243              
244             # use lib behavior is turned off by default if export or
245             # perl5lib udpate are requested.
246              
247             exists $argz{use} or $defaultz{use} = ! exists $argz{export};
248             exists $argz{use} or $defaultz{use} = ! exists $argz{p5lib};
249              
250             # now apply the defaults, then sanity check the result.
251             # base is a special case since it always has to exist.
252             #
253             # if $argz{export} is defined but false then it takes
254             # its default from $argz{base}.
255              
256             exists $argz{$_} or $argz{$_} = $defaultz{$_}
257             for keys %defaultz;
258              
259             exists $argz{base} && $argz{base}
260             or croak "Bogus FindBin::libs: missing/false base argument, should be 'base=NAME'";
261              
262             defined $argz{export} and $argz{export} ||= $argz{base};
263              
264             $argz{ ignore } =
265             [
266             grep { $_ }
267             split /\s*,\s*/,
268             $argz{ignore}
269             ];
270              
271             $verbose = defined $argz{verbose};
272              
273             my $base = $argz{base};
274              
275             # now locate the libraries.
276             #
277             # %found contains the abs_path results for each directory to
278             # avoid double-including directories.
279             #
280             # note: loop short-curcuts for the (usually) list.
281              
282             %found = ();
283              
284             for( @{ $argz{ ignore } } )
285             {
286             if( my $dir = eval { abs_path catdir $_, $base } )
287             {
288             if( -d $dir )
289             {
290             $found{ $dir } = 1;
291             }
292             }
293             }
294             };
295              
296             sub import
297 1     1   39 {
298             &$handle_args;
299 1         10  
300             my @libz = find_libs;
301              
302             # HAK ALERT: the regex does nothing for security,
303             # just dodges -T. putting this down here instead
304             # of inside find_libs allows people to use saner
305             # untainting plans via find_libs.
306 1         2  
  1         5  
307             @libz = map { m{ (.+) }x } @libz;
308 1         2  
309             my $caller = caller;
310 1 50 33     7  
311             if( $verbose || defined $argz{print} )
312 0         0 {
313 0         0 local $\ = "\n";
314             local $, = "\n\t";
315 0         0  
316             print STDERR "Found */$argz{ base }:", @libz
317             }
318 1 50       3  
319             if( $argz{export} )
320 0         0 {
321             my $caller = caller;
322 0 0       0  
323             print STDERR join '', "\nExporting: @", $caller, '::', $argz{export}, "\n"
324             if $verbose;
325              
326             # Symbol this is cleaner than "no strict"
327             # for installing the array.
328 0         0  
329             my $ref = qualify_to_ref $argz{ export }, $caller;
330 0         0  
331             *$ref = \@libz;
332             }
333 1 50       5  
334             if( defined $argz{ p5lib } )
335             {
336             # stuff the lib's found at the front of $ENV{ PERL5LIB }
337 0 0       0  
338             ( substr $ENV{ PERL5LIB }, 0, 0 ) = join ':', @libz, ''
339             if @libz;
340 0 0       0  
341             print STDERR "\nUpdated PERL5LIB:\t$ENV{ PERL5LIB }\n"
342             if $verbose;
343             }
344 1 50 33     7  
345             if( $argz{use} && @libz )
346             {
347             # this obviously won't work if lib ever depends
348             # on the caller's package.
349             #
350             # it does avoids issues with -T blowing up on the
351             # old eval technique.
352 1         1013  
353             require lib;
354 1         790  
355             lib->import( @libz );
356             }
357              
358 1         156 0
359             }
360              
361             # keep require happy
362              
363             1
364              
365             __END__