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