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