Use config.arch in OS/390 where the combination of
[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
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 }
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
59605c55 53=item catdir()
270d1e39 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
2586ba89 178This does not consult the local filesystem on Unix, Win32, OS/2 or Mac
179OS (Classic). It does consult the working environment for VMS (see
3c32ced9 180L<File::Spec::VMS/file_name_is_absolute>).
270d1e39 181
182=cut
183
184sub file_name_is_absolute {
cbc7acb0 185 my ($self,$file) = @_;
1b1e14d3 186 return scalar($file =~ m:^/:s);
270d1e39 187}
188
189=item path
190
191Takes no argument, returns the environment variable PATH as an array.
192
193=cut
194
195sub path {
cbc7acb0 196 my @path = split(':', $ENV{PATH});
197 foreach (@path) { $_ = '.' if $_ eq '' }
198 return @path;
270d1e39 199}
200
201=item join
202
203join is the same as catfile.
204
205=cut
206
207sub join {
cbc7acb0 208 my $self = shift;
209 return $self->catfile(@_);
270d1e39 210}
211
c27914c9 212=item splitpath
213
214 ($volume,$directories,$file) = File::Spec->splitpath( $path );
215 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
216
217Splits a path in to volume, directory, and filename portions. On systems
218with no concept of volume, returns undef for volume.
219
220For systems with no syntax differentiating filenames from directories,
221assumes that the last file is a path unless $no_file is true or a
222trailing separator or /. or /.. is present. On Unix this means that $no_file
223true makes this return ( '', $path, '' ).
224
225The directory portion may or may not be returned with a trailing '/'.
226
227The results can be passed to L</catpath()> to get back a path equivalent to
228(usually identical to) the original path.
229
230=cut
231
232sub splitpath {
233 my ($self,$path, $nofile) = @_;
234
235 my ($volume,$directory,$file) = ('','','');
236
237 if ( $nofile ) {
238 $directory = $path;
239 }
240 else {
9c045eb2 241 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
c27914c9 242 $directory = $1;
243 $file = $2;
244 }
245
246 return ($volume,$directory,$file);
247}
248
249
250=item splitdir
251
252The opposite of L</catdir()>.
253
254 @dirs = File::Spec->splitdir( $directories );
255
256$directories must be only the directory portion of the path on systems
257that have the concept of a volume or that have path syntax that differentiates
258files from directories.
259
200f06d0 260Unlike just splitting the directories on the separator, empty
261directory names (C<''>) can be returned, because these are significant
2586ba89 262on some OSs.
c27914c9 263
200f06d0 264On Unix,
265
266 File::Spec->splitdir( "/a/b//c/" );
c27914c9 267
268Yields:
269
270 ( '', 'a', 'b', '', 'c', '' )
271
272=cut
273
274sub splitdir {
275 my ($self,$directories) = @_ ;
276 #
277 # split() likes to forget about trailing null fields, so here we
278 # check to be sure that there will not be any before handling the
279 # simple case.
280 #
9c045eb2 281 if ( $directories !~ m|/\Z(?!\n)| ) {
c27914c9 282 return split( m|/|, $directories );
283 }
284 else {
285 #
286 # since there was a trailing separator, add a file name to the end,
287 # then do the split, then replace it with ''.
288 #
289 my( @directories )= split( m|/|, "${directories}dummy" ) ;
290 $directories[ $#directories ]= '' ;
291 return @directories ;
292 }
293}
294
295
59605c55 296=item catpath()
c27914c9 297
298Takes volume, directory and file portions and returns an entire path. Under
0994714a 299Unix, $volume is ignored, and directory and file are catenated. A '/' is
300inserted if need be. On other OSs, $volume is significant.
c27914c9 301
302=cut
303
304sub catpath {
305 my ($self,$volume,$directory,$file) = @_;
306
307 if ( $directory ne '' &&
308 $file ne '' &&
309 substr( $directory, -1 ) ne '/' &&
310 substr( $file, 0, 1 ) ne '/'
311 ) {
312 $directory .= "/$file" ;
313 }
314 else {
315 $directory .= $file ;
316 }
317
318 return $directory ;
319}
320
321=item abs2rel
322
323Takes a destination path and an optional base path returns a relative path
324from the base path to the destination path:
325
3c32ced9 326 $rel_path = File::Spec->abs2rel( $path ) ;
327 $rel_path = File::Spec->abs2rel( $path, $base ) ;
c27914c9 328
59605c55 329If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 330then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 331is taken to be relative to L<cwd()|Cwd>.
c27914c9 332
333On systems with the concept of a volume, this assumes that both paths
334are on the $destination volume, and ignores the $base volume.
335
336On systems that have a grammar that indicates filenames, this ignores the
337$base filename as well. Otherwise all path components are assumed to be
338directories.
339
340If $path is relative, it is converted to absolute form using L</rel2abs()>.
59605c55 341This means that it is taken to be relative to L<cwd()|Cwd>.
c27914c9 342
2586ba89 343No checks against the filesystem are made. On VMS, there is
3c32ced9 344interaction with the working environment, as logicals and
345macros are expanded.
c27914c9 346
3c32ced9 347Based on code written by Shigio Yamaguchi.
c27914c9 348
349=cut
350
351sub abs2rel {
352 my($self,$path,$base) = @_;
353
354 # Clean up $path
355 if ( ! $self->file_name_is_absolute( $path ) ) {
356 $path = $self->rel2abs( $path ) ;
357 }
358 else {
359 $path = $self->canonpath( $path ) ;
360 }
361
362 # Figure out the effective $base and clean it up.
363 if ( !defined( $base ) || $base eq '' ) {
364 $base = cwd() ;
365 }
366 elsif ( ! $self->file_name_is_absolute( $base ) ) {
367 $base = $self->rel2abs( $base ) ;
368 }
369 else {
370 $base = $self->canonpath( $base ) ;
371 }
372
373 # Now, remove all leading components that are the same
6fd19b73 374 my @pathchunks = $self->splitdir( $path);
375 my @basechunks = $self->splitdir( $base);
376
377 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
c27914c9 378 shift @pathchunks ;
379 shift @basechunks ;
380 }
381
6fd19b73 382 $path = CORE::join( '/', @pathchunks );
383 $base = CORE::join( '/', @basechunks );
384
385 # $base now contains the directories the resulting relative path
c27914c9 386 # must ascend out of before it can descend to $path_directory. So,
387 # replace all names with $parentDir
6fd19b73 388 $base =~ s|[^/]+|..|g ;
c27914c9 389
390 # Glue the two together, using a separator if necessary, and preventing an
391 # empty result.
6fd19b73 392 if ( $path ne '' && $base ne '' ) {
393 $path = "$base/$path" ;
394 } else {
395 $path = "$base$path" ;
396 }
c27914c9 397
398 return $self->canonpath( $path ) ;
399}
400
59605c55 401=item rel2abs()
c27914c9 402
403Converts a relative path to an absolute path.
404
3c32ced9 405 $abs_path = File::Spec->rel2abs( $path ) ;
406 $abs_path = File::Spec->rel2abs( $path, $base ) ;
c27914c9 407
59605c55 408If $base is not present or '', then L<cwd()|Cwd> is used. If $base is relative,
c27914c9 409then it is converted to absolute form using L</rel2abs()>. This means that it
59605c55 410is taken to be relative to L<cwd()|Cwd>.
c27914c9 411
412On systems with the concept of a volume, this assumes that both paths
3c32ced9 413are on the $base volume, and ignores the $path volume.
c27914c9 414
415On systems that have a grammar that indicates filenames, this ignores the
416$base filename as well. Otherwise all path components are assumed to be
417directories.
418
419If $path is absolute, it is cleaned up and returned using L</canonpath()>.
420
2586ba89 421No checks against the filesystem are made. On VMS, there is
3c32ced9 422interaction with the working environment, as logicals and
423macros are expanded.
c27914c9 424
3c32ced9 425Based on code written by Shigio Yamaguchi.
c27914c9 426
427=cut
428
786b702f 429sub rel2abs {
c27914c9 430 my ($self,$path,$base ) = @_;
431
432 # Clean up $path
433 if ( ! $self->file_name_is_absolute( $path ) ) {
434 # Figure out the effective $base and clean it up.
435 if ( !defined( $base ) || $base eq '' ) {
436 $base = cwd() ;
437 }
438 elsif ( ! $self->file_name_is_absolute( $base ) ) {
439 $base = $self->rel2abs( $base ) ;
440 }
441 else {
442 $base = $self->canonpath( $base ) ;
443 }
444
445 # Glom them together
6fd19b73 446 $path = $self->catdir( $base, $path ) ;
c27914c9 447 }
448
449 return $self->canonpath( $path ) ;
450}
451
452
270d1e39 453=back
454
455=head1 SEE ALSO
456
457L<File::Spec>
458
459=cut
460
4611;