Cleanup the File::Spec tmpdir() implementations:
[p5sagit/p5-mst-13.2.git] / lib / File / Spec / Mac.pm
CommitLineData
270d1e39 1package File::Spec::Mac;
2
270d1e39 3use strict;
b4296952 4use vars qw(@ISA $VERSION);
cbc7acb0 5require File::Spec::Unix;
b4296952 6
07824bd1 7$VERSION = '1.4';
b4296952 8
270d1e39 9@ISA = qw(File::Spec::Unix);
270d1e39 10
bcdb689b 11my $macfiles;
12if ($^O eq 'MacOS') {
13 $macfiles = eval { require Mac::Files };
14}
be708cc0 15
270d1e39 16=head1 NAME
17
2586ba89 18File::Spec::Mac - File::Spec for Mac OS (Classic)
270d1e39 19
20=head1 SYNOPSIS
21
cbc7acb0 22 require File::Spec::Mac; # Done internally by File::Spec if needed
270d1e39 23
24=head1 DESCRIPTION
25
26Methods for manipulating file specifications.
27
28=head1 METHODS
29
30=over 2
31
32=item canonpath
33
2586ba89 34On Mac OS, there's nothing to be done. Returns what it's given.
270d1e39 35
36=cut
37
38sub canonpath {
cbc7acb0 39 my ($self,$path) = @_;
40 return $path;
270d1e39 41}
42
59605c55 43=item catdir()
270d1e39 44
be708cc0 45Concatenate two or more directory names to form a path separated by colons
2586ba89 46(":") ending with a directory. Resulting paths are B<relative> by default,
45657e91 47but can be forced to be absolute (but avoid this, see below). Automatically
48puts a trailing ":" on the end of the complete path, because that's what's
49done in MacPerl's environment and helps to distinguish a file path from a
2586ba89 50directory path.
51
45657e91 52B<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the resulting
53path is relative by default and I<not> absolute. This descision was made due
54to portability reasons. Since C<File::Spec-E<gt>catdir()> returns relative paths
55on all other operating systems, it will now also follow this convention on Mac
2586ba89 56OS. Note that this may break some existing scripts.
be708cc0 57
58The intended purpose of this routine is to concatenate I<directory names>.
59But because of the nature of Macintosh paths, some additional possibilities
60are allowed to make using this routine give reasonable results for some
61common situations. In other words, you are also allowed to concatenate
62I<paths> instead of directory names (strictly speaking, a string like ":a"
63is a path, but not a name, since it contains a punctuation character ":").
64
be708cc0 65So, beside calls like
66
2586ba89 67 catdir("a") = ":a:"
68 catdir("a","b") = ":a:b:"
69 catdir() = "" (special case)
be708cc0 70
71calls like the following
270d1e39 72
2586ba89 73 catdir(":a:") = ":a:"
74 catdir(":a","b") = ":a:b:"
75 catdir(":a:","b") = ":a:b:"
76 catdir(":a:",":b:") = ":a:b:"
77 catdir(":") = ":"
270d1e39 78
be708cc0 79are allowed.
270d1e39 80
5813de03 81Here are the rules that are used in C<catdir()>; note that we try to be as
82compatible as possible to Unix:
2586ba89 83
84=over 2
85
2586ba89 86=item 1.
2586ba89 87
5813de03 88The resulting path is relative by default, i.e. the resulting path will have a
89leading colon.
2586ba89 90
91=item 2.
2586ba89 92
5813de03 93A trailing colon is added automatically to the resulting path, to denote a
94directory.
2586ba89 95
96=item 3.
2586ba89 97
5813de03 98Generally, each argument has one leading ":" and one trailing ":"
99removed (if any). They are then joined together by a ":". Special
100treatment applies for arguments denoting updir paths like "::lib:",
101see (4), or arguments consisting solely of colons ("colon paths"),
102see (5).
270d1e39 103
2586ba89 104=item 4.
5813de03 105
106When an updir path like ":::lib::" is passed as argument, the number
107of directories to climb up is handled correctly, not removing leading
108or trailing colons when necessary. E.g.
270d1e39 109
2586ba89 110 catdir(":::a","::b","c") = ":::a::b:c:"
111 catdir(":::a::","::b","c") = ":::a:::b:c:"
270d1e39 112
2586ba89 113=item 5.
5813de03 114
115Adding a colon ":" or empty string "" to a path at I<any> position
116doesn't alter the path, i.e. these arguments are ignored. (When a ""
117is passed as the first argument, it has a special meaning, see
118(6)). This way, a colon ":" is handled like a "." (curdir) on Unix,
119while an empty string "" is generally ignored (see
120C<Unix-E<gt>canonpath()> ). Likewise, a "::" is handled like a ".."
121(updir), and a ":::" is handled like a "../.." etc. E.g.
270d1e39 122
2586ba89 123 catdir("a",":",":","b") = ":a:b:"
124 catdir("a",":","::",":b") = ":a::b:"
125
2586ba89 126=item 6.
5813de03 127
128If the first argument is an empty string "" or is a volume name, i.e. matches
129the pattern /^[^:]+:/, the resulting path is B<absolute>.
2586ba89 130
131=item 7.
5813de03 132
133Passing an empty string "" as the first argument to C<catdir()> is
134like passingC<File::Spec-E<gt>rootdir()> as the first argument, i.e.
2586ba89 135
136 catdir("","a","b") is the same as
137
45657e91 138 catdir(rootdir(),"a","b").
2586ba89 139
5813de03 140This is true on Unix, where C<catdir("","a","b")> yields "/a/b" and
141C<rootdir()> is "/". Note that C<rootdir()> on Mac OS is the startup
142volume, which is the closest in concept to Unix' "/". This should help
143to run existing scripts originally written for Unix.
2586ba89 144
145=item 8.
5813de03 146
147For absolute paths, some cleanup is done, to ensure that the volume
148name isn't immediately followed by updirs. This is invalid, because
149this would go beyond "root". Generally, these cases are handled like
150their Unix counterparts:
2586ba89 151
152 Unix:
153 Unix->catdir("","") = "/"
154 Unix->catdir("",".") = "/"
155 Unix->catdir("","..") = "/" # can't go beyond root
156 Unix->catdir("",".","..","..","a") = "/a"
157 Mac:
158 Mac->catdir("","") = rootdir() # (e.g. "HD:")
159 Mac->catdir("",":") = rootdir()
160 Mac->catdir("","::") = rootdir() # can't go beyond root
161 Mac->catdir("",":","::","::","a") = rootdir() . "a:" # (e.g. "HD:a:")
162
5813de03 163However, this approach is limited to the first arguments following
164"root" (again, see C<Unix-E<gt>canonpath()> ). If there are more
165arguments that move up the directory tree, an invalid path going
166beyond root can be created.
2586ba89 167
168=back
169
5813de03 170As you've seen, you can force C<catdir()> to create an absolute path
171by passing either an empty string or a path that begins with a volume
172name as the first argument. However, you are strongly encouraged not
173to do so, since this is done only for backward compatibility. Newer
174versions of File::Spec come with a method called C<catpath()> (see
175below), that is designed to offer a portable solution for the creation
176of absolute paths. It takes volume, directory and file portions and
177returns an entire path. While C<catdir()> is still suitable for the
178concatenation of I<directory names>, you are encouraged to use
179C<catpath()> to concatenate I<volume names> and I<directory
180paths>. E.g.
2586ba89 181
182 $dir = File::Spec->catdir("tmp","sources");
183 $abs_path = File::Spec->catpath("MacintoshHD:", $dir,"");
270d1e39 184
be708cc0 185yields
270d1e39 186
2586ba89 187 "MacintoshHD:tmp:sources:" .
270d1e39 188
270d1e39 189=cut
190
270d1e39 191sub catdir {
45657e91 192 my $self = shift;
193 return '' unless @_;
194 my @args = @_;
195 my $first_arg;
196 my $relative;
197
2586ba89 198 # take care of the first argument
45657e91 199
2586ba89 200 if ($args[0] eq '') { # absolute path, rootdir
201 shift @args;
202 $relative = 0;
203 $first_arg = $self->rootdir;
45657e91 204
2586ba89 205 } elsif ($args[0] =~ /^[^:]+:/) { # absolute path, volume name
206 $relative = 0;
207 $first_arg = shift @args;
208 # add a trailing ':' if need be (may be it's a path like HD:dir)
209 $first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
45657e91 210
2586ba89 211 } else { # relative path
212 $relative = 1;
45657e91 213 if ( $args[0] =~ /^::+\Z(?!\n)/ ) {
2586ba89 214 # updir colon path ('::', ':::' etc.), don't shift
215 $first_arg = ':';
216 } elsif ($args[0] eq ':') {
217 $first_arg = shift @args;
218 } else {
219 # add a trailing ':' if need be
220 $first_arg = shift @args;
221 $first_arg = "$first_arg:" unless ($first_arg =~ /:\Z(?!\n)/);
45657e91 222 }
223 }
224
225 # For all other arguments,
2586ba89 226 # (a) ignore arguments that equal ':' or '',
227 # (b) handle updir paths specially:
228 # '::' -> concatenate '::'
229 # '::' . '::' -> concatenate ':::' etc.
230 # (c) add a trailing ':' if need be
45657e91 231
2586ba89 232 my $result = $first_arg;
233 while (@args) {
234 my $arg = shift @args;
235 unless (($arg eq '') || ($arg eq ':')) {
236 if ($arg =~ /^::+\Z(?!\n)/ ) { # updir colon path like ':::'
237 my $updir_count = length($arg) - 1;
238 while ((@args) && ($args[0] =~ /^::+\Z(?!\n)/) ) { # while updir colon path
45657e91 239 $arg = shift @args;
2586ba89 240 $updir_count += (length($arg) - 1);
241 }
45657e91 242 $arg = (':' x $updir_count);
2586ba89 243 } else {
244 $arg =~ s/^://s; # remove a leading ':' if any
245 $arg = "$arg:" unless ($arg =~ /:\Z(?!\n)/); # ensure trailing ':'
246 }
247 $result .= $arg;
248 }#unless
45657e91 249 }
250
251 if ( ($relative) && ($result !~ /^:/) ) {
2586ba89 252 # add a leading colon if need be
253 $result = ":$result";
254 }
45657e91 255
256 unless ($relative) {
2586ba89 257 # remove updirs immediately following the volume name
258 $result =~ s/([^:]+:)(:*)(.*)\Z(?!\n)/$1$3/;
259 }
45657e91 260
261 return $result;
270d1e39 262}
263
264=item catfile
265
266Concatenate one or more directory names and a filename to form a
45657e91 267complete path ending with a filename. Resulting paths are B<relative>
268by default, but can be forced to be absolute (but avoid this).
269
270B<IMPORTANT NOTE:> Beginning with version 1.3 of this module, the
271resulting path is relative by default and I<not> absolute. This
272descision was made due to portability reasons. Since
273C<File::Spec-E<gt>catfile()> returns relative paths on all other
274operating systems, it will now also follow this convention on Mac OS.
2586ba89 275Note that this may break some existing scripts.
276
45657e91 277The last argument is always considered to be the file portion. Since
278C<catfile()> uses C<catdir()> (see above) for the concatenation of the
279directory portions (if any), the following with regard to relative and
2586ba89 280absolute paths is true:
281
282 catfile("") = ""
45657e91 283 catfile("file") = "file"
2586ba89 284
285but
286
287 catfile("","") = rootdir() # (e.g. "HD:")
288 catfile("","file") = rootdir() . file # (e.g. "HD:file")
289 catfile("HD:","file") = "HD:file"
270d1e39 290
45657e91 291This means that C<catdir()> is called only when there are two or more
2586ba89 292arguments, as one might expect.
270d1e39 293
2586ba89 294Note that the leading ":" is removed from the filename, so that
270d1e39 295
2586ba89 296 catfile("a","b","file") = ":a:b:file" and
270d1e39 297
2586ba89 298 catfile("a","b",":file") = ":a:b:file"
299
45657e91 300give the same answer.
2586ba89 301
45657e91 302To concatenate I<volume names>, I<directory paths> and I<filenames>,
2586ba89 303you are encouraged to use C<catpath()> (see below).
270d1e39 304
305=cut
306
307sub catfile {
cbc7acb0 308 my $self = shift;
be708cc0 309 return '' unless @_;
270d1e39 310 my $file = pop @_;
311 return $file unless @_;
312 my $dir = $self->catdir(@_);
1b1e14d3 313 $file =~ s/^://s;
270d1e39 314 return $dir.$file;
315}
316
317=item curdir
318
be708cc0 319Returns a string representing the current directory. On Mac OS, this is ":".
270d1e39 320
321=cut
322
323sub curdir {
cbc7acb0 324 return ":";
325}
326
327=item devnull
328
be708cc0 329Returns a string representing the null device. On Mac OS, this is "Dev:Null".
cbc7acb0 330
331=cut
332
333sub devnull {
334 return "Dev:Null";
270d1e39 335}
336
337=item rootdir
338
339Returns a string representing the root directory. Under MacPerl,
340returns the name of the startup volume, since that's the closest in
be708cc0 341concept, although other volumes aren't rooted there. The name has a
342trailing ":", because that's the correct specification for a volume
343name on Mac OS.
270d1e39 344
bcdb689b 345If Mac::Files could not be loaded, the empty string is returned.
346
270d1e39 347=cut
348
349sub rootdir {
350#
2586ba89 351# There's no real root directory on Mac OS. The name of the startup
cbc7acb0 352# volume is returned, since that's the closest in concept.
270d1e39 353#
bcdb689b 354 return '' unless $macfiles;
355 my $system = Mac::Files::FindFolder(&Mac::Files::kOnSystemDisk,
356 &Mac::Files::kSystemFolderType);
9c045eb2 357 $system =~ s/:.*\Z(?!\n)/:/s;
cbc7acb0 358 return $system;
359}
360
361=item tmpdir
362
07824bd1 363Returns the contents of $ENV{TMPDIR}, if that directory exits or the
364current working directory otherwise. Under MacPerl, $ENV{TMPDIR} will
365contain a path like "MacintoshHD:Temporary Items:", which is a hidden
366directory on your startup volume.
cbc7acb0 367
368=cut
369
370my $tmpdir;
371sub tmpdir {
372 return $tmpdir if defined $tmpdir;
07824bd1 373 my $self = shift;
374 $tmpdir = $self->_tmpdir( $ENV{TMPDIR} );
270d1e39 375}
376
377=item updir
378
be708cc0 379Returns a string representing the parent directory. On Mac OS, this is "::".
270d1e39 380
381=cut
382
383sub updir {
384 return "::";
385}
386
387=item file_name_is_absolute
388
be708cc0 389Takes as argument a path and returns true, if it is an absolute path.
2586ba89 390If the path has a leading ":", it's a relative path. Otherwise, it's an
be708cc0 391absolute path, unless the path doesn't contain any colons, i.e. it's a name
392like "a". In this particular case, the path is considered to be relative
393(i.e. it is considered to be a filename). Use ":" in the appropriate place
394in the path if you want to distinguish unambiguously. As a special case,
45657e91 395the filename '' is always considered to be absolute. Note that with version
3961.2 of File::Spec::Mac, this does no longer consult the local filesystem.
be708cc0 397
398E.g.
399
400 File::Spec->file_name_is_absolute("a"); # false (relative)
401 File::Spec->file_name_is_absolute(":a:b:"); # false (relative)
402 File::Spec->file_name_is_absolute("MacintoshHD:"); # true (absolute)
403 File::Spec->file_name_is_absolute(""); # true (absolute)
270d1e39 404
3c32ced9 405
270d1e39 406=cut
407
408sub file_name_is_absolute {
cbc7acb0 409 my ($self,$file) = @_;
410 if ($file =~ /:/) {
be708cc0 411 return (! ($file =~ m/^:/s) );
3c32ced9 412 } elsif ( $file eq '' ) {
413 return 1 ;
cbc7acb0 414 } else {
be708cc0 415 return 0; # i.e. a file like "a"
270d1e39 416 }
417}
418
419=item path
420
be708cc0 421Returns the null list for the MacPerl application, since the concept is
2586ba89 422usually meaningless under Mac OS. But if you're using the MacPerl tool under
be708cc0 423MPW, it gives back $ENV{Commands} suitably split, as is done in
270d1e39 424:lib:ExtUtils:MM_Mac.pm.
425
426=cut
427
428sub path {
429#
430# The concept is meaningless under the MacPerl application.
431# Under MPW, it has a meaning.
432#
cbc7acb0 433 return unless exists $ENV{Commands};
434 return split(/,/, $ENV{Commands});
270d1e39 435}
436
0994714a 437=item splitpath
438
be708cc0 439 ($volume,$directories,$file) = File::Spec->splitpath( $path );
440 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
441
40d020d9 442Splits a path into volume, directory, and filename portions.
be708cc0 443
444On Mac OS, assumes that the last part of the path is a filename unless
445$no_file is true or a trailing separator ":" is present.
446
447The volume portion is always returned with a trailing ":". The directory portion
448is always returned with a leading (to denote a relative path) and a trailing ":"
449(to denote a directory). The file portion is always returned I<without> a leading ":".
2586ba89 450Empty portions are returned as empty string ''.
be708cc0 451
2586ba89 452The results can be passed to C<catpath()> to get back a path equivalent to
be708cc0 453(usually identical to) the original path.
454
455
0994714a 456=cut
457
458sub splitpath {
459 my ($self,$path, $nofile) = @_;
be708cc0 460 my ($volume,$directory,$file);
0994714a 461
462 if ( $nofile ) {
be708cc0 463 ( $volume, $directory ) = $path =~ m|^((?:[^:]+:)?)(.*)|s;
0994714a 464 }
465 else {
be708cc0 466 $path =~
467 m|^( (?: [^:]+: )? )
468 ( (?: .*: )? )
469 ( .* )
470 |xs;
0994714a 471 $volume = $1;
472 $directory = $2;
473 $file = $3;
474 }
475
be708cc0 476 $volume = '' unless defined($volume);
477 $directory = ":$directory" if ( $volume && $directory ); # take care of "HD::dir"
478 if ($directory) {
479 # Make sure non-empty directories begin and end in ':'
480 $directory .= ':' unless (substr($directory,-1) eq ':');
481 $directory = ":$directory" unless (substr($directory,0,1) eq ':');
482 } else {
483 $directory = '';
484 }
485 $file = '' unless defined($file);
486
0994714a 487 return ($volume,$directory,$file);
488}
489
490
491=item splitdir
492
2586ba89 493The opposite of C<catdir()>.
be708cc0 494
495 @dirs = File::Spec->splitdir( $directories );
496
2586ba89 497$directories should be only the directory portion of the path on systems
be708cc0 498that have the concept of a volume or that have path syntax that differentiates
2586ba89 499files from directories. Consider using C<splitpath()> otherwise.
be708cc0 500
501Unlike just splitting the directories on the separator, empty directory names
502(C<"">) can be returned. Since C<catdir()> on Mac OS always appends a trailing
503colon to distinguish a directory path from a file path, a single trailing colon
504will be ignored, i.e. there's no empty directory name after it.
505
506Hence, on Mac OS, both
507
508 File::Spec->splitdir( ":a:b::c:" ); and
509 File::Spec->splitdir( ":a:b::c" );
510
511yield:
512
2586ba89 513 ( "a", "b", "::", "c")
be708cc0 514
515while
516
517 File::Spec->splitdir( ":a:b::c::" );
518
519yields:
520
2586ba89 521 ( "a", "b", "::", "c", "::")
be708cc0 522
523
0994714a 524=cut
525
526sub splitdir {
45657e91 527 my ($self, $path) = @_;
2586ba89 528 my @result = ();
529 my ($head, $sep, $tail, $volume, $directories);
45657e91 530
2586ba89 531 return ('') if ( (!defined($path)) || ($path eq '') );
532 return (':') if ($path eq ':');
533
534 ( $volume, $sep, $directories ) = $path =~ m|^((?:[^:]+:)?)(:*)(.*)|s;
535
536 # deprecated, but handle it correctly
537 if ($volume) {
538 push (@result, $volume);
539 $sep .= ':';
540 }
45657e91 541
2586ba89 542 while ($sep || $directories) {
543 if (length($sep) > 1) {
544 my $updir_count = length($sep) - 1;
545 for (my $i=0; $i<$updir_count; $i++) {
546 # push '::' updir_count times;
547 # simulate Unix '..' updirs
45657e91 548 push (@result, '::');
2586ba89 549 }
550 }
551 $sep = '';
552 if ($directories) {
553 ( $head, $sep, $tail ) = $directories =~ m|^((?:[^:]+)?)(:*)(.*)|s;
554 push (@result, $head);
555 $directories = $tail;
556 }
45657e91 557 }
2586ba89 558 return @result;
0994714a 559}
560
561
45657e91 562=item catpath
0994714a 563
be708cc0 564 $path = File::Spec->catpath($volume,$directory,$file);
565
566Takes volume, directory and file portions and returns an entire path. On Mac OS,
567$volume, $directory and $file are concatenated. A ':' is inserted if need be. You
568may pass an empty string for each portion. If all portions are empty, the empty
569string is returned. If $volume is empty, the result will be a relative path,
570beginning with a ':'. If $volume and $directory are empty, a leading ":" (if any)
571is removed form $file and the remainder is returned. If $file is empty, the
572resulting path will have a trailing ':'.
573
574
0994714a 575=cut
576
577sub catpath {
be708cc0 578 my ($self,$volume,$directory,$file) = @_;
0994714a 579
be708cc0 580 if ( (! $volume) && (! $directory) ) {
581 $file =~ s/^:// if $file;
582 return $file ;
583 }
0994714a 584
be708cc0 585 my $path = $volume; # may be ''
586 $path .= ':' unless (substr($path, -1) eq ':'); # ensure trailing ':'
587
588 if ($directory) {
589 $directory =~ s/^://; # remove leading ':' if any
590 $path .= $directory;
591 $path .= ':' unless (substr($path, -1) eq ':'); # ensure trailing ':'
0994714a 592 }
593
be708cc0 594 if ($file) {
595 $file =~ s/^://; # remove leading ':' if any
596 $path .= $file;
597 }
598
599 return $path;
0994714a 600}
601
602=item abs2rel
603
be708cc0 604Takes a destination path and an optional base path and returns a relative path
605from the base path to the destination path:
606
607 $rel_path = File::Spec->abs2rel( $path ) ;
608 $rel_path = File::Spec->abs2rel( $path, $base ) ;
609
610Note that both paths are assumed to have a notation that distinguishes a
611directory path (with trailing ':') from a file path (without trailing ':').
612
613If $base is not present or '', then the current working directory is used.
614If $base is relative, then it is converted to absolute form using C<rel2abs()>.
615This means that it is taken to be relative to the current working directory.
616
617Since Mac OS has the concept of volumes, this assumes that both paths
618are on the $destination volume, and ignores the $base volume (!).
619
620If $base doesn't have a trailing colon, the last element of $base is
621assumed to be a filename. This filename is ignored (!). Otherwise all path
622components are assumed to be directories.
623
624If $path is relative, it is converted to absolute form using C<rel2abs()>.
625This means that it is taken to be relative to the current working directory.
626
627Based on code written by Shigio Yamaguchi.
3c32ced9 628
3c32ced9 629
0994714a 630=cut
631
be708cc0 632# maybe this should be done in canonpath() ?
633sub _resolve_updirs {
634 my $path = shift @_;
635 my $proceed;
636
637 # resolve any updirs, e.g. "HD:tmp::file" -> "HD:file"
638 do {
639 $proceed = ($path =~ s/^(.*):[^:]+::(.*?)\z/$1:$2/);
640 } while ($proceed);
641
642 return $path;
643}
644
645
0994714a 646sub abs2rel {
647 my($self,$path,$base) = @_;
648
649 # Clean up $path
650 if ( ! $self->file_name_is_absolute( $path ) ) {
651 $path = $self->rel2abs( $path ) ;
652 }
653
654 # Figure out the effective $base and clean it up.
655 if ( !defined( $base ) || $base eq '' ) {
be708cc0 656 $base = cwd();
0994714a 657 }
658 elsif ( ! $self->file_name_is_absolute( $base ) ) {
659 $base = $self->rel2abs( $base ) ;
be708cc0 660 $base = _resolve_updirs( $base ); # resolve updirs in $base
0994714a 661 }
be708cc0 662 else {
663 $base = _resolve_updirs( $base );
664 }
665
666 # Split up paths
667 my ( $path_dirs, $path_file ) = ($self->splitpath( $path ))[1,2] ;
668
669 # ignore $base's volume and file
670 my $base_dirs = ($self->splitpath( $base ))[1] ;
0994714a 671
672 # Now, remove all leading components that are the same
7c90792d 673 my @pathchunks = $self->splitdir( $path_dirs );
674 my @basechunks = $self->splitdir( $base_dirs );
45657e91 675
be708cc0 676 while ( @pathchunks &&
677 @basechunks &&
678 lc( $pathchunks[0] ) eq lc( $basechunks[0] ) ) {
0994714a 679 shift @pathchunks ;
680 shift @basechunks ;
681 }
45657e91 682
be708cc0 683 # @pathchunks now has the directories to descend in to.
45657e91 684 # ensure relative path, even if @pathchunks is empty
685 $path_dirs = $self->catdir( ':', @pathchunks );
0994714a 686
687 # @basechunks now contains the number of directories to climb out of.
be708cc0 688 $base_dirs = (':' x @basechunks) . ':' ;
0994714a 689
2586ba89 690 return $self->catpath( '', $self->catdir( $base_dirs, $path_dirs ), $path_file ) ;
0994714a 691}
692
693=item rel2abs
694
be708cc0 695Converts a relative path to an absolute path:
696
697 $abs_path = File::Spec->rel2abs( $path ) ;
698 $abs_path = File::Spec->rel2abs( $path, $base ) ;
0994714a 699
be708cc0 700Note that both paths are assumed to have a notation that distinguishes a
701directory path (with trailing ':') from a file path (without trailing ':').
702
703If $base is not present or '', then $base is set to the current working
704directory. If $base is relative, then it is converted to absolute form
705using C<rel2abs()>. This means that it is taken to be relative to the
706current working directory.
707
708If $base doesn't have a trailing colon, the last element of $base is
709assumed to be a filename. This filename is ignored (!). Otherwise all path
710components are assumed to be directories.
711
712If $path is already absolute, it is returned and $base is ignored.
713
714Based on code written by Shigio Yamaguchi.
0994714a 715
716=cut
717
786b702f 718sub rel2abs {
be708cc0 719 my ($self,$path,$base) = @_;
0994714a 720
be708cc0 721 if ( ! $self->file_name_is_absolute($path) ) {
722 # Figure out the effective $base and clean it up.
0994714a 723 if ( !defined( $base ) || $base eq '' ) {
be708cc0 724 $base = cwd();
0994714a 725 }
be708cc0 726 elsif ( ! $self->file_name_is_absolute($base) ) {
727 $base = $self->rel2abs($base) ;
0994714a 728 }
729
be708cc0 730 # Split up paths
731
732 # igonore $path's volume
733 my ( $path_dirs, $path_file ) = ($self->splitpath($path))[1,2] ;
734
735 # ignore $base's file part
736 my ( $base_vol, $base_dirs, undef ) = $self->splitpath($base) ;
737
738 # Glom them together
739 $path_dirs = ':' if ($path_dirs eq '');
740 $base_dirs =~ s/:$//; # remove trailing ':', if any
741 $base_dirs = $base_dirs . $path_dirs;
0994714a 742
be708cc0 743 $path = $self->catpath( $base_vol, $base_dirs, $path_file );
744 }
745 return $path;
0994714a 746}
747
748
270d1e39 749=back
750
be708cc0 751=head1 AUTHORS
752
2586ba89 753See the authors list in I<File::Spec>. Mac OS support by Paul Schinder
be708cc0 754<schinder@pobox.com> and Thomas Wegner <wegner_thomas@yahoo.com>.
755
756
270d1e39 757=head1 SEE ALSO
758
759L<File::Spec>
760
761=cut
762
7631;