Manual integration error in #12235.
[p5sagit/p5-mst-13.2.git] / lib / File / Spec / Unix.pm
CommitLineData
270d1e39 1package File::Spec::Unix;
2
270d1e39 3use strict;
f168a5e7 4our($VERSION);
b4296952 5
88d01e8d 6$VERSION = '1.3';
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
28=item canonpath
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
40 # Handle POSIX-style node names beginning with double slash
41 my $node = '';
61c0c206 42 if ( $^O =~ m/^(?:qnx|nto)$/ && $path =~ s:^(//[^/]+)(/|\z):/:s ) {
89bb8afa 43 $node = $1;
44 }
4fabb596 45 $path =~ s|/+|/|g unless($^O eq 'cygwin'); # xx////xx -> xx/xx
6bf11762 46 $path =~ s@(/\.)+(/|\Z(?!\n))@/@g; # xx/././xx -> xx/xx
1b1e14d3 47 $path =~ s|^(\./)+||s unless $path eq "./"; # ./xx -> xx
48 $path =~ s|^/(\.\./)+|/|s; # /../../xx -> xx
9c045eb2 49 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx
89bb8afa 50 return "$node$path";
270d1e39 51}
52
53=item catdir
54
55Concatenate two or more directory names to form a complete path ending
56with a directory. But remove the trailing slash from the resulting
57string, because it doesn't look good, isn't necessary and confuses
58OS2. Of course, if this is the root directory, don't cut off the
59trailing slash :-)
60
61=cut
62
270d1e39 63sub catdir {
cbc7acb0 64 my $self = shift;
270d1e39 65 my @args = @_;
cbc7acb0 66 foreach (@args) {
270d1e39 67 # append a slash to each argument unless it has one there
cbc7acb0 68 $_ .= "/" if $_ eq '' || substr($_,-1) ne "/";
270d1e39 69 }
cbc7acb0 70 return $self->canonpath(join('', @args));
270d1e39 71}
72
73=item catfile
74
75Concatenate one or more directory names and a filename to form a
76complete path ending with a filename
77
78=cut
79
80sub catfile {
cbc7acb0 81 my $self = shift;
270d1e39 82 my $file = pop @_;
83 return $file unless @_;
84 my $dir = $self->catdir(@_);
cbc7acb0 85 $dir .= "/" unless substr($dir,-1) eq "/";
270d1e39 86 return $dir.$file;
87}
88
89=item curdir
90
cbc7acb0 91Returns a string representation of the current directory. "." on UNIX.
270d1e39 92
93=cut
94
95sub curdir {
cbc7acb0 96 return ".";
270d1e39 97}
98
99804bbb 99=item devnull
100
cbc7acb0 101Returns a string representation of the null device. "/dev/null" on UNIX.
99804bbb 102
103=cut
104
105sub devnull {
106 return "/dev/null";
107}
108
270d1e39 109=item rootdir
110
cbc7acb0 111Returns a string representation of the root directory. "/" on UNIX.
270d1e39 112
113=cut
114
115sub rootdir {
116 return "/";
117}
118
cbc7acb0 119=item tmpdir
120
121Returns a string representation of the first writable directory
122from the following list or "" if none are writable:
123
124 $ENV{TMPDIR}
125 /tmp
126
127=cut
128
129my $tmpdir;
130sub tmpdir {
131 return $tmpdir if defined $tmpdir;
132 foreach ($ENV{TMPDIR}, "/tmp") {
133 next unless defined && -d && -w _;
134 $tmpdir = $_;
135 last;
136 }
137 $tmpdir = '' unless defined $tmpdir;
138 return $tmpdir;
139}
140
270d1e39 141=item updir
142
cbc7acb0 143Returns a string representation of the parent directory. ".." on UNIX.
270d1e39 144
145=cut
146
147sub updir {
148 return "..";
149}
150
151=item no_upwards
152
153Given a list of file names, strip out those that refer to a parent
154directory. (Does not strip symlinks, only '.', '..', and equivalents.)
155
156=cut
157
158sub no_upwards {
cbc7acb0 159 my $self = shift;
9c045eb2 160 return grep(!/^\.{1,2}\Z(?!\n)/s, @_);
270d1e39 161}
162
46726cbe 163=item case_tolerant
164
165Returns a true or false value indicating, respectively, that alphabetic
166is not or is significant when comparing file specifications.
167
168=cut
169
170sub case_tolerant {
171 return 0;
172}
173
270d1e39 174=item file_name_is_absolute
175
3c32ced9 176Takes as argument a path and returns true if it is an absolute path.
177
178This does not consult the local filesystem on Unix, Win32, or OS/2. It
179does sometimes on MacOS (see L<File::Spec::MacOS/file_name_is_absolute>).
180It does consult the working environment for VMS (see
181L<File::Spec::VMS/file_name_is_absolute>).
270d1e39 182
183=cut
184
185sub file_name_is_absolute {
cbc7acb0 186 my ($self,$file) = @_;
1b1e14d3 187 return scalar($file =~ m:^/:s);
270d1e39 188}
189
190=item path
191
192Takes no argument, returns the environment variable PATH as an array.
193
194=cut
195
196sub path {
cbc7acb0 197 my @path = split(':', $ENV{PATH});
198 foreach (@path) { $_ = '.' if $_ eq '' }
199 return @path;
270d1e39 200}
201
202=item join
203
204join is the same as catfile.
205
206=cut
207
208sub join {
cbc7acb0 209 my $self = shift;
210 return $self->catfile(@_);
270d1e39 211}
212
c27914c9 213=item splitpath
214
215 ($volume,$directories,$file) = File::Spec->splitpath( $path );
216 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
217
218Splits a path in to volume, directory, and filename portions. On systems
219with no concept of volume, returns undef for volume.
220
221For systems with no syntax differentiating filenames from directories,
222assumes that the last file is a path unless $no_file is true or a
223trailing separator or /. or /.. is present. On Unix this means that $no_file
224true makes this return ( '', $path, '' ).
225
226The directory portion may or may not be returned with a trailing '/'.
227
228The results can be passed to L</catpath()> to get back a path equivalent to
229(usually identical to) the original path.
230
231=cut
232
233sub splitpath {
234 my ($self,$path, $nofile) = @_;
235
236 my ($volume,$directory,$file) = ('','','');
237
238 if ( $nofile ) {
239 $directory = $path;
240 }
241 else {
9c045eb2 242 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
c27914c9 243 $directory = $1;
244 $file = $2;
245 }
246
247 return ($volume,$directory,$file);
248}
249
250
251=item splitdir
252
253The opposite of L</catdir()>.
254
255 @dirs = File::Spec->splitdir( $directories );
256
257$directories must be only the directory portion of the path on systems
258that have the concept of a volume or that have path syntax that differentiates
259files from directories.
260
200f06d0 261Unlike just splitting the directories on the separator, empty
262directory names (C<''>) can be returned, because these are significant
263on some OSs (e.g. MacOS).
c27914c9 264
200f06d0 265On Unix,
266
267 File::Spec->splitdir( "/a/b//c/" );
c27914c9 268
269Yields:
270
271 ( '', 'a', 'b', '', 'c', '' )
272
273=cut
274
275sub splitdir {
276 my ($self,$directories) = @_ ;
277 #
278 # split() likes to forget about trailing null fields, so here we
279 # check to be sure that there will not be any before handling the
280 # simple case.
281 #
9c045eb2 282 if ( $directories !~ m|/\Z(?!\n)| ) {
c27914c9 283 return split( m|/|, $directories );
284 }
285 else {
286 #
287 # since there was a trailing separator, add a file name to the end,
288 # then do the split, then replace it with ''.
289 #
290 my( @directories )= split( m|/|, "${directories}dummy" ) ;
291 $directories[ $#directories ]= '' ;
292 return @directories ;
293 }
294}
295
296
297=item catpath
298
299Takes volume, directory and file portions and returns an entire path. Under
0994714a 300Unix, $volume is ignored, and directory and file are catenated. A '/' is
301inserted if need be. On other OSs, $volume is significant.
c27914c9 302
303=cut
304
305sub catpath {
306 my ($self,$volume,$directory,$file) = @_;
307
308 if ( $directory ne '' &&
309 $file ne '' &&
310 substr( $directory, -1 ) ne '/' &&
311 substr( $file, 0, 1 ) ne '/'
312 ) {
313 $directory .= "/$file" ;
314 }
315 else {
316 $directory .= $file ;
317 }
318
319 return $directory ;
320}
321
322=item abs2rel
323
324Takes a destination path and an optional base path returns a relative path
325from the base path to the destination path:
326
3c32ced9 327 $rel_path = File::Spec->abs2rel( $path ) ;
328 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 329
330If $base is not present or '', then L<cwd()> is used. If $base is relative,
331then it is converted to absolute form using L</rel2abs()>. This means that it
332is taken to be relative to L<cwd()>.
333
334On systems with the concept of a volume, this assumes that both paths
335are on the $destination volume, and ignores the $base volume.
336
337On systems that have a grammar that indicates filenames, this ignores the
338$base filename as well. Otherwise all path components are assumed to be
339directories.
340
341If $path is relative, it is converted to absolute form using L</rel2abs()>.
342This means that it is taken to be relative to L<cwd()>.
343
3c32ced9 344No checks against the filesystem are made on most systems. On MacOS,
345the filesystem may be consulted (see
346L<File::Spec::MacOS/file_name_is_absolute>). On VMS, there is
347interaction with the working environment, as logicals and
348macros are expanded.
c27914c9 349
3c32ced9 350Based on code written by Shigio Yamaguchi.
c27914c9 351
352=cut
353
354sub abs2rel {
355 my($self,$path,$base) = @_;
356
357 # Clean up $path
358 if ( ! $self->file_name_is_absolute( $path ) ) {
359 $path = $self->rel2abs( $path ) ;
360 }
361 else {
362 $path = $self->canonpath( $path ) ;
363 }
364
365 # Figure out the effective $base and clean it up.
366 if ( !defined( $base ) || $base eq '' ) {
367 $base = cwd() ;
368 }
369 elsif ( ! $self->file_name_is_absolute( $base ) ) {
370 $base = $self->rel2abs( $base ) ;
371 }
372 else {
373 $base = $self->canonpath( $base ) ;
374 }
375
376 # Now, remove all leading components that are the same
6fd19b73 377 my @pathchunks = $self->splitdir( $path);
378 my @basechunks = $self->splitdir( $base);
379
380 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 381 shift @pathchunks ;
382 shift @basechunks ;
383 }
384
6fd19b73 385 $path = CORE::join( '/', @pathchunks );
386 $base = CORE::join( '/', @basechunks );
387
388 # $base now contains the directories the resulting relative path
c27914c9 389 # must ascend out of before it can descend to $path_directory. So,
390 # replace all names with $parentDir
6fd19b73 391 $base =~ s|[^/]+|..|g ;
c27914c9 392
393 # Glue the two together, using a separator if necessary, and preventing an
394 # empty result.
6fd19b73 395 if ( $path ne '' && $base ne '' ) {
396 $path = "$base/$path" ;
397 } else {
398 $path = "$base$path" ;
399 }
c27914c9 400
401 return $self->canonpath( $path ) ;
402}
403
404=item rel2abs
405
406Converts a relative path to an absolute path.
407
3c32ced9 408 $abs_path = File::Spec->rel2abs( $path ) ;
409 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 410
411If $base is not present or '', then L<cwd()> is used. If $base is relative,
412then it is converted to absolute form using L</rel2abs()>. This means that it
413is taken to be relative to L<cwd()>.
414
415On systems with the concept of a volume, this assumes that both paths
3c32ced9 416are on the $base volume, and ignores the $path volume.
c27914c9 417
418On systems that have a grammar that indicates filenames, this ignores the
419$base filename as well. Otherwise all path components are assumed to be
420directories.
421
422If $path is absolute, it is cleaned up and returned using L</canonpath()>.
423
3c32ced9 424No checks against the filesystem are made on most systems. On MacOS,
425the filesystem may be consulted (see
426L<File::Spec::MacOS/file_name_is_absolute>). On VMS, there is
427interaction with the working environment, as logicals and
428macros are expanded.
c27914c9 429
3c32ced9 430Based on code written by Shigio Yamaguchi.
c27914c9 431
432=cut
433
786b702f 434sub rel2abs {
c27914c9 435 my ($self,$path,$base ) = @_;
436
437 # Clean up $path
438 if ( ! $self->file_name_is_absolute( $path ) ) {
439 # Figure out the effective $base and clean it up.
440 if ( !defined( $base ) || $base eq '' ) {
441 $base = cwd() ;
442 }
443 elsif ( ! $self->file_name_is_absolute( $base ) ) {
444 $base = $self->rel2abs( $base ) ;
445 }
446 else {
447 $base = $self->canonpath( $base ) ;
448 }
449
450 # Glom them together
6fd19b73 451 $path = $self->catdir( $base, $path ) ;
c27914c9 452 }
453
454 return $self->canonpath( $path ) ;
455}
456
457
270d1e39 458=back
459
460=head1 SEE ALSO
461
462L<File::Spec>
463
464=cut
465
4661;