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