Re: [PATCH: perl@20760] clean up quotation issue for use with MMS on VMS
[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
346On systems with the concept of a volume, this assumes that both paths
347are on the $destination volume, and ignores the $base volume.
348
349On systems that have a grammar that indicates filenames, this ignores the
350$base filename as well. Otherwise all path components are assumed to be
351directories.
352
353If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 354This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 355
2586ba89 356No checks against the filesystem are made. On VMS, there is
3c32ced9 357interaction with the working environment, as logicals and
358macros are expanded.
c27914c9 359
3c32ced9 360Based on code written by Shigio Yamaguchi.
c27914c9 361
362=cut
363
364sub abs2rel {
365 my($self,$path,$base) = @_;
366
367 # Clean up $path
368 if ( ! $self->file_name_is_absolute( $path ) ) {
369 $path = $self->rel2abs( $path ) ;
370 }
371 else {
372 $path = $self->canonpath( $path ) ;
373 }
374
375 # Figure out the effective $base and clean it up.
376 if ( !defined( $base ) || $base eq '' ) {
c063e98f 377 $base = $self->cwd();
c27914c9 378 }
379 elsif ( ! $self->file_name_is_absolute( $base ) ) {
380 $base = $self->rel2abs( $base ) ;
381 }
382 else {
383 $base = $self->canonpath( $base ) ;
384 }
385
386 # Now, remove all leading components that are the same
6fd19b73 387 my @pathchunks = $self->splitdir( $path);
388 my @basechunks = $self->splitdir( $base);
389
390 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 391 shift @pathchunks ;
392 shift @basechunks ;
393 }
394
6fd19b73 395 $path = CORE::join( '/', @pathchunks );
396 $base = CORE::join( '/', @basechunks );
397
398 # $base now contains the directories the resulting relative path
c27914c9 399 # must ascend out of before it can descend to $path_directory. So,
400 # replace all names with $parentDir
6fd19b73 401 $base =~ s|[^/]+|..|g ;
c27914c9 402
403 # Glue the two together, using a separator if necessary, and preventing an
404 # empty result.
6fd19b73 405 if ( $path ne '' && $base ne '' ) {
406 $path = "$base/$path" ;
407 } else {
408 $path = "$base$path" ;
409 }
c27914c9 410
411 return $self->canonpath( $path ) ;
412}
413
59605c55 414=item rel2abs()
c27914c9 415
416Converts a relative path to an absolute path.
417
3c32ced9 418 $abs_path = File::Spec->rel2abs( $path ) ;
419 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 420
59605c55 421If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 422then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 423is taken to be relative to L<cwd()|Cwd>.
c27914c9 424
425On systems with the concept of a volume, this assumes that both paths
3c32ced9 426are on the $base volume, and ignores the $path volume.
c27914c9 427
428On systems that have a grammar that indicates filenames, this ignores the
429$base filename as well. Otherwise all path components are assumed to be
430directories.
431
432If $path is absolute, it is cleaned up and returned using L</canonpath()>.
433
2586ba89 434No checks against the filesystem are made. On VMS, there is
3c32ced9 435interaction with the working environment, as logicals and
436macros are expanded.
c27914c9 437
3c32ced9 438Based on code written by Shigio Yamaguchi.
c27914c9 439
440=cut
441
786b702f 442sub rel2abs {
c27914c9 443 my ($self,$path,$base ) = @_;
444
445 # Clean up $path
446 if ( ! $self->file_name_is_absolute( $path ) ) {
447 # Figure out the effective $base and clean it up.
448 if ( !defined( $base ) || $base eq '' ) {
f9fbf424 449 $base = $self->cwd();
c27914c9 450 }
451 elsif ( ! $self->file_name_is_absolute( $base ) ) {
452 $base = $self->rel2abs( $base ) ;
453 }
454 else {
455 $base = $self->canonpath( $base ) ;
456 }
457
458 # Glom them together
6fd19b73 459 $path = $self->catdir( $base, $path ) ;
c27914c9 460 }
461
462 return $self->canonpath( $path ) ;
463}
464
270d1e39 465=back
466
467=head1 SEE ALSO
468
469L<File::Spec>
470
471=cut
472
c063e98f 473# Internal routine to File::Spec, no point in publicly documenting
474# this interface since it's the standard Cwd interface. Some of the
475# platform-specific File::Spec subclasses use this.
476sub cwd {
477 require Cwd;
478 Cwd::cwd();
479}
480
270d1e39 4811;