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