Upgrade to File::Spec 0.85.
[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 {
e021ab8e 305 return split m|/|, $_[1], -1; # Preserve trailing fields
c27914c9 306}
307
308
59605c55 309=item catpath()
c27914c9 310
311Takes volume, directory and file portions and returns an entire path. Under
3099fc99 312Unix, $volume is ignored, and directory and file are concatenated. A '/' is
529a1a84 313inserted if needed (though if the directory portion doesn't start with
314'/' it is not added). On other OSs, $volume is significant.
c27914c9 315
316=cut
317
318sub catpath {
319 my ($self,$volume,$directory,$file) = @_;
320
321 if ( $directory ne '' &&
322 $file ne '' &&
323 substr( $directory, -1 ) ne '/' &&
324 substr( $file, 0, 1 ) ne '/'
325 ) {
326 $directory .= "/$file" ;
327 }
328 else {
329 $directory .= $file ;
330 }
331
332 return $directory ;
333}
334
335=item abs2rel
336
337Takes a destination path and an optional base path returns a relative path
338from the base path to the destination path:
339
3c32ced9 340 $rel_path = File::Spec->abs2rel( $path ) ;
341 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 342
59605c55 343If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 344then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 345is taken to be relative to L<cwd()|Cwd>.
c27914c9 346
347On systems with the concept of a volume, this assumes that both paths
348are on the $destination volume, and ignores the $base volume.
349
350On systems that have a grammar that indicates filenames, this ignores the
351$base filename as well. Otherwise all path components are assumed to be
352directories.
353
354If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 355This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 356
2586ba89 357No checks against the filesystem are made. On VMS, there is
3c32ced9 358interaction with the working environment, as logicals and
359macros are expanded.
c27914c9 360
3c32ced9 361Based on code written by Shigio Yamaguchi.
c27914c9 362
363=cut
364
365sub abs2rel {
366 my($self,$path,$base) = @_;
367
368 # Clean up $path
369 if ( ! $self->file_name_is_absolute( $path ) ) {
370 $path = $self->rel2abs( $path ) ;
371 }
372 else {
373 $path = $self->canonpath( $path ) ;
374 }
375
376 # Figure out the effective $base and clean it up.
377 if ( !defined( $base ) || $base eq '' ) {
378 $base = cwd() ;
379 }
380 elsif ( ! $self->file_name_is_absolute( $base ) ) {
381 $base = $self->rel2abs( $base ) ;
382 }
383 else {
384 $base = $self->canonpath( $base ) ;
385 }
386
387 # Now, remove all leading components that are the same
6fd19b73 388 my @pathchunks = $self->splitdir( $path);
389 my @basechunks = $self->splitdir( $base);
390
391 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 392 shift @pathchunks ;
393 shift @basechunks ;
394 }
395
6fd19b73 396 $path = CORE::join( '/', @pathchunks );
397 $base = CORE::join( '/', @basechunks );
398
399 # $base now contains the directories the resulting relative path
c27914c9 400 # must ascend out of before it can descend to $path_directory. So,
401 # replace all names with $parentDir
6fd19b73 402 $base =~ s|[^/]+|..|g ;
c27914c9 403
404 # Glue the two together, using a separator if necessary, and preventing an
405 # empty result.
6fd19b73 406 if ( $path ne '' && $base ne '' ) {
407 $path = "$base/$path" ;
408 } else {
409 $path = "$base$path" ;
410 }
c27914c9 411
412 return $self->canonpath( $path ) ;
413}
414
59605c55 415=item rel2abs()
c27914c9 416
417Converts a relative path to an absolute path.
418
3c32ced9 419 $abs_path = File::Spec->rel2abs( $path ) ;
420 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 421
59605c55 422If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 423then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 424is taken to be relative to L<cwd()|Cwd>.
c27914c9 425
426On systems with the concept of a volume, this assumes that both paths
3c32ced9 427are on the $base volume, and ignores the $path volume.
c27914c9 428
429On systems that have a grammar that indicates filenames, this ignores the
430$base filename as well. Otherwise all path components are assumed to be
431directories.
432
433If $path is absolute, it is cleaned up and returned using L</canonpath()>.
434
2586ba89 435No checks against the filesystem are made. On VMS, there is
3c32ced9 436interaction with the working environment, as logicals and
437macros are expanded.
c27914c9 438
3c32ced9 439Based on code written by Shigio Yamaguchi.
c27914c9 440
441=cut
442
786b702f 443sub rel2abs {
c27914c9 444 my ($self,$path,$base ) = @_;
445
446 # Clean up $path
447 if ( ! $self->file_name_is_absolute( $path ) ) {
448 # Figure out the effective $base and clean it up.
449 if ( !defined( $base ) || $base eq '' ) {
450 $base = cwd() ;
451 }
452 elsif ( ! $self->file_name_is_absolute( $base ) ) {
453 $base = $self->rel2abs( $base ) ;
454 }
455 else {
456 $base = $self->canonpath( $base ) ;
457 }
458
459 # Glom them together
6fd19b73 460 $path = $self->catdir( $base, $path ) ;
c27914c9 461 }
462
463 return $self->canonpath( $path ) ;
464}
465
466
270d1e39 467=back
468
469=head1 SEE ALSO
470
471L<File::Spec>
472
473=cut
474
4751;