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