Cleanup the File::Spec tmpdir() implementations:
[p5sagit/p5-mst-13.2.git] / lib / File / Spec / Unix.pm
CommitLineData
270d1e39 1package File::Spec::Unix;
2
270d1e39 3use strict;
07824bd1 4use vars qw($VERSION);
b4296952 5
b4c5e263 6$VERSION = '1.4';
270d1e39 7
c27914c9 8use Cwd;
9
270d1e39 10=head1 NAME
11
6fad8743 12File::Spec::Unix - File::Spec for Unix, base for other File::Spec modules
270d1e39 13
14=head1 SYNOPSIS
15
cbc7acb0 16 require File::Spec::Unix; # Done automatically by File::Spec
270d1e39 17
18=head1 DESCRIPTION
19
6fad8743 20Methods for manipulating file specifications. Other File::Spec
21modules, such as File::Spec::Mac, inherit from File::Spec::Unix and
22override specific methods.
270d1e39 23
24=head1 METHODS
25
26=over 2
27
59605c55 28=item canonpath()
270d1e39 29
30No physical check on the filesystem, but a logical cleanup of a
6fad8743 31path. On UNIX eliminates successive slashes and successive "/.".
270d1e39 32
c27914c9 33 $cpath = File::Spec->canonpath( $path ) ;
c27914c9 34
270d1e39 35=cut
36
37sub canonpath {
0994714a 38 my ($self,$path) = @_;
89bb8afa 39
04ca015e 40 # Handle POSIX-style node names beginning with double slash (qnx, nto)
41 # Handle network path names beginning with double slash (cygwin)
42 # (POSIX says: "a pathname that begins with two successive slashes
43 # may be interpreted in an implementation-defined manner, although
44 # more than two leading slashes shall be treated as a single slash.")
89bb8afa 45 my $node = '';
04ca015e 46 if ( $^O =~ m/^(?:qnx|nto|cygwin)$/ && $path =~ s:^(//[^/]+)(/|\z):/:s ) {
89bb8afa 47 $node = $1;
48 }
7aa86a29 49 # This used to be
50 # $path =~ s|/+|/|g unless($^O eq 'cygwin');
51 # but that made tests 29, 30, 35, 46, and 213 (as of #13272) to fail
52 # (Mainly because trailing "" directories didn't get stripped).
53 # Why would cygwin avoid collapsing multiple slashes into one? --jhi
54 $path =~ s|/+|/|g; # xx////xx -> xx/xx
6bf11762 55 $path =~ s@(/\.)+(/|\Z(?!\n))@/@g; # xx/././xx -> xx/xx
1b1e14d3 56 $path =~ s|^(\./)+||s unless $path eq "./"; # ./xx -> xx
57 $path =~ s|^/(\.\./)+|/|s; # /../../xx -> xx
9c045eb2 58 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx
89bb8afa 59 return "$node$path";
270d1e39 60}
61
59605c55 62=item catdir()
270d1e39 63
64Concatenate two or more directory names to form a complete path ending
65with a directory. But remove the trailing slash from the resulting
66string, because it doesn't look good, isn't necessary and confuses
67OS2. Of course, if this is the root directory, don't cut off the
68trailing slash :-)
69
70=cut
71
270d1e39 72sub catdir {
cbc7acb0 73 my $self = shift;
270d1e39 74 my @args = @_;
cbc7acb0 75 foreach (@args) {
270d1e39 76 # append a slash to each argument unless it has one there
cbc7acb0 77 $_ .= "/" if $_ eq '' || substr($_,-1) ne "/";
270d1e39 78 }
cbc7acb0 79 return $self->canonpath(join('', @args));
270d1e39 80}
81
82=item catfile
83
84Concatenate one or more directory names and a filename to form a
85complete path ending with a filename
86
87=cut
88
89sub catfile {
cbc7acb0 90 my $self = shift;
63c6dcc1 91 my $file = $self->canonpath(pop @_);
270d1e39 92 return $file unless @_;
93 my $dir = $self->catdir(@_);
cbc7acb0 94 $dir .= "/" unless substr($dir,-1) eq "/";
270d1e39 95 return $dir.$file;
96}
97
98=item curdir
99
cbc7acb0 100Returns a string representation of the current directory. "." on UNIX.
270d1e39 101
102=cut
103
104sub curdir {
cbc7acb0 105 return ".";
270d1e39 106}
107
99804bbb 108=item devnull
109
cbc7acb0 110Returns a string representation of the null device. "/dev/null" on UNIX.
99804bbb 111
112=cut
113
114sub devnull {
115 return "/dev/null";
116}
117
270d1e39 118=item rootdir
119
cbc7acb0 120Returns a string representation of the root directory. "/" on UNIX.
270d1e39 121
122=cut
123
124sub rootdir {
125 return "/";
126}
127
cbc7acb0 128=item tmpdir
129
07824bd1 130Returns a string representation of the first writable directory from
131the following list or the current directory if none from the list are
132writable:
cbc7acb0 133
134 $ENV{TMPDIR}
135 /tmp
136
b4c5e263 137Since perl 5.8.0, if running under taint mode, and if $ENV{TMPDIR}
138is tainted, it is not used.
139
cbc7acb0 140=cut
141
142my $tmpdir;
07824bd1 143sub _tmpdir {
cbc7acb0 144 return $tmpdir if defined $tmpdir;
07824bd1 145 my $self = shift;
146 my @dirlist = @_;
5b577f92 147 {
148 no strict 'refs';
149 if (${"\cTAINT"}) { # Check for taint mode on perl >= 5.8.0
150 require Scalar::Util;
07824bd1 151 @dirlist = grep { ! Scalar::Util::tainted($_) } @dirlist;
5b577f92 152 }
b4c5e263 153 }
154 foreach (@dirlist) {
cbc7acb0 155 next unless defined && -d && -w _;
156 $tmpdir = $_;
157 last;
158 }
07824bd1 159 $tmpdir = $self->curdir unless defined $tmpdir;
160 $tmpdir = defined $tmpdir && $self->canonpath($tmpdir);
cbc7acb0 161 return $tmpdir;
162}
163
07824bd1 164sub tmpdir {
165 return $tmpdir if defined $tmpdir;
166 $tmpdir = _tmpdir( $ENV{TMPDIR}, "/tmp" );
167}
168
270d1e39 169=item updir
170
cbc7acb0 171Returns a string representation of the parent directory. ".." on UNIX.
270d1e39 172
173=cut
174
175sub updir {
176 return "..";
177}
178
179=item no_upwards
180
181Given a list of file names, strip out those that refer to a parent
182directory. (Does not strip symlinks, only '.', '..', and equivalents.)
183
184=cut
185
186sub no_upwards {
cbc7acb0 187 my $self = shift;
9c045eb2 188 return grep(!/^\.{1,2}\Z(?!\n)/s, @_);
270d1e39 189}
190
46726cbe 191=item case_tolerant
192
193Returns a true or false value indicating, respectively, that alphabetic
194is not or is significant when comparing file specifications.
195
196=cut
197
198sub case_tolerant {
199 return 0;
200}
201
270d1e39 202=item file_name_is_absolute
203
3c32ced9 204Takes as argument a path and returns true if it is an absolute path.
205
2586ba89 206This does not consult the local filesystem on Unix, Win32, OS/2 or Mac
207OS (Classic). It does consult the working environment for VMS (see
3c32ced9 208L<File::Spec::VMS/file_name_is_absolute>).
270d1e39 209
210=cut
211
212sub file_name_is_absolute {
cbc7acb0 213 my ($self,$file) = @_;
1b1e14d3 214 return scalar($file =~ m:^/:s);
270d1e39 215}
216
217=item path
218
219Takes no argument, returns the environment variable PATH as an array.
220
221=cut
222
223sub path {
802aa3ba 224 return () unless exists $ENV{PATH};
cbc7acb0 225 my @path = split(':', $ENV{PATH});
226 foreach (@path) { $_ = '.' if $_ eq '' }
227 return @path;
270d1e39 228}
229
230=item join
231
232join is the same as catfile.
233
234=cut
235
236sub join {
cbc7acb0 237 my $self = shift;
238 return $self->catfile(@_);
270d1e39 239}
240
c27914c9 241=item splitpath
242
243 ($volume,$directories,$file) = File::Spec->splitpath( $path );
244 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
245
40d020d9 246Splits a path into volume, directory, and filename portions. On systems
247with no concept of volume, returns '' for volume.
c27914c9 248
249For systems with no syntax differentiating filenames from directories,
250assumes that the last file is a path unless $no_file is true or a
251trailing separator or /. or /.. is present. On Unix this means that $no_file
252true makes this return ( '', $path, '' ).
253
254The directory portion may or may not be returned with a trailing '/'.
255
256The results can be passed to L</catpath()> to get back a path equivalent to
257(usually identical to) the original path.
258
259=cut
260
261sub splitpath {
262 my ($self,$path, $nofile) = @_;
263
264 my ($volume,$directory,$file) = ('','','');
265
266 if ( $nofile ) {
267 $directory = $path;
268 }
269 else {
9c045eb2 270 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
c27914c9 271 $directory = $1;
272 $file = $2;
273 }
274
275 return ($volume,$directory,$file);
276}
277
278
279=item splitdir
280
281The opposite of L</catdir()>.
282
283 @dirs = File::Spec->splitdir( $directories );
284
285$directories must be only the directory portion of the path on systems
286that have the concept of a volume or that have path syntax that differentiates
287files from directories.
288
200f06d0 289Unlike just splitting the directories on the separator, empty
290directory names (C<''>) can be returned, because these are significant
2586ba89 291on some OSs.
c27914c9 292
200f06d0 293On Unix,
294
295 File::Spec->splitdir( "/a/b//c/" );
c27914c9 296
297Yields:
298
299 ( '', 'a', 'b', '', 'c', '' )
300
301=cut
302
303sub splitdir {
304 my ($self,$directories) = @_ ;
305 #
306 # split() likes to forget about trailing null fields, so here we
307 # check to be sure that there will not be any before handling the
308 # simple case.
309 #
9c045eb2 310 if ( $directories !~ m|/\Z(?!\n)| ) {
c27914c9 311 return split( m|/|, $directories );
312 }
313 else {
314 #
315 # since there was a trailing separator, add a file name to the end,
316 # then do the split, then replace it with ''.
317 #
318 my( @directories )= split( m|/|, "${directories}dummy" ) ;
319 $directories[ $#directories ]= '' ;
320 return @directories ;
321 }
322}
323
324
59605c55 325=item catpath()
c27914c9 326
327Takes volume, directory and file portions and returns an entire path. Under
0994714a 328Unix, $volume is ignored, and directory and file are catenated. A '/' is
529a1a84 329inserted if needed (though if the directory portion doesn't start with
330'/' it is not added). On other OSs, $volume is significant.
c27914c9 331
332=cut
333
334sub catpath {
335 my ($self,$volume,$directory,$file) = @_;
336
337 if ( $directory ne '' &&
338 $file ne '' &&
339 substr( $directory, -1 ) ne '/' &&
340 substr( $file, 0, 1 ) ne '/'
341 ) {
342 $directory .= "/$file" ;
343 }
344 else {
345 $directory .= $file ;
346 }
347
348 return $directory ;
349}
350
351=item abs2rel
352
353Takes a destination path and an optional base path returns a relative path
354from the base path to the destination path:
355
3c32ced9 356 $rel_path = File::Spec->abs2rel( $path ) ;
357 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 358
59605c55 359If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 360then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 361is taken to be relative to L<cwd()|Cwd>.
c27914c9 362
363On systems with the concept of a volume, this assumes that both paths
364are on the $destination volume, and ignores the $base volume.
365
366On systems that have a grammar that indicates filenames, this ignores the
367$base filename as well. Otherwise all path components are assumed to be
368directories.
369
370If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 371This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 372
2586ba89 373No checks against the filesystem are made. On VMS, there is
3c32ced9 374interaction with the working environment, as logicals and
375macros are expanded.
c27914c9 376
3c32ced9 377Based on code written by Shigio Yamaguchi.
c27914c9 378
379=cut
380
381sub abs2rel {
382 my($self,$path,$base) = @_;
383
384 # Clean up $path
385 if ( ! $self->file_name_is_absolute( $path ) ) {
386 $path = $self->rel2abs( $path ) ;
387 }
388 else {
389 $path = $self->canonpath( $path ) ;
390 }
391
392 # Figure out the effective $base and clean it up.
393 if ( !defined( $base ) || $base eq '' ) {
394 $base = cwd() ;
395 }
396 elsif ( ! $self->file_name_is_absolute( $base ) ) {
397 $base = $self->rel2abs( $base ) ;
398 }
399 else {
400 $base = $self->canonpath( $base ) ;
401 }
402
403 # Now, remove all leading components that are the same
6fd19b73 404 my @pathchunks = $self->splitdir( $path);
405 my @basechunks = $self->splitdir( $base);
406
407 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 408 shift @pathchunks ;
409 shift @basechunks ;
410 }
411
6fd19b73 412 $path = CORE::join( '/', @pathchunks );
413 $base = CORE::join( '/', @basechunks );
414
415 # $base now contains the directories the resulting relative path
c27914c9 416 # must ascend out of before it can descend to $path_directory. So,
417 # replace all names with $parentDir
6fd19b73 418 $base =~ s|[^/]+|..|g ;
c27914c9 419
420 # Glue the two together, using a separator if necessary, and preventing an
421 # empty result.
6fd19b73 422 if ( $path ne '' && $base ne '' ) {
423 $path = "$base/$path" ;
424 } else {
425 $path = "$base$path" ;
426 }
c27914c9 427
428 return $self->canonpath( $path ) ;
429}
430
59605c55 431=item rel2abs()
c27914c9 432
433Converts a relative path to an absolute path.
434
3c32ced9 435 $abs_path = File::Spec->rel2abs( $path ) ;
436 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 437
59605c55 438If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 439then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 440is taken to be relative to L<cwd()|Cwd>.
c27914c9 441
442On systems with the concept of a volume, this assumes that both paths
3c32ced9 443are on the $base volume, and ignores the $path volume.
c27914c9 444
445On systems that have a grammar that indicates filenames, this ignores the
446$base filename as well. Otherwise all path components are assumed to be
447directories.
448
449If $path is absolute, it is cleaned up and returned using L</canonpath()>.
450
2586ba89 451No checks against the filesystem are made. On VMS, there is
3c32ced9 452interaction with the working environment, as logicals and
453macros are expanded.
c27914c9 454
3c32ced9 455Based on code written by Shigio Yamaguchi.
c27914c9 456
457=cut
458
786b702f 459sub rel2abs {
c27914c9 460 my ($self,$path,$base ) = @_;
461
462 # Clean up $path
463 if ( ! $self->file_name_is_absolute( $path ) ) {
464 # Figure out the effective $base and clean it up.
465 if ( !defined( $base ) || $base eq '' ) {
466 $base = cwd() ;
467 }
468 elsif ( ! $self->file_name_is_absolute( $base ) ) {
469 $base = $self->rel2abs( $base ) ;
470 }
471 else {
472 $base = $self->canonpath( $base ) ;
473 }
474
475 # Glom them together
6fd19b73 476 $path = $self->catdir( $base, $path ) ;
c27914c9 477 }
478
479 return $self->canonpath( $path ) ;
480}
481
482
270d1e39 483=back
484
485=head1 SEE ALSO
486
487L<File::Spec>
488
489=cut
490
4911;