[perl #8599] s/catenate/concatenate/
[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;
f4b08ef8 166 my $self = shift;
167 $tmpdir = $self->_tmpdir( $ENV{TMPDIR}, "/tmp" );
07824bd1 168}
169
270d1e39 170=item updir
171
cbc7acb0 172Returns a string representation of the parent directory. ".." on UNIX.
270d1e39 173
174=cut
175
176sub updir {
177 return "..";
178}
179
180=item no_upwards
181
182Given a list of file names, strip out those that refer to a parent
183directory. (Does not strip symlinks, only '.', '..', and equivalents.)
184
185=cut
186
187sub no_upwards {
cbc7acb0 188 my $self = shift;
9c045eb2 189 return grep(!/^\.{1,2}\Z(?!\n)/s, @_);
270d1e39 190}
191
46726cbe 192=item case_tolerant
193
194Returns a true or false value indicating, respectively, that alphabetic
195is not or is significant when comparing file specifications.
196
197=cut
198
199sub case_tolerant {
200 return 0;
201}
202
270d1e39 203=item file_name_is_absolute
204
3c32ced9 205Takes as argument a path and returns true if it is an absolute path.
206
2586ba89 207This does not consult the local filesystem on Unix, Win32, OS/2 or Mac
208OS (Classic). It does consult the working environment for VMS (see
3c32ced9 209L<File::Spec::VMS/file_name_is_absolute>).
270d1e39 210
211=cut
212
213sub file_name_is_absolute {
cbc7acb0 214 my ($self,$file) = @_;
1b1e14d3 215 return scalar($file =~ m:^/:s);
270d1e39 216}
217
218=item path
219
220Takes no argument, returns the environment variable PATH as an array.
221
222=cut
223
224sub path {
802aa3ba 225 return () unless exists $ENV{PATH};
cbc7acb0 226 my @path = split(':', $ENV{PATH});
227 foreach (@path) { $_ = '.' if $_ eq '' }
228 return @path;
270d1e39 229}
230
231=item join
232
233join is the same as catfile.
234
235=cut
236
237sub join {
cbc7acb0 238 my $self = shift;
239 return $self->catfile(@_);
270d1e39 240}
241
c27914c9 242=item splitpath
243
244 ($volume,$directories,$file) = File::Spec->splitpath( $path );
245 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
246
40d020d9 247Splits a path into volume, directory, and filename portions. On systems
248with no concept of volume, returns '' for volume.
c27914c9 249
250For systems with no syntax differentiating filenames from directories,
251assumes that the last file is a path unless $no_file is true or a
252trailing separator or /. or /.. is present. On Unix this means that $no_file
253true makes this return ( '', $path, '' ).
254
255The directory portion may or may not be returned with a trailing '/'.
256
257The results can be passed to L</catpath()> to get back a path equivalent to
258(usually identical to) the original path.
259
260=cut
261
262sub splitpath {
263 my ($self,$path, $nofile) = @_;
264
265 my ($volume,$directory,$file) = ('','','');
266
267 if ( $nofile ) {
268 $directory = $path;
269 }
270 else {
9c045eb2 271 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
c27914c9 272 $directory = $1;
273 $file = $2;
274 }
275
276 return ($volume,$directory,$file);
277}
278
279
280=item splitdir
281
282The opposite of L</catdir()>.
283
284 @dirs = File::Spec->splitdir( $directories );
285
286$directories must be only the directory portion of the path on systems
287that have the concept of a volume or that have path syntax that differentiates
288files from directories.
289
200f06d0 290Unlike just splitting the directories on the separator, empty
291directory names (C<''>) can be returned, because these are significant
2586ba89 292on some OSs.
c27914c9 293
200f06d0 294On Unix,
295
296 File::Spec->splitdir( "/a/b//c/" );
c27914c9 297
298Yields:
299
300 ( '', 'a', 'b', '', 'c', '' )
301
302=cut
303
304sub splitdir {
305 my ($self,$directories) = @_ ;
306 #
307 # split() likes to forget about trailing null fields, so here we
308 # check to be sure that there will not be any before handling the
309 # simple case.
310 #
9c045eb2 311 if ( $directories !~ m|/\Z(?!\n)| ) {
c27914c9 312 return split( m|/|, $directories );
313 }
314 else {
315 #
316 # since there was a trailing separator, add a file name to the end,
317 # then do the split, then replace it with ''.
318 #
319 my( @directories )= split( m|/|, "${directories}dummy" ) ;
320 $directories[ $#directories ]= '' ;
321 return @directories ;
322 }
323}
324
325
59605c55 326=item catpath()
c27914c9 327
328Takes volume, directory and file portions and returns an entire path. Under
3099fc99 329Unix, $volume is ignored, and directory and file are concatenated. A '/' is
529a1a84 330inserted if needed (though if the directory portion doesn't start with
331'/' it is not added). On other OSs, $volume is significant.
c27914c9 332
333=cut
334
335sub catpath {
336 my ($self,$volume,$directory,$file) = @_;
337
338 if ( $directory ne '' &&
339 $file ne '' &&
340 substr( $directory, -1 ) ne '/' &&
341 substr( $file, 0, 1 ) ne '/'
342 ) {
343 $directory .= "/$file" ;
344 }
345 else {
346 $directory .= $file ;
347 }
348
349 return $directory ;
350}
351
352=item abs2rel
353
354Takes a destination path and an optional base path returns a relative path
355from the base path to the destination path:
356
3c32ced9 357 $rel_path = File::Spec->abs2rel( $path ) ;
358 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 359
59605c55 360If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 361then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 362is taken to be relative to L<cwd()|Cwd>.
c27914c9 363
364On systems with the concept of a volume, this assumes that both paths
365are on the $destination volume, and ignores the $base volume.
366
367On systems that have a grammar that indicates filenames, this ignores the
368$base filename as well. Otherwise all path components are assumed to be
369directories.
370
371If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 372This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 373
2586ba89 374No checks against the filesystem are made. On VMS, there is
3c32ced9 375interaction with the working environment, as logicals and
376macros are expanded.
c27914c9 377
3c32ced9 378Based on code written by Shigio Yamaguchi.
c27914c9 379
380=cut
381
382sub abs2rel {
383 my($self,$path,$base) = @_;
384
385 # Clean up $path
386 if ( ! $self->file_name_is_absolute( $path ) ) {
387 $path = $self->rel2abs( $path ) ;
388 }
389 else {
390 $path = $self->canonpath( $path ) ;
391 }
392
393 # Figure out the effective $base and clean it up.
394 if ( !defined( $base ) || $base eq '' ) {
395 $base = cwd() ;
396 }
397 elsif ( ! $self->file_name_is_absolute( $base ) ) {
398 $base = $self->rel2abs( $base ) ;
399 }
400 else {
401 $base = $self->canonpath( $base ) ;
402 }
403
404 # Now, remove all leading components that are the same
6fd19b73 405 my @pathchunks = $self->splitdir( $path);
406 my @basechunks = $self->splitdir( $base);
407
408 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 409 shift @pathchunks ;
410 shift @basechunks ;
411 }
412
6fd19b73 413 $path = CORE::join( '/', @pathchunks );
414 $base = CORE::join( '/', @basechunks );
415
416 # $base now contains the directories the resulting relative path
c27914c9 417 # must ascend out of before it can descend to $path_directory. So,
418 # replace all names with $parentDir
6fd19b73 419 $base =~ s|[^/]+|..|g ;
c27914c9 420
421 # Glue the two together, using a separator if necessary, and preventing an
422 # empty result.
6fd19b73 423 if ( $path ne '' && $base ne '' ) {
424 $path = "$base/$path" ;
425 } else {
426 $path = "$base$path" ;
427 }
c27914c9 428
429 return $self->canonpath( $path ) ;
430}
431
59605c55 432=item rel2abs()
c27914c9 433
434Converts a relative path to an absolute path.
435
3c32ced9 436 $abs_path = File::Spec->rel2abs( $path ) ;
437 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 438
59605c55 439If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 440then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 441is taken to be relative to L<cwd()|Cwd>.
c27914c9 442
443On systems with the concept of a volume, this assumes that both paths
3c32ced9 444are on the $base volume, and ignores the $path volume.
c27914c9 445
446On systems that have a grammar that indicates filenames, this ignores the
447$base filename as well. Otherwise all path components are assumed to be
448directories.
449
450If $path is absolute, it is cleaned up and returned using L</canonpath()>.
451
2586ba89 452No checks against the filesystem are made. On VMS, there is
3c32ced9 453interaction with the working environment, as logicals and
454macros are expanded.
c27914c9 455
3c32ced9 456Based on code written by Shigio Yamaguchi.
c27914c9 457
458=cut
459
786b702f 460sub rel2abs {
c27914c9 461 my ($self,$path,$base ) = @_;
462
463 # Clean up $path
464 if ( ! $self->file_name_is_absolute( $path ) ) {
465 # Figure out the effective $base and clean it up.
466 if ( !defined( $base ) || $base eq '' ) {
467 $base = cwd() ;
468 }
469 elsif ( ! $self->file_name_is_absolute( $base ) ) {
470 $base = $self->rel2abs( $base ) ;
471 }
472 else {
473 $base = $self->canonpath( $base ) ;
474 }
475
476 # Glom them together
6fd19b73 477 $path = $self->catdir( $base, $path ) ;
c27914c9 478 }
479
480 return $self->canonpath( $path ) ;
481}
482
483
270d1e39 484=back
485
486=head1 SEE ALSO
487
488L<File::Spec>
489
490=cut
491
4921;