File Coverage

inc/FindBin/libs.pm
Criterion Covered Total %
statement 63 77 81.8
branch 13 30 43.3
condition 9 16 56.2
subroutine 12 12 100.0
pod 0 1 0.0
total 97 136 71.3


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   969  
  1         4  
  1         44  
26             use 5.00601;
27 1     1   6  
  1         2  
  1         43  
28             use strict;
29 1     1   7  
  1         3  
  1         140  
30             use Carp qw( &croak );
31 1     1   1254  
  1         1325  
  1         52  
32             use FindBin;
33 1     1   6  
  1         1  
  1         65  
34             use Symbol;
35              
36             # both of these are in the standard distro and
37             # should be available.
38 1     1   7  
  1         2  
  1         64  
39             use File::Basename;
40              
41             use File::Spec::Functions
42 1         201 qw
43             (
44             &splitpath
45             &splitdir
46             &catpath
47 1     1   1094 &catdir
  1         1022  
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   7  
  1         2  
  1         208  
64             use Cwd qw( &abs_path &cwd );
65 1 50   1   3  
  1         5  
  1         7570  
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.37';
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 = 0;
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 116 {
134             my $base = basename ( shift || $argz{ base } );
135 1   50     8  
136             my $subdir = $argz{ subdir } || '';
137 1         4  
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         4  
149             my ( $Bin ) = $argz{ Bin } =~ m{^ (.+) }xs;
150 1 50       7  
151             print STDERR "\nSearching $Bin for '$base'...\n"
152             if $verbose;
153 1         6  
154             my( $vol, $dir ) = splitpath $Bin, 1;
155 1         33  
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       13  
162             unshift @dirpath, '' if $dirpath[ 0 ];
163 1         2  
164             my @libz = ();
165 1         5  
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 stock on windog have an
174             # abs_path that croaks on missing directories. have
175             # to eval the check for subdir's.
176 5         226  
177             my $abs
178             = abs_path catpath $vol, ( catdir @dirpath, $base ), $empty;
179              
180             my $sub
181 5 50 0     244 = $subdir
182             ? eval { abs_path ( catpath '', $abs, $subdir ) } || ''
183             : ''
184             ;
185 5 50       14  
186             my @search = $subonly ? ( $sub ) : ( $abs, $sub );
187 5         10  
188             for my $dir ( @search )
189 10 100 100     123 {
      100        
190             if( $dir && -d $dir && ! exists $found{ $dir } )
191 2         5 {
192             $found{ $dir } = 1;
193 2         4  
194             push @libz, $dir;
195             }
196             }
197              
198 5         13 pop @dirpath
199             }
200              
201             # caller gets back the existing lib paths
202             # (including volume) walking up the path
203             # from $FindBin::Bin -> root.
204             #
205             # passing it back as a list isn't all that
206             # painful for a few paths.
207 1 50       89  
208             wantarray ? @libz : \@libz
209             };
210              
211             # break out the messy part into a separate block.
212              
213             my $handle_args
214             = sub
215             {
216             # discard the module, rest are arguments.
217              
218             shift;
219              
220             # anything after the module are options with arguments
221             # assigned via '='.
222              
223             %argz
224             = map
225             {
226             my ( $k, $v ) = split '=', $_, 2;
227              
228             if( $k =~ s{^(?:!|no)}{} )
229             {
230             $k => undef
231             }
232             else
233             {
234             $k => ( $v || '' )
235             }
236             }
237             @_;
238              
239             # stuff "debug=1" into your arguments and perl -d will stop here.
240              
241             $DB::single = 1 if $argz{debug};
242              
243             # use lib behavior is turned off by default if export or
244             # perl5lib udpate are requested.
245              
246             exists $argz{use} or $defaultz{use} = ! exists $argz{export};
247             exists $argz{use} or $defaultz{use} = ! exists $argz{p5lib};
248              
249             # now apply the defaults, then sanity check the result.
250             # base is a special case since it always has to exist.
251             #
252             # if $argz{export} is defined but false then it takes
253             # its default from $argz{base}.
254              
255             exists $argz{$_} or $argz{$_} = $defaultz{$_}
256             for keys %defaultz;
257              
258             exists $argz{base} && $argz{base}
259             or croak "Bogus FindBin::libs: missing/false base argument, should be 'base=NAME'";
260              
261             defined $argz{export} and $argz{export} ||= $argz{base};
262              
263             $argz{ ignore } =
264             [
265             grep { $_ }
266             split /\s*,\s*/,
267             $argz{ignore}
268             ];
269              
270             $verbose = defined $argz{verbose};
271              
272             my $base = $argz{base};
273              
274             # now locate the libraries.
275             #
276             # %found contains the abs_path results for each directory to
277             # avoid double-including directories.
278             #
279             # note: loop short-curcuts for the (usually) list.
280              
281             %found = ();
282              
283             for( @{ $argz{ ignore } } )
284             {
285             if( my $dir = abs_path catdir $_, $base )
286             {
287             if( -d $dir )
288             {
289             $found{ $dir } = 1;
290             }
291             }
292             }
293             };
294              
295             sub import
296 1     1   34 {
297             &$handle_args;
298 1         3  
299             my @libz = find_libs;
300 1         8  
301             my $caller = caller;
302 1 50 33     9  
303             if( $verbose || defined $argz{print} )
304 0         0 {
305 0         0 local $\ = "\n";
306             local $, = "\n\t";
307 0         0  
308             print STDERR "Found */$argz{ base }:", @libz
309             }
310 1 50       5  
311             if( $argz{export} )
312 0         0 {
313             my $caller = caller;
314 0 0       0  
315             print STDERR join '', "\nExporting: @", $caller, '::', $argz{export}, "\n"
316             if $verbose;
317              
318             # Symbol this is cleaner than "no strict"
319             # for installing the array.
320 0         0  
321             my $ref = qualify_to_ref $argz{ export }, $caller;
322 0         0  
323             *$ref = \@libz;
324             }
325 1 50       8  
326             if( defined $argz{ p5lib } )
327             {
328             # stuff the lib's found at the front of $ENV{ PERL5LIB }
329 0 0       0  
330             ( substr $ENV{ PERL5LIB }, 0, 0 ) = join ':', @libz, ''
331             if @libz;
332 0 0       0  
333             print STDERR "\nUpdated PERL5LIB:\t$ENV{ PERL5LIB }\n"
334             if $verbose;
335             }
336 1 50       7  
337             if( $argz{use} )
338 1         16 {
339             my @code =
340             qw
341             (
342             {
343             package caller ;
344             use lib qw( list ) ;
345             }
346             );
347              
348             # insert the caller's package and replace the "list"
349             # token with the libs found.
350 1         4  
351 1         13 $code[2] = $caller;
352             splice @code, 7, 1, @libz;
353 1         7  
354             my $code = join ' ', @code;
355 1 50       6  
356             print STDERR "\n", 'Executing:', $code, ''
357             if $verbose;
358 1     1   2078  
  1         1302  
  1         7  
  1         317  
359             eval $code
360             }
361              
362 1         5336 0
363             }
364              
365             # keep require happy
366              
367             1
368              
369             __END__