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