Update to File::Spec 0.90
[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;
638113eb 72
73 $self->canonpath(join('/', @_, '')); # '' because need a trailing '/'
270d1e39 74}
75
76=item catfile
77
78Concatenate one or more directory names and a filename to form a
79complete path ending with a filename
80
81=cut
82
83sub catfile {
cbc7acb0 84 my $self = shift;
63c6dcc1 85 my $file = $self->canonpath(pop @_);
270d1e39 86 return $file unless @_;
87 my $dir = $self->catdir(@_);
cbc7acb0 88 $dir .= "/" unless substr($dir,-1) eq "/";
270d1e39 89 return $dir.$file;
90}
91
92=item curdir
93
cbc7acb0 94Returns a string representation of the current directory. "." on UNIX.
270d1e39 95
96=cut
97
638113eb 98sub curdir () { '.' }
270d1e39 99
99804bbb 100=item devnull
101
cbc7acb0 102Returns a string representation of the null device. "/dev/null" on UNIX.
99804bbb 103
104=cut
105
638113eb 106sub devnull () { '/dev/null' }
99804bbb 107
270d1e39 108=item rootdir
109
cbc7acb0 110Returns a string representation of the root directory. "/" on UNIX.
270d1e39 111
112=cut
113
638113eb 114sub rootdir () { '/' }
270d1e39 115
cbc7acb0 116=item tmpdir
117
07824bd1 118Returns a string representation of the first writable directory from
119the following list or the current directory if none from the list are
120writable:
cbc7acb0 121
122 $ENV{TMPDIR}
123 /tmp
124
b4c5e263 125Since perl 5.8.0, if running under taint mode, and if $ENV{TMPDIR}
126is tainted, it is not used.
127
cbc7acb0 128=cut
129
130my $tmpdir;
07824bd1 131sub _tmpdir {
cbc7acb0 132 return $tmpdir if defined $tmpdir;
07824bd1 133 my $self = shift;
134 my @dirlist = @_;
5b577f92 135 {
136 no strict 'refs';
137 if (${"\cTAINT"}) { # Check for taint mode on perl >= 5.8.0
138 require Scalar::Util;
07824bd1 139 @dirlist = grep { ! Scalar::Util::tainted($_) } @dirlist;
5b577f92 140 }
b4c5e263 141 }
142 foreach (@dirlist) {
cbc7acb0 143 next unless defined && -d && -w _;
144 $tmpdir = $_;
145 last;
146 }
07824bd1 147 $tmpdir = $self->curdir unless defined $tmpdir;
148 $tmpdir = defined $tmpdir && $self->canonpath($tmpdir);
cbc7acb0 149 return $tmpdir;
150}
151
07824bd1 152sub tmpdir {
153 return $tmpdir if defined $tmpdir;
f4b08ef8 154 my $self = shift;
155 $tmpdir = $self->_tmpdir( $ENV{TMPDIR}, "/tmp" );
07824bd1 156}
157
270d1e39 158=item updir
159
cbc7acb0 160Returns a string representation of the parent directory. ".." on UNIX.
270d1e39 161
162=cut
163
638113eb 164sub updir () { '..' }
270d1e39 165
166=item no_upwards
167
168Given a list of file names, strip out those that refer to a parent
169directory. (Does not strip symlinks, only '.', '..', and equivalents.)
170
171=cut
172
173sub no_upwards {
cbc7acb0 174 my $self = shift;
9c045eb2 175 return grep(!/^\.{1,2}\Z(?!\n)/s, @_);
270d1e39 176}
177
46726cbe 178=item case_tolerant
179
180Returns a true or false value indicating, respectively, that alphabetic
181is not or is significant when comparing file specifications.
182
183=cut
184
638113eb 185sub case_tolerant () { 0 }
46726cbe 186
270d1e39 187=item file_name_is_absolute
188
3c32ced9 189Takes as argument a path and returns true if it is an absolute path.
190
2586ba89 191This does not consult the local filesystem on Unix, Win32, OS/2 or Mac
192OS (Classic). It does consult the working environment for VMS (see
3c32ced9 193L<File::Spec::VMS/file_name_is_absolute>).
270d1e39 194
195=cut
196
197sub file_name_is_absolute {
cbc7acb0 198 my ($self,$file) = @_;
1b1e14d3 199 return scalar($file =~ m:^/:s);
270d1e39 200}
201
202=item path
203
204Takes no argument, returns the environment variable PATH as an array.
205
206=cut
207
208sub path {
802aa3ba 209 return () unless exists $ENV{PATH};
cbc7acb0 210 my @path = split(':', $ENV{PATH});
211 foreach (@path) { $_ = '.' if $_ eq '' }
212 return @path;
270d1e39 213}
214
215=item join
216
217join is the same as catfile.
218
219=cut
220
221sub join {
cbc7acb0 222 my $self = shift;
223 return $self->catfile(@_);
270d1e39 224}
225
c27914c9 226=item splitpath
227
228 ($volume,$directories,$file) = File::Spec->splitpath( $path );
229 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
230
40d020d9 231Splits a path into volume, directory, and filename portions. On systems
232with no concept of volume, returns '' for volume.
c27914c9 233
234For systems with no syntax differentiating filenames from directories,
235assumes that the last file is a path unless $no_file is true or a
236trailing separator or /. or /.. is present. On Unix this means that $no_file
237true makes this return ( '', $path, '' ).
238
239The directory portion may or may not be returned with a trailing '/'.
240
241The results can be passed to L</catpath()> to get back a path equivalent to
242(usually identical to) the original path.
243
244=cut
245
246sub splitpath {
247 my ($self,$path, $nofile) = @_;
248
249 my ($volume,$directory,$file) = ('','','');
250
251 if ( $nofile ) {
252 $directory = $path;
253 }
254 else {
9c045eb2 255 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
c27914c9 256 $directory = $1;
257 $file = $2;
258 }
259
260 return ($volume,$directory,$file);
261}
262
263
264=item splitdir
265
266The opposite of L</catdir()>.
267
268 @dirs = File::Spec->splitdir( $directories );
269
270$directories must be only the directory portion of the path on systems
271that have the concept of a volume or that have path syntax that differentiates
272files from directories.
273
200f06d0 274Unlike just splitting the directories on the separator, empty
275directory names (C<''>) can be returned, because these are significant
2586ba89 276on some OSs.
c27914c9 277
200f06d0 278On Unix,
279
280 File::Spec->splitdir( "/a/b//c/" );
c27914c9 281
282Yields:
283
284 ( '', 'a', 'b', '', 'c', '' )
285
286=cut
287
288sub splitdir {
e021ab8e 289 return split m|/|, $_[1], -1; # Preserve trailing fields
c27914c9 290}
291
292
59605c55 293=item catpath()
c27914c9 294
295Takes volume, directory and file portions and returns an entire path. Under
3099fc99 296Unix, $volume is ignored, and directory and file are concatenated. A '/' is
529a1a84 297inserted if needed (though if the directory portion doesn't start with
298'/' it is not added). On other OSs, $volume is significant.
c27914c9 299
300=cut
301
302sub catpath {
303 my ($self,$volume,$directory,$file) = @_;
304
305 if ( $directory ne '' &&
306 $file ne '' &&
307 substr( $directory, -1 ) ne '/' &&
308 substr( $file, 0, 1 ) ne '/'
309 ) {
310 $directory .= "/$file" ;
311 }
312 else {
313 $directory .= $file ;
314 }
315
316 return $directory ;
317}
318
319=item abs2rel
320
321Takes a destination path and an optional base path returns a relative path
322from the base path to the destination path:
323
3c32ced9 324 $rel_path = File::Spec->abs2rel( $path ) ;
325 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 326
c063e98f 327If $base is not present or '', then L<cwd()|Cwd> is used. If $base is
328relative, then it is converted to absolute form using
329L</rel2abs()>. This means that it is taken to be relative to
330L<cwd()|Cwd>.
c27914c9 331
c27914c9 332On systems that have a grammar that indicates filenames, this ignores the
638113eb 333$base filename. Otherwise all path components are assumed to be
c27914c9 334directories.
335
336If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 337This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 338
2586ba89 339No checks against the filesystem are made. On VMS, there is
3c32ced9 340interaction with the working environment, as logicals and
341macros are expanded.
c27914c9 342
3c32ced9 343Based on code written by Shigio Yamaguchi.
c27914c9 344
345=cut
346
347sub abs2rel {
348 my($self,$path,$base) = @_;
349
350 # Clean up $path
351 if ( ! $self->file_name_is_absolute( $path ) ) {
352 $path = $self->rel2abs( $path ) ;
353 }
354 else {
355 $path = $self->canonpath( $path ) ;
356 }
357
358 # Figure out the effective $base and clean it up.
359 if ( !defined( $base ) || $base eq '' ) {
0fab864c 360 $base = $self->_cwd();
c27914c9 361 }
362 elsif ( ! $self->file_name_is_absolute( $base ) ) {
363 $base = $self->rel2abs( $base ) ;
364 }
365 else {
366 $base = $self->canonpath( $base ) ;
367 }
368
369 # Now, remove all leading components that are the same
6fd19b73 370 my @pathchunks = $self->splitdir( $path);
371 my @basechunks = $self->splitdir( $base);
372
373 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 374 shift @pathchunks ;
375 shift @basechunks ;
376 }
377
6fd19b73 378 $path = CORE::join( '/', @pathchunks );
379 $base = CORE::join( '/', @basechunks );
380
381 # $base now contains the directories the resulting relative path
c27914c9 382 # must ascend out of before it can descend to $path_directory. So,
383 # replace all names with $parentDir
6fd19b73 384 $base =~ s|[^/]+|..|g ;
c27914c9 385
386 # Glue the two together, using a separator if necessary, and preventing an
387 # empty result.
6fd19b73 388 if ( $path ne '' && $base ne '' ) {
389 $path = "$base/$path" ;
390 } else {
391 $path = "$base$path" ;
392 }
c27914c9 393
394 return $self->canonpath( $path ) ;
395}
396
59605c55 397=item rel2abs()
c27914c9 398
399Converts a relative path to an absolute path.
400
3c32ced9 401 $abs_path = File::Spec->rel2abs( $path ) ;
402 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 403
0fab864c 404If $base is not present or '', then L<cwd()|Cwd> is used. If $base is
405relative, then it is converted to absolute form using
406L</rel2abs()>. This means that it is taken to be relative to
407L<cwd()|Cwd>.
c27914c9 408
638113eb 409On systems that have a grammar that indicates filenames, this ignores
410the $base filename. Otherwise all path components are assumed to be
c27914c9 411directories.
412
413If $path is absolute, it is cleaned up and returned using L</canonpath()>.
414
2586ba89 415No checks against the filesystem are made. On VMS, there is
3c32ced9 416interaction with the working environment, as logicals and
417macros are expanded.
c27914c9 418
3c32ced9 419Based on code written by Shigio Yamaguchi.
c27914c9 420
421=cut
422
786b702f 423sub rel2abs {
c27914c9 424 my ($self,$path,$base ) = @_;
425
426 # Clean up $path
427 if ( ! $self->file_name_is_absolute( $path ) ) {
428 # Figure out the effective $base and clean it up.
429 if ( !defined( $base ) || $base eq '' ) {
0fab864c 430 $base = $self->_cwd();
c27914c9 431 }
432 elsif ( ! $self->file_name_is_absolute( $base ) ) {
433 $base = $self->rel2abs( $base ) ;
434 }
435 else {
436 $base = $self->canonpath( $base ) ;
437 }
438
439 # Glom them together
6fd19b73 440 $path = $self->catdir( $base, $path ) ;
c27914c9 441 }
442
443 return $self->canonpath( $path ) ;
444}
445
270d1e39 446=back
447
448=head1 SEE ALSO
449
450L<File::Spec>
451
452=cut
453
0fab864c 454# Internal routine to File::Spec, no point in making this public since
455# it is the standard Cwd interface. Most of the platform-specific
456# File::Spec subclasses use this.
457sub _cwd {
c063e98f 458 require Cwd;
459 Cwd::cwd();
460}
461
270d1e39 4621;